diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 1c42ba29..8da4fc34 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -37218,14 +37218,14 @@ 0x0000007100615afc,AI_Behavior_AcceptLSwordDamageDCCallback::dtorDelete,96, 0x0000007100615b5c,AI_Behavior_AcceptLSwordDamageDCCallback::rtti1,288, 0x0000007100615c7c,AI_Behavior_AcceptLSwordDamageDCCallback::rtti2,92, -0x0000007100615cd8,AI_BehaviorBase::m4,8,_ZN4ksys3act2ai8Behavior2m4Ev -0x0000007100615ce0,AI_BehaviorBase::m5,8,_ZN4ksys3act2ai8Behavior2m5Ev +0x0000007100615cd8,AI_BehaviorBase::m4,8,_ZN4ksys3act2ai8Behavior14hasPreDeleteCbEv +0x0000007100615ce0,AI_BehaviorBase::m5,8,_ZN4ksys3act2ai8Behavior23hasUpdateForPreDeleteCbEv 0x0000007100615ce8,AI_BehaviorBase::m11_null,4,_ZN4ksys3act2ai8Behavior3m11Ev -0x0000007100615cec,AI_BehaviorBase::m12,8,_ZN4ksys3act2ai8Behavior3m12Ev -0x0000007100615cf4,AI_BehaviorBase::m13_null,4,_ZN4ksys3act2ai8Behavior3m13Ev +0x0000007100615cec,AI_BehaviorBase::m12,8,_ZN4ksys3act2ai8Behavior18updateForPreDeleteEv +0x0000007100615cf4,AI_BehaviorBase::m13_null,4,_ZN4ksys3act2ai8Behavior11onPreDeleteEv 0x0000007100615cf8,AI_Behavior_AcceptLSwordDamageDCCallback::m14,8, 0x0000007100615d00,sub_7100615D00,140, -0x0000007100615d8c,sub_7100615D8C,140, +0x0000007100615d8c,sub_7100615D8C,140,_ZNK4sead15RuntimeTypeInfo6DeriveIN4ksys3act2ai8BehaviorEE9isDerivedEPKNS0_9InterfaceE 0x0000007100615e18,AI_Behavior_ActorFlagSetterAttensionNotice::ctor,52, 0x0000007100615e4c,AI_Behavior_ActorFlagSetterAttensionNotice::dtor_null,4, 0x0000007100615e50,j__ZdlPv_139,4, @@ -73145,13 +73145,13 @@ 0x0000007100d24e54,AI_BehaviorBase::m1,92,_ZNK4ksys3act2ai8Behavior18getRuntimeTypeInfoEv 0x0000007100d24eb0,AI_BehaviorBase::dtorDelete,4,_ZN4ksys3act2ai8BehaviorD0Ev 0x0000007100d24eb4,AI_BehaviorBase::m8_null,4,_ZN4ksys3act2ai8Behavior2m8Ev -0x0000007100d24eb8,ai::Behaviors::ctor,28, -0x0000007100d24ed4,sub_7100D24ED4,4, -0x0000007100d24ed8,sub_7100D24ED8,200, -0x0000007100d24fa0,ai::Behaviors::init,1212, -0x0000007100d2545c,sub_7100D2545C,32, -0x0000007100d2547c,sub_7100D2547C,96, -0x0000007100d254dc,sub_7100D254DC,68, +0x0000007100d24eb8,ai::Behaviors::ctor,28,_ZN4ksys3act2ai9BehaviorsC1Ev +0x0000007100d24ed4,sub_7100D24ED4,4,_ZN4ksys3act2ai9BehaviorsD1Ev +0x0000007100d24ed8,sub_7100D24ED8,200,_ZN4ksys3act2ai9Behaviors8finalizeEv +0x0000007100d24fa0,ai::Behaviors::init,1212,_ZN4ksys3act2ai9Behaviors4initEPNS0_5ActorEPN4sead4HeapE +0x0000007100d2545c,sub_7100D2545C,32,_ZN4ksys3act2ai9Behaviors12setFactoriesEiPNS1_15BehaviorFactoryE +0x0000007100d2547c,sub_7100D2547C,96,_ZNK4ksys3act2ai9Behaviors18updateForPreDeleteEv +0x0000007100d254dc,sub_7100D254DC,68,_ZNK4ksys3act2ai9Behaviors11onPreDeleteEv 0x0000007100d25520,sub_7100D25520,100, 0x0000007100d25584,sub_7100D25584,108, 0x0000007100d255f0,ActorDebug::createInstance,136, @@ -74337,10 +74337,10 @@ 0x0000007100d66d64,ai::ActorAI::rtti2,92,_ZNK4ksys3act2ai6RootAi18getRuntimeTypeInfoEv 0x0000007100d66dc0,ai::ActorAI::m6,8,_ZNK4ksys3act2ai6RootAi10isFlag4SetEv 0x0000007100d66dc8,sub_7100D66DC8,160, -0x0000007100d66e68,AI_BehaviorDummy::ctor,48, -0x0000007100d66e98,AI_BehaviorDummy::rtti1,204, -0x0000007100d66f64,AI_BehaviorDummy::rtti2,92, -0x0000007100d66fc0,j__ZdlPv_856,4, +0x0000007100d66e68,AI_BehaviorDummy::ctor,48,_ZN4ksys3act2ai13DummyBehaviorC1ERKNS1_8Behavior7InitArgE +0x0000007100d66e98,AI_BehaviorDummy::rtti1,204,_ZNK4ksys3act2ai13DummyBehavior27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x0000007100d66f64,AI_BehaviorDummy::rtti2,92,_ZNK4ksys3act2ai13DummyBehavior18getRuntimeTypeInfoEv +0x0000007100d66fc0,j__ZdlPv_856,4,_ZN4ksys3act2ai13DummyBehaviorD0Ev 0x0000007100d66fc4,AI_Behavior_ShowConstStringBoard::ctor,240, 0x0000007100d670b4,AI_Behavior_ShowConstStringBoard::m8,4, 0x0000007100d670b8,AI_Behavior_ShowConstStringBoard::m7,284, diff --git a/src/KingSystem/ActorSystem/CMakeLists.txt b/src/KingSystem/ActorSystem/CMakeLists.txt index ba1bddb1..ac059bc1 100644 --- a/src/KingSystem/ActorSystem/CMakeLists.txt +++ b/src/KingSystem/ActorSystem/CMakeLists.txt @@ -68,4 +68,6 @@ target_sources(uking PRIVATE actionDummyAction.h aiDummyAi.cpp aiDummyAi.h + behaviorDummyBehavior.cpp + behaviorDummyBehavior.h ) diff --git a/src/KingSystem/ActorSystem/actAiActionBase.cpp b/src/KingSystem/ActorSystem/actAiActionBase.cpp index 6de513f2..b169813c 100644 --- a/src/KingSystem/ActorSystem/actAiActionBase.cpp +++ b/src/KingSystem/ActorSystem/actAiActionBase.cpp @@ -1,10 +1,10 @@ #include "KingSystem/ActorSystem/actAiActionBase.h" +#include "KingSystem/ActorSystem/actActor.h" #include "KingSystem/ActorSystem/actActorParam.h" #include "KingSystem/ActorSystem/actAiAction.h" #include "KingSystem/ActorSystem/actAiRoot.h" #include "KingSystem/Resource/resResourceAIProgram.h" #include "KingSystem/Utils/InitTimeInfo.h" -#include "KingSystem/ActorSystem/actActor.h" namespace ksys::act::ai { @@ -119,7 +119,7 @@ void ActionBase::updateBehaviorsOnEnter() { auto* root = mActor->getRootAi(); for (auto indice : *indices) - root->setBehavior(root->getBehaviors().classes[indice]); + root->setBehavior(root->getBehaviors().getClasses()[indice]); } bool ActionBase::takeOver(ActionBase* src, const sead::SafeString& context) { @@ -200,7 +200,7 @@ void ActionBase::updateBehaviorsOnLeave() { auto* root = mActor->getRootAi(); for (auto indice : *indices) - root->resetBehavior(root->getBehaviors().classes[indice]); + root->resetBehavior(root->getBehaviors().getClasses()[indice]); } bool ActionBase::oneShot(InlineParamPack* params) { diff --git a/src/KingSystem/ActorSystem/actAiBehavior.cpp b/src/KingSystem/ActorSystem/actAiBehavior.cpp index e60780fe..28781e3c 100644 --- a/src/KingSystem/ActorSystem/actAiBehavior.cpp +++ b/src/KingSystem/ActorSystem/actAiBehavior.cpp @@ -1,9 +1,137 @@ #include "KingSystem/ActorSystem/actAiBehavior.h" +#include "KingSystem/ActorSystem/actActor.h" +#include "KingSystem/ActorSystem/actActorParam.h" #include "KingSystem/ActorSystem/actAiRoot.h" +#include "KingSystem/ActorSystem/behaviorDummyBehavior.h" +#include "KingSystem/Resource/resResourceAIProgram.h" namespace ksys::act::ai { Behavior::Behavior(const InitArg& arg) : mActor(arg.actor), mDefIdx(static_cast(arg.def_idx)) {} +Behaviors::Behaviors() = default; + +Behaviors::~Behaviors() { + finalize(); +} + +void Behaviors::finalize() { + for (s32 i = 0; i < mClasses.size(); ++i) { + if (mClasses[i]) { + delete mClasses[i]; + mClasses[i] = nullptr; + } + } + + mOnPreDeleteCbs.freeBuffer(); + mUpdateForPreDeleteCbs.freeBuffer(); + mClasses.freeBuffer(); +} + +bool Behaviors::init(Actor* actor, sead::Heap* heap) { + const auto* aiprog = actor->getParam()->getRes().mAIProgram; + + const auto num_behaviors = aiprog->getBehaviors().size(); + if (num_behaviors == 0) + return true; + + if (!mClasses.tryAllocBuffer(num_behaviors, heap)) + return false; + for (s32 i = 0, n = mClasses.size(); i != n; ++i) + mClasses(i) = nullptr; + auto it_class = mClasses.begin(); + const auto it_class_end = mClasses.end(); + + Behavior::InitArg arg; + arg.actor = actor; + s32 predelete_cb_num = 0; + s32 update_cb_num = 0; + for (; it_class != it_class_end; ++it_class) { + arg.def_idx = it_class.getIndex(); + const char* name = aiprog->getBehaviors()[it_class.getIndex()].mClassName; + + auto* factory = getFactory(name); + if (factory) + *it_class = factory->create_fn(arg, heap); + else + *it_class = new (heap) DummyBehavior(arg); + + if (!*it_class) + return false; + + update_cb_num += (*it_class)->hasUpdateForPreDeleteCb(); + predelete_cb_num += (*it_class)->hasPreDeleteCb(); + } + + // Allocate the callback lists. + if (predelete_cb_num != 0) { + if (!mOnPreDeleteCbs.tryAllocBuffer(predelete_cb_num, heap)) + return false; + for (s32 i = 0; i < predelete_cb_num; ++i) + mOnPreDeleteCbs(i) = nullptr; + } + + if (update_cb_num != 0) { + if (!mUpdateForPreDeleteCbs.tryAllocBuffer(update_cb_num, heap)) + return false; + for (s32 i = 0; i < update_cb_num; ++i) + mUpdateForPreDeleteCbs(i) = nullptr; + } + + // Initialize each class. + s32 idx_cb1 = 0, idx_cb2 = 0; + for (auto it = mClasses.begin(), end = mClasses.end(); it != end; ++it) { + if (!(*it)->init(heap)) + return false; + + if ((*it)->hasUpdateForPreDeleteCb()) { + mUpdateForPreDeleteCbs[idx_cb2] = *it; + ++idx_cb2; + } + + if ((*it)->hasPreDeleteCb()) { + mOnPreDeleteCbs[idx_cb1] = *it; + ++idx_cb1; + } + } + + return true; +} + +bool Behaviors::updateForPreDelete() const { + bool ok = true; + for (auto* cb : mUpdateForPreDeleteCbs) { + if (cb) + ok &= cb->updateForPreDelete(); + } + return ok; +} + +void Behaviors::onPreDelete() const { + for (auto* cb : mOnPreDeleteCbs) { + if (cb) + cb->onPreDelete(); + } +} + +BehaviorFactory* Behaviors::getFactory(const sead::SafeString& name) { + const u32 name_hash = sead::HashCRC32::calcStringHash(name); + const s32 idx = sFactories.binarySearch( + name_hash, +[](const BehaviorFactory& factory, const u32& hash) { + if (factory.hash < hash) + return -1; + if (factory.hash > hash) + return 1; + return 0; + }); + if (idx < 0) + return nullptr; + return sFactories.get(idx); +} + +void Behaviors::setFactories(int count, BehaviorFactory* factories) { + sFactories.setBuffer(count, factories); +} + } // namespace ksys::act::ai diff --git a/src/KingSystem/ActorSystem/actAiBehavior.h b/src/KingSystem/ActorSystem/actAiBehavior.h index 993556ca..51d2ea93 100644 --- a/src/KingSystem/ActorSystem/actAiBehavior.h +++ b/src/KingSystem/ActorSystem/actAiBehavior.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "KingSystem/Utils/Types.h" namespace ksys::act { @@ -25,16 +26,18 @@ public: explicit Behavior(const InitArg& arg); virtual ~Behavior() = default; - virtual bool m4() { return false; } - virtual bool m5() { return false; } + bool init(sead::Heap* heap); + + virtual bool hasPreDeleteCb() { return false; } + virtual bool hasUpdateForPreDeleteCb() { return false; } virtual bool m6() { return true; } virtual void m7() {} virtual void m8() {} virtual void m9() {} virtual void m10() {} virtual void m11() {} - virtual bool m12() { return true; } - virtual void m13() {} + virtual bool updateForPreDelete() { return true; } + virtual void onPreDelete() {} protected: Actor* mActor{}; @@ -46,6 +49,12 @@ protected: }; KSYS_CHECK_SIZE_NX150(Behavior, 0x28); +struct BehaviorFactory { + using CreateFn = Behavior* (*)(const Behavior::InitArg& arg, sead::Heap* heap); + u32 hash; + CreateFn create_fn; +}; + class Behaviors { public: Behaviors(); @@ -53,11 +62,22 @@ public: void finalize(); - sead::Buffer classes; - // TODO: rename - sead::Buffer x; - // TODO: rename - sead::Buffer y; + bool init(Actor* actor, sead::Heap* heap); + bool updateForPreDelete() const; + void onPreDelete() const; + + const sead::Buffer& getClasses() const { return mClasses; } + + static BehaviorFactory* getFactory(const sead::SafeString& name); + static void setFactories(int count, BehaviorFactory* factories); + +private: + static inline sead::Buffer sFactories; + sead::Buffer mClasses; + // Non-owning buffer. + sead::Buffer mOnPreDeleteCbs; + // Non-owning buffer. + sead::Buffer mUpdateForPreDeleteCbs; }; } // namespace ksys::act::ai diff --git a/src/KingSystem/ActorSystem/behaviorDummyBehavior.cpp b/src/KingSystem/ActorSystem/behaviorDummyBehavior.cpp new file mode 100644 index 00000000..660461f5 --- /dev/null +++ b/src/KingSystem/ActorSystem/behaviorDummyBehavior.cpp @@ -0,0 +1,7 @@ +#include "KingSystem/ActorSystem/behaviorDummyBehavior.h" + +namespace ksys::act::ai { + +DummyBehavior::DummyBehavior(const Behavior::InitArg& arg) : Behavior(arg) {} + +} // namespace ksys::act::ai diff --git a/src/KingSystem/ActorSystem/behaviorDummyBehavior.h b/src/KingSystem/ActorSystem/behaviorDummyBehavior.h new file mode 100644 index 00000000..bc160223 --- /dev/null +++ b/src/KingSystem/ActorSystem/behaviorDummyBehavior.h @@ -0,0 +1,13 @@ +#pragma once + +#include "KingSystem/ActorSystem/actAiBehavior.h" + +namespace ksys::act::ai { + +class DummyBehavior : public Behavior { + SEAD_RTTI_OVERRIDE(DummyBehavior, Behavior) +public: + explicit DummyBehavior(const InitArg& arg); +}; + +} // namespace ksys::act::ai