#include "KingSystem/Resource/resResourceModelList.h" #include #include "KingSystem/Resource/resModelResourceDivide.h" namespace ksys::res { namespace { sead::SafeString str_ModelData{"ModelData"}; sead::SafeString str_Unit{"Unit"}; sead::SafeString str_AnmTarget{"AnmTarget"}; sead::SafeString str_Partial{"Partial"}; sead::SafeArray sLocatorTypes{{ "Trunk", "Branch", "GlowStone", "OnTree", "MagnePos", "StopTimerPos", }}; constexpr u32 NumUnitMax = 8; } // namespace ModelList::ModelList() : ParamIO("modellist", 0) {} ModelList::~ModelList() { for (auto& entry : mModelData) entry.units.freeBuffer(); mModelData.freeBuffer(); for (auto& entry : mAnmTargets) entry.partials.freeBuffer(); mAnmTargets.freeBuffer(); } void ModelList::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} // NON_MATCHING: reorderings bool ModelList::parse_(u8* data, size_t size, sead::Heap* heap) { agl::utl::ResParameterArchive archive{data}; const auto root = archive.getRootList(); const auto model_data_list = agl::utl::getResParameterList(root, str_ModelData); if (model_data_list.ptr() && model_data_list.getResParameterListNum() > 0) { if (!parseModelData(model_data_list, heap)) return false; } addList(&mModelDataList, str_ModelData); const auto anm_target_list = agl::utl::getResParameterList(root, str_AnmTarget); if (anm_target_list.ptr() && anm_target_list.getResParameterListNum() > 0) { if (!parseAnmTarget(anm_target_list, heap)) return false; } addList(&mAnmTargetList, str_AnmTarget); mControllerInfo->mAddColor.init({0.0, 0.0, 0.0, 0.0}, "AddColor", "", &mControllerInfo->mObj); mControllerInfo->mMulColor.init({1.0, 1.0, 1.0, 1.0}, "MulColor", "", &mControllerInfo->mObj); mControllerInfo->mBaseScale.init(sead::Vector3f::ones, "BaseScale", "", &mControllerInfo->mObj); mControllerInfo->mVariationMatAnim.init("", "VariationMatAnim", "", &mControllerInfo->mObj); mControllerInfo->mVariationMatAnimFrame.init(0, "VariationMatAnimFrame", "", &mControllerInfo->mObj); mControllerInfo->mVariationShaderAnim.init("", "VariationShaderAnim", "", &mControllerInfo->mObj); mControllerInfo->mVariationShaderAnimFrame.init(0, "VariationShaderAnimFrame", "", &mControllerInfo->mObj); mControllerInfo->mCalcAABBASKey.init("Wait", "CalcAABBASKey", "", &mControllerInfo->mObj); addObj(&mControllerInfo->mObj, sead::FormatFixedSafeString<128>("ControllerInfo")); mAttention->mIsEnableAttention.init(false, "IsEnableAttention", "", &mAttention->mObj); mAttention->mLookAtBone.init("", "LookAtBone", "", &mAttention->mObj); mAttention->mLookAtOffset.init(sead::Vector3f::zero, "LookAtOffset", "", &mAttention->mObj); mAttention->mCursorOffsetY.init(0.0, "CursorOffsetY", "", &mAttention->mObj); mAttention->mAIInfoOffsetY.init(0.0, "AIInfoOffsetY", "", &mAttention->mObj); mAttention->mCutTargetBone.init("", "CutTargetBone", "", &mAttention->mObj); mAttention->mCutTargetOffset.init(sead::Vector3f::zero, "CutTargetOffset", "", &mAttention->mObj); mAttention->mGameCameraBone.init("", "GameCameraBone", "", &mAttention->mObj); mAttention->mGameCameraOffset.init(sead::Vector3f::zero, "GameCameraOffset", "", &mAttention->mObj); mAttention->mBowCameraBone.init("", "BowCameraBone", "", &mAttention->mObj); mAttention->mBowCameraOffset.init(sead::Vector3f::zero, "BowCameraOffset", "", &mAttention->mObj); mAttention->mAttackTargetBone.init("", "AttackTargetBone", "", &mAttention->mObj); mAttention->mAttackTargetOffset.init(sead::Vector3f::zero, "AttackTargetOffset", "", &mAttention->mObj); mAttention->mAttackTargetOffsetBack.init(0.0, "AttackTargetOffsetBack", "", &mAttention->mObj); mAttention->mAtObstacleChkUseLookAtPos.init(true, "AtObstacleChkUseLookAtPos", "", &mAttention->mObj); mAttention->mAtObstacleChkOffsetBone.init("", "AtObstacleChkOffsetBone", "", &mAttention->mObj); mAttention->mAtObstacleChkOffset.init(sead::Vector3f::zero, "AtObstacleChkOffset", "", &mAttention->mObj); mAttention->mCursorAIInfoBaseBone.init("", "CursorAIInfoBaseBone", "", &mAttention->mObj); mAttention->mCursorAIInfoBaseOffset.init(sead::Vector3f::zero, "CursorAIInfoBaseOffset", "", &mAttention->mObj); addObj(&mAttention->mObj, sead::FormatFixedSafeString<128>("Attention")); if (data) { applyResParameterArchive(agl::utl::ResParameterArchive{data}); mRawData = data; } return true; } bool ModelList::parseModelData(const agl::utl::ResParameterList& res, sead::Heap* heap) { if (!mModelData.tryAllocBuffer(res.getResParameterListNum() != 0, heap)) return false; sead::FixedSafeString<32> list_name{str_ModelData}; list_name.append("_"); const auto list_name_base_len = list_name.calcLength(); for (auto it = mModelData.begin(), it_end = mModelData.end(); it != it_end; ++it) { list_name.trim(list_name_base_len); list_name.appendWithFormat("%d", it.getIndex()); it->folder.init("", "Folder", "", &it->base_obj); it->list.addObj(&it->base_obj, "Base"); const auto unit_list = agl::utl::getResParameterList(res.getResParameterList(it.getIndex()), str_Unit); if (unit_list.ptr()) { const u32 num_units = unit_list.getResParameterObjNum(); if (num_units != 0) { if (!it->units.tryAllocBuffer(std::min(num_units, NumUnitMax), heap)) return false; sead::FixedSafeString<32> unit_name{str_Unit}; unit_name.append("_"); const auto unit_name_base_len = unit_name.calcLength(); for (auto unit = it->units.begin(), end = it->units.end(); unit != end; ++unit) { unit_name.trim(unit_name_base_len); unit_name.appendWithFormat("%d", unit.getIndex()); unit->unit_name.init("", "UnitName", "", &unit->obj); unit->bind_bone.init("", "BindBone", "", &unit->obj); it->unit_list.addObj(&unit->obj, unit_name); } } } it->list.addList(&it->unit_list, str_Unit); mModelDataList.addList(&it->list, list_name); } return true; } bool ModelList::parseAnmTarget(const agl::utl::ResParameterList& res, sead::Heap* heap) { if (!mAnmTargets.tryAllocBuffer(std::min(res.getResParameterListNum(), NumUnitMax), heap)) return false; sead::FixedSafeString<32> list_name{str_AnmTarget}; list_name.append("_"); const auto list_name_base_len = list_name.calcLength(); for (auto it = mAnmTargets.begin(), it_end = mAnmTargets.end(); it != it_end; ++it) { list_name.trim(list_name_base_len); list_name.appendWithFormat("%d", it.getIndex()); it->num_as_slot.init(0, "NumASSlot", "", &it->base_obj); // "is particle enabled" (particle is misspelled as "partical" [sic]) it->is_partical_enable.init(false, "IsParticalEnable", "", &it->base_obj); it->target_type.init(0, "TargetType", "", &it->base_obj); it->list.addObj(&it->base_obj, "Base"); const auto partials = agl::utl::getResParameterList(res.getResParameterList(it.getIndex()), str_Partial); if (partials.ptr() && partials.getResParameterObjNum() != 0) { if (!it->partials.tryAllocBuffer(partials.getResParameterObjNum(), heap)) return false; sead::FixedSafeString<32> partial_name{str_Partial}; partial_name.append("_"); const auto partial_name_base_len = partial_name.calcLength(); for (auto partial = it->partials.begin(), partial_end = it->partials.end(); partial != partial_end; ++partial) { partial_name.trim(partial_name_base_len); partial_name.appendWithFormat("%d", partial.getIndex()); partial->bone.init("", "Bone", "", &partial->obj); partial->bind_flag.init(0, "BindFlg", "", &partial->obj); partial->recursible.init(true, "Recursible", "", &partial->obj); it->partial_list.addObj(&partial->obj, partial_name); } } it->list.addList(&it->partial_list, str_Partial); mAnmTargetList.addList(&it->list, list_name); } return true; } int ModelList::getNumAnmTargets() const { return mAnmTargets.size(); } void ModelList::getModelDataInfo(ModelList::ModelDataInfo* info) const { *info = {}; if (mModelData.size() > 0) { info->num_model_data = mModelData.size(); for (auto it = mModelData.begin(), end = mModelData.end(); it != end; ++it) { const s32 idx = it.getIndex(); info->folder_name[idx] = it->folder.ref().cstr(); info->num_units[idx] = it->units.size(); for (auto unit = it->units.begin(), uend = it->units.end(); unit != uend; ++unit) { const s32 unit_idx = unit.getIndex(); info->unit_names[idx][unit_idx] = unit->unit_name.ref().cstr(); info->unit_bind_bones[idx][unit_idx] = unit->bind_bone.ref().cstr(); } if (info->unit_names[idx][0]) { const char* name = ModelResourceDivide::instance()->getModelResource( info->folder_name[idx], info->unit_names[idx][0]); if (name) info->folder_name[idx] = name; } } } info->base_scale = mControllerInfo->mBaseScale.ref(); } bool ModelList::getAttentionInfo(AttentionInfo* info) const { if (!mAttention->mIsEnableAttention.ref()) { info->look_at_bone = {}; info->look_at_offset = sead::Vector3f::zero; info->cursor_offset_y = {}; info->ai_info_offset_y = {}; info->cut_target_bone = {}; info->cut_target_offset = sead::Vector3f::zero; info->game_camera_bone = {}; info->game_camera_offset = sead::Vector3f::zero; info->bow_camera_bone = {}; info->bow_camera_offset = sead::Vector3f::zero; info->attack_target_bone = {}; info->attack_target_offset = sead::Vector3f::zero; info->attack_target_offset_back = {}; info->cursor_ai_info_base_bone = {}; info->cursor_ai_info_base_offset = sead::Vector3f::zero; return false; } info->look_at_bone = mAttention->mLookAtBone.ref().cstr(); info->look_at_offset = mAttention->mLookAtOffset.ref(); info->cursor_offset_y = mAttention->mCursorOffsetY.ref(); info->ai_info_offset_y = mAttention->mAIInfoOffsetY.ref(); info->cut_target_bone = mAttention->mCutTargetBone.ref().cstr(); info->cut_target_offset = mAttention->mCutTargetOffset.ref(); info->game_camera_bone = mAttention->mGameCameraBone.ref().cstr(); info->game_camera_offset = mAttention->mGameCameraOffset.ref(); info->bow_camera_bone = mAttention->mBowCameraBone.ref().cstr(); info->bow_camera_offset = mAttention->mBowCameraOffset.ref(); info->attack_target_bone = mAttention->mAttackTargetBone.ref().cstr(); info->attack_target_offset = mAttention->mAttackTargetOffset.ref(); info->attack_target_offset_back = mAttention->mAttackTargetOffsetBack.ref(); if (mAttention->mAtObstacleChkUseLookAtPos.ref()) { info->at_obstacle_chk_bone = mAttention->mLookAtBone.ref().cstr(); info->at_obstacle_chk_offset = mAttention->mLookAtOffset.ref(); } else { info->at_obstacle_chk_bone = mAttention->mAtObstacleChkOffsetBone.ref().cstr(); info->at_obstacle_chk_offset = mAttention->mAtObstacleChkOffset.ref(); } info->cursor_ai_info_base_bone = mAttention->mCursorAIInfoBaseBone.ref().cstr(); info->cursor_ai_info_base_offset = mAttention->mCursorAIInfoBaseOffset.ref(); const auto clear_if_empty = [](const char** s) { if (!(*s)[0]) *s = nullptr; }; clear_if_empty(&info->look_at_bone); clear_if_empty(&info->cut_target_bone); clear_if_empty(&info->game_camera_bone); clear_if_empty(&info->bow_camera_bone); clear_if_empty(&info->attack_target_bone); clear_if_empty(&info->at_obstacle_chk_bone); clear_if_empty(&info->cursor_ai_info_base_bone); return true; } act::InfoData::Locator::Type ModelList::getLocatorTypeFromStr(const sead::SafeString& type) { for (s32 i = 0; i < sLocatorTypes.size(); ++i) { if (type == sLocatorTypes[i]) return act::InfoData::Locator::Type(i); } return act::InfoData::Locator::Type::Invalid; } // NON_MATCHING: weird unrolling and Vector3f store (str should be a stp) bool ModelList::getLocatorInfo(act::InfoData::Locator* info, act::InfoData::Locator::Type type) const { agl::utl::ResParameterArchive archive{mRawData}; const auto root = archive.getRootList(); for (int i = 0;; ++i) { const auto obj = agl::utl::getResParameterObj(root, sead::FormatFixedSafeString<32>("Locator_%d", i)); if (!obj.ptr()) return false; const char* expected_type_str = sLocatorTypes[u32(type)]; if (sead::SafeString(getString(obj, "Type", "")) != expected_type_str) continue; info->pos = getVec3(obj, "Pos", sead::Vector3f::zero); info->rot = getVec3(obj, "Rot", sead::Vector3f::zero); info->type = type; return true; } return false; } bool ModelList::isParticalEnable(int anm_target_idx) const { return mAnmTargets[anm_target_idx].is_partical_enable.ref(); } int ModelList::getNumASSlot(int anm_target_idx) const { return mAnmTargets[anm_target_idx].num_as_slot.ref(); } int ModelList::getNumPartials(int anm_target_idx) const { return mAnmTargets[anm_target_idx].partials.size(); } void ModelList::getPartialInfo(PartialInfo* info, int anm_target_idx, int partial_idx) const { if (mAnmTargets.size() > 0) { const auto& partial = mAnmTargets[anm_target_idx].partials[partial_idx]; info->bone = partial.bone.ref(); info->bind_flag = partial.bind_flag.ref(); info->recursible = partial.recursible.ref(); } else { info->bone = ""; info->bind_flag = 0; info->recursible = true; } } } // namespace ksys::res