diff --git a/src/component/gsc.cpp b/src/component/gsc.cpp index 00165da..563b4d1 100644 --- a/src/component/gsc.cpp +++ b/src/component/gsc.cpp @@ -305,6 +305,35 @@ namespace gsc return count; }); + + gsc::function::add("toint", [](const std::string& str, const scripting::variadic_args& va) + { + auto radix = 10; + if (va.size() > 0) + { + radix = va[0]; + } + + return static_cast(std::strtoull(str.data(), nullptr, radix)); + }); + + gsc::function::add("os::date", [](const scripting::variadic_args& va) + { + std::string format = "%Y-%m-%dT%H:%M:%S%z"; + if (va.size() > 0) + { + format = va[0].as(); + } + + tm ltime{}; + char timestamp[MAX_PATH] = {0}; + const auto time = _time64(nullptr); + + _localtime64_s(<ime, &time); + std::strftime(timestamp, sizeof(timestamp) - 1, format.data(), <ime); + + return std::string(timestamp); + }); } }; } diff --git a/src/component/json.cpp b/src/component/json.cpp index 14b6726..59adf5f 100644 --- a/src/component/json.cpp +++ b/src/component/json.cpp @@ -94,7 +94,7 @@ namespace json nlohmann::json gsc_to_json(scripting::script_value value, bool print_id) { - const auto variable = value.get_raw(); + const auto& variable = value.get_raw(); if (value.is()) { @@ -131,28 +131,24 @@ namespace json return object_to_json(variable.u.uintValue, print_id); } - if (value.is()) - { - const auto function = value.as(); - return utils::string::va("[[ %s ]]", function.get_name().data()); - } - if (variable.type == game::SCRIPT_NONE) { return {}; } - // TODO: scripting component, gsc is way different in BO1 than BO2 :/ + if (value.is()) + { + return "[function]"; + } + if (variable.type == game::SCRIPT_CODEPOS) { - // const auto function = scripting::find_function(variable.u.codePosValue); - return utils::string::va("[codepos]"); + return "[codepos]"; } if (variable.type == game::SCRIPT_END) { - // const auto function = scripting::find_function(variable.u.codePosValue); - return utils::string::va("[precodepos]"); + return "[precodepos]"; } return utils::string::va("[%s]", value.type_name().data()); diff --git a/src/component/scripting.cpp b/src/component/scripting.cpp index c9d8a41..5f953f8 100644 --- a/src/component/scripting.cpp +++ b/src/component/scripting.cpp @@ -23,13 +23,21 @@ namespace scripting std::unordered_map>> script_function_table_sort; std::unordered_map> script_function_table_rev; + std::unordered_map canonical_string_table; + namespace { utils::hook::detour g_shutdown_game_hook; + utils::hook::detour sl_get_canonical_string_hook; std::vector> shutdown_callbacks; void g_shutdown_game_stub(const int free_scripts) { + if (free_scripts) + { + canonical_string_table.clear(); + } + for (const auto& callback : shutdown_callbacks) { callback(); @@ -37,6 +45,18 @@ namespace scripting return g_shutdown_game_hook.invoke(free_scripts); } + + unsigned int sl_transfer_canonical_string_stub(game::scriptInstance_t inst, unsigned int string_value) + { + const auto result = sl_get_canonical_string_hook.invoke(inst, string_value); + const auto str = game::SL_ConvertToString(string_value, inst); + if (str) + { + canonical_string_table[result] = game::SL_ConvertToString(string_value, inst); + } + + return result; + } } void on_shutdown(const std::function& callback) @@ -50,6 +70,7 @@ namespace scripting void post_unpack() override { g_shutdown_game_hook.create(SELECT_VALUE(0x607700, 0x540950), g_shutdown_game_stub); + sl_get_canonical_string_hook.create(SELECT_VALUE(0x5F3F40, 0x622530), sl_transfer_canonical_string_stub); } }; } diff --git a/src/component/scripting.hpp b/src/component/scripting.hpp index 5c872fc..57d3868 100644 --- a/src/component/scripting.hpp +++ b/src/component/scripting.hpp @@ -11,6 +11,8 @@ namespace scripting extern std::unordered_map method_map; extern std::unordered_map function_map; + extern std::unordered_map canonical_string_table; + using script_function = void(*)(game::scr_entref_t); void on_shutdown(const std::function& callback); diff --git a/src/game/scripting/object.cpp b/src/game/scripting/object.cpp index ebff53c..df7acd5 100644 --- a/src/game/scripting/object.cpp +++ b/src/game/scripting/object.cpp @@ -2,46 +2,145 @@ #include "object.hpp" #include "execution.hpp" +#include "../../component/scripting.hpp" + namespace scripting { + namespace + { + std::string get_string(unsigned int canonical_string) + { + if (canonical_string_table.find(canonical_string) != canonical_string_table.end()) + { + return canonical_string_table[canonical_string]; + } + + return ""; + } + + unsigned int get_canonical_string(const std::string& str) + { + for (const auto& value : canonical_string_table) + { + if (value.second == str) + { + return value.first; + } + } + + return game::SL_GetCanonicalString(game::SCRIPTINSTANCE_SERVER, str.data()); + } + + std::vector get_keys_sp(unsigned int id) + { + std::vector result; + + auto current = game::scr_VarGlob->variableList_sp[id + 1].nextSibling; + + while (current) + { + const auto var = &game::scr_VarGlob->variableList_sp[current + 0x6000]; + const auto key_value = get_string(var->w.status >> 8); + result.push_back(key_value); + + const auto next_sibling = game::scr_VarGlob->variableList_sp[current + 0x6000].nextSibling; + if (!next_sibling) + { + break; + } + + current = static_cast(game::scr_VarGlob->variableList_sp[next_sibling + 0x6000].id); + } + + return result; + } + + std::vector get_keys_mp(unsigned int id) + { + std::vector result; + + auto current = game::scr_VarGlob->variableList_mp[id + 1].nextSibling; + + while (current) + { + const auto var = &game::scr_VarGlob->variableList_mp[current + 0x8000]; + const auto key_value = get_string(var->w.status >> 8); + result.push_back(key_value); + + const auto next_sibling = game::scr_VarGlob->variableList_mp[current + 0x8000].nextSibling; + if (!next_sibling) + { + break; + } + + current = game::scr_VarGlob->variableList_mp[next_sibling + 0x8000].hash.id; + } + + return result; + } + } + object_value::object_value(unsigned int parent_id, unsigned int id) : id_(id) , parent_id_(parent_id) { - /*if (!this->id_) + if (!this->id_) { return; } - const auto value = game::scr_VarGlob->childVariableValue[this->id_]; - game::VariableValue variable; - variable.u = value.u.u; - variable.type = (game::scriptType_e)value.type; + game::VariableValue variable_{}; - this->value_ = variable;*/ + if (game::environment::is_sp()) + { + const auto variable = &game::scr_VarGlob->variableList_sp[this->id_ + 0x6000]; + variable_.type = variable->w.type & 0x1F; + variable_.u = variable->u.u; + } + else + { + const auto variable = &game::scr_VarGlob->variableList_mp[this->id_ + 0x8000]; + variable_.type = variable->w.type & 0x1F; + variable_.u = variable->u.u; + } + + this->value_ = variable_; } - void object_value::operator=(const script_value& /*value*/) + void object_value::operator=(const script_value& value) { - /*if (!this->id_) + if (!this->id_) { return; } - const auto value = _value.get_raw(); + const auto& value_0 = value.get_raw(); - const auto variable = &game::scr_VarGlob->childVariableValue[this->id_]; - game::VariableValue variable_{}; - variable_.type = variable->type; - variable_.u = variable->u.u; + game::VariableValue previous{}; - game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value); - game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, variable->type, variable->u.u); + if (game::environment::is_sp()) + { + const auto variable = &game::scr_VarGlob->variableList_sp[this->id_ + 0x6000]; + previous.type = variable->w.type & 0x1F; + previous.u = variable->u.u; - variable->type = gsl::narrow_cast(value.type); - variable->u.u = value.u; + variable->w.type |= value_0.type; + variable->u.u = value_0.u; + } + else + { + const auto variable = &game::scr_VarGlob->variableList_mp[this->id_ + 0x8000]; + previous.type = variable->w.type & 0x1F; + previous.u = variable->u.u; - this->value_ = value;*/ + variable->w.type |= value_0.type; + variable->u.u = value_0.u; + } + + game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value_0); + game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, previous.type, previous.u); + + this->value_ = value_0; } object::object(const unsigned int id) @@ -121,25 +220,7 @@ namespace scripting std::vector object::get_keys() const { - std::vector result; - - /*auto current = game::scr_VarGlob->objectVariableChildren[this->id_].firstChild; - - while (current) - { - const auto var = game::scr_VarGlob->childVariableValue[current]; - const auto string_id = (unsigned __int8)var.name_lo + (var.k.keys.name_hi << 8); - - if (string_id < 0x34BC) - { - const auto string = reinterpret_cast(SELECT_VALUE(0x2DACC28, 0x2D7CF28))[string_id]; - result.push_back(string); - } - - current = var.nextSibling; - }*/ - - return result; + return SELECT_VALUE(get_keys_sp, get_keys_mp)(this->id_); } unsigned int object::size() const @@ -157,9 +238,9 @@ namespace scripting }*/ } - script_value object::get(const std::string& /*key*/) const + script_value object::get(const std::string& key) const { - /*const auto string_value = game::SL_GetCanonicalString(key.data(), 0); + const auto string_value = get_canonical_string(key); const auto variable_id = game::FindVariable(game::SCRIPTINSTANCE_SERVER, this->id_, string_value); if (!variable_id) @@ -167,18 +248,27 @@ namespace scripting return {}; } - const auto value = game::scr_VarGlob->childVariableValue[variable_id]; - game::VariableValue variable; - variable.u = value.u.u; - variable.type = (game::scriptType_e)value.type; + game::VariableValue variable_{}; - return variable;*/ - return {}; + if (game::environment::is_sp()) + { + const auto variable = &game::scr_VarGlob->variableList_sp[variable_id + 0x6000]; + variable_.type = variable->w.type & 0x1F; + variable_.u = variable->u.u; + } + else + { + const auto variable = &game::scr_VarGlob->variableList_mp[variable_id + 0x8000]; + variable_.type = variable->w.type & 0x1F; + variable_.u = variable->u.u; + } + + return variable_; } - void object::set(const std::string& /*key*/, const script_value& /*value*/) const + void object::set(const std::string& key, const script_value& value) const { - /*const auto value = value_.get_raw(); + const auto& value_ = value.get_raw(); const auto variable_id = this->get_value_id(key); if (!variable_id) @@ -186,16 +276,29 @@ namespace scripting return; } - const auto variable = &game::scr_VarGlob->childVariableValue[variable_id]; - game::VariableValue variable_{}; - variable_.type = variable->type; - variable_.u = variable->u.u; + game::VariableValue previous{}; - game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value); - game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, variable_.type, variable_.u); + if (game::environment::is_sp()) + { + const auto variable = &game::scr_VarGlob->variableList_sp[variable_id + 0x6000]; + previous.type = variable->w.type & 0x1F; + previous.u = variable->u.u; - variable->type = gsl::narrow_cast(value.type); - variable->u.u = value.u;*/ + variable->w.type |= value_.type; + variable->u.u = value_.u; + } + else + { + const auto variable = &game::scr_VarGlob->variableList_mp[variable_id + 0x8000]; + previous.type = variable->w.type & 0x1F; + previous.u = variable->u.u; + + variable->w.type |= value_.type; + variable->u.u = value_.u; + } + + game::AddRefToValue(game::SCRIPTINSTANCE_SERVER, &value_); + game::RemoveRefToValue(game::SCRIPTINSTANCE_SERVER, previous.type, previous.u); } unsigned int object::get_entity_id() const @@ -205,7 +308,7 @@ namespace scripting unsigned int object::get_value_id(const std::string& key) const { - const auto string_value = game::SL_GetCanonicalString(key.data(), 0); + const auto string_value = get_canonical_string(key); const auto variable_id = game::FindVariable(game::SCRIPTINSTANCE_SERVER, this->id_, string_value); if (!variable_id) diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index 33687f0..6375e15 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -75,7 +75,7 @@ namespace game WEAK symbol SL_GetString{0x463130, 0x4B1770}; WEAK symbol SL_ConvertToString{0x687530, 0x624C70}; - WEAK symbol SL_GetCanonicalString{0x0, 0x0}; + WEAK symbol SL_GetCanonicalString{0x4FB120, 0x68D860}; WEAK symbol Scr_GetNumParam{0x0, 0x0}; WEAK symbol Scr_GetEntity{0x0, 0x0};