diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 1a809ac8..72ae1e2f 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -73354,43 +73354,43 @@ 0x0000007100d2e088,act::getPictureBookSpecialDrop,20, 0x0000007100d2e09c,sub_7100D2E09C,100, 0x0000007100d2e100,sub_7100D2E100,108, -0x0000007100d2e16c,ActorInfoData::createInstance,184, -0x0000007100d2e224,sub_7100D2E224,96, -0x0000007100d2e284,sub_7100D2E284,84, -0x0000007100d2e2d8,ActorInfoData::init,628, +0x0000007100d2e16c,ActorInfoData::createInstance,184,_ZN4ksys3act8InfoData14createInstanceEPN4sead4HeapE +0x0000007100d2e224,sub_7100D2E224,96,_ZN4ksys3act8InfoDataD1Ev +0x0000007100d2e284,sub_7100D2E284,84,_ZN4ksys3act8InfoDataD0Ev +0x0000007100d2e2d8,ActorInfoData::init,628,_ZN4ksys3act8InfoData4initEPhPN4sead4HeapES5_ 0x0000007100d2e54c,ActorInfoData::getActorScaleColorModelBfres,820, -0x0000007100d2e880,ActorInfoData::getActorDataIter,208, +0x0000007100d2e880,ActorInfoData::getActorDataIter,208,_ZNK4ksys3act8InfoData12getActorIterEPN2al9ByamlIterEPKcb 0x0000007100d2e950,ActorInfoData::isNotMergedGrudgeOrArmor50OrWeaponSwordDemoCheck,348, -0x0000007100d2eaac,ActorInfoData::x,1484, -0x0000007100d2f078,act::getActorInfoInt,56, -0x0000007100d2f0b0,bymlGetString,84, -0x0000007100d2f104,sub_7100D2F104,608, -0x0000007100d2f364,sub_7100D2F364,348, +0x0000007100d2eaac,ActorInfoData::x,1484,_ZNK4ksys3act8InfoData13getRecipeInfoEPKcRNS1_10RecipeInfoE +0x0000007100d2f078,act::getActorInfoInt,56,_ZN4ksys3act8InfoData11getIntByKeyERKN2al9ByamlIterEPKci +0x0000007100d2f0b0,bymlGetString,84,_ZN4ksys3act8InfoData14getStringByKeyERKN2al9ByamlIterEPKcRKN4sead14SafeStringBaseIcEE +0x0000007100d2f104,sub_7100D2F104,608,_ZNK4ksys3act8InfoData11getLocatorsEPKcRNS1_8LocatorsE +0x0000007100d2f364,sub_7100D2F364,348,_ZNK4ksys3act8InfoData12getHomeAreasEPKcRNS1_9HomeAreasE 0x0000007100d2f4c0,ActorInfoData::x_1,560, 0x0000007100d2f6f0,ActorInfoData::hasTagByName,232, 0x0000007100d2f7d8,ActorInfoData::hasTagWithIter,296, 0x0000007100d2f900,ActorInfoData::hasTag,224, -0x0000007100d2f9e0,ActorInfoData::getActorSameGroupActorName,256, +0x0000007100d2f9e0,ActorInfoData::getActorSameGroupActorName,256,_ZNK4ksys3act8InfoData21getSameGroupActorNameEPKc? 0x0000007100d2fae0,ActorInfoData::__auto1,136, 0x0000007100d2fb68,ActorInfoData::getTerrainTextures,452, 0x0000007100d2fd2c,ActorInfoData::getDrops,228, 0x0000007100d2fe10,sub_7100D2FE10,72, -0x0000007100d2fe58,ActorInfoData::getActorString,288, +0x0000007100d2fe58,ActorInfoData::getActorString,288,_ZNK4ksys3act8InfoData9getStringEPKcS3_RKN4sead14SafeStringBaseIcEEb 0x0000007100d2ff78,sub_7100D2FF78,8, -0x0000007100d2ff80,ActorInfoData::getSlinkUser,236, -0x0000007100d3006c,ActorInfoData::getElinkAndSlink,328, -0x0000007100d301b4,sub_7100D301B4,72, -0x0000007100d301fc,ActorInfoData::getActorProfile,276, +0x0000007100d2ff80,ActorInfoData::getSlinkUser,236,_ZNK4ksys3act8InfoData12getSLinkUserEPKc +0x0000007100d3006c,ActorInfoData::getElinkAndSlink,328,_ZNK4ksys3act8InfoData21getSLinkAndELinkUsersEPKcPS3_S4_ +0x0000007100d301b4,sub_7100D301B4,72,_ZNK4ksys3act8InfoData12getXLinkUserEPKc +0x0000007100d301fc,ActorInfoData::getActorProfile,276,_ZNK4ksys3act8InfoData15getActorProfileEPPKcS3_ 0x0000007100d30310,ActorInfoData::getProfile,132, -0x0000007100d30394,ActorInfoData::getActorInt,252, -0x0000007100d30490,ActorInfoData::getActorFloat,252, -0x0000007100d3058c,ActorInfoData::getBool,260, -0x0000007100d30690,act::getBymlPropertyFloat,56, -0x0000007100d306c8,act::getBymlPropertyBool,68, +0x0000007100d30394,ActorInfoData::getActorInt,252,_ZNK4ksys3act8InfoData6getIntEPKcS3_ib +0x0000007100d30490,ActorInfoData::getActorFloat,252,_ZNK4ksys3act8InfoData8getFloatEPKcS3_fb +0x0000007100d3058c,ActorInfoData::getBool,260,_ZNK4ksys3act8InfoData7getBoolEPKcS3_bb +0x0000007100d30690,act::getBymlPropertyFloat,56,_ZN4ksys3act8InfoData13getFloatByKeyERKN2al9ByamlIterEPKcf +0x0000007100d306c8,act::getBymlPropertyBool,68,_ZN4ksys3act8InfoData12getBoolByKeyERKN2al9ByamlIterEPKcb 0x0000007100d3070c,ActorInfoData::getActorIterByHash,168, 0x0000007100d307b4,sub_7100D307B4,104, 0x0000007100d3081c,sub_7100D3081C,252, -0x0000007100d30918,ActorInfoData::getActorScale,20, +0x0000007100d30918,ActorInfoData::getActorScale,20,_ZNK4ksys3act8InfoData8getScaleEPKc 0x0000007100d3092c,ActorInfoData::getLookAtOffsetY,272, 0x0000007100d30a3c,ActorInfoData::getCursorOffsetY,20, 0x0000007100d30a50,ActorInfoData::getTraverseDist,20, @@ -91544,7 +91544,7 @@ 0x00000071011b0c0c,Bmodellist::x,8, 0x00000071011b0c14,modellist::x,376, 0x00000071011b0d8c,sub_71011B0D8C,688, -0x00000071011b103c,sub_71011B103C,296, +0x00000071011b103c,sub_71011B103C,296,_ZN4ksys3actL21getLocatorTypeFromStrERKN4sead14SafeStringBaseIcEE 0x00000071011b1164,sub_71011B1164,544, 0x00000071011b1384,sub_71011B1384,32, 0x00000071011b13a4,sub_71011B13A4,32, diff --git a/src/KingSystem/ActorSystem/CMakeLists.txt b/src/KingSystem/ActorSystem/CMakeLists.txt index f11251c3..e5c354bb 100644 --- a/src/KingSystem/ActorSystem/CMakeLists.txt +++ b/src/KingSystem/ActorSystem/CMakeLists.txt @@ -40,8 +40,10 @@ target_sources(uking PRIVATE actBaseProcMgr.h actBaseProcUnit.cpp actBaseProcUnit.h - actLifeRecoveryInfo.h + actInfoData.cpp + actInfoData.h actInstParamPack.cpp actInstParamPack.h + actLifeRecoveryInfo.h actTag.h ) diff --git a/src/KingSystem/ActorSystem/actInfoData.cpp b/src/KingSystem/ActorSystem/actInfoData.cpp new file mode 100644 index 00000000..036ab557 --- /dev/null +++ b/src/KingSystem/ActorSystem/actInfoData.cpp @@ -0,0 +1,295 @@ +#include "KingSystem/ActorSystem/actInfoData.h" +#include +#include +#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(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"); + } +} + +// NON_MATCHING: stack +const char* InfoData::getSameGroupActorName(const char* actor) const { + al::ByamlIter iter; + 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 +#include +#include +#include +#include +#include +#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 locators; + }; + KSYS_CHECK_SIZE_NX150(Locators, 0xe4); + + struct HomeAreas { + sead::SafeArray 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 diff --git a/src/KingSystem/Utils/Byaml/Byaml.h b/src/KingSystem/Utils/Byaml/Byaml.h index 0543ce50..c13500d7 100644 --- a/src/KingSystem/Utils/Byaml/Byaml.h +++ b/src/KingSystem/Utils/Byaml/Byaml.h @@ -43,6 +43,9 @@ public: ByamlIter& operator=(const ByamlIter& rhs); + const u8* getData() const { return mData; } + const u8* getRootNode() const { return mRootNode; } + bool isValid() const; bool isTypeHash() const; bool isTypeArray() const;