From 814baf809ebe9f75ceeae3ecd8611e96d15b18ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Tue, 23 Mar 2021 11:08:11 +0100 Subject: [PATCH] ksys: Add mii::UMii --- data/uking_functions.csv | 88 ++++----- lib/agl | 2 +- src/KingSystem/CMakeLists.txt | 1 + src/KingSystem/Mii/CMakeLists.txt | 6 + src/KingSystem/Mii/miiModelCreator.cpp | 12 ++ src/KingSystem/Mii/miiModelCreator.h | 10 + src/KingSystem/Mii/miiUMii.cpp | 216 ++++++++++++++++++++++ src/KingSystem/Mii/miiUMii.h | 243 +++++++++++++++++++++++++ 8 files changed, 533 insertions(+), 45 deletions(-) create mode 100644 src/KingSystem/Mii/CMakeLists.txt create mode 100644 src/KingSystem/Mii/miiModelCreator.cpp create mode 100644 src/KingSystem/Mii/miiModelCreator.h create mode 100644 src/KingSystem/Mii/miiUMii.cpp create mode 100644 src/KingSystem/Mii/miiUMii.h diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 3fece5b2..06b43dcb 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -81900,22 +81900,22 @@ 0x0000007100f49a5c,j__ZdlPv_972,4, 0x0000007100f49a60,_ZN4sead15FixedSafeStringILi91EEaSERKNS_14SafeStringBaseIcEE,240, 0x0000007100f49b50,sub_7100F49B50,32, -0x0000007100f49b70,umii::ctor,6608, -0x0000007100f4b540,sub_7100F4B540,552, -0x0000007100f4b768,sub_7100F4B768,36, -0x0000007100f4b78c,sub_7100F4B78C,40, -0x0000007100f4b7b4,sub_7100F4B7B4,56, -0x0000007100f4b7ec,sub_7100F4B7EC,36, -0x0000007100f4b810,sub_7100F4B810,48, -0x0000007100f4b840,sub_7100F4B840,68, -0x0000007100f4b884,sub_7100F4B884,68, -0x0000007100f4b8c8,sub_7100F4B8C8,52, -0x0000007100f4b8fc,sub_7100F4B8FC,40, -0x0000007100f4b924,sub_7100F4B924,8, -0x0000007100f4b92c,sub_7100F4B92C,36, -0x0000007100f4b950,sub_7100F4B950,40, -0x0000007100f4b978,umii::load,308, -0x0000007100f4baac,umii::initDefaultVal,360, +0x0000007100f49b70,umii::ctor,6608,_ZN4ksys3mii4UMiiC1Ev +0x0000007100f4b540,sub_7100F4B540,552,_ZN4ksys3mii4UMiiD1Ev +0x0000007100f4b768,sub_7100F4B768,36,_ZN4ksys3mii4UMii4ZoraD2Ev +0x0000007100f4b78c,sub_7100F4B78C,40,_ZN4ksys3mii4UMii4RitoD2Ev +0x0000007100f4b7b4,sub_7100F4B7B4,56,_ZN4ksys3mii4UMii6GerudoD2Ev +0x0000007100f4b7ec,sub_7100F4B7EC,36,_ZN4ksys3mii4UMii5GoronD2Ev +0x0000007100f4b810,sub_7100F4B810,48,_ZN4ksys3mii4UMii5KorokD2Ev +0x0000007100f4b840,sub_7100F4B840,68,_ZN4ksys3mii4UMii6CommonD2Ev +0x0000007100f4b884,sub_7100F4B884,68,_ZN4ksys3mii4UMii8PersonalD2Ev +0x0000007100f4b8c8,sub_7100F4B8C8,52,_ZN4ksys3mii4UMii4BodyD2Ev +0x0000007100f4b8fc,sub_7100F4B8FC,40,_ZN4ksys3mii4UMii4FFSDD2Ev +0x0000007100f4b924,sub_7100F4B924,8,_ZThn464_N4ksys3mii4UMiiD1Ev +0x0000007100f4b92c,sub_7100F4B92C,36,_ZN4ksys3mii4UMiiD0Ev +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, @@ -81923,34 +81923,34 @@ 0x0000007100f4be70,umii::loadKorokValues,36, 0x0000007100f4be94,sub_7100F4BE94,120, 0x0000007100f4bf0c,sub_7100F4BF0C,36, -0x0000007100f4bf30,j__ZdlPv_973,4, -0x0000007100f4bf34,j__ZdlPv_974,4, -0x0000007100f4bf38,j__ZdlPv_975,4, -0x0000007100f4bf3c,j__ZdlPv_976,4, -0x0000007100f4bf40,sub_7100F4BF40,864, -0x0000007100f4c2a0,sub_7100F4C2A0,56, -0x0000007100f4c2d8,j__ZdlPv_977,4, -0x0000007100f4c2dc,sub_7100F4C2DC,44, -0x0000007100f4c308,j__ZdlPv_978,4, -0x0000007100f4c30c,sub_7100F4C30C,76, -0x0000007100f4c358,j__ZdlPv_979,4, -0x0000007100f4c35c,sub_7100F4C35C,56, -0x0000007100f4c394,j__ZdlPv_980,4, -0x0000007100f4c398,sub_7100F4C398,60, -0x0000007100f4c3d4,j__ZdlPv_981,4, -0x0000007100f4c3d8,sub_7100F4C3D8,44, -0x0000007100f4c404,j__ZdlPv_982,4, -0x0000007100f4c408,sub_7100F4C408,52, -0x0000007100f4c43c,j__ZdlPv_983,4, -0x0000007100f4c440,sub_7100F4C440,48, -0x0000007100f4c470,j__ZdlPv_984,4, -0x0000007100f4c474,sub_7100F4C474,40, -0x0000007100f4c49c,j__ZdlPv_985,4, -0x0000007100f4c4a0,j__ZdlPv_986,4, -0x0000007100f4c4a4,j__ZdlPv_987,4, -0x0000007100f4c4a8,j__ZdlPv_988,4, -0x0000007100f4c4ac,j__ZdlPv_989,4, -0x0000007100f4c4b0,j__ZdlPv_990,4, +0x0000007100f4bf30,j__ZdlPv_973,4,_ZN4ksys3mii4UMii4FFSDD0Ev +0x0000007100f4bf34,j__ZdlPv_974,4,_ZN4ksys3mii4UMii4BodyD0Ev +0x0000007100f4bf38,j__ZdlPv_975,4,_ZN4ksys3mii4UMii8PersonalD0Ev +0x0000007100f4bf3c,j__ZdlPv_976,4,_ZN4ksys3mii4UMii6CommonD0Ev +0x0000007100f4bf40,sub_7100F4BF40,864,_ZN4ksys3mii4UMii4FaceC2Ev +0x0000007100f4c2a0,sub_7100F4C2A0,56,_ZN4ksys3mii4UMii5ShapeD2Ev +0x0000007100f4c2d8,j__ZdlPv_977,4,_ZN4ksys3mii4UMii5ShapeD0Ev +0x0000007100f4c2dc,sub_7100F4C2DC,44,_ZN4ksys3mii4UMii4HairD2Ev +0x0000007100f4c308,j__ZdlPv_978,4,_ZN4ksys3mii4UMii4HairD0Ev +0x0000007100f4c30c,sub_7100F4C30C,76,_ZN4ksys3mii4UMii3EyeD2Ev +0x0000007100f4c358,j__ZdlPv_979,4,_ZN4ksys3mii4UMii3EyeD0Ev +0x0000007100f4c35c,sub_7100F4C35C,56,_ZN4ksys3mii4UMii7EyeCtrlD2Ev +0x0000007100f4c394,j__ZdlPv_980,4,_ZN4ksys3mii4UMii7EyeCtrlD0Ev +0x0000007100f4c398,sub_7100F4C398,60,_ZN4ksys3mii4UMii7EyebrowD2Ev +0x0000007100f4c3d4,j__ZdlPv_981,4,_ZN4ksys3mii4UMii7EyebrowD0Ev +0x0000007100f4c3d8,sub_7100F4C3D8,44,_ZN4ksys3mii4UMii4NoseD2Ev +0x0000007100f4c404,j__ZdlPv_982,4,_ZN4ksys3mii4UMii4NoseD0Ev +0x0000007100f4c408,sub_7100F4C408,52,_ZN4ksys3mii4UMii5MouthD2Ev +0x0000007100f4c43c,j__ZdlPv_983,4,_ZN4ksys3mii4UMii5MouthD0Ev +0x0000007100f4c440,sub_7100F4C440,48,_ZN4ksys3mii4UMii5BeardD2Ev +0x0000007100f4c470,j__ZdlPv_984,4,_ZN4ksys3mii4UMii5BeardD0Ev +0x0000007100f4c474,sub_7100F4C474,40,_ZN4ksys3mii4UMii5GlassD2Ev +0x0000007100f4c49c,j__ZdlPv_985,4,_ZN4ksys3mii4UMii5GlassD0Ev +0x0000007100f4c4a0,j__ZdlPv_986,4,_ZN4ksys3mii4UMii5KorokD0Ev +0x0000007100f4c4a4,j__ZdlPv_987,4,_ZN4ksys3mii4UMii5GoronD0Ev +0x0000007100f4c4a8,j__ZdlPv_988,4,_ZN4ksys3mii4UMii6GerudoD0Ev +0x0000007100f4c4ac,j__ZdlPv_989,4,_ZN4ksys3mii4UMii4RitoD0Ev +0x0000007100f4c4b0,j__ZdlPv_990,4,_ZN4ksys3mii4UMii4ZoraD0Ev 0x0000007100f4c4b4,sub_7100F4C4B4,192, 0x0000007100f4c574,nullsub_4171,4, 0x0000007100f4c578,nullsub_4172,4, diff --git a/lib/agl b/lib/agl index dcc96e3d..d8c957dc 160000 --- a/lib/agl +++ b/lib/agl @@ -1 +1 @@ -Subproject commit dcc96e3d991bf1042606521ba59017274c0bc156 +Subproject commit d8c957dc8023fb8bb8d26ac1cdf75047cc7124f9 diff --git a/src/KingSystem/CMakeLists.txt b/src/KingSystem/CMakeLists.txt index 8036f58e..97733bd4 100644 --- a/src/KingSystem/CMakeLists.txt +++ b/src/KingSystem/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(Ecosystem) add_subdirectory(Event) add_subdirectory(Framework) add_subdirectory(Map) +add_subdirectory(Mii) add_subdirectory(Sound) add_subdirectory(System) add_subdirectory(Terrain) diff --git a/src/KingSystem/Mii/CMakeLists.txt b/src/KingSystem/Mii/CMakeLists.txt new file mode 100644 index 00000000..bd470cc8 --- /dev/null +++ b/src/KingSystem/Mii/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(uking PRIVATE + miiModelCreator.cpp + miiModelCreator.h + miiUMii.cpp + miiUMii.h +) diff --git a/src/KingSystem/Mii/miiModelCreator.cpp b/src/KingSystem/Mii/miiModelCreator.cpp new file mode 100644 index 00000000..d6737069 --- /dev/null +++ b/src/KingSystem/Mii/miiModelCreator.cpp @@ -0,0 +1,12 @@ +#include "KingSystem/Mii/miiModelCreator.h" + +namespace ksys::mii { + +sead::SafeArray s_rot_labels{{ + "肩(Clavicle_L/R)", + "腕(Arm_1_L/R)", + "脚(Leg_1_L/R:X)", + "股(Leg_1_L/R:Y)", +}}; + +} // namespace ksys::mii diff --git a/src/KingSystem/Mii/miiModelCreator.h b/src/KingSystem/Mii/miiModelCreator.h new file mode 100644 index 00000000..1adef573 --- /dev/null +++ b/src/KingSystem/Mii/miiModelCreator.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +namespace ksys::mii { + +extern sead::SafeArray s_rot_labels; + +} // namespace ksys::mii diff --git a/src/KingSystem/Mii/miiUMii.cpp b/src/KingSystem/Mii/miiUMii.cpp new file mode 100644 index 00000000..20da09e1 --- /dev/null +++ b/src/KingSystem/Mii/miiUMii.cpp @@ -0,0 +1,216 @@ +#include "KingSystem/Mii/miiUMii.h" +#include +#include "KingSystem/ActorSystem/actActorParamMgr.h" +#include "KingSystem/Mii/miiModelCreator.h" +#include "KingSystem/Utils/InitTimeInfo.h" + +namespace ksys::mii { + +struct Constants { + util::InitConstants init_constants; + sead::Vector3f eye_ctrl_base_offset{0.0, 0.03, 0.0}; + sead::SafeArray rot_names{{ + "rot_cravicle", + "rot_arm", + "rot_leg", + "rot_crotch", + }}; +}; +static Constants s_constants; +constexpr sead::SafeArray s_eye_highlight_values{{1.0, 0.5, 0.2, 0.0}}; + +UMii::UMii() : agl::utl::IParameterIO("umii", 0) { + mUser = "Dummy"; + + addObj(&ffsd, "ffsd"); + ffsd.no_use_ffsd.init(false, "no_use_ffsd", "Miiデータを使用しない(NPCプロフィールとして扱う)", + &ffsd); + ffsd.type.init(0, "type", "参照先", &ffsd); + + addObj(&body, "body"); + body.race.init(0, "race", "種族", &body); + body.type.init(0, "type", "種類", &body); + body.number.init(0, "number", "番号", &body); + body.weight.init(1, "weight", "体重", &body); + body.height.init(0, "height", "身長", &body); + + addObj(&personal, "personal"); + personal.sex_age.init(1, "sex_age", "性別世代", &personal); + personal.fav_color.init(0, "fav_color", "お気に入りカラー", &personal); + personal.sub_color_1.init(-1, "sub_color_1", "サブカラー1", &personal); + personal.sub_color_2.init(-1, "sub_color_2", "サブカラー2", &personal); + personal.head_fav_color.init(-1, "head_fav_color", "お気に入りカラー(帽子)", &personal); + personal.shoulder_fav_color.init(-1, "shoulder_fav_color", "お気に入りカラー(リュック)", + &personal); + personal.shoulder_sub_color_1.init(-1, "shoulder_sub_color_1", "サブカラー1(リュック)", + &personal); + personal.personality.init(sead::SafeString::cEmptyString, "personality", "性格", &personal); + personal.voice_type.init("Normal1", "voice_type", "ボイスタイプ", &personal); + + addObj(&common, "common"); + common.backpack.init(-1, "backpack", "背負いもの", &common); + common.hat.init(-1, "hat", "帽子", &common); + common.no_hat_always.init(false, "no_hat_always", "常時帽子Off", &common); + common.body_correct.init(false, "body_correct", "体形補正", &common); + common.is_mid_age.init(false, "is_mid_age", "中年扱い(ゲルド用)", &common); + common.rot_cravicle.init(0.0, s_constants.rot_names[0], s_rot_labels[0], &common); + common.rot_arm.init(0.0, s_constants.rot_names[1], s_rot_labels[1], &common); + common.rot_leg.init(0.0, s_constants.rot_names[2], s_rot_labels[2], &common); + common.rot_crotch.init(0.0, s_constants.rot_names[3], s_rot_labels[3], &common); + + addObj(&face.shape, "shape"); + face.shape.jaw.init(0, "jaw", "顎形状", &face.shape); + face.shape.wrinkle.init(0, "wrinkle", "しわ", &face.shape); + face.shape.make.init(0, "make", "化粧", &face.shape); + face.shape.trans_v.init(0, "trans_v", "縦移動", &face.shape); + face.shape.scale.init(1.0, "scale", "拡縮", &face.shape); + 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.color.init(1, "color", "髪の色", &face.hair); + face.hair.flip.init(false, "flip", "反転", &face.hair); + + addObj(&face.eye, "eye"); + face.eye.type.init(2, "type", "種類", &face.eye); + face.eye.color.init(0, "color", "瞳の色", &face.eye); + face.eye.trans_v.init(12.0, "trans_v", "縦移動", &face.eye); + face.eye.trans_u.init(2.0, "trans_u", "横移動", &face.eye); + face.eye.rotate.init(0.0, "rotate", "回転", &face.eye); + face.eye.scale.init(4.0, "scale", "拡縮", &face.eye); + face.eye.aspect.init(3.0, "aspect", "縦拡縮", &face.eye); + face.eye.eyeball_trans_u.init(0.0, "eyeball_trans_u", "瞳上下オフセット", &face.eye); + face.eye.eyeball_trans_v.init(0.0, "eyeball_trans_v", "瞳左右オフセット", &face.eye); + face.eye.eyeball_scale.init(0.0, "eyeball_scale", "瞳拡縮オフセット", &face.eye); + face.eye.highlight_bright.init(0, "highlight_bright", "ハイライトの明るさ", &face.eye); + face.eye.highlight_value = s_eye_highlight_values[0]; + + addObj(&face.eye_ctrl, "eye_ctrl"); + face.eye_ctrl.base_offset.init(s_constants.eye_ctrl_base_offset, "base_offset", + "基準位置オフセット", &face.eye_ctrl); + face.eye_ctrl.translim_out.init(0.2, "translim_out", "外移動量上限", &face.eye_ctrl); + face.eye_ctrl.translim_in.init(0.12, "translim_in", "内移動量上限", &face.eye_ctrl); + face.eye_ctrl.translim_d.init(0.3, "translim_d", "下移動量上限", &face.eye_ctrl); + face.eye_ctrl.translim_u.init(0.1, "translim_u", "上移動量上限", &face.eye_ctrl); + face.eye_ctrl.neck_offset_ud.init(0.0, "neck_offset_ud", "首向け上下角オフセット", + &face.eye_ctrl); + + addObj(&face.eyebrow, "eyebrow"); + face.eyebrow.type.init(0, "type", "種類", &face.eyebrow); + face.eyebrow.color.init(1, "color", "色", &face.eyebrow); + face.eyebrow.trans_v.init(7.0, "trans_v", "縦移動", &face.eyebrow); + face.eyebrow.trans_u.init(2.0, "trans_u", "横移動", &face.eyebrow); + face.eyebrow.rotate.init(0.0, "rotate", "回転", &face.eyebrow); + face.eyebrow.scale.init(4.0, "scale", "拡縮", &face.eyebrow); + face.eyebrow.aspect.init(3.0, "aspect", "縦拡縮", &face.eyebrow); + + addObj(&face.nose, "nose"); + face.nose.type.init(1, "type", "種類", &face.nose); + face.nose.trans_v.init(9.0, "trans_v", "縦移動", &face.nose); + face.nose.scale.init(4.0, "scale", "拡縮", &face.nose); + + addObj(&face.mouth, "mouth"); + face.mouth.type.init(3, "type", "種類", &face.mouth); + face.mouth.color.init(0, "color", "口紅の色", &face.mouth); + face.mouth.trans_v.init(13.0, "trans_v", "縦移動", &face.mouth); + face.mouth.scale.init(4.0, "scale", "拡縮", &face.mouth); + face.mouth.aspect.init(3.0, "aspect", "縦拡縮", &face.mouth); + + addObj(&face.beard, "beard"); + face.beard.mustache.init(0, "mustache", "口髭の種類", &face.beard); + face.beard.scale.init(0.0, "scale", "口髭拡縮", &face.beard); + face.beard.type.init(0, "type", "アゴ髭の種類", &face.beard); + face.beard.color.init(0, "color", "髭の色", &face.beard); + + addObj(&face.glass, "glass"); + face.glass.type.init(0, "type", "種類", &face.glass); + face.glass.color.init(0, "color", "色", &face.glass); + + addObj(&korok, "korog"); // sic + korok.mask.init(0, "mask", "お面", &korok); + korok.skin_color.init(0, "skin_color", "肌の色", &korok); + korok.left_plant.init(0, "left_plant", "手持ち枝(左)", &korok); + korok.right_plant.init(0, "right_plant", "手持ち枝(右)", &korok); + + addObj(&goron, "goron"); + goron.skin_color.init(0, "skin_color", "肌の色", &goron); + + addObj(&gerudo, "gerudo"); + gerudo.hair.init(0, "hair", "髪", &gerudo); + gerudo.hair_color.init(0, "hair_color", "髪の色", &gerudo); + gerudo.glass.init(0, "glass", "眼鏡", &gerudo); + gerudo.glass_color.init(0, "glass_color", "眼鏡の色", &gerudo); + gerudo.skin_color.init(0, "skin_color", "肌の色", &gerudo); + gerudo.lip_color.init(0, "lip_color", "唇の色", &gerudo); + + addObj(&rito, "rito"); + rito.body_color.init(0, "body_color", "身体の色", &rito); + rito.hair_color.init(-1, "hair_color", "髪の色", &rito); + + addObj(&zora, "zora"); + zora.body_color.init(0, "body_color", "身体の色", &zora); +} + +UMii::~UMii() { + mActor = nullptr; + if (mActorParam) { + act::ActorParamMgr::instance()->unloadParam(mActorParam); + mActorParam = nullptr; + } +} + +void UMii::load(agl::utl::ResParameterArchive archive, const sead::SafeString& user, + const u32& load_req_c) { + reset(); + applyResParameterArchive(archive); + mUser = user; + doLoad(load_req_c); + face.eye.highlight_value = s_eye_highlight_values[face.eye.highlight_bright.ref()]; +} + +void UMii::reset() { + mUser = "Dummy"; + + ffsd.no_use_ffsd = false; + ffsd.type = 0; + + body.race = 0; + body.type = 0; + body.number = 0; + body.weight = 1; + body.height = 0; + + personal.sex_age = 1; + personal.fav_color = 0; + personal.sub_color_1 = -1; + personal.sub_color_2 = -1; + personal.head_fav_color = -1; + personal.shoulder_fav_color = -1; + personal.shoulder_sub_color_1 = -1; + personal.personality = sead::SafeString::cEmptyString; + personal.voice_type = "Normal1"; + + common.backpack = -1; + common.hat = -1; + + korok.mask = 0; + korok.skin_color = 0; + korok.left_plant = 0; + korok.right_plant = 0; + + goron.skin_color = 0; + + gerudo.hair = 0; + gerudo.hair_color = 0; + gerudo.glass = 0; + gerudo.glass_color = 0; + gerudo.skin_color = 0; + gerudo.lip_color = 0; + + rito.body_color = 0; + rito.hair_color = -1; + + zora.body_color = 0; +} + +} // namespace ksys::mii diff --git a/src/KingSystem/Mii/miiUMii.h b/src/KingSystem/Mii/miiUMii.h new file mode 100644 index 00000000..dc436974 --- /dev/null +++ b/src/KingSystem/Mii/miiUMii.h @@ -0,0 +1,243 @@ +#pragma once + +#include +#include +#include +#include +#include "KingSystem/Resource/resHandle.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::act { +class Actor; +class ActorParam; +} // namespace ksys::act + +namespace ksys::mii { + +enum class HairType { + Invalid = 0x21, +}; + +class UMiiBase { +public: + virtual ~UMiiBase() = default; +}; + +class UMii : public agl::utl::IParameterIO, public UMiiBase { +public: + struct FFSD : agl::utl::ParameterObj { + agl::utl::Parameter no_use_ffsd; + agl::utl::Parameter type; + }; + KSYS_CHECK_SIZE_NX150(FFSD, 0x70); + + struct Body : agl::utl::ParameterObj { + agl::utl::Parameter race; + agl::utl::Parameter type; + agl::utl::Parameter number; + agl::utl::Parameter weight; + agl::utl::Parameter height; + }; + KSYS_CHECK_SIZE_NX150(Body, 0xd0); + + struct Personal : agl::utl::ParameterObj { + agl::utl::Parameter sex_age; + agl::utl::Parameter fav_color; + agl::utl::Parameter sub_color_1; + agl::utl::Parameter sub_color_2; + agl::utl::Parameter head_fav_color; + agl::utl::Parameter shoulder_fav_color; + agl::utl::Parameter shoulder_sub_color_1; + agl::utl::Parameter personality; + agl::utl::Parameter voice_type; + }; + KSYS_CHECK_SIZE_NX150(Personal, 0x160); + + struct Common : agl::utl::ParameterObj { + agl::utl::Parameter backpack; + agl::utl::Parameter hat; + agl::utl::Parameter no_hat_always; + agl::utl::Parameter body_correct; + agl::utl::Parameter is_mid_age; + agl::utl::Parameter rot_cravicle; + agl::utl::Parameter rot_arm; + agl::utl::Parameter rot_leg; + agl::utl::Parameter rot_crotch; + }; + KSYS_CHECK_SIZE_NX150(Common, 0x150); + + struct Shape : agl::utl::ParameterObj { + agl::utl::Parameter jaw; + agl::utl::Parameter wrinkle; + agl::utl::Parameter make; + agl::utl::Parameter trans_v; + agl::utl::Parameter scale; + agl::utl::Parameter skin_color; + }; + KSYS_CHECK_SIZE_NX150(Shape, 0xf0); + + struct Hair : agl::utl::ParameterObj { + agl::utl::Parameter type; + agl::utl::Parameter color; + agl::utl::Parameter flip; + }; + KSYS_CHECK_SIZE_NX150(Hair, 0x90); + + struct Eye : agl::utl::ParameterObj { + agl::utl::Parameter type; + agl::utl::Parameter color; + agl::utl::Parameter trans_u; + agl::utl::Parameter trans_v; + agl::utl::Parameter rotate; + agl::utl::Parameter scale; + agl::utl::Parameter aspect; + agl::utl::Parameter eyeball_trans_u; + agl::utl::Parameter eyeball_trans_v; + agl::utl::Parameter eyeball_scale; + agl::utl::Parameter highlight_bright; + float highlight_value; + }; + KSYS_CHECK_SIZE_NX150(Eye, 0x198); + + struct EyeCtrl : agl::utl::ParameterObj { + agl::utl::Parameter base_offset; + agl::utl::Parameter translim_out; + agl::utl::Parameter translim_in; + agl::utl::Parameter translim_d; + agl::utl::Parameter translim_u; + agl::utl::Parameter neck_offset_ud; + }; + KSYS_CHECK_SIZE_NX150(EyeCtrl, 0xf8); + + struct Eyebrow : agl::utl::ParameterObj { + agl::utl::Parameter type; + agl::utl::Parameter color; + agl::utl::Parameter trans_u; + agl::utl::Parameter trans_v; + agl::utl::Parameter rotate; + agl::utl::Parameter scale; + agl::utl::Parameter aspect; + }; + KSYS_CHECK_SIZE_NX150(Eyebrow, 0x110); + + struct Nose : agl::utl::ParameterObj { + agl::utl::Parameter type; + agl::utl::Parameter trans_v; + agl::utl::Parameter scale; + }; + KSYS_CHECK_SIZE_NX150(Nose, 0x90); + + struct Mouth : agl::utl::ParameterObj { + agl::utl::Parameter type; + agl::utl::Parameter color; + agl::utl::Parameter trans_v; + agl::utl::Parameter scale; + agl::utl::Parameter aspect; + }; + KSYS_CHECK_SIZE_NX150(Mouth, 0xd0); + + struct Beard : agl::utl::ParameterObj { + agl::utl::Parameter mustache; + agl::utl::Parameter scale; + agl::utl::Parameter type; + agl::utl::Parameter color; + }; + KSYS_CHECK_SIZE_NX150(Beard, 0xb0); + + struct Glass : agl::utl::ParameterObj { + agl::utl::Parameter type; + agl::utl::Parameter color; + }; + KSYS_CHECK_SIZE_NX150(Glass, 0x70); + + struct Korok : agl::utl::ParameterObj { + agl::utl::Parameter mask; + agl::utl::Parameter skin_color; + agl::utl::Parameter left_plant; + agl::utl::Parameter right_plant; + }; + KSYS_CHECK_SIZE_NX150(Korok, 0xb0); + + struct Goron : agl::utl::ParameterObj { + agl::utl::Parameter skin_color; + }; + KSYS_CHECK_SIZE_NX150(Goron, 0x50); + + struct Gerudo : agl::utl::ParameterObj { + agl::utl::Parameter hair; + agl::utl::Parameter hair_color; + agl::utl::Parameter glass; + agl::utl::Parameter glass_color; + agl::utl::Parameter skin_color; + agl::utl::Parameter lip_color; + }; + KSYS_CHECK_SIZE_NX150(Gerudo, 0xf0); + + struct Rito : agl::utl::ParameterObj { + agl::utl::Parameter body_color; + agl::utl::Parameter hair_color; + }; + KSYS_CHECK_SIZE_NX150(Rito, 0x70); + + struct Zora : agl::utl::ParameterObj { + agl::utl::Parameter body_color; + }; + KSYS_CHECK_SIZE_NX150(Zora, 0x50); + + struct Face { + Shape shape; + Hair hair; + Eye eye; + EyeCtrl eye_ctrl; + Eyebrow eyebrow; + Nose nose; + Mouth mouth; + Beard beard; + Glass glass; + }; + KSYS_CHECK_SIZE_NX150(Face, 0x7a0); + + UMii(); + ~UMii() override; + + const sead::SafeString& getUser() const { return mUser; } + const FFSD& getFFSD() const { return ffsd; } + const Body& getBody() const { return body; } + const Personal& getPersonal() const { return personal; } + const Common& getCommon() const { return common; } + const Face& getFace() const { return face; } + const Korok& getKorok() const { return korok; } + const Goron& getGoron() const { return goron; } + const Gerudo& getGerudo() const { return gerudo; } + const Rito& getRito() const { return rito; } + const Zora& getZora() const { return zora; } + + void load(agl::utl::ResParameterArchive archive, const sead::SafeString& user, + const u32& load_req_c); + +private: + void reset(); + void doLoad(const u32& load_req_c); + + /// Name of the UMii config file ("user" in ActorLink). + sead::FixedSafeString<64> mUser; + + FFSD ffsd; + Body body; + Personal personal; + Common common; + Face face; + Korok korok; + Goron goron; + Gerudo gerudo; + Rito rito; + Zora zora; + + act::Actor* mActor = nullptr; + act::ActorParam* mActorParam = nullptr; + res::Handle mResHandle; + sead::SafeString mActorName = sead::SafeString::cEmptyString; +}; +KSYS_CHECK_SIZE_NX150(UMii, 0x10e0); + +} // namespace ksys::mii