#include "KingSystem/Resource/Actor/resResourceASSetting.h" #include #include #include #include "KingSystem/Resource/Actor/resResourceASResourceExtension.h" #include "KingSystem/Resource/Actor/resResourceASSettingMgr.h" #include "KingSystem/Resource/resLoadRequest.h" namespace ksys::res { bool ASFrameCtrlParser::parse(const ASParamParser::ParseArgs& args) { mRate.init(1.0, "Rate", "再生速度", "Min=0.f,Max=10.f", &mObj); mStartFrame.init(0.0, "StartFrame", "開始フレーム", "Min=0.f,Max=100.f", &mObj); mEndFrame.init(-1.0, "EndFrame", "終了フレーム", "Min=-1.f,Max=100.f", &mObj); mLoopStopCount.init(-1.0, "LoopStopCount", "ループ停止回数", "Min=-1.f,Max=10.f", &mObj); mLoopStopCountRandom.init(0.0, "LoopStopCountRandom", "ランダムループ追加回数", "Min=0.f,Max=10.f", &mObj); mReversePlay.init(false, "ReversePlay", "逆再生", "", &mObj); mUseGlobalFrame.init(false, "UseGlobalFrame", "グローバルフレーム使う", "", &mObj); mFootType.init(0, "FootType", "足解決", "", &mObj); mConnect.init(false, "Connect", "接続", "", &mObj); mAnmLoop.init(0, "AnmLoop", "ループ設定", "", &mObj); mList.addObj(&mObj, "FrameCtrl0"); return true; } bool ASTriggerEventsParser::parse(const ASParamParser::ParseArgs& args) { const int num_objs = args.res_list.getResParameterObjNum(); if (num_objs == 0) return true; if (!mEvents.tryAllocBuffer(num_objs, args.heap)) return false; auto it = mEvents.begin(); const auto end = mEvents.end(); sead::FixedSafeString<32> obj_name{"Event"}; const auto obj_name_prefix_len = obj_name.calcLength(); auto res_it = args.res_list.objBegin(); const auto res_end = args.res_list.objEnd(); while (res_it != res_end && it != end) { u32 type_index = -1; const auto TypeIndex = agl::utl::getResParameter(res_it.getObj(), "TypeIndex"); if (TypeIndex.ptr()) type_index = *TypeIndex.getData(); // TODO: add a TypeIndex enum it->type_index = type_index > 33 ? 88 : int(type_index) + 54; it->frame.init(0.0, "Frame", "フレーム", "Min=0.f,Max=100.f", &it->obj); it->value.init("", "Value", "値", "", &it->obj); obj_name.trim(obj_name_prefix_len); obj_name.appendWithFormat("%d", it.getIndex()); mList.addObj(&it->obj, obj_name); ++res_it; ++it; } return true; } bool ASHoldEventsParser::parse(const ASParamParser::ParseArgs& args) { const int num_objs = args.res_list.getResParameterObjNum(); if (num_objs == 0) return true; if (!mEvents.tryAllocBuffer(num_objs, args.heap)) return false; auto it = mEvents.begin(); const auto end = mEvents.end(); sead::FixedSafeString<32> obj_name{"Event"}; const auto obj_name_prefix_len = obj_name.calcLength(); auto res_it = args.res_list.objBegin(); const auto res_end = args.res_list.objEnd(); while (res_it != res_end && it != end) { u32 type_index = -1; const auto TypeIndex = agl::utl::getResParameter(res_it.getObj(), "TypeIndex"); if (TypeIndex.ptr()) type_index = *TypeIndex.getData(); // TODO: add a TypeIndex enum it->type_index = type_index > 53 ? 88 : int(type_index); it->start_frame.init(0.0, "StartFrame", "開始フレーム", "Min=0.f,Max=100.f", &it->obj); it->end_frame.init(0.0, "EndFrame", "終了フレーム", "Min=0.f,Max=100.f", &it->obj); it->value.init("", "Value", "値", "", &it->obj); obj_name.trim(obj_name_prefix_len); obj_name.appendWithFormat("%d", it.getIndex()); mList.addObj(&it->obj, obj_name); ++res_it; ++it; } return true; } bool ASStringArrayParser::parse(const ASParamParser::ParseArgs& args) { const int size = args.res_list.getResParameterObj(0).getNum(); if (size != 0) { if (!mValues.tryAllocBuffer(size, args.heap)) return false; sead::FixedSafeString<32> param_name{"Value"}; const auto param_name_prefix_len = param_name.calcLength(); for (int i = 0; i < size; ++i) { param_name.trim(param_name_prefix_len); param_name.appendWithFormat("%d", i); mValues[i].value.init("", param_name, "値", "", &mObj); } } mList.addObj(&mObj, "StringArray0"); return true; } bool ASRangesParser::parse(const ASParamParser::ParseArgs& args) { const int num_objs = args.res_list.getResParameterObjNum(); if (num_objs == 0) return true; if (!mRanges.tryAllocBuffer(num_objs, args.heap)) return false; auto it = mRanges.begin(); const auto end = mRanges.end(); sead::FixedSafeString<32> obj_name{"Range"}; const auto obj_name_prefix_len = obj_name.calcLength(); auto res_it = args.res_list.objBegin(); const auto res_end = args.res_list.objEnd(); while (res_it != res_end && it != end) { obj_name.trim(obj_name_prefix_len); obj_name.appendWithFormat("%d", it.getIndex()); it->start.init(0.0, "Start", "開始", "Min=0.f,Max=1.f", &it->obj); it->end.init(0.0, "End", "終了", "Min=0.f,Max=1.f", &it->obj); mList.addObj(&it->obj, obj_name); ++res_it; ++it; } return true; } bool ASFloatArrayParser::parse(const ASParamParser::ParseArgs& args) { const int size = args.res_list.getResParameterObj(0).getNum(); if (size != 0) { if (!mValues.tryAllocBuffer(size, args.heap)) return false; sead::FixedSafeString<32> param_name{"Value"}; const auto param_name_prefix_len = param_name.calcLength(); for (int i = 0; i < size; ++i) { param_name.trim(param_name_prefix_len); param_name.appendWithFormat("%d", i); mValues[i].value.init(1.0, param_name, "値", "", &mObj); } } mList.addObj(&mObj, "FloatArray0"); return true; } bool ASIntArrayParser::parse(const ASParamParser::ParseArgs& args) { const int size = args.res_list.getResParameterObj(0).getNum(); if (size != 0) { if (!mValues.tryAllocBuffer(size, args.heap)) return false; sead::FixedSafeString<32> param_name{"Value"}; const auto param_name_prefix_len = param_name.calcLength(); for (int i = 0; i < size; ++i) { param_name.trim(param_name_prefix_len); param_name.appendWithFormat("%d", i); mValues[i].value.init(1, param_name, "値", "", &mObj); } } mList.addObj(&mObj, "IntArray0"); return true; } bool ASBitIndexParser::parse(const ASParamParser::ParseArgs& args) { const auto obj = args.res_list.getResParameterObj(0); if (obj.getNum() < 1) return true; const auto TypeIndex = agl::utl::getResParameter(obj, "TypeIndex"); if (!TypeIndex.ptr()) return true; mTypeIndex = *TypeIndex.getData(); return true; } bool ASSetting::BoneParams::parse(const ASParamParser::ParseArgs& args) { const auto num_objects = args.res_list.getResParameterObjNum(); if (num_objects == 0) return true; if (!mBuffer.tryAllocBuffer(num_objects, args.heap)) return false; auto it = mBuffer.begin(); const auto end = mBuffer.end(); sead::FixedSafeString<32> obj_name{"BoneParam"}; const auto obj_name_base_len = obj_name.calcLength(); auto res_it = args.res_list.objBegin(); const auto res_end = args.res_list.objEnd(); for (; it != end && res_it != res_end; ++it, ++res_it) { it->mBone.init("", "Bone", "ボーン名", "", &it->mObj); it->mWeight.init(0.0, "Weight", "ウェイト値", "Min=0.f,Max=1.f", &it->mObj); obj_name.trim(obj_name_base_len); obj_name.appendWithFormat("%d", res_it.getIndex()); mList.addObj(&it->mObj, obj_name); } return true; } f32 ASSetting::BoneParams::getBoneWeight(const sead::SafeString& name) const { for (const auto& param : mBuffer) { if (name == *param.mBone) return *param.mWeight; } return 1.0; } namespace { struct Factory { const char* name; ASParamParser* (*make)(sead::Heap* heap); }; extern sead::SafeArray sASFactories; } // namespace ASExtensions::~ASExtensions() { for (auto*& parser : mParsers) { if (parser && parser->getType() != ASParamParser::Type::BlenderBone) delete parser; parser = nullptr; } mParsers.freeBuffer(); } bool ASExtensions::parse(const ASExtensions::ParseArgs& args) { const auto Extend = agl::utl::getResParameterList(args.res_list, "Extend"); if (!Extend) return true; const auto num_extensions = Extend.getResParameterListNum(); if (num_extensions == 0) return true; if (!mParsers.tryAllocBuffer(num_extensions, args.heap)) return false; mParsers.fill(nullptr); auto it = mParsers.begin(); const auto end = mParsers.end(); ASParamParser::ParseArgs parse_args{}; parse_args.list = &mList; parse_args.heap = args.heap; auto res_it = Extend.listBegin(); const auto res_end = Extend.listEnd(); for (; it != end && res_it != res_end; ++it, ++res_it) { parse_args.res_list = res_it.getList(); *it = makeParser(parse_args); constexpr int bone = int(ASParamParser::Type::BlenderBone); if (*it == nullptr && parse_args.res_list.getParameterListNameHash() != agl::utl::ParameterBase::calcHash(sASFactories[bone].name)) { return false; } } args.list->addList(&mList, "Extend"); return true; } ASParamParser* ASExtensions::makeParser(const ASParamParser::ParseArgs& args) const { const auto is_factory = [&args](int i) { return args.res_list.getParameterListNameHash() == agl::utl::ParameterBase::calcHash(sASFactories[i].name); }; std::optional type; for (int i = 0; i < ASParamParser::NumTypes - 1; ++i) { if (!is_factory(i)) continue; type = i; break; } if (!type.has_value() && is_factory(int(ASParamParser::Type::BlenderBone))) { const auto obj = args.res_list.getResParameterObj(0); if (obj.getNum() > 0) { const sead::SafeString name = obj.getResParameter(0).getData(); return ASSettingMgr::instance()->getBoneParams(name); } } if (!type.has_value()) return nullptr; const auto& factory = sASFactories[*type]; auto* parser = factory.make(args.heap); if (!parser) return nullptr; if (!parser->parse(args)) { delete parser; return nullptr; } args.list->addList(&parser->getList(), factory.name); return parser; } // NON_MATCHING: sead::DirectResource to res::ASSetting cast nullptr check; branching for the return ASParamParser* ASSettingMgr::getBoneParams(const sead::SafeString& key) const { auto* res = sead::DynamicCast(mHandle.getResource()); if (!res) return nullptr; for (auto& bones : res->getBlenderBones()) { if (key == bones.mKeyName.ref()) return &bones.mBoneParams; } return nullptr; } ASParamParser* ASExtensions::getParser(ASParamParser::Type type) const { for (int i = 0, n = mParsers.size(); i < n; ++i) { auto* parser = mParsers[i]; if (parser && parser->getType() == type) return parser; } return nullptr; } ASSetting::ASSetting() { mType = "assetting"; mVersion = 0; } ASSetting::~ASSetting() { mBlenderBones.freeBuffer(); } void ASSetting::doCreate_(u8* buffer, u32 buffer_size, sead::Heap* heap) {} bool allocBlenderBones(sead::Buffer& buffer, int size, sead::Heap* heap, int align = sizeof(void*)); bool ASSetting::parse_(u8* data, size_t size, sead::Heap* heap) { if (!data) return true; agl::utl::ResParameterArchive archive{data}; const auto root = archive.getRootList(); addList(&mBlenderBoneList, "BlenderBone"); const auto lists = agl::utl::getResParameterList(root, "BlenderBone"); if (!lists.ptr()) return true; const auto num_blender_bones = lists.getResParameterListNum(); if (num_blender_bones == 0) return true; if (!allocBlenderBones(mBlenderBones, num_blender_bones, heap)) return false; auto res_it = lists.listBegin(); const auto res_it_end = lists.listEnd(); sead::FixedSafeString<32> list_name{"BlenderBone"}; const auto list_name_base_len = list_name.calcLength(); ASParamParser::ParseArgs args; args.res_list = {}; args.heap = heap; auto it = mBlenderBones.begin(); const auto end = mBlenderBones.end(); for (; it != end && res_it != res_it_end; ++it, ++res_it) { list_name.trim(list_name_base_len); list_name.appendWithFormat("%d", it.getIndex()); mBlenderBoneList.addList(&it->mList, list_name); it->mKeyName.init("", "KeyName", "キー名", "", &it->mNameParamObj); it->mList.addObj(&it->mNameParamObj, "NameParam"); it->mList.addList(&it->mBoneParams.getList(), "BoneParam"); const auto list = *res_it; args.list = &it->mList; args.res_list = agl::utl::getResParameterList(list, "BoneParam"); if (!it->mBoneParams.parse(args)) return false; } applyResParameterArchive(archive); return true; } bool allocBlenderBones(sead::Buffer& buffer, int size, sead::Heap* heap, int align) { return buffer.tryAllocBuffer(size, heap, align); } SEAD_SINGLETON_DISPOSER_IMPL(ASSettingMgr) void ASSettingMgr::init(const sead::SafeString& config_path, sead::Heap* heap) { LoadRequest req; req.mRequester = "ASSetting"; req._22 = true; mHandle.load(config_path, &req); } template static ASParamParser* factoryImpl_(sead::Heap* heap) { return new (heap) T; } static ASParamParser* dummyASParserFactoryImpl_(sead::Heap*) { return nullptr; } namespace { sead::SafeArray sASFactories{{ {"FrameCtrl", factoryImpl_}, {"TriggerEvents", factoryImpl_}, {"HoldEvents", factoryImpl_}, {"StringArray", factoryImpl_}, {"Ranges", factoryImpl_}, {"FloatArray", factoryImpl_}, {"IntArray", factoryImpl_}, {"BitIndex", factoryImpl_}, {"BlenderBone", dummyASParserFactoryImpl_}, }}; } // namespace } // namespace ksys::res