Better mod stats + add some gsc funcs
This commit is contained in:
parent
9ee00ba9e8
commit
234f29690f
@ -12,6 +12,37 @@
|
||||
|
||||
namespace gsc
|
||||
{
|
||||
std::array<const char*, 27> var_typename =
|
||||
{
|
||||
"undefined",
|
||||
"object",
|
||||
"string",
|
||||
"localized string",
|
||||
"vector",
|
||||
"float",
|
||||
"int",
|
||||
"codepos",
|
||||
"precodepos",
|
||||
"function",
|
||||
"builtin function",
|
||||
"builtin method",
|
||||
"stack",
|
||||
"animation",
|
||||
"pre animation",
|
||||
"thread",
|
||||
"thread",
|
||||
"thread",
|
||||
"thread",
|
||||
"struct",
|
||||
"removed entity",
|
||||
"entity",
|
||||
"array",
|
||||
"removed thread",
|
||||
"<free>",
|
||||
"thread list",
|
||||
"endon list",
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour scr_emit_function_hook;
|
||||
@ -20,37 +51,6 @@ namespace gsc
|
||||
|
||||
std::string unknown_function_error;
|
||||
|
||||
std::array<const char*, 27> var_typename =
|
||||
{
|
||||
"undefined",
|
||||
"object",
|
||||
"string",
|
||||
"localized string",
|
||||
"vector",
|
||||
"float",
|
||||
"int",
|
||||
"codepos",
|
||||
"precodepos",
|
||||
"function",
|
||||
"builtin function",
|
||||
"builtin method",
|
||||
"stack",
|
||||
"animation",
|
||||
"pre animation",
|
||||
"thread",
|
||||
"thread",
|
||||
"thread",
|
||||
"thread",
|
||||
"struct",
|
||||
"removed entity",
|
||||
"entity",
|
||||
"array",
|
||||
"removed thread",
|
||||
"<free>",
|
||||
"thread list",
|
||||
"endon list",
|
||||
};
|
||||
|
||||
void scr_emit_function_stub(unsigned int filename, unsigned int thread_name, char* code_pos)
|
||||
{
|
||||
current_filename = filename;
|
||||
|
@ -2,5 +2,7 @@
|
||||
|
||||
namespace gsc
|
||||
{
|
||||
extern std::array<const char*, 27> var_typename;
|
||||
|
||||
std::optional<std::pair<std::string, std::string>> find_function(const char* pos);
|
||||
}
|
||||
|
@ -10,8 +10,15 @@
|
||||
#include "component/console.hpp"
|
||||
#include "component/command.hpp"
|
||||
#include "component/notifies.hpp"
|
||||
#include "component/scheduler.hpp"
|
||||
#include "component/mods.hpp"
|
||||
#include "component/mod_stats.hpp"
|
||||
#include "component/scripting.hpp"
|
||||
|
||||
#include "game/scripting/script_value.hpp"
|
||||
#include "game/scripting/execution.hpp"
|
||||
|
||||
#include "game/ui_scripting/execution.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
@ -225,6 +232,42 @@ namespace gsc
|
||||
|
||||
return game::scr_VmPub->top[-index];
|
||||
}
|
||||
|
||||
nlohmann::json gsc_to_json(const scripting::script_value& value)
|
||||
{
|
||||
#define CHECK_TYPE(__type__) \
|
||||
if (value.is<__type__>()) \
|
||||
{ \
|
||||
return value.as<__type__>(); \
|
||||
} \
|
||||
|
||||
CHECK_TYPE(std::string);
|
||||
CHECK_TYPE(int);
|
||||
CHECK_TYPE(float);
|
||||
CHECK_TYPE(bool);
|
||||
|
||||
return {};
|
||||
|
||||
#undef CHECK_TYPE
|
||||
}
|
||||
|
||||
scripting::script_value json_to_gsc(const nlohmann::json& value)
|
||||
{
|
||||
#define CHECK_TYPE(__func__, __type__) \
|
||||
if (value.__func__()) \
|
||||
{ \
|
||||
return value.get<__type__>(); \
|
||||
} \
|
||||
|
||||
CHECK_TYPE(is_string, std::string);
|
||||
CHECK_TYPE(is_number_integer, int);
|
||||
CHECK_TYPE(is_number_float, float);
|
||||
CHECK_TYPE(is_boolean, bool);
|
||||
|
||||
return {};
|
||||
|
||||
#undef CHECK_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
void scr_error(bool force_print, const char* fmt, ...)
|
||||
@ -322,6 +365,115 @@ namespace gsc
|
||||
const auto cmd = game::Scr_GetString(0);
|
||||
command::execute(cmd);
|
||||
});
|
||||
|
||||
add_function("luinotify", []()
|
||||
{
|
||||
const std::string name = game::Scr_GetString(0);
|
||||
const std::string data = game::Scr_GetString(1);
|
||||
|
||||
scheduler::once([=]()
|
||||
{
|
||||
ui_scripting::notify(name, {{"data", data}});
|
||||
}, scheduler::pipeline::lui);
|
||||
});
|
||||
|
||||
add_function("statsset", []()
|
||||
{
|
||||
const auto key = game::Scr_GetString(0);
|
||||
const auto value = get_argument(1);
|
||||
const auto json_value = gsc_to_json(value);
|
||||
mod_stats::set(key, json_value);
|
||||
});
|
||||
|
||||
add_function("statssetstruct", []()
|
||||
{
|
||||
const auto struct_ = game::Scr_GetString(0);
|
||||
const auto field = game::Scr_GetString(1);
|
||||
const auto value = get_argument(2);
|
||||
const auto json_value = gsc_to_json(value);
|
||||
mod_stats::set_struct(struct_, field, json_value);
|
||||
});
|
||||
|
||||
add_function("statsget", []()
|
||||
{
|
||||
const auto key = game::Scr_GetString(0);
|
||||
const auto& value = mod_stats::get(key);
|
||||
scripting::push_value(json_to_gsc(value));
|
||||
});
|
||||
|
||||
add_function("statsgetor", []()
|
||||
{
|
||||
const auto key = game::Scr_GetString(0);
|
||||
const auto default_value = get_argument(1);
|
||||
const auto json_default_value = gsc_to_json(default_value);
|
||||
const auto value = mod_stats::get(key, json_default_value);
|
||||
scripting::push_value(json_to_gsc(value));
|
||||
});
|
||||
|
||||
add_function("statsgetstruct", []()
|
||||
{
|
||||
const auto struct_ = game::Scr_GetString(0);
|
||||
const auto field = game::Scr_GetString(1);
|
||||
const auto value = mod_stats::get_struct(struct_, field);
|
||||
scripting::push_value(json_to_gsc(value));
|
||||
});
|
||||
|
||||
add_function("statsgetstructor", []()
|
||||
{
|
||||
const auto struct_ = game::Scr_GetString(0);
|
||||
const auto field = game::Scr_GetString(1);
|
||||
const auto default_value = get_argument(2);
|
||||
const auto json_default_value = gsc_to_json(default_value);
|
||||
const auto value = mod_stats::get_struct(struct_, field, json_default_value);
|
||||
scripting::push_value(json_to_gsc(value));
|
||||
});
|
||||
|
||||
add_function("typeof", []()
|
||||
{
|
||||
const auto arg = get_argument(0);
|
||||
const auto type = arg.get_raw().type;
|
||||
|
||||
if (type < var_typename.size())
|
||||
{
|
||||
game::Scr_AddString(var_typename[type]);
|
||||
}
|
||||
else
|
||||
{
|
||||
game::Scr_AddString("unknown");
|
||||
}
|
||||
});
|
||||
|
||||
add_function("sharedset", []()
|
||||
{
|
||||
const std::string key = game::Scr_GetString(0);
|
||||
const std::string value = game::Scr_GetString(1);
|
||||
|
||||
scripting::shared_table.access([&](scripting::shared_table_t& table)
|
||||
{
|
||||
table[key] = value;
|
||||
});
|
||||
});
|
||||
|
||||
add_function("sharedget", []()
|
||||
{
|
||||
const std::string key = game::Scr_GetString(0);
|
||||
const auto value = scripting::shared_table.access<std::string>(
|
||||
[&](scripting::shared_table_t& table)
|
||||
{
|
||||
return table[key];
|
||||
}
|
||||
);
|
||||
|
||||
game::Scr_AddString(value.data());
|
||||
});
|
||||
|
||||
add_function("sharedclear", []()
|
||||
{
|
||||
scripting::shared_table.access([&](scripting::shared_table_t& table)
|
||||
{
|
||||
table.clear();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -20,6 +20,23 @@ namespace gui::debug
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct debug_line
|
||||
{
|
||||
float start[3];
|
||||
float end[3];
|
||||
float color[4];
|
||||
};
|
||||
|
||||
struct debug_square
|
||||
{
|
||||
float origin[3];
|
||||
float color[4];
|
||||
};
|
||||
|
||||
std::vector<debug_line> debug_lines;
|
||||
std::vector<debug_square> debug_squares;
|
||||
std::mutex debug_items_mutex;
|
||||
|
||||
game::dvar_t* cl_paused = nullptr;
|
||||
|
||||
enum object_type
|
||||
@ -570,6 +587,12 @@ namespace gui::debug
|
||||
continue;
|
||||
}
|
||||
|
||||
float screen_center[2]{};
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
world_pos_to_screen_pos(origin, screen_center);
|
||||
window->DrawList->AddText(ImGui::GetDefaultFont(), ImGui::GetFontSize(), ImVec2(screen_center[0],
|
||||
screen_center[1]), ImColor(255, 255, 0, 255), utils::string::va("%i", node->constant.type), 0, 0.f, 0);
|
||||
|
||||
switch (path_node_settings.type)
|
||||
{
|
||||
case object_type::square:
|
||||
@ -654,6 +677,21 @@ namespace gui::debug
|
||||
}
|
||||
}
|
||||
|
||||
void draw_debug_items()
|
||||
{
|
||||
std::lock_guard _0(debug_items_mutex);
|
||||
|
||||
for (auto& line : debug_lines)
|
||||
{
|
||||
draw_line(line.start, line.end, line.color, 1.f);
|
||||
}
|
||||
|
||||
for (auto& square : debug_squares)
|
||||
{
|
||||
draw_square(square.origin, 100.f, square.color);
|
||||
}
|
||||
}
|
||||
|
||||
void update_camera()
|
||||
{
|
||||
camera[0] = game::refdef->org[0];
|
||||
@ -688,6 +726,62 @@ namespace gui::debug
|
||||
}
|
||||
}
|
||||
|
||||
size_t add_debug_line(const float* start, const float* end, const float* color)
|
||||
{
|
||||
debug_line line{};
|
||||
std::memcpy(line.start, start, sizeof(float[3]));
|
||||
std::memcpy(line.end, end, sizeof(float[3]));
|
||||
std::memcpy(line.color, color, sizeof(float[4]));
|
||||
|
||||
std::lock_guard _0(debug_items_mutex);
|
||||
const auto index = debug_squares.size();
|
||||
debug_lines.emplace_back(line);
|
||||
return index;
|
||||
}
|
||||
|
||||
void set_debug_line_color(size_t line, const float* color)
|
||||
{
|
||||
std::lock_guard _0(debug_items_mutex);
|
||||
if (line >= debug_lines.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto& line_ = debug_lines.at(line);
|
||||
std::memcpy(line_.color, color, sizeof(float[4]));
|
||||
}
|
||||
|
||||
size_t add_debug_square(const float* origin, const float* color)
|
||||
{
|
||||
debug_square line{};
|
||||
std::memcpy(line.origin, origin, sizeof(float[3]));
|
||||
std::memcpy(line.color, color, sizeof(float[4]));
|
||||
|
||||
std::lock_guard _0(debug_items_mutex);
|
||||
const auto index = debug_squares.size();
|
||||
debug_squares.emplace_back(line);
|
||||
return index;
|
||||
}
|
||||
|
||||
void set_debug_square_color(size_t square, const float* color)
|
||||
{
|
||||
std::lock_guard _0(debug_items_mutex);
|
||||
if (square >= debug_squares.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto& square_ = debug_squares.at(square);
|
||||
std::memcpy(square_.color, color, sizeof(float[4]));
|
||||
}
|
||||
|
||||
void reset_debug_items()
|
||||
{
|
||||
std::lock_guard _0(debug_items_mutex);
|
||||
debug_lines.clear();
|
||||
debug_squares.clear();
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
@ -705,6 +799,7 @@ namespace gui::debug
|
||||
begin_render_window();
|
||||
draw_nodes();
|
||||
draw_triggers();
|
||||
draw_debug_items();
|
||||
end_render_window();
|
||||
}, true);
|
||||
|
||||
|
10
src/client/component/gui/debug.hpp
Normal file
10
src/client/component/gui/debug.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
namespace gui::debug
|
||||
{
|
||||
size_t add_debug_line(const float* start, const float* end, const float* color);
|
||||
void set_debug_line_color(size_t line, const float* color);
|
||||
|
||||
size_t add_debug_square(const float* origin, const float* color);
|
||||
void set_debug_square_color(size_t square, const float* color);
|
||||
|
||||
void reset_debug_items();
|
||||
}
|
245
src/client/component/mod_stats.cpp
Normal file
245
src/client/component/mod_stats.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "console.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "mods.hpp"
|
||||
#include "mod_stats.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
#include <utils/thread.hpp>
|
||||
#include <utils/properties.hpp>
|
||||
|
||||
namespace mod_stats
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct
|
||||
{
|
||||
utils::concurrency::container<mod_stats_t> current_stats;
|
||||
std::atomic_bool modified_stats;
|
||||
std::atomic_bool kill_thread;
|
||||
std::thread stats_write_thread;
|
||||
} globals{};
|
||||
|
||||
std::optional<std::string> get_mod_basename()
|
||||
{
|
||||
const auto mod = mods::get_mod();
|
||||
if (!mod.has_value())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& value = mod.value();
|
||||
const auto last_index = value.find_last_of('/');
|
||||
const auto basename = value.substr(last_index + 1);
|
||||
return {basename};
|
||||
}
|
||||
|
||||
std::optional<std::string> get_stats_path()
|
||||
{
|
||||
const auto current_mod = get_mod_basename();
|
||||
if (!current_mod.has_value())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto path = utils::properties::get_appdata_path() /
|
||||
"player/modstats" / (current_mod.value() + ".json");
|
||||
return {path.generic_string()};
|
||||
}
|
||||
|
||||
nlohmann::json default_mod_stats()
|
||||
{
|
||||
nlohmann::json json;
|
||||
json["maps"] = {};
|
||||
return json;
|
||||
}
|
||||
|
||||
nlohmann::json verify_mod_stats(nlohmann::json& json)
|
||||
{
|
||||
if (!json.is_object())
|
||||
{
|
||||
json = {};
|
||||
}
|
||||
|
||||
if (!json.contains("maps") || !json["maps"].is_object())
|
||||
{
|
||||
json["maps"] = {};
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
nlohmann::json parse_mod_stats()
|
||||
{
|
||||
const auto stats_file = get_stats_path();
|
||||
if (!stats_file.has_value())
|
||||
{
|
||||
return default_mod_stats();
|
||||
}
|
||||
|
||||
const auto& stats_file_value = stats_file.value();
|
||||
if (!utils::io::file_exists(stats_file_value))
|
||||
{
|
||||
return default_mod_stats();
|
||||
}
|
||||
|
||||
const auto data = utils::io::read_file(stats_file_value);
|
||||
try
|
||||
{
|
||||
auto json = nlohmann::json::parse(data);
|
||||
return verify_mod_stats(json);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
console::error("Failed to parse json mod stats file \"%s\": %s",
|
||||
stats_file_value.data(), e.what());
|
||||
}
|
||||
|
||||
return default_mod_stats();
|
||||
}
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
globals.modified_stats = false;
|
||||
globals.current_stats.access([](mod_stats_t& stats)
|
||||
{
|
||||
stats = parse_mod_stats();
|
||||
});
|
||||
}
|
||||
|
||||
utils::concurrency::container<mod_stats_t>& get_stats()
|
||||
{
|
||||
return globals.current_stats;
|
||||
}
|
||||
|
||||
void set_modified()
|
||||
{
|
||||
globals.modified_stats = true;
|
||||
}
|
||||
|
||||
void write()
|
||||
{
|
||||
const auto path = get_stats_path();
|
||||
if (!path.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
console::debug("[Mod stats] writing stats\n");
|
||||
globals.current_stats.access([&](mod_stats_t& stats)
|
||||
{
|
||||
const auto dump = stats.dump(4);
|
||||
const auto& path_value = path.value();
|
||||
utils::io::write_file(path_value, dump, false);
|
||||
globals.modified_stats = false;
|
||||
});
|
||||
}
|
||||
|
||||
nlohmann::json get(const std::string& key, const nlohmann::json& default_value)
|
||||
{
|
||||
return get_stats().access<nlohmann::json>([&](mod_stats_t& stats)
|
||||
-> nlohmann::json
|
||||
{
|
||||
if (!stats.is_object() || stats[key].is_null())
|
||||
{
|
||||
return default_value;
|
||||
}
|
||||
|
||||
return stats[key];
|
||||
});
|
||||
}
|
||||
|
||||
nlohmann::json get_all()
|
||||
{
|
||||
return get_stats().access<nlohmann::json>([&](mod_stats_t& stats)
|
||||
-> nlohmann::json
|
||||
{
|
||||
return stats;
|
||||
});
|
||||
}
|
||||
|
||||
nlohmann::json get_struct(const std::string& name, const std::string& field, const nlohmann::json& default_value)
|
||||
{
|
||||
return get_stats().access<nlohmann::json>([&](mod_stats_t& stats)
|
||||
-> nlohmann::json
|
||||
{
|
||||
if (!stats.is_object() || !stats[name].is_object() || stats[name].is_null())
|
||||
{
|
||||
return default_value;
|
||||
}
|
||||
|
||||
return stats[name][field];
|
||||
});
|
||||
}
|
||||
|
||||
void set(const std::string& key, const nlohmann::json& value)
|
||||
{
|
||||
get_stats().access([&](mod_stats_t& stats)
|
||||
{
|
||||
stats[key] = value;
|
||||
set_modified();
|
||||
});
|
||||
}
|
||||
|
||||
void set_struct(const std::string& name, const std::string& field, const nlohmann::json& value)
|
||||
{
|
||||
get_stats().access([&](mod_stats_t& stats)
|
||||
{
|
||||
stats[name][field] = value;
|
||||
set_modified();
|
||||
});
|
||||
}
|
||||
|
||||
void set_all(const nlohmann::json& value)
|
||||
{
|
||||
get_stats().access([&](mod_stats_t& stats)
|
||||
{
|
||||
stats = value;
|
||||
set_modified();
|
||||
});
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
globals.stats_write_thread = utils::thread::create_named_thread("Stats Write (H2-Mod)", []()
|
||||
{
|
||||
while (!globals.kill_thread)
|
||||
{
|
||||
const auto _0 = gsl::finally([]
|
||||
{
|
||||
std::this_thread::sleep_for(50ms);
|
||||
});
|
||||
|
||||
if (!globals.modified_stats)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
write();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
{
|
||||
globals.kill_thread = true;
|
||||
if (globals.stats_write_thread.joinable())
|
||||
{
|
||||
globals.stats_write_thread.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(mod_stats::component)
|
21
src/client/component/mod_stats.hpp
Normal file
21
src/client/component/mod_stats.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace mod_stats
|
||||
{
|
||||
using mod_stats_t = nlohmann::ordered_json;
|
||||
utils::concurrency::container<mod_stats_t>& get_stats();
|
||||
|
||||
void initialize();
|
||||
void set_modified();
|
||||
void write();
|
||||
|
||||
nlohmann::json get(const std::string& key, const nlohmann::json& default_value = {});
|
||||
nlohmann::json get_struct(const std::string& name, const std::string& field, const nlohmann::json& default_value = {});
|
||||
nlohmann::json get_all();
|
||||
|
||||
void set(const std::string& key, const nlohmann::json& value);
|
||||
void set_struct(const std::string& name, const std::string& field, const nlohmann::json& value);
|
||||
void set_all(const nlohmann::json& value);
|
||||
}
|
@ -9,11 +9,13 @@
|
||||
#include "filesystem.hpp"
|
||||
#include "fonts.hpp"
|
||||
#include "mods.hpp"
|
||||
#include "mod_stats.hpp"
|
||||
#include "loadscreen.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
#define MOD_FOLDER "mods"
|
||||
#define MOD_STATS_FOLDER "players2/modstats"
|
||||
@ -174,97 +176,6 @@ namespace mods
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> get_mod_basename()
|
||||
{
|
||||
const auto mod = get_mod();
|
||||
if (!mod.has_value())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& value = mod.value();
|
||||
const auto last_index = value.find_last_of('/');
|
||||
const auto basename = value.substr(last_index + 1);
|
||||
return {basename};
|
||||
}
|
||||
|
||||
nlohmann::json default_mod_stats()
|
||||
{
|
||||
nlohmann::json json;
|
||||
json["maps"] = {};
|
||||
return json;
|
||||
}
|
||||
|
||||
nlohmann::json verify_mod_stats(nlohmann::json& json)
|
||||
{
|
||||
if (!json.is_object())
|
||||
{
|
||||
json = {};
|
||||
}
|
||||
|
||||
if (!json.contains("maps") || !json["maps"].is_object())
|
||||
{
|
||||
json["maps"] = {};
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
nlohmann::json parse_mod_stats()
|
||||
{
|
||||
const auto name = get_mod_basename();
|
||||
if (!name.has_value())
|
||||
{
|
||||
return default_mod_stats();
|
||||
}
|
||||
|
||||
const auto& name_value = name.value();
|
||||
const auto stat_file = MOD_STATS_FOLDER "/" + name_value + ".json";
|
||||
if (!utils::io::file_exists(stat_file))
|
||||
{
|
||||
return default_mod_stats();
|
||||
}
|
||||
|
||||
const auto data = utils::io::read_file(stat_file);
|
||||
try
|
||||
{
|
||||
auto json = nlohmann::json::parse(data);
|
||||
return verify_mod_stats(json);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
console::error("Failed to parse json mod stat file \"%s.json\": %s",
|
||||
name_value.data(), e.what());
|
||||
}
|
||||
|
||||
return default_mod_stats();
|
||||
}
|
||||
|
||||
void initialize_stats()
|
||||
{
|
||||
get_current_stats() = parse_mod_stats();
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json& get_current_stats()
|
||||
{
|
||||
static nlohmann::json stats;
|
||||
stats = verify_mod_stats(stats);
|
||||
return stats;
|
||||
}
|
||||
|
||||
void write_mod_stats()
|
||||
{
|
||||
const auto name = get_mod_basename();
|
||||
if (!name.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& name_value = name.value();
|
||||
const auto stat_file = MOD_STATS_FOLDER "/" + name_value + ".json";
|
||||
utils::io::write_file(stat_file, get_current_stats().dump(), false);
|
||||
}
|
||||
|
||||
bool mod_requires_restart(const std::string& path)
|
||||
@ -281,9 +192,9 @@ namespace mods
|
||||
filesystem::unregister_path(mod_info.path.value());
|
||||
}
|
||||
|
||||
write_mod_stats();
|
||||
initialize_stats();
|
||||
mod_stats::write();
|
||||
mod_info.path = path;
|
||||
mod_stats::initialize();
|
||||
filesystem::register_path(path);
|
||||
parse_mod_zones();
|
||||
}
|
||||
|
@ -34,7 +34,4 @@ namespace mods
|
||||
std::vector<std::string> get_mod_list();
|
||||
std::optional<nlohmann::json> get_mod_info(const std::string& mod);
|
||||
bool mod_exists(const std::string& folder);
|
||||
|
||||
nlohmann::json& get_current_stats();
|
||||
void write_mod_stats();
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
#include "scheduler.hpp"
|
||||
#include "scripting.hpp"
|
||||
#include "console.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include "gsc/script_loading.hpp"
|
||||
|
||||
@ -173,6 +174,7 @@ namespace scripting
|
||||
|
||||
void add_function_sort(unsigned int id, const char* pos)
|
||||
{
|
||||
|
||||
std::string filename = current_file;
|
||||
if (current_file_id)
|
||||
{
|
||||
@ -369,6 +371,12 @@ namespace scripting
|
||||
|
||||
utils::hook::call(0x1404B07D2, get_spawn_point_stub);
|
||||
|
||||
command::add("getfunctionptr", [](const command::params& params)
|
||||
{
|
||||
const auto func = find_function(params.get(1), false);
|
||||
console::info("%p\n", func);
|
||||
});
|
||||
|
||||
scheduler::loop([]()
|
||||
{
|
||||
lua::engine::run_frame();
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "scripting.hpp"
|
||||
#include "fastfiles.hpp"
|
||||
#include "mods.hpp"
|
||||
#include "mod_stats.hpp"
|
||||
#include "updater.hpp"
|
||||
#include "console.hpp"
|
||||
#include "language.hpp"
|
||||
@ -505,41 +506,37 @@ namespace ui_scripting
|
||||
mods_stats_table["set"] = [](const std::string& key, const script_value& value)
|
||||
{
|
||||
const auto json_value = lua_to_json(value);
|
||||
mods::get_current_stats()[key] = json_value;
|
||||
mods::write_mod_stats();
|
||||
mod_stats::set(key, json_value);
|
||||
};
|
||||
|
||||
mods_stats_table["get"] = [](const std::string& key)
|
||||
{
|
||||
return json_to_lua(mods::get_current_stats());
|
||||
return json_to_lua(mod_stats::get(key));
|
||||
};
|
||||
|
||||
mods_stats_table["mapset"] = [](const std::string& mapname,
|
||||
mods_stats_table["setstruct"] = [](const std::string& mapname,
|
||||
const std::string& key, const script_value& value)
|
||||
{
|
||||
const auto json_value = lua_to_json(value);
|
||||
auto& stats = mods::get_current_stats();
|
||||
stats["maps"][mapname][key] = json_value;
|
||||
mods::write_mod_stats();
|
||||
mod_stats::set_struct(mapname, key, json_value);
|
||||
};
|
||||
|
||||
mods_stats_table["mapget"] = [](const std::string& mapname,
|
||||
mods_stats_table["getstruct"] = [](const std::string& mapname,
|
||||
const std::string& key)
|
||||
{
|
||||
auto& stats = mods::get_current_stats();
|
||||
return json_to_lua(stats["maps"][mapname][key]);
|
||||
return json_to_lua(mod_stats::get_struct(mapname, key));
|
||||
};
|
||||
|
||||
mods_stats_table["save"] = mods::write_mod_stats;
|
||||
mods_stats_table["save"] = mod_stats::write;
|
||||
mods_stats_table["getall"] = []()
|
||||
{
|
||||
return json_to_lua(mods::get_current_stats());
|
||||
return json_to_lua(mod_stats::get_all());
|
||||
};
|
||||
|
||||
mods_stats_table["setfromjson"] = [](const std::string& data)
|
||||
{
|
||||
const auto json = nlohmann::json::parse(data);
|
||||
mods::get_current_stats() = json;
|
||||
mod_stats::set_all(json);
|
||||
};
|
||||
|
||||
auto config_table = table();
|
||||
@ -742,6 +739,11 @@ namespace ui_scripting
|
||||
lua["table"]["unpack"] = lua["unpack"];
|
||||
lua["luiglobals"] = lua;
|
||||
|
||||
lua["printmemoryusage"] = []()
|
||||
{
|
||||
utils::hook::invoke<void>(0x14031F470);
|
||||
};
|
||||
|
||||
load_script("lui_common", lui_common);
|
||||
load_script("lui_updater", lui_updater);
|
||||
load_script("lua_json", lua_json);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "component/mods.hpp"
|
||||
#include "component/scheduler.hpp"
|
||||
#include "component/filesystem.hpp"
|
||||
#include "component/gui/debug.hpp"
|
||||
|
||||
#include "component/gsc/script_loading.hpp"
|
||||
|
||||
@ -478,6 +479,64 @@ namespace scripting::lua
|
||||
return sol::as_returns(returns);
|
||||
};
|
||||
}
|
||||
|
||||
void setup_debug_funcs(sol::state& state)
|
||||
{
|
||||
struct debug
|
||||
{
|
||||
};
|
||||
auto debug_type = state.new_usertype<debug>("debug_");
|
||||
state["debug"] = debug();
|
||||
|
||||
debug_type["reset"] = [](const debug&)
|
||||
{
|
||||
gui::debug::reset_debug_items();
|
||||
};
|
||||
|
||||
debug_type["addline"] = [](const debug&, const vector& start, const vector& end, const vector& color)
|
||||
{
|
||||
float color_[4]{};
|
||||
color_[0] = color[0];
|
||||
color_[1] = color[1];
|
||||
color_[2] = color[2];
|
||||
color_[3] = 1.f;
|
||||
|
||||
return gui::debug::add_debug_line(start, end, color_);
|
||||
};
|
||||
|
||||
debug_type["addsquare"] = [](const debug&, const vector& origin, const vector& color)
|
||||
{
|
||||
float color_[4]{};
|
||||
color_[0] = color[0];
|
||||
color_[1] = color[1];
|
||||
color_[2] = color[2];
|
||||
color_[3] = 1.f;
|
||||
|
||||
return gui::debug::add_debug_square(origin, color_);
|
||||
};
|
||||
|
||||
debug_type["setsquarecolor"] = [](const debug&, const size_t& square, const vector& color)
|
||||
{
|
||||
float color_[4]{};
|
||||
color_[0] = color[0];
|
||||
color_[1] = color[1];
|
||||
color_[2] = color[2];
|
||||
color_[3] = 1.f;
|
||||
|
||||
gui::debug::set_debug_square_color(square, color_);
|
||||
};
|
||||
|
||||
debug_type["setlinecolor"] = [](const debug&, const size_t& line, const vector& color)
|
||||
{
|
||||
float color_[4]{};
|
||||
color_[0] = color[0];
|
||||
color_[1] = color[1];
|
||||
color_[2] = color[2];
|
||||
color_[3] = 1.f;
|
||||
|
||||
gui::debug::set_debug_line_color(line, color_);
|
||||
};
|
||||
}
|
||||
|
||||
void setup_game_type(sol::state& state, event_handler& handler, scheduler& scheduler)
|
||||
{
|
||||
@ -793,14 +852,6 @@ namespace scripting::lua
|
||||
scripting::get_dvar_int_overrides.erase(dvar);
|
||||
};
|
||||
|
||||
game_type["luinotify"] = [](const game&, const std::string& name, const std::string& data)
|
||||
{
|
||||
::scheduler::once([=]()
|
||||
{
|
||||
ui_scripting::notify(name, {{"data", data}});
|
||||
}, ::scheduler::pipeline::lui);
|
||||
};
|
||||
|
||||
auto function_ptr_type = state.new_usertype<function_ptr>("functionptr",
|
||||
sol::constructors<function_ptr(const std::string&, const std::string&)>());
|
||||
|
||||
@ -845,6 +896,7 @@ namespace scripting::lua
|
||||
setup_io(this->state_);
|
||||
setup_json(this->state_);
|
||||
setup_vector_type(this->state_);
|
||||
setup_debug_funcs(this->state_);
|
||||
setup_entity_type(this->state_, this->event_handler_, this->scheduler_);
|
||||
setup_game_type(this->state_, this->event_handler_, this->scheduler_);
|
||||
|
||||
@ -877,6 +929,7 @@ namespace scripting::lua
|
||||
setup_io(this->state_);
|
||||
setup_json(this->state_);
|
||||
setup_vector_type(this->state_);
|
||||
setup_debug_funcs(this->state_);
|
||||
setup_entity_type(this->state_, this->event_handler_, this->scheduler_);
|
||||
setup_game_type(this->state_, this->event_handler_, this->scheduler_);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user