Add scripting array support

This commit is contained in:
quaK 2021-03-13 02:35:59 +02:00
parent d04a8fd19e
commit 3957ad2ce9
3 changed files with 132 additions and 0 deletions

View File

@ -3,6 +3,114 @@
namespace scripting::lua
{
namespace
{
struct array_value
{
int index;
sol::lua_value value{};
};
sol::lua_value entity_to_array(lua_State* state, unsigned int id)
{
auto table = sol::table::create(state);
std::unordered_map<std::string, array_value> values;
const auto offset = 64000 * (id & 3);
auto current = game::scr_VarGlob->objectVariableChildren[id].firstChild;
auto idx = 1;
for (auto i = offset + current; current; i = offset + current)
{
const auto var = game::scr_VarGlob->childVariableValue[i];
if (var.type == game::SCRIPT_NONE)
{
current = var.nextSibling;
continue;
}
const auto string_value = (game::scr_string_t)((unsigned __int8)var.name_lo + (var.k.keys.name_hi << 8));
const auto* str = game::SL_ConvertToString(string_value);
std::string key = string_value < 0x40000 && str
? str
: std::to_string(idx++);
game::VariableValue variable{};
variable.type = var.type;
variable.u = var.u.u;
array_value value;
value.index = i;
value.value = convert(state, script_value(variable));
values[key] = value;
current = var.nextSibling;
}
auto metatable = sol::table::create(state);
metatable[sol::meta_function::new_index] = [state, values](const sol::table t, const sol::this_state s,
const sol::lua_value& key_value, const sol::lua_value& value)
{
const auto key = key_value.is<int>()
? std::to_string(key_value.as<int>())
: key_value.as<std::string>();
if (values.find(key) == values.end())
{
return;
}
const auto variable = convert(value).get_raw();
const auto i = values.at(key).index;
game::scr_VarGlob->childVariableValue[i].type = (char)variable.type;
game::scr_VarGlob->childVariableValue[i].u.u = variable.u;
};
metatable[sol::meta_function::index] = [state, values](const sol::table t, const sol::this_state s,
const sol::lua_value& key_value)
{
const auto key = key_value.is<int>()
? std::to_string(key_value.as<int>())
: key_value.as<std::string>();
if (values.find(key) == values.end())
{
return sol::lua_value{};
}
return values.at(key).value;
};
metatable[sol::meta_function::length] = [values]()
{
return values.size();
};
table[sol::metatable_key] = metatable;
table["getkeys"] = [values]()
{
std::vector<std::string> _keys;
for (const auto& entry : values)
{
_keys.push_back(entry.first);
}
return _keys;
};
return table;
}
}
script_value convert(const sol::lua_value& value)
{
if (value.is<int>())
@ -65,6 +173,11 @@ namespace scripting::lua
return {state, value.as<std::string>()};
}
if (value.is<std::vector<script_value>>())
{
return entity_to_array(state, value.get_raw().u.uintValue);
}
if (value.is<entity>())
{
return {state, value.as<entity>()};

View File

@ -189,6 +189,24 @@ namespace scripting
return this->get<const char*>();
}
/***************************************************************
* Array
**************************************************************/
template <>
bool script_value::is<std::vector<script_value>>() const
{
if (this->get_raw().type != game::SCRIPT_OBJECT)
{
return false;
}
const auto id = this->get_raw().u.uintValue;
const auto type = game::scr_VarGlob->objectVariableValue[id].w.type;
return type == game::SCRIPT_ARRAY;
}
/***************************************************************
* Entity
**************************************************************/

View File

@ -214,6 +214,7 @@ namespace game
WEAK symbol<jmp_buf> g_script_error{0x14A1917B0, 0x1487FA0C0};
WEAK symbol<scr_classStruct_t> g_classMap{0x14080A840, 0x1409BE1B0};
WEAK symbol<scrVarGlob_t> scr_VarGlob{ 0x149B1D680, 0x148185F80 };
WEAK symbol<scrVmPub_t> scr_VmPub{0x14A1938C0, 0x1487FC1C0};
WEAK symbol<const char*> command_whitelist{0x140808EF0, 0x1409B8DC0};