Add mod stats funcs
This commit is contained in:
parent
c7f6864aea
commit
0225505661
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -46,3 +46,6 @@
|
|||||||
[submodule "deps/gsc-tool-h2"]
|
[submodule "deps/gsc-tool-h2"]
|
||||||
path = deps/gsc-tool-h2
|
path = deps/gsc-tool-h2
|
||||||
url = https://github.com/fedddddd/gsc-tool-h2.git
|
url = https://github.com/fedddddd/gsc-tool-h2.git
|
||||||
|
[submodule "deps/json"]
|
||||||
|
path = deps/json
|
||||||
|
url = https://github.com/nlohmann/json.git
|
||||||
|
@ -39,24 +39,22 @@ LUI.addmenubutton("main_campaign", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function getmodname(path)
|
function getmodname(path)
|
||||||
local name = path
|
local modinfo = mods.getinfo(path)
|
||||||
game:addlocalizedstring(name, name)
|
|
||||||
local desc = Engine.Localize("LUA_MENU_MOD_DESC_DEFAULT", name)
|
|
||||||
local infofile = path .. "/info.json"
|
|
||||||
|
|
||||||
if (io.fileexists(infofile)) then
|
if (not modinfo.isvalid) then
|
||||||
pcall(function()
|
game:addlocalizedstring(path, path)
|
||||||
local data = json.decode(io.readfile(infofile))
|
local desc = Engine.Localize("LUA_MENU_MOD_DESC_DEFAULT", path)
|
||||||
game:addlocalizedstring(data.description, data.description)
|
|
||||||
game:addlocalizedstring(data.author, data.author)
|
return path, desc
|
||||||
game:addlocalizedstring(data.version, data.version)
|
else
|
||||||
desc = Engine.Localize("@LUA_MENU_MOD_DESC",
|
game:addlocalizedstring(modinfo.name, modinfo.name)
|
||||||
data.description, data.author, data.version)
|
game:addlocalizedstring(modinfo.description, modinfo.description)
|
||||||
name = data.name
|
game:addlocalizedstring(modinfo.author, modinfo.author)
|
||||||
end)
|
game:addlocalizedstring(modinfo.version, modinfo.version)
|
||||||
|
local desc = Engine.Localize("@LUA_MENU_MOD_DESC",
|
||||||
|
modinfo.description, modinfo.author, modinfo.version)
|
||||||
|
return modinfo.name, desc
|
||||||
end
|
end
|
||||||
|
|
||||||
return name, desc
|
|
||||||
end
|
end
|
||||||
|
|
||||||
LUI.MenuBuilder.registerType("mods_menu", function(a1)
|
LUI.MenuBuilder.registerType("mods_menu", function(a1)
|
||||||
@ -69,13 +67,13 @@ LUI.MenuBuilder.registerType("mods_menu", function(a1)
|
|||||||
uppercase_title = true
|
uppercase_title = true
|
||||||
})
|
})
|
||||||
|
|
||||||
menu:AddButton("@LUA_MENU_WORKSHOP", function()
|
--[[menu:AddButton("@LUA_MENU_WORKSHOP", function()
|
||||||
if (LUI.MenuBuilder.m_types_build["mods_workshop_menu"]) then
|
if (LUI.MenuBuilder.m_types_build["mods_workshop_menu"]) then
|
||||||
LUI.FlowManager.RequestAddMenu(nil, "mods_workshop_menu")
|
LUI.FlowManager.RequestAddMenu(nil, "mods_workshop_menu")
|
||||||
end
|
end
|
||||||
end, nil, true, nil, {
|
end, nil, true, nil, {
|
||||||
desc_text = Engine.Localize("@LUA_MENU_WORKSHOP_DESC")
|
desc_text = Engine.Localize("@LUA_MENU_WORKSHOP_DESC")
|
||||||
})
|
})--]]
|
||||||
|
|
||||||
local modfolder = game:getloadedmod()
|
local modfolder = game:getloadedmod()
|
||||||
if (modfolder ~= "") then
|
if (modfolder ~= "") then
|
||||||
@ -91,21 +89,21 @@ LUI.MenuBuilder.registerType("mods_menu", function(a1)
|
|||||||
|
|
||||||
createdivider(menu, Engine.Localize("@LUA_MENU_AVAILABLE_MODS"))
|
createdivider(menu, Engine.Localize("@LUA_MENU_AVAILABLE_MODS"))
|
||||||
|
|
||||||
if (io.directoryexists("mods")) then
|
local contentpresent = false
|
||||||
local mods = io.listfiles("mods/")
|
|
||||||
for i = 1, #mods do
|
|
||||||
if (io.directoryexists(mods[i]) and not io.directoryisempty(mods[i])) then
|
|
||||||
local name, desc = getmodname(mods[i])
|
|
||||||
|
|
||||||
if (mods[i] ~= modfolder) then
|
local mods = mods.getlist()
|
||||||
game:addlocalizedstring(name, name)
|
for i = 1, #mods do
|
||||||
menu:AddButton(name, function()
|
contentpresent = true
|
||||||
Engine.Exec("loadmod " .. mods[i])
|
|
||||||
end, nil, true, nil, {
|
local name, desc = getmodname(mods[i])
|
||||||
desc_text = desc
|
|
||||||
})
|
if (mods[i] ~= modfolder) then
|
||||||
end
|
game:addlocalizedstring(name, name)
|
||||||
end
|
menu:AddButton(name, function()
|
||||||
|
Engine.Exec("loadmod " .. mods[i])
|
||||||
|
end, nil, true, nil, {
|
||||||
|
desc_text = desc
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -116,7 +114,10 @@ LUI.MenuBuilder.registerType("mods_menu", function(a1)
|
|||||||
|
|
||||||
LUI.Options.InitScrollingList(menu.list, nil)
|
LUI.Options.InitScrollingList(menu.list, nil)
|
||||||
menu:CreateBottomDivider()
|
menu:CreateBottomDivider()
|
||||||
menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu)
|
|
||||||
|
if (contentpresent) then
|
||||||
|
menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu)
|
||||||
|
end
|
||||||
|
|
||||||
return menu
|
return menu
|
||||||
end)
|
end)
|
||||||
|
1
deps/json
vendored
Submodule
1
deps/json
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b2306145e1789368e6f261680e8dc007e91cc986
|
17
deps/premake/json.lua
vendored
Normal file
17
deps/premake/json.lua
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
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)
|
@ -97,6 +97,23 @@ namespace filesystem
|
|||||||
static auto current_path = std::filesystem::current_path().string();
|
static auto current_path = std::filesystem::current_path().string();
|
||||||
return current_path.data();
|
return current_path.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_parent_path(const std::filesystem::path& parent, const std::filesystem::path& child)
|
||||||
|
{
|
||||||
|
std::filesystem::path iter = child;
|
||||||
|
|
||||||
|
while (iter != iter.parent_path())
|
||||||
|
{
|
||||||
|
if (iter == parent)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = iter.parent_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string read_file(const std::string& path)
|
std::string read_file(const std::string& path)
|
||||||
@ -230,6 +247,50 @@ namespace filesystem
|
|||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void check_path(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
if (path.generic_string().find("..") != std::string::npos)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("directory traversal is not allowed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_safe_path(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
check_path(path);
|
||||||
|
const auto absolute = std::filesystem::weakly_canonical(path);
|
||||||
|
|
||||||
|
static std::vector<std::filesystem::path> allowed_directories =
|
||||||
|
{
|
||||||
|
{std::filesystem::weakly_canonical("mods")},
|
||||||
|
{std::filesystem::weakly_canonical("h2-mod")},
|
||||||
|
{std::filesystem::weakly_canonical("players2/default")},
|
||||||
|
};
|
||||||
|
|
||||||
|
auto is_allowed = false;
|
||||||
|
for (const auto& dir : allowed_directories)
|
||||||
|
{
|
||||||
|
if (is_parent_path(dir, absolute))
|
||||||
|
{
|
||||||
|
is_allowed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_allowed)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::format("Disallowed access to directory \"{}\"", path.generic_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.generic_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool safe_write_file(const std::string& file, const std::string& data, bool append)
|
||||||
|
{
|
||||||
|
const auto path = filesystem::get_safe_path(file);
|
||||||
|
return utils::io::write_file(path, data, append);
|
||||||
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -14,4 +14,7 @@ namespace filesystem
|
|||||||
|
|
||||||
std::vector<std::string> get_search_paths();
|
std::vector<std::string> get_search_paths();
|
||||||
std::vector<std::string> get_search_paths_rev();
|
std::vector<std::string> get_search_paths_rev();
|
||||||
|
|
||||||
|
std::string get_safe_path(const std::filesystem::path& path);
|
||||||
|
bool safe_write_file(const std::string& file, const std::string& data, bool append = false);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
|
#define MOD_FOLDER "mods"
|
||||||
|
#define MOD_STATS_FOLDER "players2/modstats"
|
||||||
|
|
||||||
namespace mods
|
namespace mods
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
@ -123,6 +126,97 @@ namespace mods
|
|||||||
mod_info.zone_info.zones.emplace_back(values[1], alloc_flags);
|
mod_info.zone_info.zones.emplace_back(values[1], alloc_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
bool mod_requires_restart(const std::string& path)
|
||||||
@ -139,6 +233,8 @@ namespace mods
|
|||||||
filesystem::unregister_path(mod_info.path.value());
|
filesystem::unregister_path(mod_info.path.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write_mod_stats();
|
||||||
|
initialize_stats();
|
||||||
mod_info.path = path;
|
mod_info.path = path;
|
||||||
filesystem::register_path(path);
|
filesystem::register_path(path);
|
||||||
parse_mod_zones();
|
parse_mod_zones();
|
||||||
@ -165,14 +261,63 @@ namespace mods
|
|||||||
return mod_info.path;
|
return mod_info.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> get_mod_list()
|
||||||
|
{
|
||||||
|
if (!utils::io::directory_exists(MOD_FOLDER))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> mod_list;
|
||||||
|
|
||||||
|
const auto files = utils::io::list_files(MOD_FOLDER);
|
||||||
|
for (const auto& file : files)
|
||||||
|
{
|
||||||
|
if (!utils::io::directory_exists(file) || utils::io::directory_is_empty(file))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_list.push_back(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<nlohmann::json> get_mod_info(const std::string& name)
|
||||||
|
{
|
||||||
|
const auto info_file = name + "/info.json";
|
||||||
|
if (!utils::io::directory_exists(name) || !utils::io::file_exists(info_file))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> info;
|
||||||
|
const auto data = utils::io::read_file(info_file);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return {nlohmann::json::parse(data)};
|
||||||
|
}
|
||||||
|
catch (const std::exception&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
if (!utils::io::directory_exists("mods"))
|
if (!utils::io::directory_exists(MOD_FOLDER))
|
||||||
{
|
{
|
||||||
utils::io::create_directory("mods");
|
utils::io::create_directory(MOD_FOLDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!utils::io::directory_exists(MOD_STATS_FOLDER))
|
||||||
|
{
|
||||||
|
utils::io::create_directory(MOD_STATS_FOLDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
db_release_xassets_hook.create(0x140416A80, db_release_xassets_stub);
|
db_release_xassets_hook.create(0x140416A80, db_release_xassets_stub);
|
||||||
|
@ -12,4 +12,10 @@ namespace mods
|
|||||||
void set_mod(const std::string& path);
|
void set_mod(const std::string& path);
|
||||||
std::optional<std::string> get_mod();
|
std::optional<std::string> get_mod();
|
||||||
std::vector<mod_zone> get_mod_zones();
|
std::vector<mod_zone> get_mod_zones();
|
||||||
|
|
||||||
|
std::vector<std::string> get_mod_list();
|
||||||
|
std::optional<nlohmann::json> get_mod_info(const std::string& mod);
|
||||||
|
|
||||||
|
nlohmann::json& get_current_stats();
|
||||||
|
void write_mod_stats();
|
||||||
}
|
}
|
@ -142,21 +142,106 @@ namespace ui_scripting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename R>
|
||||||
|
std::function<R(const std::string& str)>
|
||||||
|
safe_io_func(const std::function<R(const std::string& str)>& func)
|
||||||
|
{
|
||||||
|
return [func](const std::string& path)
|
||||||
|
{
|
||||||
|
const auto safe_path = filesystem::get_safe_path(path);
|
||||||
|
return func(safe_path);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value json_to_lua(const nlohmann::json& json)
|
||||||
|
{
|
||||||
|
if (json.is_object())
|
||||||
|
{
|
||||||
|
table object;
|
||||||
|
for (const auto& [key, value] : json.items())
|
||||||
|
{
|
||||||
|
object[key] = json_to_lua(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.is_array())
|
||||||
|
{
|
||||||
|
table array;
|
||||||
|
auto index = 1;
|
||||||
|
for (const auto& value : json.array())
|
||||||
|
{
|
||||||
|
array[index++] = json_to_lua(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.is_boolean())
|
||||||
|
{
|
||||||
|
return json.get<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.is_number_integer())
|
||||||
|
{
|
||||||
|
return json.get<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.is_number_float())
|
||||||
|
{
|
||||||
|
return json.get<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.is_string())
|
||||||
|
{
|
||||||
|
return json.get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json lua_to_json(const script_value& value)
|
||||||
|
{
|
||||||
|
if (value.is<bool>())
|
||||||
|
{
|
||||||
|
return value.as<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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.get_raw().t == game::hks::TNIL)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("lua value must be of primitive type (boolean, integer, float, string)");
|
||||||
|
}
|
||||||
|
|
||||||
void setup_functions()
|
void setup_functions()
|
||||||
{
|
{
|
||||||
const auto lua = get_globals();
|
const auto lua = get_globals();
|
||||||
|
|
||||||
lua["io"]["fileexists"] = utils::io::file_exists;
|
lua["io"]["fileexists"] = safe_io_func<bool>(utils::io::file_exists);
|
||||||
lua["io"]["writefile"] = utils::io::write_file;
|
lua["io"]["writefile"] = filesystem::safe_write_file;
|
||||||
lua["io"]["movefile"] = utils::io::move_file;
|
lua["io"]["filesize"] = safe_io_func<size_t>(utils::io::file_size);
|
||||||
lua["io"]["filesize"] = utils::io::file_size;
|
lua["io"]["createdirectory"] = safe_io_func<bool>(utils::io::create_directory);
|
||||||
lua["io"]["createdirectory"] = utils::io::create_directory;
|
lua["io"]["directoryexists"] = safe_io_func<bool>(utils::io::directory_exists);
|
||||||
lua["io"]["directoryexists"] = utils::io::directory_exists;
|
lua["io"]["directoryisempty"] = safe_io_func<bool>(utils::io::directory_is_empty);
|
||||||
lua["io"]["directoryisempty"] = utils::io::directory_is_empty;
|
lua["io"]["listfiles"] = safe_io_func<std::vector<std::string>>(utils::io::list_files);
|
||||||
lua["io"]["listfiles"] = utils::io::list_files;
|
lua["io"]["removefile"] = safe_io_func<bool>(utils::io::remove_file);
|
||||||
lua["io"]["removefile"] = utils::io::remove_file;
|
lua["io"]["removedirectory"] = safe_io_func<bool>(utils::io::remove_directory);
|
||||||
lua["io"]["removedirectory"] = utils::io::remove_directory;
|
lua["io"]["readfile"] = safe_io_func<std::string>(
|
||||||
lua["io"]["readfile"] = static_cast<std::string(*)(const std::string&)>(utils::io::read_file);
|
static_cast<std::string(*)(const std::string&)>(utils::io::read_file));
|
||||||
|
|
||||||
using game = table;
|
using game = table;
|
||||||
auto game_type = game();
|
auto game_type = game();
|
||||||
@ -320,6 +405,85 @@ namespace ui_scripting
|
|||||||
|
|
||||||
updater_table["getlasterror"] = updater::get_last_error;
|
updater_table["getlasterror"] = updater::get_last_error;
|
||||||
updater_table["getcurrentfile"] = updater::get_current_file;
|
updater_table["getcurrentfile"] = updater::get_current_file;
|
||||||
|
|
||||||
|
auto mods_table = table();
|
||||||
|
lua["mods"] = mods_table;
|
||||||
|
|
||||||
|
mods_table["getloaded"] = []() -> script_value
|
||||||
|
{
|
||||||
|
const auto& mod = mods::get_mod();
|
||||||
|
if (mod.has_value())
|
||||||
|
{
|
||||||
|
return mod.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
mods_table["getlist"] = mods::get_mod_list;
|
||||||
|
mods_table["getinfo"] = [](const std::string& mod)
|
||||||
|
{
|
||||||
|
table info_table{};
|
||||||
|
const auto info = mods::get_mod_info(mod);
|
||||||
|
const auto has_value = info.has_value();
|
||||||
|
info_table["isvalid"] = has_value;
|
||||||
|
|
||||||
|
if (!has_value)
|
||||||
|
{
|
||||||
|
return info_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& map = info.value();
|
||||||
|
for (const auto& [key, value] : map.items())
|
||||||
|
{
|
||||||
|
info_table[key] = json_to_lua(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return info_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto mods_stats_table = table();
|
||||||
|
mods_table["stats"] = mods_stats_table;
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
mods_stats_table["get"] = [](const std::string& key)
|
||||||
|
{
|
||||||
|
return json_to_lua(mods::get_current_stats());
|
||||||
|
};
|
||||||
|
|
||||||
|
mods_stats_table["mapset"] = [](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();
|
||||||
|
};
|
||||||
|
|
||||||
|
mods_stats_table["mapget"] = [](const std::string& mapname,
|
||||||
|
const std::string& key)
|
||||||
|
{
|
||||||
|
auto& stats = mods::get_current_stats();
|
||||||
|
return json_to_lua(stats["maps"][mapname][key]);
|
||||||
|
};
|
||||||
|
|
||||||
|
mods_stats_table["save"] = mods::write_mod_stats;
|
||||||
|
mods_stats_table["getall"] = []()
|
||||||
|
{
|
||||||
|
return json_to_lua(mods::get_current_stats());
|
||||||
|
};
|
||||||
|
|
||||||
|
mods_stats_table["setfromjson"] = [](const std::string& data)
|
||||||
|
{
|
||||||
|
const auto json = nlohmann::json::parse(data);
|
||||||
|
mods::get_current_stats() = json;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void start()
|
void start()
|
||||||
@ -490,6 +654,11 @@ namespace ui_scripting
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int removed_function_stub(game::hks::lua_State* /*state*/)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
|
@ -79,6 +79,13 @@ namespace ui_scripting
|
|||||||
* Constructors
|
* Constructors
|
||||||
**************************************************************/
|
**************************************************************/
|
||||||
|
|
||||||
|
script_value::script_value()
|
||||||
|
{
|
||||||
|
game::hks::HksObject nil{};
|
||||||
|
nil.t = game::hks::TNIL;
|
||||||
|
this->value_ = nil;
|
||||||
|
}
|
||||||
|
|
||||||
script_value::script_value(const game::hks::HksObject& value)
|
script_value::script_value(const game::hks::HksObject& value)
|
||||||
: value_(value)
|
: value_(value)
|
||||||
{
|
{
|
||||||
|
@ -91,7 +91,7 @@ namespace ui_scripting
|
|||||||
class script_value
|
class script_value
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
script_value() = default;
|
script_value();
|
||||||
script_value(const game::hks::HksObject& value);
|
script_value(const game::hks::HksObject& value);
|
||||||
|
|
||||||
script_value(int value);
|
script_value(int value);
|
||||||
@ -136,6 +136,19 @@ namespace ui_scripting
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
script_value(const std::optional<F> optional)
|
||||||
|
{
|
||||||
|
if (optional.has_value())
|
||||||
|
{
|
||||||
|
script_value::script_value(optional.value());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
script_value::script_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const script_value& other) const;
|
bool operator==(const script_value& other) const;
|
||||||
|
|
||||||
arguments operator()() const;
|
arguments operator()() const;
|
||||||
@ -227,6 +240,11 @@ namespace ui_scripting
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator script_value() const
|
||||||
|
{
|
||||||
|
return this->value_;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
operator T() const
|
operator T() const
|
||||||
{
|
{
|
||||||
|
@ -87,6 +87,11 @@
|
|||||||
#include <rapidjson/prettywriter.h>
|
#include <rapidjson/prettywriter.h>
|
||||||
#include <rapidjson/stringbuffer.h>
|
#include <rapidjson/stringbuffer.h>
|
||||||
|
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4459)
|
||||||
|
#include <json.hpp>
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
#include <asmjit/core/jitruntime.h>
|
#include <asmjit/core/jitruntime.h>
|
||||||
#include <asmjit/x86/x86assembler.h>
|
#include <asmjit/x86/x86assembler.h>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user