From 804d46a2df8d54885ce339f868cde6bdce0fff0a Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Tue, 7 Oct 2025 03:28:44 +0100 Subject: EAD Limb and Animation Factories (#200) Co-authored-by: Lywx --- src/Companion.cpp | 5 + src/factories/AssetArrayFactory.cpp | 2 +- src/factories/fzerox/EADAnimationFactory.cpp | 183 +++++++++++++++++++++++++++ src/factories/fzerox/EADAnimationFactory.h | 58 +++++++++ src/factories/fzerox/EADLimbFactory.cpp | 158 +++++++++++++++++++++++ src/factories/fzerox/EADLimbFactory.h | 60 +++++++++ 6 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 src/factories/fzerox/EADAnimationFactory.cpp create mode 100644 src/factories/fzerox/EADAnimationFactory.h create mode 100644 src/factories/fzerox/EADLimbFactory.cpp create mode 100644 src/factories/fzerox/EADLimbFactory.h diff --git a/src/Companion.cpp b/src/Companion.cpp index c52d87e..231b24c 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -71,8 +71,10 @@ #endif #ifdef FZERO_SUPPORT +#include "factories/fzerox/EADAnimationFactory.h" #include "factories/fzerox/CourseFactory.h" #include "factories/fzerox/GhostRecordFactory.h" +#include "factories/fzerox/EADLimbFactory.h" #include "factories/fzerox/SequenceFactory.h" #include "factories/fzerox/SoundFontFactory.h" #endif @@ -187,8 +189,10 @@ void Companion::Init(const ExportType type) { #endif #ifdef FZERO_SUPPORT + this->RegisterFactory("FZX:ANIM", std::make_shared()); this->RegisterFactory("FZX:COURSE", std::make_shared()); this->RegisterFactory("FZX:GHOST", std::make_shared()); + this->RegisterFactory("FZX:LIMB", std::make_shared()); this->RegisterFactory("FZX:SEQUENCE", std::make_shared()); this->RegisterFactory("FZX:SOUNDFONT", std::make_shared()); #endif @@ -1620,6 +1624,7 @@ std::optional Companion::AddAsset(YAML::Node asset) { if(!asset["offset"] || !asset["type"]) { return std::nullopt; } + asset["offset"] = PatchVirtualAddr(GetSafeNode(asset, "offset")); const auto type = GetTypeNode(asset); const auto offset = GetSafeNode(asset, "offset"); const auto symbol = GetSafeNode(asset, "symbol", ""); diff --git a/src/factories/AssetArrayFactory.cpp b/src/factories/AssetArrayFactory.cpp index b62a8c2..37ee325 100644 --- a/src/factories/AssetArrayFactory.cpp +++ b/src/factories/AssetArrayFactory.cpp @@ -27,7 +27,7 @@ ExportResult AssetArrayCodeExporter::Export(std::ostream &write, std::shared_ptr auto data = std::static_pointer_cast(raw); - write << "static " << data->mType << "* " << symbol << "[] = {\n"; + write << data->mType << "* " << symbol << "[] = {\n"; for (auto ptr : data->mPtrs) { write << fourSpaceTab; if (ptr == 0) { diff --git a/src/factories/fzerox/EADAnimationFactory.cpp b/src/factories/fzerox/EADAnimationFactory.cpp new file mode 100644 index 0000000..fff1545 --- /dev/null +++ b/src/factories/fzerox/EADAnimationFactory.cpp @@ -0,0 +1,183 @@ +#include "EADAnimationFactory.h" + +#include "utils/Decompressor.h" +#include "spdlog/spdlog.h" +#include "Companion.h" + +#define FORMAT_HEX(x) std::hex << "0x" << std::uppercase << x << std::nouppercase << std::dec +#define FZX_ANIMATION_SIZE 0x1C + +ExportResult FZX::EADAnimationHeaderExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern EADDemoAnimationInfo " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult FZX::EADAnimationCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + const auto offset = GetSafeNode(node, "offset"); + const auto anim = std::static_pointer_cast(raw); + + write << "EADDemoAnimationInfo " << symbol << " = {\n"; + write << fourSpaceTab << anim->mFrameCount << ", " << anim->mLimbCount << ", "; + + if (anim->mScaleData == 0) { + write << "NULL, "; + } else { + auto dec = Companion::Instance->GetNodeByAddr(anim->mScaleData); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << assetSymbol << ", "; + } else { + write << FORMAT_HEX(anim->mScaleData) << ", "; + } + } + if (anim->mScaleInfo == 0) { + write << "NULL, "; + } else { + auto dec = Companion::Instance->GetNodeByAddr(anim->mScaleInfo); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << assetSymbol << ", "; + } else { + write << FORMAT_HEX(anim->mScaleInfo) << ", "; + } + } + if (anim->mRotationData == 0) { + write << "NULL, "; + } else { + auto dec = Companion::Instance->GetNodeByAddr(anim->mRotationData); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << assetSymbol << ", "; + } else { + write << FORMAT_HEX(anim->mRotationData) << ", "; + } + } + if (anim->mRotationInfo == 0) { + write << "NULL, "; + } else { + auto dec = Companion::Instance->GetNodeByAddr(anim->mRotationInfo); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << assetSymbol << ", "; + } else { + write << FORMAT_HEX(anim->mRotationInfo) << ", "; + } + } + if (anim->mPositionData == 0) { + write << "NULL,"; + } else { + auto dec = Companion::Instance->GetNodeByAddr(anim->mPositionData); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << assetSymbol << ","; + } else { + write << FORMAT_HEX(anim->mPositionData) << ","; + } + } + if (anim->mPositionInfo == 0) { + write << "NULL, "; + } else { + auto dec = Companion::Instance->GetNodeByAddr(anim->mPositionInfo); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << assetSymbol << ", "; + } else { + write << FORMAT_HEX(anim->mPositionInfo) << ", "; + } + } + write << "\n};\n\n"; + + return offset + FZX_ANIMATION_SIZE; +} + +ExportResult FZX::EADAnimationBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + auto writer = LUS::BinaryWriter(); + const auto animation = std::static_pointer_cast(raw); + + return std::nullopt; +} + +std::optional> FZX::EADAnimationFactory::parse(std::vector& buffer, YAML::Node& node) { + auto [_, segment] = Decompressor::AutoDecode(node, buffer); + LUS::BinaryReader reader(segment.data, segment.size); + const auto symbol = GetSafeNode(node, "symbol"); + const auto scaleCount = GetSafeNode(node, "scale_count"); + const auto rotationCount = GetSafeNode(node, "rot_count"); + const auto positionCount = GetSafeNode(node, "pos_count"); + + reader.SetEndianness(Torch::Endianness::Big); + + auto frameCount = reader.ReadInt16(); + auto limbCount = reader.ReadInt16(); + auto scaleData = reader.ReadUInt32(); + auto scaleInfo = reader.ReadUInt32(); + auto rotationData = reader.ReadUInt32(); + auto rotationInfo = reader.ReadUInt32(); + auto positionData = reader.ReadUInt32(); + auto positionInfo = reader.ReadUInt32(); + + YAML::Node scaleDataNode; + scaleDataNode["type"] = "ARRAY"; + scaleDataNode["array_type"] = "f32"; + scaleDataNode["count"] = scaleCount; + scaleDataNode["offset"] = scaleData; + scaleDataNode["symbol"] = symbol + "ScaleData"; + Companion::Instance->AddAsset(scaleDataNode); + + YAML::Node scaleInfoNode; + scaleInfoNode["type"] = "ARRAY"; + scaleInfoNode["array_type"] = "s32"; + scaleInfoNode["count"] = 6 * limbCount; + scaleInfoNode["offset"] = scaleInfo; + scaleInfoNode["symbol"] = symbol + "ScaleInfo"; + Companion::Instance->AddAsset(scaleInfoNode); + + YAML::Node rotationDataNode; + rotationDataNode["type"] = "ARRAY"; + rotationDataNode["array_type"] = "s16"; + rotationDataNode["count"] = rotationCount; + rotationDataNode["offset"] = rotationData; + rotationDataNode["symbol"] = symbol + "RotationData"; + Companion::Instance->AddAsset(rotationDataNode); + + YAML::Node rotationInfoNode; + rotationInfoNode["type"] = "ARRAY"; + rotationInfoNode["array_type"] = "s32"; + rotationInfoNode["count"] = 6 * limbCount; + rotationInfoNode["offset"] = rotationInfo; + rotationInfoNode["symbol"] = symbol + "RotationInfo"; + Companion::Instance->AddAsset(rotationInfoNode); + + YAML::Node positionDataNode; + positionDataNode["type"] = "ARRAY"; + positionDataNode["array_type"] = "s16"; + positionDataNode["count"] = positionCount; + positionDataNode["offset"] = positionData; + positionDataNode["symbol"] = symbol + "PositionData"; + Companion::Instance->AddAsset(positionDataNode); + + YAML::Node positionInfoNode; + positionInfoNode["type"] = "ARRAY"; + positionInfoNode["array_type"] = "s32"; + positionInfoNode["count"] = 6 * limbCount; + positionInfoNode["offset"] = positionInfo; + positionInfoNode["symbol"] = symbol + "PositionInfo"; + Companion::Instance->AddAsset(positionInfoNode); + + return std::make_shared(frameCount, limbCount, scaleData, scaleInfo, rotationData, rotationInfo, positionData, positionInfo); +} diff --git a/src/factories/fzerox/EADAnimationFactory.h b/src/factories/fzerox/EADAnimationFactory.h new file mode 100644 index 0000000..bd87256 --- /dev/null +++ b/src/factories/fzerox/EADAnimationFactory.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +namespace FZX { + +class EADAnimationData : public IParsedData { +public: + int16_t mFrameCount; + int16_t mLimbCount; + uint32_t mScaleData; + uint32_t mScaleInfo; + uint32_t mRotationData; + uint32_t mRotationInfo; + uint32_t mPositionData; + uint32_t mPositionInfo; + + EADAnimationData(int16_t frameCount, int16_t limbCount, uint32_t scaleData, uint32_t scaleInfo, uint32_t rotationData, uint32_t rotationInfo, uint32_t positionData, uint32_t positionInfo) : + mFrameCount(frameCount), + mLimbCount(limbCount), + mScaleData(scaleData), + mScaleInfo(scaleInfo), + mRotationData(rotationData), + mRotationInfo(rotationInfo), + mPositionData(positionData), + mPositionInfo(positionInfo) + {} +}; + +class EADAnimationHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EADAnimationBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EADAnimationCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EADAnimationModdingExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EADAnimationFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Code, EADAnimationCodeExporter) + REGISTER(Header, EADAnimationHeaderExporter) + REGISTER(Binary, EADAnimationBinaryExporter) + }; + } +}; +} // namespace FZX diff --git a/src/factories/fzerox/EADLimbFactory.cpp b/src/factories/fzerox/EADLimbFactory.cpp new file mode 100644 index 0000000..ba349b3 --- /dev/null +++ b/src/factories/fzerox/EADLimbFactory.cpp @@ -0,0 +1,158 @@ +#include "EADLimbFactory.h" + +#include "utils/Decompressor.h" +#include "spdlog/spdlog.h" +#include "Companion.h" + +#define FORMAT_HEX(x) std::hex << "0x" << std::uppercase << x << std::nouppercase << std::dec +#define FZX_LIMB_SIZE 0x36 + +ExportResult FZX::EADLimbHeaderExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern EADDemoLimb " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult FZX::EADLimbCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + const auto offset = GetSafeNode(node, "offset"); + const auto limb = std::static_pointer_cast(raw); + + write << "EADDemoLimb " << symbol << " = {\n"; + + write << fourSpaceTab; + + if (limb->mDl == 0) { + write << "NULL,\n"; + } else { + auto dec = Companion::Instance->GetNodeByAddr(limb->mDl); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << assetSymbol << ",\n"; + } else { + write << FORMAT_HEX(limb->mDl) << ",\n"; + } + } + + write << fourSpaceTab << limb->mScale << ",\n"; + write << fourSpaceTab << limb->mPos << ",\n"; + write << fourSpaceTab << limb->mRot << ",\n"; + + write << fourSpaceTab; + if (limb->mNextLimb == 0) { + write << "NULL,\n"; + } else { + auto dec = Companion::Instance->GetNodeByAddr(limb->mNextLimb); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << "&" << assetSymbol << ",\n"; + } else { + write << FORMAT_HEX(limb->mNextLimb) << ",\n"; + } + } + + write << fourSpaceTab; + if (limb->mChildLimb == 0) { + write << "NULL,\n"; + } else { + auto dec = Companion::Instance->GetNodeByAddr(limb->mChildLimb); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << "&" << assetSymbol << ",\n"; + } else { + write << FORMAT_HEX(limb->mChildLimb) << ",\n"; + } + } + + write << fourSpaceTab; + if (limb->mAssociatedLimb == 0) { + write << "NULL,\n"; + } else { + auto dec = Companion::Instance->GetNodeByAddr(limb->mAssociatedLimb); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << "&" << assetSymbol << ",\n"; + } else { + write << FORMAT_HEX(limb->mAssociatedLimb) << ",\n"; + } + } + + write << fourSpaceTab; + if (limb->mAssociatedLimbDL == 0) { + write << "NULL,\n"; + } else { + auto dec = Companion::Instance->GetNodeByAddr(limb->mAssociatedLimbDL); + if (dec.has_value()) { + auto node = std::get<1>(dec.value()); + auto assetSymbol = GetSafeNode(node, "symbol"); + write << assetSymbol << ",\n"; + } else { + write << FORMAT_HEX(limb->mAssociatedLimbDL) << ",\n"; + } + } + + write << fourSpaceTab << limb->mLimbId << "\n};\n\n"; + + return offset + FZX_LIMB_SIZE; +} + +ExportResult FZX::EADLimbBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + auto writer = LUS::BinaryWriter(); + const auto limb = std::static_pointer_cast(raw); + + return std::nullopt; +} + +std::optional> FZX::EADLimbFactory::parse(std::vector& buffer, YAML::Node& node) { + auto [_, segment] = Decompressor::AutoDecode(node, buffer); + LUS::BinaryReader reader(segment.data, segment.size); + + reader.SetEndianness(Torch::Endianness::Big); + + Vec3f scale; + Vec3f pos; + Vec3s rot; + + auto dl = reader.ReadUInt32(); + + if (dl != 0) { + YAML::Node dListNode; + dListNode["type"] = "GFX"; + dListNode["offset"] = dl; + Companion::Instance->AddAsset(dListNode); + } + scale.x = reader.ReadFloat(); + scale.y = reader.ReadFloat(); + scale.z = reader.ReadFloat(); + pos.x = reader.ReadFloat(); + pos.y = reader.ReadFloat(); + pos.z = reader.ReadFloat(); + rot.x = reader.ReadInt16(); + rot.y = reader.ReadInt16(); + rot.z = reader.ReadInt16(); + reader.ReadInt16(); + auto nextLimb = reader.ReadUInt32(); + auto childLimb = reader.ReadUInt32(); + auto associatedLimb = reader.ReadUInt32(); + auto associatedLimbDL = reader.ReadUInt32(); + if (associatedLimbDL != 0) { + YAML::Node dListNode; + dListNode["type"] = "GFX"; + dListNode["offset"] = associatedLimbDL; + Companion::Instance->AddAsset(dListNode); + } + auto limbId = reader.ReadInt16(); + + return std::make_shared(dl, scale, pos, rot, nextLimb, childLimb, associatedLimb, associatedLimbDL, limbId); +} diff --git a/src/factories/fzerox/EADLimbFactory.h b/src/factories/fzerox/EADLimbFactory.h new file mode 100644 index 0000000..efbf76a --- /dev/null +++ b/src/factories/fzerox/EADLimbFactory.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +namespace FZX { + +class EADLimbData : public IParsedData { +public: + uint32_t mDl; + Vec3f mScale; + Vec3f mPos; + Vec3s mRot; + uint32_t mNextLimb; + uint32_t mChildLimb; + uint32_t mAssociatedLimb; + uint32_t mAssociatedLimbDL; + int16_t mLimbId; + + EADLimbData(uint32_t dl, Vec3f scale, Vec3f pos, Vec3s rot, uint32_t nextLimb, uint32_t childLimb, uint32_t associatedLimb, uint32_t associatedLimbDL, int16_t limbId) : + mDl(dl), + mScale(scale), + mPos(pos), + mRot(rot), + mNextLimb(nextLimb), + mChildLimb(childLimb), + mAssociatedLimb(associatedLimb), + mAssociatedLimbDL(associatedLimbDL), + mLimbId(limbId) + {} +}; + +class EADLimbHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EADLimbBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EADLimbCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EADLimbModdingExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EADLimbFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Code, EADLimbCodeExporter) + REGISTER(Header, EADLimbHeaderExporter) + REGISTER(Binary, EADLimbBinaryExporter) + }; + } +}; +} // namespace FZX -- cgit v1.2.3