Organize scripts and add TWS plugins with HTTP timeouts
Vendor pinned T5 and T6 plugin sources under the new plugins layout. Add native HTTP deadlines, status and timing diagnostics, telemetry integration, and build/test tooling.
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/scripting/event.hpp"
|
||||
#include "game/scripting/execution.hpp"
|
||||
#include "game/scripting/array.hpp"
|
||||
|
||||
#include "gsc.hpp"
|
||||
#include "json.hpp"
|
||||
#include "scripting.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace json
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr const auto max_str_len = 0x5000u;
|
||||
|
||||
struct dump_context_t
|
||||
{
|
||||
std::unordered_set<std::uint32_t> visited_objects;
|
||||
};
|
||||
|
||||
nlohmann::json gsc_to_json(const scripting::script_value& value, bool print_id, dump_context_t& ctx);
|
||||
|
||||
nlohmann::json array_to_json(const scripting::array& array, bool print_id, dump_context_t& ctx)
|
||||
{
|
||||
if (array.size() == 0)
|
||||
{
|
||||
return nlohmann::json::array();
|
||||
}
|
||||
|
||||
nlohmann::json obj;
|
||||
|
||||
auto string_indexed = -1;
|
||||
const auto keys = array.get_keys();
|
||||
|
||||
for (const auto& key : keys)
|
||||
{
|
||||
const auto is_int = key.is<int>();
|
||||
const auto is_string = key.is<std::string>();
|
||||
|
||||
if (string_indexed == -1)
|
||||
{
|
||||
string_indexed = is_string;
|
||||
}
|
||||
|
||||
if (!string_indexed && is_int)
|
||||
{
|
||||
const auto index = key.as<int>();
|
||||
obj[index] = gsc_to_json(array[index], print_id, ctx);
|
||||
}
|
||||
else if (string_indexed && is_string)
|
||||
{
|
||||
const auto key_str = key.as<std::string>();
|
||||
obj.emplace(key_str, gsc_to_json(array[key_str], print_id, ctx));
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
nlohmann::json object_to_json(const scripting::object& object, bool print_id, dump_context_t& ctx)
|
||||
{
|
||||
const auto id = object.get_entity_id();
|
||||
if (ctx.visited_objects.find(id) != ctx.visited_objects.end())
|
||||
{
|
||||
return utils::string::va("[struct reference %i]", id);
|
||||
}
|
||||
|
||||
ctx.visited_objects.insert(id);
|
||||
auto obj = nlohmann::json::object();
|
||||
|
||||
if (print_id)
|
||||
{
|
||||
obj["__id"] = id;
|
||||
}
|
||||
|
||||
const auto keys = object.get_keys();
|
||||
for (const auto& key : keys)
|
||||
{
|
||||
if (key == "__id")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
obj.emplace(key, gsc_to_json(object[key], print_id, ctx));
|
||||
}
|
||||
|
||||
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(const scripting::script_value& value, bool print_id, dump_context_t& ctx)
|
||||
{
|
||||
const auto& variable = value.get_raw();
|
||||
|
||||
if (value.is<int>())
|
||||
{
|
||||
return value.as<int>();
|
||||
}
|
||||
|
||||
if (value.is<float>())
|
||||
{
|
||||
return value.as<float>();
|
||||
}
|
||||
|
||||
if (value.is<std::string>())
|
||||
{
|
||||
return value.as<std::string>();
|
||||
}
|
||||
|
||||
if (value.is<scripting::vector>())
|
||||
{
|
||||
return vector_to_array(variable.u.vectorValue);
|
||||
}
|
||||
|
||||
if (value.is<scripting::object>())
|
||||
{
|
||||
return object_to_json(variable.u.uintValue, print_id, ctx);
|
||||
}
|
||||
|
||||
if (value.is<scripting::array>())
|
||||
{
|
||||
return array_to_json(variable.u.uintValue, print_id, ctx);
|
||||
}
|
||||
|
||||
if (value.is<scripting::entity>())
|
||||
{
|
||||
return object_to_json(variable.u.uintValue, print_id, ctx);
|
||||
}
|
||||
|
||||
if (value.is<scripting::function>())
|
||||
{
|
||||
const auto function = value.as<scripting::function>();
|
||||
return utils::string::va("[[ %s ]]", function.get_name().data());
|
||||
}
|
||||
|
||||
if (variable.type == game::SCRIPT_NONE)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (variable.type == game::SCRIPT_CODEPOS)
|
||||
{
|
||||
const auto function = scripting::find_function(variable.u.codePosValue);
|
||||
return utils::string::va("[codepos: %s]", function.data());
|
||||
}
|
||||
|
||||
if (variable.type == game::SCRIPT_END)
|
||||
{
|
||||
const auto function = scripting::find_function(variable.u.codePosValue);
|
||||
return utils::string::va("[precodepos: %s]", function.data());
|
||||
}
|
||||
|
||||
return utils::string::va("[%s]", value.type_name().data());
|
||||
}
|
||||
|
||||
scripting::script_value json_to_gsc(nlohmann::json obj)
|
||||
{
|
||||
const auto type = obj.type();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case (nlohmann::detail::value_t::boolean):
|
||||
return obj.get<bool>();
|
||||
case (nlohmann::detail::value_t::number_integer):
|
||||
case (nlohmann::detail::value_t::number_unsigned):
|
||||
return obj.get<int>();
|
||||
case (nlohmann::detail::value_t::number_float):
|
||||
return obj.get<float>();
|
||||
case (nlohmann::detail::value_t::string):
|
||||
return obj.get<std::string>();
|
||||
case (nlohmann::detail::value_t::array):
|
||||
{
|
||||
scripting::array array;
|
||||
|
||||
for (const auto& [key, value] : obj.items())
|
||||
{
|
||||
array.emplace_back(json_to_gsc(value));
|
||||
}
|
||||
|
||||
return array.get_raw();
|
||||
}
|
||||
case (nlohmann::detail::value_t::object):
|
||||
{
|
||||
scripting::array array;
|
||||
|
||||
for (const auto& [key, value] : obj.items())
|
||||
{
|
||||
array[key] = json_to_gsc(value);
|
||||
}
|
||||
|
||||
return array.get_raw();
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::string gsc_to_string(const scripting::script_value& value)
|
||||
{
|
||||
dump_context_t ctx;
|
||||
return gsc_to_json(value, false, ctx).dump();
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void on_startup([[maybe_unused]] plugin::plugin* plugin) override
|
||||
{
|
||||
gsc::function::add_multiple([](const scripting::variadic_args& args)
|
||||
{
|
||||
scripting::array array;
|
||||
|
||||
for (auto i = 0u; i < args.size(); i += 2)
|
||||
{
|
||||
if (i >= args.size() - 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto key = args[i].as<std::string>();
|
||||
array[key] = args[i + 1];
|
||||
}
|
||||
|
||||
return array;
|
||||
}, "createmap", "json::create_map");
|
||||
|
||||
gsc::function::add_multiple([](const std::string& json)
|
||||
{
|
||||
const auto obj = nlohmann::json::parse(json);
|
||||
return json_to_gsc(obj);
|
||||
}, "jsonparse", "json::parse");
|
||||
|
||||
gsc::function::add_multiple([](const scripting::script_value& value, const scripting::variadic_args& args)
|
||||
{
|
||||
auto indent = -1;
|
||||
auto print_id = false;
|
||||
|
||||
if (args.size() > 0)
|
||||
{
|
||||
indent = args[0].as<int>();
|
||||
}
|
||||
|
||||
if (args.size() > 1)
|
||||
{
|
||||
print_id = args[1].as<bool>();
|
||||
}
|
||||
|
||||
dump_context_t ctx;
|
||||
const auto json = gsc_to_json(value, print_id, ctx);
|
||||
auto dump = json.dump(indent);
|
||||
|
||||
if (dump.size() > max_str_len)
|
||||
{
|
||||
printf("^3WARNING: json dump longer than %i bytes, truncating!", max_str_len);
|
||||
dump.resize(max_str_len);
|
||||
}
|
||||
|
||||
return dump;
|
||||
}, "jsonserialize", "json::serialize");
|
||||
|
||||
gsc::function::add_multiple([](const std::string& file, const scripting::script_value& value, const scripting::variadic_args& va)
|
||||
{
|
||||
std::string file_name = file;
|
||||
|
||||
auto indent = -1;
|
||||
auto print_id = false;
|
||||
|
||||
if (!file_name.ends_with(".json"))
|
||||
{
|
||||
file_name.append(".json");
|
||||
}
|
||||
|
||||
if (va.size() > 0)
|
||||
{
|
||||
indent = va[0].as<int>();
|
||||
}
|
||||
|
||||
if (va.size() > 1)
|
||||
{
|
||||
print_id = va[1].as<bool>();
|
||||
}
|
||||
|
||||
dump_context_t ctx;
|
||||
const auto json = gsc_to_json(value, print_id, ctx);
|
||||
const auto dump = json.dump(indent);
|
||||
|
||||
return utils::io::write_file(file_name, dump);
|
||||
}, "jsondump", "json::dump");
|
||||
|
||||
gsc::function::add_multiple([](const scripting::variadic_args& args)
|
||||
{
|
||||
std::string buffer;
|
||||
|
||||
for (const auto& arg : args)
|
||||
{
|
||||
buffer.append(gsc_to_string(arg));
|
||||
buffer.append("\t");
|
||||
}
|
||||
|
||||
printf("%s\n", buffer.data());
|
||||
}, "jsonprint", "json::print");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(json::component)
|
||||
Reference in New Issue
Block a user