summaryrefslogtreecommitdiff
path: root/src/KingSystem/ActorSystem/actAiClassDef.cpp
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2020-12-05 12:39:29 +0100
committerLéo Lam <leo@leolam.fr>2020-12-05 17:57:30 +0100
commitd3b065bfa2c36257775a0e92a2ede6003a303ae3 (patch)
tree9f48704d05edeef859b9e9ffa078cc6dbf34b184 /src/KingSystem/ActorSystem/actAiClassDef.cpp
parentfd2f653b6ff54aa552f89c5b8daf79110d4a0e8f (diff)
ksys/act: Implement the rest of AIClassDef
Diffstat (limited to 'src/KingSystem/ActorSystem/actAiClassDef.cpp')
-rw-r--r--src/KingSystem/ActorSystem/actAiClassDef.cpp248
1 files changed, 234 insertions, 14 deletions
diff --git a/src/KingSystem/ActorSystem/actAiClassDef.cpp b/src/KingSystem/ActorSystem/actAiClassDef.cpp
index b9b144c9..6ff69a14 100644
--- a/src/KingSystem/ActorSystem/actAiClassDef.cpp
+++ b/src/KingSystem/ActorSystem/actAiClassDef.cpp
@@ -4,10 +4,11 @@
#include <prim/seadContainerIterator.h>
#include <resource/seadResource.h>
#include "KingSystem/Resource/resLoadRequest.h"
+#include "KingSystem/Utils/Byaml/ByamlData.h"
+#include "KingSystem/Utils/Byaml/ByamlHashIter.h"
namespace ksys {
-namespace {
const char* str_AIAfter = "AIAfter";
const char* str_ModelAfter = "ModelAfter";
const char* str_ChangeDeleteState = "ChangeDeleteState";
@@ -19,7 +20,6 @@ const char* str_AIs = "AIs";
const char* str_Actions = "Actions";
const char* str_Behaviors = "Behaviors";
const char* str_Querys = "Querys";
-} // namespace
SEAD_SINGLETON_DISPOSER_IMPL(AIClassDef)
@@ -48,10 +48,10 @@ bool AIClassDef::Data::load(sead::Heap* heap) {
root_iter.tryGetIterByKey(&iters[s32(AIDefType::Behavior)], str_Behaviors);
root_iter.tryGetIterByKey(&iters[s32(AIDefType::Query)], str_Querys);
- idx_StaticInstParams = root_iter.getKeyIndex(str_StaticInstParams);
- idx_DynamicInstParams = root_iter.getKeyIndex(str_DynamicInstParams);
- idx_MapUnitInstParams = root_iter.getKeyIndex(str_MapUnitInstParams);
- idx_AITreeVariables = root_iter.getKeyIndex(str_AITreeVariables);
+ inst_params_key_idx[0] = root_iter.getKeyIndex(str_StaticInstParams);
+ inst_params_key_idx[1] = root_iter.getKeyIndex(str_DynamicInstParams);
+ inst_params_key_idx[2] = root_iter.getKeyIndex(str_MapUnitInstParams);
+ inst_params_key_idx[3] = root_iter.getKeyIndex(str_AITreeVariables);
idx_Childs = root_iter.getKeyIndex("childs");
static_cast<void>(heap->getFreeSize());
@@ -82,21 +82,241 @@ bool AIClassDef::Data::load(sead::Heap* heap) {
return true;
}
-// NON_MATCHING: binary search might be a handwritten loop?
-bool AIClassDef::isSystemQuery(const sead::SafeString& query) const {
- bool ret = false;
- const u32 hash = sead::HashCRC32::calcStringHash(query);
+s32 AIClassDef::getRawDefIdx(const sead::SafeString& def_name, AIDefType type) const {
+ const auto hash = sead::HashCRC32::calcStringHash(def_name);
if (!mData)
- return false;
+ return -1;
+
+ auto& buffer = mData->defs[s32(type)];
+ if (buffer.size() == 0)
+ return -1;
+
+ s32 a = 0;
+ s32 b = buffer.size() - 1;
+ while (a < b) {
+ const s32 m = (a + b) / 2;
+ auto* def = &buffer(m);
+
+#ifdef MATCHING_HACK_NX_CLANG
+ {
+ // The original code has a bunch of useless comparisons that look like this:
+ // if (def->name_hash < hash == def->name_hash > hash)
+ // Unfortunately it doesn't match when written that way or with a more obvious
+ // equality check. Inline assembly to the rescue.
+ int lt, gt;
+ asm("cmp %w[def_hash], %w[hash]\n"
+ "cset %w[lt], cc\n"
+ "cset %w[gt], hi\n"
+ : [lt] "=r"(lt), [gt] "=r"(gt)
+ : [def_hash] "r"(def->name_hash), [hash] "r"(hash)
+ : "cc");
+ if (gt == lt)
+ return m;
+ }
+#else
+ if (def->name_hash == hash)
+ return m;
+#endif
+
+ if (def->name_hash >= hash)
+ b = m;
+ else
+ a = m + 1;
+ }
+
+ if (buffer(a).name_hash != hash)
+ return -1;
+
+ return a;
+}
+
+void AIClassDef::getDef(const sead::SafeString& class_name, AIDefSet* set,
+ AIDefType class_type) const {
+ set->num_children = 0;
+ set->dynamic_params.num_params = 0;
+ set->map_unit_params.num_params = 0;
+ set->ai_tree_params.num_params = 0;
+
+ const s32 idx = getRawDefIdx(class_name, class_type);
+ if (idx < 0)
+ return;
+
+ const auto* data = mData;
+ const auto& iter = getRawDefs(class_type)[idx].iter;
+
+ if (class_type == AIDefType::AI) {
+ al::ByamlHashIter hash_iter{iter.getRootNode()};
+ al::ByamlData byaml_data;
+ if (hash_iter.getDataByKey(&byaml_data, data->idx_Childs)) {
+ al::ByamlIter it{iter.getData(), iter.getData() + byaml_data.getValue()};
+ if (it.isValid()) {
+ const s32 num_children = it.getSize();
+ for (s32 i = 0; i < num_children; ++i) {
+ if (!it.tryGetStringByIndex(&set->children[set->num_children], i))
+ set->children[set->num_children] = nullptr;
+ ++set->num_children;
+ }
+ }
+ }
+ }
+
+ doGetDef(&set->dynamic_params, iter, AIDefInstParamKind::Dynamic, class_type,
+ data->inst_params_key_idx[s32(AIDefInstParamKind::Dynamic)]);
+ doGetDef(&set->map_unit_params, iter, AIDefInstParamKind::MapUnit, class_type,
+ data->inst_params_key_idx[s32(AIDefInstParamKind::MapUnit)]);
+ doGetDef(&set->ai_tree_params, iter, AIDefInstParamKind::AITree, class_type,
+ data->inst_params_key_idx[s32(AIDefInstParamKind::AITree)]);
+}
+
+// NON_MATCHING: CalcTiming ifs are reordered
+void AIClassDef::doGetDef(AIDef* def, const al::ByamlIter& iter, AIDefInstParamKind param_kind,
+ AIDefType class_type, s32 key_idx) const {
+ def->no_stop = false;
+ def->trigger_action = false;
+ def->dynamic_param_child = false;
+ def->_24b = 0;
+ def->num_params = 0;
+ def->calc_timing = CalcTiming::AIAfter;
+
+ if (param_kind == AIDefInstParamKind::Static) {
+ switch (class_type) {
+ case AIDefType::Action:
+ iter.tryGetBoolByKey(&def->trigger_action, "TriggerAction");
+ break;
+ case AIDefType::AI:
+ iter.tryGetBoolByKey(&def->trigger_action, "TriggerAction");
+ iter.tryGetBoolByKey(&def->dynamic_param_child, "DynamicParamChild");
+ break;
+ case AIDefType::Behavior: {
+ const char* timing_c;
+ if (iter.tryGetStringByKey(&timing_c, "CalcTiming")) {
+ const sead::SafeString timing = timing_c;
+ if (timing == str_AIAfter)
+ def->calc_timing = CalcTiming::AIAfter;
+ else if (timing == str_ModelAfter)
+ def->calc_timing = CalcTiming::ModelAfter;
+ else if (timing == str_ChangeDeleteState)
+ def->calc_timing = CalcTiming::ChangeDeleteState;
+ }
+ iter.tryGetBoolByKey(&def->no_stop, "NoStop");
+ break;
+ }
+ case AIDefType::Query:
+ break;
+ }
+ }
+
+ if (!iter.getRootNode())
+ return;
+
+ al::ByamlHashIter hash_iter{iter.getRootNode()};
+ al::ByamlData data;
+ if (!hash_iter.getDataByKey(&data, key_idx))
+ return;
+
+ al::ByamlIter params_iter{iter.getData(), iter.getData() + data.getValue()};
+ if (!params_iter.isValid())
+ return;
+
+ const s32 num_params = params_iter.getSize();
+ for (s32 i = 0; i < num_params; ++i) {
+ al::ByamlIter it;
+ if (!params_iter.tryGetIterByIndex(&it, i))
+ continue;
+
+ if (it.tryGetStringByKey(&def->param_names[def->num_params], "Name")) {
+ const char* type_cstr = nullptr;
+ if (it.tryGetStringByKey(&type_cstr, "Type")) {
+ const sead::SafeString type = type_cstr;
+
+ if (type == "Int") {
+ def->param_types[def->num_params] = AIDefParamType::Int;
+ def->param_values[def->num_params].i = 0;
+ if (paramKindHasValue(param_kind))
+ it.tryGetIntByKey(&def->param_values[def->num_params].i, "Value");
+
+ } else if (type == "Float" || type == "Angle") {
+ def->param_types[def->num_params] = AIDefParamType::Float;
+ def->param_values[def->num_params].f = 0;
+ if (paramKindHasValue(param_kind))
+ it.tryGetFloatByKey(&def->param_values[def->num_params].f, "Value");
+
+ } else if (type == "Bool") {
+ def->param_types[def->num_params] = AIDefParamType::Bool;
+ def->param_values[def->num_params].b = false;
+ if (paramKindHasValue(param_kind))
+ it.tryGetBoolByKey(&def->param_values[def->num_params].b, "Value");
+
+ } else if (type == "Vec3" || type == "Angle3") {
+ def->param_types[def->num_params] = AIDefParamType::Vec3;
+ al::ByamlIter vec_iter;
+ def->param_values[def->num_params].vec3.x = 0;
+ def->param_values[def->num_params].vec3.y = 0;
+ def->param_values[def->num_params].vec3.z = 0;
+ if (paramKindHasValue(param_kind) && it.tryGetIterByKey(&vec_iter, "Value")) {
+ vec_iter.tryGetFloatByIndex(&def->param_values[def->num_params].vec3.x, 0);
+ vec_iter.tryGetFloatByIndex(&def->param_values[def->num_params].vec3.y, 1);
+ vec_iter.tryGetFloatByIndex(&def->param_values[def->num_params].vec3.z, 2);
+ }
- const s32 idx = mData->defs[s32(AIDefType::Query)].binarySearchC(
- [hash](const Data::Def& def) -> s32 { return hash - def.name_hash; });
+ } else if (type == "String" || type == "AS") {
+ def->param_types[def->num_params] = AIDefParamType::String;
+ def->param_values[def->num_params].str = "";
+ if (paramKindHasValue(param_kind))
+ it.tryGetStringByKey(&def->param_values[def->num_params].str, "Value");
+
+ } else if (type == "Tree") {
+ def->param_types[def->num_params] = AIDefParamType::Tree;
+ } else if (type == "Actor") {
+ def->param_types[def->num_params] = AIDefParamType::BaseProcLink;
+ } else if (type == "MesTransceiverId") {
+ def->param_types[def->num_params] = AIDefParamType::MesTransceiverId;
+ } else if (type == "BaseProcHandle") {
+ def->param_types[def->num_params] = AIDefParamType::BaseProcHandle;
+ } else if (type == "AITreeVariablePointer") {
+ def->param_types[def->num_params] = AIDefParamType::AITreeVariablePointer;
+ } else if (type == "Rail") {
+ def->param_types[def->num_params] = AIDefParamType::Rail;
+ } else {
+ def->param_types[def->num_params] = AIDefParamType::Other;
+ }
+ } else {
+ def->param_types[def->num_params] = AIDefParamType::Other;
+ }
+ } else {
+ def->param_names[def->num_params] = nullptr;
+ def->param_types[def->num_params] = AIDefParamType::Other;
+ }
+ ++def->num_params;
+ }
+}
+
+void AIClassDef::getDef(AIDef* def, const sead::SafeString& class_name,
+ AIDefInstParamKind param_kind, AIDefType class_type) const {
+ def->num_params = 0;
+ def->calc_timing = CalcTiming::AIAfter;
+ def->no_stop = false;
+ def->trigger_action = false;
+ def->dynamic_param_child = false;
+ def->_24b = 0;
+
+ const s32 idx = getRawDefIdx(class_name, class_type);
+ if (idx < 0)
+ return;
+
+ doGetDef(def, getRawDefs(class_type)[idx].iter, param_kind, class_type,
+ mData->inst_params_key_idx[s32(param_kind)]);
+}
+
+bool AIClassDef::isSystemQuery(const sead::SafeString& query) const {
+ bool ret = false;
+ const s32 idx = getRawDefIdx(query, AIDefType::Query);
if (idx < 0)
return false;
- mData->defs[s32(AIDefType::Query)][idx].iter.tryGetBoolByKey(&ret, "SystemQuery");
+ getRawDefs(AIDefType::Query)[idx].iter.tryGetBoolByKey(&ret, "SystemQuery");
return ret;
}