#include "SCLY.hpp" #include "ScriptObjects/ScriptTypes.hpp" namespace DataSpec::DNAMP1 { template <> void SCLY::Enumerate(athena::io::IStreamReader& rs) { fourCC.read(rs); version = rs.readUint32Big(); layerCount = rs.readUint32Big(); rs.enumerateBig(layerSizes, layerCount); atUint32 i = 0; rs.enumerate(layers, layerCount, [&i, this](athena::io::IStreamReader& rs, ScriptLayer& layer) { atUint64 start = rs.position(); layer.read(rs); rs.seek(start + layerSizes[i++], athena::SeekOrigin::Begin); }); } template <> void SCLY::Enumerate(athena::io::IStreamWriter& ws) { fourCC.write(ws); ws.writeUint32Big(version); ws.writeUint32Big(layerCount); ws.enumerateBig(layerSizes); ws.enumerate(layers); } template <> void SCLY::Enumerate(size_t& __isz) { __isz += 12; __isz += layerSizes.size() * 4; for (const ScriptLayer& layer : layers) layer.binarySize(__isz); } void SCLY::exportToLayerDirectories(const PAK::Entry& entry, PAKRouter& pakRouter, bool force) const { for (atUint32 i = 0; i < layerCount; i++) { bool active; hecl::ProjectPath layerPath = pakRouter.getAreaLayerWorking(entry.id, i, active); if (layerPath.isNone()) layerPath.makeDirChain(true); if (active) { const hecl::ProjectPath activePath(layerPath, "!defaultactive"); [[maybe_unused]] const auto fp = hecl::FopenUnique(activePath.getAbsolutePath().data(), "wb"); } hecl::ProjectPath yamlFile(layerPath, "!objects.yaml"); if (force || yamlFile.isNone()) { athena::io::FileWriter writer(yamlFile.getAbsolutePath()); athena::io::ToYAMLStream(layers[i], writer); } } } void SCLY::addCMDLRigPairs(PAKRouter& pakRouter, CharacterAssociations& charAssoc) const { for (const ScriptLayer& layer : layers) layer.addCMDLRigPairs(pakRouter, charAssoc); } void SCLY::ScriptLayer::addCMDLRigPairs(PAKRouter& pakRouter, CharacterAssociations& charAssoc) const { for (const std::unique_ptr& obj : objects) obj->addCMDLRigPairs(pakRouter, charAssoc); } void SCLY::nameIDs(PAKRouter& pakRouter) const { for (const ScriptLayer& layer : layers) layer.nameIDs(pakRouter); } void SCLY::ScriptLayer::nameIDs(PAKRouter& pakRouter) const { for (const std::unique_ptr& obj : objects) obj->nameIDs(pakRouter); } template <> void SCLY::Enumerate(athena::io::YAMLDocReader& docin) { Do(athena::io::PropId{"fourCC"}, fourCC, docin); version = docin.readUint32("version"); layerCount = docin.enumerate("layerSizes", layerSizes); docin.enumerate("layers", layers); } template <> void SCLY::Enumerate(athena::io::YAMLDocWriter& docout) { Do(athena::io::PropId{"fourCC"}, fourCC, docout); docout.writeUint32("version", version); docout.enumerate("layerSizes", layerSizes); docout.enumerate("layers", layers); } std::string_view SCLY::DNAType() { return "DNAMP1::SCLY"sv; } template <> void SCLY::ScriptLayer::Enumerate(athena::io::IStreamReader& rs) { unknown = rs.readUByte(); objectCount = rs.readUint32Big(); objects.clear(); objects.reserve(objectCount); for (atUint32 i = 0; i < objectCount; i++) { atUint8 type = rs.readUByte(); atUint32 len = rs.readUint32Big(); atUint64 start = rs.position(); auto iter = std::find_if(SCRIPT_OBJECT_DB.begin(), SCRIPT_OBJECT_DB.end(), [&type](const ScriptObjectSpec* obj) -> bool { return obj->type == type; }); if (iter != SCRIPT_OBJECT_DB.end()) { std::unique_ptr obj((*iter)->loader()); obj->type = type; obj->read(rs); objects.push_back(std::move(obj)); size_t actualLen = rs.position() - start; if (actualLen != len) Log.report(logvisor::Fatal, FMT_STRING("Error while reading object of type 0x{:02X}, did not read the expected amount of " "data, read 0x{:x}, expected 0x{:x}"), (atUint32)type, actualLen, len); rs.seek(start + len, athena::SeekOrigin::Begin); } else { Log.report(logvisor::Fatal, FMT_STRING("Unable to find type 0x{:X} in object database"), (atUint32)type); } } } template <> void SCLY::ScriptLayer::Enumerate(athena::io::YAMLDocReader& rs) { unknown = rs.readUByte("unknown"); size_t objCount; objects.clear(); if (auto v = rs.enterSubVector("objects", objCount)) { objectCount = objCount; objects.reserve(objCount); for (atUint32 i = 0; i < objectCount; i++) { if (auto rec = rs.enterSubRecord()) { atUint8 type = rs.readUByte("type"); auto iter = std::find_if(SCRIPT_OBJECT_DB.begin(), SCRIPT_OBJECT_DB.end(), [&type](const ScriptObjectSpec* obj) -> bool { return obj->type == type; }); if (iter != SCRIPT_OBJECT_DB.end()) { std::unique_ptr obj((*iter)->loader()); obj->read(rs); obj->type = type; objects.push_back(std::move(obj)); } else Log.report(logvisor::Fatal, FMT_STRING("Unable to find type 0x{:X} in object database"), (atUint32)type); } } } else objectCount = 0; } template <> void SCLY::ScriptLayer::Enumerate(athena::io::IStreamWriter& ws) { ws.writeUByte(unknown); ws.writeUint32Big(objectCount); for (const std::unique_ptr& obj : objects) { ws.writeByte(obj->type); size_t expLen = 0; obj->binarySize(expLen); ws.writeUint32Big(expLen); auto start = ws.position(); obj->write(ws); auto wrote = ws.position() - start; if (wrote != expLen) Log.report(logvisor::Error, FMT_STRING("expected writing {} byte SCLY obj; wrote {}"), expLen, wrote); } } template <> void SCLY::ScriptLayer::Enumerate(size_t& __isz) { __isz += 5; for (const std::unique_ptr& obj : objects) { __isz += 5; obj->binarySize(__isz); } } template <> void SCLY::ScriptLayer::Enumerate(athena::io::YAMLDocWriter& ws) { ws.writeUByte("unknown", unknown); if (auto v = ws.enterSubVector("objects")) { for (const std::unique_ptr& obj : objects) { if (auto rec = ws.enterSubRecord()) { ws.writeUByte("type", obj->type); obj->write(ws); } } } } std::string_view SCLY::ScriptLayer::DNAType() { return "DNAMP1::SCLY::ScriptLayer"sv; } } // namespace DataSpec::DNAMP1