diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b270c7c..6f3d2ff7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,8 @@ add_executable(uking src/KingSystem/Resource/resResource.h src/KingSystem/Resource/resResourceActorLink.cpp src/KingSystem/Resource/resResourceActorLink.h + src/KingSystem/Resource/resResourceAIProgram.cpp + src/KingSystem/Resource/resResourceAIProgram.h src/KingSystem/Resource/resResourceArchive.cpp src/KingSystem/Resource/resResourceArchive.h src/KingSystem/Resource/resResourceDemo.cpp diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 131a1c5f..af2901bd 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -88859,7 +88859,7 @@ 0x00000071011802bc,sub_71011802BC,156, 0x0000007101180358,sub_7101180358,8, 0x0000007101180360,sub_7101180360,8, -0x0000007101180368,Aiprog::ctor,352, +0x0000007101180368,Aiprog::ctor,352,_ZN4ksys3res9AIProgramC1Ev 0x00000071011804c8,sub_71011804C8,68, 0x000000710118050c,sub_710118050C,76, 0x0000007101180558,sub_7101180558,132, @@ -89224,37 +89224,37 @@ 0x00000071011a7f38,sub_71011A7F38,12, 0x00000071011a7f44,sub_71011A7F44,12, 0x00000071011a80c4,sub_71011A80C4,140, -0x00000071011a8150,sub_71011A8150,108, -0x00000071011a81bc,ResourceAiprog::m2,104, -0x00000071011a8224,sub_71011A8224,112, -0x00000071011a8294,sub_71011A8294,108, -0x00000071011a8300,ResourceAiprog::m3,104, -0x00000071011a8368,sub_71011A8368,112, -0x00000071011a83d8,Aiprog::x,312, -0x00000071011a8510,Aiprog::x_0,256, -0x00000071011a8610,Aiprog::x_1,256, -0x00000071011a8710,sub_71011A8710,68, -0x00000071011a8754,ResourceAiprog::doCreate,68, -0x00000071011a8798,Aiprog::parse,1116, -0x00000071011a8bf4,Aiprog::parseListAIAction,2624, -0x00000071011a9634,Aiprog::parseListBehavior,1204, -0x00000071011a9ae8,Aiprog::parseListQuery,1204, -0x00000071011a9f9c,ResourceAiprog::parse,8, -0x00000071011a9fa4,Aiprog::m5,196, -0x00000071011aa068,ResourceAiprog::m5,8, -0x00000071011aa070,Aiprog::loadDefParameters,1556, -0x00000071011aa684,sub_71011AA684,256, -0x00000071011aa784,Aiprog::getActionsOrAIs,20, -0x00000071011aa840,Aiprog::x_2,208, -0x00000071011aa910,sub_71011AA910,156, -0x00000071011aaa48,Aiprog::x_3,156, -0x00000071011aaae4,sub_71011AAAE4,168, -0x00000071011aab8c,sub_71011AAB8C,8, -0x00000071011aab94,sub_71011AAB94,92, -0x00000071011aabf0,sub_71011AABF0,8, -0x00000071011aabf8,ResourceAiprog::m0,8, -0x00000071011aac00,ResourceAiprog::m1,92, -0x00000071011aac5c,ResourceAiprog::needsParse,8, +0x00000071011a8150,sub_71011A8150,108,_ZN4ksys3res9AIProgramD1Ev +0x00000071011a81bc,ResourceAiprog::m2,104,_ZThn632_N4ksys3res9AIProgramD1Ev +0x00000071011a8224,sub_71011A8224,112,_ZThn664_N4ksys3res9AIProgramD1Ev +0x00000071011a8294,sub_71011A8294,108,_ZN4ksys3res9AIProgramD0Ev +0x00000071011a8300,ResourceAiprog::m3,104,_ZThn632_N4ksys3res9AIProgramD0Ev +0x00000071011a8368,sub_71011A8368,112,_ZThn664_N4ksys3res9AIProgramD0Ev +0x00000071011a83d8,Aiprog::x,312,_ZN4ksys3res9AIProgram17finalizeAIActionsERN4sead6BufferINS1_11AIActionDefEEE +0x00000071011a8510,Aiprog::x_0,256,_ZN4ksys3res9AIProgram17finalizeBehaviorsEv +0x00000071011a8610,Aiprog::x_1,256,_ZN4ksys3res9AIProgram15finalizeQueriesEv +0x00000071011a8710,sub_71011A8710,68,_ZN4ksys3res9AIProgram9doCreate_EPhjPN4sead4HeapE +0x00000071011a8754,ResourceAiprog::doCreate,68,_ZThn632_N4ksys3res9AIProgram9doCreate_EPhjPN4sead4HeapE +0x00000071011a8798,Aiprog::parse,1116,_ZN4ksys3res9AIProgram6parse_EPhmPN4sead4HeapE! +0x00000071011a8bf4,Aiprog::parseListAIAction,2624,_ZN4ksys3res9AIProgram14parseAIActionsERN4sead6BufferINS1_11AIActionDefEEEPNS2_4HeapERN3agl3utl13ParameterListERKNSA_16ResParameterListEPKc! +0x00000071011a9634,Aiprog::parseListBehavior,1204,_ZN4ksys3res9AIProgram14parseBehaviorsEPN4sead4HeapERKN3agl3utl16ResParameterListE +0x00000071011a9ae8,Aiprog::parseListQuery,1204,_ZN4ksys3res9AIProgram12parseQueriesEPN4sead4HeapERKN3agl3utl16ResParameterListE +0x00000071011a9f9c,ResourceAiprog::parse,8,_ZThn632_N4ksys3res9AIProgram6parse_EPhmPN4sead4HeapE +0x00000071011a9fa4,Aiprog::m5,196,_ZN4ksys3res9AIProgram9finalize_Ev? +0x00000071011aa068,ResourceAiprog::m5,8,_ZThn632_N4ksys3res9AIProgram9finalize_Ev +0x00000071011aa070,Aiprog::loadDefParameters,1556,_ZN4ksys3res9AIProgram14parseDefParamsEPNS1_10DefinitionEPvPN4sead4HeapERKN3agl3utl16ResParameterListEPtSD_ +0x00000071011aa684,sub_71011AA684,256,_ZN4ksys3res9AIProgram10Definition14addSInstParam_IN4sead14SafeStringBaseIcEEEEbiPKcPNS4_4HeapERKT_ +0x00000071011aa784,Aiprog::getActionsOrAIs,20,_ZNK4ksys3res9AIProgram15getActionsOrAIsENS1_12AIActionTypeE +0x00000071011aa840,Aiprog::x_2,208,_ZNK4ksys3res9AIProgram13getSInstParamEPN4sead14SafeStringBaseIcEERKNS1_10DefinitionERKS4_ +0x00000071011aa910,sub_71011AA910,156,_ZNK4ksys3res9AIProgram13getSInstParamEPPKiRKNS1_10DefinitionERKN4sead14SafeStringBaseIcEE? +0x00000071011aaa48,Aiprog::x_3,156,_ZNK4ksys3res9AIProgram13getSInstParamEPPKN4sead7Vector3IfEERKNS1_10DefinitionERKNS2_14SafeStringBaseIcEE? +0x00000071011aaae4,sub_71011AAAE4,168,_ZNK4ksys3res9AIProgram13getSInstParamEPPKbRKNS1_10DefinitionERKN4sead14SafeStringBaseIcEE +0x00000071011aab8c,sub_71011AAB8C,8,_ZNK4ksys3res9AIProgram27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE? +0x00000071011aab94,sub_71011AAB94,92,_ZNK4ksys3res9AIProgram18getRuntimeTypeInfoEv +0x00000071011aabf0,sub_71011AABF0,8,_ZNK4ksys3res9AIProgram10needsParseEv +0x00000071011aabf8,ResourceAiprog::m0,8,_ZThn632_NK4ksys3res9AIProgram27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE? +0x00000071011aac00,ResourceAiprog::m1,92,_ZThn632_NK4ksys3res9AIProgram18getRuntimeTypeInfoEv +0x00000071011aac5c,ResourceAiprog::needsParse,8,_ZThn632_NK4ksys3res9AIProgram10needsParseEv 0x00000071011aadd8,sub_71011AADD8,364, 0x00000071011aaf44,sub_71011AAF44,140, 0x00000071011aafd0,sub_71011AAFD0,136, diff --git a/lib/agl b/lib/agl index 27e919f2..2f5bcf2d 160000 --- a/lib/agl +++ b/lib/agl @@ -1 +1 @@ -Subproject commit 27e919f21530a5c7b2186d9c616f9ad590b71496 +Subproject commit 2f5bcf2d6617da25a9d60470ae4e5da8380965a1 diff --git a/src/KingSystem/ActorSystem/actAiClassDef.h b/src/KingSystem/ActorSystem/actAiClassDef.h new file mode 100644 index 00000000..d3f3adad --- /dev/null +++ b/src/KingSystem/ActorSystem/actAiClassDef.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include +#include "KingSystem/Utils/Types.h" + +namespace ksys { + +enum class AIDefType { + AI = 0, + Action = 1, + Behavior = 2, + Query = 3, +}; + +enum class AIDefInstParamKind { + Static = 0, + Dynamic = 1, + MapUnit = 2, + AITree = 3, +}; + +enum class AIDefParamType { + String = 0, + Int = 1, + Float = 2, + Vec3 = 3, + Bool = 4, + Tree = 5, + AITreeVariablePointer = 6, + UInt = 7, + BaseProcLink = 8, + MesTransceiverId = 9, + BaseProcHandle = 10, + Rail = 11, + Other = 12, +}; + +struct AIDef { + union Value { + u8 raw[16]; + }; + + static constexpr size_t NumParametersMax = 64; + + const char* param_names[NumParametersMax]; + sead::SizedEnum param_types[NumParametersMax]; + s32 num_params; + u32 calc_timing; + bool no_stop; + bool trigger_action; + bool dynamic_param_child; + u8 _24b; + Value param_values[NumParametersMax]; +}; +KSYS_CHECK_SIZE_NX150(AIDef, 0x650); + +// FIXME +class AIClassDef { + SEAD_SINGLETON_DISPOSER(AIClassDef) +public: + void init(const sead::SafeString& aidef_file_name, sead::Heap* heap); + + void getDef(AIDef* def, const sead::SafeString& class_name, AIDefInstParamKind param_kind, + AIDefType class_type); + +private: + class Data; + + Data* mData; + // res::Handle mResHandle; +}; +// KSYS_CHECK_SIZE_NX150(AIClassDef, 0x78); + +} // namespace ksys diff --git a/src/KingSystem/ActorSystem/actAiParam.cpp b/src/KingSystem/ActorSystem/actAiParam.cpp index 5343ff07..094cd362 100644 --- a/src/KingSystem/ActorSystem/actAiParam.cpp +++ b/src/KingSystem/ActorSystem/actAiParam.cpp @@ -8,38 +8,38 @@ ParamPack::~ParamPack() { auto* param = mParams; while (param) { if (param->data) { - switch (Param::Type(param->type)) { - case Param::Type::String: + switch (param->type) { + case AIDefParamType::String: delete static_cast(param->data); break; - case Param::Type::Int: + case AIDefParamType::Int: delete static_cast(param->data); break; - case Param::Type::Float: + case AIDefParamType::Float: delete static_cast(param->data); break; - case Param::Type::Vec3: + case AIDefParamType::Vec3: delete static_cast(param->data); break; - case Param::Type::Bool: + case AIDefParamType::Bool: delete static_cast(param->data); break; - case Param::Type::AITreeVariablePointer: + case AIDefParamType::AITreeVariablePointer: delete static_cast(param->data); break; - case Param::Type::UInt: + case AIDefParamType::UInt: delete static_cast(param->data); break; - case Param::Type::MesTransceiverId: + case AIDefParamType::MesTransceiverId: delete static_cast(param->data); break; - case Param::Type::BaseProcHandle: + case AIDefParamType::BaseProcHandle: delete static_cast(param->data); break; - case Param::Type::Rail: + case AIDefParamType::Rail: delete static_cast(param->data); break; - case Param::Type::BaseProcLink: + case AIDefParamType::BaseProcLink: delete static_cast(param->data); break; default: @@ -58,47 +58,47 @@ void InlineParamPack::copyToParamPack(ParamPack& pack) const { const InlineParam* param = params; for (u32 i = 0; i < n; ++i, ++param) { switch (param->type) { - case Param::Type::String: { + case AIDefParamType::String: { const sead::SafeString src = param->cstr; const sead::SafeString key = param->key; - auto* dst = pack.getVariable(key, Param::Type::String); + auto* dst = pack.getVariable(key, AIDefParamType::String); if (dst) dst->copy(src); break; } - case Param::Type::Int: - pack.setVariable(param->key, Param::Type::Int, param->i); + case AIDefParamType::Int: + pack.setVariable(param->key, AIDefParamType::Int, param->i); break; - case Param::Type::Float: - pack.setVariable(param->key, Param::Type::Float, param->f); + case AIDefParamType::Float: + pack.setVariable(param->key, AIDefParamType::Float, param->f); break; - case Param::Type::Vec3: - if (auto* dst = pack.getVariable(param->key, Param::Type::Vec3)) { + case AIDefParamType::Vec3: + if (auto* dst = pack.getVariable(param->key, AIDefParamType::Vec3)) { dst->x = param->vec3.x; dst->y = param->vec3.y; dst->z = param->vec3.z; } break; - case Param::Type::Bool: - pack.setVariable(param->key, Param::Type::Bool, param->b); + case AIDefParamType::Bool: + pack.setVariable(param->key, AIDefParamType::Bool, param->b); break; - case Param::Type::UInt: - pack.setVariable(param->key, Param::Type::UInt, param->u); + case AIDefParamType::UInt: + pack.setVariable(param->key, AIDefParamType::UInt, param->u); break; - case Param::Type::BaseProcLink: - pack.setVariable(param->key, Param::Type::BaseProcLink, param->baseProcLink); + case AIDefParamType::BaseProcLink: + pack.setVariable(param->key, AIDefParamType::BaseProcLink, param->baseProcLink); break; - case Param::Type::MesTransceiverId: - pack.setVariable(param->key, Param::Type::MesTransceiverId, param->mesTransceiverId); + case AIDefParamType::MesTransceiverId: + pack.setVariable(param->key, AIDefParamType::MesTransceiverId, param->mesTransceiverId); break; - case Param::Type::BaseProcHandle: { + case AIDefParamType::BaseProcHandle: { auto* baseProcHandle = static_cast(param->ptr); - pack.setVariable(param->key, Param::Type::BaseProcHandle, baseProcHandle); + pack.setVariable(param->key, AIDefParamType::BaseProcHandle, baseProcHandle); break; } - case Param::Type::Rail: { + case AIDefParamType::Rail: { auto* rail = static_cast(param->ptr); - pack.setVariable(param->key, Param::Type::Rail, rail); + pack.setVariable(param->key, AIDefParamType::Rail, rail); break; } default: diff --git a/src/KingSystem/ActorSystem/actAiParam.h b/src/KingSystem/ActorSystem/actAiParam.h index b15e9807..69fedc2b 100644 --- a/src/KingSystem/ActorSystem/actAiParam.h +++ b/src/KingSystem/ActorSystem/actAiParam.h @@ -4,7 +4,9 @@ #include #include #include +#include +#include "KingSystem/ActorSystem/actAiClassDef.h" #include "KingSystem/ActorSystem/actBaseProc.h" #include "KingSystem/ActorSystem/actBaseProcLink.h" #include "KingSystem/MessageSystem/mesTransceiver.h" @@ -17,27 +19,11 @@ class Rail; namespace act::ai { struct Param { - enum class Type { - String = 0, - Int = 1, - Float = 2, - Vec3 = 3, - Bool = 4, - Tree = 5, - AITreeVariablePointer = 6, - UInt = 7, - BaseProcLink = 8, - MesTransceiverId = 9, - BaseProcHandle = 10, - Rail = 11, - Other = 12, - }; - Param* next; u32 hash; const char* name; void* data; - u16 type; + sead::SizedEnum type; bool used; u8 _23; }; @@ -49,12 +35,12 @@ public: ~ParamPack(); template - T* getVariable(const sead::SafeString& key, Param::Type type, bool a4 = true) const { + T* getVariable(const sead::SafeString& key, AIDefParamType type, bool a4 = true) const { const u32 hash = agl::utl::ParameterBase::calcHash(key); auto* param = mParams; if (!param) return nullptr; - while (param->hash != hash || Param::Type(param->type) != type) { + while (param->hash != hash || param->type != type) { param = param->next; if (!param) return nullptr; @@ -65,7 +51,7 @@ public: } template - void setVariable(const sead::SafeString& key, Param::Type type, const T& val) const { + void setVariable(const sead::SafeString& key, AIDefParamType type, const T& val) const { T* variable = getVariable(key, type, true); if (variable) *variable = val; @@ -87,7 +73,7 @@ struct InlineParam { BaseProcLink baseProcLink; sead::Vector3f vec3; mes::TransceiverId mesTransceiverId; - Param::Type type; + AIDefParamType type; const char* key; }; KSYS_CHECK_SIZE_NX150(InlineParam, 0x50); diff --git a/src/KingSystem/Resource/resResourceAIProgram.cpp b/src/KingSystem/Resource/resResourceAIProgram.cpp new file mode 100644 index 00000000..fad0ce6f --- /dev/null +++ b/src/KingSystem/Resource/resResourceAIProgram.cpp @@ -0,0 +1,447 @@ +#include "KingSystem/Resource/resResourceAIProgram.h" +#include +#include +#include "KingSystem/ActorSystem/actAiClassDef.h" +#include "KingSystem/Resource/resCurrentResNameMgr.h" +#include "KingSystem/Utils/HeapUtil.h" + +namespace ksys::res { + +AIProgram::AIProgram() : ParamIO("aiprog", 0) {} + +AIProgram::~AIProgram() = default; + +const sead::Buffer& AIProgram::getActionsOrAIs(AIActionType type) const { + return type == AIActionType::AI ? mAIs : mActions; +} + +void AIProgram::doCreate_(u8*, u32, sead::Heap*) { + mStr = CurrentResNameMgr::instance()->getCurrentResName(); +} + +static bool parseAIActionIdx(agl::utl::ResParameterObj obj, sead::Buffer& buffer, + sead::Heap* heap, bool clear = false) { + if (obj.ptr() == nullptr) + return true; + + const auto num = obj.getNum(); + if (num == 0) + return true; + + if (!buffer.tryAllocBuffer(num, heap)) + return false; + + if (clear) { + for (s32 i = 0; i < num; ++i) + buffer(i) = 0; + } + + auto it = buffer.begin(), it_end = buffer.end(); + auto it_res = obj.begin(), it_res_end = obj.end(); + auto* res_ptr = it_res.getParam().ptr(); + for (; it != it_end && it_res != it_res_end; ++it, ++it_res) + *it = *agl::utl::ResParameter{res_ptr + it.getIndex()}.getData(); + + return true; +} + +static bool parseBehaviorIdx(agl::utl::ResParameterObj obj, sead::Buffer& buffer, + sead::Heap* heap) { + if (obj.ptr() == nullptr) + return true; + + const auto num = obj.getNum(); + if (num == 0) + return true; + + if (!buffer.tryAllocBuffer(num, heap)) + return false; + + for (s32 i = 0; i < num; ++i) + buffer(i) = 0; + + auto it = buffer.begin(), it_end = buffer.end(); + auto it_res = obj.begin(), it_res_end = obj.end(); + for (; it != it_end && it_res != it_res_end; ++it, ++it_res) + *it = *it_res.getParam().getData(); + + return true; +} + +// NON_MATCHING: the parameter iteration loops in parseAIActionIdx and parseBehaviorIdx +bool AIProgram::parse_(u8* data, size_t, sead::Heap* parent_heap) { + if (data) { + auto* heap = util::tryCreateDualHeap(parent_heap); + mHeap = heap; + if (!heap) + return false; + + heap->enableWarning(false); + heap = mHeap; + + agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + + if (!parseAIActions(mAIs, heap, mParamListAI, root, "AI") || + !parseAIActions(mActions, heap, mParamListAction, root, "Action") || + !parseBehaviors(heap, root) || !parseQueries(heap, root)) { + return false; + } + + const auto ai_idx_obj = agl::utl::getResParameterObj(root, "DemoAIActionIdx"); + if (!parseAIActionIdx(ai_idx_obj, mDemoAIActionIndices, heap)) { + mHeap->adjust(); + return false; + } + + const auto behavior_idx_obj = agl::utl::getResParameterObj(root, "DemoBehaviorIdx"); + if (!parseBehaviorIdx(behavior_idx_obj, mDemoBehaviorIndices, heap)) { + mHeap->adjust(); + return false; + } + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + } + + mHeap->adjust(); + return true; +} + +// NON_MATCHING: the parameter iteration loops in parseAIActionIdx and parseBehaviorIdx +bool AIProgram::parseAIActions(sead::Buffer& defs, sead::Heap* heap, + agl::utl::ParameterList& target_list, + const agl::utl::ResParameterList& root, const char* type_name) { + const auto list = agl::utl::getResParameterList(root, type_name); + if (!list.ptr()) + return false; + + const auto num = list.getResParameterListNum(); + if (num == 0) + return true; + + if (!defs.tryAllocBuffer(num, heap)) + return false; + + for (auto& action : defs) { + action.mClassName = ""; + action.mName = ""; + action.mGroupName = ""; + } + + auto it_res = list.listBegin(); + const auto it_res_end = list.listEnd(); + + sead::FixedSafeString<32> list_name{type_name}; + list_name.append("_"); + const s32 trim_length = list_name.calcLength(); + + auto it = defs.begin(); + const auto it_end = defs.end(); + for (; it != it_end && it_res != it_res_end; ++it, ++it_res) { + list_name.trim(trim_length); + list_name.appendWithFormat("%d", it.getIndex()); + target_list.addList(&it->mList, list_name); + + const auto res = *it_res; + const auto def_obj = agl::utl::getResParameterObj(res, "Def"); + if (def_obj.ptr()) { + it->mName = agl::utl::getResParameter(def_obj, "Name").getData(); + it->mClassName = agl::utl::getResParameter(def_obj, "ClassName").getData(); + + const auto group_name = agl::utl::getResParameter(def_obj, "GroupName"); + if (group_name.ptr()) + it->mGroupName = group_name.getData(); + else + it->mGroupName = ""; + } + + const auto child_idx_obj = agl::utl::getResParameterObj(res, "ChildIdx"); + if (!parseAIActionIdx(child_idx_obj, it->mChildIndices, heap, true)) + return false; + + const auto behavior_idx_obj = agl::utl::getResParameterObj(res, "BehaviorIdx"); + if (!parseBehaviorIdx(behavior_idx_obj, it->mBehaviorIndices, heap)) + return false; + + if (!parseDefParams(&*it, &defs, heap, res, &it->mTriggerAction, &it->mDynamicParamChild)) + return false; + } + + addList(&target_list, type_name); + return true; +} + +bool AIProgram::parseBehaviors(sead::Heap* heap, const agl::utl::ResParameterList& root) { + const auto list = agl::utl::getResParameterList(root, "Behavior"); + if (!list.ptr()) + return true; + + const auto num = list.getResParameterListNum(); + if (num == 0) + return true; + + if (!mBehaviors.tryAllocBuffer(num, heap)) + return false; + + for (auto& behavior : mBehaviors) { + behavior.mClassName = ""; + behavior.mName = ""; + } + + auto it_res = list.listBegin(); + const auto it_res_end = list.listEnd(); + + sead::FixedSafeString<32> list_name{"Behavior_"}; + const s32 trim_length = list_name.calcLength(); + + auto it = mBehaviors.begin(); + const auto it_end = mBehaviors.end(); + for (; it != it_end && it_res != it_res_end; ++it, ++it_res) { + list_name.trim(trim_length); + list_name.appendWithFormat("%d", it.getIndex()); + mParamListBehavior.addList(&it->mList, list_name); + + const auto res = *it_res; + const auto obj = agl::utl::getResParameterObj(res, "Def"); + if (obj.ptr()) { + const auto name_param = agl::utl::getResParameter(obj, "ClassName"); + it->mClassName = name_param.getData(); + } + + if (!parseDefParams(&*it, &mBehaviors, heap, res, &it->mCalcTiming, &it->mNoStop)) + return false; + } + + addList(&mParamListBehavior, "Behavior"); + return true; +} + +bool AIProgram::parseQueries(sead::Heap* heap, const agl::utl::ResParameterList& root) { + const auto list = agl::utl::getResParameterList(root, "Query"); + if (!list.ptr()) + return true; + + const auto num = list.getResParameterListNum(); + if (num == 0) + return true; + + if (!mQueries.tryAllocBuffer(num, heap)) + return false; + + for (auto& query : mQueries) { + query.mClassName = ""; + query.mName = ""; + } + + auto it_res = list.listBegin(); + const auto it_res_end = list.listEnd(); + + sead::FixedSafeString<32> list_name{"Query_"}; + const s32 trim_length = list_name.calcLength(); + + auto it = mQueries.begin(); + const auto it_end = mQueries.end(); + for (; it != it_end && it_res != it_res_end; ++it, ++it_res) { + list_name.trim(trim_length); + list_name.appendWithFormat("%d", it.getIndex()); + mParamListQuery.addList(&it->mList, list_name); + + const auto res = *it_res; + const auto obj = agl::utl::getResParameterObj(res, "Def"); + if (obj.ptr()) { + const auto name_param = agl::utl::getResParameter(obj, "ClassName"); + it->mClassName = name_param.getData(); + } + + if (!parseDefParams(&*it, &mQueries, heap, res, nullptr, nullptr)) + return false; + } + + addList(&mParamListQuery, "Query"); + return true; +} + +void AIProgram::finalize_() { + { + sead::ScopedCurrentHeapSetter setter{mHeap}; + + finalizeAIActions(mAIs); + finalizeAIActions(mActions); + finalizeBehaviors(); + finalizeQueries(); + mDemoBehaviorIndices.freeBuffer(); + mDemoAIActionIndices.freeBuffer(); + } + + if (mHeap) { + mHeap->destroy(); + mHeap = nullptr; + } +} + +void AIProgram::Definition::finalize_() { + for (auto*& param : mSInstParams) { + if (param) { + delete param; + param = nullptr; + } + } + mSInstParams.freeBuffer(); +} + +void AIProgram::AIActionDef::finalize_() { + Definition::finalize_(); + mChildIndices.freeBuffer(); + mBehaviorIndices.freeBuffer(); +} + +void AIProgram::finalizeAIActions(sead::Buffer& defs) { + for (auto& def : defs) + def.finalize_(); + defs.freeBuffer(); +} + +void AIProgram::finalizeBehaviors() { + for (auto& def : mBehaviors) + def.finalize_(); + mBehaviors.freeBuffer(); +} + +void AIProgram::finalizeQueries() { + for (auto& def : mQueries) + def.finalize_(); + mQueries.freeBuffer(); +} + +const agl::utl::ParameterBase* AIProgram::Definition::findSInstParam(u32 name_hash) const { + for (const auto* param : mSInstParams) { + if (param && param->getNameHash() == name_hash) + return param; + } + return nullptr; +} + +const agl::utl::ParameterBase* +AIProgram::Definition::findSInstParam(const sead::SafeString& name) const { + return findSInstParam(agl::utl::ParameterBase::calcHash(name)); +} + +bool AIProgram::getSInstParam(sead::SafeString* value, const AIProgram::Definition& def, + const sead::SafeString& param_name) const { + const auto* param = def.findSInstParam(param_name); + if (!param || param->getParameterType() != agl::utl::ParameterType::StringRef) { + *value = sead::SafeString::cEmptyString; + return false; + } + *value = param->ptrT(); + return true; +} + +bool AIProgram::getSInstParam(const s32** value, const AIProgram::Definition& def, + const sead::SafeString& param_name) const { + static const s32 sDefault{}; + return getSInstParam_(value, def, param_name, agl::utl::ParameterType::Int, &sDefault); +} + +bool AIProgram::getSInstParam(const sead::Vector3f** value, const AIProgram::Definition& def, + const sead::SafeString& param_name) const { + return getSInstParam_(value, def, param_name, agl::utl::ParameterType::Vec3, + &sead::Vector3f::zero); +} + +bool AIProgram::getSInstParam(const bool** value, const AIProgram::Definition& def, + const sead::SafeString& param_name) const { + static const bool sDefault{}; + return getSInstParam_(value, def, param_name, agl::utl::ParameterType::Bool, &sDefault); +} + +bool AIProgram::parseDefParams(AIProgram::Definition* def, void* buffer, sead::Heap* heap, + const agl::utl::ResParameterList& res, u16* param1, u16* param2) { + const auto sinst_obj = agl::utl::getResParameterObj(res, "SInst"); + const s32 sinst_num_params = sinst_obj.ptr() ? sinst_obj.getNum() : 0; + + AIDef aidef; + + if (&mAIs == buffer) { + AIClassDef::instance()->getDef(&aidef, def->mClassName, AIDefInstParamKind::Static, + AIDefType::AI); + *param1 = aidef.trigger_action; + *param2 = aidef.dynamic_param_child; + } else if (&mActions == buffer) { + AIClassDef::instance()->getDef(&aidef, def->mClassName, AIDefInstParamKind::Static, + AIDefType::Action); + *param1 = aidef.trigger_action; + *param2 = 0; + } else if (&mBehaviors == buffer) { + AIClassDef::instance()->getDef(&aidef, def->mClassName, AIDefInstParamKind::Static, + AIDefType::Behavior); + *param1 = aidef.calc_timing; + *param2 = aidef.no_stop; + } else { + AIClassDef::instance()->getDef(&aidef, def->mClassName, AIDefInstParamKind::Static, + AIDefType::Query); + } + + if (sinst_num_params != 0) { + const auto num_params = + aidef.num_params < sinst_num_params ? aidef.num_params : sinst_num_params; + + if (!def->mSInstParams.tryAllocBuffer(sinst_num_params, heap)) + return false; + + for (s32 i = 0; i < sinst_num_params; ++i) + def->mSInstParams[i] = nullptr; + + for (s32 i = 0; i < num_params; ++i) { + const char* name = aidef.param_names[i]; + switch (aidef.param_types[i]) { + case AIDefParamType::String: + case AIDefParamType::Tree: + if (!def->addSInstParam_(i, name, heap, "")) + return false; + break; + case AIDefParamType::UInt: + if (!def->addSInstParam_(i, name, heap, 0)) + return false; + break; + case AIDefParamType::Int: + if (!def->addSInstParam_(i, name, heap, 0)) + return false; + break; + case AIDefParamType::Float: + if (!def->addSInstParam_(i, name, heap, 0)) + return false; + break; + case AIDefParamType::Vec3: + if (!def->addSInstParam_(i, name, heap, sead::Vector3f::zero)) + return false; + break; + case AIDefParamType::Bool: + if (!def->addSInstParam_(i, name, heap, false)) + return false; + break; + default: + def->mSInstParams[i] = nullptr; + break; + } + } + } + + def->mList.addObj(&def->mSInstObj, "SInst"); + return true; +} + +template +bool AIProgram::Definition::addSInstParam_(s32 idx, const char* name, sead::Heap* heap, + const T& value) { + mSInstParams[idx] = new (heap) agl::utl::Parameter; + + auto* param = static_cast*>(mSInstParams[idx]); + if (!param) + return false; + + param->initializeParameter(value, name, name, &mSInstObj); + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/resResourceAIProgram.h b/src/KingSystem/Resource/resResourceAIProgram.h new file mode 100644 index 00000000..a7781937 --- /dev/null +++ b/src/KingSystem/Resource/resResourceAIProgram.h @@ -0,0 +1,138 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class AIProgram : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(AIProgram, Resource) +public: + enum class AIActionType { + AI = 0, + Action = 1, + }; + + struct Definition { + const agl::utl::ParameterBase* findSInstParam(u32 name_hash) const; + const agl::utl::ParameterBase* findSInstParam(const sead::SafeString& name) const; + + template + bool addSInstParam_(s32 idx, const char* name, sead::Heap* heap, const T& value); + + void finalize_(); + + agl::utl::ParameterList mList; + const char* mClassName; + const char* mName; + sead::Buffer mSInstParams; + agl::utl::ParameterObj mSInstObj; + }; + KSYS_CHECK_SIZE_NX150(Definition, 0x98); + + struct AIActionDef : Definition { + void finalize_(); + + const char* mGroupName; + sead::Buffer mChildIndices; + sead::Buffer mBehaviorIndices; + u16 mTriggerAction; + u16 mDynamicParamChild; + u16 _c4; + }; + KSYS_CHECK_SIZE_NX150(AIActionDef, 0xc8); + + struct BehaviorDef : Definition { + u16 mCalcTiming; + u16 mNoStop; + }; + KSYS_CHECK_SIZE_NX150(BehaviorDef, 0xa0); + + struct QueryDef : Definition {}; + KSYS_CHECK_SIZE_NX150(QueryDef, 0x98); + + AIProgram(); + ~AIProgram() override; + + const sead::Buffer& getActionsOrAIs(AIActionType type) const; + const sead::Buffer& getBehaviors() const { return mBehaviors; } + const sead::Buffer& getQueries() const { return mQueries; } + + bool getSInstParam(sead::SafeString* value, const Definition& def, + const sead::SafeString& param_name) const; + bool getSInstParam(const f32** value, const Definition& def, + const sead::SafeString& param_name) const; + bool getSInstParam(const s32** value, const Definition& def, + const sead::SafeString& param_name) const; + bool getSInstParam(const sead::Vector3f** value, const Definition& def, + const sead::SafeString& param_name) const; + bool getSInstParam(const bool** value, const Definition& def, + const sead::SafeString& param_name) const; + + void doCreate_(u8* buffer, u32 bufferSize, sead::Heap* heap) override; + bool needsParse() const override { return true; } + +private: + bool parse_(u8* data, size_t size, sead::Heap* parent_heap) override; + bool parseAIActions(sead::Buffer& defs, sead::Heap* heap, + agl::utl::ParameterList& target_list, + const agl::utl::ResParameterList& root, const char* type_name); + bool parseBehaviors(sead::Heap* heap, const agl::utl::ResParameterList& root); + bool parseQueries(sead::Heap* heap, const agl::utl::ResParameterList& root); + bool parseDefParams(Definition* def, void* buffer, sead::Heap* heap, + const agl::utl::ResParameterList& res, u16* param1, u16* param2); + + void finalize_() override; + void finalizeAIActions(sead::Buffer& defs); + void finalizeBehaviors(); + void finalizeQueries(); + + template + bool getSInstParam_(const T** value, const Definition& def, const sead::SafeString& param_name, + agl::utl::ParameterType param_type, const T* default_value) const; + + sead::Heap* mHeap = nullptr; + sead::SafeString mStr; + + sead::Buffer mAIs; + sead::Buffer mActions; + sead::Buffer mBehaviors; + sead::Buffer mQueries; + + agl::utl::ParameterList mParamListAI; + agl::utl::ParameterList mParamListAction; + agl::utl::ParameterList mParamListBehavior; + agl::utl::ParameterList mParamListQuery; + + sead::Buffer mDemoAIActionIndices; + sead::Buffer mDemoBehaviorIndices; +}; +KSYS_CHECK_SIZE_NX150(AIProgram, 0x448); + +template +inline bool AIProgram::getSInstParam_(const T** value, const AIProgram::Definition& def, + const sead::SafeString& param_name, + agl::utl::ParameterType param_type, + const T* default_value) const { + const auto* param = def.findSInstParam(param_name); + if (!param || param->getParameterType() != param_type) { + *value = default_value; + return false; + } + *value = param->ptrT(); + return true; +} + +inline bool AIProgram::getSInstParam(const f32** value, const AIProgram::Definition& def, + const sead::SafeString& param_name) const { + static const f32 sDefault{}; + return getSInstParam_(value, def, param_name, agl::utl::ParameterType::F32, &sDefault); +} + +} // namespace ksys::res