From c8063eb0b02efda855a7d99c1a097c211654b8b7 Mon Sep 17 00:00:00 2001 From: Federico Cecchetto Date: Fri, 18 Jun 2021 22:42:12 +0200 Subject: [PATCH] Use array class --- src/component/gsc.cpp | 35 +---- src/component/gsc.hpp | 4 - src/component/json.cpp | 66 +++----- src/game/scripting/array.cpp | 236 ++++++++++++++++++++++++++++ src/game/scripting/array.hpp | 62 ++++++++ src/game/scripting/execution.cpp | 27 ++++ src/game/scripting/execution.hpp | 4 + src/game/scripting/script_value.cpp | 10 +- src/game/scripting/script_value.hpp | 3 +- src/game/symbols.hpp | 1 + 10 files changed, 364 insertions(+), 84 deletions(-) create mode 100644 src/game/scripting/array.cpp create mode 100644 src/game/scripting/array.hpp diff --git a/src/component/gsc.cpp b/src/component/gsc.cpp index 69a1470..c36bb12 100644 --- a/src/component/gsc.cpp +++ b/src/component/gsc.cpp @@ -7,6 +7,7 @@ #include "game/scripting/event.hpp" #include "game/scripting/execution.hpp" #include "game/scripting/functions.hpp" +#include "game/scripting/array.hpp" #include "gsc.hpp" @@ -251,33 +252,6 @@ namespace gsc } } - unsigned int make_array() - { - unsigned int index = 0; - const auto variable = game::AllocVariable(&index); - variable->w.type = game::SCRIPT_ARRAY; - variable->u.f.prev = 0; - variable->u.f.next = 0; - - return index; - } - - void add_array_key_value(unsigned int parent_id, const std::string& _key, const scripting::script_value& value) - { - const auto key = game::SL_GetString(_key.data(), 0); - - scripting::push_value(scripting::entity(parent_id)); - scripting::push_value(value); - game::Scr_AddArrayStringIndexed(key); - } - - void add_array_value(unsigned int parent_id, const scripting::script_value& value) - { - scripting::push_value(scripting::entity(parent_id)); - scripting::push_value(value); - game::Scr_AddArray(); - } - class component final : public component_interface { public: @@ -317,14 +291,13 @@ namespace gsc const auto pos = function.u.codePosValue; command::add_script_command(name, [pos](const command::params& params) { - const auto array = make_array(); + scripting::array array; for (auto i = 0; i < params.size(); i++) { - add_array_value(array, params[i]); + array.push(params[i]); } - const auto entity = scripting::entity(array); - scripting::exec_ent_thread(*game::levelEntityId, pos, {entity}); + scripting::exec_ent_thread(*game::levelEntityId, pos, {array.get_raw()}); }); return {}; diff --git a/src/component/gsc.hpp b/src/component/gsc.hpp index 4168a34..d44a32e 100644 --- a/src/component/gsc.hpp +++ b/src/component/gsc.hpp @@ -19,8 +19,4 @@ namespace gsc { void add(const std::string& name, const script_method& func); } - - unsigned int make_array(); - void add_array_key_value(unsigned int parent_id, const std::string& _key, const scripting::script_value& value); - void add_array_value(unsigned int parent_id, const scripting::script_value& value); } \ No newline at end of file diff --git a/src/component/json.cpp b/src/component/json.cpp index b8d989f..1b4e7fd 100644 --- a/src/component/json.cpp +++ b/src/component/json.cpp @@ -6,6 +6,7 @@ #include "game/scripting/event.hpp" #include "game/scripting/execution.hpp" #include "game/scripting/functions.hpp" +#include "game/scripting/array.hpp" #include "gsc.hpp" @@ -19,45 +20,26 @@ namespace json nlohmann::json entity_to_array(unsigned int id) { + scripting::array array(id); nlohmann::json obj; + auto string_indexed = -1; - - const auto offset = 0xC800 * (id & 1); - auto current = game::scr_VarGlob->objectVariableChildren[id].firstChild; - - for (auto i = offset + current; current; i = offset + current) + const auto keys = array.get_keys(); + for (auto i = 0; i < keys.size(); i++) { - const auto var = game::scr_VarGlob->childVariableValue[i]; - - if (var.type == game::SCRIPT_NONE) - { - current = var.nextSibling; - continue; - } - - const auto string_value = (unsigned int)((unsigned __int8)var.name_lo + (var.k.keys.name_hi << 8)); - const auto* str = game::SL_ConvertToString(string_value); - if (string_indexed == -1) { - string_indexed = string_value < 0x40000 && str; + string_indexed = keys[i].is_string; } - game::VariableValue variable{}; - variable.type = (game::scriptType_e)var.type; - variable.u = var.u.u; - - if (!string_indexed) + if (!string_indexed && keys[i].is_integer) { - const auto index = (string_value - 0x800000) & 0xFFFFFF; - obj[index] = gsc_to_json(variable); + obj[keys[i].index] = gsc_to_json(array[keys[i].index]); } - else + else if (string_indexed && keys[i].is_string) { - obj.emplace(str, gsc_to_json(variable)); + obj.emplace(keys[i].key, gsc_to_json(array[keys[i].key])); } - - current = var.nextSibling; } return obj; @@ -128,25 +110,25 @@ namespace json return obj.get(); case (nlohmann::detail::value_t::array): { - const auto arr = gsc::make_array(); + scripting::array array; for (const auto& [key, value] : obj.items()) { - gsc::add_array_value(arr, json_to_gsc(value)); + array.push(json_to_gsc(value)); } - return scripting::entity(arr); + return array.get_raw(); } case (nlohmann::detail::value_t::object): { - const auto arr = gsc::make_array(); + scripting::array array; for (const auto& [key, value] : obj.items()) { - gsc::add_array_key_value(arr, key, json_to_gsc(value)); + array[key] = json_to_gsc(value); } - return scripting::entity(arr); + return array.get_raw(); } } @@ -161,19 +143,13 @@ namespace json { gsc::function::add("array", [](gsc::function_args args) { - const auto array = gsc::make_array(); - - for (auto i = 0; i < args.size(); i++) - { - gsc::add_array_value(array, args[i]); - } - - return scripting::entity(array); + scripting::array array(args); + return array.get_raw(); }); gsc::function::add("map", [](gsc::function_args args) { - const auto array = gsc::make_array(); + scripting::array array; for (auto i = 0; i < args.size(); i += 2) { @@ -183,10 +159,10 @@ namespace json } const auto key = args[i].as(); - gsc::add_array_key_value(array, key, args[i + 1]); + array[key] = args[i + 1]; } - return scripting::entity(array); + return array.get_raw(); }); gsc::function::add("jsonparse", [](gsc::function_args args) diff --git a/src/game/scripting/array.cpp b/src/game/scripting/array.cpp new file mode 100644 index 0000000..659e3e5 --- /dev/null +++ b/src/game/scripting/array.cpp @@ -0,0 +1,236 @@ +#include +#include "array.hpp" +#include "execution.hpp" + +namespace scripting +{ + array_value::array_value(unsigned int parent_id, unsigned int id) + : id_(id) + , parent_id_(parent_id) + { + if (!this->id_) + { + return; + } + + const auto value = game::scr_VarGlob->childVariableValue[this->id_ + 0xC800 * (this->parent_id_ & 1)]; + game::VariableValue variable; + variable.u = value.u.u; + variable.type = (game::scriptType_e)value.type; + + this->value_ = variable; + } + + void array_value::operator=(const script_value& _value) + { + if (!this->id_) + { + return; + } + + const auto value = _value.get_raw(); + + const auto variable = &game::scr_VarGlob->childVariableValue[this->id_ + 0xC800 * (this->parent_id_ & 1)]; + game::AddRefToValue(value.type, value.u); + game::RemoveRefToValue(variable->type, variable->u.u); + + variable->type = value.type; + variable->u.u = value.u; + + this->value_ = value; + } + + array::array(unsigned int id) + : id_(id) + { + } + + array::array() + { + this->id_ = make_array(); + } + + array::array(std::vector values) + { + this->id_ = make_array(); + + for (const auto& value : values) + { + add_array_value(this->id_, value); + } + } + + array::array(std::unordered_map values) + { + this->id_ = make_array(); + + for (const auto& value : values) + { + add_array_key_value(this->id_, value.first, value.second); + } + } + + std::vector array::get_keys() const + { + std::vector result; + + const auto offset = 0xC800 * (this->id_ & 1); + auto current = game::scr_VarGlob->objectVariableChildren[this->id_].firstChild; + + 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 = (unsigned int)((unsigned __int8)var.name_lo + (var.k.keys.name_hi << 8)); + const auto* str = game::SL_ConvertToString(string_value); + + array_key key; + if (string_value < 0x40000 && str) + { + key.is_string = true; + key.key = str; + } + else + { + key.is_integer = true; + key.index = (string_value - 0x800000) & 0xFFFFFF; + } + + result.push_back(key); + + current = var.nextSibling; + } + + return result; + } + + int array::size() const + { + return game::Scr_GetSelf(this->id_); + } + + void array::push(script_value value) const + { + add_array_value(this->id_, value); + } + + script_value array::get(const std::string& key) const + { + const auto string_value = game::SL_GetString(key.data(), 0); + const auto variable_id = game::GetVariable(this->id_, string_value); + + if (!variable_id) + { + return {}; + } + + const auto value = game::scr_VarGlob->childVariableValue[variable_id + 0xC800 * (this->id_ & 1)]; + game::VariableValue variable; + variable.u = value.u.u; + variable.type = (game::scriptType_e)value.type; + + return variable; + } + + script_value array::get(const unsigned int index) const + { + const auto variable_id = game::GetVariable(this->id_, (index - 0x800000) & 0xFFFFFF); + + if (!variable_id) + { + return {}; + } + + const auto value = game::scr_VarGlob->childVariableValue[variable_id + 0xC800 * (this->id_ & 1)]; + game::VariableValue variable; + variable.u = value.u.u; + variable.type = (game::scriptType_e)value.type; + + return variable; + } + + unsigned int array::get_entity_id() const + { + return this->id_; + } + + unsigned int array::get_value_id(const std::string& key) const + { + const auto string_value = game::SL_GetString(key.data(), 0); + const auto variable_id = game::GetVariable(this->id_, string_value); + + if (!variable_id) + { + add_array_key_value(this->id_, key, {}); + return this->get_value_id(key); + } + + return variable_id; + } + + unsigned int array::get_value_id(const unsigned int index) const + { + const auto variable_id = game::GetVariable(this->id_, (index - 0x800000) & 0xFFFFFF); + if (!variable_id) + { + return game::GetNewArrayVariable(this->id_, index); + } + + return variable_id; + } + + void array::set(const std::string& key, const script_value& _value) const + { + const auto value = _value.get_raw(); + + const auto string_value = game::SL_GetString(key.data(), 0); + const auto variable_id = game::GetVariable(this->id_, string_value); + + if (variable_id) + { + const auto variable = &game::scr_VarGlob->childVariableValue[variable_id + 0xC800 * (this->id_ & 1)]; + + game::AddRefToValue(value.type, value.u); + game::RemoveRefToValue(variable->type, variable->u.u); + + variable->type = value.type; + variable->u.u = value.u; + + return; + } + + add_array_key_value(this->id_, key, _value); + } + + void array::set(const unsigned int index, const script_value& _value) const + { + const auto value = _value.get_raw(); + const auto variable_id = game::GetVariable(this->id_, (index - 0x800000) & 0xFFFFFF); + + if (variable_id) + { + const auto variable = &game::scr_VarGlob->childVariableValue[variable_id + 0xC800 * (this->id_ & 1)]; + + game::AddRefToValue(value.type, value.u); + game::RemoveRefToValue(variable->type, variable->u.u); + + variable->type = value.type; + variable->u.u = value.u; + + return; + } + + add_array_value(this->id_, _value); + } + + entity array::get_raw() const + { + return entity(this->id_); + } +} diff --git a/src/game/scripting/array.hpp b/src/game/scripting/array.hpp new file mode 100644 index 0000000..131e465 --- /dev/null +++ b/src/game/scripting/array.hpp @@ -0,0 +1,62 @@ +#pragma once +#include "script_value.hpp" + +namespace scripting +{ + struct array_key + { + bool is_string = false; + bool is_integer = false; + int index{}; + std::string key{}; + }; + + class array_value : public script_value + { + public: + array_value(unsigned int parent_id, unsigned int id); + void array_value::operator=(const script_value& value); + private: + unsigned int id_; + unsigned int parent_id_; + }; + + class array final + { + public: + array(); + array(unsigned int); + array(std::vector); + array(std::unordered_map); + + std::vector get_keys() const; + + int size() const; + void push(script_value) const; + + script_value get(const std::string&) const; + script_value get(const unsigned int) const; + + unsigned int get_entity_id() const; + + unsigned int get_value_id(const std::string&) const; + unsigned int get_value_id(const unsigned int) const; + + void set(const std::string&, const script_value&) const; + void set(const unsigned int, const script_value&) const; + + entity get_raw() const; + + array_value array::operator[](const int index) const + { + return {this->id_, this->get_value_id(index)}; + } + + array_value array::operator[](const std::string& key) const + { + return {this->id_, this->get_value_id(key)}; + } + private: + unsigned int id_; + }; +} diff --git a/src/game/scripting/execution.cpp b/src/game/scripting/execution.cpp index ee1441c..82875fb 100644 --- a/src/game/scripting/execution.cpp +++ b/src/game/scripting/execution.cpp @@ -269,4 +269,31 @@ namespace scripting return {}; } + + unsigned int make_array() + { + unsigned int index = 0; + const auto variable = game::AllocVariable(&index); + variable->w.type = game::SCRIPT_ARRAY; + variable->u.f.prev = 0; + variable->u.f.next = 0; + + return index; + } + + void add_array_key_value(unsigned int parent_id, const std::string& _key, const scripting::script_value& value) + { + const auto key = game::SL_GetString(_key.data(), 0); + + scripting::push_value(scripting::entity(parent_id)); + scripting::push_value(value); + game::Scr_AddArrayStringIndexed(key); + } + + void add_array_value(unsigned int parent_id, const scripting::script_value& value) + { + scripting::push_value(scripting::entity(parent_id)); + scripting::push_value(value); + game::Scr_AddArray(); + } } \ No newline at end of file diff --git a/src/game/scripting/execution.hpp b/src/game/scripting/execution.hpp index cc9b80c..7a3a51e 100644 --- a/src/game/scripting/execution.hpp +++ b/src/game/scripting/execution.hpp @@ -34,4 +34,8 @@ namespace scripting script_value get_entity_field(const entity& entity, const std::string& field); void notify(const entity& entity, const std::string& event, const std::vector& arguments); + + unsigned int make_array(); + void add_array_key_value(unsigned int parent_id, const std::string& _key, const scripting::script_value& value); + void add_array_value(unsigned int parent_id, const scripting::script_value& value); } diff --git a/src/game/scripting/script_value.cpp b/src/game/scripting/script_value.cpp index 6962c1a..1d606bb 100644 --- a/src/game/scripting/script_value.cpp +++ b/src/game/scripting/script_value.cpp @@ -1,7 +1,7 @@ #include #include "script_value.hpp" #include "entity.hpp" - +#include "array.hpp" namespace scripting { @@ -219,7 +219,7 @@ namespace scripting **************************************************************/ template <> - bool script_value::is>() const + bool script_value::is() const { if (this->get_raw().type != game::SCRIPT_OBJECT) { @@ -232,6 +232,12 @@ namespace scripting return type == game::SCRIPT_ARRAY; } + template <> + array script_value::get() const + { + return array(this->get_raw().u.uintValue); + } + /*************************************************************** * Struct **************************************************************/ diff --git a/src/game/scripting/script_value.hpp b/src/game/scripting/script_value.hpp index ce07b91..0e159b6 100644 --- a/src/game/scripting/script_value.hpp +++ b/src/game/scripting/script_value.hpp @@ -63,10 +63,9 @@ namespace scripting const game::VariableValue& get_raw() const; + variable_value value_{}; private: template T get() const; - - variable_value value_{}; }; } diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index 6d83da1..647c1f6 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -31,6 +31,7 @@ namespace game WEAK symbol FindObject{0x565BD0}; WEAK symbol GetVariable{0x5663E0}; WEAK symbol GetNewVariable{0x566390}; + WEAK symbol GetNewArrayVariable{0x5668C0}; WEAK symbol SetNewVariableValue{0x5658D0}; WEAK symbol Scr_AllocVector{0x565680};