#ifndef _DNAMP1_ANCS_HPP_ #define _DNAMP1_ANCS_HPP_ #include #include "../DNACommon/DNACommon.hpp" #include "../DNACommon/ANCS.hpp" #include "CMDLMaterials.hpp" #include "BlenderConnection.hpp" #include "CINF.hpp" #include "CSKR.hpp" #include "ANIM.hpp" #include "athena/FileReader.hpp" namespace DataSpec { namespace DNAMP1 { struct ANCS : BigYAML { using CINFType = CINF; using CSKRType = CSKR; using ANIMType = ANIM; DECL_YAML Value version; struct CharacterSet : BigYAML { DECL_YAML Value version; Value characterCount; struct CharacterInfo : BigYAML { DECL_YAML Delete expl; atUint32 idx; std::string name; UniqueID32 cmdl; UniqueID32 cskr; UniqueID32 cinf; struct Animation : BigYAML { DECL_YAML Value animIdx; String<-1> strA; String<-1> strB; }; std::vector animations; struct PASDatabase : BigYAML { DECL_YAML Value magic; Value animStateCount; Value defaultState; struct AnimState : BigYAML { DECL_YAML Delete expl; atUint32 id; struct ParmInfo : BigYAML { DECL_YAML Delete expl; enum class DataType { Int32 = 0, UInt32 = 1, Float = 2, Bool = 3, Enum = 4 }; union Parm { atInt32 int32; atUint32 uint32; float float32; bool bool1; Parm() : int32(0) {} Parm(atInt32 val) : int32(val) {} Parm(atUint32 val) : uint32(val) {} Parm(float val) : float32(val) {} Parm(bool val) : bool1(val) {} }; atUint32 parmType; atUint32 unk1; float unk2; Parm parmVals[2]; }; std::vector parmInfos; struct AnimInfo { atUint32 id; std::vector parmVals; }; std::vector animInfos; }; Vector animStates; } pasDatabase; struct ParticleResData { std::vector part; std::vector swhc; std::vector unk; std::vector elsc; } partResData; atUint32 unk1 = 0; struct ActionAABB : BigYAML { DECL_YAML String<-1> name; Value aabb[2]; }; std::vector animAABBs; struct Effect : BigYAML { DECL_YAML String<-1> name; Value compCount; struct EffectComponent : BigYAML { DECL_YAML String<-1> name; DNAFourCC type; UniqueID32 id; String<-1> name2; Value unk1; Value unk2; Value unk3; }; Vector comps; }; std::vector effects; UniqueID32 cmdlOverlay; UniqueID32 cskrOverlay; std::vector animIdxs; }; Vector characters; } characterSet; struct AnimationSet : BigYAML { DECL_YAML Delete expl; struct MetaAnimPrimitive; struct IMetaAnim : BigYAML { Delete expl; virtual ~IMetaAnim() {} enum class Type { Primitive = 0, Blend = 1, PhaseBlend = 2, Random = 3, Sequence = 4 } m_type; const char* m_typeStr; IMetaAnim(Type type, const char* typeStr) : m_type(type), m_typeStr(typeStr) {} virtual void gatherPrimitives(std::map>& out)=0; virtual bool enumeratePrimitives(const std::function& func)=0; }; struct MetaAnimFactory : BigYAML { DECL_YAML Delete expl; std::unique_ptr m_anim; }; struct MetaAnimPrimitive : IMetaAnim { Delete expl; MetaAnimPrimitive() : IMetaAnim(Type::Primitive, "Primitive") {} UniqueID32 animId; Value animIdx; String<-1> animName; Value unk1; Value unk2; void read(athena::io::IStreamReader& __dna_reader) { /* animId */ animId.read(__dna_reader); /* animIdx */ animIdx = __dna_reader.readUint32Big(); /* animName */ animName = __dna_reader.readString(-1); /* unk1 */ unk1 = __dna_reader.readFloatBig(); /* unk2 */ unk2 = __dna_reader.readUint32Big(); } void write(athena::io::IStreamWriter& __dna_writer) const { /* animId */ animId.write(__dna_writer); /* animIdx */ __dna_writer.writeUint32Big(animIdx); /* animName */ __dna_writer.writeString(animName, -1); /* unk1 */ __dna_writer.writeFloatBig(unk1); /* unk2 */ __dna_writer.writeUint32Big(unk2); } void read(athena::io::YAMLDocReader& __dna_docin) { /* animIdx */ animIdx = __dna_docin.readUint32("animIdx"); /* animName */ animName = __dna_docin.readString("animName"); /* unk1 */ unk1 = __dna_docin.readFloat("unk1"); /* unk2 */ unk2 = __dna_docin.readUint32("unk2"); } void write(athena::io::YAMLDocWriter& __dna_docout) const { /* animIdx */ __dna_docout.writeUint32("animIdx", animIdx); /* animName */ __dna_docout.writeString("animName", animName); /* unk1 */ __dna_docout.writeFloat("unk1", unk1); /* unk2 */ __dna_docout.writeUint32("unk2", unk2); } static const char* DNAType() { return "DataSpec::DNAMP1::ANCS::AnimationSet::MetaAnimPrimitive"; } size_t binarySize(size_t __isz) const { __isz = animId.binarySize(__isz); __isz += animName.size() + 1; return __isz + 12; } void gatherPrimitives(std::map>& out) { out[animIdx] = {animName, animId, UniqueID32(), false}; } bool enumeratePrimitives(const std::function& func) { return func(*this); } }; struct MetaAnimBlend : IMetaAnim { MetaAnimBlend() : IMetaAnim(Type::Blend, "Blend") {} DECL_YAML MetaAnimFactory animA; MetaAnimFactory animB; Value unkFloat; Value unk; void gatherPrimitives(std::map>& out) { animA.m_anim->gatherPrimitives(out); animB.m_anim->gatherPrimitives(out); } bool enumeratePrimitives(const std::function& func) { if (!animA.m_anim->enumeratePrimitives(func)) return false; if (!animB.m_anim->enumeratePrimitives(func)) return false; return true; } }; struct MetaAnimPhaseBlend : IMetaAnim { MetaAnimPhaseBlend() : IMetaAnim(Type::PhaseBlend, "PhaseBlend") {} DECL_YAML MetaAnimFactory animA; MetaAnimFactory animB; Value unkFloat; Value unk; void gatherPrimitives(std::map>& out) { animA.m_anim->gatherPrimitives(out); animB.m_anim->gatherPrimitives(out); } bool enumeratePrimitives(const std::function& func) { if (!animA.m_anim->enumeratePrimitives(func)) return false; if (!animB.m_anim->enumeratePrimitives(func)) return false; return true; } }; struct MetaAnimRandom : IMetaAnim { MetaAnimRandom() : IMetaAnim(Type::Random, "Random") {} DECL_YAML Value animCount; struct Child : BigYAML { DECL_YAML MetaAnimFactory anim; Value probability; }; Vector children; void gatherPrimitives(std::map>& out) { for (const auto& child : children) child.anim.m_anim->gatherPrimitives(out); } bool enumeratePrimitives(const std::function& func) { for (auto& child : children) if (!child.anim.m_anim->enumeratePrimitives(func)) return false; return true; } }; struct MetaAnimSequence : IMetaAnim { MetaAnimSequence() : IMetaAnim(Type::Sequence, "Sequence") {} DECL_YAML Value animCount; Vector children; void gatherPrimitives(std::map>& out) { for (const auto& child : children) child.m_anim->gatherPrimitives(out); } bool enumeratePrimitives(const std::function& func) { for (auto& child : children) if (!child.m_anim->enumeratePrimitives(func)) return false; return true; } }; struct Animation : BigYAML { DECL_YAML String<-1> name; MetaAnimFactory metaAnim; }; std::vector animations; struct IMetaTrans : BigYAML { Delete expl; virtual ~IMetaTrans() {} enum class Type { MetaAnim = 0, Trans = 1, PhaseTrans = 2, NoTrans = 3, } m_type; const char* m_typeStr; IMetaTrans(Type type, const char* typeStr) : m_type(type), m_typeStr(typeStr) {} virtual void gatherPrimitives(std::map>& out) {} virtual bool enumeratePrimitives(const std::function& func) {return true;} }; struct MetaTransFactory : BigYAML { DECL_YAML Delete expl; std::unique_ptr m_trans; }; struct MetaTransMetaAnim : IMetaTrans { MetaTransMetaAnim() : IMetaTrans(Type::MetaAnim, "MetaAnim") {} DECL_YAML MetaAnimFactory anim; void gatherPrimitives(std::map>& out) { anim.m_anim->gatherPrimitives(out); } bool enumeratePrimitives(const std::function& func) { return anim.m_anim->enumeratePrimitives(func); } }; struct MetaTransTrans : IMetaTrans { MetaTransTrans() : IMetaTrans(Type::Trans, "Trans") {} DECL_YAML Value time; Value unk1; Value unk2; Value unk3; Value unk4; }; struct MetaTransPhaseTrans : IMetaTrans { MetaTransPhaseTrans() : IMetaTrans(Type::PhaseTrans, "PhaseTrans") {} DECL_YAML Value time; Value unk1; Value unk2; Value unk3; Value unk4; }; struct Transition : BigYAML { DECL_YAML Value unk; Value animIdxA; Value animIdxB; MetaTransFactory metaTrans; }; std::vector transitions; MetaTransFactory defaultTransition; struct AdditiveAnimationInfo : BigYAML { DECL_YAML Value animIdx; Value unk1; Value unk2; }; std::vector additiveAnims; float floatA = 0.0; float floatB = 0.0; struct HalfTransition : BigYAML { DECL_YAML Value animIdx; MetaTransFactory metaTrans; }; std::vector halfTransitions; struct AnimationResources : BigYAML { DECL_YAML UniqueID32 animId; UniqueID32 evntId; }; std::vector animResources; } animationSet; void getCharacterResInfo(std::vector>& out) const { out.clear(); out.reserve(characterSet.characters.size()); for (const CharacterSet::CharacterInfo& ci : characterSet.characters) { out.emplace_back(); DNAANCS::CharacterResInfo& chOut = out.back(); chOut.name = ci.name; chOut.cmdl = ci.cmdl; chOut.cskr = ci.cskr; chOut.cinf = ci.cinf; if (ci.cmdlOverlay) chOut.overlays.emplace_back(FOURCC('OVER'), std::make_pair(ci.cmdlOverlay, ci.cskrOverlay)); } } void getAnimationResInfo(std::map>& out) const { out.clear(); for (const AnimationSet::Animation& ai : animationSet.animations) ai.metaAnim.m_anim->gatherPrimitives(out); for (const AnimationSet::Transition& ti : animationSet.transitions) if (ti.metaTrans.m_trans) ti.metaTrans.m_trans->gatherPrimitives(out); if (animationSet.defaultTransition.m_trans) animationSet.defaultTransition.m_trans->gatherPrimitives(out); for (auto& anim : out) { for (const AnimationSet::AnimationResources& res : animationSet.animResources) { if (res.animId == anim.second.animId) { anim.second.evntId = res.evntId; break; } } } } void enumeratePrimitives(const std::function& func) { for (const AnimationSet::Animation& ai : animationSet.animations) ai.metaAnim.m_anim->enumeratePrimitives(func); for (const AnimationSet::Transition& ti : animationSet.transitions) ti.metaTrans.m_trans->enumeratePrimitives(func); animationSet.defaultTransition.m_trans->enumeratePrimitives(func); } static bool Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath, PAKRouter& pakRouter, const PAK::Entry& entry, bool force, hecl::BlenderToken& btok, std::function fileChanged) { hecl::ProjectPath yamlPath = outPath.getWithExtension(_S(".yaml")); hecl::ProjectPath::Type yamlType = yamlPath.getPathType(); hecl::ProjectPath blendPath = outPath.getWithExtension(_S(".blend")); hecl::ProjectPath::Type blendType = blendPath.getPathType(); if (force || yamlType == hecl::ProjectPath::Type::None || blendType == hecl::ProjectPath::Type::None) { ANCS ancs; ancs.read(rs); if (force || yamlType == hecl::ProjectPath::Type::None) { FILE* fp = hecl::Fopen(yamlPath.getAbsolutePath().c_str(), _S("wb")); ancs.toYAMLFile(fp); fclose(fp); } if (force || blendType == hecl::ProjectPath::Type::None) { hecl::BlenderConnection& conn = btok.getBlenderConnection(); DNAANCS::ReadANCSToBlender, ANCS, MaterialSet, DNACMDL::SurfaceHeader_1, 2> (conn, ancs, blendPath, pakRouter, entry, dataSpec, fileChanged, force); } } return true; } static bool Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const DNAANCS::Actor& actor) { /* Search for yaml */ hecl::ProjectPath yamlPath = inPath.getWithExtension(_S(".yaml"), true); if (yamlPath.getPathType() != hecl::ProjectPath::Type::File) Log.report(logvisor::Fatal, _S("'%s' not found as file"), yamlPath.getRelativePath().c_str()); athena::io::FileReader yamlReader(yamlPath.getAbsolutePath()); if (!BigYAML::ValidateFromYAMLFile(yamlReader)) Log.report(logvisor::Fatal, _S("'%s' is not urde::DNAMP1::ANCS type"), yamlPath.getRelativePath().c_str()); ANCS ancs; ancs.read(yamlReader); /* Set Character Resource IDs */ for (ANCS::CharacterSet::CharacterInfo& ch : ancs.characterSet.characters) { hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(ch.cmdl); if (path) ch.cskr = path.ensureAuxInfo(_S("skin")); for (const DNAANCS::Actor::Subtype& sub : actor.subtypes) { if (!sub.name.compare(ch.name)) { if (sub.armature >= 0) { const DNAANCS::Actor::Armature& arm = actor.armatures[sub.armature]; hecl::SystemStringView chSysName(arm.name); ch.cinf = inPath.ensureAuxInfo(chSysName.c_str()); break; } } } path = UniqueIDBridge::TranslatePakIdToPath(ch.cmdlOverlay); if (path) ch.cskrOverlay = path.ensureAuxInfo(_S("skin")); } /* Set Animation Resource IDs */ ancs.enumeratePrimitives([&](AnimationSet::MetaAnimPrimitive& prim) -> bool { hecl::SystemStringView sysStr(prim.animName); prim.animId = inPath.ensureAuxInfo(sysStr.c_str()); return true; }); /* Write out CINF resources */ for (const DNAANCS::Actor::Armature& arm : actor.armatures) { hecl::SystemStringView sysStr(arm.name); hecl::ProjectPath pathOut = inPath.getWithExtension(sysStr.c_str(), true); athena::io::FileWriter w(pathOut.getAbsolutePath(), true, false); if (w.hasError()) Log.report(logvisor::Fatal, _S("unable to open '%s' for writing"), pathOut.getRelativePath().c_str()); CINF cinf(arm); cinf.write(w); } return true; } }; } } #endif // _DNAMP1_ANCS_HPP_