diff options
| author | notyourav <65437533+notyourav@users.noreply.github.com> | 2020-11-16 15:49:02 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-16 15:49:02 -0800 |
| commit | d4f80d7cf97641742dd56cabc0b1d503cfdf7b0d (patch) | |
| tree | 05b09142b74869f74779a00deff410019b8dcaac /src/KingSystem/ActorSystem | |
| parent | 8205744abcae5784138629038976f2449269a81f (diff) | |
| parent | b0498a15bf6f1782f1429ffbd0b03c187f61d7c9 (diff) | |
Merge branch 'master' into placement
Diffstat (limited to 'src/KingSystem/ActorSystem')
| -rw-r--r-- | src/KingSystem/ActorSystem/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/KingSystem/ActorSystem/actActorParam.cpp | 8 | ||||
| -rw-r--r-- | src/KingSystem/ActorSystem/actActorParam.h | 22 | ||||
| -rw-r--r-- | src/KingSystem/ActorSystem/actActorParamMgr.cpp | 754 | ||||
| -rw-r--r-- | src/KingSystem/ActorSystem/actActorParamMgr.h | 54 | ||||
| -rw-r--r-- | src/KingSystem/ActorSystem/actActorTemplate.cpp | 2 | ||||
| -rw-r--r-- | src/KingSystem/ActorSystem/actAttention.cpp | 9 | ||||
| -rw-r--r-- | src/KingSystem/ActorSystem/actAttention.h | 70 | ||||
| -rw-r--r-- | src/KingSystem/ActorSystem/actInfoData.cpp | 296 | ||||
| -rw-r--r-- | src/KingSystem/ActorSystem/actInfoData.h | 135 |
10 files changed, 1314 insertions, 41 deletions
diff --git a/src/KingSystem/ActorSystem/CMakeLists.txt b/src/KingSystem/ActorSystem/CMakeLists.txt index d80bb38d..05aff8cd 100644 --- a/src/KingSystem/ActorSystem/CMakeLists.txt +++ b/src/KingSystem/ActorSystem/CMakeLists.txt @@ -22,6 +22,8 @@ target_sources(uking PRIVATE actAiClass.h actAiParam.cpp actAiParam.h + actAttention.cpp + actAttention.h actBaseProc.cpp actBaseProc.h actBaseProcHandle.cpp @@ -40,7 +42,10 @@ target_sources(uking PRIVATE actBaseProcUnit.h actDebug.cpp actDebug.h + actInfoData.cpp + actInfoData.h actInstParamPack.cpp actInstParamPack.h + actLifeRecoveryInfo.h actTag.h ) diff --git a/src/KingSystem/ActorSystem/actActorParam.cpp b/src/KingSystem/ActorSystem/actActorParam.cpp index b358375a..dbe2096e 100644 --- a/src/KingSystem/ActorSystem/actActorParam.cpp +++ b/src/KingSystem/ActorSystem/actActorParam.cpp @@ -3,7 +3,7 @@ #include <prim/seadScopedLock.h> #include "KingSystem/ActorSystem/actActorParamMgr.h" #include "KingSystem/ActorSystem/actActorTemplate.h" -#include "KingSystem/Utils/Byaml.h" +#include "KingSystem/Utils/Byaml/Byaml.h" namespace ksys::act { @@ -49,8 +49,8 @@ void ActorParam::deleteResHandles() { handles.freeBuffer(); } -bool ActorParam::isDummyParam(res::ActorLink::Users::User user) const { - return mRes.mActorLink->getUsers().getUserName(user) == "Dummy"; +bool ActorParam::isDummyParam(res::ActorLink::User user) const { + return sead::SafeString(mRes.mActorLink->getUserName(user)) == "Dummy"; } void ActorParam::allocResHandles(sead::Heap* heap, u32 buffer_idx, s32 count) { @@ -154,4 +154,6 @@ void ActorParam::setProfileAndPriority(const char* profile, const char* priority } } +void ActorParam::onLoadFinished(ActorParamMgr*) {} + } // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actActorParam.h b/src/KingSystem/ActorSystem/actActorParam.h index 88f563ec..1186e244 100644 --- a/src/KingSystem/ActorSystem/actActorParam.h +++ b/src/KingSystem/ActorSystem/actActorParam.h @@ -40,6 +40,8 @@ class UMii; namespace act { +class ActorParamMgr; + // FIXME: incomplete class ActorParam : public sead::hostio::Node { public: @@ -69,7 +71,15 @@ public: LifeCondition = 22, UMii = 23, AnimationInfo = 24, + AS = 25, + AttClient = 26, + RagdollConfig = 27, }; + static constexpr s32 NumResourceTypes = 28; + + static constexpr bool isValidType(ResourceType type) { + return type <= ResourceType::AnimationInfo; + } union Resources { struct { @@ -112,7 +122,7 @@ public: Priority getPriority() const { return mPriority; } const Resources& getRes() const { return mRes; } - bool isDummyParam(res::ActorLink::Users::User user) const; + bool isDummyParam(res::ActorLink::User user) const; static void resetDummyResources(); @@ -141,7 +151,15 @@ private: bool setPriority(const sead::SafeString& priority); void setProfileAndPriority(const char* profile, const char* priority); - u16 _8 = 0; + void setResourceIfValidType(ResourceType type, ParamIO* param_io) { + if (isValidType(type)) + setResource(type, param_io); + } + + void onLoadFinished(ActorParamMgr* mgr); + + u8 _8 = 0; + u8 _9 = 0; u8 _a = 0; sead::FixedSafeString<64> mActorName; sead::SafeString mProfile; diff --git a/src/KingSystem/ActorSystem/actActorParamMgr.cpp b/src/KingSystem/ActorSystem/actActorParamMgr.cpp index 82fa697e..e75eb43f 100644 --- a/src/KingSystem/ActorSystem/actActorParamMgr.cpp +++ b/src/KingSystem/ActorSystem/actActorParamMgr.cpp @@ -3,18 +3,75 @@ #include "KingSystem/ActorSystem/actASSetting.h" #include "KingSystem/ActorSystem/actActorParam.h" #include "KingSystem/Resource/resLoadRequest.h" +#include "KingSystem/Resource/resResourceAIProgram.h" +#include "KingSystem/Resource/resResourceAISchedule.h" +#include "KingSystem/Resource/resResourceAS.h" +#include "KingSystem/Resource/resResourceASList.h" +#include "KingSystem/Resource/resResourceActorLink.h" +#include "KingSystem/Resource/resResourceAnimInfo.h" +#include "KingSystem/Resource/resResourceArchive.h" +#include "KingSystem/Resource/resResourceAttClient.h" +#include "KingSystem/Resource/resResourceAttClientList.h" +#include "KingSystem/Resource/resResourceAwareness.h" +#include "KingSystem/Resource/resResourceBoneControl.h" +#include "KingSystem/Resource/resResourceChemical.h" +#include "KingSystem/Resource/resResourceDamageParam.h" +#include "KingSystem/Resource/resResourceDrop.h" #include "KingSystem/Resource/resResourceGParamList.h" +#include "KingSystem/Resource/resResourceLifeCondition.h" +#include "KingSystem/Resource/resResourceLod.h" +#include "KingSystem/Resource/resResourceMgrTask.h" +#include "KingSystem/Resource/resResourceModelList.h" +#include "KingSystem/Resource/resResourcePhysics.h" +#include "KingSystem/Resource/resResourceRagdollBlendWeight.h" +#include "KingSystem/Resource/resResourceRagdollConfig.h" +#include "KingSystem/Resource/resResourceRagdollConfigList.h" +#include "KingSystem/Resource/resResourceRecipe.h" +#include "KingSystem/Resource/resResourceShop.h" +#include "KingSystem/Resource/resResourceUMii.h" +#include "KingSystem/Resource/resSystem.h" +#include "KingSystem/Resource/resTempResourceLoader.h" +#include "KingSystem/Utils/Debug.h" +#include "KingSystem/Utils/ParamIO.h" namespace ksys::act { SEAD_SINGLETON_DISPOSER_IMPL(ActorParamMgr) +using Type = ActorParam::ResourceType; +using User = res::ActorLink::User; + ActorParamMgr::ActorParamMgr() = default; ActorParamMgr::~ActorParamMgr() { ASSetting::deleteInstance(); } +bool ActorParamMgr::checkPath(const sead::SafeString& path) const { + return res::returnFalse3(path); +} + +ActorParam* ActorParamMgr::allocParam(const char* actor_name, bool* allocated_new) { + auto lock = sead::makeScopedLock(mCS); + + ActorParam* free_param = nullptr; + auto* param = getParam(actor_name, &free_param); + + if (!param) { + param = free_param; + if (free_param) + free_param->mRes = {}; + else + param = &mParams[NumParams - 1]; + + param->mActorName = actor_name; + *allocated_new = true; + } + + param->incrementRef(); + return param; +} + // NON_MATCHING: addressing mode ActorParam* ActorParamMgr::getParam(const char* actor_name, ActorParam** out_free_param) const { auto lock = sead::makeScopedLock(mCS); @@ -30,33 +87,13 @@ ActorParam* ActorParamMgr::getParam(const char* actor_name, ActorParam** out_fre return nullptr; } -ActorParam* ActorParamMgr::loadParam(const char* actor_name, res::Handle* handle, void* x, +ActorParam* ActorParamMgr::loadParam(const char* actor_name, res::Handle* pack_handle, void* x, u32 load_req_c) { - ActorParam* param; - bool existing = false; - - { - auto lock = sead::makeScopedLock(mCS); - - ActorParam* free_param = nullptr; - param = getParam(actor_name, &free_param); + bool allocated_new = false; + ActorParam* param = allocParam(actor_name, &allocated_new); - if (param) { - existing = true; - } else { - param = free_param; - if (free_param) - free_param->mRes = {}; - else - param = &mParams[NumParams - 1]; - - param->mActorName = actor_name; - } - param->incrementRef(); - } - - if (!existing) { - loadFiles(param, mTmpActorParamMgrHeap, handle, x, load_req_c); + if (allocated_new) { + loadFiles(param, mTmpActorParamMgrHeap, pack_handle, x, load_req_c); param->setEventSignal(); } else { param->waitForEvent(); @@ -65,8 +102,40 @@ ActorParam* ActorParamMgr::loadParam(const char* actor_name, res::Handle* handle return param; } -bool ActorParamMgr::loadActorPack(res::Handle* handle, const sead::SafeString& actor_name, - u32 load_req_c) { +void ActorParamMgr::loadFiles(ActorParam* param, sead::Heap* heap, res::Handle* pack_handle, + void* x, u32 load_req_c) { + param->deleteResHandles(); + param->allocResHandles(heap, 0, ActorParam::NumResourceTypes + 1); + param->mActiveBufferIdx = 0; + + const auto* link = + loadFile<res::ActorLink>(param, Type::ActorLink, "Actor/ActorLink", "xml", + param->getActorName().cstr(), pack_handle, x, load_req_c); + + if (link) + param->setProfileAndPriority(link->getUserName(User::Profile), link->getPriority().cstr()); + + const auto* actor_link = param->getRes().mActorLink; + if (!actor_link) + return; + + param->mActiveBufferIdx = 0; + + loadFile<res::ModelList>(param, Type::ModelList, "Actor/ModelList", "modellist", + actor_link->getUserName(User::Model), pack_handle, x, load_req_c); + + loadFile<res::UMii>(param, Type::UMii, "Actor/UMii", "umii", + actor_link->getUserName(User::UMii), pack_handle, x, load_req_c); + + loadFile<res::ASList>(param, Type::ASList, "Actor/ASList", "aslist", + actor_link->getUserName(res::ActorLink::User::AS), pack_handle, x, + load_req_c); + + loadFilesStep2(param, heap, pack_handle, x, load_req_c); +} + +bool ActorParamMgr::requestLoadActorPack(res::Handle* handle, const sead::SafeString& actor_name, + u32 load_req_c) { sead::FixedSafeString<128> path; res::LoadRequest req; @@ -81,9 +150,638 @@ bool ActorParamMgr::loadActorPack(res::Handle* handle, const sead::SafeString& a return handle->requestLoad(path, &req); } +ActorParam* ActorParamMgr::loadParamAsync(const char* actor_name, res::Handle* pack_handle, + bool* allocated_new, void* x, u32 load_req_c) { + auto* param = allocParam(actor_name, allocated_new); + if (!*allocated_new) + return param; + + param->deleteResHandles(); + param->allocResHandles(mTmpActorParamMgrHeap, 0, ActorParam::NumResourceTypes + 1); + param->mActiveBufferIdx = 0; + + loadFileAsync<res::ActorLink>(param, Type::ActorLink, "Actor/ActorLink", "xml", + param->getActorName().cstr(), pack_handle, x, load_req_c); + return param; +} + +template <typename T> +bool ActorParamMgr::loadFileAsync(ActorParam* param, ActorParam::ResourceType type, + const sead::SafeString& dir_name, + const sead::SafeString& extension, const sead::SafeString& name, + res::Handle* pack_handle, void* x, u32 load_req_c) { + auto* handle = param->allocHandle(); + + if (name != "Dummy" && !name.isEmpty()) { + sead::FixedSafeString<128> path; + res::LoadRequest req; + prepareLoadFromActorPack(&path, &req, x, dir_name, extension, name, pack_handle, load_req_c, + param->getActorName()); + return handle->requestLoad(path, &req); + } + + if (ActorParam::isValidType(type)) { + auto* res = sead::DynamicCast<T>(mDummyResources[u32(type)].getResource()); + param->setResource(type, res); + } + + return true; +} + +// NON_MATCHING: different address calculation for static_cast<ParamIO*>(res)->getPath() +template <typename T> +T* ActorParamMgr::handleAsyncFileLoad(ActorParam* param, s32* idx, ActorParam::ResourceType type, + void*) { + const s32 current_idx = *idx; + auto& handle = param->mHandles[param->mActiveBufferIdx][current_idx]; + *idx = current_idx + 1; + + if (ActorParam::isValidType(type)) { + if (auto* res = static_cast<T*>(param->getRes().mArray[u32(type)])) + return res; + } + + if (handle.isFlag8Set()) + return sead::DynamicCast<T>(handle.getResource()); + + if (!handle.isReadyOrNeedsParse()) + return nullptr; + + handle.parseResource(nullptr); + + if (handle.checkLoadStatus() && type != Type::EventFlow) + param->_a = 1; + + auto* res = sead::DynamicCast<T>(handle.getResource()); + if (res) { + auto* unit = handle.getUnit(); + if (unit) + static_cast<ParamIO*>(res)->getPath().copy(unit->getPath()); + } else { + res = sead::DynamicCast<T>(mDummyResources[s32(type)].getResource()); + } + + if (ActorParam::isValidType(type) && res) + param->setResource(type, res); + + return res; +} + +bool ActorParamMgr::finishLoadingActorLink(ActorParam* param, void* x) { + s32 idx = 0; + if (!handleAsyncFileLoad<res::ActorLink>(param, &idx, Type::ActorLink, x)) + return param->_a != 0; + + const auto* link = param->getRes().mActorLink; + if (!link) + return true; + + param->setProfileAndPriority(link->getUsers().getProfile(), link->getPriority().cstr()); + return true; +} + +void ActorParamMgr::loadParamAsyncStep2(ActorParam* param, res::Handle* pack_handle, void* x, + u32 load_req_c) { + const auto* link = param->getRes().mActorLink; + + loadFileAsync<res::ModelList>(param, Type::ModelList, "Actor/ModelList", "modellist", + link->getUsers().getModel(), pack_handle, x, load_req_c); + + loadFileAsync<res::UMii>(param, Type::UMii, "Actor/UMii", "umii", link->getUsers().getUMii(), + pack_handle, x, load_req_c); + + loadFileAsync<res::ASList>(param, Type::ASList, "Actor/ASList", "aslist", + link->getUsers().getAS(), pack_handle, x, load_req_c); + + loadFileAsync<res::AttClientList>(param, Type::AttClientList, "Actor/AttClientList", "atcllist", + link->getUserName(User::Attention), pack_handle, x, + load_req_c); + + loadFileAsync<res::RagdollConfigList>(param, Type::RagdollConfigList, "Actor/RagdollConfigList", + "rgconfiglist", link->getUserName(User::RgConfigList), + pack_handle, x, load_req_c); + + loadFileAsync<res::AIProgram>(param, Type::AIProgram, "Actor/AIProgram", "aiprog", + link->getUsers().getAIProgram(), pack_handle, x, load_req_c); + + loadFileAsync<res::GParamList>(param, Type::GParamList, "Actor/GeneralParamList", "gparamlist", + link->getUsers().getGParam(), pack_handle, x, load_req_c); + + loadFileAsync<res::Physics>(param, Type::Physics, "Actor/Physics", "physics", + link->getUsers().getPhysics(), pack_handle, x, load_req_c); + + loadFileAsync<res::Chemical>(param, Type::Chemical, "Actor/Chemical", "chemical", + link->getUsers().getChemical(), pack_handle, x, load_req_c); + + loadFileAsync<res::DamageParam>(param, Type::DamageParam, "Actor/DamageParam", "dmgparam", + link->getUsers().getDamageParam(), pack_handle, x, load_req_c); + + loadFileAsync<res::RagdollBlendWeight>( + param, Type::RagdollBlendWeight, "Actor/RagdollBlendWeight", "rgbw", + link->getUsers().getRgBlendWeight(), pack_handle, x, load_req_c); + + loadFileAsync<res::Awareness>(param, Type::Awareness, "Actor/Awareness", "awareness", + link->getUsers().getAwareness(), pack_handle, x, load_req_c); + + loadFileAsync<res::Drop>(param, Type::DropTable, "Actor/DropTable", "drop", + link->getUsers().getDropTable(), pack_handle, x, load_req_c); + + loadFileAsync<res::Shop>(param, Type::ShopData, "Actor/ShopData", "shop", + link->getUsers().getShopData(), pack_handle, x, load_req_c); + + loadFileAsync<res::Recipe>(param, Type::Recipe, "Actor/Recipe", "recipe", + link->getUsers().getRecipe(), pack_handle, x, load_req_c); + + loadFileAsync<res::Lod>(param, Type::Lod, "Actor/LOD", "lod", link->getUsers().getLOD(), + pack_handle, x, load_req_c); + + loadFileAsync<res::AISchedule>(param, Type::AISchedule, "Actor/AISchedule", "aischedule", + link->getUsers().getAISchedule(), pack_handle, x, load_req_c); + + loadFileAsync<res::BoneControl>(param, Type::BoneControl, "Actor/BoneControl", "bonectrl", + link->getUsers().getBoneControl(), pack_handle, x, load_req_c); + + loadFileAsync<res::LifeCondition>(param, Type::LifeCondition, "Actor/LifeCondition", + "lifecondition", link->getUsers().getLifeCondition(), + pack_handle, x, load_req_c); + + loadFileAsync<res::AnimInfo>(param, Type::AnimationInfo, "Actor/AnimationInfo", "animinfo", + link->getUsers().getAnimationInfo(), pack_handle, x, load_req_c); +} + +bool ActorParamMgr::finishLoadingStep2(ActorParam* param, void* x) { + s32 idx = 1; + + if (!handleAsyncFileLoad<res::ModelList>(param, &idx, Type::ModelList, x)) + return false; + + if (!handleAsyncFileLoad<res::UMii>(param, &idx, Type::UMii, x)) + return false; + + if (!handleAsyncFileLoad<res::ASList>(param, &idx, Type::ASList, x)) + return false; + + if (!handleAsyncFileLoad<res::AttClientList>(param, &idx, Type::AttClientList, x)) + return false; + + if (!handleAsyncFileLoad<res::RagdollConfigList>(param, &idx, Type::RagdollConfigList, x)) + return false; + + if (!handleAsyncFileLoad<res::AIProgram>(param, &idx, Type::AIProgram, x)) + return false; + + if (!handleAsyncFileLoad<res::GParamList>(param, &idx, Type::GParamList, x)) + return false; + + if (!handleAsyncFileLoad<res::Physics>(param, &idx, Type::Physics, x)) + return false; + + if (!handleAsyncFileLoad<res::Chemical>(param, &idx, Type::Chemical, x)) + return false; + + if (!handleAsyncFileLoad<res::DamageParam>(param, &idx, Type::DamageParam, x)) + return false; + + if (!handleAsyncFileLoad<res::RagdollBlendWeight>(param, &idx, Type::RagdollBlendWeight, x)) + return false; + + if (!handleAsyncFileLoad<res::Awareness>(param, &idx, Type::Awareness, x)) + return false; + + if (!handleAsyncFileLoad<res::Drop>(param, &idx, Type::DropTable, x)) + return false; + + if (!handleAsyncFileLoad<res::Shop>(param, &idx, Type::ShopData, x)) + return false; + + if (!handleAsyncFileLoad<res::Recipe>(param, &idx, Type::Recipe, x)) + return false; + + if (!handleAsyncFileLoad<res::Lod>(param, &idx, Type::Lod, x)) + return false; + + if (!handleAsyncFileLoad<res::AISchedule>(param, &idx, Type::AISchedule, x)) + return false; + + if (!handleAsyncFileLoad<res::BoneControl>(param, &idx, Type::BoneControl, x)) + return false; + + if (!handleAsyncFileLoad<res::LifeCondition>(param, &idx, Type::LifeCondition, x)) + return false; + + if (!handleAsyncFileLoad<res::AnimInfo>(param, &idx, Type::AnimationInfo, x)) + return false; + + return true; +} + +void ActorParamMgr::loadExtraResAsync(ActorParam* param, res::Handle* pack_handle, void* x, + u32 load_req_c) { + const auto* aslist = param->getRes().mASList; + const auto* atcllist = param->getRes().mAttClientList; + const auto* rgconfiglist = param->getRes().mRagdollConfigList; + + const auto num_as = aslist ? aslist->getASDefines().size() : 0; + const auto num_att = atcllist ? atcllist->getClients().size() : 0; + const auto num_rg = rgconfiglist ? rgconfiglist->getImpulseParams().size() : 0; + + param->allocResHandles(mTmpActorParamMgrHeap, 1, num_as + num_att + num_rg); + param->mActiveBufferIdx = 1; + + if (aslist) { + for (s32 i = 0; i < num_as; ++i) { + loadFileAsync<res::AS>(param, Type::AS, "Actor/AS", "as", + aslist->getASDefines()[i].getFileName(), pack_handle, x, + load_req_c); + } + } + + if (atcllist) { + for (s32 i = 0; i < num_att; ++i) { + loadFileAsync<res::AttClient>(param, Type::AttClient, "Actor/AttClient", "atcl", + atcllist->getClients()[i].getFileName(), pack_handle, x, + load_req_c); + } + } + + if (rgconfiglist) { + for (s32 i = 0; i < num_rg; ++i) { + loadFileAsync<res::RagdollConfig>( + param, Type::RagdollConfig, "Actor/RagdollConfig", "rgconfig", + rgconfiglist->getImpulseParams()[i].getFileName(), pack_handle, x, load_req_c); + } + } +} + +bool ActorParamMgr::finishLoadingExtraRes(ActorParam* param, void* x) { + s32 idx = 0; + + auto* aslist = param->getRes().mASList; + if (aslist) { + for (s32 i = 0, n = aslist->getASDefines().size(); i < n; ++i) { + const sead::SafeString file_name = aslist->getASDefines()[i].getFileName(); + if (file_name == "Dummy" || file_name.isEmpty()) { + auto* as = sead::DynamicCast<res::AS>(mDummyResources[u32(Type::AS)].getResource()); + as->setIndex(u32(Type::AS)); + aslist->addAS_(i, as); + ++idx; + } else { + const res::Handle& handle = param->mHandles[1][idx]; + if (handle.isFlag8Set()) { + ++idx; + continue; + } + + auto* as = handleAsyncFileLoad<res::AS>(param, &idx, Type::AS, x); + if (!as) + return false; + + as->setIndex(u32(Type::AS)); + aslist->addAS_(i, as); + } + } + } + + auto* atcllist = param->getRes().mAttClientList; + if (atcllist) { + for (s32 i = 0, n = atcllist->getClients().size(); i < n; ++i) { + const sead::SafeString file_name = atcllist->getClients()[i].getFileName(); + if (file_name == "Dummy" || file_name.isEmpty()) { + auto* res = sead::DynamicCast<res::AttClient>( + mDummyResources[u32(Type::AttClient)].getResource()); + /// @bug This should be Type::AttClient. Copy paste error? + res->setIndex(u32(Type::AS)); + atcllist->addClient_(i, res); + ++idx; + } else { + const res::Handle& handle = param->mHandles[1][idx]; + if (handle.isFlag8Set()) { + ++idx; + continue; + } + + auto* res = handleAsyncFileLoad<res::AttClient>(param, &idx, Type::AttClient, x); + if (!res) + return false; + + res->setIndex(u32(Type::AttClient)); + atcllist->addClient_(i, res); + } + } + } + + auto* rgconfiglist = param->getRes().mRagdollConfigList; + if (rgconfiglist) { + for (s32 i = 0, n = rgconfiglist->getImpulseParams().size(); i < n; ++i) { + const sead::SafeString file_name = rgconfiglist->getImpulseParams()[i].getFileName(); + if (file_name == "Dummy" || file_name.isEmpty()) { + auto* res = sead::DynamicCast<res::RagdollConfig>( + mDummyResources[u32(Type::RagdollConfig)].getResource()); + res->setIndex(u32(Type::RagdollConfig)); + rgconfiglist->addImpulseParamConfig_(i, res); + ++idx; + } else { + const res::Handle& handle = param->mHandles[1][idx]; + if (handle.isFlag8Set()) { + ++idx; + continue; + } + + auto* res = + handleAsyncFileLoad<res::RagdollConfig>(param, &idx, Type::RagdollConfig, x); + if (!res) + return false; + + res->setIndex(u32(Type::RagdollConfig)); + rgconfiglist->addImpulseParamConfig_(i, res); + } + } + } + + param->_9 = 0; + param->onLoadFinished(this); + param->setEventSignal(); + return true; +} + +void ActorParamMgr::allocExtraResHandles(ActorParam* param, sead::Heap* heap) const { + s32 num_extra_handles = 0; + + auto* aslist = param->getRes().mASList; + auto* atcllist = param->getRes().mAttClientList; + auto* rgconfiglist = param->getRes().mRagdollConfigList; + + if (aslist) + num_extra_handles += aslist->getASDefines().size(); + + if (atcllist) + num_extra_handles += atcllist->getClients().size(); + + if (rgconfiglist) + num_extra_handles += rgconfiglist->getImpulseParams().size(); + + param->allocResHandles(heap, 1, num_extra_handles); +} + +void ActorParamMgr::loadFilesStep2(ActorParam* param, sead::Heap* heap, res::Handle* pack_handle, + void* x, u32 load_req_c) { + const auto* link = param->getRes().mActorLink; + param->mActiveBufferIdx = 0; + + loadFile<res::AttClientList>(param, Type::AttClientList, "Actor/AttClientList", "atcllist", + link->getUserName(User::Attention), pack_handle, x, load_req_c); + + loadFile<res::RagdollConfigList>(param, Type::RagdollConfigList, "Actor/RagdollConfigList", + "rgconfiglist", link->getUserName(User::RgConfigList), + pack_handle, x, load_req_c); + + // Start loading the extra ActorParam files. + allocExtraResHandles(param, heap); + param->mActiveBufferIdx = 1; + + if (auto* aslist = param->getRes().mASList) { + for (s32 i = 0; i < aslist->getASDefines().size(); ++i) { + auto* as = loadFile<res::AS>(param, Type::AS, "Actor/AS", "as", + aslist->getASDefines()[i].getFileName(), pack_handle, x, + load_req_c); + if (as) { + as->setIndex(u32(Type::AS)); + aslist->addAS_(i, as); + } + } + } + + if (auto* list = param->getRes().mAttClientList) { + for (s32 i = 0; i < list->getClients().size(); ++i) { + auto* client = loadFile<res::AttClient>(param, Type::AttClient, "Actor/AttClient", + "atcl", list->getClients()[i].getFileName(), + pack_handle, x, load_req_c); + if (client) { + client->setIndex(u32(Type::AttClient)); + list->addClient_(i, client); + } + } + } + + if (auto* list = param->getRes().mRagdollConfigList) { + for (s32 i = 0; i < list->getImpulseParams().size(); ++i) { + auto* config = loadFile<res::RagdollConfig>( + param, Type::RagdollConfig, "Actor/RagdollConfig", "rgconfig", + list->getImpulseParams()[i].getFileName(), pack_handle, x, load_req_c); + if (config) { + config->setIndex(u32(Type::RagdollConfig)); + list->addImpulseParamConfig_(i, config); + } + } + } + + // We have now finished loading the extra ActorParam files. + // Go back to using the main resource handle buffer. + param->mActiveBufferIdx = 0; + + loadFile<res::AIProgram>(param, Type::AIProgram, "Actor/AIProgram", "aiprog", + link->getUsers().getAIProgram(), pack_handle, x, load_req_c); + + loadFile<res::GParamList>(param, Type::GParamList, "Actor/GeneralParamList", "gparamlist", + link->getUsers().getGParam(), pack_handle, x, load_req_c); + + loadFile<res::Physics>(param, Type::Physics, "Actor/Physics", "physics", + link->getUsers().getPhysics(), pack_handle, x, load_req_c); + + loadFile<res::Chemical>(param, Type::Chemical, "Actor/Chemical", "chemical", + link->getUsers().getChemical(), pack_handle, x, load_req_c); + + loadFile<res::DamageParam>(param, Type::DamageParam, "Actor/DamageParam", "dmgparam", + link->getUsers().getDamageParam(), pack_handle, x, load_req_c); + + loadFile<res::RagdollBlendWeight>(param, Type::RagdollBlendWeight, "Actor/RagdollBlendWeight", + "rgbw", link->getUsers().getRgBlendWeight(), pack_handle, x, + load_req_c); + + loadFile<res::Awareness>(param, Type::Awareness, "Actor/Awareness", "awareness", + link->getUsers().getAwareness(), pack_handle, x, load_req_c); + + loadFile<res::Drop>(param, Type::DropTable, "Actor/DropTable", "drop", + link->getUsers().getDropTable(), pack_handle, x, load_req_c); + + loadFile<res::Shop>(param, Type::ShopData, "Actor/ShopData", "shop", + link->getUsers().getShopData(), pack_handle, x, load_req_c); + + loadFile<res::Recipe>(param, Type::Recipe, "Actor/Recipe", "recipe", + link->getUsers().getRecipe(), pack_handle, x, load_req_c); + + loadFile<res::Lod>(param, Type::Lod, "Actor/LOD", "lod", link->getUsers().getLOD(), pack_handle, + x, load_req_c); + + loadFile<res::AISchedule>(param, Type::AISchedule, "Actor/AISchedule", "aischedule", + link->getUsers().getAISchedule(), pack_handle, x, load_req_c); + + loadFile<res::BoneControl>(param, Type::BoneControl, "Actor/BoneControl", "bonectrl", + link->getUsers().getBoneControl(), pack_handle, x, load_req_c); + + loadFile<res::LifeCondition>(param, Type::LifeCondition, "Actor/LifeCondition", "lifecondition", + link->getUsers().getLifeCondition(), pack_handle, x, load_req_c); + + loadFile<res::AnimInfo>(param, Type::AnimationInfo, "Actor/AnimationInfo", "animinfo", + link->getUsers().getAnimationInfo(), pack_handle, x, load_req_c); + + param->_9 = 0; + param->onLoadFinished(this); +} + +void ActorParamMgr::unloadParam(ActorParam* param) { + auto lock = sead::makeScopedLock(mCS); + param->decrementRef(); +} + +bool ActorParamMgr::prepareLoadFromActorPack(sead::BufferedSafeString* path, res::LoadRequest* req, + void*, const sead::SafeString& dir_name, + const sead::SafeString& extension, + const sead::SafeString& file_name, + res::Handle* pack_handle, u32 load_req_c, + const sead::SafeString& requester) { + path->format("%s/%s.b%s", dir_name.cstr(), file_name.cstr(), extension.cstr()); + + bool in_pack = false; + if (pack_handle && pack_handle->isSuccess()) { + auto* pack = static_cast<sead::ArchiveRes*>(pack_handle->getResourceUnchecked()); + in_pack = pack->getFile(*path) != nullptr; + } + + const bool cond1 = res::returnFalse3(*path); + const bool is_host_path = res::isHostPath(*path); + if (!in_pack && !cond1 && !is_host_path && path->include("bxml")) { + sead::FormatFixedSafeString<256> message("↓↓↓\nファイルパス : %s\n↑↑↑\n", path->cstr()); + util::PrintDebug(message); + } + + const bool ret = res::returnFalse3(*path); + if (!ret && pack_handle && pack_handle->isSuccess()) { + req->mPackHandle = pack_handle; + req->_24 = false; + } + + req->_c = load_req_c; + req->mRequester = requester; + req->_8 = true; + return ret; +} + +res::Archive* ActorParamMgr::loadActorPack(res::Handle* handle, const sead::SafeString& actor_name, + u32 load_req_c) { + sead::FixedSafeString<128> path; + res::TempResourceLoader::LoadArg arg; + arg.retry_on_failure = true; + arg.use_handle = true; + + if (mFlags.isOn(Flag::_5)) + return nullptr; + + path.format("Actor/Pack/%s.bactorpack", actor_name.cstr()); + arg.load_req.mRequester = actor_name; + arg.load_req._c = load_req_c; + arg.load_req._8 = true; + arg.load_req._28 = false; + arg.load_req.mPath = path; + + res::TempResourceLoader loader; + { + res::TempResourceLoader::InitArg init_arg{}; + res::ResourceMgrTask::instance()->initTempResourceLoader(&loader, init_arg); + } + loader.load(arg); + + res::SimpleLoadRequest req; + req.mRequester = "tap::ActorParamMgr"; + req.mPath = path; + req._c = 2; + return sead::DynamicCast<res::Archive>(handle->load(path, &req)); +} + +template <typename T> +T* ActorParamMgr::loadFile(ActorParam* param, ActorParam::ResourceType type, const char* dir_name_c, + const char* extension_c, const char* name_c, res::Handle* pack_handle, + void* x, u32 load_req_c) { + const sead::SafeString name = name_c; + const sead::SafeString extension = extension_c; + sead::FixedSafeString<128> path; + + T* res = nullptr; + + if (name != "Dummy" && !name.isEmpty()) { + auto* temp_handle = param->allocHandle(); + const sead::SafeString* actor_name; + path.format("%s/%s.b%s", dir_name_c, name_c, extension_c); + { + res::SimpleLoadRequest req; + req._8 = true; + actor_name = ¶m->getActorName(); + req.mRequester = *actor_name; + req.mPath = path; + req._c = 2; + res = sead::DynamicCast<T>(temp_handle->load(path, &req)); + } + + // If loading the resource from the RomFS has failed, try to load it from the actor pack. + if (!res) { + if (!pack_handle->isSuccess()) + loadActorPack(pack_handle, *actor_name, load_req_c); + + res::LoadRequest req; + prepareLoadFromActorPack(&path, &req, x, dir_name_c, extension_c, name_c, pack_handle, + load_req_c, *actor_name); + res = sead::DynamicCast<T>(temp_handle->load(path, &req)); + + if (!res) { + static_cast<void>(temp_handle->isSuccess()); + // Try again without the pack. + if (req.mPackHandle) { + req.mPackHandle = nullptr; + req._24 = false; + res = sead::DynamicCast<T>(temp_handle->load(path, &req)); + if (!res) + static_cast<void>(temp_handle->isSuccess()); + } + } + } + + if (!res) + param->freeLastHandle(); + else if (type == ActorParam::ResourceType::EventFlow) + temp_handle->requestUnload2(); + + } else { + path.format("%s/%s.b%s", dir_name_c, name_c, extension_c); + res = sead::DynamicCast<T>(mDummyResources[s32(type)].getResource()); + } + + if (res) { + if (type == ActorParam::ResourceType::EventFlow) + return res; + + static_cast<ParamIO*>(res)->getPath().copy(path); + param->setResourceIfValidType(type, res); + return res; + } + + if (extension != "fevfl") + param->_a = 1; + + // Fall back to using the dummy resource. + res = sead::DynamicCast<T>(mDummyResources[s32(type)].getResource()); + sead::FixedSafeString<128> dummy_path; + dummy_path.format("%s/Dummy.b%s", dir_name_c, extension_c); + if (res) { + static_cast<ParamIO*>(res)->getPath().copy(dummy_path); + param->setResourceIfValidType(type, res); + } + + return res; +} + res::GParamList* ActorParamMgr::getDummyGParamList() const { return static_cast<res::GParamList*>( - mResHandles[u32(ActorParam::ResourceType::GParamList)].getResourceUnchecked()); + mDummyResources[u32(ActorParam::ResourceType::GParamList)].getResourceUnchecked()); } } // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actActorParamMgr.h b/src/KingSystem/ActorSystem/actActorParamMgr.h index accb3457..461ca4a6 100644 --- a/src/KingSystem/ActorSystem/actActorParamMgr.h +++ b/src/KingSystem/ActorSystem/actActorParamMgr.h @@ -6,6 +6,7 @@ #include <prim/seadSafeString.h> #include <prim/seadTypedBitFlag.h> #include <thread/seadCriticalSection.h> +#include "KingSystem/ActorSystem/actActorParam.h" #include "KingSystem/Resource/resHandle.h" #include "KingSystem/System/DebugMessage.h" #include "KingSystem/System/KingEditor.h" @@ -14,13 +15,13 @@ namespace ksys { namespace res { +class Archive; class GParamList; +class LoadRequest; } // namespace res namespace act { -class ActorParam; - // FIXME: incomplete class ActorParamMgr final : public sead::hostio::Node, public KingEditorComponent { SEAD_SINGLETON_DISPOSER(ActorParamMgr) @@ -35,11 +36,23 @@ public: sead::Heap* getDebugHeap() const { return mDebugHeap; } sead::Heap* getTmpActorParamMgrHeap() const { return mTmpActorParamMgrHeap; } + bool checkPath(const sead::SafeString& path) const; + void init(sead::Heap* heap, sead::Heap* debug_heap); + ActorParam* allocParam(const char* actor_name, bool* allocated_new); ActorParam* getParam(const char* actor_name, ActorParam** out_free_param) const; - ActorParam* loadParam(const char* actor_name, res::Handle* handle, void* x, u32 load_req_c); - + ActorParam* loadParam(const char* actor_name, res::Handle* pack_handle, void* x, + u32 load_req_c); + void unloadParam(ActorParam* param); + + ActorParam* loadParamAsync(const char* actor_name, res::Handle* pack_handle, + bool* allocated_new, void* x, u32 load_req_c); + bool finishLoadingActorLink(ActorParam* param, void* x); + void loadParamAsyncStep2(ActorParam* param, res::Handle* pack_handle, void* x, u32 load_req_c); + bool finishLoadingStep2(ActorParam* param, void* x); + void loadExtraResAsync(ActorParam* param, res::Handle* pack_handle, void* x, u32 load_req_c); + bool finishLoadingExtraRes(ActorParam* param, void* x); res::GParamList* getDummyGParamList() const; private: @@ -50,9 +63,36 @@ private: _5 = _1 | _4, }; - void loadFiles(ActorParam* param, sead::Heap* heap, res::Handle* handle, void* x, + void loadFiles(ActorParam* param, sead::Heap* heap, res::Handle* pack_handle, void* x, u32 load_req_c); - bool loadActorPack(res::Handle* handle, const sead::SafeString& actor_name, u32 load_req_c); + bool requestLoadActorPack(res::Handle* handle, const sead::SafeString& actor_name, + u32 load_req_c); + bool prepareLoadFromActorPack(sead::BufferedSafeString* path, res::LoadRequest* req, void* x, + const sead::SafeString& dir_name, + const sead::SafeString& extension, + const sead::SafeString& file_name, res::Handle* pack_handle, + u32 load_req_c, const sead::SafeString& requester); + res::Archive* loadActorPack(res::Handle* handle, const sead::SafeString& actor_name, + u32 load_req_c); + + template <typename T> + T* loadFile(ActorParam* param, ActorParam::ResourceType type, const char* dir_name_c, + const char* extension_c, const char* name_c, res::Handle* pack_handle, void* x, + u32 load_req_c); + + template <typename T> + bool loadFileAsync(ActorParam* param, ActorParam::ResourceType type, + const sead::SafeString& dir_name, const sead::SafeString& extension, + const sead::SafeString& name, res::Handle* pack_handle, void* x, + u32 load_req_c); + + template <typename T> + T* handleAsyncFileLoad(ActorParam* param, s32* idx, ActorParam::ResourceType type, void* x); + + void loadFilesStep2(ActorParam* param, sead::Heap* heap, res::Handle* pack_handle, void* x, + u32 load_req_c); + + void allocExtraResHandles(ActorParam* param, sead::Heap* heap) const; static constexpr s32 NumParams = 0x400; @@ -63,7 +103,7 @@ private: void* _e8 = nullptr; sead::Heap* mDebugHeap = nullptr; sead::Heap* mTmpActorParamMgrHeap = nullptr; - sead::SafeArray<res::Handle, 28> mResHandles; + sead::SafeArray<res::Handle, ActorParam::NumResourceTypes> mDummyResources; mutable sead::CriticalSection mCS; }; KSYS_CHECK_SIZE_NX150(ActorParamMgr, 0xa00); diff --git a/src/KingSystem/ActorSystem/actActorTemplate.cpp b/src/KingSystem/ActorSystem/actActorTemplate.cpp index 0daf5dae..f4b16526 100644 --- a/src/KingSystem/ActorSystem/actActorTemplate.cpp +++ b/src/KingSystem/ActorSystem/actActorTemplate.cpp @@ -1,6 +1,6 @@ #include "KingSystem/ActorSystem/actActorTemplate.h" #include "KingSystem/ActorSystem/actActorParamMgr.h" -#include "KingSystem/Utils/Byaml.h" +#include "KingSystem/Utils/Byaml/Byaml.h" #include "KingSystem/Utils/SafeDelete.h" namespace ksys::act { diff --git a/src/KingSystem/ActorSystem/actAttention.cpp b/src/KingSystem/ActorSystem/actAttention.cpp new file mode 100644 index 00000000..001c72f2 --- /dev/null +++ b/src/KingSystem/ActorSystem/actAttention.cpp @@ -0,0 +1,9 @@ +#include "KingSystem/ActorSystem/actAttention.h" + +namespace ksys::act { + +SEAD_ENUM_IMPL(AttActionType) + +SEAD_ENUM_IMPL(AttPriorityType) + +} // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actAttention.h b/src/KingSystem/ActorSystem/actAttention.h new file mode 100644 index 00000000..bf7ed816 --- /dev/null +++ b/src/KingSystem/ActorSystem/actAttention.h @@ -0,0 +1,70 @@ +#pragma once + +#include <prim/seadEnum.h> + +namespace ksys::act { + +enum class AttType { + Action = 0, + Lock = 1, + SwordSearch = 2, + Attack = 3, + Appeal = 4, + JumpRide = 5, + NameBalloon = 6, + LookOnly = 7, + Invalid = 8, +}; + +// Make sure to update AttActionType if this is changed +enum class AttActionCode { + None = 0x1800000, + Talk, + Listen, + Awake, + Grab, + Open, + Pick, + Catch, + CheckCatch, + CatchWeapon, + Skin, + Sleep, + Sit, + Lumber, + Pushpull, + Read, + Check, + Boot, + BootPStop, + Leave, + Remind, + Buy, + Ride, + Wakeboard, + WakeboardRide, + RideRito, + RideZora, + Cook, + KillTime, + Display, + DisplayBow, + DisplayShield, + PickUp, + Pray, + PullOut, + Waterfall, + CommandWait, + CommandCome, + Thrust, + Put, + PickToEvent, + Dummy, +}; + +// clang-format off +SEAD_ENUM(AttActionType, None,Talk,Listen,Awake,Grab,Open,Pick,Catch,CheckCatch,CatchWeapon,Skin,Sleep,Sit,Lumber,Pushpull,Read,Check,Boot,BootPStop,Leave,Remind,Buy,Ride,Wakeboard,WakeboardRide,RideRito,RideZora,Cook,KillTime,Display,DisplayBow,DisplayShield,PickUp,Pray,PullOut,Waterfall,CommandWait,CommandCome,Thrust,Put,PickToEvent,Dummy) +SEAD_ENUM(AttPriorityType, Default,Enemy,Npc,Obj,ObjLow,ObjMiddle,ObjHigh,Bullet) +// clang-format on + +} // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actInfoData.cpp b/src/KingSystem/ActorSystem/actInfoData.cpp new file mode 100644 index 00000000..54499e40 --- /dev/null +++ b/src/KingSystem/ActorSystem/actInfoData.cpp @@ -0,0 +1,296 @@ +#include "KingSystem/ActorSystem/actInfoData.h" +#include <codec/seadHashCRC32.h> +#include <math/seadMathNumbers.h> +#include "KingSystem/Utils/Byaml/Byaml.h" +#include "KingSystem/Utils/Byaml/ByamlArrayIter.h" +#include "KingSystem/Utils/Byaml/ByamlData.h" +#include "KingSystem/Utils/Byaml/ByamlHashIter.h" + +namespace ksys::act { + +SEAD_SINGLETON_DISPOSER_IMPL(InfoData) + +InfoData::~InfoData() { + if (mHashesIter) + delete mHashesIter; + + if (mActorsIter) + delete mActorsIter; + + if (mRootIter) + delete mRootIter; + + mRootIter = nullptr; + mHashesIter = nullptr; + mActorsIter = nullptr; + mHashesBytes = nullptr; + mHashes = nullptr; + mActorsBytes = nullptr; + mActorOffsets = nullptr; +} + +void InfoData::init(u8* data, sead::Heap* heap, sead::Heap* debug_heap) { + mRootIter = new (heap) al::ByamlIter(data); + mHashesIter = new (heap) al::ByamlIter(); + mActorsIter = new (heap) al::ByamlIter(); + + if (debug_heap) { + mDebugEntries = new (debug_heap) DebugEntry[NumDebugEntries]; + for (s32 i = 0; i != NumDebugEntries; ++i) + mDebugEntries[i].used = false; + } else { + mDebugEntries = nullptr; + } + + if (mRootIter->tryGetIterByKey(mHashesIter, "Hashes")) { + mHashesBytes = mHashesIter->getData(); + mHashes = al::ByamlArrayIter(mHashesIter->getRootNode()).getDataTable(); + } + + if (mRootIter->tryGetIterByKey(mActorsIter, "Actors")) { + mActorsBytes = mActorsIter->getData(); + mActorOffsets = al::ByamlArrayIter(mActorsIter->getRootNode()).getDataTable(); + } + + mNumActors = mActorsIter->getSize(); + _88 = 0; + mDebugHeap = debug_heap; + mTagsIdx = mRootIter->getKeyIndex("tags"); + mProfileIdx = mRootIter->getKeyIndex("profile"); + mInvalidWeathersIdx = mRootIter->getKeyIndex("invalidWeathers"); + mInvalidTimesIdx = mRootIter->getKeyIndex("invalidTimes"); + mNameIdx = mRootIter->getKeyIndex("name"); + mSystemSameGroupActorNameIdx = mRootIter->getKeyIndex("systemSameGroupActorName"); +} + +bool InfoData::getActorIter(al::ByamlIter* iter, const char* actor, bool x) const { + const u32 hash = sead::HashCRC32::calcStringHash(actor); + + // Perform a binary search. + s32 a = 0; + s32 b = mNumActors; + while (a < b) { + const s32 idx = (a + b) / 2; + const u32 hash_i = mHashes[idx]; + + if (hash_i == hash) { + *iter = al::ByamlIter(mActorsBytes, mActorsBytes + mActorOffsets[idx]); + return true; + } + + if (hash_i >= hash) + b = idx; + else + a = idx + 1; + } + + if (x) + static_cast<void>(logFailure(actor)); + + return false; +} + +void InfoData::getRecipeInfo(const char* actor, InfoData::RecipeInfo& info) const { + al::ByamlIter iter; + if (getActorIter(&iter, actor)) { + info.num_items = iter.getIntByKey("normal0StuffNum"); + + info.items[0].name = iter.getStringByKey("normal0ItemName01"); + info.items[0].num = iter.getIntByKey("normal0ItemNum01"); + + info.items[1].name = iter.getStringByKey("normal0ItemName02"); + info.items[1].num = iter.getIntByKey("normal0ItemNum02"); + + info.items[2].name = iter.getStringByKey("normal0ItemName03"); + info.items[2].num = iter.getIntByKey("normal0ItemNum03"); + + } else { + info.num_items = 0; + + info.items[0].name = sead::SafeString::cEmptyString; + info.items[0].num = 0; + + info.items[1].name = sead::SafeString::cEmptyString; + info.items[1].num = 0; + + info.items[2].name = sead::SafeString::cEmptyString; + info.items[2].num = 0; + } +} + +s32 InfoData::getIntByKey(const al::ByamlIter& iter, const char* key, s32 default_) { + s32 value; + return iter.tryGetIntByKey(&value, key) ? value : default_; +} + +const char* InfoData::getStringByKey(const al::ByamlIter& iter, const char* key, + const sead::SafeString& default_) { + const char* value; + return iter.tryGetStringByKey(&value, key) ? value : default_.cstr(); +} + +[[gnu::noinline]] static InfoData::Locator::Type +getLocatorTypeFromStr(const sead::SafeString& type) { + static constexpr const char* types[] = {"Trunk", "Branch", "GlowStone", + "OnTree", "MagnePos", "StopTimerPos"}; + for (s32 i = 0; i < s32(std::size(types)); ++i) { + if (type == types[i]) + return InfoData::Locator::Type(i); + } + return InfoData::Locator::Type::Invalid; +} + +void InfoData::getLocators(const char* actor, Locators& info) const { + info.num = 0; + + al::ByamlIter iter; + if (!getActorIter(&iter, actor)) + return; + + al::ByamlIter iter_locators; + if (!iter.tryGetIterByKey(&iter_locators, "locators")) + return; + + info.num = iter_locators.getSize(); + for (s32 i = 0; i < info.num; ++i) { + al::ByamlIter it; + if (!iter_locators.tryGetIterByIndex(&it, i)) + continue; + + const char* type_str{}; + auto& locator = info.locators[i]; + + it.tryGetFloatByKey(&locator.pos.x, "pos_x"); + it.tryGetFloatByKey(&locator.pos.y, "pos_y"); + it.tryGetFloatByKey(&locator.pos.z, "pos_z"); + + it.tryGetFloatByKey(&locator.rot.x, "rot_x"); + it.tryGetFloatByKey(&locator.rot.y, "rot_y"); + it.tryGetFloatByKey(&locator.rot.z, "rot_z"); + + it.tryGetStringByKey(&type_str, "type"); + locator.type = type_str ? getLocatorTypeFromStr(type_str) : Locator::Type::Invalid; + + locator.rot *= 2 * sead::numbers::pi / 360.0; + } +} + +void InfoData::getHomeAreas(const char* actor, HomeAreas& info) const { + info.names.fill(""); + + al::ByamlIter iter; + if (!getActorIter(&iter, actor)) + return; + + al::ByamlIter home_area; + if (!iter.tryGetIterByKey(&home_area, "homeArea")) + return; + + for (s32 i = 0, n = home_area.getSize(); i < info.names.size() && i < n; ++i) { + al::ByamlIter it; + if (home_area.tryGetIterByIndex(&it, i)) + it.tryGetStringByKey(&info.names[i], "name"); + } +} + +const char* InfoData::getSameGroupActorName(const char* actor) const { + al::ByamlIter iter; + return [&] { + if (getActorIter(&iter, actor, false)) { + al::ByamlHashIter hash_iter{iter.getRootNode()}; + al::ByamlData data; + if (hash_iter.getDataByKey(&data, mSystemSameGroupActorNameIdx)) { + const char* name; + if (iter.tryConvertString(&name, &data)) + return name; + } + } + return sead::SafeString::cEmptyString.cstr(); + }(); +} + +const char* InfoData::getString(const char* actor, const char* key, + const sead::SafeString& default_, bool x) const { + al::ByamlIter iter; + if (!getActorIter(&iter, actor, x)) + return default_.cstr(); + + return getStringByKey(iter, key, default_); +} + +const char* InfoData::getSLinkUser(const char* actor) const { + al::ByamlIter iter; + if (!getActorIter(&iter, actor)) + return "Dummy"; + + return getStringByKey(iter, "slink", "Dummy"); +} + +bool InfoData::getSLinkAndELinkUsers(const char* actor, const char** elink, + const char** slink) const { + al::ByamlIter iter; + if (getActorIter(&iter, actor)) { + *elink = getStringByKey(iter, "elink", "Dummy"); + *slink = getStringByKey(iter, "slink", "Dummy"); + return true; + } + *elink = "Dummy"; + *slink = "Dummy"; + return false; +} + +const char* InfoData::getXLinkUser(const char* actor) const { + return getString(actor, "xlink", "Dummy"); +} + +bool InfoData::getActorProfile(const char** profile, const char* actor) const { + al::ByamlIter iter; + if (getActorIter(&iter, actor)) { + al::ByamlHashIter hash_iter{iter.getRootNode()}; + al::ByamlData data; + if (hash_iter.getDataByKey(&data, mProfileIdx)) + return iter.tryConvertString(profile, &data); + } + *profile = "Dummy"; + return false; +} + +s32 InfoData::getInt(const char* actor, const char* key, s32 default_, bool x) const { + al::ByamlIter iter; + if (!getActorIter(&iter, actor, x)) + return default_; + + return getIntByKey(iter, key, default_); +} + +f32 InfoData::getFloat(const char* actor, const char* key, f32 default_, bool x) const { + al::ByamlIter iter; + if (!getActorIter(&iter, actor, x)) + return default_; + + return getFloatByKey(iter, key, default_); +} + +bool InfoData::getBool(const char* actor, const char* key, bool default_, bool x) const { + al::ByamlIter iter; + if (!getActorIter(&iter, actor, x)) + return default_; + + return getBoolByKey(iter, key, default_); +} + +f32 InfoData::getFloatByKey(const al::ByamlIter& iter, const char* key, f32 default_) { + f32 value; + return iter.tryGetFloatByKey(&value, key) ? value : default_; +} + +bool InfoData::getBoolByKey(const al::ByamlIter& iter, const char* key, bool default_) { + bool value; + return iter.tryGetBoolByKey(&value, key) ? value != 0 : default_; +} + +f32 InfoData::getScale(const char* actor) const { + return getFloat(actor, "actorScale", 1.0); +} + +} // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actInfoData.h b/src/KingSystem/ActorSystem/actInfoData.h new file mode 100644 index 00000000..56a84e6f --- /dev/null +++ b/src/KingSystem/ActorSystem/actInfoData.h @@ -0,0 +1,135 @@ +#pragma once + +#include <basis/seadTypes.h> +#include <container/seadSafeArray.h> +#include <gfx/seadColor.h> +#include <heap/seadDisposer.h> +#include <math/seadVector.h> +#include <prim/seadSafeString.h> +#include "KingSystem/Utils/Types.h" + +namespace al { +class ByamlIter; +} + +namespace ksys::act { + +class InfoData { + SEAD_SINGLETON_DISPOSER(InfoData) + InfoData() = default; + virtual ~InfoData(); + +public: + struct ModelInfo { + sead::Vector3f baseScale; + sead::Color4f addColor; + sead::Color4f mulColor; + const char* bfres; + const char* mainModel; + }; + KSYS_CHECK_SIZE_NX150(ModelInfo, 0x40); + + struct RecipeInfo { + struct Item { + sead::FixedSafeString<64> name; + s32 num; + }; + + s32 num_items; + Item items[3]; + }; + KSYS_CHECK_SIZE_NX150(RecipeInfo, 0x128); + + struct Locator { + enum class Type { + Invalid = -1, + Trunk = 0, + Branch = 1, + GlowStone = 2, + OnTree = 3, + MagnePos = 4, + StopTimerPos = 5, + }; + + Type type; + sead::Vector3f pos; + sead::Vector3f rot; + }; + KSYS_CHECK_SIZE_NX150(Locator, 0x1c); + + struct Locators { + s32 num; + sead::SafeArray<Locator, 8> locators; + }; + KSYS_CHECK_SIZE_NX150(Locators, 0xe4); + + struct HomeAreas { + sead::SafeArray<const char*, 3> names; + }; + KSYS_CHECK_SIZE_NX150(HomeAreas, 0x18); + + void init(u8* data, sead::Heap* heap, sead::Heap* debug_heap); + + void getModelInfo(const char* actor, ModelInfo& info) const; + bool getActorIter(al::ByamlIter* iter, const char* actor, bool x = true) const; + bool logFailure(const sead::SafeString& actor_name) const; + void getRecipeInfo(const char* actor, RecipeInfo& info) const; + void getLocators(const char* actor, Locators& info) const; + void getHomeAreas(const char* actor, HomeAreas& info) const; + // TODO: invalid time function + // TODO: tag functions + const char* getSameGroupActorName(const char* actor) const; + // TODO: more functions + const char* getSLinkUser(const char* actor) const; + bool getSLinkAndELinkUsers(const char* actor, const char** elink, const char** slink) const; + const char* getXLinkUser(const char* actor) const; + bool getActorProfile(const char** profile, const char* actor) const; + // TODO: more functions + f32 getScale(const char* actor) const; + + const char* getString(const char* actor, const char* key, const sead::SafeString& default_, + bool x = true) const; + s32 getInt(const char* actor, const char* key, s32 default_ = 0, bool x = true) const; + f32 getFloat(const char* actor, const char* key, f32 default_ = 0, bool x = true) const; + bool getBool(const char* actor, const char* key, bool default_ = false, bool x = true) const; + + static s32 getIntByKey(const al::ByamlIter& iter, const char* key, s32 default_ = 0); + static f32 getFloatByKey(const al::ByamlIter& iter, const char* key, f32 default_ = 0); + static bool getBoolByKey(const al::ByamlIter& iter, const char* key, bool default_ = false); + static const char* getStringByKey(const al::ByamlIter& iter, const char* key, + const sead::SafeString& default_); + +private: + struct DebugEntry { + sead::FixedSafeString<64> str; + bool used; + }; + KSYS_CHECK_SIZE_NX150(DebugEntry, 0x60); + + al::ByamlIter* mRootIter{}; + al::ByamlIter* mHashesIter{}; + al::ByamlIter* mActorsIter{}; + + const u8* mHashesBytes{}; + const u32* mHashes{}; + + const u8* mActorsBytes{}; + const u32* mActorOffsets{}; + + s32 mTagsIdx = -1; + s32 mInvalidWeathersIdx = -1; + s32 mInvalidTimesIdx = -1; + s32 mSystemSameGroupActorNameIdx = -1; + s32 mNameIdx = -1; + s32 mProfileIdx = -1; + + s32 mNumActors = 0; + DebugEntry* mDebugEntries{}; + u32 _88 = 0; + sead::Heap* mDebugHeap{}; + + static constexpr s32 NumDebugEntries = 512; +}; +KSYS_CHECK_SIZE_NX150(InfoData, 0x98); + +} // namespace ksys::act |
