diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 06b43dcb..5d91bb8b 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -81916,13 +81916,13 @@ 0x0000007100f4b950,sub_7100F4B950,40,_ZThn464_N4ksys3mii4UMiiD0Ev 0x0000007100f4b978,umii::load,308,_ZN4ksys3mii4UMii4loadEN3agl3utl19ResParameterArchiveERKN4sead14SafeStringBaseIcEERKj 0x0000007100f4baac,umii::initDefaultVal,360,_ZN4ksys3mii4UMii5resetEv -0x0000007100f4bc14,umii::x,512, -0x0000007100f4be14,sub_7100F4BE14,16, -0x0000007100f4be24,sub_7100F4BE24,20, -0x0000007100f4be38,sub_7100F4BE38,56, -0x0000007100f4be70,umii::loadKorokValues,36, -0x0000007100f4be94,sub_7100F4BE94,120, -0x0000007100f4bf0c,sub_7100F4BF0C,36, +0x0000007100f4bc14,umii::x,512,_ZN4ksys3mii4UMii6doLoadERKj +0x0000007100f4be14,sub_7100F4BE14,16,_ZNK4ksys3mii4UMii8isFemaleEv +0x0000007100f4be24,sub_7100F4BE24,20,_ZNK4ksys3mii4UMii20getHeightWeightIndexEv +0x0000007100f4be38,sub_7100F4BE38,56,_ZNK4ksys3mii4UMii6getAgeEv +0x0000007100f4be70,umii::loadKorokValues,36,_ZN4ksys3mii4UMii14setKorokValuesERKNS1_5KorokE +0x0000007100f4be94,sub_7100F4BE94,120,_ZNK4ksys3mii4UMii14sub_7100F4BE94Ev +0x0000007100f4bf0c,sub_7100F4BF0C,36,_ZNK4ksys3mii4UMii14sub_7100F4BF0CEv 0x0000007100f4bf30,j__ZdlPv_973,4,_ZN4ksys3mii4UMii4FFSDD0Ev 0x0000007100f4bf34,j__ZdlPv_974,4,_ZN4ksys3mii4UMii4BodyD0Ev 0x0000007100f4bf38,j__ZdlPv_975,4,_ZN4ksys3mii4UMii8PersonalD0Ev diff --git a/lib/agl b/lib/agl index d8c957dc..078f7ddb 160000 --- a/lib/agl +++ b/lib/agl @@ -1 +1 @@ -Subproject commit d8c957dc8023fb8bb8d26ac1cdf75047cc7124f9 +Subproject commit 078f7ddbca63a4e20410558f48edd726f7c5ddbc diff --git a/src/KingSystem/ActorSystem/actActorParam.h b/src/KingSystem/ActorSystem/actActorParam.h index 1186e244..70b399d5 100644 --- a/src/KingSystem/ActorSystem/actActorParam.h +++ b/src/KingSystem/ActorSystem/actActorParam.h @@ -122,6 +122,8 @@ public: Priority getPriority() const { return mPriority; } const Resources& getRes() const { return mRes; } + bool isA() const { return _a; } + bool isDummyParam(res::ActorLink::User user) const; static void resetDummyResources(); @@ -160,7 +162,7 @@ private: u8 _8 = 0; u8 _9 = 0; - u8 _a = 0; + bool _a = false; sead::FixedSafeString<64> mActorName; sead::SafeString mProfile; const char* mClassName{}; diff --git a/src/KingSystem/Mii/miiModelCreator.h b/src/KingSystem/Mii/miiModelCreator.h index 1adef573..432a80a3 100644 --- a/src/KingSystem/Mii/miiModelCreator.h +++ b/src/KingSystem/Mii/miiModelCreator.h @@ -1,10 +1,25 @@ #pragma once #include +#include +#include #include namespace ksys::mii { extern sead::SafeArray s_rot_labels; +// FIXME: incomplete +class ModelCreator final : public sead::hostio::Node { + SEAD_SINGLETON_DISPOSER(ModelCreator) +public: + ModelCreator() = default; + + struct Arg { + int type; + }; + + const sead::SafeString& getActorName(const Arg& arg) const; +}; + } // namespace ksys::mii diff --git a/src/KingSystem/Mii/miiUMii.cpp b/src/KingSystem/Mii/miiUMii.cpp index 20da09e1..7c282e90 100644 --- a/src/KingSystem/Mii/miiUMii.cpp +++ b/src/KingSystem/Mii/miiUMii.cpp @@ -1,7 +1,9 @@ #include "KingSystem/Mii/miiUMii.h" #include +#include #include "KingSystem/ActorSystem/actActorParamMgr.h" #include "KingSystem/Mii/miiModelCreator.h" +#include "KingSystem/Resource/resResourceUMii.h" #include "KingSystem/Utils/InitTimeInfo.h" namespace ksys::mii { @@ -67,7 +69,7 @@ UMii::UMii() : agl::utl::IParameterIO("umii", 0) { face.shape.skin_color.init(0, "skin_color", "肌の色", &face.shape); addObj(&face.hair, "hair"); - face.hair.type.init(int(HairType::Invalid), "type", "髪型", &face.hair); + face.hair.type.init(Hair::Type_Invalid, "type", "髪型", &face.hair); face.hair.color.init(1, "color", "髪の色", &face.hair); face.hair.flip.init(false, "flip", "反転", &face.hair); @@ -180,7 +182,7 @@ void UMii::reset() { body.weight = 1; body.height = 0; - personal.sex_age = 1; + personal.sex_age = Personal::SexAge_Man; personal.fav_color = 0; personal.sub_color_1 = -1; personal.sub_color_2 = -1; @@ -213,4 +215,112 @@ void UMii::reset() { zora.body_color = 0; } +void UMii::doLoad(const u32& load_req_c) { + if (ffsd.type.ref() == FFSD::Type_1) { + mActorName = ModelCreator::instance()->getActorName({isFemale()}); + + void* x; + mActorParam = act::ActorParamMgr::instance()->loadParam(mActorName.cstr(), &mResHandle, &x, + load_req_c); + + if (mActorParam) { + res::UMii* umii = nullptr; + if (!mActorParam->isA()) { + umii = act::ActorParam::sDummyResources.mUMii; + if (!umii) + umii = mActorParam->getRes().mUMii; + } + + if (umii) { + applyResParameterArchive(umii->getArchive()); + + static const char* voice_types[2] = { + "Hylia_Man_Young_Normal04", + "Hylia_Woman_Young_Normal04", + }; + personal.voice_type.ref() = voice_types[isFemale()]; + } else { + act::ActorParamMgr::instance()->unloadParam(mActorParam); + mActorParam = nullptr; + mResHandle.requestUnload(); + } + } + } + + if (korok.mask.ref() == Korok::Mask_Random) + korok.mask = sead::GlobalRandom::instance()->getU32(Korok::Mask_Random); + + if (korok.skin_color.ref() == Korok::SkinColor_Random) + korok.skin_color = sead::GlobalRandom::instance()->getU32(Korok::SkinColor_Random); + + if (korok.left_plant.ref() == Korok::LeftPlant_Random) + korok.left_plant = sead::GlobalRandom::instance()->getU32(Korok::LeftPlant_Random); + + if (korok.right_plant.ref() == Korok::RightPlant_Random) + korok.right_plant = sead::GlobalRandom::instance()->getU32(Korok::RightPlant_Random); +} + +bool UMii::isFemale() const { + return personal.sex_age.ref() > Personal::SexAge_OldMan; +} + +int UMii::getHeightWeightIndex() const { + return 3 * *body.height + *body.weight; +} + +UMii::Personal::Age UMii::getAge() const { + if (getSexAge() == Personal::SexAge_Boy || getSexAge() == Personal::SexAge_Girl) + return Personal::Age_Child; + + if (getSexAge() == Personal::SexAge_Man || getSexAge() == Personal::SexAge_Woman) + return Personal::Age_Adult; + + return Personal::Age_OldAdult; +} + +void UMii::setKorokValues(const UMii::Korok& info) { + korok.mask = *info.mask; + korok.skin_color = *info.skin_color; + korok.left_plant = *info.left_plant; + korok.right_plant = *info.right_plant; +} + +int UMii::sub_7100F4BE94() const { + const auto age = getAge(); + + if (age == Personal::Age_Child) + return 0; + + if (age == Personal::Age_OldAdult) + return 3; + + if (*body.race == Body::Race_Gerudo) { + if (*ffsd.no_use_ffsd) { + if (*common.is_mid_age) + return 1; + } else { + if (*body.number == 1) + return 1; + } + } + + return isFemale() + 1; +} + +int UMii::sub_7100F4BF0C() const { + switch (getSexAge()) { + case Personal::SexAge_Boy: + return 0; + case Personal::SexAge_Man: + return 1; + case Personal::SexAge_OldMan: + case Personal::SexAge_Woman: + return 2; + case Personal::SexAge_Girl: + return 0; + default: + return 2; + } +} + } // namespace ksys::mii diff --git a/src/KingSystem/Mii/miiUMii.h b/src/KingSystem/Mii/miiUMii.h index dc436974..34e2f71a 100644 --- a/src/KingSystem/Mii/miiUMii.h +++ b/src/KingSystem/Mii/miiUMii.h @@ -14,10 +14,6 @@ class ActorParam; namespace ksys::mii { -enum class HairType { - Invalid = 0x21, -}; - class UMiiBase { public: virtual ~UMiiBase() = default; @@ -26,12 +22,35 @@ public: class UMii : public agl::utl::IParameterIO, public UMiiBase { public: struct FFSD : agl::utl::ParameterObj { + enum Type { + Type_0 = 0, + Type_1 = 1, + }; + agl::utl::Parameter no_use_ffsd; agl::utl::Parameter type; }; KSYS_CHECK_SIZE_NX150(FFSD, 0x70); struct Body : agl::utl::ParameterObj { + enum Race { + Race_Hylian = 0, + Race_Korok = 1, + Race_Goron = 2, + Race_Sheikah = 3, + Race_Gerudo = 4, + Race_Zora = 5, + Race_Rito = 6, + }; + + enum Type { + Type_C = 0, + Type_N = 1, + Type_T = 2, + Type_S = 3, + Type_SK = 4, + }; + agl::utl::Parameter race; agl::utl::Parameter type; agl::utl::Parameter number; @@ -41,6 +60,21 @@ public: KSYS_CHECK_SIZE_NX150(Body, 0xd0); struct Personal : agl::utl::ParameterObj { + enum SexAge { + SexAge_Boy = 0, + SexAge_Man = 1, + SexAge_OldMan = 2, + SexAge_Girl = 3, + SexAge_Woman = 4, + SexAge_OldWoman = 5, + }; + + enum Age { + Age_Child = 0, + Age_Adult = 1, + Age_OldAdult = 2, + }; + agl::utl::Parameter sex_age; agl::utl::Parameter fav_color; agl::utl::Parameter sub_color_1; @@ -77,6 +111,10 @@ public: KSYS_CHECK_SIZE_NX150(Shape, 0xf0); struct Hair : agl::utl::ParameterObj { + enum Type { + Type_Invalid = 0x21, + }; + agl::utl::Parameter type; agl::utl::Parameter color; agl::utl::Parameter flip; @@ -151,6 +189,22 @@ public: KSYS_CHECK_SIZE_NX150(Glass, 0x70); struct Korok : agl::utl::ParameterObj { + enum Mask { + Mask_Random = 9, + }; + + enum SkinColor { + SkinColor_Random = 5, + }; + + enum LeftPlant { + LeftPlant_Random = 3, + }; + + enum RightPlant { + RightPlant_Random = 3, + }; + agl::utl::Parameter mask; agl::utl::Parameter skin_color; agl::utl::Parameter left_plant; @@ -215,6 +269,14 @@ public: void load(agl::utl::ResParameterArchive archive, const sead::SafeString& user, const u32& load_req_c); + bool isFemale() const; + int getHeightWeightIndex() const; + Personal::SexAge getSexAge() const { return Personal::SexAge(*personal.sex_age); } + Personal::Age getAge() const; + void setKorokValues(const Korok& info); + int sub_7100F4BE94() const; + int sub_7100F4BF0C() const; + private: void reset(); void doLoad(const u32& load_req_c); diff --git a/src/KingSystem/Resource/resResourceUMii.cpp b/src/KingSystem/Resource/resResourceUMii.cpp index cefadea6..677f8f58 100644 --- a/src/KingSystem/Resource/resResourceUMii.cpp +++ b/src/KingSystem/Resource/resResourceUMii.cpp @@ -8,7 +8,7 @@ UMii::~UMii() = default; bool UMii::parse_(u8* data, size_t, sead::Heap*) { agl::utl::ResParameterArchive archive{data + mAllocSize}; - mData = archive.ptr(); + mArchive = archive; return true; } diff --git a/src/KingSystem/Resource/resResourceUMii.h b/src/KingSystem/Resource/resResourceUMii.h index 1191c76e..ed4f8d0d 100644 --- a/src/KingSystem/Resource/resResourceUMii.h +++ b/src/KingSystem/Resource/resResourceUMii.h @@ -1,5 +1,6 @@ #pragma once +#include #include "KingSystem/Resource/resResource.h" #include "KingSystem/Utils/ParamIO.h" #include "KingSystem/Utils/Types.h" @@ -12,15 +13,15 @@ public: UMii(); ~UMii() override; - agl::utl::ResParameterArchiveData* getData() const { return mData; } + agl::utl::ResParameterArchive getArchive() const { return mArchive; } bool needsParse() const override { return true; } - bool m2_() override { return mData != nullptr; } + 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::ResParameterArchiveData* mData{}; + agl::utl::ResParameterArchive mArchive{}; }; KSYS_CHECK_SIZE_NX150(UMii, 0x2b8);