summaryrefslogtreecommitdiff
path: root/src/KingSystem/ActorSystem/actAiQueries.cpp
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2020-12-21 16:41:28 +0100
committerLéo Lam <leo@leolam.fr>2020-12-21 16:53:44 +0100
commitb1470e45fad6a43bb2583aed7f6e9bce3172f0bf (patch)
tree52314b2d75328d3166a7b6ed6ab74559752cf0f4 /src/KingSystem/ActorSystem/actAiQueries.cpp
parent64b93c984e2109771f7b8210f6906f2069316ba1 (diff)
ksys/act: Add Queries
Diffstat (limited to 'src/KingSystem/ActorSystem/actAiQueries.cpp')
-rw-r--r--src/KingSystem/ActorSystem/actAiQueries.cpp143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/KingSystem/ActorSystem/actAiQueries.cpp b/src/KingSystem/ActorSystem/actAiQueries.cpp
new file mode 100644
index 00000000..5d900bcc
--- /dev/null
+++ b/src/KingSystem/ActorSystem/actAiQueries.cpp
@@ -0,0 +1,143 @@
+#include "KingSystem/ActorSystem/actAiQueries.h"
+#include <codec/seadHashCRC32.h>
+#include "KingSystem/ActorSystem/actActor.h"
+#include "KingSystem/ActorSystem/actActorParam.h"
+#include "KingSystem/ActorSystem/actAiQuery.h"
+#include "KingSystem/ActorSystem/queryDummyQuery.h"
+#include "KingSystem/Resource/resResourceAIProgram.h"
+
+namespace ksys::act::ai {
+
+Queries::Queries() = default;
+
+Queries::~Queries() {
+ finalize();
+}
+
+void Queries::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 Queries::init(Actor* actor, sead::Heap* heap) {
+ const auto* aiprog = actor->getParam()->getRes().mAIProgram;
+
+ const auto num_Queries = aiprog->getQueries().size();
+ if (num_Queries == 0)
+ return true;
+
+ if (!mClasses.tryAllocBuffer(num_Queries, 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();
+
+ Query::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->getQueries()[it_class.getIndex()].mClassName;
+
+ auto* factory = getFactory(name);
+ if (factory)
+ *it_class = factory->create_fn(arg, heap);
+ else
+ *it_class = new (heap) DummyQuery(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 Queries::updateForPreDelete() const {
+ bool ok = true;
+ for (auto* cb : mUpdateForPreDeleteCbs) {
+ if (cb)
+ ok &= cb->updateForPreDelete();
+ }
+ return ok;
+}
+
+void Queries::onPreDelete() const {
+ for (auto* cb : mOnPreDeleteCbs) {
+ if (cb)
+ cb->onPreDelete();
+ }
+}
+
+Query* Queries::getQuery(const sead::SafeString& name) const {
+ for (auto* query : mClasses) {
+ if (name == query->getName())
+ return query;
+ }
+ return nullptr;
+}
+
+QueryFactory* Queries::getFactory(const sead::SafeString& name) {
+ const u32 name_hash = sead::HashCRC32::calcStringHash(name);
+ const s32 idx = sFactories.binarySearch(
+ name_hash, +[](const QueryFactory& 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 Queries::setFactories(int count, QueryFactory* factories) {
+ sFactories.setBuffer(count, factories);
+}
+
+} // namespace ksys::act::ai