diff options
| author | Léo Lam <leo@leolam.fr> | 2021-06-15 17:47:03 +0200 |
|---|---|---|
| committer | Léo Lam <leo@leolam.fr> | 2021-06-15 18:04:39 +0200 |
| commit | dd0cc52ce99b9d78f1c7022c1bf13349149f263a (patch) | |
| tree | 2eb5acd7d704d612181399bd8ab2be7b84fe450f /src/KingSystem/Resource/Actor | |
| parent | 38e5e47b07696a0954145bf68148cb0301cf133c (diff) | |
ksys: Move ActorParam classes into separate folder to declutter Resource/
Diffstat (limited to 'src/KingSystem/Resource/Actor')
56 files changed, 6922 insertions, 0 deletions
diff --git a/src/KingSystem/Resource/Actor/resResourceAIProgram.cpp b/src/KingSystem/Resource/Actor/resResourceAIProgram.cpp new file mode 100644 index 00000000..4900aa20 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAIProgram.cpp @@ -0,0 +1,464 @@ +#include "KingSystem/Resource/Actor/resResourceAIProgram.h" +#include <agl/Utils/aglParameter.h> +#include <heap/seadHeapMgr.h> +#include "KingSystem/ActorSystem/actAiActionBase.h" +#include "KingSystem/ActorSystem/actAiClassDef.h" +#include "KingSystem/Resource/resCurrentResNameMgr.h" +#include "KingSystem/Utils/HeapUtil.h" + +namespace ksys::res { + +AIProgram::~AIProgram() = default; + +const sead::Buffer<AIProgram::AIActionDef>& +AIProgram::getActionsOrAIs(act::ai::ActionType type) const { + return type == act::ai::ActionType::AI ? mAIs : mActions; +} + +void AIProgram::doCreate_(u8*, u32, sead::Heap*) { + mStr = CurrentResNameMgr::instance()->getCurrentResName(); +} + +static bool parseAIActionIdx(agl::utl::ResParameterObj obj, sead::Buffer<u16>& 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<s32>(); + + return true; +} + +static bool parseBehaviorIdx(agl::utl::ResParameterObj obj, sead::Buffer<u8>& 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<s32>(); + + 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<AIActionDef>& 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<char>(); + it->mClassName = agl::utl::getResParameter(def_obj, "ClassName").getData<char>(); + + const auto group_name = agl::utl::getResParameter(def_obj, "GroupName"); + if (group_name.ptr()) + it->mGroupName = group_name.getData<char>(); + 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<char>(); + } + + 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<char>(); + } + + 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<AIActionDef>& 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(const char** 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::cNullChar; + return false; + } + *value = param->ptrT<char>(); + return true; +} + +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<char>(); + 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 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); +} + +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 = u16(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_<sead::SafeString>(i, name, heap, "")) + return false; + break; + case AIDefParamType::UInt: + if (!def->addSInstParam_<u32>(i, name, heap, 0)) + return false; + break; + case AIDefParamType::Int: + if (!def->addSInstParam_<s32>(i, name, heap, 0)) + return false; + break; + case AIDefParamType::Float: + if (!def->addSInstParam_<f32>(i, name, heap, 0)) + return false; + break; + case AIDefParamType::Vec3: + if (!def->addSInstParam_<sead::Vector3f>(i, name, heap, sead::Vector3f::zero)) + return false; + break; + case AIDefParamType::Bool: + if (!def->addSInstParam_<bool>(i, name, heap, false)) + return false; + break; + default: + def->mSInstParams[i] = nullptr; + break; + } + } + } + + def->mList.addObj(&def->mSInstObj, "SInst"); + return true; +} + +template <typename T> +bool AIProgram::Definition::addSInstParam_(s32 idx, const char* name, sead::Heap* heap, + const T& value) { + mSInstParams[idx] = new (heap) agl::utl::Parameter<T>; + + auto* param = static_cast<agl::utl::Parameter<T>*>(mSInstParams[idx]); + if (!param) + return false; + + param->initializeParameter(value, name, name, &mSInstObj); + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAIProgram.h b/src/KingSystem/Resource/Actor/resResourceAIProgram.h new file mode 100644 index 00000000..c7a646bf --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAIProgram.h @@ -0,0 +1,144 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include <math/seadVector.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::act::ai { +enum class ActionType : int; +} + +namespace ksys::res { + +class AIProgram : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(AIProgram, Resource) +public: + struct Definition { + const agl::utl::ParameterBase* findSInstParam(u32 name_hash) const; + const agl::utl::ParameterBase* findSInstParam(const sead::SafeString& name) const; + + template <typename T> + 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<agl::utl::ParameterBase*> mSInstParams; + agl::utl::ParameterObj mSInstObj; + }; + KSYS_CHECK_SIZE_NX150(Definition, 0x98); + + struct AIActionDef : Definition { + void finalize_(); + + const char* mGroupName; + sead::Buffer<u16> mChildIndices; + sead::Buffer<u8> 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() : ParamIO("aiprog", 0) {} + ~AIProgram() override; + + const sead::Buffer<AIActionDef>& getActionsOrAIs(act::ai::ActionType type) const; + const sead::Buffer<BehaviorDef>& getBehaviors() const { return mBehaviors; } + const sead::Buffer<QueryDef>& getQueries() const { return mQueries; } + + const AIActionDef& getAI(s32 index) const { return mAIs[index]; } + const sead::Buffer<AIActionDef>& getAIs() const { return mAIs; } + const sead::Buffer<AIActionDef>& getActions() const { return mActions; } + + const AIActionDef& getAction(act::ai::ActionType type, s32 index) const { + return getActionsOrAIs(type)[index]; + } + + const sead::Buffer<u16>& getDemoAiActionIndices() const { return mDemoAIActionIndices; } + const sead::Buffer<u8>& getDemoBehaviorIndices() const { return mDemoBehaviorIndices; } + + bool getSInstParam(const char** value, const Definition& def, + const sead::SafeString& param_name) const; + bool getSInstParam(sead::SafeString* 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 f32** 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<AIActionDef>& 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<AIActionDef>& defs); + void finalizeBehaviors(); + void finalizeQueries(); + + template <typename T> + 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<AIActionDef> mAIs; + sead::Buffer<AIActionDef> mActions; + sead::Buffer<BehaviorDef> mBehaviors; + sead::Buffer<QueryDef> mQueries; + + agl::utl::ParameterList mParamListAI; + agl::utl::ParameterList mParamListAction; + agl::utl::ParameterList mParamListBehavior; + agl::utl::ParameterList mParamListQuery; + + sead::Buffer<u16> mDemoAIActionIndices; + sead::Buffer<u8> mDemoBehaviorIndices; +}; +KSYS_CHECK_SIZE_NX150(AIProgram, 0x448); + +template <typename T> +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<T>(); + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAISchedule.cpp b/src/KingSystem/Resource/Actor/resResourceAISchedule.cpp new file mode 100644 index 00000000..6f812de1 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAISchedule.cpp @@ -0,0 +1,9 @@ +#include "KingSystem/Resource/Actor/resResourceAISchedule.h" + +namespace ksys::res { + +void AISchedule::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) { + mData = buffer; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAISchedule.h b/src/KingSystem/Resource/Actor/resResourceAISchedule.h new file mode 100644 index 00000000..d7de2803 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAISchedule.h @@ -0,0 +1,22 @@ +#pragma once + +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class AISchedule : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(AISchedule, Resource) +public: + AISchedule() : ParamIO("baischedule", 0) {} + + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool needsParse() const override { return false; } + + u8* getData() const { return mData; } + +private: + u8* mData{}; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAS.cpp b/src/KingSystem/Resource/Actor/resResourceAS.cpp new file mode 100644 index 00000000..2453d491 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAS.cpp @@ -0,0 +1,170 @@ +#include "KingSystem/Resource/Actor/resResourceAS.h" +#include <memory> +#include <random/seadGlobalRandom.h> +#include "KingSystem/Utils/HeapUtil.h" +#include "KingSystem/Utils/SafeDelete.h" +#include "resResourceASResource.h" + +namespace ksys::res { + +namespace { +sead::SafeString str_Elements = "Elements"; +sead::SafeString str_CommonParams = "CommonParams"; +} // namespace + +AS::AS() : ParamIO("as", 0) {} + +AS::~AS() = default; + +void AS::doCreate_(u8*, u32, sead::Heap*) {} + +// NON_MATCHING: SafeString vtable load is reordered +bool AS::parse_(u8* data, size_t size, sead::Heap* parent_heap) { + mHeap = util::tryCreateDualHeap(parent_heap); + if (!mHeap) + return false; + + mHeap->enableWarning(false); + auto* heap = mHeap; + + agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + + const auto Elements = agl::utl::getResParameterList(root, str_Elements); + if (!Elements) { + mHeap->adjust(); + return true; + } + + const int num_elements = Elements.getResParameterListNum(); + if (num_elements == 0) { + mHeap->adjust(); + return true; + } + + if (!mElementResources.tryAllocBuffer(num_elements, heap)) { + mHeap->adjust(); + return false; + } + + for (int i = 0, n = mElementResources.size(); i < n; ++i) + mElementResources(i) = nullptr; + + ASResource::ParseArgs args; + args.list = {}; + args.heap = heap; + args.as = this; + args.index = 0; + + auto res_it = Elements.listBegin(); + const auto res_end = Elements.listEnd(); + + sead::FixedSafeString<16> name{"Element"}; + const auto name_prefix_len = name.calcLength(); + + for (auto it = mElementResources.begin(), end = mElementResources.end(); + it != end && res_it != res_end; ++it, ++res_it) { + args.list = res_it.getList(); + *it = ASResource::make(args); + if (*it == nullptr) { + mHeap->adjust(); + return false; + } + + name.trim(name_prefix_len); + name.appendWithFormat("%d", args.index); + mElementsList.addList(&(*it)->getList(), name); + ++args.index; + } + + addList(&mElementsList, str_Elements); + + mRandomRateMin.init(1.0, "RandomRateMin", "ランダム再生率小", "Min=0.f,Max=10.f", + &mCommonParams); + mRandomRateMax.init(1.0, "RandomRateMax", "ランダム再生率大", "Min=0.f,Max=10.f", + &mCommonParams); + mForbidPartialDemoAS.init(false, "ForbidPartialDemoAS", "一括再生する", "", &mCommonParams); + mUseIK.init(true, "UseIK", "IKする", "", &mCommonParams); + + addObj(&mCommonParams, str_CommonParams); + + _3bb = 0; + + res_it = Elements.listBegin(); + args.index = 0; + for (auto it = mElementResources.begin(), end = mElementResources.end(); + it != end && res_it != res_end; ++it, ++res_it) { + args.list = res_it.getList(); + if (!(*it)->parse(args)) { + mHeap->adjust(); + return false; + } + + _3ba |= (*it)->m7() & 1; + + switch ((*it)->getTypeIndex()) { + case 62: + _3bb |= 1 << 0; + break; + case 63: + _3bb |= 1 << 1; + break; + case 64: + _3bb |= 1 << 2; + break; + case 83: + _3bb |= 1 << 3; + break; + case 6: + _3bb |= 1 << 4; + break; + case 39: + _3bb |= 1 << 5; + break; + } + ++args.index; + } + + applyResParameterArchive(archive); + + if (auto* first = getFirstResource()) { + u32 x = first->m4(); + x = x >= 0xff ? 0xff : x; + u32 y = first->m5(); + y = y >= 0xff ? 0xff : y; + + _3b8 = x; + _3b9 = y; + } else { + _3b8 = 0; + _3b9 = 0; + } + + mHeap->adjust(); + return true; +} + +ASResource* AS::getFirstResource() const { + if (mElementResources.size() == 0) + return nullptr; + return mElementResources[0]; +} + +void AS::finalize_() { + for (auto* ptr : mElementResources) { + if (ptr) + std::destroy_at(ptr); + } + + util::safeDeleteHeap(mHeap); +} + +float AS::getRandomRate() const { + const auto max = getRandomRateMax(); + const auto min = getRandomRateMin(); + if (max - min > 0.0) + return sead::GlobalRandom::instance()->getF32Range(min, max); + return min; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAS.h b/src/KingSystem/Resource/Actor/resResourceAS.h new file mode 100644 index 00000000..14a6b1e4 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAS.h @@ -0,0 +1,56 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class ASResource; + +class AS : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(AS, Resource) +public: + AS(); + ~AS() override; + AS(const AS&) = delete; + auto operator=(const AS&) = delete; + + void doCreate_(u8*, u32, sead::Heap*) override; + bool needsParse() const override { return true; } + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + void finalize_() override; + + const sead::Buffer<ASResource*>& getElementResources() const { return mElementResources; } + const auto& getRandomRateMin() const { return *mRandomRateMin; } + const auto& getRandomRateMax() const { return *mRandomRateMax; } + const auto& getForbidPartialDemoAs() const { return *mForbidPartialDemoAS; } + const auto& getUseIk() const { return *mUseIK; } + + ASResource* getFirstResource() const; + float getRandomRate() const; + +private: + friend class ASList; + + sead::Buffer<ASResource*> mElementResources; + agl::utl::ParameterList mElementsList; + + agl::utl::ParameterObj mCommonParams; + agl::utl::Parameter<f32> mRandomRateMin; + agl::utl::Parameter<f32> mRandomRateMax; + agl::utl::Parameter<bool> mForbidPartialDemoAS; + agl::utl::Parameter<bool> mUseIK; + u8 _3b8{}; + u8 _3b9{}; + u8 _3ba{}; + u8 _3bb{}; + sead::Heap* mHeap{}; +}; +KSYS_CHECK_SIZE_NX150(AS, 0x3c8); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceASList.cpp b/src/KingSystem/Resource/Actor/resResourceASList.cpp new file mode 100644 index 00000000..2a5a1f4c --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceASList.cpp @@ -0,0 +1,251 @@ +#include "KingSystem/Resource/Actor/resResourceASList.h" +#include "KingSystem/Resource/Actor/resResourceAS.h" + +namespace ksys::res { + +namespace { +[[maybe_unused]] sead::SafeArray<sead::FixedSafeString<128>, 3> sStrings; +} + +ASList::ASList() : ParamIO("aslist", 0) {} + +ASList::~ASList() { + mASDefines.freeBuffer(); + for (auto& cf : mCFDefines) { + cf.posts.freeBuffer(); + cf.excepts.freeBuffer(); + } + mCFDefines.freeBuffer(); + mAddReses.freeBuffer(); +} + +void ASList::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} + +bool ASList::parse_(u8* data, size_t size, sead::Heap* heap) { + if (!data) + return false; + + agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + + const auto ASDefines = agl::utl::getResParameterList(root, "ASDefines"); + auto ASDefine_name = sead::FixedSafeString<32>{"ASDefine_"}; + const auto ASDefine_prefix_len = ASDefine_name.calcLength(); + if (!ASDefines.ptr()) + return true; + const auto ASDefines_num = ASDefines.getResParameterObjNum(); + if (ASDefines_num != 0) { + if (!mASDefines.tryAllocBuffer(ASDefines_num, heap)) + return false; + for (auto it = mASDefines.begin(), end = mASDefines.end(); it != end; ++it) { + it->name.init("", "Name", "", &it->obj); + it->file_name.init("", "Filename", "", &it->obj); + it->as = nullptr; + + ASDefine_name.trim(ASDefine_prefix_len); + ASDefine_name.appendWithFormat("%d", it.getIndex()); + mASDefinesList.addObj(&it->obj, ASDefine_name); + } + addList(&mASDefinesList, "ASDefines"); + + const auto CFDefines = agl::utl::getResParameterList(root, "CFDefines"); + if (int CFDefines_num; + CFDefines.ptr() && (CFDefines_num = CFDefines.getResParameterListNum()) != 0) { + if (!mCFDefines.tryAllocBuffer(CFDefines_num, heap)) + return false; + + auto CFDefine_name = sead::FixedSafeString<32>{"CFDefine_"}; + const auto CFDefine_prefix_len = CFDefine_name.calcLength(); + + auto CFPost_name = sead::FixedSafeString<32>{"CFPost_"}; + const auto CFPost_prefix_len = CFPost_name.calcLength(); + + auto Name_name = sead::FixedSafeString<32>{"Name_"}; + const auto Name_prefix_len = Name_name.calcLength(); + + for (auto it = mCFDefines.begin(), end = mCFDefines.end(); it != end; ++it) { + CFDefine_name.trim(CFDefine_prefix_len); + CFDefine_name.appendWithFormat("%d", it.getIndex()); + mCFDefinesList.addList(&it->list, CFDefine_name); + const auto CFDefine = agl::utl::getResParameterList(CFDefines, CFDefine_name); + + const auto CFPosts = agl::utl::getResParameterList(CFDefine, "CFPosts"); + if (int num; CFPosts.ptr() && (num = CFPosts.getResParameterObjNum()) != 0) { + if (!it->posts.tryAllocBuffer(num, heap)) + return false; + for (auto post = it->posts.begin(), post_end = it->posts.end(); + post != post_end; ++post) { + post->name.init("", "Name", "", &post->obj); + post->frame.init(0, "Frame", "", &post->obj); + post->start_frame_rate.init(0, "StartFrameRate", "", &post->obj); + + CFPost_name.trim(CFPost_prefix_len); + CFPost_name.appendWithFormat("%d", post.getIndex()); + it->posts_list.addObj(&post->obj, CFPost_name); + } + } + + const auto CFExcepts = agl::utl::getResParameterObj(CFDefine, "CFExcepts"); + if (int num; CFExcepts.ptr() && (num = CFExcepts.getNum()) != 0) { + if (!it->excepts.tryAllocBuffer(num, heap)) + return false; + for (auto except = it->excepts.begin(), except_end = it->excepts.end(); + except != except_end; ++except) { + Name_name.trim(Name_prefix_len); + Name_name.appendWithFormat("%d", except.getIndex()); + except->name.init("", Name_name, "", &it->excepts_obj); + } + } + + it->name.init("", "Name", "", &it->pre_obj); + it->list.addObj(&it->pre_obj, "CFPre"); + it->list.addList(&it->posts_list, "CFPosts"); + it->list.addObj(&it->excepts_obj, "CFExcepts"); + } + + addList(&mCFDefinesList, "CFDefines"); + } + } + + const auto AddReses = agl::utl::getResParameterList(root, "AddReses"); + if (int num; AddReses.ptr() && (num = AddReses.getResParameterObjNum()) != 0) { + if (!mAddReses.tryAllocBuffer(num, heap)) + return false; + + auto AddRes_name = sead::FixedSafeString<32>{"AddRes_"}; + const auto AddRes_prefix_len = AddRes_name.calcLength(); + for (auto it = mAddReses.begin(), end = mAddReses.end(); it != end; ++it) { + it->anim.init("", "Anim", "", &it->obj); + it->retarget_model.init("", "RetargetModel", "", &it->obj); + it->retarget_no_correct.init(false, "RetargetNoCorrect", "", &it->obj); + + AddRes_name.trim(AddRes_prefix_len); + AddRes_name.appendWithFormat("%d", it.getIndex()); + mAddResesList.addObj(&it->obj, AddRes_name); + } + addList(&mAddResesList, "AddReses"); + } + + if (agl::utl::getResParameterObj(root, "Common").ptr()) { + const sead::SafeString name = "RateAll"; + const sead::SafeString label = ""; + mCommon->rate_all.init(1.0, name, label, &mCommon->obj); + addObj(&mCommon->obj, "Common"); + } else { + mCommon->rate_all = 1.0; + } + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + return true; +} + +bool ASList::finishParsing_() { + return true; +} + +bool ASList::m7_() { + for (auto& as : mASDefines) + as.as = nullptr; + + _2b0 = 0; + _2b1 = 0; + _2b2 = 0; + _2b3 = 0; + return true; +} + +void ASList::addAS_(s32 index, AS* as) { + mASDefines[index].as = as; + + _2b0 = _2b0 > as->_3b8 ? _2b0 : as->_3b8; + + const auto as_counter = as->_3b9; + if (_2b1 == 0) { + _2b1 = as_counter; + _2b3 = as->_3bb; + } else { + u8* flags1; + u8* flags2; + if (as_counter > _2b1) { + _2b1 = as_counter; + flags1 = &as->_3bb; + flags2 = &_2b3; + } else { + flags1 = &_2b3; + flags2 = &as->_3bb; + } + + for (int i = 0; i < 6; ++i) { + const auto mask = 1u << i; + if ((*flags1 & mask) == 0 && (*flags2 & mask) != 0) { + _2b3 |= mask; + _2b1++; + } + } + } + + _2b2 |= as->_3ba; +} + +const char* ASList::getASFileName(const sead::SafeString& name) const { + const int idx = findASDefine(name); + if (idx == -1) + return nullptr; + return mASDefines[idx].getFileName(); +} + +int ASList::findASDefine(const sead::SafeString& name) const { + return mASDefines.binarySearch( + name, +[](const ASDefine& define, const sead::SafeString& key) { + return define.name->compare(key); + }); +} + +int ASList::findCFDefine(const sead::SafeString& name) const { + return mCFDefines.binarySearch( + name, +[](const CFDefine& define, const sead::SafeString& key) { + return define.name->compare(key); + }); +} + +int ASList::CFExcept::compare(const ASList::CFExcept& o, const sead::SafeString& n) { + return o.name->compare(n); +} + +int ASList::CFPost::compare(const ASList::CFPost& o, const sead::SafeString& n) { + return o.name->compare(n); +} + +bool ASList::getCFDefineInfo(float* frame, float* start_frame_value, const sead::SafeString& name, + const sead::SafeString& post_name, bool* is_default) const { + const int idx = findCFDefine(name); + *is_default = false; + if (idx == -1) + return false; + + const auto& cfdefine = mCFDefines[idx]; + + const int except_idx = cfdefine.excepts.binarySearch(post_name, CFExcept::compare); + if (except_idx >= 0) + return false; + + const CFPost* post = nullptr; + const int post_idx = cfdefine.posts.binarySearch(post_name, CFPost::compare); + if (post_idx != -1) { + post = std::addressof(cfdefine.posts[post_idx]); + } else { + post = std::addressof(cfdefine.posts[0]); + if (!post->name->isEmpty()) + return false; + *is_default = true; + } + + if (!post) + return false; + + *frame = *post->frame; + *start_frame_value = *post->start_frame_rate; + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceASList.h b/src/KingSystem/Resource/Actor/resResourceASList.h new file mode 100644 index 00000000..d8836523 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceASList.h @@ -0,0 +1,109 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include <prim/seadStorageFor.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class AS; + +class ASList : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(ASList, Resource) +public: + struct ASDefine { + const char* getFileName() const { return file_name.ref().cstr(); } + + agl::utl::Parameter<sead::SafeString> name; + agl::utl::Parameter<sead::SafeString> file_name; + agl::utl::ParameterObj obj; + AS* as; + }; + KSYS_CHECK_SIZE_NX150(ASDefine, 0x88); + + struct CFPost { + static int compare(const CFPost& o, const sead::SafeString& n); + + agl::utl::Parameter<sead::SafeString> name; + agl::utl::Parameter<float> frame; + agl::utl::Parameter<float> start_frame_rate; + agl::utl::ParameterObj obj; + }; + KSYS_CHECK_SIZE_NX150(CFPost, 0x98); + + struct CFExcept { + static int compare(const CFExcept& o, const sead::SafeString& n); + + agl::utl::Parameter<sead::SafeString> name; + }; + KSYS_CHECK_SIZE_NX150(CFExcept, 0x28); + + struct CFDefine { + agl::utl::Parameter<sead::SafeString> name; + agl::utl::ParameterObj pre_obj; + sead::Buffer<CFPost> posts; + agl::utl::ParameterList posts_list; + sead::Buffer<CFExcept> excepts; + agl::utl::ParameterObj excepts_obj; + agl::utl::ParameterList list; + }; + KSYS_CHECK_SIZE_NX150(CFDefine, 0x138); + + struct AddRes { + agl::utl::Parameter<sead::SafeString> anim; + agl::utl::Parameter<sead::SafeString> retarget_model; + agl::utl::Parameter<bool> retarget_no_correct; + agl::utl::ParameterObj obj; + }; + KSYS_CHECK_SIZE_NX150(AddRes, 0xa0); + + struct Common { + agl::utl::Parameter<f32> rate_all; + agl::utl::ParameterObj obj; + }; + KSYS_CHECK_SIZE_NX150(Common, 0x50); + + ASList(); + ~ASList() override; + + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool needsParse() const override { return true; } + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + + const sead::Buffer<ASDefine>& getASDefines() const { return mASDefines; } + const sead::Buffer<CFDefine>& getCFDefines() const { return mCFDefines; } + const sead::Buffer<AddRes>& getAddReses() const { return mAddReses; } + const Common& getCommon() const { return mCommon.ref(); } + + void addAS_(s32 index, AS* as); + + const char* getASFileName(const sead::SafeString& name) const; + int findASDefine(const sead::SafeString& name) const; + int findCFDefine(const sead::SafeString& name) const; + bool getCFDefineInfo(float* frame, float* key, const sead::SafeString& name, + const sead::SafeString& post_name, bool* is_default) const; + +protected: + bool finishParsing_() override; + bool m7_() override; + +private: + u8 _2b0 = 0; + u8 _2b1 = 0; + u8 _2b2 = 0; + u8 _2b3 = 0; + sead::Buffer<ASDefine> mASDefines; + sead::Buffer<CFDefine> mCFDefines; + sead::Buffer<AddRes> mAddReses; + agl::utl::ParameterList mCFDefinesList; + agl::utl::ParameterList mASDefinesList; + agl::utl::ParameterList mAddResesList; + sead::StorageFor<Common, true> mCommon{sead::ZeroInitializeTag{}}; +}; +KSYS_CHECK_SIZE_NX150(ASList, 0x410); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceASResource.cpp b/src/KingSystem/Resource/Actor/resResourceASResource.cpp new file mode 100644 index 00000000..e6b2be31 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceASResource.cpp @@ -0,0 +1,375 @@ +#include "KingSystem/Resource/Actor/resResourceASResource.h" +#include <limits> +#include <prim/seadSafeString.h> +#include "KingSystem/Resource/Actor/resResourceAS.h" + +namespace ksys::as { +class Element; +} + +namespace ksys::res { + +namespace { + +struct ASElementFactory { + const char* name; + ASResource* (*make_res)(int type_index, const ASResource::ParseArgs& args); + // FIXME: signature + as::Element* (*make)(); + /// Arbitrary value that is passed to the Element class + int value; +}; + +sead::SafeString sStr_default = "default"; + +template <typename T> +ASResource* resFactoryImpl_(int type_index, const ASResource::ParseArgs& arg) { + return new (arg.heap) T(type_index, arg.index); +} + +// FIXME: make functions +sead::SafeArray<ASElementFactory, 107> sFactories{{ + /* 000 */ {"AbsTemperatureBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 24}, + /* 001 */ {"AbsTemperatureSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 24}, + /* 002 */ {"ArmorSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 57}, + /* 003 */ {"ArrowSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 60}, + /* 004 */ {"AttentionSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 48}, + /* 005 */ {"BoneBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 28}, + /* 006 */ {"BoneVisibilityAsset", resFactoryImpl_<ASAssetExResource>, nullptr, -1}, + /* 007 */ {"BoolSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 66}, + /* 008 */ {"ButtonSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 46}, + /* 009 */ {"ChargeSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 42}, + + /* 010 */ {"ClearMatAnmAsset", resFactoryImpl_<ASResource>, nullptr, -1}, + /* 011 */ {"ComboSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 43}, + /* 012 */ {"DiffAngleYBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 26}, + /* 013 */ {"DiffAngleYSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 26}, + /* 014 */ {"DirectionAngleBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 9}, + /* 015 */ {"DirectionAngleSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 9}, + /* 016 */ {"DistanceBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 16}, + /* 017 */ {"DistanceSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 16}, + /* 018 */ {"DungeonClearSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 64}, + /* 019 */ {"DungeonNumberSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 41}, + + /* 020 */ {"EmotionSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 55}, + /* 021 */ {"EventFlagSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 65}, + /* 022 */ {"EyeSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 37}, + /* 023 */ {"EyebrowSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 38}, + /* 024 */ {"FaceEmotionSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 56}, + /* 025 */ {"FootBLLifeSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 34}, + /* 026 */ {"FootBRLifeSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 33}, + /* 027 */ {"FootFLLifeSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 32}, + /* 028 */ {"FootFRLifeSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 31}, + /* 029 */ {"ForwardBentBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 18}, + + /* 030 */ {"ForwardBentSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 18}, + /* 031 */ {"GearSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 64}, + /* 032 */ {"GenerationSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 35}, + /* 033 */ {"GrabTypeSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 49}, + /* 034 */ {"GroundNormalBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 21}, + /* 035 */ {"GroundNormalSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 21}, + /* 036 */ {"GroundNormalSideBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 22}, + /* 037 */ {"GroundNormalSideSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 22}, + /* 038 */ {"MaskSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 58}, + /* 039 */ {"MatVisibilityAsset", resFactoryImpl_<ASAssetExResource>, nullptr, -1}, + + /* 040 */ {"MouthSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 36}, + /* 041 */ {"NoAnmAsset", resFactoryImpl_<ASResource>, nullptr, -1}, + /* 042 */ {"NoLoopStickAngleBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 7}, + /* 043 */ {"NoLoopStickAngleSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 7}, + /* 044 */ {"NodePosSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 63}, + /* 045 */ {"PersonalitySelector", resFactoryImpl_<ASSelectorResource>, nullptr, 50}, + /* 046 */ {"PostureSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 59}, + /* 047 */ {"PreASSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 51}, + /* 048 */ {"PreExclusionRandomSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 30}, + /* 049 */ {"RandomSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 30}, + + /* 050 */ {"RideSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 61}, + /* 051 */ {"RightStickAngleBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 8}, + /* 052 */ {"RightStickAngleSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 8}, + /* 053 */ {"RightStickValueBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 3}, + /* 054 */ {"RightStickValueSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 3}, + /* 055 */ {"RightStickXBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 4}, + /* 056 */ {"RightStickXSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 4}, + /* 057 */ {"RightStickYBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 5}, + /* 058 */ {"RightStickYSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 5}, + /* 059 */ {"SelfHeightSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 39}, + + /* 060 */ {"SelfWeightSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 40}, + /* 061 */ + {"SequencePlayContainer", resFactoryImpl_<ASSequencePlayContainerResource>, nullptr, -1}, + /* 062 */ {"ShaderParamAsset", resFactoryImpl_<ASAssetExResource>, nullptr, -1}, + /* 063 */ {"ShaderParamColorAsset", resFactoryImpl_<ASAssetExResource>, nullptr, -1}, + /* 064 */ {"ShaderParamTexSRTAsset", resFactoryImpl_<ASAssetExResource>, nullptr, -1}, + /* 065 */ {"SizeBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 17}, + /* 066 */ {"SizeSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 17}, + /* 067 */ {"SkeltalAsset", resFactoryImpl_<ASSkeltalAssetResource>, nullptr, -1}, + /* 068 */ {"SpeedBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 19}, + /* 069 */ {"SpeedSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 19}, + + /* 070 */ {"StickAngleBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 6}, + /* 071 */ {"StickAngleSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 6}, + /* 072 */ {"StickValueBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 0}, + /* 073 */ {"StickValueSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 0}, + /* 074 */ {"StickXBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 1}, + /* 075 */ {"StickXSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 1}, + /* 076 */ {"StickYBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 2}, + /* 077 */ {"StickYSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 2}, + /* 078 */ {"StressBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 14}, + /* 079 */ {"StressSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 14}, + + /* 080 */ {"SyncPlayContainer", resFactoryImpl_<ASResourceWithChildren>, nullptr, -1}, + /* 081 */ {"TemperatureBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 23}, + /* 082 */ {"TemperatureSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 23}, + /* 083 */ {"TexturePatternAsset", resFactoryImpl_<ASAssetExResource>, nullptr, -1}, + /* 084 */ {"TimeSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 52}, + /* 085 */ {"TiredBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 13}, + /* 086 */ {"TiredSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 13}, + /* 087 */ {"UseItemSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 62}, + /* 088 */ {"UserAngle2Blender", resFactoryImpl_<ASBlenderResource>, nullptr, 12}, + /* 089 */ {"UserAngle2Selector", resFactoryImpl_<ASSelectorResource>, nullptr, 12}, + + /* 090 */ {"UserAngleBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 11}, + /* 091 */ {"UserAngleSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 11}, + /* 092 */ {"UserSpeedBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 10}, + /* 093 */ {"UserSpeedSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 10}, + /* 094 */ {"VariationSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 47}, + /* 095 */ {"WallAngleBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 15}, + /* 096 */ {"WallAngleSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 15}, + /* 097 */ {"WeaponDetailSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 45}, + /* 098 */ {"WeaponSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 44}, + /* 099 */ {"WeatherSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 53}, + + /* 100 */ {"WeightBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 25}, + /* 101 */ {"WeightSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 25}, + /* 102 */ {"WindVelocityBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 27}, + /* 103 */ {"YSpeedBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 20}, + /* 104 */ {"YSpeedSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 20}, + /* 105 */ {"ZEx00ExposureBlender", resFactoryImpl_<ASBlenderResource>, nullptr, 29}, + /* 106 */ {"ZEx00ExposureSelector", resFactoryImpl_<ASSelectorResource>, nullptr, 29}, +}}; + +} // namespace + +bool ASResource::parse(const ASResource::ParseArgs& args) { + if (!doParse(args)) + return false; + + ASExtensions::ParseArgs parse_args{}; + parse_args.heap = args.heap; + parse_args.list = &mList; + parse_args.res_list = args.list; + return mExtensions.parse(parse_args); +} + +int ASResource::findStringIndex(const sead::SafeString& value) const { + auto* parser = sead::DynamicCast<ASStringArrayParser>( + mExtensions.getParser(ASParamParser::Type::StringArray)); + + if (!parser) + return -1; + + const u32 size = parser->getValues().size(); + if (size == 0) + return -1; + + for (u32 i = 0; i < size; ++i) { + if (value == *parser->getValues()[i].value) + return i; + } + + const int default_idx = int(size - 1); + if (default_idx < 0) + return -1; + if (getDefaultStr() == *parser->getValues()[default_idx].value) + return default_idx; + return -1; +} + +int ASResource::findIntIndex(int value) const { + auto* parser = + sead::DynamicCast<ASIntArrayParser>(mExtensions.getParser(ASParamParser::Type::IntArray)); + if (parser) { + const u32 size = parser->getValues().size(); + if (size == 0) + return -1; + + for (u32 i = 0; i < size; ++i) { + if (*parser->getValues()[i].value == value) + return i; + } + + const int default_idx = int(size - 1); + if (default_idx >= 0 && + *parser->getValues()[default_idx].value == std::numeric_limits<int>::min()) { + return default_idx; + } + } + return -1; +} + +const sead::SafeString& ASResource::getDefaultStr() { + return sStr_default; +} + +ASResourceWithChildren::~ASResourceWithChildren() { + mChildren.freeBuffer(); +} + +// NON_MATCHING: getParameterData (redundant uxtw which leads to localised regalloc diffs) +bool ASResourceWithChildren::doParse(const ASResource::ParseArgs& args) { + const auto Children = agl::utl::getResParameterObj(args.list, "Children"); + if (!Children) + return true; + + const auto size = Children.getNum(); + if (size == 0) + return true; + + if (!mChildren.tryAllocBuffer(size, args.heap)) + return false; + for (int i = 0, n = mChildren.size(); i < n; ++i) + mChildren(i) = nullptr; + + for (auto it = mChildren.begin(), end = mChildren.end(); it != end; ++it) { + const auto idx = *Children.getParameterData<int>(it.getIndex()); + *it = args.as->getElementResources()[idx]; + } + + return true; +} + +int ASResourceWithChildren::callOnChildren_(MemberFunction fn) { + int ret = 0; + for (int i = 0; i < mChildren.size(); ++i) + ret += (mChildren[i]->*fn)(); + return ret; +} + +bool ASSequencePlayContainerResource::doParse(const ASResource::ParseArgs& args) { + if (!ASResourceWithChildren::doParse(args)) + return false; + + mSequenceLoop.init(false, "SequenceLoop", "シーケンスループ", &mObj); + + mList.addObj(&mObj, "Parameters"); + return true; +} + +int ASSequencePlayContainerResource::callOnChildren_(ASResourceWithChildren::MemberFunction fn) { + int ret = 0; + for (int i = 0; i < mChildren.size(); ++i) { + int value = (mChildren[i]->*fn)(); + if (u32(ret) <= u32(value)) + ret = value; + } + return ret; +} + +int ASSequencePlayContainerResource::m7() { + auto* parser = sead::DynamicCast<ASFloatArrayParser>( + mExtensions.getParser(ASParamParser::Type::FloatArray)); + if (!parser) + return 0; + + for (int i = 0, n = parser->getValues().size(); i < n; ++i) { + if (*parser->getValues()[i].value < 1.0) + return 1; + } + return 0; +} + +float ASSequencePlayContainerResource::getValue(int index) const { + auto* parser = sead::DynamicCast<ASFloatArrayParser>( + mExtensions.getParser(ASParamParser::Type::FloatArray)); + if (!parser || parser->getValues().size() <= index) + return 1.0; + return *parser->getValues()[index].value; +} + +bool ASSelectorResource::doParse(const ASResource::ParseArgs& args) { + if (!ASResourceWithChildren::doParse(args)) + return false; + + mNoSync.init(false, "NoSync", "非同期", &mObj); + mJudgeOnce.init(true, "JudgeOnce", "初期化時のみ判定", &mObj); + + mList.addObj(&mObj, "Parameters"); + return true; +} + +int ASSelectorResource::callOnChildren_(ASResourceWithChildren::MemberFunction fn) { + int ret = 0; + for (int i = 0; i < mChildren.size(); ++i) { + int value = (mChildren[i]->*fn)(); + if (u32(ret) <= u32(value)) + ret = value; + } + return ret; +} + +bool ASBlenderResource::doParse(const ASResource::ParseArgs& args) { + if (!ASResourceWithChildren::doParse(args)) + return false; + + mNoSync.init(false, "NoSync", "非同期", &mObj); + mJudgeOnce.init(false, "JudgeOnce", "初期化時のみ判定", &mObj); + mInputLimit.init(-1.0, "InputLimit", "入力変化制限", &mObj); + + mList.addObj(&mObj, "Parameters"); + return true; +} + +int ASBlenderResource::callOnChildren_(ASResourceWithChildren::MemberFunction fn) { + if (mChildren.size() == 0) + return 0; + + const u32 first = (mChildren[0]->*fn)(); + + u32 max = first; + u32 previous = first; + for (int i = 1; i < mChildren.size(); ++i) { + const u32 current = (mChildren[i]->*fn)(); + if (max <= previous + current) + max = previous + current; + previous = current; + } + + if (max <= first + previous) + max = first + previous; + + return max; +} + +bool ASAssetResource::doParse(const ASResource::ParseArgs& args) { + mFileName.init("", "FileName", "ファイル名", &mObj); + + mList.addObj(&mObj, "Parameters"); + return true; +} + +bool ASSkeltalAssetResource::doParse(const ASResource::ParseArgs& args) { + ASAssetResource::doParse(args); + + mMorph.init(5.0, "Morph", "補間", "Min=0.f,Max=20.f", &mObj); + mResetMorph.init(5.0, "ResetMorph", "リセット時補間", "Min=0.f,Max=20.f", &mObj); + mInitAnmDriven.init(false, "InitAnmDriven", "初期アニメドリブン", "", &mObj); + + return true; +} + +ASResource* ASResource::make(const ASResource::ParseArgs& args) { + const auto Parameters = agl::utl::getResParameterObj(args.list, "Parameters"); + + const auto TypeIndex = agl::utl::getResParameter(Parameters, "TypeIndex"); + if (!TypeIndex.ptr()) + return nullptr; + + const auto type_index = *TypeIndex.getData<int>(); + if (u32(type_index) >= u32(sFactories.size())) + return nullptr; + + return sFactories[type_index].make_res(type_index, args); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceASResource.h b/src/KingSystem/Resource/Actor/resResourceASResource.h new file mode 100644 index 00000000..4160a2bf --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceASResource.h @@ -0,0 +1,166 @@ +#pragma once + +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglResParameter.h> +#include <container/seadBuffer.h> +#include <prim/seadRuntimeTypeInfo.h> +#include "KingSystem/Resource/Actor/resResourceASResourceExtension.h" + +namespace ksys::res { + +class AS; + +class ASResource { + SEAD_RTTI_BASE(ASResource) +public: + struct ParseArgs { + agl::utl::ResParameterList list; + sead::Heap* heap; + AS* as; + int index; + }; + + ASResource(int type_index, int index) : mTypeIndex(type_index), mIndex(index) {} + virtual ~ASResource() = default; + + bool parse(const ParseArgs& args); + + virtual int m4() { return 0; } + virtual int m5() { return 0; } + virtual int m6() { return 1; } + virtual int m7() { return 0; } + + static const sead::SafeString& getDefaultStr(); + static ASResource* make(const ParseArgs& args); + + u16 getTypeIndex() const { return mTypeIndex; } + u16 getIndex() const { return mIndex; } + int findStringIndex(const sead::SafeString& value) const; + int findIntIndex(int value) const; + + agl::utl::ParameterList& getList() { return mList; } + +protected: + virtual bool doParse(const ParseArgs& args) { return true; } + + u16 mTypeIndex{}; + u16 mIndex{}; + agl::utl::ParameterList mList; + ASExtensions mExtensions; +}; + +class ASResourceWithChildren : public ASResource { + SEAD_RTTI_OVERRIDE(ASResourceWithChildren, ASResource) +public: + using ASResource::ASResource; + ~ASResourceWithChildren() override; + ASResourceWithChildren(const ASResourceWithChildren&) = delete; + auto operator=(const ASResourceWithChildren&) = delete; + + int m4() override { return callOnChildren_(&ASResource::m4); } + int m5() override { return callOnChildren_(&ASResource::m5); } + int m6() override { return callOnChildren_(&ASResource::m6) + 1; } + +protected: + using MemberFunction = int (ASResource::*)(); + + bool doParse(const ParseArgs& args) override; + virtual int callOnChildren_(MemberFunction fn); + + sead::Buffer<ASResource*> mChildren; +}; + +class ASSequencePlayContainerResource : public ASResourceWithChildren { + SEAD_RTTI_OVERRIDE(ASSequencePlayContainerResource, ASResourceWithChildren) +public: + using ASResourceWithChildren::ASResourceWithChildren; + + const auto& getSequenceLoop() const { return *mSequenceLoop; } + float getValue(int index) const; + +protected: + bool doParse(const ParseArgs& args) override; + int callOnChildren_(MemberFunction fn) override; + int m7() override; + + agl::utl::ParameterObj mObj; + agl::utl::Parameter<bool> mSequenceLoop; +}; + +class ASSelectorResource : public ASResourceWithChildren { + SEAD_RTTI_OVERRIDE(ASSelectorResource, ASResourceWithChildren) +public: + using ASResourceWithChildren::ASResourceWithChildren; + + const auto& getNoSync() const { return *mNoSync; } + const auto& getJudgeOnce() const { return *mJudgeOnce; } + +protected: + bool doParse(const ParseArgs& args) override; + int callOnChildren_(MemberFunction fn) override; + + agl::utl::ParameterObj mObj; + agl::utl::Parameter<bool> mNoSync; + agl::utl::Parameter<bool> mJudgeOnce; +}; + +class ASBlenderResource : public ASResourceWithChildren { + SEAD_RTTI_OVERRIDE(ASBlenderResource, ASResourceWithChildren) +public: + using ASResourceWithChildren::ASResourceWithChildren; + + const auto& getNoSync() const { return *mNoSync; } + const auto& getJudgeOnce() const { return *mJudgeOnce; } + const auto& getInputLimit() const { return *mInputLimit; } + +protected: + bool doParse(const ParseArgs& args) override; + int callOnChildren_(MemberFunction fn) override; + + agl::utl::ParameterObj mObj; + agl::utl::Parameter<bool> mNoSync; + agl::utl::Parameter<bool> mJudgeOnce; + agl::utl::Parameter<float> mInputLimit; +}; + +class ASAssetResource : public ASResource { + SEAD_RTTI_OVERRIDE(ASAssetResource, ASResource) +public: + using ASResource::ASResource; + + const sead::SafeString& getFileName() const { return *mFileName; } + +protected: + bool doParse(const ParseArgs& args) override; + + agl::utl::ParameterObj mObj; + agl::utl::Parameter<sead::SafeString> mFileName; +}; + +class ASAssetExResource : public ASAssetResource { + SEAD_RTTI_OVERRIDE(ASAssetExResource, ASAssetResource) +public: + using ASAssetResource::ASAssetResource; + +protected: + int m5() override { return 1; } +}; + +class ASSkeltalAssetResource : public ASAssetResource { + SEAD_RTTI_OVERRIDE(ASSkeltalAssetResource, ASAssetResource) +public: + using ASAssetResource::ASAssetResource; + + const auto& getInitAnmDriven() const { return *mInitAnmDriven; } + const auto& getMorph() const { return *mMorph; } + const auto& getResetMorph() const { return *mResetMorph; } + +protected: + bool doParse(const ParseArgs& args) override; + + agl::utl::Parameter<int> mInitAnmDriven; + agl::utl::Parameter<float> mMorph; + agl::utl::Parameter<float> mResetMorph; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceASResourceExtension.cpp b/src/KingSystem/Resource/Actor/resResourceASResourceExtension.cpp new file mode 100644 index 00000000..9a400cd1 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceASResourceExtension.cpp @@ -0,0 +1,339 @@ +#include "KingSystem/Resource/Actor/resResourceASResourceExtension.h" +#include <container/seadSafeArray.h> +#include <optional> +#include <prim/seadSafeString.h> +#include "KingSystem/ActorSystem/actASSetting.h" +#include "KingSystem/Resource/resResourceASSetting.h" + +namespace ksys::res { + +bool ASFrameCtrlParser::parse(const ASParamParser::ParseArgs& args) { + mRate.init(1.0, "Rate", "再生速度", "Min=0.f,Max=10.f", &mObj); + mStartFrame.init(0.0, "StartFrame", "開始フレーム", "Min=0.f,Max=100.f", &mObj); + mEndFrame.init(-1.0, "EndFrame", "終了フレーム", "Min=-1.f,Max=100.f", &mObj); + mLoopStopCount.init(-1.0, "LoopStopCount", "ループ停止回数", "Min=-1.f,Max=10.f", &mObj); + mLoopStopCountRandom.init(0.0, "LoopStopCountRandom", "ランダムループ追加回数", + "Min=0.f,Max=10.f", &mObj); + mReversePlay.init(false, "ReversePlay", "逆再生", "", &mObj); + mUseGlobalFrame.init(false, "UseGlobalFrame", "グローバルフレーム使う", "", &mObj); + mFootType.init(0, "FootType", "足解決", "", &mObj); + mConnect.init(false, "Connect", "接続", "", &mObj); + mAnmLoop.init(0, "AnmLoop", "ループ設定", "", &mObj); + + mList.addObj(&mObj, "FrameCtrl0"); + return true; +} + +bool ASTriggerEventsParser::parse(const ASParamParser::ParseArgs& args) { + const int num_objs = args.res_list.getResParameterObjNum(); + if (num_objs == 0) + return true; + + if (!mEvents.tryAllocBuffer(num_objs, args.heap)) + return false; + + auto it = mEvents.begin(); + const auto end = mEvents.end(); + + sead::FixedSafeString<32> obj_name{"Event"}; + const auto obj_name_prefix_len = obj_name.calcLength(); + + auto res_it = args.res_list.objBegin(); + const auto res_end = args.res_list.objEnd(); + + while (res_it != res_end && it != end) { + u32 type_index = -1; + const auto TypeIndex = agl::utl::getResParameter(res_it.getObj(), "TypeIndex"); + if (TypeIndex.ptr()) + type_index = *TypeIndex.getData<int>(); + + // TODO: add a TypeIndex enum + it->type_index = type_index > 33 ? 88 : int(type_index) + 54; + + it->frame.init(0.0, "Frame", "フレーム", "Min=0.f,Max=100.f", &it->obj); + it->value.init("", "Value", "値", "", &it->obj); + + obj_name.trim(obj_name_prefix_len); + obj_name.appendWithFormat("%d", it.getIndex()); + mList.addObj(&it->obj, obj_name); + + ++res_it; + ++it; + } + + return true; +} + +bool ASHoldEventsParser::parse(const ASParamParser::ParseArgs& args) { + const int num_objs = args.res_list.getResParameterObjNum(); + if (num_objs == 0) + return true; + + if (!mEvents.tryAllocBuffer(num_objs, args.heap)) + return false; + + auto it = mEvents.begin(); + const auto end = mEvents.end(); + + sead::FixedSafeString<32> obj_name{"Event"}; + const auto obj_name_prefix_len = obj_name.calcLength(); + + auto res_it = args.res_list.objBegin(); + const auto res_end = args.res_list.objEnd(); + + while (res_it != res_end && it != end) { + u32 type_index = -1; + const auto TypeIndex = agl::utl::getResParameter(res_it.getObj(), "TypeIndex"); + if (TypeIndex.ptr()) + type_index = *TypeIndex.getData<int>(); + + // TODO: add a TypeIndex enum + it->type_index = type_index > 53 ? 88 : int(type_index); + + it->start_frame.init(0.0, "StartFrame", "開始フレーム", "Min=0.f,Max=100.f", &it->obj); + it->end_frame.init(0.0, "EndFrame", "終了フレーム", "Min=0.f,Max=100.f", &it->obj); + it->value.init("", "Value", "値", "", &it->obj); + + obj_name.trim(obj_name_prefix_len); + obj_name.appendWithFormat("%d", it.getIndex()); + mList.addObj(&it->obj, obj_name); + + ++res_it; + ++it; + } + + return true; +} + +bool ASStringArrayParser::parse(const ASParamParser::ParseArgs& args) { + const int size = args.res_list.getResParameterObj(0).getNum(); + if (size != 0) { + if (!mValues.tryAllocBuffer(size, args.heap)) + return false; + + sead::FixedSafeString<32> param_name{"Value"}; + const auto param_name_prefix_len = param_name.calcLength(); + + for (int i = 0; i < size; ++i) { + param_name.trim(param_name_prefix_len); + param_name.appendWithFormat("%d", i); + mValues[i].value.init("", param_name, "値", "", &mObj); + } + } + + mList.addObj(&mObj, "StringArray0"); + return true; +} + +bool ASRangesParser::parse(const ASParamParser::ParseArgs& args) { + const int num_objs = args.res_list.getResParameterObjNum(); + if (num_objs == 0) + return true; + + if (!mRanges.tryAllocBuffer(num_objs, args.heap)) + return false; + + auto it = mRanges.begin(); + const auto end = mRanges.end(); + + sead::FixedSafeString<32> obj_name{"Range"}; + const auto obj_name_prefix_len = obj_name.calcLength(); + + auto res_it = args.res_list.objBegin(); + const auto res_end = args.res_list.objEnd(); + + while (res_it != res_end && it != end) { + obj_name.trim(obj_name_prefix_len); + obj_name.appendWithFormat("%d", it.getIndex()); + + it->start.init(0.0, "Start", "開始", "Min=0.f,Max=1.f", &it->obj); + it->end.init(0.0, "End", "終了", "Min=0.f,Max=1.f", &it->obj); + + mList.addObj(&it->obj, obj_name); + + ++res_it; + ++it; + } + + return true; +} + +bool ASFloatArrayParser::parse(const ASParamParser::ParseArgs& args) { + const int size = args.res_list.getResParameterObj(0).getNum(); + if (size != 0) { + if (!mValues.tryAllocBuffer(size, args.heap)) + return false; + + sead::FixedSafeString<32> param_name{"Value"}; + const auto param_name_prefix_len = param_name.calcLength(); + + for (int i = 0; i < size; ++i) { + param_name.trim(param_name_prefix_len); + param_name.appendWithFormat("%d", i); + mValues[i].value.init(1.0, param_name, "値", "", &mObj); + } + } + + mList.addObj(&mObj, "FloatArray0"); + return true; +} + +bool ASIntArrayParser::parse(const ASParamParser::ParseArgs& args) { + const int size = args.res_list.getResParameterObj(0).getNum(); + if (size != 0) { + if (!mValues.tryAllocBuffer(size, args.heap)) + return false; + + sead::FixedSafeString<32> param_name{"Value"}; + const auto param_name_prefix_len = param_name.calcLength(); + + for (int i = 0; i < size; ++i) { + param_name.trim(param_name_prefix_len); + param_name.appendWithFormat("%d", i); + mValues[i].value.init(1, param_name, "値", "", &mObj); + } + } + + mList.addObj(&mObj, "IntArray0"); + return true; +} + +bool ASBitIndexParser::parse(const ASParamParser::ParseArgs& args) { + const auto obj = args.res_list.getResParameterObj(0); + if (obj.getNum() < 1) + return true; + + const auto TypeIndex = agl::utl::getResParameter(obj, "TypeIndex"); + if (!TypeIndex.ptr()) + return true; + + mTypeIndex = *TypeIndex.getData<int>(); + return true; +} + +template <typename T> +static ASParamParser* factoryImpl_(sead::Heap* heap) { + return new (heap) T; +} + +static ASParamParser* dummyASParserFactoryImpl_(sead::Heap*) { + return nullptr; +} + +namespace { +struct Factory { + const char* name; + ASParamParser* (*make)(sead::Heap* heap); +}; + +sead::SafeArray<Factory, ASParamParser::NumTypes> sASFactories{{ + {"FrameCtrl", factoryImpl_<ASFrameCtrlParser>}, + {"TriggerEvents", factoryImpl_<ASTriggerEventsParser>}, + {"HoldEvents", factoryImpl_<ASHoldEventsParser>}, + {"StringArray", factoryImpl_<ASStringArrayParser>}, + {"Ranges", factoryImpl_<ASRangesParser>}, + {"FloatArray", factoryImpl_<ASFloatArrayParser>}, + {"IntArray", factoryImpl_<ASIntArrayParser>}, + {"BitIndex", factoryImpl_<ASBitIndexParser>}, + {"BlenderBone", dummyASParserFactoryImpl_}, +}}; +} // namespace + +ASExtensions::~ASExtensions() { + for (auto*& parser : mParsers) { + if (parser && parser->getType() != ASParamParser::Type::BlenderBone) + delete parser; + parser = nullptr; + } + mParsers.freeBuffer(); +} + +bool ASExtensions::parse(const ASExtensions::ParseArgs& args) { + const auto Extend = agl::utl::getResParameterList(args.res_list, "Extend"); + if (!Extend) + return true; + + const auto num_extensions = Extend.getResParameterListNum(); + if (num_extensions == 0) + return true; + + if (!mParsers.tryAllocBuffer(num_extensions, args.heap)) + return false; + for (int i = 0, n = mParsers.size(); i < n; ++i) + mParsers(i) = nullptr; + + auto it = mParsers.begin(); + const auto end = mParsers.end(); + + ASParamParser::ParseArgs parse_args{}; + parse_args.list = &mList; + parse_args.heap = args.heap; + + auto res_it = Extend.listBegin(); + const auto res_end = Extend.listEnd(); + + for (; it != end && res_it != res_end; ++it, ++res_it) { + parse_args.res_list = res_it.getList(); + *it = makeParser(parse_args); + + constexpr int bone = int(ASParamParser::Type::BlenderBone); + if (*it == nullptr && parse_args.res_list.getParameterListNameHash() != + agl::utl::ParameterBase::calcHash(sASFactories[bone].name)) { + return false; + } + } + + args.list->addList(&mList, "Extend"); + return true; +} + +ASParamParser* ASExtensions::makeParser(const ASParamParser::ParseArgs& args) const { + const auto is_factory = [&args](int i) { + return args.res_list.getParameterListNameHash() == + agl::utl::ParameterBase::calcHash(sASFactories[i].name); + }; + + std::optional<int> type; + for (int i = 0; i < ASParamParser::NumTypes - 1; ++i) { + if (!is_factory(i)) + continue; + type = i; + break; + } + + if (!type.has_value() && is_factory(int(ASParamParser::Type::BlenderBone))) { + const auto obj = args.res_list.getResParameterObj(0); + if (obj.getNum() > 0) { + const sead::SafeString name = obj.getResParameter(0).getData<const char>(); + return act::ASSetting::instance()->getBoneParams(name); + } + } + + if (!type.has_value()) + return nullptr; + + const auto& factory = sASFactories[*type]; + + auto* parser = factory.make(args.heap); + if (!parser) + return nullptr; + + if (!parser->parse(args)) { + delete parser; + return nullptr; + } + + args.list->addList(&parser->getList(), factory.name); + return parser; +} + +ASParamParser* ASExtensions::getParser(ASParamParser::Type type) const { + for (int i = 0, n = mParsers.size(); i < n; ++i) { + auto* parser = mParsers[i]; + if (parser && parser->getType() == type) + return parser; + } + return nullptr; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceASResourceExtension.h b/src/KingSystem/Resource/Actor/resResourceASResourceExtension.h new file mode 100644 index 00000000..fd244cc6 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceASResourceExtension.h @@ -0,0 +1,259 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglParameterObj.h> +#include <agl/Utils/aglResParameter.h> +#include <array> +#include <basis/seadTypes.h> +#include <container/seadBuffer.h> +#include <prim/seadRuntimeTypeInfo.h> +#include "KingSystem/Utils/Types.h" + +namespace sead { +class Heap; +} + +namespace ksys::res { + +class ASParamParser { + SEAD_RTTI_BASE(ASParamParser) +public: + enum class Type { + FrameCtrl = 0, + TriggerEvents = 1, + HoldEvents = 2, + StringArray = 3, + Ranges = 4, + FloatArray = 5, + IntArray = 6, + BitIndex = 7, + BlenderBone = 8, + }; + static constexpr int NumTypes = 9; + + struct ParseArgs { + agl::utl::ParameterList* list; + agl::utl::ResParameterList res_list; + sead::Heap* heap; + }; + + explicit ASParamParser(Type type) : mType(type) {} + virtual ~ASParamParser() = default; + virtual bool parse(const ParseArgs& args) { return true; } + + Type getType() const { return mType; } + agl::utl::ParameterList& getList() { return mList; } + const agl::utl::ParameterList& getList() const { return mList; } + +protected: + Type mType; + agl::utl::ParameterList mList; +}; +KSYS_CHECK_SIZE_NX150(ASParamParser, 0x58); + +class ASExtensions { +public: + struct ParseArgs { + agl::utl::ResParameterList res_list; + agl::utl::ParameterList* list; + sead::Heap* heap; + }; + + ASExtensions() = default; + ~ASExtensions(); + ASExtensions(const ASExtensions&) = delete; + auto operator=(const ASExtensions&) = delete; + + const sead::Buffer<ASParamParser*>& getParsers() const { return mParsers; } + ASParamParser* getParser(ASParamParser::Type type) const; + + bool parse(const ParseArgs& args); + +private: + ASParamParser* makeParser(const ASParamParser::ParseArgs& args) const; + + agl::utl::ParameterList mList; + sead::Buffer<ASParamParser*> mParsers; +}; + +class ASFrameCtrlParser : public ASParamParser { + SEAD_RTTI_OVERRIDE(ASFrameCtrlParser, ASParamParser) +public: + ASFrameCtrlParser() : ASParamParser(Type::FrameCtrl) {} + + const auto& getRate() const { return *mRate; } + const auto& getStartFrame() const { return *mStartFrame; } + const auto& getEndFrame() const { return *mEndFrame; } + const auto& getLoopStopCount() const { return *mLoopStopCount; } + const auto& getLoopStopCountRandom() const { return *mLoopStopCountRandom; } + const auto& getReversePlay() const { return *mReversePlay; } + const auto& getUseGlobalFrame() const { return *mUseGlobalFrame; } + const auto& getConnect() const { return *mConnect; } + const auto& getFootType() const { return *mFootType; } + const auto& getAnmLoop() const { return *mAnmLoop; } + + bool parse(const ParseArgs& args) override; + +private: + agl::utl::ParameterObj mObj; + agl::utl::Parameter<float> mRate; + agl::utl::Parameter<float> mStartFrame; + agl::utl::Parameter<float> mEndFrame; + agl::utl::Parameter<float> mLoopStopCount; + agl::utl::Parameter<float> mLoopStopCountRandom; + agl::utl::Parameter<bool> mReversePlay; + agl::utl::Parameter<bool> mUseGlobalFrame; + agl::utl::Parameter<int> mConnect; + agl::utl::Parameter<int> mFootType; + agl::utl::Parameter<int> mAnmLoop; +}; + +class ASTriggerEventsParser : public ASParamParser { + SEAD_RTTI_OVERRIDE(ASTriggerEventsParser, ASParamParser) +public: + struct Event { + agl::utl::ParameterObj obj; + int type_index; + agl::utl::Parameter<float> frame; + agl::utl::Parameter<sead::SafeString> value; + }; + + ASTriggerEventsParser() : ASParamParser(Type::TriggerEvents) {} + ~ASTriggerEventsParser() override { mEvents.freeBuffer(); } + ASTriggerEventsParser(const ASTriggerEventsParser&) = delete; + auto operator=(const ASTriggerEventsParser&) = delete; + + const sead::Buffer<Event>& getEvents() const { return mEvents; } + + bool parse(const ParseArgs& args) override; + +private: + sead::Buffer<Event> mEvents; +}; + +class ASHoldEventsParser : public ASParamParser { + SEAD_RTTI_OVERRIDE(ASHoldEventsParser, ASParamParser) +public: + struct Event { + agl::utl::ParameterObj obj; + int type_index; + agl::utl::Parameter<float> start_frame; + agl::utl::Parameter<float> end_frame; + agl::utl::Parameter<sead::SafeString> value; + }; + + ASHoldEventsParser() : ASParamParser(Type::HoldEvents) {} + ~ASHoldEventsParser() override { mEvents.freeBuffer(); } + ASHoldEventsParser(const ASHoldEventsParser&) = delete; + auto operator=(const ASHoldEventsParser&) = delete; + + const sead::Buffer<Event>& getEvents() const { return mEvents; } + + bool parse(const ParseArgs& args) override; + +private: + sead::Buffer<Event> mEvents; +}; + +class ASStringArrayParser : public ASParamParser { + SEAD_RTTI_OVERRIDE(ASStringArrayParser, ASParamParser) +public: + struct Value { + agl::utl::Parameter<sead::SafeString> value; + }; + + ASStringArrayParser() : ASParamParser(Type::StringArray) {} + ~ASStringArrayParser() override { mValues.freeBuffer(); } + ASStringArrayParser(const ASStringArrayParser&) = delete; + auto operator=(const ASStringArrayParser&) = delete; + + const sead::Buffer<Value>& getValues() const { return mValues; } + + bool parse(const ParseArgs& args) override; + +private: + agl::utl::ParameterObj mObj; + sead::Buffer<Value> mValues; +}; + +class ASRangesParser : public ASParamParser { + SEAD_RTTI_OVERRIDE(ASRangesParser, ASParamParser) +public: + struct Range { + agl::utl::ParameterObj obj; + agl::utl::Parameter<float> start; + agl::utl::Parameter<float> end; + }; + + ASRangesParser() : ASParamParser(Type::Ranges) {} + ~ASRangesParser() override { mRanges.freeBuffer(); } + ASRangesParser(const ASRangesParser&) = delete; + auto operator=(const ASRangesParser&) = delete; + + const sead::Buffer<Range>& getRanges() const { return mRanges; } + + bool parse(const ParseArgs& args) override; + +private: + sead::Buffer<Range> mRanges; +}; + +class ASFloatArrayParser : public ASParamParser { + SEAD_RTTI_OVERRIDE(ASFloatArrayParser, ASParamParser) +public: + struct Value { + agl::utl::Parameter<float> value; + }; + + ASFloatArrayParser() : ASParamParser(Type::FloatArray) {} + + ~ASFloatArrayParser() override { mValues.freeBuffer(); } + ASFloatArrayParser(const ASFloatArrayParser&) = delete; + auto operator=(const ASFloatArrayParser&) = delete; + + const sead::Buffer<Value>& getValues() const { return mValues; } + + bool parse(const ParseArgs& args) override; + +private: + agl::utl::ParameterObj mObj; + sead::Buffer<Value> mValues; +}; + +class ASIntArrayParser : public ASParamParser { + SEAD_RTTI_OVERRIDE(ASIntArrayParser, ASParamParser) +public: + struct Value { + agl::utl::Parameter<int> value; + }; + + ASIntArrayParser() : ASParamParser(Type::IntArray) {} + + ~ASIntArrayParser() override { mValues.freeBuffer(); } + ASIntArrayParser(const ASIntArrayParser&) = delete; + auto operator=(const ASIntArrayParser&) = delete; + + const sead::Buffer<Value>& getValues() const { return mValues; } + + bool parse(const ParseArgs& args) override; + +private: + agl::utl::ParameterObj mObj; + sead::Buffer<Value> mValues; +}; + +class ASBitIndexParser : public ASParamParser { + SEAD_RTTI_OVERRIDE(ASBitIndexParser, ASParamParser) +public: + ASBitIndexParser() : ASParamParser(Type::BitIndex) {} + + int getBitIndex() const { return mTypeIndex; } + + bool parse(const ParseArgs& args) override; + +private: + int mTypeIndex = -1; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceActorCapture.cpp b/src/KingSystem/Resource/Actor/resResourceActorCapture.cpp new file mode 100644 index 00000000..a2d0b3f4 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceActorCapture.cpp @@ -0,0 +1,61 @@ +#include "KingSystem/Resource/Actor/resResourceActorCapture.h" + +namespace ksys::res { + +static ActorCapture::ActorCaptureConstants sConstants; + +const ActorCapture::ActorCaptureConstants& ActorCapture::getConstants() { + return sConstants; +} + +ActorCapture::ActorCapture() : ParamIO("actcapt", 0) { + addObj(&mCameraInfoObj, "camera_info"); + mCameraInfoObj.position.init(sConstants.camera_position, "pos", "カメラ位置", &mCameraInfoObj); + mCameraInfoObj.direction.init(sConstants.camera_direction, "at", "カメラ注視点", + &mCameraInfoObj); + mCameraInfoObj.fov.init(50.0, "fovy", "カメラ画角", &mCameraInfoObj); + mCameraInfoObj.tilt.init(0.0, "twist", "カメラひねり", &mCameraInfoObj); + + addObj(&mActorInfoObj, "actor_info"); + mActorInfoObj.position.init(sConstants.actor_position, "pos", "アクタ位置", &mActorInfoObj); + mActorInfoObj.rotation.init(sConstants.actor_rotation, "rotate", "アクタRotate", + &mActorInfoObj); + mActorInfoObj.as_name.init(sead::SafeString::cEmptyString, "as_name", "適用するASのKey名", + &mActorInfoObj); + mActorInfoObj.apply_skel_anim.init(false, "apply_skl_anim", + "スケルタルアニメを検索して直接適用する", &mActorInfoObj); + mActorInfoObj.frame.init(0.0, "as_frame", "ASのフレーム・経過時間指定", &mActorInfoObj); + mActorInfoObj.bounding_adjustment.init(false, "adjust_bounding", + "バウンディングを元に位置を調整する", &mActorInfoObj); + mActorInfoObj.force_idle.init(false, "force_idle", "強制待機", &mActorInfoObj); + mActorInfoObj.disable_cloth.init(false, "disable_cloth", "クロスを切る", &mActorInfoObj); + + addObj(&mLightInfoObj, "light_info"); + mLightInfoObj.direction.init(sConstants.light_direction, "dir", "ライト方向", &mLightInfoObj); +} + +bool ActorCapture::parse_(u8* data, size_t, sead::Heap*) { + if (data) + applyResParameterArchive(agl::utl::ResParameterArchive(data)); + return true; +} + +void ActorCapture::reset() { + mCameraInfoObj.position.ref() = sConstants.camera_position; + mCameraInfoObj.direction.ref() = sConstants.camera_direction; + mCameraInfoObj.fov.ref() = 50; + mCameraInfoObj.tilt.ref() = 0; + + mActorInfoObj.position.ref() = sConstants.actor_position; + mActorInfoObj.rotation.ref() = sConstants.actor_rotation; + mActorInfoObj.as_name.ref().copy(sead::FixedSafeString<32>(sead::SafeString::cEmptyString)); + mActorInfoObj.apply_skel_anim.ref() = false; + mActorInfoObj.frame.ref() = 0; + mActorInfoObj.bounding_adjustment.ref() = false; + mActorInfoObj.force_idle.ref() = false; + mActorInfoObj.disable_cloth.ref() = false; + + mLightInfoObj.direction.ref() = sConstants.light_direction; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceActorCapture.h b/src/KingSystem/Resource/Actor/resResourceActorCapture.h new file mode 100644 index 00000000..51145a68 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceActorCapture.h @@ -0,0 +1,72 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include <math/seadVector.h> +#include <prim/seadSafeString.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class ActorCapture : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(ActorCapture, Resource) +public: + struct ActorCaptureConstants { + // NON_MATCHING: equivalent but reordered + ActorCaptureConstants() { + camera_position = {0.0, 2.0, 5.0}; + camera_direction = {0.0, 2.0, 0.0}; + light_direction = {0.5720610022544861, -0.7071070075035095, -0.41562700271606445}; + actor_position = sead::Vector3f::zero; + actor_rotation = sead::Vector3f::zero; + } + sead::Vector3f camera_position; + sead::Vector3f camera_direction; + sead::Vector3f light_direction; + sead::Vector3f actor_position; + sead::Vector3f actor_rotation; + }; + + struct CameraInfo : agl::utl::ParameterObj { + agl::utl::Parameter<sead::Vector3f> position; + agl::utl::Parameter<sead::Vector3f> direction; + agl::utl::Parameter<f32> fov; + agl::utl::Parameter<f32> tilt; + }; + + struct ActorInfo : agl::utl::ParameterObj { + agl::utl::Parameter<sead::Vector3f> position; + agl::utl::Parameter<sead::Vector3f> rotation; + agl::utl::Parameter<sead::FixedSafeString<32>> as_name; + agl::utl::Parameter<bool> apply_skel_anim; + agl::utl::Parameter<f32> frame; + agl::utl::Parameter<bool> bounding_adjustment; + agl::utl::Parameter<bool> force_idle; + agl::utl::Parameter<bool> disable_cloth; + }; + + struct LightInfo : agl::utl::ParameterObj { + agl::utl::Parameter<sead::Vector3f> direction; + }; + + ActorCapture(); + + void doCreate_(u8*, u32, sead::Heap*) override {} + bool needsParse() const override { return true; } + bool ParamIO_m0(char* data) override { return true; } + + void reset(); + + static const ActorCaptureConstants& getConstants(); + + CameraInfo mCameraInfoObj; + ActorInfo mActorInfoObj; + LightInfo mLightInfoObj; + +private: + bool parse_(u8* data, size_t size, sead::Heap* heap) override; +}; +KSYS_CHECK_SIZE_NX150(ActorCapture, 0x538); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceActorLink.cpp b/src/KingSystem/Resource/Actor/resResourceActorLink.cpp new file mode 100644 index 00000000..d941d417 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceActorLink.cpp @@ -0,0 +1,103 @@ +#include "KingSystem/Resource/Actor/resResourceActorLink.h" +#include <codec/seadHashCRC32.h> +#include <heap/seadHeapMgr.h> + +namespace ksys::res { + +ActorLink::ActorLink() : ParamIO("xml", 0) { + const auto init_user = [this](auto& param, const char* key, const char* default_ = "Dummy") { + param.init(default_, key, "", &mUsers.obj); + }; + init_user(mUsers.profile, "ProfileUser"); + init_user(mUsers.actor_capture, "ActorCaptureUser"); + init_user(mUsers.as, "ASUser", ""); + init_user(mUsers.model, "ModelUser", ""); + init_user(mUsers.anim, "AnimUser", ""); + init_user(mUsers.ai_program, "AIProgramUser", ""); + init_user(mUsers.gparam, "GParamUser", ""); + init_user(mUsers.damage_param, "DamageParamUser"); + init_user(mUsers.rg_config_list, "RgConfigListUser"); + init_user(mUsers.rg_blend_weight, "RgBlendWeightUser"); + init_user(mUsers.awareness, "AwarenessUser"); + init_user(mUsers.elink, "ElinkUser"); + init_user(mUsers.slink, "SlinkUser"); + init_user(mUsers.xlink, "XlinkUser"); + init_user(mUsers.attention, "AttentionUser"); + init_user(mUsers.physics, "PhysicsUser"); + init_user(mUsers.chemical, "ChemicalUser"); + init_user(mUsers.drop_table, "DropTableUser"); + init_user(mUsers.shop_data, "ShopDataUser"); + init_user(mUsers.recipe, "RecipeUser"); + init_user(mUsers.lod, "LODUser"); + init_user(mUsers.ai_schedule, "AIScheduleUser"); + init_user(mUsers.bone_control, "BoneControlUser"); + init_user(mUsers.life_condition, "LifeConditionUser"); + init_user(mUsers.umii, "UMiiUser"); + init_user(mUsers.animation_info, "AnimationInfo"); + + mActorScale.init(1.0, "ActorScale", "", &mUsers.obj); + mActorNameJpn.init("不正な名前", "ActorNameJpn", "ActorNameJpn", &mUsers.obj); + mPriority.init("", "Priority", "Priority", &mUsers.obj); + + addObj(&mUsers.obj, "LinkTarget"); +} + +bool ActorLink::parse_(u8* data, size_t, sead::Heap* heap) { + if (!data) + return true; + + const agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + + const s32 tags_idx = root.searchObjIndex(agl::utl::ParameterBase::calcHash("Tags")); + // NON_MATCHING: getResParameter (redundant uxtw; i and res increment order) + const auto parse_tags = [&] { + if (tags_idx == -1) + return; + + const auto obj = root.getResParameterObj(tags_idx); + if (!obj.ptr()) + return; + + const auto num_tags = obj.getNum(); + if (num_tags == 0) + return; + + mHeap = heap; + mTags.allocBufferAssert(num_tags, heap); + + for (s32 i = 0; i != num_tags; ++i) { + const char* tag = obj.getResParameter(i).getData<char>(); + mTags[i] = sead::HashCRC32::calcStringHash(tag); + } + + if (num_tags > 1) + mTags.heapSort(0, num_tags - 1); + }; + parse_tags(); + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + return true; +} + +void ActorLink::finalize_() { + if (!mTags.isBufferReady()) + return; + + if (!mHeap) + return; + + sead::ScopedCurrentHeapSetter setter{mHeap}; + mTags.freeBuffer(); +} + +// NON_MATCHING: operands are swapped for an equality comparison in binarySearch +bool ActorLink::hasTag(const char* tag_name) const { + return mTags.size() >= 1 && mTags.binarySearch(sead::HashCRC32::calcStringHash(tag_name)) != -1; +} + +bool ActorLink::hasTag(u32 tag) const { + return mTags.size() >= 1 && mTags.binarySearch(tag) != -1; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceActorLink.h b/src/KingSystem/Resource/Actor/resResourceActorLink.h new file mode 100644 index 00000000..0b2f017e --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceActorLink.h @@ -0,0 +1,137 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include "KingSystem/ActorSystem/actTag.h" +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class ActorLink : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(ActorLink, Resource) +public: + enum class User { + Profile = 0, + ActorCapture = 1, + AS = 2, + Model = 3, + Anim = 4, + AIProgram = 5, + GParam = 6, + DamageParam = 7, + RgConfigList = 8, + RgBlendWeight = 9, + Awareness = 10, + Physics = 11, + Chemical = 12, + Attention = 13, + ELink = 14, + SLink = 15, + XLink = 16, + DropTable = 17, + ShopData = 18, + Recipe = 19, + LOD = 20, + BoneControl = 21, + AISchedule = 22, + LifeCondition = 23, + UMii = 24, + AnimationInfo = 25, + }; + + struct Users { + const agl::utl::Parameter<sead::SafeString>& getUser(User user) const { + return *(&profile + u32(user)); + } + + const char* getUserName(User user) const { return getUser(user).ref().cstr(); } + + const char* getProfile() const { return profile.ref().cstr(); } + const char* getActorCapture() const { return actor_capture.ref().cstr(); } + const char* getAS() const { return as.ref().cstr(); } + const char* getModel() const { return model.ref().cstr(); } + const char* getAnim() const { return anim.ref().cstr(); } + const char* getAIProgram() const { return ai_program.ref().cstr(); } + const char* getGParam() const { return gparam.ref().cstr(); } + const char* getDamageParam() const { return damage_param.ref().cstr(); } + const char* getRgConfigList() const { return rg_config_list.ref().cstr(); } + const char* getRgBlendWeight() const { return rg_blend_weight.ref().cstr(); } + const char* getAwareness() const { return awareness.ref().cstr(); } + const char* getPhysics() const { return physics.ref().cstr(); } + const char* getChemical() const { return chemical.ref().cstr(); } + const char* getAttention() const { return attention.ref().cstr(); } + const char* getELink() const { return elink.ref().cstr(); } + const char* getSLink() const { return slink.ref().cstr(); } + const char* getXLink() const { return xlink.ref().cstr(); } + const char* getDropTable() const { return drop_table.ref().cstr(); } + const char* getShopData() const { return shop_data.ref().cstr(); } + const char* getRecipe() const { return recipe.ref().cstr(); } + const char* getLOD() const { return lod.ref().cstr(); } + const char* getBoneControl() const { return bone_control.ref().cstr(); } + const char* getAISchedule() const { return ai_schedule.ref().cstr(); } + const char* getLifeCondition() const { return life_condition.ref().cstr(); } + const char* getUMii() const { return umii.ref().cstr(); } + const char* getAnimationInfo() const { return animation_info.ref().cstr(); } + + agl::utl::Parameter<sead::SafeString> profile; + agl::utl::Parameter<sead::SafeString> actor_capture; + agl::utl::Parameter<sead::SafeString> as; + agl::utl::Parameter<sead::SafeString> model; + agl::utl::Parameter<sead::SafeString> anim; + agl::utl::Parameter<sead::SafeString> ai_program; + agl::utl::Parameter<sead::SafeString> gparam; + agl::utl::Parameter<sead::SafeString> damage_param; + agl::utl::Parameter<sead::SafeString> rg_config_list; + agl::utl::Parameter<sead::SafeString> rg_blend_weight; + agl::utl::Parameter<sead::SafeString> awareness; + agl::utl::Parameter<sead::SafeString> physics; + agl::utl::Parameter<sead::SafeString> chemical; + agl::utl::Parameter<sead::SafeString> attention; + agl::utl::Parameter<sead::SafeString> elink; + agl::utl::Parameter<sead::SafeString> slink; + agl::utl::Parameter<sead::SafeString> xlink; + agl::utl::Parameter<sead::SafeString> drop_table; + agl::utl::Parameter<sead::SafeString> shop_data; + agl::utl::Parameter<sead::SafeString> recipe; + agl::utl::Parameter<sead::SafeString> lod; + agl::utl::Parameter<sead::SafeString> bone_control; + agl::utl::Parameter<sead::SafeString> ai_schedule; + agl::utl::Parameter<sead::SafeString> life_condition; + agl::utl::Parameter<sead::SafeString> umii; + agl::utl::Parameter<sead::SafeString> animation_info; + agl::utl::ParameterObj obj; + }; + + ActorLink(); + + void doCreate_(u8*, u32, sead::Heap*) override {} + bool needsParse() const override { return true; } + + const Users& getUsers() const { return mUsers; } + const char* getUserName(User user) const { return getUsers().getUserName(user); } + const sead::SafeString& getActorNameJpn() const { return mActorNameJpn.ref(); } + const sead::SafeString& getPriority() const { return mPriority.ref(); } + f32 getActorScale() const { return mActorScale.ref(); } + + bool hasTag(const char* tag_name) const; + bool hasTag(u32 tag) const; + + const sead::Buffer<u32>& getTags() const { return mTags; } + +private: + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + void finalize_() override; + + Users mUsers; + agl::utl::Parameter<sead::SafeString> mActorNameJpn; + agl::utl::Parameter<sead::SafeString> mPriority; + agl::utl::Parameter<f32> mActorScale; + sead::Buffer<u32> mTags; + sead::Heap* mHeap = nullptr; +}; +KSYS_CHECK_SIZE_NX150(ActorLink, 0x778); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAnimInfo.cpp b/src/KingSystem/Resource/Actor/resResourceAnimInfo.cpp new file mode 100644 index 00000000..7c6da1b0 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAnimInfo.cpp @@ -0,0 +1,132 @@ +#include "KingSystem/Resource/Actor/resResourceAnimInfo.h" +#include "KingSystem/Utils/Byaml/Byaml.h" +#include "KingSystem/Utils/SafeDelete.h" + +namespace ksys::res { + +AnimInfo::AnimInfo() : ParamIO("animinfo", 0) {} + +AnimInfo::~AnimInfo() { + mAnims.freeBuffer(); + + if (mSwordBlurInfo) { + mSwordBlurInfo->finalize(); + util::safeDelete(mSwordBlurInfo); + } +} + +void AnimInfo::SwordBlurInfo::finalize() { + if (!entries) + return; + + for (int i = 0; i < num_entries; ++i) { + SwordBlur& entry = entries[i]; + auto* h = heap; + if (entry.frames) { + h->free(entry.frames); + entry.frames = nullptr; + } + if (entry._18) { + h->free(entry._18); + entry._18 = nullptr; + } + } + + heap->free(entries); + entries = nullptr; +} + +void AnimInfo::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} + +bool AnimInfo::parse_(u8* data, size_t size, sead::Heap* heap) { + al::ByamlIter root_iter{data}; + + const int num_entries = root_iter.getSize(); + int num_anims = num_entries - 1; + if (num_entries < 1) + return true; + + al::ByamlIter iter; + int double_attack_anm_num = 0; + int num = 0; + bool allocate_anims = false; + if (root_iter.isExistKey("_sword_blur")) { + iter = root_iter.getIterByKey("_sword_blur"); + const int num_sword_blurs = iter.getSize(); + iter.tryGetIntByKey(&double_attack_anm_num, "double_attack_anm_num"); + num = num_sword_blurs - 1; + if (num_entries > 1) + allocate_anims = true; + } else { + num = 0; + num_anims = num_entries; + allocate_anims = true; + } + + if (allocate_anims) { + if (!mAnims.tryAllocBuffer(num_anims, heap)) + return false; + + for (int i = 0; i < num_anims; ++i) { + auto& anim = mAnims[i]; + anim.scale.e.fill(0.0); + + al::ByamlIter entry_iter; + if (root_iter.tryGetIterByIndex(&entry_iter, i)) { + const char* name_c; + if (root_iter.getKeyName(&name_c, i)) { + if (std::strcmp(name_c, "_sword_blur") == 0) + continue; + anim.name = name_c; + } else { + anim.name = ""; + } + entry_iter.tryGetFloatByKey(&anim.scale.x, "scaleX"); + entry_iter.tryGetFloatByKey(&anim.scale.y, "scaleY"); + entry_iter.tryGetFloatByKey(&anim.scale.z, "scaleZ"); + } else { + anim.name = ""; + } + } + } + + if (num >= 1) { + if (!mSwordBlurInfo) { + auto* info = new (heap) SwordBlurInfo; + info->entries = nullptr; + mSwordBlurInfo = info; + info->heap = heap; + info->num_entries = double_attack_anm_num; + /// @bug SwordBlur is not trivially constructible and not trivially copyable. + /// The only reason using SwordBlur::name doesn't crash is that Clang and GHS + /// are smart enough to devirtualize sead::SafeString virtual function calls, + /// which removes the need to go through the vtable. +#ifdef AVOID_UB + info->entries = new (heap) SwordBlur[info->num_entries]; +#else + info->entries = static_cast<SwordBlur*>( + heap->tryAlloc(sizeof(SwordBlur) * info->num_entries, alignof(SwordBlur))); + std::memset(info->entries, 0, sizeof(SwordBlur) * info->num_entries); +#endif + } + + // TODO / FIXME: finish this + } + + return true; +} + +const AnimInfo::Anim* AnimInfo::getAnim(const sead::SafeString& name) const { + const auto idx = findAnimIndex(name); + if (idx < 0) + return nullptr; + return &mAnims[idx]; +} + +int AnimInfo::findAnimIndex(const sead::SafeString& name) const { + return mAnims.binarySearch( + name, + +[](const Anim& anim, const sead::SafeString& key) { return anim.name.compare(key); }); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAnimInfo.h b/src/KingSystem/Resource/Actor/resResourceAnimInfo.h new file mode 100644 index 00000000..b27e28a7 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAnimInfo.h @@ -0,0 +1,59 @@ +#pragma once + +#include <container/seadBuffer.h> +#include <math/seadMatrix.h> +#include <math/seadVector.h> +#include <prim/seadSafeString.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +// TODO +class AnimInfo : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(AnimInfo, Resource) +public: + struct Anim { + sead::SafeString name; + sead::Vector3f scale; + }; + KSYS_CHECK_SIZE_NX150(Anim, 0x20); + + struct SwordBlur { + int frame_num; + int start; + int end; + sead::Matrix34f* frames; + float* _18; + sead::SafeString name; + }; + KSYS_CHECK_SIZE_NX150(SwordBlur, 0x30); + + AnimInfo(); + ~AnimInfo() override; + + bool needsParse() const override { return true; } + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + + const sead::Buffer<Anim>& getAnims() const { return mAnims; } + + const Anim* getAnim(const sead::SafeString& name) const; + int findAnimIndex(const sead::SafeString& name) const; + +private: + struct SwordBlurInfo { + void finalize(); + + sead::Heap* heap; + int num_entries; + SwordBlur* entries; + }; + KSYS_CHECK_SIZE_NX150(SwordBlurInfo, 0x18); + + sead::Buffer<Anim> mAnims; + SwordBlurInfo* mSwordBlurInfo = nullptr; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAttCheck.cpp b/src/KingSystem/Resource/Actor/resResourceAttCheck.cpp new file mode 100644 index 00000000..e75d35d1 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAttCheck.cpp @@ -0,0 +1,200 @@ +#include "KingSystem/Resource/Actor/resResourceAttCheck.h" + +namespace ksys::res { + +void AttCheck::m4() {} + +bool AttCheck::check() { + return true; +} + +float AttCheck::m6() { + return -1.0; +} + +bool AttCheckLine::parse(const CreateArg& arg) { + mRadius.init(0.0, "Radius", "半径", "Min=0,Max=10", &mObj); + mAsLineOfSight.init(false, "AsLineOfSight", "視線を透かすコリジョンを無視する", "", &mObj); + return true; +} + +bool AttCheckArea::parse(const CreateArg& arg) { + mAttPos.init(&mObj); + mFromPlayer.init(false, "FromPlayer", "目標側基準", "", &mObj); + return true; +} + +bool AttCheckAreaSphere::parse(const CreateArg& arg) { + mForceEditModelArea.init(false, "ForceEditModelArea", "(モデル範囲)強制編集", "", &mObj); + mRadius.init(0.0, "Radius", "(モデル範囲)半径", "Min=0.f,Max=100.f", &mObj); + mFixedRadius.init(-1.0, "FixedRadius", "(アテンション範囲)半径", "Min=-1.f,Max=100.f", &mObj); + mForceEditMargin.init(false, "ForceEditMargin", "(あそびの範囲)強制編集", "", &mObj); + mMarginRadius.init(1.0, "MarginRadius", "(あそびの範囲)半径", "Min=0.f,Max=100.f", &mObj); + return AttCheckArea::parse(arg); +} + +bool AttCheckAreaFan::parse(const CreateArg& arg) { + mAngleCheckIgnoreLockOn.init(false, "AngleCheckIgnoreLockOn", "ロックオン時も角度チェック有効", + "", &mObj); + mForceEditModelArea.init(false, "ForceEditModelArea", "(モデル範囲)強制編集", "", &mObj); + mRadius.init(0.0, "Radius", "(モデル範囲)半径", "Min=0.f,Max=100.f", &mObj); + mTop.init(0.0, "Top", "(モデル範囲)上辺", "Min=-100.f,Max=100.f", &mObj); + mBottom.init(0.0, "Bottom", "(モデル範囲)下辺", "Min=-100.f,Max=100.f", &mObj); + mAngle.init(0.0, "Angle", "(アテンション範囲)角度", "Min=0.f,Max=3.1415f", &mObj); + mFixedRadius.init(-1.0, "FixedRadius", "(アテンション範囲)半径", "Min=-1.f,Max=100.f", &mObj); + mFixedTop.init(-1.0, "FixedTop", "(アテンション範囲)上辺", "Min=-1.f,Max=100.f", &mObj); + mFixedBottom.init(-1.0, "FixedBottom", "(アテンション範囲)下辺", "Min=-1.f,Max=100.f", &mObj); + mForceEditMargin.init(false, "ForceEditMargin", "(あそびの範囲)強制編集", "", &mObj); + mMarginRadius.init(1.0, "MarginRadius", "(あそびの範囲)半径", "Min=0.f,Max=100.f", &mObj); + mMarginTop.init(1.0, "MarginTop", "(あそびの範囲)上辺", "Min=0.f,Max=100.f", &mObj); + mMarginBottom.init(1.0, "MarginBottom", "(あそびの範囲)下辺", "Min=0.f,Max=100.f", &mObj); + return AttCheckArea::parse(arg); +} + +bool AttCheckAreaCylinderFan::parse(const CreateArg& arg) { + mAngleCheckIgnoreLockOn.init(false, "AngleCheckIgnoreLockOn", "ロックオン時も角度チェック有効", + "", &mObj); + mForceEditModelArea.init(false, "ForceEditModelArea", "(モデル範囲)強制編集", "", &mObj); + mRadius.init(0.0, "Radius", "(モデル範囲)半径", "Min=0.f,Max=100.f", &mObj); + mTop.init(0.0, "Top", "(モデル範囲)上辺", "Min=-100.f,Max=100.f", &mObj); + mBottom.init(0.0, "Bottom", "(モデル範囲)下辺", "Min=-100.f,Max=100.f", &mObj); + mAngle.init(0.0, "Angle", "(アテンション範囲)角度", "Min=0.f,Max=3.1415f", &mObj); + mFixedRadiusCylinder.init(-1.0, "FixedRadiusCylinder", "(アテンション範囲)円柱の半径", + "Min=-1.f,Max=100.f", &mObj); + mFixedRadiusFan.init(-1.0, "FixedRadiusFan", "(アテンション範囲)扇形の半径", + "Min=-1.f,Max=100.f", &mObj); + mFixedTop.init(-1.0, "FixedTop", "(アテンション範囲)上辺", "Min=-1.f,Max=100.f", &mObj); + mFixedBottom.init(-1.0, "FixedBottom", "(アテンション範囲)下辺", "Min=-1.f,Max=100.f", &mObj); + mForceEditMargin.init(false, "ForceEditMargin", "(あそびの範囲)強制編集", "", &mObj); + mMarginRadiusCylinder.init(1.0, "MarginRadiusCylinder", "(あそびの範囲)円柱の半径", + "Min=0.f,Max=100.f", &mObj); + mMarginRadiusFan.init(1.0, "MarginRadiusFan", "(あそびの範囲)扇形の半径", "Min=0.f,Max=100.f", + &mObj); + mMarginTop.init(1.0, "MarginTop", "(あそびの範囲)上辺", "Min=0.f,Max=100.f", &mObj); + mMarginBottom.init(1.0, "MarginBottom", "(あそびの範囲)下辺", "Min=0.f,Max=100.f", &mObj); + return AttCheckArea::parse(arg); +} + +bool AttCheckAreaBox::parse(const CreateArg& arg) { + mForceEditModelArea.init(false, "ForceEditModelArea", "(モデル範囲)強制編集", "", &mObj); + mMin.init(sead::Vector3f::zero, "Min", "(モデル範囲)最小", "Min=-100.f,Max=100.f", &mObj); + mMax.init(sead::Vector3f::zero, "Max", "(モデル範囲)最大", "Min=-100.f,Max=100.f", &mObj); + mFixedMin.init(-1 * sead::Vector3f::ones, "FixedMin", "(アテンション範囲)最小", + "Min=-1.f,Max=100.f", &mObj); + mFixedMax.init(-1 * sead::Vector3f::ones, "FixedMax", "(アテンション範囲)最大", + "Min=-1.f,Max=100.f", &mObj); + mForceEditMargin.init(false, "ForceEditMargin", "(あそびの範囲)強制編集", "", &mObj); + mMarginMin.init(sead::Vector3f::ones, "MarginMin", "(あそびの範囲)最小", "Min=-100.f,Max=100.f", + &mObj); + mMarginMax.init(sead::Vector3f::ones, "MarginMax", "(あそびの範囲)最大", "Min=-100.f,Max=100.f", + &mObj); + return AttCheckArea::parse(arg); +} + +AttCheckEachOtherArea::AttCheckEachOtherArea(AttCheckType type) : AttCheck(type) {} + +bool AttCheckEachOtherArea::parse(const CreateArg& arg) { + mForceEditModelArea.init(false, "ForceEditModelArea", "(モデル範囲)強制編集", "", &mObj); + mRadius.init(0.0, "Radius", "(モデル範囲)半径", "Min=0.f,Max=100.f", &mObj); + mTop.init(0.0, "Top", "(モデル範囲)上辺", "Min=-100.f,Max=100.f", &mObj); + mBottom.init(0.0, "Bottom", "(モデル範囲)下辺", "Min=-100.f,Max=100.f", &mObj); + mFixedRadius.init(-1.0, "FixedRadius", "(アテンション範囲)半径", "Min=-1.f,Max=100.f", &mObj); + mFixedTop.init(-1.0, "FixedTop", "(アテンション範囲)上辺", "Min=-1.f,Max=100.f", &mObj); + mFixedBottom.init(-1.0, "FixedBottom", "(アテンション範囲)下辺", "Min=-1.f,Max=100.f", &mObj); + mForceEditMargin.init(false, "ForceEditMargin", "(あそびの範囲)強制編集", "", &mObj); + mMarginRadius.init(1.0, "MarginRadius", "(あそびの範囲)半径", "Min=0.f,Max=100.f", &mObj); + mMarginTop.init(1.0, "MarginTop", "(あそびの範囲)上辺", "Min=0.f,Max=100.f", &mObj); + mMarginBottom.init(1.0, "MarginBottom", "(あそびの範囲)下辺", "Min=0.f,Max=100.f", &mObj); + mOffsetTop.init(0.0, "OffsetTop", "(アテンションを出される側の範囲オフセット)上辺", + "Min=-100,Max=100", &mObj); + mOffsetBottom.init(0.0, "OffsetBottom", "(アテンションを出される側の範囲オフセット)下辺", + "Min=-100,Max=100", &mObj); + return AttCheck::parse(arg); +} + +bool AttCheckAngle::parse(const CreateArg& arg) { + mAttPos.init(&mObj); + mAngle.init(0.0, "Angle", "角度", "Min=0.f,Max=3.1415f", &mObj); + return AttCheck::parse(arg); +} + +bool AttCheck::parse(const CreateArg& arg) { + return true; +} + +namespace { +struct AttCheckFactory { + const char* name; + AttCheck* (*make)(AttCheckType type, sead::Heap* heap); +}; + +template <typename T> +constexpr AttCheckFactory makeFactory(const char* name) { + AttCheckFactory factory{}; + factory.name = name; + factory.make = [](AttCheckType type, sead::Heap* heap) -> AttCheck* { + return new (heap) T(type); + }; + return factory; +} + +sead::SafeArray<AttCheckFactory, 19> sFactories{{ + makeFactory<AttCheckLine>("Line"), + makeFactory<AttCheckScreen>("Screen"), + makeFactory<AttCheckAreaSphere>("AreaSphere"), + makeFactory<AttCheckAreaFan>("AreaFan"), + makeFactory<AttCheckAreaCylinderFan>("AreaCylinderFan"), + makeFactory<AttCheckAreaBox>("AreaBox"), + makeFactory<AttCheckEachOtherArea>("EachOtherArea"), + makeFactory<AttCheckAngle>("Angle"), + makeFactory<AttCheckWeight>("Weight"), + makeFactory<AttCheckRideHorse>("RideHorse"), + makeFactory<AttCheckRideSpace>("RideSpace"), + makeFactory<AttCheckSwim>("Swim"), + makeFactory<AttCheckCarry>("Carry"), + makeFactory<AttCheckNoCarry>("NoCarry"), + makeFactory<AttCheckGrab>("Grab"), + makeFactory<AttCheckBootFirstTower>("BootFirstTower"), + makeFactory<AttCheckFireContact>("FireContact"), + makeFactory<AttCheckCharacterOn>("CharacterOn"), + makeFactory<AttCheckUnderWater>("UnderWater"), +}}; +} // namespace + +AttCheck* AttCheck::make(const CreateArg& arg) { + const auto Parameters = agl::utl::getResParameterObj(arg.res_list, "Parameters"); + if (!Parameters) + return nullptr; + + int type = sFactories.size(); + const auto CheckType = agl::utl::getResParameter(Parameters, "CheckType"); + const sead::SafeString check_type_str = CheckType.getData<char>(); + for (int i = 0; i < sFactories.size(); ++i) { + if (check_type_str == sFactories[i].name) { + type = i; + break; + } + } + + if (type == sFactories.size()) + return nullptr; + + auto* check = sFactories[type].make(AttCheckType(type), arg.heap); + if (!check) + return nullptr; + + if (!check->init(arg)) { + delete check; + return nullptr; + } + + return check; +} + +bool AttCheck::init(const AttCheck::CreateArg& arg) { + mList.addObj(&mObj, "Parameters"); + mClient = arg.client; + return parse(arg); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAttCheck.h b/src/KingSystem/Resource/Actor/resResourceAttCheck.h new file mode 100644 index 00000000..5b788b33 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAttCheck.h @@ -0,0 +1,332 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglParameterObj.h> +#include <prim/seadRuntimeTypeInfo.h> +#include "resResourceAttClient.h" +#include "resResourceAttPos.h" + +namespace ksys::res { + +enum class AttCheckType { + Line, + Screen, + AreaSphere, + AreaFan, + AreaCylinderFan, + AreaBox, + EachOtherArea, + Angle, + Weight, + RideHorse, + RideSpace, + Swim, + Carry, + NoCarry, + Grab, + BootFirstTower, + FireContact, + CharacterOn, + UnderWater, +}; + +class AttClient; + +class AttCheck { + SEAD_RTTI_BASE(AttCheck) +public: + struct CreateArg { + agl::utl::ResParameterList res_list; + sead::Heap* heap; + AttClient* client; + }; + + static AttCheck* make(const CreateArg& arg); + + explicit AttCheck(AttCheckType type) : mType{type} {} + virtual ~AttCheck() = default; + + // FIXME: signatures and names + virtual void m4(); + virtual bool check(); + virtual float m6(); + virtual void m7() {} + + virtual bool parse(const CreateArg& arg); + + // For internal use by AttClient. + agl::utl::ParameterList& getList_() { return mList; } + +protected: + bool init(const CreateArg& arg); + + AttClient* mClient = nullptr; + AttCheckType mType{}; + agl::utl::ParameterObj mObj; + agl::utl::ParameterList mList; +}; + +class AttCheckLine : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckLine, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; + bool parse(const CreateArg& arg) override; + +private: + agl::utl::Parameter<float> mRadius; + agl::utl::Parameter<bool> mAsLineOfSight; +}; + +class AttCheckScreen : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckScreen, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckArea : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckArea, AttCheck) +public: + using AttCheck::AttCheck; + + void m4() override; + bool check() override; + float m6() override; + void m7() override; + bool parse(const CreateArg& arg) override; + + virtual bool m9() { return true; } + virtual float m10() { return 0; } + virtual void m11() {} + +protected: + AttPos mAttPos; + agl::utl::Parameter<bool> mFromPlayer; +}; + +class AttCheckAreaSphere : public AttCheckArea { + SEAD_RTTI_OVERRIDE(AttCheckAreaSphere, AttCheckArea) +public: + using AttCheckArea::AttCheckArea; + + bool parse(const CreateArg& arg) override; + bool m9() override; + float m10() override; + void m11() override; + +private: + agl::utl::Parameter<bool> mForceEditModelArea; + agl::utl::Parameter<float> mRadius; + agl::utl::Parameter<float> mFixedRadius; + agl::utl::Parameter<bool> mForceEditMargin; + agl::utl::Parameter<float> mMarginRadius; +}; + +class AttCheckAreaFan : public AttCheckArea { + SEAD_RTTI_OVERRIDE(AttCheckAreaFan, AttCheckArea) +public: + using AttCheckArea::AttCheckArea; + + bool parse(const CreateArg& arg) override; + bool m9() override; + float m10() override; + void m11() override; + +private: + agl::utl::Parameter<bool> mAngleCheckIgnoreLockOn; + agl::utl::Parameter<bool> mForceEditModelArea; + agl::utl::Parameter<float> mRadius; + agl::utl::Parameter<float> mAngle; + agl::utl::Parameter<float> mTop; + agl::utl::Parameter<float> mBottom; + agl::utl::Parameter<float> mMarginRadius; + agl::utl::Parameter<float> mMarginTop; + agl::utl::Parameter<float> mMarginBottom; + agl::utl::Parameter<bool> mForceEditMargin; + agl::utl::Parameter<float> mFixedRadius; + agl::utl::Parameter<float> mFixedTop; + agl::utl::Parameter<float> mFixedBottom; +}; + +class AttCheckAreaCylinderFan : public AttCheckArea { + SEAD_RTTI_OVERRIDE(AttCheckAreaCylinderFan, AttCheckArea) +public: + using AttCheckArea::AttCheckArea; + + bool parse(const CreateArg& arg) override; + bool m9() override; + float m10() override; + +private: + agl::utl::Parameter<bool> mAngleCheckIgnoreLockOn; + agl::utl::Parameter<bool> mForceEditModelArea; + agl::utl::Parameter<float> mRadius; + agl::utl::Parameter<float> mTop; + agl::utl::Parameter<float> mBottom; + agl::utl::Parameter<float> mAngle; + agl::utl::Parameter<float> mFixedRadiusCylinder; + agl::utl::Parameter<float> mFixedRadiusFan; + agl::utl::Parameter<float> mFixedTop; + agl::utl::Parameter<float> mFixedBottom; + agl::utl::Parameter<bool> mForceEditMargin; + agl::utl::Parameter<float> mMarginRadiusCylinder; + agl::utl::Parameter<float> mMarginRadiusFan; + agl::utl::Parameter<float> mMarginTop; + agl::utl::Parameter<float> mMarginBottom; +}; + +class AttCheckAreaBox : public AttCheckArea { + SEAD_RTTI_OVERRIDE(AttCheckAreaBox, AttCheckArea) +public: + explicit AttCheckAreaBox(AttCheckType type) : AttCheckArea(type) {} + + bool parse(const CreateArg& arg) override; + bool m9() override; + float m10() override; + void m11() override; + +private: + agl::utl::Parameter<bool> mForceEditModelArea; + agl::utl::Parameter<sead::Vector3f> mMin; + agl::utl::Parameter<sead::Vector3f> mMax; + agl::utl::Parameter<sead::Vector3f> mFixedMin; + agl::utl::Parameter<sead::Vector3f> mFixedMax; + agl::utl::Parameter<bool> mForceEditMargin; + agl::utl::Parameter<sead::Vector3f> mMarginMin; + agl::utl::Parameter<sead::Vector3f> mMarginMax; +}; + +class AttCheckEachOtherArea : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckEachOtherArea, AttCheck) +public: + explicit AttCheckEachOtherArea(AttCheckType type); + + void m4() override; + bool check() override; + float m6() override; + void m7() override; + bool parse(const CreateArg& arg) override; + +private: + agl::utl::Parameter<bool> mForceEditModelArea; + agl::utl::Parameter<float> mRadius; + agl::utl::Parameter<float> mTop; + agl::utl::Parameter<float> mBottom; + agl::utl::Parameter<bool> mForceEditMargin; + agl::utl::Parameter<float> mMarginRadius; + agl::utl::Parameter<float> mMarginTop; + agl::utl::Parameter<float> mMarginBottom; + agl::utl::Parameter<float> mFixedRadius; + agl::utl::Parameter<float> mFixedTop; + agl::utl::Parameter<float> mFixedBottom; + agl::utl::Parameter<float> mOffsetTop; + agl::utl::Parameter<float> mOffsetBottom; +}; + +class AttCheckAngle : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckAngle, AttCheck) +public: + using AttCheck::AttCheck; + + void m4() override; + bool check() override; + bool parse(const CreateArg& arg) override; + +private: + AttPos mAttPos; + agl::utl::Parameter<float> mAngle; +}; + +class AttCheckWeight : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckWeight, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckRideHorse : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckRideHorse, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckRideSpace : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckRideSpace, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckSwim : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckSwim, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckCarry : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckCarry, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckNoCarry : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckNoCarry, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckGrab : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckGrab, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckBootFirstTower : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckBootFirstTower, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckFireContact : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckFireContact, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckCharacterOn : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckCharacterOn, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +class AttCheckUnderWater : public AttCheck { + SEAD_RTTI_OVERRIDE(AttCheckUnderWater, AttCheck) +public: + using AttCheck::AttCheck; + + bool check() override; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAttClient.cpp b/src/KingSystem/Resource/Actor/resResourceAttClient.cpp new file mode 100644 index 00000000..070c5561 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAttClient.cpp @@ -0,0 +1,185 @@ +#include "resResourceAttClient.h" +#include <container/seadSafeArray.h> +#include "resResourceAttCheck.h" + +namespace ksys::res { + +AttClientList::~AttClientList() { + mClients.freeBuffer(); +} + +void AttClientList::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} + +bool AttClientList::parse_(u8* data, size_t size, sead::Heap* heap) { + if (!data) + return false; + + agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + + mAttPos.init(&mAttPosObj); + mForceEdit.init(false, "ForceEdit", "強制編集", "", &mAttPosObj); + addObj(&mAttPosObj, "AttPos"); + + const auto AttClients = agl::utl::getResParameterList(root, "AttClients"); + if (int num; AttClients && (num = AttClients.getResParameterObjNum()) != 0) { + mClients.allocBufferAssert(num, heap); + for (auto it = mClients.begin(), end = mClients.end(); it != end; ++it) { + it->client = nullptr; + it->name.init("", "Name", "クライアントのキー名", "", &it->obj); + it->file_name.init("", "FileName", "クライアントのデータファイル名", "", &it->obj); + it->is_valid.init(true, "IsValid", "デフォルトの有効・無効状態", "", &it->obj); + + mAttClientsList.addObj( + &it->obj, sead::FormatFixedSafeString<32>("%s%d", "AttClient_", it.getIndex())); + } + } + + addList(&mAttClientsList, "AttClients"); + + applyResParameterArchive(archive); + return true; +} + +bool AttClientList::finishParsing_() { + return true; +} + +bool AttClientList::m7_() { + for (auto& client : mClients) + client.client = nullptr; + return true; +} + +bool AttClientList::isForceEdit() const { + return mForceEdit.ref(); +} + +AttClient::~AttClient() { + for (int i = 0; i < mChecks.size(); ++i) { + if (mChecks[i]) { + delete mChecks[i]; + mChecks[i] = nullptr; + } + } + mChecks.freeBuffer(); +} + +void AttClient::doCreate_(u8*, u32, sead::Heap*) {} + +namespace { + +// Keep this in sync with ksys::act::AttType! +sead::SafeArray<const char*, 8> sAttTypes = {{ + "Action", + "Lock", + "SwordSearch", + "Attack", + "Appeal", + "JumpRide", + "NameBalloon", + "LookOnly", +}}; + +void parseAttType(const agl::utl::ResParameterObj& AttClientParams, act::AttType* type) { + const sead::SafeString AttType = + agl::utl::getResParameter(AttClientParams, "AttType").getData<char>(); + + *type = act::AttType::Invalid; + + for (int i = 0; i < sAttTypes.size(); ++i) { + if (AttType == sAttTypes[i]) { + *type = static_cast<act::AttType>(i); + break; + } + } + + if (*type == act::AttType::Invalid) + *type = act::AttType::Action; +} + +void parseActionType(const agl::utl::ResParameterObj& AttClientParams, act::AttActionCode* code) { + const sead::SafeString ActionType = + agl::utl::getResParameter(AttClientParams, "ActionType").getData<char>(); + + *code = act::AttActionCode::Dummy; + + for (int i = int(act::AttActionCode::None); i < int(act::AttActionCode::Dummy); ++i) { + if (ActionType == act::AttActionType::text(i - int(act::AttActionCode::None))) { + *code = static_cast<act::AttActionCode>(i); + break; + } + } + + if (*code == act::AttActionCode::Dummy) + *code = act::AttActionCode::None; +} + +} // namespace + +bool AttClient::parse_(u8* data, size_t size, sead::Heap* heap) { + if (!data) + return false; + + agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + const auto AttClientParams = root.getResParameterObj(0); + + parseAttType(AttClientParams, &mAttType); + parseActionType(AttClientParams, &mActionCode); + addObj(&mAttClientParamsObj, "AttClientParams"); + + mAttTypeParam.init({sAttTypes[0]}, "AttType", "", &mAttClientParamsObj); + mActionTypeParam.init({act::AttActionType(act::AttActionType::None).text()}, "ActionType", "", + &mAttClientParamsObj); + mPriorityTypeParam.init({act::AttPriorityType(act::AttPriorityType::Obj).text()}, + "PriorityType", "", &mAttClientParamsObj); + + const int num_checks = root.getResParameterListNum(); + if (num_checks != 0) { + mChecks.allocBufferAssert(num_checks, heap); + for (int i = 0; i < num_checks; ++i) + mChecks[i] = nullptr; + + AttCheck::CreateArg arg{}; + arg.heap = heap; + arg.client = this; + + auto it = mChecks.begin(), end = mChecks.end(); + auto res_it = root.listBegin(), res_end = root.listEnd(); + for (; it != end && res_it != res_end; ++res_it, ++it) { + arg.res_list = res_it.getList(); + + auto* check = *it = AttCheck::make(arg); + if (check == nullptr) + return false; + + addList(&check->getList_(), + sead::FormatFixedSafeString<32>("%s%d", "Check_", it.getIndex())); + } + } + + applyResParameterArchive(archive); + + const sead::SafeString PriorityType = mPriorityTypeParam.ref(); + for (auto priority : act::AttPriorityType{}) { + if (PriorityType == priority.text()) { + mPriorityType = priority; + mPriorityTypeStr = PriorityType; + return true; + } + } + mPriorityType = act::AttPriorityType::Obj; + mPriorityTypeStr = mPriorityType.text(); + return true; +} + +int AttClient::getNumChecks() const { + return mChecks.size(); +} + +void AttClient::appendPriority(sead::BufferedSafeString* str) { + str->append(mPriorityTypeStr); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAttClient.h b/src/KingSystem/Resource/Actor/resResourceAttClient.h new file mode 100644 index 00000000..96df34d3 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAttClient.h @@ -0,0 +1,95 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include <prim/seadSafeString.h> +#include "KingSystem/ActorSystem/Attention/actAttention.h" +#include "KingSystem/Resource/Actor/resResourceAttPos.h" +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class AttCheck; + +class AttClient : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(AttClient, Resource) +public: + AttClient() : ParamIO("atcl", 0) {} + ~AttClient() override; + + act::AttType getAttType() const { return mAttType; } + act::AttActionCode getActionCode() const { return mActionCode; } + act::AttPriorityType getPriorityType() const { return mPriorityType; } + const sead::SafeString& getPriorityTypeStr() const { return mPriorityTypeStr; } + const sead::Buffer<AttCheck*>& getChecks() const { return mChecks; } + + int getNumChecks() const; + + // TODO: check functions + + void appendPriority(sead::BufferedSafeString* str); + + void doCreate_(u8*, u32, sead::Heap*) override; + bool needsParse() const override { return true; } + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + +private: + act::AttType mAttType = act::AttType::Action; + act::AttActionCode mActionCode = act::AttActionCode::None; + act::AttPriorityType mPriorityType = act::AttPriorityType::Default; + sead::FixedSafeString<32> mPriorityTypeStr; + agl::utl::ParameterObj mAttClientParamsObj; + agl::utl::Parameter<sead::FixedSafeString<32>> mAttTypeParam; + agl::utl::Parameter<sead::FixedSafeString<32>> mActionTypeParam; + agl::utl::Parameter<sead::FixedSafeString<32>> mPriorityTypeParam; + sead::Buffer<AttCheck*> mChecks; +}; +KSYS_CHECK_SIZE_NX150(AttClient, 0x428); + +class AttClientList : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(AttClientList, Resource) +public: + struct Client { + const char* getFileName() const { return file_name.ref().cstr(); } + + agl::utl::Parameter<sead::SafeString> name; + agl::utl::Parameter<sead::SafeString> file_name; + agl::utl::Parameter<bool> is_valid; + agl::utl::ParameterObj obj; + AttClient* client; + }; + KSYS_CHECK_SIZE_NX150(Client, 0xa8); + + AttClientList() : ParamIO("atcllist", 0) {} + ~AttClientList() override; + AttClientList(const AttClientList&) = delete; + auto operator=(const AttClientList&) = delete; + + const AttPos& getAttPos() const { return mAttPos; } + bool isForceEdit() const; + const sead::Buffer<Client>& getClients() const { return mClients; } + + // TODO: one more function + + void addClient_(s32 index, AttClient* client) { mClients[index].client = client; } + + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool needsParse() const override { return true; } + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + bool finishParsing_() override; + bool m7_() override; + +private: + agl::utl::ParameterList mAttClientsList; + agl::utl::ParameterObj mAttPosObj; + AttPos mAttPos; + agl::utl::Parameter<bool> mForceEdit; + sead::Buffer<Client> mClients; +}; +KSYS_CHECK_SIZE_NX150(AttClientList, 0x3f0); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAttPos.cpp b/src/KingSystem/Resource/Actor/resResourceAttPos.cpp new file mode 100644 index 00000000..1eb43c83 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAttPos.cpp @@ -0,0 +1,15 @@ +#include "KingSystem/Resource/Actor/resResourceAttPos.h" + +namespace ksys::res { + +AttPos::AttPos() = default; + +void AttPos::init(agl::utl::IParameterObj* obj, const char* node_key, const char* offset_key, + const char* rotate_key, const char* y_rot_only_key) { + node.init("", node_key, "ノード", "", obj); + offset.init(sead::Vector3f::zero, offset_key, "オフセット", "Min=-100.f,Max=100.f", obj); + rotate.init(sead::Vector3f::zero, rotate_key, "回転", "Min=-3.1415f,Max=3.1415f", obj); + y_rot_only.init(false, y_rot_only_key, "Y軸回転のみ有効", "", obj); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAttPos.h b/src/KingSystem/Resource/Actor/resResourceAttPos.h new file mode 100644 index 00000000..0251b02c --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAttPos.h @@ -0,0 +1,25 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +struct AttPos { + AttPos(); + + void init(agl::utl::IParameterObj* obj, const char* node_key = "Node", + const char* offset_key = "Offset", const char* rotate_key = "Rotate", + const char* y_rot_only_key = "YRotOnly"); + + // TODO: more functions + + agl::utl::Parameter<sead::SafeString> node; + agl::utl::Parameter<sead::Vector3f> offset; + agl::utl::Parameter<sead::Vector3f> rotate; + agl::utl::Parameter<bool> y_rot_only; +}; +KSYS_CHECK_SIZE_NX150(AttPos, 0x98); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAwareness.cpp b/src/KingSystem/Resource/Actor/resResourceAwareness.cpp new file mode 100644 index 00000000..9011ac29 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAwareness.cpp @@ -0,0 +1,87 @@ +#include "KingSystem/Resource/Actor/resResourceAwareness.h" + +namespace ksys::res { + +bool Awareness::parse_(u8* data, size_t, sead::Heap*) { + addObj(&mBasisObj, "Basis"); + addObj(&mSightObj, "Sight"); + addObj(&mHearingObj, "Hearing"); + addObj(&mSenseObj, "Sense"); + addObj(&mWorryObj, "Worry"); + + contactpoint_num.init(64, "contactpoint_num", "センサーに引っ掛けるバッファの数", &mBasisObj); + base_node_name.init(sead::FixedSafeString<32>(""), "base_node_name", "前方基準ノード", + &mBasisObj); + is_bind_rot.init(false, "is_bind_rot", "姿勢を追従させる", &mBasisObj); + is_bind_pos.init(false, "is_bind_pos", "位置を追従させる", &mBasisObj); + base_offset.init(sead::Vector3f::zero, "base_offset", "位置オフセット", &mBasisObj); + base_dir.init(2, "base_dir", "基準方向", &mBasisObj); + up_dir.init(6, "up_dir", "UP方向", &mBasisObj); + awareness_target.init(sead::FixedSafeString<32>("一般敵"), "awareness_target", "種別設定", + &mBasisObj); + interest_lv1_radius.init(5.0, "interest_lv1_radius", "興味値用接近距離", &mBasisObj); + system_radius.init(0.0, "system_radius", "システム半径(プログラマ設定用)", &mBasisObj); + invalidate_wheather_ratio.init(false, "invalidate_wheather_ratio", "天候影響無視", &mBasisObj); + + sight_buffer_num.init(32, "sight_buffer_num", "情報を格納するバッファの数", &mSightObj); + sight_radius.init(15.0, "sight_radius", "発見水平範囲", &mSightObj); + sight_angle.init(1.04719758034, "sight_angle", "発見有効角度", &mSightObj); + sight_height_max.init(4.0, "sight_height_max", "発見垂直範囲最大", &mSightObj); + sight_height_min.init(-2.0, "sight_height_min", "発見垂直範囲最小", &mSightObj); + sight_height_near_max.init(4.0, "sight_height_near_max", "至近発見垂直範囲最大", &mSightObj); + sight_height_near_min.init(-2.0, "sight_height_near_min", "至近発見垂直範囲最小", &mSightObj); + sight_alert_radius.init(0.0, "sight_alert_radius", "警戒水平範囲", &mSightObj); + sight_alert_angle.init(0.0, "sight_alert_angle", "警戒有効角度", &mSightObj); + sight_alert_height_max.init(0.0, "sight_alert_height_max", "警戒垂直範囲最大", &mSightObj); + sight_alert_height_min.init(0.0, "sight_alert_height_min", "警戒垂直範囲最小", &mSightObj); + sight_alert_height_near_max.init(0.0, "sight_alert_height_near_max", "至近警戒垂直範囲最大", + &mSightObj); + sight_alert_height_near_min.init(0.0, "sight_alert_height_near_min", "至近警戒垂直範囲最小", + &mSightObj); + sight_ignore_grass_radius.init(2.0, "sight_ignore_grass_radius", "草無視範囲", &mSightObj); + sight_delay_time_max.init(0, "sight_delay_time_max", "認識遅延時間最大", &mSightObj); + sight_ray_check_range_max.init(-1.0, "sight_ray_check_range_max", "レイキャストの長さ制限値", + &mSightObj); + sight_base_node_name.init(sead::FixedSafeString<32>(""), "sight_base_node_name", + "(上書き用)前方基準ノード", &mSightObj); + sight_far_use.init(false, "sight_far_use", "遠距離視界を使う", &mSightObj); + sight_radius_far.init(0.0, "sight_radius_far", "遠距離開始距離", &mSightObj); + sight_angle_far.init(1.04719758034, "sight_angle_far", "遠距離発見有効角度", &mSightObj); + + hearing_buffer_num.init(32, "hearing_buffer_num", "情報を格納するバッファの数", &mHearingObj); + hearing_radius.init(15.0, "hearing_radius", "半径", &mHearingObj); + hearing_notice_level.init(1.0, "hearing_notice_level", "発見状態になるノイズレベル", + &mHearingObj); + hearing_alert_level.init(0.40000000596, "hearing_alert_level", "警戒状態になるノイズレベル", + &mHearingObj); + hearing_blind_angle.init(0.0, "hearing_blind_angle", "死角角度", &mHearingObj); + hearing_blind_margin_angle.init(0.0, "hearing_blind_margin_angle", "死角入り角度", + &mHearingObj); + hearing_reduce_ratio.init(0.0, "hearing_reduce_ratio", "死角に入られた際のノイズ反応倍率", + &mHearingObj); + hearing_delay_time_max.init(0, "hearing_delay_time_max", "認識遅延時間最大", &mHearingObj); + hearing_base_node_name.init(sead::FixedSafeString<32>(""), "hearing_base_node_name", + "(上書き用)前方基準ノード", &mHearingObj); + + sense_buffer_num.init(32, "sense_buffer_num", "情報を格納するバッファの数", &mSenseObj); + sense_target.init(sead::FixedSafeString<32>("Enemy"), "sense_target", "テラー受付設定", + &mSenseObj); + sense_radius_offset.init(0.0, "sense_radius_offset", "水平範囲オフセット", &mSenseObj); + sense_angle.init(3.14159274101, "sense_angle", "有効角度", &mSenseObj); + sense_delay_time_max.init(0, "sense_delay_time_max", "認識遅延時間最大", &mSenseObj); + sense_base_node_name.init(sead::FixedSafeString<32>(""), "sense_base_node_name", + "(上書き用)前方基準ノード", &mSenseObj); + + worry_buffer_num.init(0, "worry_buffer_num", "情報を格納するバッファの数", &mWorryObj); + worry_radius.init(0.0, "worry_radius", "範囲", &mWorryObj); + worry_delay_time_max.init(0, "worry_delay_time_max", "認識遅延時間最大", &mWorryObj); + worry_base_node_name.init(sead::FixedSafeString<32>(""), "worry_base_node_name", + "(上書き用)前方基準ノード", &mWorryObj); + + if (data) + applyResParameterArchive(agl::utl::ResParameterArchive(data)); + + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceAwareness.h b/src/KingSystem/Resource/Actor/resResourceAwareness.h new file mode 100644 index 00000000..2e6888ef --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceAwareness.h @@ -0,0 +1,86 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class Awareness : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(Awareness, Resource) +public: + Awareness() : ParamIO("awareness", 0) {} + ~Awareness() override = default; + + bool needsParse() const override { return true; } + bool ParamIO_m0(char* data) override { return true; } + +private: + void doCreate_(u8*, u32, sead::Heap*) override {} + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + + agl::utl::ParameterObj mBasisObj; + agl::utl::ParameterObj mSightObj; + agl::utl::ParameterObj mHearingObj; + agl::utl::ParameterObj mSenseObj; + agl::utl::ParameterObj mWorryObj; + +public: + agl::utl::Parameter<s32> contactpoint_num; + agl::utl::Parameter<sead::FixedSafeString<32>> base_node_name; + agl::utl::Parameter<bool> is_bind_rot; + agl::utl::Parameter<bool> is_bind_pos; + agl::utl::Parameter<sead::Vector3f> base_offset; + agl::utl::Parameter<s32> base_dir; + agl::utl::Parameter<s32> up_dir; + agl::utl::Parameter<sead::FixedSafeString<32>> awareness_target; + agl::utl::Parameter<f32> interest_lv1_radius; + agl::utl::Parameter<f32> system_radius; + agl::utl::Parameter<bool> invalidate_wheather_ratio; + + agl::utl::Parameter<s32> sight_buffer_num; + agl::utl::Parameter<f32> sight_radius; + agl::utl::Parameter<f32> sight_angle; + agl::utl::Parameter<f32> sight_height_max; + agl::utl::Parameter<f32> sight_height_min; + agl::utl::Parameter<f32> sight_height_near_max; + agl::utl::Parameter<f32> sight_height_near_min; + agl::utl::Parameter<f32> sight_alert_radius; + agl::utl::Parameter<f32> sight_alert_angle; + agl::utl::Parameter<f32> sight_alert_height_max; + agl::utl::Parameter<f32> sight_alert_height_min; + agl::utl::Parameter<f32> sight_alert_height_near_max; + agl::utl::Parameter<f32> sight_alert_height_near_min; + agl::utl::Parameter<f32> sight_ignore_grass_radius; + agl::utl::Parameter<s32> sight_delay_time_max; + agl::utl::Parameter<f32> sight_ray_check_range_max; + agl::utl::Parameter<sead::FixedSafeString<32>> sight_base_node_name; + agl::utl::Parameter<bool> sight_far_use; + agl::utl::Parameter<f32> sight_radius_far; + agl::utl::Parameter<f32> sight_angle_far; + + agl::utl::Parameter<s32> hearing_buffer_num; + agl::utl::Parameter<f32> hearing_radius; + agl::utl::Parameter<f32> hearing_notice_level; + agl::utl::Parameter<f32> hearing_alert_level; + agl::utl::Parameter<f32> hearing_blind_angle; + agl::utl::Parameter<f32> hearing_blind_margin_angle; + agl::utl::Parameter<f32> hearing_reduce_ratio; + agl::utl::Parameter<s32> hearing_delay_time_max; + agl::utl::Parameter<sead::FixedSafeString<32>> hearing_base_node_name; + + agl::utl::Parameter<s32> sense_buffer_num; + agl::utl::Parameter<sead::FixedSafeString<32>> sense_target; + agl::utl::Parameter<f32> sense_radius_offset; + agl::utl::Parameter<f32> sense_angle; + agl::utl::Parameter<s32> sense_delay_time_max; + agl::utl::Parameter<sead::FixedSafeString<32>> sense_base_node_name; + + agl::utl::Parameter<s32> worry_buffer_num; + agl::utl::Parameter<f32> worry_radius; + agl::utl::Parameter<s32> worry_delay_time_max; + agl::utl::Parameter<sead::FixedSafeString<32>> worry_base_node_name; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceBoneControl.cpp b/src/KingSystem/Resource/Actor/resResourceBoneControl.cpp new file mode 100644 index 00000000..1c4fe869 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceBoneControl.cpp @@ -0,0 +1,239 @@ +#include "KingSystem/Resource/Actor/resResourceBoneControl.h" + +namespace ksys::res { + +BoneControl::BoneControl() : ParamIO("bonectrl", 0) {} + +BoneControl::~BoneControl() { + mEyeSets.freeBuffer(); + mSpine.spineNodes.freeBuffer(); + + for (auto& group : mBoneGroups) + group.bones.freeBuffer(); + + mBoneGroups.freeBuffer(); +} + +void BoneControl::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} + +// NON_MATCHING: mFootIkController.isInvalidFt (???) +bool BoneControl::parse_(u8* data, size_t size, sead::Heap* heap) { + if (!data) + return true; + + agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + + mWhole.neckAndEyeRatio.init(0.0, "neckAndEyeRatio", "首向けと眼球制御の比率", &mWhole.obj); + mWhole.isFaceCtrlInvalid.init(true, "isFaceCtrlInvalid", "顔全体無効", &mWhole.obj); + addObj(&mWhole.obj, "Whole"); + + mEyeBall.isEyeBallCtrlInvalid.init(false, "isEyeBallCtrlInvalid", "無効にする", &mEyeBall.obj); + mEyeBall.isEyeBallRotWorldAxis.init(false, "isEyeBallRotWorldAxis", "ワールド軸で回転する", + &mEyeBall.obj); + mEyeBall.eyeBallSRTName.init("", "eyeBallSRTName", "眼球SRT名", &mEyeBall.obj); + mEyeBall.eyeRotRateLR.init(0.0, "eyeRotRateLR", "左右回転比率", &mEyeBall.obj); + mEyeBall.eyeRotRateUD.init(0.0, "eyeRotRateUD", "上下回転比率", &mEyeBall.obj); + mEyeBall.eyeMinRotPerFrame.init(0.5, "eyeMinRotPerFrame", "フレーム毎の最小回転量", + &mEyeBall.obj); + mEyeBall.eyeMaxRotPerFrame.init(6.0, "eyeMaxRotPerFrame", "フレーム毎の最大回転量", + &mEyeBall.obj); + mEyeBall.eyeSetNum.init(0, "eyeSetNum", "眼球セット数", &mEyeBall.obj); + addObj(&mEyeBall.obj, "EyeBall"); + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + + const int eye_set_num = mEyeBall.eyeSetNum.ref(); + if (eye_set_num > 0) { + if (!mEyeSets.tryAllocBuffer(eye_set_num, heap)) + return false; + + for (int i = 0; i < eye_set_num; ++i) { + sead::FormatFixedSafeString<64> name(""); + name.format("EyeSet_%02d", i); + + mEyeSets[i].isControlTexture.init(false, "isControlTexture", "テクスチャ制御する", + &mEyeSets[i].obj); + mEyeSets[i].materialName.init("", "materialName", "マテリアル名", &mEyeSets[i].obj); + mEyeSets[i].boneName.init("", "boneName", "ボーン名", &mEyeSets[i].obj); + mEyeSets[i].forwardBoneName.init("", "forwardBoneName", "前方方向ボーン名", + &mEyeSets[i].obj); + mEyeSets[i].forwardAxis.init(1, "forwardAxis", "前方方向とする軸", &mEyeSets[i].obj); + mEyeSets[i].axisLR.init(0, "axisLR", "左右回転軸", &mEyeSets[i].obj); + mEyeSets[i].axisUD.init(0, "axisUD", "上下回転軸", &mEyeSets[i].obj); + mEyeSets[i].lTransLimit.init(0.0, "lTransLimit", "左移動量上限", &mEyeSets[i].obj); + mEyeSets[i].rTransLimit.init(0.0, "rTransLimit", "右移動量上限", &mEyeSets[i].obj); + mEyeSets[i].dTransLimit.init(0.0, "dTransLimit", "下移動量上限", &mEyeSets[i].obj); + mEyeSets[i].uTransLimit.init(0.0, "uTransLimit", "上移動量上限", &mEyeSets[i].obj); + mEyeSets[i].isCorrectForward.init(false, "isCorrectForward", "前方方向を補正する", + &mEyeSets[i].obj); + mEyeSets[i].axisCorrect.init(0, "axisCorrect", "補正軸", &mEyeSets[i].obj); + mEyeSets[i].correctRot.init(0.0, "correctRot", "補正量", &mEyeSets[i].obj); + mEyeSets[i].lRotLimit.init(0.0, "lRotLimit", "左向き角上限", &mEyeSets[i].obj); + mEyeSets[i].rRotLimit.init(0.0, "rRotLimit", "右向き角上限", &mEyeSets[i].obj); + mEyeSets[i].dRotLimit.init(0.0, "dRotLimit", "下向き角上限", &mEyeSets[i].obj); + mEyeSets[i].uRotLimit.init(0.0, "uRotLimit", "上向き角上限", &mEyeSets[i].obj); + mEyeSets[i].offset.init({0.0, 0.0, 0.0}, "offset", "オフセット", &mEyeSets[i].obj); + + addObj(&mEyeSets[i].obj, name); + } + } + + mSpine.isInvalid.init(false, "isInvalid", "無効にする", &mSpine.obj); + mSpine.isBasisSelfPosNeckLR.init(false, "isBasisSelfPosNeckLR", + "左右計算を自分の位置基準にする", &mSpine.obj); + mSpine.isBasisSelfPosNeckUD.init(false, "isBasisSelfPosNeckUD", + "上下計算を自分の位置基準にする", &mSpine.obj); + mSpine.isBattleNeckRecalcUD.init(false, "isBattleNeckRecalcUD", + "戦闘時の首向け上下角を再計算する", &mSpine.obj); + mSpine.spineDisableBaseDirAlongXZ.init(false, "spineDisableBaseDirAlongXZ", + "基準方向をXZ平面に沿わせない", &mSpine.obj); + mSpine.spineRotRate.init(0.0, "spineRotRate", "回転比率", &mSpine.obj); + mSpine.spineRetRotRate.init(0.0, "spineRetRotRate", "戻り回転比率", &mSpine.obj); + mSpine.spineNeckBaseBone.init("", "spineNeckBaseBone", "首向け基準位置ボーン名", &mSpine.obj); + mSpine.neckPosOffset.init(sead::Vector3f::zero, "neckPosOffset", "オフセット", &mSpine.obj); + mSpine.spineNodeNum.init(0, "spineNodeNum", "背骨ノード数", &mSpine.obj); + mSpine.spineNeckNodeNum.init(0, "spineNeckNodeNum", "首とみなすノード数", &mSpine.obj); + addObj(&mSpine.obj, "Spine"); + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + + const auto spine_node_num = mSpine.spineNodeNum.ref(); + if (spine_node_num > 0) { + if (!mSpine.spineNodes.tryAllocBuffer(spine_node_num, heap)) + return false; + + for (int i = 0; i < spine_node_num; ++i) { + sead::FormatFixedSafeString<64> name(""); + name.format("SpineNode_%02d", i); + + mSpine.spineNodes[i].boneName.init("", "boneName", "ボーン名", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].isRotWorldAxis.init( + false, "isRotWorldAxis", "ワールド軸で回転する", &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].axisLR.init(0, "axisLR", "左右回転軸", &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].axisUD.init(0, "axisUD", "上下回転軸", &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].lLimit.init(0.0, "lLimit", "左向き角上限", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].rLimit.init(0.0, "rLimit", "右向き角上限", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].dLimit.init(0.0, "dLimit", "下向き角上限", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].uLimit.init(0.0, "uLimit", "上向き角上限", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].lBattleLimit.init(0.0, "lBattleLimit", "左向き角上限(戦闘時)", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].rBattleLimit.init(0.0, "rBattleLimit", "右向き角上限(戦闘時)", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].dBattleLimit.init(0.0, "dBattleLimit", "下向き角上限(戦闘時)", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].uBattleLimit.init(0.0, "uBattleLimit", "上向き角上限(戦闘時)", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].minRotPerFrame.init( + 0.5, "minRotPerFrame", "フレーム毎の最小回転量", &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].maxRotPerFrame.init( + 6.0, "maxRotPerFrame", "フレーム毎の最大回転量", &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].isEnableCorrect.init( + false, "isEnableCorrect", "左右回転時に補正する", &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].axisCorrect.init(0, "axisCorrect", "補正回転軸", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].lCorrect.init(0.0, "lCorrect", "左向き補正回転量", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].rCorrect.init(0.0, "rCorrect", "右向き補正回転量", + &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].lBattleCorrect.init( + 0.0, "lBattleCorrect", "左向き補正回転量(戦闘時)", &mSpine.spineNodes[i].obj); + mSpine.spineNodes[i].rBattleCorrect.init( + 0.0, "rBattleCorrect", "右向き補正回転量(戦闘時)", &mSpine.spineNodes[i].obj); + + addObj(&mSpine.spineNodes[i].obj, name); + } + } + + mFootIkController.isInvalidFt.init(true, "isInvalidFt", "無効", &mFootIkController.obj); + mFootIkController.calculateTypeFt.init(1, "calculateTypeFt", "計算タイプ", + &mFootIkController.obj); + mFootIkController.ankleOffsetYFt.init(0.125, "ankleOffsetYFt", "地面から足首(Ankle)までの高さ", + &mFootIkController.obj); + mFootIkController.ankleOffsetAngleDegFt.init(-27.0, "ankleOffsetAngleDegFt", + "足首オフセット角度(Deg)", &mFootIkController.obj); + mFootIkController.ankleAngleLimitUpDegFt.init( + 90.0, "ankleAngleLimitUpDegFt", "上方向への足首回転最大角度(Deg)", &mFootIkController.obj); + mFootIkController.ankleAngleLimitDownDegFt.init(-90.0, "ankleAngleLimitDownDegFt", + "下方向への足首回転最大角度(Deg)", + &mFootIkController.obj); + mFootIkController.ankleHeightLimitRateFt.init( + 0.8, "ankleHeightLimitRateFt", "地面に対して足位置の制限比率", &mFootIkController.obj); + mFootIkController.waistDownRateFt.init(0.7, "waistDownRateFt", "腰を落とす最長比率", + &mFootIkController.obj); + mFootIkController.kneeRotateAgnleMinDegFt.init( + 0.0, "kneeRotateAgnleMinDegFt", "ヒザの最小回転角度(Deg)", &mFootIkController.obj); + mFootIkController.kneeRotateAgnleMaxDegFt.init( + 180.0, "kneeRotateAgnleMaxDegFt", "ヒザの最大回転角度(Deg)", &mFootIkController.obj); + mFootIkController.enableLimitThighAngleFt.init( + false, "enableLimitThighAngleFt", "モモの角度制限を行なうか?", &mFootIkController.obj); + mFootIkController.thighRotateAngleMinDegFt.init( + -180.0, "thighRotateAngleMinDegFt", "モモの最小回転角度(Deg)", &mFootIkController.obj); + mFootIkController.thighRotateAngleMaxDegFt.init( + 180.0, "thighRotateAngleMaxDegFt", "モモの最大回転角度(Deg)", &mFootIkController.obj); + addObj(&mFootIkController.obj, "FootIkController"); + + const auto bone_groups = agl::utl::getResParameterList(root, "BoneGroups"); + if (bone_groups.ptr() && bone_groups.getResParameterListNum() != 0) { + if (!mBoneGroups.tryAllocBuffer(bone_groups.getResParameterListNum(), heap)) + return false; + + sead::FixedSafeString<32> bone_group_name{"BoneGroup_"}; + const auto bone_group_name_base_len = bone_group_name.calcLength(); + + sead::FixedSafeString<32> bone_name{"Bone_"}; + const auto bone_name_base_len = bone_name.calcLength(); + + for (auto it = mBoneGroups.begin(), end = mBoneGroups.end(); it != end; ++it) { + const auto list = bone_groups.getResParameterList(it.getIndex()); + if (!list.ptr()) + continue; + + const auto bones = agl::utl::getResParameterObj(list, "Bones"); + if (!bones.ptr()) + continue; + + it->groupName.init("", "GroupName", "グループ名", &it->paramObj); + + const auto num_bones = bones.getNum(); + if (num_bones != 0 && !it->bones.tryAllocBuffer(num_bones, heap)) + return false; + + auto& bones_obj = it->bonesObj; + for (auto b = it->bones.begin(), bone_end = it->bones.end(); b != bone_end; ++b) { + bone_name.trim(bone_name_base_len); + bone_name.appendWithFormat("%d", b.getIndex()); + b->name.init("", bone_name, "ボーン名", &bones_obj); + } + + it->list.addObj(&bones_obj, "Bones"); + it->list.addObj(&it->paramObj, "Param"); + + bone_group_name.trim(bone_group_name_base_len); + bone_group_name.appendWithFormat("%d", it.getIndex()); + mBoneGroupsList.addList(&it->list, bone_group_name); + } + + addList(&mBoneGroupsList, "BoneGroups"); + } + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + return true; +} + +const BoneControl::BoneGroup* BoneControl::getBoneGroup(const sead::SafeString& name) const { + const auto idx = mBoneGroups.binarySearch( + name, +[](const BoneGroup& group, const sead::SafeString& key) { + return group.groupName.ref().compare(key); + }); + if (idx == -1) + return nullptr; + return &mBoneGroups[idx]; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceBoneControl.h b/src/KingSystem/Resource/Actor/resResourceBoneControl.h new file mode 100644 index 00000000..4cb74ea5 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceBoneControl.h @@ -0,0 +1,166 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include <math/seadVector.h> +#include <prim/seadSafeString.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class BoneControl : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(BoneControl, Resource) +public: + struct Whole { + agl::utl::ParameterObj obj; + agl::utl::Parameter<bool> isFaceCtrlInvalid; + agl::utl::Parameter<float> neckAndEyeRatio; + }; + KSYS_CHECK_SIZE_NX150(Whole, 0x70); + + struct EyeBall { + agl::utl::ParameterObj obj; + agl::utl::Parameter<bool> isEyeBallCtrlInvalid; + agl::utl::Parameter<bool> isEyeBallRotWorldAxis; + agl::utl::Parameter<sead::SafeString> eyeBallSRTName; + agl::utl::Parameter<float> eyeRotRateLR; + agl::utl::Parameter<float> eyeRotRateUD; + agl::utl::Parameter<float> eyeMinRotPerFrame; + agl::utl::Parameter<float> eyeMaxRotPerFrame; + agl::utl::Parameter<int> eyeSetNum; + }; + KSYS_CHECK_SIZE_NX150(EyeBall, 0x138); + + struct EyeSet { + agl::utl::ParameterObj obj; + agl::utl::Parameter<sead::SafeString> boneName; + agl::utl::Parameter<bool> isControlTexture; + agl::utl::Parameter<sead::SafeString> materialName; + agl::utl::Parameter<sead::SafeString> forwardBoneName; + agl::utl::Parameter<int> forwardAxis; + agl::utl::Parameter<int> axisLR; + agl::utl::Parameter<int> axisUD; + agl::utl::Parameter<float> lTransLimit; + agl::utl::Parameter<float> rTransLimit; + agl::utl::Parameter<float> dTransLimit; + agl::utl::Parameter<float> uTransLimit; + agl::utl::Parameter<bool> isCorrectForward; + agl::utl::Parameter<int> axisCorrect; + agl::utl::Parameter<float> correctRot; + agl::utl::Parameter<float> lRotLimit; + agl::utl::Parameter<float> rRotLimit; + agl::utl::Parameter<float> dRotLimit; + agl::utl::Parameter<float> uRotLimit; + agl::utl::Parameter<sead::Vector3f> offset; + }; + KSYS_CHECK_SIZE_NX150(EyeSet, 0x2b0); + + struct Bone { + agl::utl::Parameter<sead::SafeString> name; + }; + KSYS_CHECK_SIZE_NX150(Bone, 0x28); + + struct BoneGroup { + agl::utl::ParameterList list; + agl::utl::ParameterObj paramObj; + agl::utl::ParameterObj bonesObj; + agl::utl::Parameter<sead::SafeString> groupName; + sead::Buffer<Bone> bones; + }; + KSYS_CHECK_SIZE_NX150(BoneGroup, 0xe0); + + struct SpineNode { + agl::utl::ParameterObj obj; + agl::utl::Parameter<sead::SafeString> boneName; + agl::utl::Parameter<bool> isRotWorldAxis; + agl::utl::Parameter<int> axisLR; + agl::utl::Parameter<int> axisUD; + agl::utl::Parameter<float> lLimit; + agl::utl::Parameter<float> rLimit; + agl::utl::Parameter<float> dLimit; + agl::utl::Parameter<float> uLimit; + agl::utl::Parameter<float> lBattleLimit; + agl::utl::Parameter<float> rBattleLimit; + agl::utl::Parameter<float> dBattleLimit; + agl::utl::Parameter<float> uBattleLimit; + agl::utl::Parameter<bool> isEnableCorrect; + agl::utl::Parameter<int> axisCorrect; + agl::utl::Parameter<float> lCorrect; + agl::utl::Parameter<float> rCorrect; + agl::utl::Parameter<float> lBattleCorrect; + agl::utl::Parameter<float> rBattleCorrect; + agl::utl::Parameter<float> minRotPerFrame; + agl::utl::Parameter<float> maxRotPerFrame; + }; + KSYS_CHECK_SIZE_NX150(SpineNode, 0x2b8); + + struct Spine { + agl::utl::ParameterObj obj; + agl::utl::ParameterList list; + agl::utl::Parameter<bool> isInvalid; + agl::utl::Parameter<bool> isBasisSelfPosNeckLR; + agl::utl::Parameter<bool> isBasisSelfPosNeckUD; + agl::utl::Parameter<bool> isBattleNeckRecalcUD; + agl::utl::Parameter<bool> spineDisableBaseDirAlongXZ; + agl::utl::Parameter<float> spineRotRate; + agl::utl::Parameter<float> spineRetRotRate; + agl::utl::Parameter<sead::SafeString> spineNeckBaseBone; + agl::utl::Parameter<sead::Vector3f> neckPosOffset; + agl::utl::Parameter<int> spineNeckNodeNum; + agl::utl::Parameter<int> spineNodeNum; + sead::Buffer<SpineNode> spineNodes; + }; + KSYS_CHECK_SIZE_NX150(Spine, 0x1f8); + + struct FootIkController { + agl::utl::ParameterObj obj; + agl::utl::Parameter<bool> isInvalidFt; + agl::utl::Parameter<int> calculateTypeFt; + agl::utl::Parameter<float> ankleOffsetYFt; + agl::utl::Parameter<float> ankleOffsetAngleDegFt; + agl::utl::Parameter<float> ankleAngleLimitUpDegFt; + agl::utl::Parameter<float> ankleAngleLimitDownDegFt; + agl::utl::Parameter<float> ankleHeightLimitRateFt; + agl::utl::Parameter<float> waistDownRateFt; + agl::utl::Parameter<float> kneeRotateAgnleMinDegFt; + agl::utl::Parameter<float> kneeRotateAgnleMaxDegFt; + agl::utl::Parameter<bool> enableLimitThighAngleFt; + agl::utl::Parameter<float> thighRotateAngleMinDegFt; + agl::utl::Parameter<float> thighRotateAngleMaxDegFt; + }; + KSYS_CHECK_SIZE_NX150(FootIkController, 0x1d0); + + BoneControl(); + ~BoneControl() override; + + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + bool ParamIO_m0(char* data) override { return true; } + bool needsParse() const override { return true; } + + const Whole& getWhole() const { return mWhole; } + const Spine& getSpine() const { return mSpine; } + const EyeBall& getEyeBall() const { return mEyeBall; } + const sead::Buffer<EyeSet>& getEyeSets() const { return mEyeSets; } + const FootIkController& getFootIkController() const { return mFootIkController; } + const sead::Buffer<BoneGroup>& getBoneGroups() const { return mBoneGroups; } + + const BoneGroup* getBoneGroup(const sead::SafeString& name) const; + +private: + Whole mWhole; + Spine mSpine; + EyeBall mEyeBall; + agl::utl::ParameterList _650; + sead::Buffer<EyeSet> mEyeSets; + FootIkController mFootIkController; + agl::utl::ParameterList mBoneGroupsList; + sead::Buffer<BoneGroup> mBoneGroups; +}; +KSYS_CHECK_SIZE_NX150(BoneControl, 0x8d0); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceChemical.cpp b/src/KingSystem/Resource/Actor/resResourceChemical.cpp new file mode 100644 index 00000000..45346d1f --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceChemical.cpp @@ -0,0 +1,24 @@ +#include "KingSystem/Resource/Actor/resResourceChemical.h" + +namespace ksys::res { + +Chemical::Chemical() : ParamIO("chemical", 0) { + addList(&mRoot, "chemical_root"); +} + +void Chemical::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} + +bool Chemical::parse_(u8* data, size_t size, sead::Heap* heap) { + if (!data) + return true; + + agl::utl::ResParameterArchive archive{data}; + + const auto chemical_root_list = + agl::utl::getResParameterList(archive.getRootList(), "chemical_root"); + mRoot.parse(chemical_root_list, heap); + + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceChemical.h b/src/KingSystem/Resource/Actor/resResourceChemical.h new file mode 100644 index 00000000..4b27461c --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceChemical.h @@ -0,0 +1,25 @@ +#pragma once + +#include "KingSystem/Chemical/chmRoot.h" +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class Chemical : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(Chemical, Resource) + +public: + Chemical(); + + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool needsParse() const override { return true; } + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + + const chm::Root& getRoot() const { return mRoot; } + +private: + chm::Root mRoot; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceDamageParam.cpp b/src/KingSystem/Resource/Actor/resResourceDamageParam.cpp new file mode 100644 index 00000000..432f2fdc --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceDamageParam.cpp @@ -0,0 +1,255 @@ +#include "KingSystem/Resource/Actor/resResourceDamageParam.h" + +namespace ksys::res { + +bool DamageParam::parse_(u8* data, size_t, sead::Heap* heap) { + mDamageRateBuffer.allocBufferAssert(DamageSource::size(), heap); + mDamageTypeBuffer.allocBufferAssert(DamageSource::size() * DamageSize::size(), heap); + + sead::FormatFixedSafeString<64> str; + for (int i = 0; i < DamageSource::size(); ++i) { + str.format("%s", DamageSource::text(i)); + mDamageRateBuffer[i].init(1.0, str, "", &mDamageRateObj); + } + + for (int source = 0; source < DamageSource::size(); ++source) { + for (int size = 0; size < DamageSize::size(); ++size) { + str.format("%s-%s", DamageSource::text(source), DamageSize::text(size)); + if (source == DamageSource::Arrow) { + mDamageTypeBuffer.get(source * 4 + size) + ->init("通常ダメージ", str, "", &mReactionTableObj); + } else if (size == DamageSize::Large || size == DamageSize::Huge || + source == DamageSource::Bomb || source == DamageSource::LargeSword) { + mDamageTypeBuffer.get(source * 4 + size) + ->init("吹っ飛び", str, "", &mReactionTableObj); + } else if (size == DamageSize::Middle) { + mDamageTypeBuffer.get(source * 4 + size) + ->init("中ダメージ", str, "", &mReactionTableObj); + } else { + mDamageTypeBuffer.get(source * 4 + size) + ->init("通常ダメージ", str, "", &mReactionTableObj); + } + } + } + + mBreakable.init(false, "Breakable", "壊れるかどうか(AI無しで破壊エフェクト・消滅挙動を行う)", + "", &mParametersObj); + mHammerAffect.init( + false, "HammerAffect", + "ハンマーが有効かどうか(ハンマー属性にチェックを入れた武器で攻撃されると即死する)", "", + &mParametersObj); + mWeakBreakerAffect.init(false, "WeakBreakerAffect", "Objを一撃破壊しない武器設定が有効か", "", + &mParametersObj); + mChemicalAttackAffect.init(true, "ChemicalAttackAffect", + "ケミカルAtによる追加ダメージを受けるか(Ex:ロッドの玉)", "", + &mParametersObj); + mSpAffectRatio.init(1.0, "SpAffectRatio", "特効ダメージ倍率(武器倍率と掛け算される)", "", + &mParametersObj); + mSpAffectDamage.init(0, "SpAffectDamage", "特効ダメージ加算値(ダメージ計算後に加算される)", "", + &mParametersObj); + mVanishAffect.init(false, "VanishAffect", "消滅攻撃有効(Ex:古代の矢)", "", &mParametersObj); + mIsCriticalBlowOff.init(true, "IsCriticalBlowOff", "クリティカルで吹き飛ぶ", "", + &mParametersObj); + mIsAcceptAtkImpulse.init(false, "IsAcceptAtkImpulse", + "攻撃的衝撃力を受けるかどうか(Ex:ボコブリンの石)", "", + &mParametersObj); + mIsCommonCalcImpuleDamage.init( + true, "IsCommonCalcImpuleDamage", + "衝撃力ダメージを自動計算する(Offの場合のみImpulseDamageTableが有効になります)", "", + &mParametersObj); + mIsHeavyBreak.init(false, "IsHeavyBreak", "巨体属性でへし折れる", "", &mParametersObj); + mImpulseThresholdLv0.init(-1.0, "ImpulseThresholdLv0", "(Small)衝撃力ダメージ閾値", "", + &mParametersObj); + mImpulseDamageLv0.init(0.0, "ImpulseDamageLv0", "(Small)衝撃力ダメージ値", "", &mParametersObj); + mImpulseThresholdLv1.init(-1.0, "ImpulseThresholdLv1", "(Middle)衝撃力ダメージ閾値", "", + &mParametersObj); + mImpulseDamageLv1.init(0.0, "ImpulseDamageLv1", "(Middle)衝撃力ダメージ値", "", + &mParametersObj); + mImpulseThresholdLv2.init(-1.0, "ImpulseThresholdLv2", "(Large)衝撃力ダメージ閾値", "", + &mParametersObj); + mImpulseDamageLv2.init(0.0, "ImpulseDamageLv2", "(Large)衝撃力ダメージ値", "", &mParametersObj); + mImpulseThresholdLv3.init(-1.0, "ImpulseThresholdLv3", "(Huge)衝撃力ダメージ閾値", "", + &mParametersObj); + mImpulseDamageLv3.init(0.0, "ImpulseDamageLv3", "(Huge)衝撃力ダメージ値", "", &mParametersObj); + mImpulseThresholdLv4.init(-1.0, "ImpulseThresholdLv4", "(即死)衝撃力ダメージ閾値", "", + &mParametersObj); + mFallDamageStartHeight.init(10000.0, "FallDamageStartHeight", "落下ダメージ開始高さ", "", + &mParametersObj); + mFallDamageMin.init(0, "FallDamageMin", "落下ダメージ最低値", "", &mParametersObj); + mFallDamagePerMeter.init(0.0, "FallDamagePerMeter", "1mあたりの加算落下ダメージ量", "", + &mParametersObj); + mFallDamageHighStart.init(-1.0, "FallDamageHighStart", "強落下ダメージ開始高さ(-1で無効)", "", + &mParametersObj); + mFallDamageHighPerMeter.init(0, "FallDamageHighPerMeter", + "強落下時1mあたりの加算落下ダメージ量", "", &mParametersObj); + mFallDamageNoWaterDepth.init(-1.0, "FallDamageNoWaterDepth", "落下ダメージ受けない水深", "", + &mParametersObj); + mWeakPointBone.init(sead::SafeString(""), "WeakPointBone", "弱手ボーン名(空白だとモデル原点)", + "", &mParametersObj); + mWeakPointCalcArea.init(0.0, "WeakPointCalcArea", "弱点判定エリア(弱点不要アクターはここを0に)", + "", &mParametersObj); + mWeakPointCalcOffset.init({0, 0, 0}, "WeakPointCalcOffset", + "弱手判定エリアの指定ボーンからのオフセット(ローカル座標系)", "", + &mParametersObj); + mWeakPointArea.init(0.0, "WeakPointArea", "弱点エリア", "", &mParametersObj); + mWeakPointOffset.init({0, 0, 0}, "WeakPointOffset", + "弱点エリアの指定ボーンからのオフセット(ローカル座標系)", "", + &mParametersObj); + mWeakPointRatio.init(4.0, "WeakPointRatio", "弱点ダメージ倍率", "", &mParametersObj); + mWeakPointNoUIFlag.init(false, "WeakPointNoUIFlag", "ヒット時説明UIを出さない", "", + &mParametersObj); + mWeakPointBone2.init(sead::SafeString(""), "WeakPointBone2", "弱手ボーン名(空白だとモデル原点)", + "", &mParametersObj); + mWeakPointCalcArea2.init(0.0, "WeakPointCalcArea2", + "弱点判定エリア(弱点不要アクターはここを0に)", "", &mParametersObj); + mWeakPointCalcOffset2.init({0, 0, 0}, "WeakPointCalcOffset2", + "弱手判定エリアの指定ボーンからのオフセット(ローカル座標系)", "", + &mParametersObj); + mWeakPointArea2.init(0.0, "WeakPointArea2", "弱点エリア", "", &mParametersObj); + mWeakPointOffset2.init({0, 0, 0}, "WeakPointOffset2", + "弱点エリアの指定ボーンからのオフセット(ローカル座標系)", "", + &mParametersObj); + mWeakPointRatio2.init(1.0, "WeakPointRatio2", "弱点ダメージ倍率", "", &mParametersObj); + mWeakPointNoUIFlag2.init(false, "WeakPointNoUIFlag2", "ヒット時説明UIを出さない", "", + &mParametersObj); + mSillentKillMultRatio.init(1.0, "SillentKillMultRatio", "奇襲ダメージ乗算倍率", "", + &mParametersObj); + mSillentKillAddDamage.init(0, "SillentKillAddDamage", "奇襲ダメージ加算値", "", + &mParametersObj); + mIsDeadBurnout.init(false, "IsDeadBurnout", "燃え尽きでライフ0", "", &mParametersObj); + mIsMetamorBurnout.init(false, "IsMetamorBurnout", "燃え尽きでアクタ変化", "", &mParametersObj); + mIsMatamorFromTg.init(true, "IsMatamorFromTg", "炎剣で切っても変化する", "", &mParametersObj); + mBurnable.init(false, "Burnable", "燃え状態有効", "", &mParametersObj); + mBurnDamage.init(10, "BurnDamage", "燃えダメージLv1(-1でダメージ受けない)", "", + &mParametersObj); + mBurnDamage2.init(-1, "BurnDamage2", "燃えダメージLv2(-1でLv1と同じ)", "", &mParametersObj); + mBurnDamage3.init(-1, "BurnDamage3", "燃えダメージLv3(-1でLv2と同じ)", "", &mParametersObj); + mBurnDamage4.init(-1, "BurnDamage4", "燃えダメージLv4(-1でLv3と同じ)", "", &mParametersObj); + mBurnDamage5.init(-1, "BurnDamage5", "燃えダメージLv5(-1でLv4と同じ)", "", &mParametersObj); + mBurnTime.init(10, "BurnTime", "燃え時間", "", &mParametersObj); + mBurnDamageInterval.init(-1, "BurnDamageInterval", "[火に接触時]燃えダメージ間隔(-1で無し)", "", + &mParametersObj); + mBurnContinuousDamage.init(0, "BurnContinuousDamage", "[火に接触時]燃え継続ダメージ", "", + &mParametersObj); + mBurnCritical.init(false, "BurnCritical", "火異常がクリティカル扱いか", "", &mParametersObj); + mProofBurnAtSmallDamage.init(false, "ProofBurnAtSmallDamage", + "火弾無効時小ダメージアクションをとるか", "", &mParametersObj); + mIsDeadIce.init(false, "IsDeadIce", "凍結でライフ0", "", &mParametersObj); + mIsMetamorIce.init(false, "IsMetamorIce", "凍結でアクタ変化", "", &mParametersObj); + mIceable.init(false, "Iceable", "凍結状態有効", "", &mParametersObj); + mIceDamage.init(10, "IceDamage", "凍結ダメージ", "", &mParametersObj); + mIceTime.init(10, "IceTime", "凍結時間(f)", "", &mParametersObj); + mIceBreakableByAtk.init(true, "IceBreakableByAtk", "凍結時攻撃で割れるか", "", &mParametersObj); + mIceBreakDamageRatio.init(4.0, "IceBreakDamageRatio", "凍結破壊ダメージ倍率", "", + &mParametersObj); + mIceCritical.init(false, "IceCritical", + "凍結異常がクリティカル扱いか(濡れたら死ぬようになります)", "", + &mParametersObj); + mProofIceAtSmallDamage.init(false, "ProofIceAtSmallDamage", + "冷凍弾無効時小ダメージアクションをとるか", "", &mParametersObj); + mIsDeadElectric.init(false, "IsDeadElectric", "帯電でライフ0", "", &mParametersObj); + mIsMetamorElectric.init(false, "IsMetamorElectric", "帯電でアクタ変化", "", &mParametersObj); + mElectricable.init(false, "Electricable", "痺れ状態有効", "", &mParametersObj); + mElectricDamage.init(0, "ElectricDamage", "痺れダメージ", "", &mParametersObj); + mElectricTime.init(10, "ElectricTime", "痺れ時間(f)", "", &mParametersObj); + mElecCancelableByAtk.init(false, "ElecCancelableByAtk", "痺れ時攻撃でキャンセルされるか", "", + &mParametersObj); + mProofElecAtSmallDamage.init(false, "ProofElecAtSmallDamage", + "電気弾無効時小ダメージアクションをとるか", "", &mParametersObj); + mWetAffect.init(false, "WetAffect", "濡れ有効", "", &mParametersObj); + mLightningAffect.init(true, "LightningAffect", "落雷有効", "", &mParametersObj); + mLightningDamage.init(999999, "LightningDamage", "落雷ダメージ", "", &mParametersObj); + mGerudoHeroAffect.init(true, "GerudoHeroAffect", "英傑加護(雷)有効", "", &mParametersObj); + mGerudoHeroDamage.init(100, "GerudoHeroDamage", "英傑加護(雷)ダメージ", "", &mParametersObj); + mGerudoHeroTime.init(300, "GerudoHeroTime", "英傑加護(雷)痺れ時間(0だと吹っ飛び)", "", + &mParametersObj); + mGustAffect.init(true, "GustAffect", "突風有効", "", &mParametersObj); + mDrownHeight.init(-1.0, "DrownHeight", "溺れる水深(-1で溺れない)", "", &mParametersObj); + mDrownDamage.init(0, "DrownDamage", "溺れた瞬間に食らうダメージ(特殊な場合を除き0でいい)", "", + &mParametersObj); + mColdWaterFrozenTime.init(-1, "ColdWaterFrozenTime", "冷たい水地形で凍結する時間", "", + &mParametersObj); + mColdWaterAffect.init(true, "ColdWaterAffect", "冷たい水地形でダメージ有", "", &mParametersObj); + mColdWaterDamage.init(0, "ColdWaterDamage", "冷たい水ダメージ値", "", &mParametersObj); + mColdWaterDamageInterval.init(-1, "ColdWaterDamageInterval", "冷たい水ダメージ最浅間隔", "", + &mParametersObj); + mColdWaterDamageStartDepth.init(0.0, "ColdWaterDamageStartDepth", "冷たい水ダメージ最浅閾値", + "", &mParametersObj); + mColdWaterDamageIntervalDeep.init(-1, "ColdWaterDamageIntervalDeep", + "冷たい水ダメージ最深間隔(-1なら使わない)", "", + &mParametersObj); + mColdWaterDamageDeepDepth.init(-1.0, "ColdWaterDamageDeepDepth", + "冷たい水ダメージ最深閾値(-1で最深間隔は使わない)", "", + &mParametersObj); + mHotWaterBoiledTime.init( + -1, "HotWaterBoiledTime", + "熱湯地形で茹であがる時間(-1で無効,有効にする場合は以下は無効設定にして下さい)", "", + &mParametersObj); + mHotWaterHealAffect.init(false, "HotWaterHealAffect", "温泉地形で影響有", "", &mParametersObj); + mHotWaterHeal.init(0, "HotWaterHeal", "温泉回復値", "", &mParametersObj); + mHotWaterHealInterval.init(-1, "HotWaterHealInterval", "温泉影響最浅間隔", "", &mParametersObj); + mHotWaterHealStartDepth.init(0.0, "HotWaterHealStartDepth", "温泉影響最浅閾値", "", + &mParametersObj); + mHotWaterHealIntervalDeep.init(-1, "HotWaterHealIntervalDeep", + "温泉影響最深間隔(-1なら使わない)", "", &mParametersObj); + mHotWaterHealDeepDepth.init(-1.0, "HotWaterHealDeepDepth", + "温泉影響最深閾値(-1で最深間隔は使わない)", "", &mParametersObj); + mHotWaterChemCrit.init(false, "HotWaterChemCrit", "温泉入るとケミカルクリティカル", "", + &mParametersObj); + mPoisonBogAffect.init(true, "PoisonBogAffect", "毒沼地形でダメージ有", "", &mParametersObj); + mPoisonBogDamage.init(0, "PoisonBogDamage", "毒沼ダメージ値", "", &mParametersObj); + mPoisonBogDamageInterval.init(-1, "PoisonBogDamageInterval", "毒沼ダメージ間隔", "", + &mParametersObj); + mLavaAffect.init(true, "LavaAffect", "溶岩地形でダメージ有", "", &mParametersObj); + mLavaDamage.init(999999, "LavaDamage", "溶岩ダメージ値", "", &mParametersObj); + mLavaDamageInterval.init(-1, "LavaDamageInterval", "溶岩ダメージ間隔", "", &mParametersObj); + mLavaDeepDepth.init(-1.0, "LavaDeepDepth", "深い溶岩閾値", "", &mParametersObj); + mLavaDeepDamage.init(999999, "LavaDeepDamage", "深い溶岩ダメージ値", "", &mParametersObj); + mCurseAffect.init(false, "CurseAffect", "怨念ダメージ状態有効", "", &mParametersObj); + mCurseDamage.init(30, "CurseDamage", "怨念ダメージ", "", &mParametersObj); + mCurseInterval.init(60, "CurseInterval", "怨念ダメージ間隔(-1で無し)", "", &mParametersObj); + mCurseContinuousDamage.init(5, "CurseContinuousDamage", "怨念継続ダメージ", "", + &mParametersObj); + mHeavySnowColdTime.init(-1, "HeavySnowColdTime", "大雪時凍るまでの時間(-1で凍らない)", "", + &mParametersObj); + + mKeyString.init(sead::SafeString(""), "key", "", &mDamageTypeObj); + + mParamList.addObj(&mDamageRateObj, "DamageRate"); + mParamList.addObj(&mReactionTableObj, "ReactionTable"); + mParamList.addObj(&mParametersObj, "Parameters"); + mParamList.addObj(&mDamageTypeObj, "DamageType"); + addList(&mParamList, "damage_param"); + + if (data) + applyResParameterArchive(agl::utl::ResParameterArchive(data)); + + return true; +} + +f32 DamageParam::getDamageRate(const sead::SafeString& damage_source) { + u32 hash = agl::utl::ParameterBase::calcHash(damage_source); + +#pragma clang loop unroll(full) + for (int idx = 0; idx != 10; ++idx) { + if (hash == mDamageRateBuffer[idx].getNameHash()) + return mDamageRateBuffer[idx].ref(); + } + return 0.0; +} + +const sead::SafeString& DamageParam::getDamageReaction(const sead::SafeString& damage_source, + const sead::SafeString& size) { + sead::FormatFixedSafeString<128> key("%s-%s", damage_source.cstr(), size.cstr()); + + u32 hash = agl::utl::ParameterBase::calcHash(key); + +#pragma clang loop unroll(full) + for (int idx = 0; idx != 40; ++idx) { + if (hash == mDamageTypeBuffer.get(idx)->getNameHash()) + return mDamageTypeBuffer.get(idx)->ref(); + } + return sead::SafeString::cEmptyString; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceDamageParam.h b/src/KingSystem/Resource/Actor/resResourceDamageParam.h new file mode 100644 index 00000000..30d75c44 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceDamageParam.h @@ -0,0 +1,155 @@ +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include <prim/seadEnum.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class DamageParam : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(DamageParam, Resource) + +public: + DamageParam() : ParamIO("dmgparam", 0) {} + ~DamageParam() override = default; + + bool needsParse() const override { return true; } + bool ParamIO_m0(char* data) override { return false; } + + f32 getDamageRate(const sead::SafeString& damage_source); + const sead::SafeString& getDamageReaction(const sead::SafeString& damage_source, + const sead::SafeString& damage_size); + + // clang-format off + SEAD_ENUM(DamageSize,Small,Middle,Large,Huge) + SEAD_ENUM(DamageSource,Sword,LargeSword,Spear,Arrow,Bomb,Body,Ancient,ShockWave,Impulse,GanonBeam) + // clang-format on + +private: + void doCreate_(u8*, u32, sead::Heap*) override {} + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + + agl::utl::ParameterList mParamList; + agl::utl::ParameterObj mReactionTableObj; + agl::utl::ParameterObj mDamageRateObj; + agl::utl::ParameterObj mParametersObj; + agl::utl::ParameterObj mDamageTypeObj; + + sead::Buffer<agl::utl::Parameter<f32>> mDamageRateBuffer; + sead::Buffer<agl::utl::Parameter<sead::SafeString>> mDamageTypeBuffer; + +public: + agl::utl::Parameter<sead::SafeString> mKeyString; + agl::utl::Parameter<bool> mBreakable; + agl::utl::Parameter<bool> mHammerAffect; + agl::utl::Parameter<bool> mWeakBreakerAffect; + agl::utl::Parameter<bool> mChemicalAttackAffect; + agl::utl::Parameter<f32> mSpAffectRatio; + agl::utl::Parameter<s32> mSpAffectDamage; + agl::utl::Parameter<bool> mVanishAffect; + agl::utl::Parameter<bool> mIsCriticalBlowOff; + agl::utl::Parameter<bool> mIsAcceptAtkImpulse; + agl::utl::Parameter<bool> mIsCommonCalcImpuleDamage; + agl::utl::Parameter<bool> mIsHeavyBreak; + agl::utl::Parameter<f32> mImpulseThresholdLv0; + agl::utl::Parameter<f32> mImpulseDamageLv0; + agl::utl::Parameter<f32> mImpulseThresholdLv1; + agl::utl::Parameter<f32> mImpulseDamageLv1; + agl::utl::Parameter<f32> mImpulseThresholdLv2; + agl::utl::Parameter<f32> mImpulseDamageLv2; + agl::utl::Parameter<f32> mImpulseThresholdLv3; + agl::utl::Parameter<f32> mImpulseDamageLv3; + agl::utl::Parameter<f32> mImpulseThresholdLv4; + agl::utl::Parameter<f32> mFallDamageStartHeight; + agl::utl::Parameter<s32> mFallDamageMin; + agl::utl::Parameter<f32> mFallDamagePerMeter; + agl::utl::Parameter<f32> mFallDamageHighStart; + agl::utl::Parameter<s32> mFallDamageHighPerMeter; + agl::utl::Parameter<f32> mFallDamageNoWaterDepth; + agl::utl::Parameter<sead::SafeString> mWeakPointBone; + agl::utl::Parameter<f32> mWeakPointCalcArea; + agl::utl::Parameter<sead::Vector3f> mWeakPointCalcOffset; + agl::utl::Parameter<f32> mWeakPointArea; + agl::utl::Parameter<sead::Vector3f> mWeakPointOffset; + agl::utl::Parameter<f32> mWeakPointRatio; + agl::utl::Parameter<bool> mWeakPointNoUIFlag; + agl::utl::Parameter<sead::SafeString> mWeakPointBone2; + agl::utl::Parameter<f32> mWeakPointCalcArea2; + agl::utl::Parameter<sead::Vector3f> mWeakPointCalcOffset2; + agl::utl::Parameter<f32> mWeakPointArea2; + agl::utl::Parameter<sead::Vector3f> mWeakPointOffset2; + agl::utl::Parameter<f32> mWeakPointRatio2; + agl::utl::Parameter<bool> mWeakPointNoUIFlag2; + agl::utl::Parameter<f32> mSillentKillMultRatio; + agl::utl::Parameter<s32> mSillentKillAddDamage; + agl::utl::Parameter<bool> mIsDeadBurnout; + agl::utl::Parameter<bool> mIsMetamorBurnout; + agl::utl::Parameter<bool> mIsMatamorFromTg; + agl::utl::Parameter<bool> mBurnable; + agl::utl::Parameter<s32> mBurnDamage; + agl::utl::Parameter<s32> mBurnDamage2; + agl::utl::Parameter<s32> mBurnDamage3; + agl::utl::Parameter<s32> mBurnDamage4; + agl::utl::Parameter<s32> mBurnDamage5; + agl::utl::Parameter<s32> mBurnTime; + agl::utl::Parameter<s32> mBurnDamageInterval; + agl::utl::Parameter<s32> mBurnContinuousDamage; + agl::utl::Parameter<bool> mBurnCritical; + agl::utl::Parameter<bool> mProofBurnAtSmallDamage; + agl::utl::Parameter<bool> mIsDeadIce; + agl::utl::Parameter<bool> mIsMetamorIce; + agl::utl::Parameter<bool> mIceable; + agl::utl::Parameter<s32> mIceDamage; + agl::utl::Parameter<s32> mIceTime; + agl::utl::Parameter<bool> mIceBreakableByAtk; + agl::utl::Parameter<f32> mIceBreakDamageRatio; + agl::utl::Parameter<bool> mIceCritical; + agl::utl::Parameter<bool> mProofIceAtSmallDamage; + agl::utl::Parameter<bool> mIsDeadElectric; + agl::utl::Parameter<bool> mIsMetamorElectric; + agl::utl::Parameter<bool> mElectricable; + agl::utl::Parameter<s32> mElectricDamage; + agl::utl::Parameter<s32> mElectricTime; + agl::utl::Parameter<bool> mElecCancelableByAtk; + agl::utl::Parameter<bool> mProofElecAtSmallDamage; + agl::utl::Parameter<bool> mWetAffect; + agl::utl::Parameter<bool> mLightningAffect; + agl::utl::Parameter<s32> mLightningDamage; + agl::utl::Parameter<bool> mGerudoHeroAffect; + agl::utl::Parameter<s32> mGerudoHeroDamage; + agl::utl::Parameter<s32> mGerudoHeroTime; + agl::utl::Parameter<bool> mGustAffect; + agl::utl::Parameter<f32> mDrownHeight; + agl::utl::Parameter<s32> mDrownDamage; + agl::utl::Parameter<s32> mColdWaterFrozenTime; + agl::utl::Parameter<bool> mColdWaterAffect; + agl::utl::Parameter<s32> mColdWaterDamage; + agl::utl::Parameter<s32> mColdWaterDamageInterval; + agl::utl::Parameter<f32> mColdWaterDamageStartDepth; + agl::utl::Parameter<s32> mColdWaterDamageIntervalDeep; + agl::utl::Parameter<f32> mColdWaterDamageDeepDepth; + agl::utl::Parameter<s32> mHotWaterBoiledTime; + agl::utl::Parameter<bool> mHotWaterHealAffect; + agl::utl::Parameter<s32> mHotWaterHeal; + agl::utl::Parameter<s32> mHotWaterHealInterval; + agl::utl::Parameter<f32> mHotWaterHealStartDepth; + agl::utl::Parameter<s32> mHotWaterHealIntervalDeep; + agl::utl::Parameter<f32> mHotWaterHealDeepDepth; + agl::utl::Parameter<bool> mHotWaterChemCrit; + agl::utl::Parameter<bool> mPoisonBogAffect; + agl::utl::Parameter<s32> mPoisonBogDamage; + agl::utl::Parameter<s32> mPoisonBogDamageInterval; + agl::utl::Parameter<bool> mLavaAffect; + agl::utl::Parameter<s32> mLavaDamage; + agl::utl::Parameter<s32> mLavaDamageInterval; + agl::utl::Parameter<f32> mLavaDeepDepth; + agl::utl::Parameter<s32> mLavaDeepDamage; + agl::utl::Parameter<bool> mCurseAffect; + agl::utl::Parameter<s32> mCurseDamage; + agl::utl::Parameter<s32> mCurseInterval; + agl::utl::Parameter<s32> mCurseContinuousDamage; + agl::utl::Parameter<s32> mHeavySnowColdTime; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceDrop.cpp b/src/KingSystem/Resource/Actor/resResourceDrop.cpp new file mode 100644 index 00000000..d3696ba3 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceDrop.cpp @@ -0,0 +1,173 @@ +#include "KingSystem/Resource/Actor/resResourceDrop.h" +#include <random/seadGlobalRandom.h> + +namespace ksys::res { + +bool Drop::parse_(u8* data, size_t, sead::Heap* heap) { + mTableNum.init(0, "TableNum", "テーブルの数", &mObj); + addObj(&mObj, "Header"); + + if (!data) + return true; + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + + const s32 num_tables = mTableNum.ref(); + if (num_tables < 1) + return true; + + mTables.allocBufferAssert(num_tables, heap); + + const agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + const auto header_obj = root.getResParameterObj(0); + + for (s32 i = 0; i < num_tables; ++i) { + sead::FormatFixedSafeString<64> name; + name.format("Table%02d", i + 1); + mTables[i].name.init("", name, "テーブル名", &mObj); + } + + mObj.applyResParameterObj(header_obj); + + for (s32 i = 0; i < num_tables; ++i) { + const auto obj = root.getResParameterObj(i + 1); + + mTables[i].repeat_num_min.init(0, "RepeatNumMin", "抽選回数最小", &mTables[i].obj); + mTables[i].repeat_num_max.init(0, "RepeatNumMax", "抽選回数最大", &mTables[i].obj); + mTables[i].approach_type.init(0, "ApproachType", "姿勢", &mTables[i].obj); + mTables[i].occurrence_speed_type.init(0, "OccurrenceSpeedType", "発生速度", + &mTables[i].obj); + mTables[i].column_num.init(0, "ColumnNum", "行数", &mTables[i].obj); + + addObj(&mTables[i].obj, mTables[i].name.ref()); + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + mTables[i].obj.applyResParameterObj(obj); + + if (mTables[i].column_num.ref() > 0) { + mTables[i].items.allocBufferAssert(mTables[i].column_num.ref(), heap); + } + } + + for (s32 i = 0; i < num_tables; ++i) { + parseItems_(i); + } + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + return true; +} + +void Drop::parseItems_(s32& table_idx) { + const s32 num = mTables[table_idx].column_num.ref(); + for (s32 i = 0; i < num; ++i) { + sead::FormatFixedSafeString<64> name; + name.format("ItemName%02d", i + 1); + mTables[table_idx].items[i].name.init("", name, "アイテム名", &mTables[table_idx].obj); + + sead::FormatFixedSafeString<64> name2; + name2.format("ItemProbability%02d", i + 1); + mTables[table_idx].items[i].probability.init(0.0, name2, "確率", &mTables[table_idx].obj); + } +} + +s32 Drop::findTableIndex(const sead::SafeString& table_name) const { + if (!mTables.isBufferReady()) + return -1; + + const s32 num = mTableNum.ref(); + for (s32 i = 0; i < num; ++i) { + if (mTables[i].name.ref() == table_name) + return i; + } + + return -1; +} + +s32 Drop::findTableIndexOrNormal(const sead::SafeString& table_name) const { + if (!mTables.isBufferReady()) + return -1; + + s32 normal_idx = -1; + const s32 num = mTableNum.ref(); + for (s32 i = 0; i < num; ++i) { + if (mTables[i].name.ref() == table_name) + return i; + + if (normal_idx < 0 && mTables[i].name.ref() == "Normal") + normal_idx = i; + } + + return normal_idx; +} + +const sead::SafeString& Drop::getRandomDropFromTable(const sead::SafeString& table_name) const { + return getRandomDropFromTable(findTableIndexOrNormal(table_name)); +} + +const sead::SafeString& Drop::getRandomDropFromTable(s32 table_idx) const { + if (!mTables.isBufferReady()) + return sead::SafeString::cEmptyString; + + /// @bug The index check should be done first... + if (!mTables[table_idx].items.isBufferReady() || table_idx < 0) + return sead::SafeString::cEmptyString; + + f32 x = sead::GlobalRandom::instance()->getF32() * 100.0; + + const Table& table = mTables[table_idx]; + const s32 num_items = table.column_num.ref(); + for (s32 i = 0; i < num_items; ++i) { + const Item& item = table.items[i]; + + const f32 probability = item.probability.ref(); + if (x < probability) + return item.name.ref(); + + x -= probability; + } + + return sead::SafeString::cEmptyString; +} + +s32 Drop::getApproachType(s32 table_idx) const { + if (!mTables.isBufferReady()) + return 0; + + /// @bug This bounds checking is bugged: the order is absurd and the second check is off-by-one. + if (!mTables[table_idx].items.isBufferReady() || table_idx < 0 || table_idx > mTables.size()) + return 0; + + return mTables[table_idx].approach_type.ref(); +} + +s32 Drop::getOccurrenceSpeedType(s32 table_idx) const { + if (!mTables.isBufferReady()) + return 0; + + /// @bug This bounds checking is bugged: the order is absurd and the second check is off-by-one. + if (!mTables[table_idx].items.isBufferReady() || table_idx < 0 || table_idx > mTables.size()) + return 0; + + return mTables[table_idx].occurrence_speed_type.ref(); +} + +s32 Drop::getRepeatNum(s32 table_idx) const { + if (!mTables.isBufferReady()) + return 0; + + const Table& table = mTables[table_idx]; + if (!mTables[table_idx].items.isBufferReady() || table_idx < 0 || table_idx > mTables.size()) + return 0; + + const s32 num_min = table.repeat_num_min.ref(); + const s32 num_max = table.repeat_num_max.ref(); + if (num_min == num_max) + return num_min; + return num_min + sead::GlobalRandom::instance()->getU32(1 - num_min + num_max); +} + +s32 Drop::getRepeatNum(const sead::SafeString& table_name) const { + return getRepeatNum(findTableIndexOrNormal(table_name)); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceDrop.h b/src/KingSystem/Resource/Actor/resResourceDrop.h new file mode 100644 index 00000000..198f26e5 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceDrop.h @@ -0,0 +1,71 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class Drop : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(Drop, Resource) +public: + Drop() : ParamIO("drop", 0) {} + + /// Returns the name of a randomly chosen drop from the specified table or from the Normal table + /// if the table cannot be found. + /// The empty string is returned if no drop was chosen. + const sead::SafeString& getRandomDropFromTable(const sead::SafeString& table_name) const; + + /// Returns the name of a randomly chosen drop from the specified table. + /// The empty string is returned if no drop was chosen. + const sead::SafeString& getRandomDropFromTable(s32 table_idx) const; + + /// Returns the index of the specified table. If the table cannot be found, the index of the + /// first Normal table is returned. Note that it may be equal to -1 if there is no Normal table. + s32 findTableIndexOrNormal(const sead::SafeString& table_name) const; + + /// Returns the index of the specified table or -1 if it cannot be found. + s32 findTableIndex(const sead::SafeString& table_name) const; + + s32 getApproachType(s32 table_idx) const; + s32 getOccurrenceSpeedType(s32 table_idx) const; + s32 getRepeatNum(s32 table_idx) const; + s32 getRepeatNum(const sead::SafeString& table_name) const; + + bool ParamIO_m0(char* data) override { return true; } + void doCreate_(u8*, u32, sead::Heap*) override {} + bool needsParse() const override { return true; } + +private: + struct Item { + agl::utl::Parameter<sead::SafeString> name; + agl::utl::Parameter<f32> probability; + }; + KSYS_CHECK_SIZE_NX150(Item, 0x48); + + struct Table { + agl::utl::ParameterObj obj; + agl::utl::Parameter<sead::SafeString> name; + agl::utl::Parameter<s32> repeat_num_min; + agl::utl::Parameter<s32> repeat_num_max; + agl::utl::Parameter<s32> approach_type; + agl::utl::Parameter<s32> occurrence_speed_type; + agl::utl::Parameter<s32> column_num; + sead::Buffer<Item> items; + }; + KSYS_CHECK_SIZE_NX150(Table, 0x108); + + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + void parseItems_(s32& table_idx); + + agl::utl::ParameterObj mObj; + agl::utl::Parameter<s32> mTableNum; + sead::Buffer<void*> _300; + sead::Buffer<Table> mTables; +}; +KSYS_CHECK_SIZE_NX150(Drop, 0x320); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceGParamList.cpp b/src/KingSystem/Resource/Actor/resResourceGParamList.cpp new file mode 100644 index 00000000..22512e64 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceGParamList.cpp @@ -0,0 +1,304 @@ +#include "KingSystem/Resource/Actor/resResourceGParamList.h" +#include <agl/Utils/aglParameter.h> +#include <prim/seadRuntimeTypeInfo.h> +#include "KingSystem/ActorSystem/actActorParamMgr.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObject.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectAirWall.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectAnimalFollowOffset.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectAnimalUnit.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectArmor.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectArmorEffect.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectArmorHead.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectArmorUpper.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectArrow.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectAttack.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectAttackInterval.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectAutoGen.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectBeam.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectBindActor.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectBindBone.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectBow.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectBullet.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectCamera.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectChemicalType.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectClothReaction.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectCookSpice.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectCureItem.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectEatTarget.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectEnemy.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectEnemyLevel.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectEnemyRace.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectEnemyShown.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectEvent.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectExtendedEntity.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectFish.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGelEnemy.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGeneral.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGiantArmor.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGiantArmorSlot.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGlobal.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGolem.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGolemIK.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGrab.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGuardian.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGuardianMini.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectGuardianMiniWeapon.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectHorse.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectHorseCreator.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectHorseObject.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectHorseRider.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectHorseTargetedInfo.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectHorseUnit.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectInsect.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectItem.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectLargeSword.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectLiftable.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectLumberjackTree.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectMasterSword.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectMonsterShop.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectMotorcycle.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectNest.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectNpc.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectNpcEquipment.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectPictureBook.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectPlayer.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectPrey.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectRod.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectRope.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectRupee.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectSandworm.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectSeriesArmor.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectShiekerStone.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectShield.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectSmallSword.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectSpear.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectStalEnemy.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectSwarm.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectSystem.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectTraveler.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectWeaponCommon.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectWeaponOption.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectWeaponThrow.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectWizzrobe.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectWolfLink.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListObjectZora.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListTraits.h" + +namespace ksys::res { + +void GParamList::doCreate_(u8*, u32, sead::Heap*) {} + +bool GParamList::parse_(u8* data, size_t, sead::Heap* heap) { + GParamList* dummy_list = nullptr; + if (!sead::IsDerivedFrom<DummyGParamList>(this) && act::ActorParamMgr::instance()) + dummy_list = act::ActorParamMgr::instance()->getDummyGParamList(); + + mObjects.allocBufferAssert(NumGParamListObjTypes, heap); + + const agl::utl::ResParameterArchive archive{data}; + +#define KSYS_GPARAM_ADD_(NAME) \ + do { \ + using Traits = GParamListObjTypeTraits<GParamListObjType::NAME>; \ + const auto pobj = agl::utl::getResParameterObj(archive.getRootList(), #NAME); \ + if (pobj.ptr()) { \ + auto* obj = new (heap) Traits::type; \ + if (obj) \ + addObj(&obj->getObj(), obj->getName()); \ + \ + mObjects[Traits::index] = obj; \ + \ + } else { \ + mObjects[Traits::index] = dummy_list ? dummy_list->mObjects[Traits::index] : nullptr; \ + } \ + } while (0) + + KSYS_GPARAM_ADD_(System); + KSYS_GPARAM_ADD_(General); + KSYS_GPARAM_ADD_(Enemy); + KSYS_GPARAM_ADD_(EnemyLevel); + KSYS_GPARAM_ADD_(EnemyRace); + KSYS_GPARAM_ADD_(AttackInterval); + KSYS_GPARAM_ADD_(EnemyShown); + KSYS_GPARAM_ADD_(BindBone); + KSYS_GPARAM_ADD_(Attack); + KSYS_GPARAM_ADD_(WeaponCommon); + KSYS_GPARAM_ADD_(WeaponThrow); + KSYS_GPARAM_ADD_(Sandworm); + KSYS_GPARAM_ADD_(SmallSword); + KSYS_GPARAM_ADD_(Rod); + KSYS_GPARAM_ADD_(LargeSword); + KSYS_GPARAM_ADD_(Spear); + KSYS_GPARAM_ADD_(Shield); + KSYS_GPARAM_ADD_(Bow); + KSYS_GPARAM_ADD_(WeaponOption); + KSYS_GPARAM_ADD_(MasterSword); + KSYS_GPARAM_ADD_(GuardianMiniWeapon); + KSYS_GPARAM_ADD_(Player); + KSYS_GPARAM_ADD_(Camera); + KSYS_GPARAM_ADD_(Grab); + KSYS_GPARAM_ADD_(Armor); + KSYS_GPARAM_ADD_(ArmorEffect); + KSYS_GPARAM_ADD_(ArmorHead); + KSYS_GPARAM_ADD_(ArmorUpper); + KSYS_GPARAM_ADD_(ShiekerStone); + KSYS_GPARAM_ADD_(SeriesArmor); + KSYS_GPARAM_ADD_(Liftable); + KSYS_GPARAM_ADD_(Item); + KSYS_GPARAM_ADD_(Rupee); + KSYS_GPARAM_ADD_(Arrow); + KSYS_GPARAM_ADD_(Bullet); + KSYS_GPARAM_ADD_(CureItem); + KSYS_GPARAM_ADD_(CookSpice); + KSYS_GPARAM_ADD_(LumberjackTree); + KSYS_GPARAM_ADD_(Npc); + KSYS_GPARAM_ADD_(NpcEquipment); + KSYS_GPARAM_ADD_(Zora); + KSYS_GPARAM_ADD_(Traveler); + KSYS_GPARAM_ADD_(Prey); + KSYS_GPARAM_ADD_(AnimalFollowOffset); + KSYS_GPARAM_ADD_(ExtendedEntity); + KSYS_GPARAM_ADD_(BindActor); + KSYS_GPARAM_ADD_(EatTarget); + KSYS_GPARAM_ADD_(AnimalUnit); + KSYS_GPARAM_ADD_(Insect); + KSYS_GPARAM_ADD_(Fish); + KSYS_GPARAM_ADD_(Rope); + KSYS_GPARAM_ADD_(Horse); + KSYS_GPARAM_ADD_(HorseUnit); + KSYS_GPARAM_ADD_(HorseObject); + KSYS_GPARAM_ADD_(HorseRider); + KSYS_GPARAM_ADD_(HorseCreator); + KSYS_GPARAM_ADD_(GiantArmorSlot); + KSYS_GPARAM_ADD_(GiantArmor); + KSYS_GPARAM_ADD_(Guardian); + KSYS_GPARAM_ADD_(MonsterShop); + KSYS_GPARAM_ADD_(Swarm); + KSYS_GPARAM_ADD_(GelEnemy); + KSYS_GPARAM_ADD_(Nest); + KSYS_GPARAM_ADD_(Wizzrobe); + KSYS_GPARAM_ADD_(StalEnemy); + KSYS_GPARAM_ADD_(GuardianMini); + KSYS_GPARAM_ADD_(ClothReaction); + KSYS_GPARAM_ADD_(Global); + KSYS_GPARAM_ADD_(Beam); + KSYS_GPARAM_ADD_(AutoGen); + KSYS_GPARAM_ADD_(ChemicalType); + KSYS_GPARAM_ADD_(Golem); + KSYS_GPARAM_ADD_(HorseTargetedInfo); + KSYS_GPARAM_ADD_(WolfLink); + KSYS_GPARAM_ADD_(Event); + KSYS_GPARAM_ADD_(GolemIK); + KSYS_GPARAM_ADD_(PictureBook); + KSYS_GPARAM_ADD_(AirWall); + KSYS_GPARAM_ADD_(Motorcycle); + +#undef KSYS_GPARAM_ADD_ + + if (data) + applyResParameterArchive(archive); + + return true; +} + +void GParamList::finalize_() {} + +static constexpr size_t getResourceFactoryFallbackSizeConst() { + size_t size = 0; + size += sizeof(GParamListObjectSystem); + size += sizeof(GParamListObjectGeneral); + size += sizeof(GParamListObjectEnemy); + size += sizeof(GParamListObjectEnemyLevel); + size += sizeof(GParamListObjectEnemyRace); + size += sizeof(GParamListObjectAttackInterval); + size += sizeof(GParamListObjectEnemyShown); + size += sizeof(GParamListObjectBindBone); + size += sizeof(GParamListObjectAttack); + size += sizeof(GParamListObjectWeaponCommon); + size += sizeof(GParamListObjectWeaponThrow); + size += sizeof(GParamListObjectSandworm); + size += sizeof(GParamListObjectSmallSword); + size += sizeof(GParamListObjectRod); + size += sizeof(GParamListObjectLargeSword); + size += sizeof(GParamListObjectSpear); + size += sizeof(GParamListObjectShield); + size += sizeof(GParamListObjectBow); + size += sizeof(GParamListObjectWeaponOption); + size += sizeof(GParamListObjectMasterSword); + size += sizeof(GParamListObjectGuardianMiniWeapon); + size += sizeof(GParamListObjectPlayer); + size += sizeof(GParamListObjectCamera); + size += sizeof(GParamListObjectGrab); + size += sizeof(GParamListObjectArmor); + size += sizeof(GParamListObjectArmorEffect); + size += sizeof(GParamListObjectArmorHead); + size += sizeof(GParamListObjectArmorUpper); + size += sizeof(GParamListObjectShiekerStone); + size += sizeof(GParamListObjectSeriesArmor); + size += sizeof(GParamListObjectLiftable); + size += sizeof(GParamListObjectItem); + size += sizeof(GParamListObjectRupee); + size += sizeof(GParamListObjectArrow); + size += sizeof(GParamListObjectBullet); + size += sizeof(GParamListObjectCureItem); + size += sizeof(GParamListObjectCookSpice); + size += sizeof(GParamListObjectLumberjackTree); + size += sizeof(GParamListObjectNpc); + size += sizeof(GParamListObjectNpcEquipment); + size += sizeof(GParamListObjectZora); + size += sizeof(GParamListObjectTraveler); + size += sizeof(GParamListObjectPrey); + size += sizeof(GParamListObjectAnimalFollowOffset); + size += sizeof(GParamListObjectExtendedEntity); + size += sizeof(GParamListObjectBindActor); + size += sizeof(GParamListObjectEatTarget); + size += sizeof(GParamListObjectAnimalUnit); + size += sizeof(GParamListObjectInsect); + size += sizeof(GParamListObjectFish); + size += sizeof(GParamListObjectRope); + size += sizeof(GParamListObjectHorse); + size += sizeof(GParamListObjectHorseUnit); + size += sizeof(GParamListObjectHorseObject); + size += sizeof(GParamListObjectHorseRider); + size += sizeof(GParamListObjectHorseCreator); + size += sizeof(GParamListObjectGiantArmorSlot); + size += sizeof(GParamListObjectGiantArmor); + size += sizeof(GParamListObjectGuardian); + size += sizeof(GParamListObjectMonsterShop); + size += sizeof(GParamListObjectSwarm); + size += sizeof(GParamListObjectGelEnemy); + size += sizeof(GParamListObjectNest); + size += sizeof(GParamListObjectWizzrobe); + size += sizeof(GParamListObjectStalEnemy); + size += sizeof(GParamListObjectGuardianMini); + size += sizeof(GParamListObjectClothReaction); + size += sizeof(GParamListObjectGlobal); + size += sizeof(GParamListObjectBeam); + size += sizeof(GParamListObjectAutoGen); + size += sizeof(GParamListObjectChemicalType); + size += sizeof(GParamListObjectGolem); + size += sizeof(GParamListObjectHorseTargetedInfo); + size += sizeof(GParamListObjectWolfLink); + size += sizeof(GParamListObjectEvent); + size += sizeof(GParamListObjectGolemIK); + size += sizeof(GParamListObjectPictureBook); + size += sizeof(GParamListObjectAirWall); + size += sizeof(GParamListObjectMotorcycle); + size += sizeof(GParamList); + return size; +} + +u32 GParamList::getResourceFactoryFallbackSize() { + constexpr size_t size = getResourceFactoryFallbackSizeConst(); + static_assert(size == static_cast<u32>(size)); + return static_cast<u32>(size); +} + +void DummyGParamList::doCreate_(u8*, u32, sead::Heap*) {} + +bool DummyGParamList::parse_(u8* data, size_t size, sead::Heap* heap) { + GParamList::parse_(data, size, heap); + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceGParamList.h b/src/KingSystem/Resource/Actor/resResourceGParamList.h new file mode 100644 index 00000000..98ac36f0 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceGParamList.h @@ -0,0 +1,136 @@ +#pragma once + +#include <container/seadBuffer.h> +#include "KingSystem/Resource/GeneralParamList/resGParamListObject.h" +#include "KingSystem/Resource/GeneralParamList/resGParamListTraits.h" +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class GParamList : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(GParamList, Resource) +public: + GParamList() : ParamIO("bgparamlist", 0) {} + ~GParamList() override = default; + + bool ParamIO_m0(char* data) override { return false; } + void doCreate_(u8* buffer, u32 bufferSize, sead::Heap* heap) override; + bool needsParse() const override { return true; } + + static u32 getResourceFactoryFallbackSize(); + + template <GParamListObjType Type> + const auto* get() const { + using Traits = GParamListObjTypeTraits<Type>; + return reinterpret_cast<const typename Traits::type*>(mObjects[Traits::index]); + } + +#define KSYS_GPARAM_DEFINE_GETTER_(NAME) \ + const auto* get##NAME() const { return get<GParamListObjType::NAME>(); } + + KSYS_GPARAM_DEFINE_GETTER_(System) + KSYS_GPARAM_DEFINE_GETTER_(General) + KSYS_GPARAM_DEFINE_GETTER_(Enemy) + KSYS_GPARAM_DEFINE_GETTER_(EnemyLevel) + KSYS_GPARAM_DEFINE_GETTER_(EnemyRace) + KSYS_GPARAM_DEFINE_GETTER_(AttackInterval) + KSYS_GPARAM_DEFINE_GETTER_(EnemyShown) + KSYS_GPARAM_DEFINE_GETTER_(BindBone) + KSYS_GPARAM_DEFINE_GETTER_(Attack) + KSYS_GPARAM_DEFINE_GETTER_(WeaponCommon) + KSYS_GPARAM_DEFINE_GETTER_(WeaponThrow) + KSYS_GPARAM_DEFINE_GETTER_(Sandworm) + KSYS_GPARAM_DEFINE_GETTER_(SmallSword) + KSYS_GPARAM_DEFINE_GETTER_(Rod) + KSYS_GPARAM_DEFINE_GETTER_(LargeSword) + KSYS_GPARAM_DEFINE_GETTER_(Spear) + KSYS_GPARAM_DEFINE_GETTER_(Shield) + KSYS_GPARAM_DEFINE_GETTER_(Bow) + KSYS_GPARAM_DEFINE_GETTER_(WeaponOption) + KSYS_GPARAM_DEFINE_GETTER_(MasterSword) + KSYS_GPARAM_DEFINE_GETTER_(GuardianMiniWeapon) + KSYS_GPARAM_DEFINE_GETTER_(Player) + KSYS_GPARAM_DEFINE_GETTER_(Camera) + KSYS_GPARAM_DEFINE_GETTER_(Grab) + KSYS_GPARAM_DEFINE_GETTER_(Armor) + KSYS_GPARAM_DEFINE_GETTER_(ArmorEffect) + KSYS_GPARAM_DEFINE_GETTER_(ArmorHead) + KSYS_GPARAM_DEFINE_GETTER_(ArmorUpper) + KSYS_GPARAM_DEFINE_GETTER_(ShiekerStone) + KSYS_GPARAM_DEFINE_GETTER_(SeriesArmor) + KSYS_GPARAM_DEFINE_GETTER_(Liftable) + KSYS_GPARAM_DEFINE_GETTER_(Item) + KSYS_GPARAM_DEFINE_GETTER_(Rupee) + KSYS_GPARAM_DEFINE_GETTER_(Arrow) + KSYS_GPARAM_DEFINE_GETTER_(Bullet) + KSYS_GPARAM_DEFINE_GETTER_(CureItem) + KSYS_GPARAM_DEFINE_GETTER_(CookSpice) + KSYS_GPARAM_DEFINE_GETTER_(LumberjackTree) + KSYS_GPARAM_DEFINE_GETTER_(Npc) + KSYS_GPARAM_DEFINE_GETTER_(NpcEquipment) + KSYS_GPARAM_DEFINE_GETTER_(Zora) + KSYS_GPARAM_DEFINE_GETTER_(Traveler) + KSYS_GPARAM_DEFINE_GETTER_(Prey) + KSYS_GPARAM_DEFINE_GETTER_(AnimalFollowOffset) + KSYS_GPARAM_DEFINE_GETTER_(ExtendedEntity) + KSYS_GPARAM_DEFINE_GETTER_(BindActor) + KSYS_GPARAM_DEFINE_GETTER_(EatTarget) + KSYS_GPARAM_DEFINE_GETTER_(AnimalUnit) + KSYS_GPARAM_DEFINE_GETTER_(Insect) + KSYS_GPARAM_DEFINE_GETTER_(Fish) + KSYS_GPARAM_DEFINE_GETTER_(Rope) + KSYS_GPARAM_DEFINE_GETTER_(Horse) + KSYS_GPARAM_DEFINE_GETTER_(HorseUnit) + KSYS_GPARAM_DEFINE_GETTER_(HorseObject) + KSYS_GPARAM_DEFINE_GETTER_(HorseRider) + KSYS_GPARAM_DEFINE_GETTER_(HorseCreator) + KSYS_GPARAM_DEFINE_GETTER_(GiantArmorSlot) + KSYS_GPARAM_DEFINE_GETTER_(GiantArmor) + KSYS_GPARAM_DEFINE_GETTER_(Guardian) + KSYS_GPARAM_DEFINE_GETTER_(MonsterShop) + KSYS_GPARAM_DEFINE_GETTER_(Swarm) + KSYS_GPARAM_DEFINE_GETTER_(GelEnemy) + KSYS_GPARAM_DEFINE_GETTER_(Nest) + KSYS_GPARAM_DEFINE_GETTER_(Wizzrobe) + KSYS_GPARAM_DEFINE_GETTER_(StalEnemy) + KSYS_GPARAM_DEFINE_GETTER_(GuardianMini) + KSYS_GPARAM_DEFINE_GETTER_(ClothReaction) + KSYS_GPARAM_DEFINE_GETTER_(Global) + KSYS_GPARAM_DEFINE_GETTER_(Beam) + KSYS_GPARAM_DEFINE_GETTER_(AutoGen) + KSYS_GPARAM_DEFINE_GETTER_(ChemicalType) + KSYS_GPARAM_DEFINE_GETTER_(Golem) + KSYS_GPARAM_DEFINE_GETTER_(HorseTargetedInfo) + KSYS_GPARAM_DEFINE_GETTER_(WolfLink) + KSYS_GPARAM_DEFINE_GETTER_(Event) + KSYS_GPARAM_DEFINE_GETTER_(GolemIK) + KSYS_GPARAM_DEFINE_GETTER_(PictureBook) + KSYS_GPARAM_DEFINE_GETTER_(AirWall) + KSYS_GPARAM_DEFINE_GETTER_(Motorcycle) + +#undef KSYS_GPARAM_DEFINE_GETTER_ + +protected: + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + void finalize_() override; + +private: + sead::Buffer<GParamListObject*> mObjects; +}; +KSYS_CHECK_SIZE_NX150(GParamList, 0x2c0); + +class DummyGParamList : public GParamList { + SEAD_RTTI_OVERRIDE(DummyGParamList, GParamList) +public: + using GParamList::GParamList; + ~DummyGParamList() override = default; + + void doCreate_(u8* buffer, u32 bufferSize, sead::Heap* heap) override; + +private: + bool parse_(u8* data, size_t size, sead::Heap* heap) override; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceLifeCondition.cpp b/src/KingSystem/Resource/Actor/resResourceLifeCondition.cpp new file mode 100644 index 00000000..84edd261 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceLifeCondition.cpp @@ -0,0 +1,82 @@ +#include "KingSystem/Resource/Actor/resResourceLifeCondition.h" + +namespace ksys::res { + +// NON_MATCHING: two instructions swapped +bool LifeCondition::parse_(u8* data, size_t, sead::Heap* heap) { + if (!data) + return true; + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + const agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + + const auto invalid_weathers_obj = agl::utl::getResParameterObj(root, "InvalidWeathers"); + if (invalid_weathers_obj.ptr()) + LifeCondition::parseArray(&invalid_weathers_obj, &mInvalidWeathersObj, + &mInvalidWeathersBuffer, "InvalidWeathers", "天候", heap); + + const auto invalid_times_obj = agl::utl::getResParameterObj(root, "InvalidTimes"); + if (invalid_times_obj.ptr()) + LifeCondition::parseArray(&invalid_times_obj, &mInvalidTimesObj, &mInvalidTimesBuffer, + "InvalidTimes", "時間", heap); + + const auto display_distance_obj = agl::utl::getResParameterObj(root, "DisplayDistance"); + if (display_distance_obj.ptr()) { + mDisplayDistance.init(0.0, "Item", "表示距離", &mDisplayDistanceObj); + addObj(&mDisplayDistanceObj, "DisplayDistance"); + mDisplayDistanceObj.applyResParameterObj(display_distance_obj); + } + + const auto auto_display_distance_algorithm_obj = + agl::utl::getResParameterObj(root, "AutoDisplayDistanceAlgorithm"); + if (auto_display_distance_algorithm_obj.ptr()) { + mBoundingY.init("Bouding.Y", "Item", "自動距離算出アルゴリズム", &mBoundingYObj); + addObj(&mBoundingYObj, "AutoDisplayDistanceAlgorithm"); + mBoundingYObj.applyResParameterObj(auto_display_distance_algorithm_obj); + } + + const auto y_limit_algorithm_obj = agl::utl::getResParameterObj(root, "YLimitAlgorithm"); + if (y_limit_algorithm_obj.ptr()) { + mYLimitAlgorithm.init("NoLimit", "Item", "Y制限アルゴリズム", &mYLimitAlgorithmObj); + addObj(&mYLimitAlgorithmObj, "YLimitAlgorithm"); + mYLimitAlgorithmObj.applyResParameterObj(y_limit_algorithm_obj); + } + + const auto delete_weathers_obj = agl::utl::getResParameterObj(root, "DeleteWeathers"); + if (delete_weathers_obj.ptr()) + LifeCondition::parseArray(&delete_weathers_obj, &mDeleteWeathersObj, &mDeleteWeathersBuffer, + "DeleteWeathers", "天候", heap); + + const auto delete_times_obj = agl::utl::getResParameterObj(root, "DeleteTimes"); + if (delete_times_obj.ptr()) + LifeCondition::parseArray(&delete_times_obj, &mDeleteTimesObj, &mDeleteTimesBuffer, + "DeleteTimes", "時間", heap); + + return true; +} + +void LifeCondition::parseArray(const agl::utl::ResParameterObj* data, agl::utl::IParameterObj* obj, + sead::Buffer<agl::utl::Parameter<sead::SafeString>>* buffer, + const sead::SafeString& key, const sead::SafeString& desc, + sead::Heap* heap) { + addObj(obj, key); + obj->applyResParameterObj(*data); + + auto count = data->mPtr->getNumParameters(); + if (count == 0) + return; + + buffer->allocBufferAssert(count, heap); + + for (int i = 0; i != count; ++i) { + sead::FormatFixedSafeString<64> s; + s.format("Item%03d", (i + 1)); + + (*buffer)[i].init("", s, desc, obj); + } + + obj->applyResParameterObj(*data); +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceLifeCondition.h b/src/KingSystem/Resource/Actor/resResourceLifeCondition.h new file mode 100644 index 00000000..8f6d6d9d --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceLifeCondition.h @@ -0,0 +1,45 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class LifeCondition : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(LifeCondition, Resource) +public: + LifeCondition() : ParamIO("lifecondition", 0) {} + ~LifeCondition() override = default; + + bool needsParse() const override { return true; } + bool ParamIO_m0(char* data) override { return true; } + +private: + void doCreate_(u8*, u32, sead::Heap*) override {} + void parseArray(const agl::utl::ResParameterObj* data, agl::utl::IParameterObj* obj, + sead::Buffer<agl::utl::Parameter<sead::SafeString>>* buffer, + const sead::SafeString& key, const sead::SafeString& desc, sead::Heap* heap); + + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + + agl::utl::ParameterObj mInvalidWeathersObj; + agl::utl::ParameterObj mInvalidTimesObj; + agl::utl::ParameterObj mDisplayDistanceObj; + agl::utl::ParameterObj mDeleteWeathersObj; + agl::utl::ParameterObj mDeleteTimesObj; + agl::utl::ParameterObj mBoundingYObj; + agl::utl::ParameterObj mYLimitAlgorithmObj; + + sead::Buffer<agl::utl::Parameter<sead::SafeString>> mInvalidWeathersBuffer; + sead::Buffer<agl::utl::Parameter<sead::SafeString>> mInvalidTimesBuffer; + agl::utl::Parameter<f32> mDisplayDistance; + agl::utl::Parameter<sead::SafeString> mBoundingY; + agl::utl::Parameter<sead::SafeString> mYLimitAlgorithm; + sead::Buffer<agl::utl::Parameter<sead::SafeString>> mDeleteWeathersBuffer; + sead::Buffer<agl::utl::Parameter<sead::SafeString>> mDeleteTimesBuffer; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceLod.cpp b/src/KingSystem/Resource/Actor/resResourceLod.cpp new file mode 100644 index 00000000..04c02b3e --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceLod.cpp @@ -0,0 +1,22 @@ +#include "KingSystem/Resource/Actor/resResourceLod.h" + +namespace ksys::res { + +bool Lod::parse_(u8* data, size_t, sead::Heap*) { + mDisableOutScreenCalcStop.init(false, "DisableOutScreenCalcStop", "", &mHeader); + mDisableXLinkSkip.init(false, "DisableXLinkSkip", "", &mHeader); + mDisableCalcSkipFrame.init(4, "DisableCalcSkipFrame", "", &mHeader); + mDisableConstActor.init(false, "DisableConstActor", "", &mHeader); + mDistanceScale.init(1.0, "DistanceScale", "", &mHeader); + mDisableBehaviorSkip.init(false, "DisableBehaviorSkip", "", &mHeader); + mDisableCalcRescueDistLimit.init(false, "DisableCalcRescueDistLimit", "", &mHeader); + + addObj(&mHeader, "Header"); + + if (data) + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceLod.h b/src/KingSystem/Resource/Actor/resResourceLod.h new file mode 100644 index 00000000..098faee2 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceLod.h @@ -0,0 +1,37 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterIO.h> +#include <agl/Utils/aglParameterObj.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class Lod : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(Lod, Resource) +public: + Lod() : ParamIO("lod", 0) {} + ~Lod() override = default; + + bool ParamIO_m0(char* data) override { return true; } + void doCreate_(u8*, u32, sead::Heap*) override {} + bool needsParse() const override { return true; } + +protected: + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + + agl::utl::ParameterObj mHeader; + +public: + agl::utl::Parameter<bool> mDisableOutScreenCalcStop; + agl::utl::Parameter<bool> mDisableXLinkSkip; + agl::utl::Parameter<s32> mDisableCalcSkipFrame; + agl::utl::Parameter<bool> mDisableConstActor; + agl::utl::Parameter<f32> mDistanceScale; + agl::utl::Parameter<bool> mDisableBehaviorSkip; + agl::utl::Parameter<bool> mDisableCalcRescueDistLimit; +}; +KSYS_CHECK_SIZE_NX150(Lod, 0x3c0); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceModelList.cpp b/src/KingSystem/Resource/Actor/resResourceModelList.cpp new file mode 100644 index 00000000..18b9c0e8 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceModelList.cpp @@ -0,0 +1,364 @@ +#include "KingSystem/Resource/Actor/resResourceModelList.h" +#include <container/seadSafeArray.h> +#include "KingSystem/Resource/resModelResourceDivide.h" + +namespace ksys::res { + +namespace { +sead::SafeString str_ModelData{"ModelData"}; +sead::SafeString str_Unit{"Unit"}; +sead::SafeString str_AnmTarget{"AnmTarget"}; +sead::SafeString str_Partial{"Partial"}; + +sead::SafeArray<const char*, 6> sLocatorTypes{{ + "Trunk", + "Branch", + "GlowStone", + "OnTree", + "MagnePos", + "StopTimerPos", +}}; + +constexpr u32 NumUnitMax = 8; +} // namespace + +ModelList::ModelList() : ParamIO("modellist", 0) {} + +ModelList::~ModelList() { + for (auto& entry : mModelData) + entry.units.freeBuffer(); + mModelData.freeBuffer(); + + for (auto& entry : mAnmTargets) + entry.partials.freeBuffer(); + mAnmTargets.freeBuffer(); +} + +void ModelList::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} + +// NON_MATCHING: reorderings +bool ModelList::parse_(u8* data, size_t size, sead::Heap* heap) { + agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + + const auto model_data_list = agl::utl::getResParameterList(root, str_ModelData); + if (model_data_list.ptr() && model_data_list.getResParameterListNum() > 0) { + if (!parseModelData(model_data_list, heap)) + return false; + } + addList(&mModelDataList, str_ModelData); + + const auto anm_target_list = agl::utl::getResParameterList(root, str_AnmTarget); + if (anm_target_list.ptr() && anm_target_list.getResParameterListNum() > 0) { + if (!parseAnmTarget(anm_target_list, heap)) + return false; + } + addList(&mAnmTargetList, str_AnmTarget); + + mControllerInfo->mAddColor.init({0.0, 0.0, 0.0, 0.0}, "AddColor", "", &mControllerInfo->mObj); + mControllerInfo->mMulColor.init({1.0, 1.0, 1.0, 1.0}, "MulColor", "", &mControllerInfo->mObj); + mControllerInfo->mBaseScale.init(sead::Vector3f::ones, "BaseScale", "", &mControllerInfo->mObj); + mControllerInfo->mVariationMatAnim.init("", "VariationMatAnim", "", &mControllerInfo->mObj); + mControllerInfo->mVariationMatAnimFrame.init(0, "VariationMatAnimFrame", "", + &mControllerInfo->mObj); + mControllerInfo->mVariationShaderAnim.init("", "VariationShaderAnim", "", + &mControllerInfo->mObj); + mControllerInfo->mVariationShaderAnimFrame.init(0, "VariationShaderAnimFrame", "", + &mControllerInfo->mObj); + mControllerInfo->mCalcAABBASKey.init("Wait", "CalcAABBASKey", "", &mControllerInfo->mObj); + addObj(&mControllerInfo->mObj, sead::FormatFixedSafeString<128>("ControllerInfo")); + + mAttention->mIsEnableAttention.init(false, "IsEnableAttention", "", &mAttention->mObj); + mAttention->mLookAtBone.init("", "LookAtBone", "", &mAttention->mObj); + mAttention->mLookAtOffset.init(sead::Vector3f::zero, "LookAtOffset", "", &mAttention->mObj); + mAttention->mCursorOffsetY.init(0.0, "CursorOffsetY", "", &mAttention->mObj); + mAttention->mAIInfoOffsetY.init(0.0, "AIInfoOffsetY", "", &mAttention->mObj); + mAttention->mCutTargetBone.init("", "CutTargetBone", "", &mAttention->mObj); + mAttention->mCutTargetOffset.init(sead::Vector3f::zero, "CutTargetOffset", "", + &mAttention->mObj); + mAttention->mGameCameraBone.init("", "GameCameraBone", "", &mAttention->mObj); + mAttention->mGameCameraOffset.init(sead::Vector3f::zero, "GameCameraOffset", "", + &mAttention->mObj); + mAttention->mBowCameraBone.init("", "BowCameraBone", "", &mAttention->mObj); + mAttention->mBowCameraOffset.init(sead::Vector3f::zero, "BowCameraOffset", "", + &mAttention->mObj); + mAttention->mAttackTargetBone.init("", "AttackTargetBone", "", &mAttention->mObj); + mAttention->mAttackTargetOffset.init(sead::Vector3f::zero, "AttackTargetOffset", "", + &mAttention->mObj); + mAttention->mAttackTargetOffsetBack.init(0.0, "AttackTargetOffsetBack", "", &mAttention->mObj); + mAttention->mAtObstacleChkUseLookAtPos.init(true, "AtObstacleChkUseLookAtPos", "", + &mAttention->mObj); + mAttention->mAtObstacleChkOffsetBone.init("", "AtObstacleChkOffsetBone", "", &mAttention->mObj); + mAttention->mAtObstacleChkOffset.init(sead::Vector3f::zero, "AtObstacleChkOffset", "", + &mAttention->mObj); + mAttention->mCursorAIInfoBaseBone.init("", "CursorAIInfoBaseBone", "", &mAttention->mObj); + mAttention->mCursorAIInfoBaseOffset.init(sead::Vector3f::zero, "CursorAIInfoBaseOffset", "", + &mAttention->mObj); + addObj(&mAttention->mObj, sead::FormatFixedSafeString<128>("Attention")); + + if (data) { + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + mRawData = data; + } + + return true; +} + +bool ModelList::parseModelData(const agl::utl::ResParameterList& res, sead::Heap* heap) { + if (!mModelData.tryAllocBuffer(res.getResParameterListNum() != 0, heap)) + return false; + + sead::FixedSafeString<32> list_name{str_ModelData}; + list_name.append("_"); + const auto list_name_base_len = list_name.calcLength(); + + for (auto it = mModelData.begin(), it_end = mModelData.end(); it != it_end; ++it) { + list_name.trim(list_name_base_len); + list_name.appendWithFormat("%d", it.getIndex()); + + it->folder.init("", "Folder", "", &it->base_obj); + it->list.addObj(&it->base_obj, "Base"); + + const auto unit_list = + agl::utl::getResParameterList(res.getResParameterList(it.getIndex()), str_Unit); + if (unit_list.ptr()) { + const u32 num_units = unit_list.getResParameterObjNum(); + if (num_units != 0) { + if (!it->units.tryAllocBuffer(std::min(num_units, NumUnitMax), heap)) + return false; + + sead::FixedSafeString<32> unit_name{str_Unit}; + unit_name.append("_"); + const auto unit_name_base_len = unit_name.calcLength(); + + for (auto unit = it->units.begin(), end = it->units.end(); unit != end; ++unit) { + unit_name.trim(unit_name_base_len); + unit_name.appendWithFormat("%d", unit.getIndex()); + + unit->unit_name.init("", "UnitName", "", &unit->obj); + unit->bind_bone.init("", "BindBone", "", &unit->obj); + it->unit_list.addObj(&unit->obj, unit_name); + } + } + } + + it->list.addList(&it->unit_list, str_Unit); + mModelDataList.addList(&it->list, list_name); + } + + return true; +} + +bool ModelList::parseAnmTarget(const agl::utl::ResParameterList& res, sead::Heap* heap) { + if (!mAnmTargets.tryAllocBuffer(std::min<u32>(res.getResParameterListNum(), NumUnitMax), heap)) + return false; + + sead::FixedSafeString<32> list_name{str_AnmTarget}; + list_name.append("_"); + const auto list_name_base_len = list_name.calcLength(); + + for (auto it = mAnmTargets.begin(), it_end = mAnmTargets.end(); it != it_end; ++it) { + list_name.trim(list_name_base_len); + list_name.appendWithFormat("%d", it.getIndex()); + + it->num_as_slot.init(0, "NumASSlot", "", &it->base_obj); + // "is particle enabled" (particle is misspelled as "partical" [sic]) + it->is_partical_enable.init(false, "IsParticalEnable", "", &it->base_obj); + it->target_type.init(0, "TargetType", "", &it->base_obj); + it->list.addObj(&it->base_obj, "Base"); + + const auto partials = + agl::utl::getResParameterList(res.getResParameterList(it.getIndex()), str_Partial); + if (partials.ptr() && partials.getResParameterObjNum() != 0) { + if (!it->partials.tryAllocBuffer(partials.getResParameterObjNum(), heap)) + return false; + + sead::FixedSafeString<32> partial_name{str_Partial}; + partial_name.append("_"); + const auto partial_name_base_len = partial_name.calcLength(); + + for (auto partial = it->partials.begin(), partial_end = it->partials.end(); + partial != partial_end; ++partial) { + partial_name.trim(partial_name_base_len); + partial_name.appendWithFormat("%d", partial.getIndex()); + + partial->bone.init("", "Bone", "", &partial->obj); + partial->bind_flag.init(0, "BindFlg", "", &partial->obj); + partial->recursible.init(true, "Recursible", "", &partial->obj); + it->partial_list.addObj(&partial->obj, partial_name); + } + } + + it->list.addList(&it->partial_list, str_Partial); + mAnmTargetList.addList(&it->list, list_name); + } + + return true; +} + +int ModelList::getNumAnmTargets() const { + return mAnmTargets.size(); +} + +void ModelList::getModelDataInfo(ModelList::ModelDataInfo* info) const { + *info = {}; + + if (mModelData.size() > 0) { + info->num_model_data = mModelData.size(); + for (auto it = mModelData.begin(), end = mModelData.end(); it != end; ++it) { + const s32 idx = it.getIndex(); + + info->folder_name[idx] = it->folder.ref().cstr(); + info->num_units[idx] = it->units.size(); + + for (auto unit = it->units.begin(), uend = it->units.end(); unit != uend; ++unit) { + const s32 unit_idx = unit.getIndex(); + info->unit_names[idx][unit_idx] = unit->unit_name.ref().cstr(); + info->unit_bind_bones[idx][unit_idx] = unit->bind_bone.ref().cstr(); + } + + if (info->unit_names[idx][0]) { + const char* name = ModelResourceDivide::instance()->getModelResource( + info->folder_name[idx], info->unit_names[idx][0]); + if (name) + info->folder_name[idx] = name; + } + } + } + + info->base_scale = mControllerInfo->mBaseScale.ref(); +} + +bool ModelList::getAttentionInfo(AttentionInfo* info) const { + if (!mAttention->mIsEnableAttention.ref()) { + info->look_at_bone = {}; + info->look_at_offset = sead::Vector3f::zero; + + info->cursor_offset_y = {}; + info->ai_info_offset_y = {}; + + info->cut_target_bone = {}; + info->cut_target_offset = sead::Vector3f::zero; + + info->game_camera_bone = {}; + info->game_camera_offset = sead::Vector3f::zero; + + info->bow_camera_bone = {}; + info->bow_camera_offset = sead::Vector3f::zero; + + info->attack_target_bone = {}; + info->attack_target_offset = sead::Vector3f::zero; + info->attack_target_offset_back = {}; + + info->cursor_ai_info_base_bone = {}; + info->cursor_ai_info_base_offset = sead::Vector3f::zero; + + return false; + } + + info->look_at_bone = mAttention->mLookAtBone.ref().cstr(); + info->look_at_offset = mAttention->mLookAtOffset.ref(); + + info->cursor_offset_y = mAttention->mCursorOffsetY.ref(); + info->ai_info_offset_y = mAttention->mAIInfoOffsetY.ref(); + + info->cut_target_bone = mAttention->mCutTargetBone.ref().cstr(); + info->cut_target_offset = mAttention->mCutTargetOffset.ref(); + + info->game_camera_bone = mAttention->mGameCameraBone.ref().cstr(); + info->game_camera_offset = mAttention->mGameCameraOffset.ref(); + + info->bow_camera_bone = mAttention->mBowCameraBone.ref().cstr(); + info->bow_camera_offset = mAttention->mBowCameraOffset.ref(); + + info->attack_target_bone = mAttention->mAttackTargetBone.ref().cstr(); + info->attack_target_offset = mAttention->mAttackTargetOffset.ref(); + info->attack_target_offset_back = mAttention->mAttackTargetOffsetBack.ref(); + + if (mAttention->mAtObstacleChkUseLookAtPos.ref()) { + info->at_obstacle_chk_bone = mAttention->mLookAtBone.ref().cstr(); + info->at_obstacle_chk_offset = mAttention->mLookAtOffset.ref(); + } else { + info->at_obstacle_chk_bone = mAttention->mAtObstacleChkOffsetBone.ref().cstr(); + info->at_obstacle_chk_offset = mAttention->mAtObstacleChkOffset.ref(); + } + + info->cursor_ai_info_base_bone = mAttention->mCursorAIInfoBaseBone.ref().cstr(); + info->cursor_ai_info_base_offset = mAttention->mCursorAIInfoBaseOffset.ref(); + + const auto clear_if_empty = [](const char** s) { + if (!(*s)[0]) + *s = nullptr; + }; + + clear_if_empty(&info->look_at_bone); + clear_if_empty(&info->cut_target_bone); + clear_if_empty(&info->game_camera_bone); + clear_if_empty(&info->bow_camera_bone); + clear_if_empty(&info->attack_target_bone); + clear_if_empty(&info->at_obstacle_chk_bone); + clear_if_empty(&info->cursor_ai_info_base_bone); + + return true; +} + +act::InfoData::Locator::Type ModelList::getLocatorTypeFromStr(const sead::SafeString& type) { + for (s32 i = 0; i < sLocatorTypes.size(); ++i) { + if (type == sLocatorTypes[i]) + return act::InfoData::Locator::Type(i); + } + return act::InfoData::Locator::Type::Invalid; +} + +// NON_MATCHING: weird unrolling and Vector3f store (str should be a stp) +bool ModelList::getLocatorInfo(act::InfoData::Locator* info, + act::InfoData::Locator::Type type) const { + agl::utl::ResParameterArchive archive{mRawData}; + const auto root = archive.getRootList(); + + for (int i = 0;; ++i) { + const auto obj = + agl::utl::getResParameterObj(root, sead::FormatFixedSafeString<32>("Locator_%d", i)); + if (!obj.ptr()) + return false; + + const char* expected_type_str = sLocatorTypes[u32(type)]; + + if (sead::SafeString(getString(obj, "Type", "")) != expected_type_str) + continue; + + info->pos = getVec3(obj, "Pos", sead::Vector3f::zero); + info->rot = getVec3(obj, "Rot", sead::Vector3f::zero); + info->type = type; + return true; + } + + return false; +} + +bool ModelList::isParticalEnable(int anm_target_idx) const { + return mAnmTargets[anm_target_idx].is_partical_enable.ref(); +} + +int ModelList::getNumASSlot(int anm_target_idx) const { + return mAnmTargets[anm_target_idx].num_as_slot.ref(); +} + +int ModelList::getNumPartials(int anm_target_idx) const { + return mAnmTargets[anm_target_idx].partials.size(); +} + +void ModelList::getPartialInfo(PartialInfo* info, int anm_target_idx, int partial_idx) const { + if (mAnmTargets.size() > 0) { + const auto& partial = mAnmTargets[anm_target_idx].partials[partial_idx]; + info->bone = partial.bone.ref(); + info->bind_flag = partial.bind_flag.ref(); + info->recursible = partial.recursible.ref(); + } else { + info->bone = ""; + info->bind_flag = 0; + info->recursible = true; + } +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceModelList.h b/src/KingSystem/Resource/Actor/resResourceModelList.h new file mode 100644 index 00000000..1d399f46 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceModelList.h @@ -0,0 +1,169 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include <prim/seadSafeString.h> +#include <prim/seadStorageFor.h> +#include "KingSystem/ActorSystem/actInfoData.h" +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class ModelList : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(ModelList, Resource) +public: + struct ControllerInfo { + agl::utl::Parameter<sead::Color4f> mAddColor; + agl::utl::Parameter<sead::Color4f> mMulColor; + agl::utl::ParameterObj mObj; + agl::utl::Parameter<sead::Vector3f> mBaseScale; + agl::utl::Parameter<sead::SafeString> mVariationMatAnim; + agl::utl::Parameter<s32> mVariationMatAnimFrame; + agl::utl::Parameter<sead::SafeString> mVariationShaderAnim; + agl::utl::Parameter<s32> mVariationShaderAnimFrame; + agl::utl::Parameter<sead::SafeString> mCalcAABBASKey; + }; + KSYS_CHECK_SIZE_NX150(ControllerInfo, 0x160); + + struct Attention { + agl::utl::Parameter<bool> mIsEnableAttention; + agl::utl::Parameter<sead::SafeString> mLookAtBone; + agl::utl::Parameter<sead::Vector3f> mLookAtOffset; + agl::utl::Parameter<f32> mCursorOffsetY; + agl::utl::Parameter<f32> mAIInfoOffsetY; + agl::utl::Parameter<sead::SafeString> mCutTargetBone; + agl::utl::Parameter<sead::Vector3f> mCutTargetOffset; + agl::utl::Parameter<sead::SafeString> mGameCameraBone; + agl::utl::Parameter<sead::Vector3f> mGameCameraOffset; + agl::utl::Parameter<sead::SafeString> mBowCameraBone; + agl::utl::Parameter<sead::Vector3f> mBowCameraOffset; + agl::utl::Parameter<sead::SafeString> mAttackTargetBone; + agl::utl::Parameter<sead::Vector3f> mAttackTargetOffset; + agl::utl::Parameter<f32> mAttackTargetOffsetBack; + agl::utl::Parameter<sead::SafeString> mAtObstacleChkOffsetBone; + agl::utl::Parameter<sead::Vector3f> mAtObstacleChkOffset; + agl::utl::Parameter<bool> mAtObstacleChkUseLookAtPos; + agl::utl::Parameter<sead::SafeString> mCursorAIInfoBaseBone; + agl::utl::Parameter<sead::Vector3f> mCursorAIInfoBaseOffset; + agl::utl::ParameterObj mObj; + }; + KSYS_CHECK_SIZE_NX150(Attention, 0x300); + + struct Unit { + agl::utl::Parameter<sead::SafeString> unit_name; + agl::utl::Parameter<sead::SafeString> bind_bone; + agl::utl::ParameterObj obj; + }; + KSYS_CHECK_SIZE_NX150(Unit, 0x80); + + struct ModelData { + agl::utl::Parameter<sead::SafeString> folder; + agl::utl::ParameterObj base_obj; + sead::Buffer<Unit> units; + agl::utl::ParameterList unit_list; + agl::utl::ParameterList list; + }; + KSYS_CHECK_SIZE_NX150(ModelData, 0xf8); + + // Misspelling of "partical", which is a misspelling of "particle"? + struct Partial { + agl::utl::Parameter<sead::SafeString> bone; + agl::utl::Parameter<s32> bind_flag; + agl::utl::Parameter<bool> recursible; + agl::utl::ParameterObj obj; + }; + KSYS_CHECK_SIZE_NX150(Partial, 0x98); + + struct AnmTarget { + agl::utl::Parameter<s32> num_as_slot; + agl::utl::Parameter<bool> is_partical_enable; + agl::utl::Parameter<s32> target_type; + agl::utl::ParameterObj base_obj; + sead::Buffer<Partial> partials; + agl::utl::ParameterList partial_list; + agl::utl::ParameterList list; + }; + KSYS_CHECK_SIZE_NX150(AnmTarget, 0x130); + + struct ModelDataInfo { + std::array<std::array<const char*, 8>, 1> unit_names; + std::array<std::array<const char*, 8>, 1> unit_bind_bones; + std::array<int, 1> num_units; + std::array<const char*, 1> folder_name; + int num_model_data; + sead::Vector3f base_scale; + }; + KSYS_CHECK_SIZE_NX150(ModelDataInfo, 0xa0); + + struct AttentionInfo { + const char* look_at_bone; + sead::Vector3f look_at_offset; + float cursor_offset_y; + float ai_info_offset_y; + const char* cut_target_bone; + sead::Vector3f cut_target_offset; + const char* game_camera_bone; + sead::Vector3f game_camera_offset; + const char* bow_camera_bone; + sead::Vector3f bow_camera_offset; + const char* attack_target_bone; + sead::Vector3f attack_target_offset; + float attack_target_offset_back; + const char* at_obstacle_chk_bone; + sead::Vector3f at_obstacle_chk_offset; + const char* cursor_ai_info_base_bone; + sead::Vector3f cursor_ai_info_base_offset; + }; + KSYS_CHECK_SIZE_NX150(AttentionInfo, 0xb0); + + struct PartialInfo { + sead::SafeString bone; + int bind_flag; + bool recursible; + }; + KSYS_CHECK_SIZE_NX150(PartialInfo, 0x18); + + ModelList(); + ~ModelList() override; + + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool needsParse() const override { return true; } + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + + const ControllerInfo& getControllerInfo() const { return mControllerInfo.ref(); } + const Attention& getAttention() const { return mAttention.ref(); } + const sead::Buffer<ModelData>& getModelData() const { return mModelData; } + const sead::Buffer<AnmTarget>& getAnmTargets() const { return mAnmTargets; } + + bool isDummy() const { return mIsDummy; } + void markAsDummy() { mIsDummy = true; } + + int getNumAnmTargets() const; + void getModelDataInfo(ModelDataInfo* info) const; + bool getAttentionInfo(AttentionInfo* info) const; + bool getLocatorInfo(act::InfoData::Locator* info, act::InfoData::Locator::Type type) const; + bool isParticalEnable(int anm_target_idx) const; + int getNumASSlot(int anm_target_idx) const; + int getNumPartials(int anm_target_idx) const; + void getPartialInfo(PartialInfo* info, int anm_target_idx, int partial_idx) const; + + static act::InfoData::Locator::Type getLocatorTypeFromStr(const sead::SafeString& type); + +private: + bool parseModelData(const agl::utl::ResParameterList& res, sead::Heap* heap); + bool parseAnmTarget(const agl::utl::ResParameterList& res, sead::Heap* heap); + + sead::StorageFor<ControllerInfo, true> mControllerInfo{sead::ZeroInitializeTag{}}; + sead::StorageFor<Attention, true> mAttention{sead::ZeroInitializeTag{}}; + u8* mRawData{}; + sead::Buffer<ModelData> mModelData; + agl::utl::ParameterList mModelDataList; + sead::Buffer<AnmTarget> mAnmTargets; + agl::utl::ParameterList mAnmTargetList; + bool mIsDummy = false; +}; +KSYS_CHECK_SIZE_NX150(ModelList, 0x7d0); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourcePhysics.cpp b/src/KingSystem/Resource/Actor/resResourcePhysics.cpp new file mode 100644 index 00000000..f9a90eda --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourcePhysics.cpp @@ -0,0 +1,15 @@ +#include "KingSystem/Resource/Actor/resResourcePhysics.h" + +namespace ksys::res { + +void Physics::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} + +bool Physics::parse_(u8* data, size_t size, sead::Heap* heap) { + if (!data) + return true; + + mParamSet.parse(this, agl::utl::ResParameterArchive{data}, heap); + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourcePhysics.h b/src/KingSystem/Resource/Actor/resResourcePhysics.h new file mode 100644 index 00000000..5eef2cfd --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourcePhysics.h @@ -0,0 +1,24 @@ +#pragma once + +#include "KingSystem/Physics/System/physParamSet.h" +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class Physics : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(Physics, Resource) +public: + Physics() : ParamIO("physics", 0) {} + + phys::ParamSet& getParamSet() { return mParamSet; } + + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + bool needsParse() const override { return true; } + +private: + phys::ParamSet mParamSet; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceRagdollBlendWeight.cpp b/src/KingSystem/Resource/Actor/resResourceRagdollBlendWeight.cpp new file mode 100644 index 00000000..07aec2d7 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceRagdollBlendWeight.cpp @@ -0,0 +1,78 @@ +#include "KingSystem/Resource/Actor/resResourceRagdollBlendWeight.h" + +namespace ksys::res { + +void RagdollBlendWeight::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} + +bool RagdollBlendWeight::parse_(u8* data, size_t size, sead::Heap* heap) { + if (!data) + return false; + + using FormatString = sead::FormatFixedSafeString<32>; + + agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + const auto num_states = root.getResParameterListNum(); + + if (num_states != 0) { + mStates.allocBufferAssert(num_states, heap); + + int state_idx = 1; + for (auto it = mStates.begin(), end = mStates.end(); it != end; ++it) { + const auto State = + agl::utl::getResParameterList(root, FormatString("%s%d", "State_", state_idx)); + + if (State) { + it->state_key.init("", "StateKey", "ステートキー", "", &it->setting_obj); + it->system_key.init("", "SystemKey", "システムキー", "", &it->setting_obj); + + const auto InputWeightList = + agl::utl::getResParameterList(State, "InputWeightList"); + + if (int num_weights; InputWeightList && + (num_weights = InputWeightList.getResParameterObjNum()) != 0) { + it->input_weights.allocBufferAssert(num_weights, heap); + + int weight_idx = 1; + for (auto wit = it->input_weights.begin(), wend = it->input_weights.end(); + wit != wend; ++wit) { + wit->rigid_name.init("", "RigidName", "ボーン名", "", &wit->obj); + wit->blend_rate.init(1.0, "BlendRate", "ブレンド率", "", &wit->obj); + + it->input_weight_list.addObj( + &wit->obj, FormatString("%s%d", "InputWeight_", weight_idx)); + ++weight_idx; + } + } + } + + it->list.addObj(&it->setting_obj, FormatString("Setting")); + it->list.addList(&it->input_weight_list, FormatString("InputWeightList")); + + addList(&it->list, FormatString("%s%d", "State_", state_idx)); + ++state_idx; + } + } + + applyResParameterArchive(archive); + return true; +} + +const sead::SafeString& RagdollBlendWeight::getWeightRigidName(int state_idx, + int weight_idx) const { + return mStates[state_idx].input_weights[weight_idx].rigid_name.ref(); +} + +float RagdollBlendWeight::getWeightBlendRate(int state_idx, int weight_idx) const { + return mStates[state_idx].input_weights[weight_idx].blend_rate.ref(); +} + +int RagdollBlendWeight::findStateIdx(const sead::SafeString& key) const { + for (int i = 0; i < mStates.size(); ++i) { + if (mStates[i].state_key.ref() == key) + return i; + } + return -1; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceRagdollBlendWeight.h b/src/KingSystem/Resource/Actor/resResourceRagdollBlendWeight.h new file mode 100644 index 00000000..257c3184 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceRagdollBlendWeight.h @@ -0,0 +1,48 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class RagdollBlendWeight : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(RagdollBlendWeight, Resource) +public: + struct InputWeight { + agl::utl::Parameter<sead::SafeString> rigid_name; + agl::utl::Parameter<float> blend_rate; + agl::utl::ParameterObj obj; + }; + + struct State { + agl::utl::ParameterList list; + agl::utl::Parameter<sead::SafeString> state_key; + agl::utl::Parameter<sead::SafeString> system_key; + agl::utl::ParameterObj setting_obj; + agl::utl::ParameterList input_weight_list; + sead::Buffer<InputWeight> input_weights; + }; + + RagdollBlendWeight() : ParamIO("rgbw", 0) {} + ~RagdollBlendWeight() override { mStates.freeBuffer(); } + + const sead::Buffer<State>& getStates() const { return mStates; } + + const sead::SafeString& getWeightRigidName(int state_idx, int weight_idx) const; + float getWeightBlendRate(int state_idx, int weight_idx) const; + int findStateIdx(const sead::SafeString& key) const; + + bool ParamIO_m0(char* data) override { return true; } + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool needsParse() const override { return true; } + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + +private: + sead::Buffer<State> mStates; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceRagdollConfig.cpp b/src/KingSystem/Resource/Actor/resResourceRagdollConfig.cpp new file mode 100644 index 00000000..dfadf9fd --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceRagdollConfig.cpp @@ -0,0 +1,30 @@ +#include "KingSystem/Resource/Actor/resResourceRagdollConfig.h" + +namespace ksys::res { + +const int RagdollConfig::cNumReceiveObjs = 3; +const int RagdollConfig::cNumImpulseObjs = 5; +const int RagdollConfig::cNumImpulseParams = 10; +const std::array<char, 64> RagdollConfig::cImpulseParamNames[10] = { + {"Default"}, {"Sword"}, {"LargeSword"}, {"Spear"}, {"Arrow"}, + {"Bomb"}, {"HeadShot"}, {"ShockWave"}, {"SilentKill"}, {"Gust"}, +}; + +RagdollConfig::RagdollConfig() : ParamIO("rgconfig", 0) {} + +RagdollConfig::~RagdollConfig() = default; + +void RagdollConfig::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} + +bool RagdollConfig::parse_(u8* data, size_t size, sead::Heap* heap) { + if (!data) + return false; + + addList(&mConfig, "ConfigRoot"); + + agl::utl::ResParameterArchive archive{data}; + applyResParameterArchive(archive); + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceRagdollConfig.h b/src/KingSystem/Resource/Actor/resResourceRagdollConfig.h new file mode 100644 index 00000000..46e71cf4 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceRagdollConfig.h @@ -0,0 +1,32 @@ +#pragma once + +#include <array> + +#include "KingSystem/Physics/Ragdoll/physRagdollConfig.h" +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class RagdollConfig : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(RagdollConfig, Resource) +public: + RagdollConfig(); + ~RagdollConfig() override; + + void doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) override; + bool needsParse() const override { return true; } + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + + const phys::RagdollConfig& getConfig() const { return mConfig; } + + static const int cNumReceiveObjs; + static const int cNumImpulseObjs; + static const int cNumImpulseParams; + static const std::array<char, 64> cImpulseParamNames[10]; + +private: + phys::RagdollConfig mConfig; +}; + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceRagdollConfigList.cpp b/src/KingSystem/Resource/Actor/resResourceRagdollConfigList.cpp new file mode 100644 index 00000000..cf230021 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceRagdollConfigList.cpp @@ -0,0 +1,80 @@ +#include "KingSystem/Resource/Actor/resResourceRagdollConfigList.h" +#include "KingSystem/Resource/Actor/resResourceRagdollConfig.h" + +namespace ksys::res { + +RagdollConfigList::RagdollConfigList() + : ParamIO("rgconfiglist", 0), + mUpperLimitHeight(0.0, "UpperLimitHight" /*sic*/, "ヒット位置判定の境界(上)", &mCommonData), + mLowerLimitHeight(0.0, "LowerLimitHight" /*sic*/, "ヒット位置判定の境界(下)", + &mCommonData) {} + +RagdollConfigList::~RagdollConfigList() { + mImpulseParams.freeBuffer(); + mBodyParams.freeBuffer(); +} + +void RagdollConfigList::doCreate_(u8*, u32, sead::Heap*) {} + +bool RagdollConfigList::parse_(u8* data, size_t size, sead::Heap* heap) { + if (!data) + return false; + + if (RagdollConfig::cNumImpulseParams > 0) { + mImpulseParams.allocBufferAssert(RagdollConfig::cNumImpulseParams, heap); + if (!mImpulseParams.isBufferReady()) + return false; + +#ifdef MATCHING_HACK_NX_CLANG + __builtin_assume(RagdollConfig::cNumImpulseParams != 0); +#endif + + for (int i = 0; i != RagdollConfig::cNumImpulseParams; ++i) { + mImpulseParams[i].config = nullptr; + mImpulseParams[i].file_name.init("", "FileName", "データファイル名", "", + &mImpulseParams[i].obj); + mImpulseParamList.addObj( + &mImpulseParams[i].obj, + sead::FormatFixedSafeString<32>("%s%s", "ImpulseParam_", + RagdollConfig::cImpulseParamNames[i].data())); + } + } + addList(&mImpulseParamList, "ImpulseParamList"); + + addObj(&mCommonData, "CommonData"); + + agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + const auto BodyParamList = agl::utl::getResParameterList(root, "BodyParamList"); + if (int num_params; + BodyParamList && (num_params = BodyParamList.getResParameterObjNum()) != 0) { + mBodyParams.allocBufferAssert(num_params, heap); + for (int i = 0; i < num_params; ++i) { + mBodyParams[i].rigid_name.init(sead::SafeString::cEmptyString, "RigidName", "RigidName", + "RigidName", &mBodyParams[i]); + mBodyParams[i].friction_scale.init(1.0, "FrictionScale", "FrictionScale", + "FrictionScale", &mBodyParams[i]); + mBodyParams[i].buoyancy_scale.init(1.0, "BuoyancyScale", "BuoyancyScale", + "BuoyancyScale", &mBodyParams[i]); + mBodyParamList.addObj(&mBodyParams[i], + sead::FormatFixedSafeString<32>("BodyParam_%d", i)); + } + } + addList(&mBodyParamList, "BodyParamList"); + + applyResParameterArchive(archive); + return true; +} + +bool RagdollConfigList::finishParsing_() { + return true; +} + +bool RagdollConfigList::m7_() { + for (auto& param : mImpulseParams) + param.config = nullptr; + + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceRagdollConfigList.h b/src/KingSystem/Resource/Actor/resResourceRagdollConfigList.h new file mode 100644 index 00000000..9b207189 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceRagdollConfigList.h @@ -0,0 +1,67 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterList.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class RagdollConfig; + +class RagdollConfigList : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(RagdollConfigList, Resource) +public: + struct ImpulseParam { + const char* getFileName() const { return file_name.ref().cstr(); } + + agl::utl::Parameter<sead::SafeString> file_name; + agl::utl::ParameterObj obj; + RagdollConfig* config; + }; + KSYS_CHECK_SIZE_NX150(ImpulseParam, 0x60); + + struct BodyParam : agl::utl::ParameterObj { + agl::utl::Parameter<sead::SafeString> rigid_name; + agl::utl::Parameter<f32> friction_scale; + agl::utl::Parameter<f32> buoyancy_scale; + }; + KSYS_CHECK_SIZE_NX150(BodyParam, 0x98); + + RagdollConfigList(); + ~RagdollConfigList() override; + RagdollConfigList(const RagdollConfigList&) = delete; + auto operator=(const RagdollConfigList&) = delete; + + void doCreate_(u8*, u32, sead::Heap*) override; + bool needsParse() const override { return true; } + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + bool finishParsing_() override; + bool m7_() override; + + const sead::Buffer<ImpulseParam>& getImpulseParams() const { return mImpulseParams; } + f32 getUpperLimitHeight() const { return mUpperLimitHeight.ref(); } + f32 getLowerLimitHeight() const { return mLowerLimitHeight.ref(); } + const sead::Buffer<BodyParam>& getBodyParams() const { return mBodyParams; } + + void addImpulseParamConfig_(s32 index, RagdollConfig* config) { + mImpulseParams[index].config = config; + } + +private: + agl::utl::ParameterList mImpulseParamList; + sead::Buffer<ImpulseParam> mImpulseParams; + + agl::utl::ParameterObj mCommonData; + agl::utl::Parameter<f32> mUpperLimitHeight; + agl::utl::Parameter<f32> mLowerLimitHeight; + + agl::utl::ParameterList mBodyParamList; + sead::Buffer<BodyParam> mBodyParams; +}; +KSYS_CHECK_SIZE_NX150(RagdollConfigList, 0x3d0); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceRecipe.cpp b/src/KingSystem/Resource/Actor/resResourceRecipe.cpp new file mode 100644 index 00000000..c2921e62 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceRecipe.cpp @@ -0,0 +1,67 @@ +#include "KingSystem/Resource/Actor/resResourceRecipe.h" + +namespace ksys::res { + +// NON_MATCHING: first line (see also Drop::parse_) +bool Recipe::parse_(u8* data, size_t, sead::Heap* heap) { + mTableNum.init(0, "TableNum", "テーブルの数", &mObj); + addObj(&mObj, "Header"); + + if (!data) + return true; + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + + const s32 num_tables = mTableNum.ref(); + if (num_tables < 1) + return true; + + mTables.allocBufferAssert(num_tables, heap); + + const agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + const auto header_obj = root.getResParameterObj(0); + + for (s32 i = 0; i < num_tables; ++i) { + sead::FormatFixedSafeString<64> name; + name.format("Table%02d", i + 1); + mTables[i].name.init("", name, "テーブル名", &mObj); + } + + mObj.applyResParameterObj(header_obj); + + for (s32 i = 0; i < num_tables; ++i) { + const auto obj = root.getResParameterObj(i + 1); + mTables[i].column_num.init(0, "ColumnNum", "行数", &mTables[i].obj); + + addObj(&mTables[i].obj, mTables[i].name.ref()); + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + mTables[i].obj.applyResParameterObj(obj); + + if (mTables[i].column_num.ref() > 0) { + mTables[i].items.allocBufferAssert(mTables[i].column_num.ref(), heap); + } + } + + for (s32 i = 0; i < num_tables; ++i) { + parseTable_(i); + } + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + return true; +} + +void Recipe::parseTable_(const s32& table_idx) { + const s32 num = mTables[table_idx].column_num.ref(); + for (s32 i = 0; i < num; ++i) { + sead::FormatFixedSafeString<64> name; + name.format("ItemName%02d", i + 1); + mTables[table_idx].items[i].name.init("", name, "アイテム名", &mTables[table_idx].obj); + + sead::FormatFixedSafeString<64> name2; + name2.format("ItemNum%02d", i + 1); + mTables[table_idx].items[i].num.init(0, name2, "個数", &mTables[table_idx].obj); + } +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceRecipe.h b/src/KingSystem/Resource/Actor/resResourceRecipe.h new file mode 100644 index 00000000..0429451b --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceRecipe.h @@ -0,0 +1,48 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class Recipe : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(Recipe, Resource) +public: + struct Item { + agl::utl::Parameter<sead::SafeString> name; + agl::utl::Parameter<s32> num; + }; + KSYS_CHECK_SIZE_NX150(Item, 0x48); + + struct Table { + agl::utl::ParameterObj obj; + agl::utl::Parameter<sead::SafeString> name; + agl::utl::Parameter<s32> column_num; + sead::Buffer<Item> items; + }; + KSYS_CHECK_SIZE_NX150(Table, 0x88); + + Recipe() : ParamIO("recipe", 0) {} + + bool ParamIO_m0(char* data) override { return true; } + void doCreate_(u8*, u32, sead::Heap*) override {} + bool needsParse() const override { return true; } + + const sead::Buffer<Table>& getTables() const { return mTables; } + +private: + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + void parseTable_(const s32& table_idx); + + agl::utl::ParameterObj mObj; + agl::utl::Parameter<s32> mTableNum; + sead::Buffer<void*> _300; + sead::Buffer<Table> mTables; +}; +KSYS_CHECK_SIZE_NX150(Recipe, 0x320); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceShop.cpp b/src/KingSystem/Resource/Actor/resResourceShop.cpp new file mode 100644 index 00000000..1d6e9974 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceShop.cpp @@ -0,0 +1,115 @@ +#include "KingSystem/Resource/Actor/resResourceShop.h" + +namespace ksys::res { + +bool Shop::parse_(u8* data, size_t, sead::Heap* heap) { + mTableNum.init(0, "TableNum", "テーブルの数", &mObj); + addObj(&mObj, "Header"); + + if (!data) + return true; + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + + const s32 num_tables = mTableNum.ref(); + if (num_tables < 1) + return true; + + mTables.allocBufferAssert(num_tables, heap); + + const agl::utl::ResParameterArchive archive{data}; + const auto root = archive.getRootList(); + const auto header_obj = root.getResParameterObj(0); + + for (s32 i = 0; i < num_tables; ++i) { + sead::FormatFixedSafeString<64> name; + name.format("Table%02d", i + 1); + mTables[i].name.init("", name, "テーブル名", &mObj); + } + + mObj.applyResParameterObj(header_obj); + + for (s32 i = 0; i < num_tables; ++i) { + const auto obj = root.getResParameterObj(i + 1); + mTables[i].column_num.init(0, "ColumnNum", "行数", &mTables[i].obj); + + addObj(&mTables[i].obj, mTables[i].name.ref()); + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + mTables[i].obj.applyResParameterObj(obj); + + if (mTables[i].column_num.ref() > 0) { + mTables[i].items.allocBufferAssert(mTables[i].column_num.ref(), heap); + } + } + + for (s32 i = 0; i < num_tables; ++i) { + parseTable_(i); + } + + applyResParameterArchive(agl::utl::ResParameterArchive{data}); + + return true; +} + +void Shop::parseTable_(const s32& table_idx) { + const s32 num = mTables[table_idx].column_num.ref(); + for (s32 i = 0; i < num; ++i) { + sead::FormatFixedSafeString<64> name; + name.format("ItemSort%03d", i + 1); + mTables[table_idx].items[i].sort_value.init(0, name, "ソート値", &mTables[table_idx].obj); + + sead::FormatFixedSafeString<64> name2; + name2.format("ItemName%03d", i + 1); + mTables[table_idx].items[i].name.init("", name2, "アイテム名", &mTables[table_idx].obj); + + sead::FormatFixedSafeString<64> name3; + name3.format("ItemNum%03d", i + 1); + mTables[table_idx].items[i].num_stock.init(0, name3, "販売個数", &mTables[table_idx].obj); + + sead::FormatFixedSafeString<64> name4; + name4.format("ItemAdjustPrice%03d", i + 1); + mTables[table_idx].items[i].price_adjustment.init(0, name4, "値段調整値", + &mTables[table_idx].obj); + + sead::FormatFixedSafeString<64> name5; + name5.format("ItemLookGetFlg%03d", i + 1); + mTables[table_idx].items[i].demo_flag.init(false, name5, "ゲットフラグを見るか", + &mTables[table_idx].obj); + + sead::FormatFixedSafeString<64> name6; + name6.format("ItemAmount%03d", i + 1); + mTables[table_idx].items[i].price.init(0, name6, "価値", &mTables[table_idx].obj); + } +} + +s32 Shop::findTableIndex(const sead::SafeString& table_name) const { + if (!mTables.isBufferReady()) + return -1; + + const s32 num = mTableNum.ref(); + for (s32 i = 0; i < num; ++i) { + if (mTables[i].name.ref() == table_name) + return i; + } + + return -1; +} + +s32 Shop::findTableIndexOrNormal(const sead::SafeString& table_name) const { + if (!mTables.isBufferReady()) + return -1; + + s32 normal_idx = -1; + const s32 num = mTableNum.ref(); + for (s32 i = 0; i < num; ++i) { + if (mTables[i].name.ref() == table_name) + return i; + + if (normal_idx < 0 && mTables[i].name.ref() == "Normal") + normal_idx = i; + } + + return normal_idx; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceShop.h b/src/KingSystem/Resource/Actor/resResourceShop.h new file mode 100644 index 00000000..14c383e1 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceShop.h @@ -0,0 +1,55 @@ +#pragma once + +#include <agl/Utils/aglParameter.h> +#include <agl/Utils/aglParameterObj.h> +#include <container/seadBuffer.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" + +namespace ksys::res { + +class Shop : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(Shop, Resource) + +public: + struct Item { + agl::utl::Parameter<s32> sort_value; + agl::utl::Parameter<sead::SafeString> name; + agl::utl::Parameter<s32> num_stock; + agl::utl::Parameter<s32> price_adjustment; + agl::utl::Parameter<bool> demo_flag; + agl::utl::Parameter<s32> price; + }; + KSYS_CHECK_SIZE_NX150(Item, 0xC8); + + struct Table { + agl::utl::ParameterObj obj; + agl::utl::Parameter<sead::SafeString> name; + agl::utl::Parameter<s32> column_num; + sead::Buffer<Item> items; + }; + KSYS_CHECK_SIZE_NX150(Table, 0x88); + + Shop() : ParamIO("shop", 0) {} + + s32 findTableIndexOrNormal(const sead::SafeString& table_name) const; + s32 findTableIndex(const sead::SafeString& table_name) const; + + bool ParamIO_m0(char* data) override { return true; } + void doCreate_(u8*, u32, sead::Heap*) override {} + bool needsParse() const override { return true; } + + const sead::Buffer<Table>& getTables() const { return mTables; } + +private: + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + void parseTable_(const s32& table_idx); + + agl::utl::ParameterObj mObj; + agl::utl::Parameter<s32> mTableNum; + sead::Buffer<void*> _300; + sead::Buffer<Table> mTables; +}; +KSYS_CHECK_SIZE_NX150(Shop, 0x320); + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceUMii.cpp b/src/KingSystem/Resource/Actor/resResourceUMii.cpp new file mode 100644 index 00000000..2f432137 --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceUMii.cpp @@ -0,0 +1,15 @@ +#include "KingSystem/Resource/Actor/resResourceUMii.h" + +namespace ksys::res { + +UMii::UMii() : ParamIO("umii", 0) {} + +UMii::~UMii() = default; + +bool UMii::parse_(u8* data, size_t, sead::Heap*) { + agl::utl::ResParameterArchive archive{data + mAllocSize}; + mArchive = archive; + return true; +} + +} // namespace ksys::res diff --git a/src/KingSystem/Resource/Actor/resResourceUMii.h b/src/KingSystem/Resource/Actor/resResourceUMii.h new file mode 100644 index 00000000..ed4f8d0d --- /dev/null +++ b/src/KingSystem/Resource/Actor/resResourceUMii.h @@ -0,0 +1,28 @@ +#pragma once + +#include <agl/Utils/aglResParameter.h> +#include "KingSystem/Resource/resResource.h" +#include "KingSystem/Utils/ParamIO.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::res { + +class UMii : public ParamIO, public Resource { + SEAD_RTTI_OVERRIDE(UMii, Resource) +public: + UMii(); + ~UMii() override; + + agl::utl::ResParameterArchive getArchive() const { return mArchive; } + + bool needsParse() const override { return true; } + bool m2_() override { return mArchive.isValid(); } + void doCreate_(u8*, u32, sead::Heap*) override {} + bool parse_(u8* data, size_t size, sead::Heap* heap) override; + +private: + agl::utl::ResParameterArchive mArchive{}; +}; +KSYS_CHECK_SIZE_NX150(UMii, 0x2b8); + +} // namespace ksys::res |
