mirror of https://github.com/zeldaret/botw.git
ksys/act: Implement the rest of AIClassDef
This commit is contained in:
parent
fd2f653b6f
commit
d3b065bfa2
|
@ -92291,10 +92291,10 @@
|
|||
0x00000071011df8b0,sub_71011DF8B0,136,_ZN4ksys10AIClassDefD1Ev
|
||||
0x00000071011df938,AIClassDef::init,608,_ZN4ksys10AIClassDef4initERKN4sead14SafeStringBaseIcEEPNS1_4HeapE
|
||||
0x00000071011dfb98,AIClassDef::Data::load,1124,_ZN4ksys10AIClassDef4Data4loadEPN4sead4HeapE!
|
||||
0x00000071011dfffc,AIClassDef::getInfo,540,
|
||||
0x00000071011e0218,ai::doGetClassDef,4284,
|
||||
0x00000071011e12d4,AIClassDef::getClassDef,320,
|
||||
0x00000071011e1414,AIClassDef::isSystemQuery,264,_ZNK4ksys10AIClassDef13isSystemQueryERKN4sead14SafeStringBaseIcEE!
|
||||
0x00000071011dfffc,AIClassDef::getInfo,540,_ZNK4ksys10AIClassDef6getDefERKN4sead14SafeStringBaseIcEEPNS_8AIDefSetENS_9AIDefTypeE
|
||||
0x00000071011e0218,ai::doGetClassDef,4284,_ZNK4ksys10AIClassDef8doGetDefEPNS_5AIDefERKN2al9ByamlIterENS_18AIDefInstParamKindENS_9AIDefTypeEi!
|
||||
0x00000071011e12d4,AIClassDef::getClassDef,320,_ZNK4ksys10AIClassDef6getDefEPNS_5AIDefERKN4sead14SafeStringBaseIcEENS_18AIDefInstParamKindENS_9AIDefTypeE
|
||||
0x00000071011e1414,AIClassDef::isSystemQuery,264,_ZNK4ksys10AIClassDef13isSystemQueryERKN4sead14SafeStringBaseIcEE
|
||||
0x00000071011e151c,MassRenderer::ctor,376,
|
||||
0x00000071011e1694,sub_71011E1694,244,
|
||||
0x00000071011e1788,sub_71011E1788,380,
|
||||
|
|
Can't render this file because it is too large.
|
|
@ -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;
|
||||
|
||||
const s32 idx = mData->defs[s32(AIDefType::Query)].binarySearchC(
|
||||
[hash](const Data::Def& def) -> s32 { return hash - def.name_hash; });
|
||||
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);
|
||||
}
|
||||
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <basis/seadTypes.h>
|
||||
#include <container/seadBuffer.h>
|
||||
#include <container/seadSafeArray.h>
|
||||
#include <heap/seadDisposer.h>
|
||||
#include <math/seadVector.h>
|
||||
#include <prim/seadSafeString.h>
|
||||
#include <prim/seadSizedEnum.h>
|
||||
#include "KingSystem/Resource/resHandle.h"
|
||||
|
@ -12,6 +14,10 @@
|
|||
|
||||
namespace ksys {
|
||||
|
||||
namespace act {
|
||||
class BaseProcLink;
|
||||
}
|
||||
|
||||
enum class AIDefType {
|
||||
AI = 0,
|
||||
Action = 1,
|
||||
|
@ -19,7 +25,7 @@ enum class AIDefType {
|
|||
Query = 3,
|
||||
};
|
||||
|
||||
static constexpr s32 NumAIDefTypes = 4;
|
||||
constexpr s32 NumAIDefTypes = 4;
|
||||
|
||||
enum class AIDefInstParamKind {
|
||||
Static = 0,
|
||||
|
@ -28,6 +34,12 @@ enum class AIDefInstParamKind {
|
|||
AITree = 3,
|
||||
};
|
||||
|
||||
constexpr bool paramKindHasValue(AIDefInstParamKind kind) {
|
||||
return kind == AIDefInstParamKind::MapUnit || kind == AIDefInstParamKind::AITree;
|
||||
}
|
||||
|
||||
constexpr s32 NumAIDefInstParamKinds = 4;
|
||||
|
||||
enum class AIDefParamType {
|
||||
String = 0,
|
||||
Int = 1,
|
||||
|
@ -44,9 +56,25 @@ enum class AIDefParamType {
|
|||
Other = 12,
|
||||
};
|
||||
|
||||
enum class CalcTiming {
|
||||
AIAfter = 0,
|
||||
ModelAfter = 1,
|
||||
ChangeDeleteState = 2,
|
||||
};
|
||||
|
||||
struct AIDef {
|
||||
union Value {
|
||||
Value() {}
|
||||
u8 raw[16];
|
||||
const char* str;
|
||||
s32 i;
|
||||
f32 f;
|
||||
sead::Vector3f vec3;
|
||||
bool b;
|
||||
void* tree;
|
||||
void* variable_ptr;
|
||||
u32 u;
|
||||
act::BaseProcLink* proc_link;
|
||||
};
|
||||
|
||||
static constexpr size_t NumParametersMax = 64;
|
||||
|
@ -54,7 +82,7 @@ struct AIDef {
|
|||
const char* param_names[NumParametersMax];
|
||||
sead::SizedEnum<AIDefParamType, u8> param_types[NumParametersMax];
|
||||
s32 num_params;
|
||||
u32 calc_timing;
|
||||
CalcTiming calc_timing;
|
||||
bool no_stop;
|
||||
bool trigger_action;
|
||||
bool dynamic_param_child;
|
||||
|
@ -63,6 +91,17 @@ struct AIDef {
|
|||
};
|
||||
KSYS_CHECK_SIZE_NX150(AIDef, 0x650);
|
||||
|
||||
struct AIDefSet {
|
||||
static constexpr size_t NumChildrenMax = 256;
|
||||
|
||||
const char* children[NumChildrenMax];
|
||||
s32 num_children;
|
||||
AIDef dynamic_params;
|
||||
AIDef map_unit_params;
|
||||
AIDef ai_tree_params;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(AIDefSet, 0x1af8);
|
||||
|
||||
class AIClassDef {
|
||||
SEAD_SINGLETON_DISPOSER(AIClassDef)
|
||||
AIClassDef() = default;
|
||||
|
@ -71,8 +110,9 @@ class AIClassDef {
|
|||
public:
|
||||
void init(const sead::SafeString& aidef_file_name, sead::Heap* heap);
|
||||
|
||||
void getDef(const sead::SafeString& class_name, AIDefSet* set, AIDefType class_type) const;
|
||||
void getDef(AIDef* def, const sead::SafeString& class_name, AIDefInstParamKind param_kind,
|
||||
AIDefType class_type);
|
||||
AIDefType class_type) const;
|
||||
|
||||
bool isSystemQuery(const sead::SafeString& query) const;
|
||||
|
||||
|
@ -88,10 +128,7 @@ private:
|
|||
|
||||
sead::SafeArray<al::ByamlIter, NumAIDefTypes> iters;
|
||||
sead::SafeArray<sead::Buffer<Def>, NumAIDefTypes> defs;
|
||||
s32 idx_StaticInstParams;
|
||||
s32 idx_DynamicInstParams;
|
||||
s32 idx_MapUnitInstParams;
|
||||
s32 idx_AITreeVariables;
|
||||
sead::SafeArray<s32, NumAIDefInstParamKinds> inst_params_key_idx;
|
||||
s32 idx_Childs = -1;
|
||||
al::ByamlIter root_iter;
|
||||
};
|
||||
|
@ -107,6 +144,14 @@ private:
|
|||
util::safeDelete(mData);
|
||||
}
|
||||
|
||||
s32 getRawDefIdx(const sead::SafeString& def_name, AIDefType type) const;
|
||||
const sead::Buffer<Data::Def>& getRawDefs(AIDefType type) const {
|
||||
return mData->defs[s32(type)];
|
||||
}
|
||||
|
||||
void doGetDef(AIDef* def, const al::ByamlIter& iter, AIDefInstParamKind param_kind,
|
||||
AIDefType class_type, s32 key_idx) const;
|
||||
|
||||
Data* mData = nullptr;
|
||||
res::Handle mResHandle;
|
||||
};
|
||||
|
|
|
@ -375,7 +375,7 @@ bool AIProgram::parseDefParams(AIProgram::Definition* def, void* buffer, sead::H
|
|||
} else if (&mBehaviors == buffer) {
|
||||
AIClassDef::instance()->getDef(&aidef, def->mClassName, AIDefInstParamKind::Static,
|
||||
AIDefType::Behavior);
|
||||
*param1 = aidef.calc_timing;
|
||||
*param1 = u16(aidef.calc_timing);
|
||||
*param2 = aidef.no_stop;
|
||||
} else {
|
||||
AIClassDef::instance()->getDef(&aidef, def->mClassName, AIDefInstParamKind::Static,
|
||||
|
|
Loading…
Reference in New Issue