From d5e6a15175366490277f7bd88b4ee62af07ea78d Mon Sep 17 00:00:00 2001 From: Federico Cecchetto Date: Sun, 30 May 2021 22:44:19 +0200 Subject: [PATCH] Add json functions --- .gitmodules | 3 + deps/json | 1 + deps/premake/json.lua | 19 +++ src/component/io.cpp | 19 +-- src/component/json.cpp | 212 ++++++++++++++++++++++++++++ src/game/scripting/script_value.hpp | 2 +- src/game/symbols.hpp | 9 ++ 7 files changed, 246 insertions(+), 19 deletions(-) create mode 160000 deps/json create mode 100644 deps/premake/json.lua create mode 100644 src/component/json.cpp diff --git a/.gitmodules b/.gitmodules index f5fb961..0158c89 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "deps/lua"] path = deps/lua url = https://github.com/lua/lua.git +[submodule "deps/json"] + path = deps/json + url = https://github.com/nlohmann/json.git diff --git a/deps/json b/deps/json new file mode 160000 index 0000000..e10a3fa --- /dev/null +++ b/deps/json @@ -0,0 +1 @@ +Subproject commit e10a3fac8a255433146e3f06a703dc110fc3c3da diff --git a/deps/premake/json.lua b/deps/premake/json.lua new file mode 100644 index 0000000..e5eb493 --- /dev/null +++ b/deps/premake/json.lua @@ -0,0 +1,19 @@ +json = { + source = path.join(dependencies.basePath, "json"), +} + +function json.import() + json.includes() +end + +function json.includes() + includedirs { + path.join(json.source, "single_include/*") + } +end + +function json.project() + +end + +table.insert(dependencies, json) diff --git a/src/component/io.cpp b/src/component/io.cpp index 85a5b89..c6f9164 100644 --- a/src/component/io.cpp +++ b/src/component/io.cpp @@ -11,29 +11,12 @@ namespace io { - namespace - { - std::string load_path() - { - const auto fs_basegame = game::Dvar_FindVar("fs_basegame"); - - return fs_basegame->current.string; - } - - std::string get_path() - { - static const auto path = load_path(); - - return path; - } - } - class component final : public component_interface { public: void post_unpack() override { - const auto path = get_path(); + const auto path = game::Dvar_FindVar("fs_basegame")->current.string; std::filesystem::current_path(path); gsc::function::add("fremove", [](gsc::function_args args) diff --git a/src/component/json.cpp b/src/component/json.cpp new file mode 100644 index 0000000..938953f --- /dev/null +++ b/src/component/json.cpp @@ -0,0 +1,212 @@ +#include +#include "loader/component_loader.hpp" + +#include "scheduler.hpp" + +#include "game/scripting/event.hpp" +#include "game/scripting/execution.hpp" +#include "game/scripting/functions.hpp" + +#include "gsc.hpp" + +#include + +namespace json +{ + namespace + { + 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(); + } + + nlohmann::json gsc_to_json(scripting::script_value value); + + nlohmann::json entity_to_array(unsigned int 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 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; + } + + game::VariableValue variable{}; + variable.type = (game::scriptType_e)var.type; + variable.u = var.u.u; + + if (!string_indexed) + { + obj.emplace_back(gsc_to_json(variable)); + } + else + { + obj.emplace(str, gsc_to_json(variable)); + } + + current = var.nextSibling; + } + + return obj; + } + + nlohmann::json vector_to_array(const float* value) + { + nlohmann::json obj; + obj.push_back(value[0]); + obj.push_back(value[1]); + obj.push_back(value[2]); + + return obj; + } + + nlohmann::json gsc_to_json(scripting::script_value _value) + { + const auto variable = _value.get_raw(); + const auto value = variable.u; + const auto type = variable.type; + + switch (type) + { + case (game::SCRIPT_NONE): + return {}; + case (game::SCRIPT_INTEGER): + return value.intValue; + case (game::SCRIPT_FLOAT): + return value.floatValue; + case (game::SCRIPT_STRING): + case (game::SCRIPT_ISTRING): + return game::SL_ConvertToString(static_cast(value.stringValue)); + case (game::SCRIPT_VECTOR): + return vector_to_array(value.vectorValue); + case (game::SCRIPT_OBJECT): + { + const auto object_type = game::scr_VarGlob->objectVariableValue[value.uintValue].w.type; + + switch (object_type) + { + case (game::SCRIPT_STRUCT): + return "[struct]"; + case (game::SCRIPT_ARRAY): + return entity_to_array(value.uintValue); + default: + return "[entity]"; + } + } + case (game::SCRIPT_FUNCTION): + return "[function]"; + default: + return "[unknown type]"; + } + } + + scripting::script_value json_to_gsc(nlohmann::json obj) + { + const auto type = obj.type(); + + switch (type) + { + case (nlohmann::detail::value_t::number_integer): + case (nlohmann::detail::value_t::number_unsigned): + return obj.get(); + case (nlohmann::detail::value_t::number_float): + return obj.get(); + case (nlohmann::detail::value_t::string): + return obj.get(); + case (nlohmann::detail::value_t::array): + { + const auto arr = make_array(); + + for (const auto& [key, value] : obj.items()) + { + add_array_value(arr, json_to_gsc(value)); + } + + return scripting::entity(arr); + } + case (nlohmann::detail::value_t::object): + { + const auto arr = make_array(); + + for (const auto& [key, value] : obj.items()) + { + add_array_key_value(arr, key, json_to_gsc(value)); + } + + return scripting::entity(arr); + } + } + + return {}; + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + gsc::function::add("jsonparse", [](gsc::function_args args) + { + const auto json = args[0].as(); + const auto obj = nlohmann::json::parse(json); + + return json_to_gsc(obj); + }); + + gsc::function::add("jsonserialize", [](gsc::function_args args) + { + const auto value = args[0]; + auto indent = -1; + + if (args.size() > 1) + { + indent = args[1].as(); + } + + return gsc_to_json(value).dump(indent); + }); + } + }; +} + +REGISTER_COMPONENT(json::component) \ No newline at end of file diff --git a/src/game/scripting/script_value.hpp b/src/game/scripting/script_value.hpp index e53d2a6..ce07b91 100644 --- a/src/game/scripting/script_value.hpp +++ b/src/game/scripting/script_value.hpp @@ -58,7 +58,7 @@ namespace scripting throw std::runtime_error("Null pointer"); } - return reinterpret_cast(this->get()); + return reinterpret_cast(value); } const game::VariableValue& get_raw() const; diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index 4b87e53..0479147 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -9,6 +9,7 @@ namespace game WEAK symbol AddRefToValue{0x5656E0}; WEAK symbol AddRefToObject{0x5655F0}; WEAK symbol AllocThread{0x565580}; + WEAK symbol AllocVariable{0x565430}; WEAK symbol AllocObject{0x565530}; WEAK symbol RemoveRefToValue{0x565730}; WEAK symbol RemoveRefToObject{0x5681E0}; @@ -28,6 +29,8 @@ namespace game WEAK symbol FindVariable{0x5651F0}; WEAK symbol FindObject{0x565BD0}; WEAK symbol GetVariable{0x5663E0}; + WEAK symbol GetNewVariable{0x566390}; + WEAK symbol SetNewVariableValue{0x5658D0}; WEAK symbol Scr_AllocVector{0x565680}; WEAK symbol Scr_ClearOutParams{0x569010}; @@ -36,6 +39,12 @@ namespace game WEAK symbol Scr_NotifyId{0x56B5E0}; WEAK symbol Scr_GetFunctionHandle{0x5618A0}; WEAK symbol Scr_ExecThreadInternal{0x56E1C0}; + WEAK symbol Scr_GetEntityId{0x567D80}; + WEAK symbol Scr_AddEntityNum{0x56ABC0}; + WEAK symbol Scr_AddArray{0x56AE30}; + WEAK symbol Scr_GetSelf{0x5655E0}; + WEAK symbol Scr_MakeArray{0x56ADE0}; + WEAK symbol Scr_AddArrayStringIndexed{0x56AE70}; WEAK symbol SL_GetString{0x5649E0}; WEAK symbol SL_ConvertToString{0x564270};