Add UI Scripting support
This commit is contained in:
parent
59586e18e6
commit
27d081700a
370
src/client/component/ui_scripting.cpp
Normal file
370
src/client/component/ui_scripting.cpp
Normal file
@ -0,0 +1,370 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "game/ui_scripting/execution.hpp"
|
||||
|
||||
#include "ui_scripting.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/finally.hpp>
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<game::hks::cclosure*, std::function<arguments(const function_arguments& args)>> converted_functions;
|
||||
|
||||
utils::hook::detour ui_cod_init_hook;
|
||||
utils::hook::detour ui_shutdown_hook;
|
||||
utils::hook::detour hks_package_require_hook;
|
||||
utils::hook::detour lua_cod_getrawfile_hook;
|
||||
|
||||
struct globals_t
|
||||
{
|
||||
std::string in_require_script;
|
||||
std::unordered_map<std::string, std::string> loaded_scripts;
|
||||
std::unordered_map<std::string, std::string> local_scripts;
|
||||
bool load_raw_script{};
|
||||
std::string raw_script_name{};
|
||||
};
|
||||
|
||||
globals_t globals;
|
||||
|
||||
bool is_loaded_script(const std::string& name)
|
||||
{
|
||||
return globals.loaded_scripts.contains(name);
|
||||
}
|
||||
|
||||
bool is_local_script(const std::string& name)
|
||||
{
|
||||
return globals.local_scripts.contains(name);
|
||||
}
|
||||
|
||||
std::string get_root_script(const std::string& name)
|
||||
{
|
||||
const auto itr = globals.loaded_scripts.find(name);
|
||||
return (itr == globals.loaded_scripts.end()) ? std::string() : itr->second;
|
||||
}
|
||||
|
||||
table get_globals()
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
return state->globals.v.table;
|
||||
}
|
||||
|
||||
void print_error(const std::string& error)
|
||||
{
|
||||
printf("************** LUI script execution error **************\n");
|
||||
printf("%s\n", error.data());
|
||||
printf("********************************************************\n");
|
||||
}
|
||||
|
||||
void print_loading_script(const std::string& name)
|
||||
{
|
||||
printf("Loading LUI script '%s'\n", name.data());
|
||||
}
|
||||
|
||||
std::string get_current_script(game::hks::lua_State* state)
|
||||
{
|
||||
game::hks::lua_Debug info{};
|
||||
game::hks::hksi_lua_getstack(state, 1, &info);
|
||||
game::hks::hksi_lua_getinfo(state, "nSl", &info);
|
||||
return info.short_src;
|
||||
}
|
||||
|
||||
int load_buffer(const std::string& name, const std::string& data)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto sharing_mode = state->m_global->m_bytecodeSharingMode;
|
||||
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_ON;
|
||||
|
||||
const auto _0 = utils::finally([&]
|
||||
{
|
||||
state->m_global->m_bytecodeSharingMode = sharing_mode;
|
||||
});
|
||||
|
||||
game::hks::HksCompilerSettings compiler_settings{};
|
||||
return game::hks::hksi_hksL_loadbuffer(state, &compiler_settings, data.data(), data.size(), name.data());
|
||||
}
|
||||
|
||||
void load_script(const std::string& name, const std::string& data)
|
||||
{
|
||||
globals.loaded_scripts[name] = name;
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto lua = get_globals();
|
||||
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_ON;
|
||||
const auto load_results = lua["loadstring"](data, name);
|
||||
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_SECURE;
|
||||
|
||||
if (load_results[0].is<function>())
|
||||
{
|
||||
const auto results = lua["pcall"](load_results);
|
||||
if (!results[0].as<bool>())
|
||||
{
|
||||
print_error(results[1].as<std::string>());
|
||||
}
|
||||
}
|
||||
else if (load_results[1].is<std::string>())
|
||||
{
|
||||
print_error(load_results[1].as<std::string>());
|
||||
}
|
||||
}
|
||||
|
||||
void load_local_script_files(const std::string& script_dir)
|
||||
{
|
||||
if (!utils::io::directory_exists(script_dir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto scripts = utils::io::list_files(script_dir);
|
||||
|
||||
for (const auto& script : scripts)
|
||||
{
|
||||
if (std::filesystem::is_regular_file(script))
|
||||
{
|
||||
const std::string file_path = script.substr(script.find("ui_scripts") + 11);
|
||||
globals.local_scripts[file_path.c_str()] = script;
|
||||
}
|
||||
else if (std::filesystem::is_directory(script))
|
||||
{
|
||||
load_local_script_files(script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load_scripts(const std::string& script_dir)
|
||||
{
|
||||
if (!utils::io::directory_exists(script_dir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
load_local_script_files(script_dir);
|
||||
|
||||
const auto scripts = utils::io::list_files(script_dir);
|
||||
|
||||
for (const auto& script : scripts)
|
||||
{
|
||||
std::string data;
|
||||
|
||||
if (std::filesystem::is_directory(script) && utils::io::read_file(script + "/__init__.lua", &data))
|
||||
{
|
||||
print_loading_script(script);
|
||||
load_script(script + "/__init__.lua", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup_functions()
|
||||
{
|
||||
const auto lua = get_globals();
|
||||
|
||||
using game = table;
|
||||
auto game_type = game();
|
||||
lua["game"] = game_type;
|
||||
}
|
||||
|
||||
void enable_globals()
|
||||
{
|
||||
const auto lua = get_globals();
|
||||
const std::string code =
|
||||
"local g = getmetatable(_G)\n"
|
||||
"if not g then\n"
|
||||
"g = {}\n"
|
||||
"setmetatable(_G, g)\n"
|
||||
"end\n"
|
||||
"g.__newindex = nil\n";
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_ON;
|
||||
lua["loadstring"](code)[0]();
|
||||
state->m_global->m_bytecodeSharingMode = game::hks::HKS_BYTECODE_SHARING_SECURE;
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
globals = {};
|
||||
|
||||
const auto lua = get_globals();
|
||||
enable_globals();
|
||||
|
||||
setup_functions();
|
||||
|
||||
lua["print"] = function(reinterpret_cast<game::hks::lua_function>(0x141D30290_g)); // hks::base_print
|
||||
lua["table"]["unpack"] = lua["unpack"];
|
||||
lua["luiglobals"] = lua;
|
||||
|
||||
load_scripts(game::get_host_library().get_folder().append("/data/ui_scripts/").string());
|
||||
load_scripts("boiii/ui_scripts/");
|
||||
load_scripts("data/ui_scripts/");
|
||||
}
|
||||
|
||||
void try_start()
|
||||
{
|
||||
try
|
||||
{
|
||||
start();
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
printf("Failed to load LUI scripts: %s\n", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void ui_cod_init_stub(void* a1, void* a2)
|
||||
{
|
||||
ui_cod_init_hook.invoke(a1, a2);
|
||||
const auto _0 = utils::finally(&try_start);
|
||||
}
|
||||
|
||||
void ui_shutdown_stub()
|
||||
{
|
||||
converted_functions.clear();
|
||||
globals = {};
|
||||
return ui_shutdown_hook.invoke<void>();
|
||||
}
|
||||
|
||||
void* hks_package_require_stub(game::hks::lua_State* state)
|
||||
{
|
||||
const auto script = get_current_script(state);
|
||||
const auto root = get_root_script(script);
|
||||
globals.in_require_script = root;
|
||||
return hks_package_require_hook.invoke<void*>(state);
|
||||
}
|
||||
|
||||
int hks_load_stub(game::hks::lua_State* state, void* compiler_options, void* reader, void* reader_data, void* debug_reader, void* debug_reader_data, const char* chunk_name)
|
||||
{
|
||||
if (globals.load_raw_script)
|
||||
{
|
||||
globals.load_raw_script = false;
|
||||
globals.loaded_scripts[globals.raw_script_name] = globals.in_require_script;
|
||||
return load_buffer(globals.raw_script_name, utils::io::read_file(globals.raw_script_name));
|
||||
}
|
||||
|
||||
return utils::hook::invoke<int>(0x141D3AFB0_g, state, compiler_options, reader, reader_data, debug_reader, debug_reader_data, chunk_name);
|
||||
}
|
||||
|
||||
game::XAssetHeader lua_cod_getrawfile_stub(char* filename)
|
||||
{
|
||||
game::XAssetHeader header{ .luaFile = nullptr };
|
||||
|
||||
if (!is_local_script(filename))
|
||||
{
|
||||
return lua_cod_getrawfile_hook.invoke<game::XAssetHeader>(filename);
|
||||
}
|
||||
|
||||
std::string target_script = globals.local_scripts[filename];
|
||||
|
||||
if (utils::io::file_exists(target_script))
|
||||
{
|
||||
globals.load_raw_script = true;
|
||||
globals.raw_script_name = target_script;
|
||||
header.luaFile = reinterpret_cast<game::LuaFile*>(1);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
return lua_cod_getrawfile_hook.invoke<game::XAssetHeader>(filename);
|
||||
}
|
||||
|
||||
int luaopen_stub([[maybe_unused]] game::hks::lua_State* l)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hks_base_stub([[maybe_unused]] game::hks::lua_State* l)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
int main_handler(game::hks::lua_State* state)
|
||||
{
|
||||
const auto value = state->m_apistack.base[-1];
|
||||
if (value.t != game::hks::TCFUNCTION)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto closure = value.v.cClosure;
|
||||
if (!converted_functions.contains(closure))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& function = converted_functions[closure];
|
||||
|
||||
try
|
||||
{
|
||||
const auto args = get_return_values();
|
||||
const auto results = function(args);
|
||||
|
||||
for (const auto& result : results)
|
||||
{
|
||||
push_value(result);
|
||||
}
|
||||
|
||||
return static_cast<int>(results.size());
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
game::hks::hksi_luaL_error(state, ex.what());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
game::hks::cclosure* convert_function(F f)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto closure = game::hks::cclosure_Create(state, main_handler, 0, 0, 0);
|
||||
converted_functions[closure] = wrap_function(f);
|
||||
return closure;
|
||||
}
|
||||
|
||||
class component final : public client_component
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
// Do not allow the HKS vm to open LUA's libraries
|
||||
utils::hook::jump(0x141D33510_g, luaopen_stub); // io
|
||||
utils::hook::jump(0x141D33D20_g, luaopen_stub); // os
|
||||
utils::hook::jump(0x141D34B40_g, luaopen_stub); // serialize
|
||||
utils::hook::jump(0x141D34B10_g, luaopen_stub); // havokscript
|
||||
utils::hook::jump(0x141D34190_g, luaopen_stub); // debug
|
||||
|
||||
// Disable unsafe functions
|
||||
utils::hook::jump(0x141D300B0_g, hks_base_stub); // base_loadfile
|
||||
utils::hook::jump(0x141D31EE0_g, hks_base_stub); // base_load
|
||||
|
||||
utils::hook::jump(0x141D2CF00_g, hks_base_stub); // string_dump
|
||||
utils::hook::jump(0x141D2AF90_g, hks_base_stub); // os_execute
|
||||
|
||||
utils::hook::call(0x141D4979A_g, hks_load_stub);
|
||||
|
||||
hks_package_require_hook.create(0x141D28EF0_g, hks_package_require_stub);
|
||||
ui_cod_init_hook.create(0x141F298B0_g, ui_cod_init_stub);
|
||||
ui_shutdown_hook.create(0x14270E9C0_g, ui_shutdown_stub);
|
||||
lua_cod_getrawfile_hook.create(0x141F0F880_g, lua_cod_getrawfile_stub);
|
||||
|
||||
scheduler::once([]() {
|
||||
game::dvar_t* dvar_callstack_ship = game::Dvar_FindVar("ui_error_callstack_ship");
|
||||
dvar_callstack_ship->flags = (game::dvarFlags_e)0;
|
||||
game::dvar_t* dvar_report_delay= game::Dvar_FindVar("ui_error_report_delay");
|
||||
dvar_report_delay->flags = (game::dvarFlags_e)0;
|
||||
|
||||
game::Dvar_SetFromStringByName("ui_error_callstack_ship", "1", true);
|
||||
game::Dvar_SetFromStringByName("ui_error_report_delay", "0", true);
|
||||
}, scheduler::pipeline::main);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(ui_scripting::component)
|
7
src/client/component/ui_scripting.hpp
Normal file
7
src/client/component/ui_scripting.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
template <typename F>
|
||||
game::hks::cclosure* convert_function(F f);
|
||||
}
|
@ -1,27 +1,23 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "game.hpp"
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const utils::nt::library& get_host_library()
|
||||
{
|
||||
const utils::nt::library& get_host_library()
|
||||
static auto host_library = []
|
||||
{
|
||||
static auto host_library = []
|
||||
utils::nt::library host{};
|
||||
if (!host || host == utils::nt::library::get_by_address(get_base))
|
||||
{
|
||||
utils::nt::library host{};
|
||||
if (!host || host == utils::nt::library::get_by_address(get_base))
|
||||
{
|
||||
throw std::runtime_error("Invalid host application");
|
||||
}
|
||||
throw std::runtime_error("Invalid host application");
|
||||
}
|
||||
|
||||
return host;
|
||||
}();
|
||||
return host;
|
||||
}();
|
||||
|
||||
return host_library;
|
||||
}
|
||||
return host_library;
|
||||
}
|
||||
|
||||
size_t get_base()
|
||||
|
@ -1,9 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "structs.hpp"
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
namespace game
|
||||
{
|
||||
{
|
||||
const utils::nt::library& get_host_library();
|
||||
size_t get_base();
|
||||
bool is_server();
|
||||
|
||||
|
@ -412,6 +412,132 @@ namespace game
|
||||
ERROR_LUA = 0x200,
|
||||
ERROR_SOFTRESTART = 0x400,
|
||||
ERROR_SOFTRESTART_KEEPDW = 0x800,
|
||||
};
|
||||
|
||||
enum XAssetType
|
||||
{
|
||||
ASSET_TYPE_PHYSPRESET = 0x0,
|
||||
ASSET_TYPE_PHYSCONSTRAINTS = 0x1,
|
||||
ASSET_TYPE_DESTRUCTIBLEDEF = 0x2,
|
||||
ASSET_TYPE_XANIMPARTS = 0x3,
|
||||
ASSET_TYPE_XMODEL = 0x4,
|
||||
ASSET_TYPE_XMODELMESH = 0x5,
|
||||
ASSET_TYPE_MATERIAL = 0x6,
|
||||
ASSET_TYPE_COMPUTE_SHADER_SET = 0x7,
|
||||
ASSET_TYPE_TECHNIQUE_SET = 0x8,
|
||||
ASSET_TYPE_IMAGE = 0x9,
|
||||
ASSET_TYPE_SOUND = 0xA,
|
||||
ASSET_TYPE_SOUND_PATCH = 0xB,
|
||||
ASSET_TYPE_CLIPMAP = 0xC,
|
||||
ASSET_TYPE_COMWORLD = 0xD,
|
||||
ASSET_TYPE_GAMEWORLD = 0xE,
|
||||
ASSET_TYPE_MAP_ENTS = 0xF,
|
||||
ASSET_TYPE_GFXWORLD = 0x10,
|
||||
ASSET_TYPE_LIGHT_DEF = 0x11,
|
||||
ASSET_TYPE_LENSFLARE_DEF = 0x12,
|
||||
ASSET_TYPE_UI_MAP = 0x13,
|
||||
ASSET_TYPE_FONT = 0x14,
|
||||
ASSET_TYPE_FONTICON = 0x15,
|
||||
ASSET_TYPE_LOCALIZE_ENTRY = 0x16,
|
||||
ASSET_TYPE_WEAPON = 0x17,
|
||||
ASSET_TYPE_WEAPONDEF = 0x18,
|
||||
ASSET_TYPE_WEAPON_VARIANT = 0x19,
|
||||
ASSET_TYPE_WEAPON_FULL = 0x1A,
|
||||
ASSET_TYPE_CGMEDIA = 0x1B,
|
||||
ASSET_TYPE_PLAYERSOUNDS = 0x1C,
|
||||
ASSET_TYPE_PLAYERFX = 0x1D,
|
||||
ASSET_TYPE_SHAREDWEAPONSOUNDS = 0x1E,
|
||||
ASSET_TYPE_ATTACHMENT = 0x1F,
|
||||
ASSET_TYPE_ATTACHMENT_UNIQUE = 0x20,
|
||||
ASSET_TYPE_WEAPON_CAMO = 0x21,
|
||||
ASSET_TYPE_CUSTOMIZATION_TABLE = 0x22,
|
||||
ASSET_TYPE_CUSTOMIZATION_TABLE_FE_IMAGES = 0x23,
|
||||
ASSET_TYPE_CUSTOMIZATION_TABLE_COLOR = 0x24,
|
||||
ASSET_TYPE_SNDDRIVER_GLOBALS = 0x25,
|
||||
ASSET_TYPE_FX = 0x26,
|
||||
ASSET_TYPE_TAGFX = 0x27,
|
||||
ASSET_TYPE_NEW_LENSFLARE_DEF = 0x28,
|
||||
ASSET_TYPE_IMPACT_FX = 0x29,
|
||||
ASSET_TYPE_IMPACT_SOUND = 0x2A,
|
||||
ASSET_TYPE_PLAYER_CHARACTER = 0x2B,
|
||||
ASSET_TYPE_AITYPE = 0x2C,
|
||||
ASSET_TYPE_CHARACTER = 0x2D,
|
||||
ASSET_TYPE_XMODELALIAS = 0x2E,
|
||||
ASSET_TYPE_RAWFILE = 0x2F,
|
||||
ASSET_TYPE_STRINGTABLE = 0x30,
|
||||
ASSET_TYPE_STRUCTURED_TABLE = 0x31,
|
||||
ASSET_TYPE_LEADERBOARD = 0x32,
|
||||
ASSET_TYPE_DDL = 0x33,
|
||||
ASSET_TYPE_GLASSES = 0x34,
|
||||
ASSET_TYPE_TEXTURELIST = 0x35,
|
||||
ASSET_TYPE_SCRIPTPARSETREE = 0x36,
|
||||
ASSET_TYPE_KEYVALUEPAIRS = 0x37,
|
||||
ASSET_TYPE_VEHICLEDEF = 0x38,
|
||||
ASSET_TYPE_ADDON_MAP_ENTS = 0x39,
|
||||
ASSET_TYPE_TRACER = 0x3A,
|
||||
ASSET_TYPE_SLUG = 0x3B,
|
||||
ASSET_TYPE_SURFACEFX_TABLE = 0x3C,
|
||||
ASSET_TYPE_SURFACESOUNDDEF = 0x3D,
|
||||
ASSET_TYPE_FOOTSTEP_TABLE = 0x3E,
|
||||
ASSET_TYPE_ENTITYFXIMPACTS = 0x3F,
|
||||
ASSET_TYPE_ENTITYSOUNDIMPACTS = 0x40,
|
||||
ASSET_TYPE_ZBARRIER = 0x41,
|
||||
ASSET_TYPE_VEHICLEFXDEF = 0x42,
|
||||
ASSET_TYPE_VEHICLESOUNDDEF = 0x43,
|
||||
ASSET_TYPE_TYPEINFO = 0x44,
|
||||
ASSET_TYPE_SCRIPTBUNDLE = 0x45,
|
||||
ASSET_TYPE_SCRIPTBUNDLELIST = 0x46,
|
||||
ASSET_TYPE_RUMBLE = 0x47,
|
||||
ASSET_TYPE_BULLETPENETRATION = 0x48,
|
||||
ASSET_TYPE_LOCDMGTABLE = 0x49,
|
||||
ASSET_TYPE_AIMTABLE = 0x4A,
|
||||
ASSET_TYPE_ANIMSELECTORTABLESET = 0x4B,
|
||||
ASSET_TYPE_ANIMMAPPINGTABLE = 0x4C,
|
||||
ASSET_TYPE_ANIMSTATEMACHINE = 0x4D,
|
||||
ASSET_TYPE_BEHAVIORTREE = 0x4E,
|
||||
ASSET_TYPE_BEHAVIORSTATEMACHINE = 0x4F,
|
||||
ASSET_TYPE_TTF = 0x50,
|
||||
ASSET_TYPE_SANIM = 0x51,
|
||||
ASSET_TYPE_LIGHT_DESCRIPTION = 0x52,
|
||||
ASSET_TYPE_SHELLSHOCK = 0x53,
|
||||
ASSET_TYPE_XCAM = 0x54,
|
||||
ASSET_TYPE_BG_CACHE = 0x55,
|
||||
ASSET_TYPE_TEXTURE_COMBO = 0x56,
|
||||
ASSET_TYPE_FLAMETABLE = 0x57,
|
||||
ASSET_TYPE_BITFIELD = 0x58,
|
||||
ASSET_TYPE_ATTACHMENT_COSMETIC_VARIANT = 0x59,
|
||||
ASSET_TYPE_MAPTABLE = 0x5A,
|
||||
ASSET_TYPE_MAPTABLE_LOADING_IMAGES = 0x5B,
|
||||
ASSET_TYPE_MEDAL = 0x5C,
|
||||
ASSET_TYPE_MEDALTABLE = 0x5D,
|
||||
ASSET_TYPE_OBJECTIVE = 0x5E,
|
||||
ASSET_TYPE_OBJECTIVE_LIST = 0x5F,
|
||||
ASSET_TYPE_UMBRA_TOME = 0x60,
|
||||
ASSET_TYPE_NAVMESH = 0x61,
|
||||
ASSET_TYPE_NAVVOLUME = 0x62,
|
||||
ASSET_TYPE_BINARYHTML = 0x63,
|
||||
ASSET_TYPE_LASER = 0x64,
|
||||
ASSET_TYPE_BEAM = 0x65,
|
||||
ASSET_TYPE_STREAMER_HINT = 0x66,
|
||||
ASSET_TYPE_COUNT = 0x67,
|
||||
ASSET_TYPE_STRING = 0x68,
|
||||
ASSET_TYPE_ASSETLIST = 0x69,
|
||||
ASSET_TYPE_REPORT = 0x6A,
|
||||
ASSET_TYPE_DEPEND = 0x68,
|
||||
ASSET_TYPE_FULL_COUNT = 0x6C,
|
||||
};
|
||||
|
||||
struct LuaFile
|
||||
{
|
||||
const char* name;
|
||||
int len;
|
||||
const char* buffer;
|
||||
};
|
||||
|
||||
union XAssetHeader
|
||||
{
|
||||
void* data;
|
||||
LuaFile* luaFile;
|
||||
};
|
||||
|
||||
struct XZoneBuffer
|
||||
@ -493,6 +619,23 @@ namespace game
|
||||
DVAR_TYPE_COLOR_LAB = 0xE,
|
||||
DVAR_TYPE_SESSIONMODE_BASE_DVAR = 0xF,
|
||||
DVAR_TYPE_COUNT = 0x10,
|
||||
};
|
||||
|
||||
enum dvarFlags_e
|
||||
{
|
||||
DVAR_ARCHIVE = 1 << 0,
|
||||
DVAR_USERINFO = 1 << 1,
|
||||
DVAR_SYSTEMINFO = 1 << 2,
|
||||
DVAR_CODINFO = 1 << 3,
|
||||
DVAR_LATCH = 1 << 4,
|
||||
DVAR_ROM = 1 << 5,
|
||||
DVAR_SAVED = 1 << 6,
|
||||
DVAR_INIT = 1 << 7,
|
||||
DVAR_CHEAT = 1 << 8,
|
||||
//DVAR_UNKNOWN = 1 << 9,
|
||||
DVAR_EXTERNAL = 1 << 10,
|
||||
//DVAR_UNKNOWN3x = 1 << 11-13,
|
||||
DVAR_SESSIONMODE = 1 << 15
|
||||
};
|
||||
|
||||
typedef float vec_t;
|
||||
@ -868,7 +1011,513 @@ namespace game
|
||||
Agreement debugAgreement;
|
||||
JoinType joinType;
|
||||
JoinResult joinResult;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
namespace hks
|
||||
{
|
||||
struct lua_State;
|
||||
struct HashTable;
|
||||
struct StringTable;
|
||||
struct cclosure;
|
||||
typedef int hksBool;
|
||||
typedef char hksChar;
|
||||
typedef unsigned __int8 hksByte;
|
||||
typedef __int16 hksShort16;
|
||||
typedef unsigned __int16 hksUshort16;
|
||||
typedef float HksNumber;
|
||||
typedef int hksInt32;
|
||||
typedef unsigned int hksUint32;
|
||||
typedef __int64 hksInt64;
|
||||
typedef unsigned __int64 hksUint64;
|
||||
|
||||
typedef int HksGcCost;
|
||||
|
||||
|
||||
typedef size_t hksSize;
|
||||
typedef void* (*lua_Alloc)(void*, void*, size_t, size_t);
|
||||
typedef hksInt32(*lua_CFunction)(lua_State*);
|
||||
|
||||
struct GenericChunkHeader
|
||||
{
|
||||
hksSize m_flags;
|
||||
};
|
||||
|
||||
struct ChunkHeader : GenericChunkHeader
|
||||
{
|
||||
ChunkHeader* m_next;
|
||||
};
|
||||
|
||||
struct ChunkList
|
||||
{
|
||||
ChunkHeader m_head;
|
||||
};
|
||||
|
||||
struct UserData : ChunkHeader
|
||||
{
|
||||
unsigned __int64 m_envAndSizeOffsetHighBits;
|
||||
unsigned __int64 m_metaAndSizeOffsetLowBits;
|
||||
char m_data[8];
|
||||
};
|
||||
|
||||
struct InternString
|
||||
{
|
||||
unsigned __int64 m_flags;
|
||||
unsigned __int64 m_lengthbits;
|
||||
unsigned int m_hash;
|
||||
char m_data[30];
|
||||
};
|
||||
|
||||
union HksValue
|
||||
{
|
||||
cclosure* cClosure;
|
||||
void* closure;
|
||||
UserData* userData;
|
||||
HashTable* table;
|
||||
void* tstruct;
|
||||
InternString* str;
|
||||
void* thread;
|
||||
void* ptr;
|
||||
float number;
|
||||
unsigned int native;
|
||||
bool boolean;
|
||||
};
|
||||
|
||||
enum HksObjectType
|
||||
{
|
||||
TANY = 0xFFFFFFFE,
|
||||
TNONE = 0xFFFFFFFF,
|
||||
TNIL = 0x0,
|
||||
TBOOLEAN = 0x1,
|
||||
TLIGHTUSERDATA = 0x2,
|
||||
TNUMBER = 0x3,
|
||||
TSTRING = 0x4,
|
||||
TTABLE = 0x5,
|
||||
TFUNCTION = 0x6, // idk
|
||||
TUSERDATA = 0x7,
|
||||
TTHREAD = 0x8,
|
||||
TIFUNCTION = 0x9, // Lua function
|
||||
TCFUNCTION = 0xA, // C function
|
||||
TUI64 = 0xB,
|
||||
TSTRUCT = 0xC,
|
||||
NUM_TYPE_OBJECTS = 0xE,
|
||||
};
|
||||
|
||||
struct HksObject
|
||||
{
|
||||
HksObjectType t;
|
||||
HksValue v;
|
||||
};
|
||||
|
||||
const struct hksInstruction
|
||||
{
|
||||
unsigned int code;
|
||||
};
|
||||
|
||||
struct ActivationRecord
|
||||
{
|
||||
HksObject* m_base;
|
||||
const hksInstruction* m_returnAddress;
|
||||
__int16 m_tailCallDepth;
|
||||
__int16 m_numVarargs;
|
||||
int m_numExpectedReturns;
|
||||
};
|
||||
|
||||
struct CallStack
|
||||
{
|
||||
ActivationRecord* m_records;
|
||||
ActivationRecord* m_lastrecord;
|
||||
ActivationRecord* m_current;
|
||||
const hksInstruction* m_current_lua_pc;
|
||||
const hksInstruction* m_hook_return_addr;
|
||||
int m_hook_level;
|
||||
};
|
||||
|
||||
struct ApiStack
|
||||
{
|
||||
HksObject* top;
|
||||
HksObject* base;
|
||||
HksObject* alloc_top;
|
||||
HksObject* bottom;
|
||||
};
|
||||
|
||||
struct UpValue : ChunkHeader
|
||||
{
|
||||
HksObject m_storage;
|
||||
HksObject* loc;
|
||||
UpValue* m_next;
|
||||
};
|
||||
|
||||
struct CallSite
|
||||
{
|
||||
_SETJMP_FLOAT128 m_jumpBuffer[16];
|
||||
CallSite* m_prev;
|
||||
};
|
||||
|
||||
enum Status
|
||||
{
|
||||
NEW = 0x1,
|
||||
RUNNING = 0x2,
|
||||
YIELDED = 0x3,
|
||||
DEAD_ERROR = 0x4,
|
||||
};
|
||||
|
||||
enum HksError
|
||||
{
|
||||
HKS_NO_ERROR = 0,
|
||||
HKS_ERRSYNTAX = -4,
|
||||
HKS_ERRFILE = -5,
|
||||
HKS_ERRRUN = -100,
|
||||
HKS_ERRMEM = -200,
|
||||
HKS_ERRERR = -300,
|
||||
HKS_THROWING_ERROR = -500,
|
||||
HKS_GC_YIELD = 1,
|
||||
};
|
||||
|
||||
struct lua_Debug
|
||||
{
|
||||
int event;
|
||||
const char* name;
|
||||
const char* namewhat;
|
||||
const char* what;
|
||||
const char* source;
|
||||
int currentline;
|
||||
int nups;
|
||||
int nparams;
|
||||
int ishksfunc;
|
||||
int linedefined;
|
||||
int lastlinedefined;
|
||||
char short_src[512];
|
||||
int callstack_level;
|
||||
int is_tail_call;
|
||||
};
|
||||
|
||||
using lua_function = int(__fastcall*)(lua_State*);
|
||||
|
||||
struct luaL_Reg
|
||||
{
|
||||
const char* name;
|
||||
lua_function function;
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
HksObject m_key;
|
||||
HksObject m_value;
|
||||
};
|
||||
|
||||
struct StringPinner
|
||||
{
|
||||
struct Node
|
||||
{
|
||||
InternString* m_strings[32];
|
||||
Node* m_prev;
|
||||
};
|
||||
|
||||
lua_State* const m_state;
|
||||
StringPinner* const m_prev;
|
||||
InternString** m_nextStringsPlace;
|
||||
Node m_firstNode;
|
||||
Node* m_currentNode;
|
||||
};
|
||||
|
||||
struct StringTable
|
||||
{
|
||||
InternString** m_data;
|
||||
unsigned int m_count;
|
||||
unsigned int m_mask;
|
||||
StringPinner* m_pinnedStrings;
|
||||
};
|
||||
|
||||
struct Metatable
|
||||
{
|
||||
};
|
||||
|
||||
struct HashTable : ChunkHeader
|
||||
{
|
||||
Metatable* m_meta;
|
||||
unsigned int m_version;
|
||||
unsigned int m_mask;
|
||||
Node* m_hashPart;
|
||||
HksObject* m_arrayPart;
|
||||
unsigned int m_arraySize;
|
||||
Node* m_freeNode;
|
||||
};
|
||||
|
||||
struct cclosure : ChunkHeader
|
||||
{
|
||||
lua_function m_function;
|
||||
HashTable* m_env;
|
||||
__int16 m_numUpvalues;
|
||||
__int16 m_flags;
|
||||
InternString* m_name;
|
||||
HksObject m_upvalues[1];
|
||||
};
|
||||
|
||||
enum HksCompilerSettings_BytecodeSharingFormat
|
||||
{
|
||||
BYTECODE_DEFAULT = 0x0,
|
||||
BYTECODE_INPLACE = 0x1,
|
||||
BYTECODE_REFERENCED = 0x2,
|
||||
};
|
||||
|
||||
enum HksCompilerSettings_IntLiteralOptions
|
||||
{
|
||||
INT_LITERALS_NONE = 0x0,
|
||||
INT_LITERALS_LUD = 0x1,
|
||||
INT_LITERALS_32BIT = 0x1,
|
||||
INT_LITERALS_UI64 = 0x2,
|
||||
INT_LITERALS_64BIT = 0x2,
|
||||
INT_LITERALS_ALL = 0x3,
|
||||
};
|
||||
|
||||
struct HksCompilerSettings
|
||||
{
|
||||
int m_emitStructCode;
|
||||
const char** m_stripNames;
|
||||
int m_emitGlobalMemoization;
|
||||
int _m_isHksGlobalMemoTestingMode;
|
||||
HksCompilerSettings_BytecodeSharingFormat m_bytecodeSharingFormat;
|
||||
HksCompilerSettings_IntLiteralOptions m_enableIntLiterals;
|
||||
int(*m_debugMap)(const char*, int);
|
||||
};
|
||||
|
||||
enum HksBytecodeSharingMode : __int64
|
||||
{
|
||||
HKS_BYTECODE_SHARING_OFF = 0,
|
||||
HKS_BYTECODE_SHARING_ON = 1,
|
||||
HKS_BYTECODE_SHARING_SECURE = 2
|
||||
};
|
||||
|
||||
struct HksGcWeights
|
||||
{
|
||||
int m_removeString;
|
||||
int m_finalizeUserdataNoMM;
|
||||
int m_finalizeUserdataGcMM;
|
||||
int m_cleanCoroutine;
|
||||
int m_removeWeak;
|
||||
int m_markObject;
|
||||
int m_traverseString;
|
||||
int m_traverseUserdata;
|
||||
int m_traverseCoroutine;
|
||||
int m_traverseWeakTable;
|
||||
int m_freeChunk;
|
||||
int m_sweepTraverse;
|
||||
};
|
||||
|
||||
struct GarbageCollector_Stack
|
||||
{
|
||||
void* m_storage;
|
||||
unsigned int m_numEntries;
|
||||
unsigned int m_numAllocated;
|
||||
};
|
||||
|
||||
struct ProtoList
|
||||
{
|
||||
void** m_protoList;
|
||||
unsigned __int16 m_protoSize;
|
||||
unsigned __int16 m_protoAllocSize;
|
||||
};
|
||||
|
||||
struct MemoryManager;
|
||||
|
||||
struct GarbageCollector
|
||||
{
|
||||
struct ResumeStack
|
||||
{
|
||||
void* m_storage;
|
||||
hksInt32 m_numEntries;
|
||||
hksUint32 m_numAllocated;
|
||||
};
|
||||
|
||||
struct GreyStack
|
||||
{
|
||||
HksObject* m_storage;
|
||||
hksSize m_numEntries;
|
||||
hksSize m_numAllocated;
|
||||
};
|
||||
|
||||
struct RemarkStack
|
||||
{
|
||||
HashTable** m_storage;
|
||||
hksSize m_numAllocated;
|
||||
hksSize m_numEntries;
|
||||
};
|
||||
|
||||
struct WeakStack_Entry
|
||||
{
|
||||
hksInt32 m_weakness;
|
||||
HashTable* m_table;
|
||||
};
|
||||
|
||||
struct WeakStack
|
||||
{
|
||||
WeakStack_Entry* m_storage;
|
||||
hksInt32 m_numEntries;
|
||||
hksUint32 m_numAllocated;
|
||||
};
|
||||
|
||||
HksGcCost m_target;
|
||||
HksGcCost m_stepsLeft;
|
||||
HksGcCost m_stepLimit;
|
||||
HksGcWeights m_costs;
|
||||
HksGcCost m_unit;
|
||||
void* m_jumpPoint;
|
||||
lua_State* m_mainState;
|
||||
lua_State* m_finalizerState;
|
||||
MemoryManager* m_memory;
|
||||
void* m_emergencyGCMemory;
|
||||
hksInt32 m_phase;
|
||||
ResumeStack m_resumeStack;
|
||||
GreyStack m_greyStack;
|
||||
RemarkStack m_remarkStack;
|
||||
WeakStack m_weakStack;
|
||||
hksBool m_finalizing;
|
||||
HksObject m_safeTableValue;
|
||||
lua_State* m_startOfStateStackList;
|
||||
lua_State* m_endOfStateStackList;
|
||||
lua_State* m_currentState;
|
||||
HksObject m_safeValue;
|
||||
void* m_compiler;
|
||||
void* m_bytecodeReader;
|
||||
void* m_bytecodeWriter;
|
||||
hksInt32 m_pauseMultiplier;
|
||||
HksGcCost m_stepMultiplier;
|
||||
hksSize m_emergencyMemorySize;
|
||||
bool m_stopped;
|
||||
lua_CFunction m_gcPolicy;
|
||||
hksSize m_pauseTriggerMemoryUsage;
|
||||
hksInt32 m_stepTriggerCountdown;
|
||||
hksUint32 m_stringTableIndex;
|
||||
hksUint32 m_stringTableSize;
|
||||
UserData* m_lastBlackUD;
|
||||
UserData* m_activeUD;
|
||||
};
|
||||
|
||||
enum MemoryManager_ChunkColor
|
||||
{
|
||||
RED = 0x0,
|
||||
BLACK = 0x1,
|
||||
};
|
||||
|
||||
enum Hks_DeleteCheckingMode
|
||||
{
|
||||
HKS_DELETE_CHECKING_OFF = 0x0,
|
||||
HKS_DELETE_CHECKING_ACCURATE = 0x1,
|
||||
HKS_DELETE_CHECKING_SAFE = 0x2,
|
||||
};
|
||||
|
||||
struct MemoryManager
|
||||
{
|
||||
enum ChunkColor : __int32
|
||||
{
|
||||
WHITE = 0x0,
|
||||
BLACK = 0x1,
|
||||
};
|
||||
|
||||
lua_Alloc m_allocator;
|
||||
void* m_allocatorUd;
|
||||
ChunkColor m_chunkColor;
|
||||
hksSize m_used;
|
||||
hksSize m_highwatermark;
|
||||
ChunkList m_allocationList;
|
||||
ChunkList m_sweepList;
|
||||
ChunkHeader* m_lastKeptChunk;
|
||||
lua_State* m_state;
|
||||
};
|
||||
|
||||
struct StaticStringCache
|
||||
{
|
||||
HksObject m_objects[41];
|
||||
};
|
||||
|
||||
enum HksBytecodeEndianness
|
||||
{
|
||||
HKS_BYTECODE_DEFAULT_ENDIAN = 0x0,
|
||||
HKS_BYTECODE_BIG_ENDIAN = 0x1,
|
||||
HKS_BYTECODE_LITTLE_ENDIAN = 0x2,
|
||||
};
|
||||
|
||||
struct RuntimeProfileData_Stats
|
||||
{
|
||||
unsigned __int64 hksTime;
|
||||
unsigned __int64 callbackTime;
|
||||
unsigned __int64 gcTime;
|
||||
unsigned __int64 cFinalizerTime;
|
||||
unsigned __int64 compilerTime;
|
||||
unsigned int hkssTimeSamples;
|
||||
unsigned int callbackTimeSamples;
|
||||
unsigned int gcTimeSamples;
|
||||
unsigned int compilerTimeSamples;
|
||||
unsigned int num_newuserdata;
|
||||
unsigned int num_tablerehash;
|
||||
unsigned int num_pushstring;
|
||||
unsigned int num_pushcfunction;
|
||||
unsigned int num_newtables;
|
||||
};
|
||||
|
||||
struct RuntimeProfileData
|
||||
{
|
||||
__int64 stackDepth;
|
||||
__int64 callbackDepth;
|
||||
unsigned __int64 lastTimer;
|
||||
RuntimeProfileData_Stats frameStats;
|
||||
unsigned __int64 gcStartTime;
|
||||
unsigned __int64 finalizerStartTime;
|
||||
unsigned __int64 compilerStartTime;
|
||||
unsigned __int64 compilerStartGCTime;
|
||||
unsigned __int64 compilerStartGCFinalizerTime;
|
||||
unsigned __int64 compilerCallbackStartTime;
|
||||
__int64 compilerDepth;
|
||||
void* outFile;
|
||||
lua_State* rootState;
|
||||
};
|
||||
|
||||
struct HksGlobal
|
||||
{
|
||||
MemoryManager m_memory;
|
||||
GarbageCollector m_collector;
|
||||
StringTable m_stringTable;
|
||||
__int64 padding3;
|
||||
HksBytecodeSharingMode m_bytecodeSharingMode;
|
||||
int padding;
|
||||
HksObject m_registry;
|
||||
ChunkList m_userDataList;
|
||||
lua_State* m_root;
|
||||
StaticStringCache m_staticStringCache;
|
||||
void* m_debugger;
|
||||
void* m_profiler;
|
||||
RuntimeProfileData m_runProfilerData;
|
||||
HksCompilerSettings m_compilerSettings;
|
||||
int(*m_panicFunction)(lua_State*);
|
||||
void* m_luaplusObjectList;
|
||||
int m_heapAssertionFrequency;
|
||||
int m_heapAssertionCount;
|
||||
void (*m_logFunction)(lua_State*, const char*, ...);
|
||||
void (*m_emergencyGCFailFunction)(lua_State*, size_t);
|
||||
HksBytecodeEndianness m_bytecodeDumpEndianness;
|
||||
int padding2;
|
||||
};
|
||||
|
||||
struct lua_State
|
||||
{
|
||||
ChunkHeader baseclass;
|
||||
HksGlobal* m_global;
|
||||
CallStack m_callStack;
|
||||
ApiStack m_apistack;
|
||||
UpValue* pending;
|
||||
HksObject globals;
|
||||
HksObject m_cEnv;
|
||||
CallSite* m_callsites;
|
||||
int m_numberOfCCalls;
|
||||
void* m_context;
|
||||
InternString* m_name;
|
||||
lua_State* m_nextState;
|
||||
lua_State* m_nextStateStack;
|
||||
Status m_status;
|
||||
HksError m_error;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ namespace game
|
||||
// DB
|
||||
WEAK symbol<void(XZoneInfo* zoneInfo, uint32_t zoneCount, bool sync, bool suppressSync)> DB_LoadXAssets{
|
||||
0x1414236A0
|
||||
};
|
||||
};
|
||||
WEAK symbol<XAssetHeader(XAssetType type, const char* name, bool errorIfMissing, int waitTime)> DB_FindXAssetHeader{ 0x141420ED0 };
|
||||
|
||||
// Live
|
||||
WEAK symbol<bool(uint64_t, int*, bool)> Live_GetConnectivityInformation{0x141E0C410};
|
||||
@ -53,11 +54,11 @@ namespace game
|
||||
WEAK symbol<TLSData*()> Sys_GetTLS{0x142184210};
|
||||
|
||||
// Dvar
|
||||
WEAK symbol<const dvar_t*(const char* dvarName)> Dvar_FindVar{0x1422BD730};
|
||||
WEAK symbol<dvar_t*(const char* dvarName)> Dvar_FindVar{0x1422BD730};
|
||||
WEAK symbol<unsigned int(const char* str)> Dvar_GenerateHash{0x14133DBF0};
|
||||
WEAK symbol<dvar_t*(unsigned int hash)> Dvar_FindMalleableVar{0x1422BD6A0};
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetDebugName{0x1422BDCB0};
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetString{0x1422BFFF0};
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetString{0x1422BFFF0};
|
||||
WEAK symbol<void(const char* dvarName, const char* string, bool createIfMissing)> Dvar_SetFromStringByName{
|
||||
0x1422C7F60
|
||||
};
|
||||
@ -96,5 +97,25 @@ namespace game
|
||||
constexpr auto CMD_MAX_NESTING = 8;
|
||||
|
||||
// Re-implementations
|
||||
eModes Com_SessionMode_GetMode();
|
||||
eModes Com_SessionMode_GetMode();
|
||||
|
||||
namespace hks
|
||||
{
|
||||
WEAK symbol<lua_State*> lua_state { 0x159C78D88 };
|
||||
WEAK symbol<void(lua_State* s, const char* str, unsigned int l)> hksi_lua_pushlstring{ 0x140A18430 };
|
||||
|
||||
WEAK symbol<void(lua_State* s, const HksObject* tbl, const HksObject* key, const HksObject* val)> hks_obj_settable{ 0x141D4B660 };
|
||||
WEAK symbol<HksObject* (HksObject* result, lua_State* s, const HksObject* table, const HksObject* key)> hks_obj_gettable{ 0x141D4ABF0 };
|
||||
WEAK symbol<void(lua_State* s, int nargs, int nresults, const unsigned int* pc)> vm_call_internal{ 0x141D71070 };
|
||||
WEAK symbol<HashTable* (lua_State* s, unsigned int arraySize, unsigned int hashSize)> Hashtable_Create{ 0x141D3B5F0 };
|
||||
WEAK symbol<cclosure* (lua_State* s, lua_function function, int num_upvalues, int internal_, int profilerTreatClosureAsFunc)> cclosure_Create{ 0x141D3B7E0 };
|
||||
WEAK symbol<int(lua_State* s, int t)> hksi_luaL_ref{ 0x141D4D1A0 };
|
||||
WEAK symbol<void(lua_State* s, int t, int ref)> hksi_luaL_unref{ 0x141D4D320 };
|
||||
|
||||
WEAK symbol<int(lua_State* s, const HksCompilerSettings* options, const char* buff, unsigned __int64 sz, const char* name)> hksi_hksL_loadbuffer{ 0x141D4BD80 };
|
||||
WEAK symbol<int(lua_State* s, const char* what, lua_Debug* ar)> hksi_lua_getinfo{ 0x141D4D960 };
|
||||
WEAK symbol<int(lua_State* s, int level, lua_Debug* ar)> hksi_lua_getstack{ 0x141D4DC20 };
|
||||
WEAK symbol<void(lua_State* s, const char* fmt, ...)> hksi_luaL_error{ 0x141D4D050 };
|
||||
WEAK symbol<const char*> s_compilerTypeName{ 0x140A18430 };
|
||||
}
|
||||
}
|
||||
|
171
src/client/game/ui_scripting/execution.cpp
Normal file
171
src/client/game/ui_scripting/execution.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
#include <std_include.hpp>
|
||||
#include "execution.hpp"
|
||||
|
||||
//#include "component/console.hpp"
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
namespace
|
||||
{
|
||||
script_value get_field(void* ptr, game::hks::HksObjectType type, const script_value& key)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto top = state->m_apistack.top;
|
||||
|
||||
push_value(key);
|
||||
|
||||
game::hks::HksObject value{};
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = type;
|
||||
obj.v.ptr = ptr;
|
||||
|
||||
game::hks::hks_obj_gettable(&value, state, &obj, &state->m_apistack.top[-1]);
|
||||
state->m_apistack.top = top;
|
||||
return value;
|
||||
}
|
||||
|
||||
void set_field(void* ptr, game::hks::HksObjectType type, const script_value& key, const script_value& value)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = type;
|
||||
obj.v.ptr = ptr;
|
||||
|
||||
game::hks::hks_obj_settable(state, &obj, &key.get_raw(), &value.get_raw());
|
||||
}
|
||||
}
|
||||
|
||||
void push_value(const script_value& value)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
*state->m_apistack.top = value.get_raw();
|
||||
state->m_apistack.top++;
|
||||
}
|
||||
|
||||
void push_value(const game::hks::HksObject& value)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
*state->m_apistack.top = value;
|
||||
state->m_apistack.top++;
|
||||
}
|
||||
|
||||
script_value get_return_value(std::int64_t offset)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
return state->m_apistack.top[-1 - offset];
|
||||
}
|
||||
|
||||
arguments get_return_values()
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto count = state->m_apistack.top - state->m_apistack.base;
|
||||
arguments values;
|
||||
|
||||
for (auto i = count - 1; i >= 0; i--)
|
||||
{
|
||||
values.push_back(get_return_value(i));
|
||||
}
|
||||
|
||||
if (values.empty())
|
||||
{
|
||||
values.push_back({});
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
arguments get_return_values(game::hks::HksObject* base)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto count = state->m_apistack.top - base;
|
||||
arguments values;
|
||||
|
||||
for (auto i = count - 1; i >= 0; i--)
|
||||
{
|
||||
values.push_back(get_return_value(i));
|
||||
}
|
||||
|
||||
if (values.empty())
|
||||
{
|
||||
values.push_back({});
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
bool notify(const std::string& name, const event_arguments& arguments)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
if (state == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//const auto _0 = gsl::finally(game::LUI_LeaveCriticalSection);
|
||||
//game::LUI_EnterCriticalSection();
|
||||
|
||||
try
|
||||
{
|
||||
const auto globals = table((*::game::hks::lua_state)->globals.v.table);
|
||||
const auto engine = globals.get("Engine").as<table>();
|
||||
const auto root = engine.get("GetLuiRoot")()[0].as<userdata>();
|
||||
const auto process_event = root.get("processEvent");
|
||||
|
||||
table event{};
|
||||
event.set("name", name);
|
||||
event.set("dispatchChildren", true);
|
||||
|
||||
for (const auto& arg : arguments)
|
||||
{
|
||||
event.set(arg.first, arg.second);
|
||||
}
|
||||
|
||||
process_event(root, event);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
printf("Error processing event '%s' %s\n", name.data(), ex.what());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
arguments call_script_function(const function& function, const arguments& arguments)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto top = state->m_apistack.top;
|
||||
|
||||
push_value(function);
|
||||
for (auto i = arguments.begin(); i != arguments.end(); ++i)
|
||||
{
|
||||
push_value(*i);
|
||||
}
|
||||
|
||||
game::hks::vm_call_internal(state, static_cast<int>(arguments.size()), -1, nullptr);
|
||||
const auto args = get_return_values(top);
|
||||
state->m_apistack.top = top;
|
||||
return args;
|
||||
}
|
||||
|
||||
script_value get_field(const userdata& self, const script_value& key)
|
||||
{
|
||||
return get_field(self.ptr, game::hks::TUSERDATA, key);
|
||||
}
|
||||
|
||||
script_value get_field(const table& self, const script_value& key)
|
||||
{
|
||||
return get_field(self.ptr, game::hks::TTABLE, key);
|
||||
}
|
||||
|
||||
void set_field(const userdata& self, const script_value& key, const script_value& value)
|
||||
{
|
||||
set_field(self.ptr, game::hks::TUSERDATA, key, value);
|
||||
}
|
||||
|
||||
void set_field(const table& self, const script_value& key, const script_value& value)
|
||||
{
|
||||
set_field(self.ptr, game::hks::TTABLE, key, value);
|
||||
}
|
||||
}
|
23
src/client/game/ui_scripting/execution.hpp
Normal file
23
src/client/game/ui_scripting/execution.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
#include "types.hpp"
|
||||
#include "script_value.hpp"
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
void push_value(const script_value& value);
|
||||
void push_value(const game::hks::HksObject& value);
|
||||
|
||||
script_value get_return_value(std::int64_t offset);
|
||||
arguments get_return_values();
|
||||
arguments get_return_values(game::hks::HksObject* base);
|
||||
|
||||
bool notify(const std::string& name, const event_arguments& arguments);
|
||||
|
||||
arguments call_script_function(const function& function, const arguments& arguments);
|
||||
|
||||
script_value get_field(const userdata& self, const script_value& key);
|
||||
script_value get_field(const table& self, const script_value& key);
|
||||
void set_field(const userdata& self, const script_value& key, const script_value& value);
|
||||
void set_field(const table& self, const script_value& key, const script_value& value);
|
||||
}
|
400
src/client/game/ui_scripting/script_value.cpp
Normal file
400
src/client/game/ui_scripting/script_value.cpp
Normal file
@ -0,0 +1,400 @@
|
||||
#include <std_include.hpp>
|
||||
#include "execution.hpp"
|
||||
#include "types.hpp"
|
||||
#include "script_value.hpp"
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
hks_object::hks_object(const game::hks::HksObject& value)
|
||||
{
|
||||
this->assign(value);
|
||||
}
|
||||
|
||||
hks_object::hks_object(const hks_object& other) noexcept
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
hks_object::hks_object(hks_object&& other) noexcept
|
||||
{
|
||||
this->operator=(std::move(other));
|
||||
}
|
||||
|
||||
hks_object& hks_object::operator=(const hks_object& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
this->release();
|
||||
this->assign(other.value_);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
hks_object& hks_object::operator=(hks_object&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
this->release();
|
||||
this->value_ = other.value_;
|
||||
other.value_.t = game::hks::TNONE;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
hks_object::~hks_object()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
const game::hks::HksObject& hks_object::get() const
|
||||
{
|
||||
return this->value_;
|
||||
}
|
||||
|
||||
void hks_object::assign(const game::hks::HksObject& value)
|
||||
{
|
||||
this->value_ = value;
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto top = state->m_apistack.top;
|
||||
|
||||
push_value(this->value_);
|
||||
this->ref_ = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||
state->m_apistack.top = top;
|
||||
}
|
||||
|
||||
void hks_object::release()
|
||||
{
|
||||
if (this->ref_)
|
||||
{
|
||||
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref_);
|
||||
this->value_.t = game::hks::TNONE;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Constructors
|
||||
**************************************************************/
|
||||
|
||||
script_value::script_value(const game::hks::HksObject& value)
|
||||
: value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const int value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TNUMBER;
|
||||
obj.v.number = static_cast<float>(value);
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const unsigned int value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TNUMBER;
|
||||
obj.v.number = static_cast<float>(value);
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const bool value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TBOOLEAN;
|
||||
obj.v.boolean = value;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const float value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TNUMBER;
|
||||
obj.v.number = static_cast<float>(value);
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const double value)
|
||||
: script_value(static_cast<float>(value))
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const char* value, const std::size_t len)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
if (state == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto top = state->m_apistack.top;
|
||||
game::hks::hksi_lua_pushlstring(state, value, static_cast<std::uint32_t>(len));
|
||||
obj = state->m_apistack.top[-1];
|
||||
state->m_apistack.top = top;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const char* value)
|
||||
: script_value(value, std::strlen(value))
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const std::string& value)
|
||||
: script_value(value.data(), value.size())
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const lightuserdata& value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TLIGHTUSERDATA;
|
||||
obj.v.ptr = value.ptr;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const userdata& value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TUSERDATA;
|
||||
obj.v.ptr = value.ptr;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const table& value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TTABLE;
|
||||
obj.v.ptr = value.ptr;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
script_value::script_value(const function& value)
|
||||
{
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = value.type;
|
||||
obj.v.ptr = value.ptr;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Integer
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<int>() const
|
||||
{
|
||||
const auto number = this->get_raw().v.number;
|
||||
return this->get_raw().t == game::hks::TNUMBER && static_cast<int>(number) == number;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::is<unsigned int>() const
|
||||
{
|
||||
return this->is<int>();
|
||||
}
|
||||
|
||||
template <>
|
||||
int script_value::get() const
|
||||
{
|
||||
return static_cast<int>(this->get_raw().v.number);
|
||||
}
|
||||
|
||||
template <>
|
||||
unsigned int script_value::get() const
|
||||
{
|
||||
return static_cast<unsigned int>(this->get_raw().v.number);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Boolean
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<bool>() const
|
||||
{
|
||||
return this->get_raw().t == game::hks::TBOOLEAN;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::get() const
|
||||
{
|
||||
return this->get_raw().v.boolean;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Float
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<float>() const
|
||||
{
|
||||
return this->get_raw().t == game::hks::TNUMBER;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::is<double>() const
|
||||
{
|
||||
return this->is<float>();
|
||||
}
|
||||
|
||||
template <>
|
||||
float script_value::get() const
|
||||
{
|
||||
return this->get_raw().v.number;
|
||||
}
|
||||
|
||||
template <>
|
||||
double script_value::get() const
|
||||
{
|
||||
return this->get_raw().v.number;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* String
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<const char*>() const
|
||||
{
|
||||
return this->get_raw().t == game::hks::TSTRING;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::is<std::string>() const
|
||||
{
|
||||
return this->is<const char*>();
|
||||
}
|
||||
|
||||
template <>
|
||||
const char* script_value::get() const
|
||||
{
|
||||
return this->get_raw().v.str->m_data;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string script_value::get() const
|
||||
{
|
||||
return this->get<const char*>();
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Lightuserdata
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<lightuserdata>() const
|
||||
{
|
||||
return this->get_raw().t == game::hks::TLIGHTUSERDATA;
|
||||
}
|
||||
|
||||
template <>
|
||||
lightuserdata script_value::get() const
|
||||
{
|
||||
return this->get_raw().v.ptr;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Userdata
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<userdata>() const
|
||||
{
|
||||
return this->get_raw().t == game::hks::TUSERDATA;
|
||||
}
|
||||
|
||||
template <>
|
||||
userdata script_value::get() const
|
||||
{
|
||||
return this->get_raw().v.ptr;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Table
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<table>() const
|
||||
{
|
||||
return this->get_raw().t == game::hks::TTABLE;
|
||||
}
|
||||
|
||||
template <>
|
||||
table script_value::get() const
|
||||
{
|
||||
return this->get_raw().v.table;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Function
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<function>() const
|
||||
{
|
||||
return this->get_raw().t == game::hks::TIFUNCTION
|
||||
|| this->get_raw().t == game::hks::TCFUNCTION;
|
||||
}
|
||||
|
||||
template <>
|
||||
function script_value::get() const
|
||||
{
|
||||
return { this->get_raw().v.cClosure, this->get_raw().t };
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
const game::hks::HksObject& script_value::get_raw() const
|
||||
{
|
||||
return this->value_.get();
|
||||
}
|
||||
|
||||
bool script_value::operator==(const script_value& other) const
|
||||
{
|
||||
if (this->get_raw().t != other.get_raw().t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->get_raw().t == game::hks::TSTRING)
|
||||
{
|
||||
return this->get<std::string>() == other.get<std::string>();
|
||||
}
|
||||
|
||||
return this->get_raw().v.native == other.get_raw().v.native;
|
||||
}
|
||||
|
||||
arguments script_value::operator()() const
|
||||
{
|
||||
return this->as<function>()();
|
||||
}
|
||||
|
||||
arguments script_value::operator()(const arguments& arguments) const
|
||||
{
|
||||
return this->as<function>()(arguments);
|
||||
}
|
||||
|
||||
function_argument::function_argument(const arguments& args, const script_value& value, const int index)
|
||||
: values_(args), value_(value), index_(index)
|
||||
{
|
||||
}
|
||||
|
||||
function_arguments::function_arguments(const arguments& values)
|
||||
: values_(values)
|
||||
{
|
||||
}
|
||||
}
|
251
src/client/game/ui_scripting/script_value.hpp
Normal file
251
src/client/game/ui_scripting/script_value.hpp
Normal file
@ -0,0 +1,251 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
class lightuserdata;
|
||||
class userdata_value;
|
||||
class userdata;
|
||||
class table_value;
|
||||
class table;
|
||||
class function;
|
||||
class script_value;
|
||||
|
||||
template <typename T>
|
||||
std::string get_typename()
|
||||
{
|
||||
auto& info = typeid(T);
|
||||
|
||||
if (info == typeid(std::string) ||
|
||||
info == typeid(const char*))
|
||||
{
|
||||
return "string";
|
||||
}
|
||||
|
||||
if (info == typeid(lightuserdata))
|
||||
{
|
||||
return "lightuserdata";
|
||||
}
|
||||
|
||||
if (info == typeid(userdata))
|
||||
{
|
||||
return "userdata";
|
||||
}
|
||||
|
||||
if (info == typeid(table))
|
||||
{
|
||||
return "table";
|
||||
}
|
||||
|
||||
if (info == typeid(function))
|
||||
{
|
||||
return "function";
|
||||
}
|
||||
|
||||
if (info == typeid(int) ||
|
||||
info == typeid(float) ||
|
||||
info == typeid(unsigned int))
|
||||
{
|
||||
return "number";
|
||||
}
|
||||
|
||||
if (info == typeid(bool))
|
||||
{
|
||||
return "boolean";
|
||||
}
|
||||
|
||||
return info.name();
|
||||
}
|
||||
|
||||
class hks_object
|
||||
{
|
||||
public:
|
||||
hks_object() = default;
|
||||
hks_object(const game::hks::HksObject& value);
|
||||
hks_object(const hks_object& other) noexcept;
|
||||
hks_object(hks_object&& other) noexcept;
|
||||
|
||||
hks_object& operator=(const hks_object& other) noexcept;
|
||||
hks_object& operator=(hks_object&& other) noexcept;
|
||||
|
||||
~hks_object();
|
||||
|
||||
const game::hks::HksObject& get() const;
|
||||
|
||||
private:
|
||||
void assign(const game::hks::HksObject& value);
|
||||
void release();
|
||||
|
||||
game::hks::HksObject value_{ game::hks::TNONE, {} };
|
||||
int ref_{};
|
||||
};
|
||||
|
||||
using arguments = std::vector<script_value>;
|
||||
using event_arguments = std::unordered_map<std::string, script_value>;
|
||||
|
||||
class script_value
|
||||
{
|
||||
public:
|
||||
script_value() = default;
|
||||
script_value(const game::hks::HksObject& value);
|
||||
|
||||
script_value(int value);
|
||||
script_value(unsigned int value);
|
||||
script_value(bool value);
|
||||
|
||||
script_value(float value);
|
||||
script_value(double value);
|
||||
|
||||
script_value(const char* value, std::size_t len);
|
||||
script_value(const char* value);
|
||||
script_value(const std::string& value);
|
||||
|
||||
script_value(const lightuserdata& value);
|
||||
script_value(const userdata& value);
|
||||
script_value(const table& value);
|
||||
script_value(const function& value);
|
||||
|
||||
template <template<class, class> class C, class T, typename TableType = table>
|
||||
script_value(const C<T, std::allocator<T>>& container)
|
||||
{
|
||||
TableType table_{};
|
||||
int index = 1;
|
||||
|
||||
for (const auto& value : container)
|
||||
{
|
||||
table_.set(index++, value);
|
||||
}
|
||||
|
||||
game::hks::HksObject obj{};
|
||||
obj.t = game::hks::TTABLE;
|
||||
obj.v.ptr = table_.ptr;
|
||||
|
||||
this->value_ = obj;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
script_value(F f)
|
||||
: script_value(function(f))
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const script_value& other) const;
|
||||
|
||||
arguments operator()() const;
|
||||
arguments operator()(const arguments& arguments) const;
|
||||
|
||||
template<class ...T>
|
||||
arguments operator()(T... arguments) const
|
||||
{
|
||||
return this->as<function>().call({ arguments... });
|
||||
}
|
||||
|
||||
template <size_t Size>
|
||||
table_value operator[](const char(&key)[Size]) const
|
||||
{
|
||||
return { this->as<table>(), key };
|
||||
}
|
||||
|
||||
template <typename T = script_value>
|
||||
table_value operator[](const T& key) const
|
||||
{
|
||||
return { this->as<table>(), key };
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] bool is() const;
|
||||
|
||||
template <typename T>
|
||||
T as() const
|
||||
{
|
||||
if (!this->is<T>())
|
||||
{
|
||||
const auto hks_typename = game::hks::s_compilerTypeName[this->get_raw().t + 2];
|
||||
const auto typename_ = get_typename<T>();
|
||||
|
||||
throw std::runtime_error(utils::string::va("%s expected, got %s", typename_.data(), hks_typename));
|
||||
}
|
||||
|
||||
return get<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
operator T() const
|
||||
{
|
||||
return this->as<T>();
|
||||
}
|
||||
|
||||
[[nodiscard]] const game::hks::HksObject& get_raw() const;
|
||||
|
||||
hks_object value_{};
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
T get() const;
|
||||
};
|
||||
|
||||
class variadic_args : public arguments
|
||||
{
|
||||
};
|
||||
|
||||
class function_argument
|
||||
{
|
||||
public:
|
||||
function_argument(const arguments& args, const script_value& value, const int index);
|
||||
|
||||
template <typename T>
|
||||
T as() const
|
||||
{
|
||||
try
|
||||
{
|
||||
return this->value_.as<T>();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error(utils::string::va("bad argument #%d (%s)", this->index_ + 1, e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
variadic_args as() const
|
||||
{
|
||||
variadic_args args{};
|
||||
for (auto i = this->index_; i < this->values_.size(); i++)
|
||||
{
|
||||
args.push_back(this->values_[i]);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
operator T() const
|
||||
{
|
||||
return this->as<T>();
|
||||
}
|
||||
|
||||
private:
|
||||
arguments values_{};
|
||||
script_value value_{};
|
||||
int index_{};
|
||||
};
|
||||
|
||||
class function_arguments
|
||||
{
|
||||
public:
|
||||
function_arguments(const arguments& values);
|
||||
|
||||
function_argument operator[](const int index) const
|
||||
{
|
||||
if (static_cast<std::size_t>(index) >= values_.size())
|
||||
{
|
||||
return { values_, {}, index };
|
||||
}
|
||||
|
||||
return { values_, values_[index], index };
|
||||
}
|
||||
private:
|
||||
arguments values_{};
|
||||
};
|
||||
}
|
351
src/client/game/ui_scripting/types.cpp
Normal file
351
src/client/game/ui_scripting/types.cpp
Normal file
@ -0,0 +1,351 @@
|
||||
#include <std_include.hpp>
|
||||
#include "types.hpp"
|
||||
#include "execution.hpp"
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
/***************************************************************
|
||||
* Lightuserdata
|
||||
**************************************************************/
|
||||
|
||||
lightuserdata::lightuserdata(void* ptr_)
|
||||
: ptr(ptr_)
|
||||
{
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Userdata
|
||||
**************************************************************/
|
||||
|
||||
userdata::userdata(void* ptr_)
|
||||
: ptr(ptr_)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
|
||||
userdata::userdata(const userdata& other)
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
userdata::userdata(userdata&& other) noexcept
|
||||
{
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
userdata::~userdata()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
userdata& userdata::operator=(const userdata& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
this->add();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
userdata& userdata::operator=(userdata&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void userdata::add()
|
||||
{
|
||||
game::hks::HksObject value{};
|
||||
value.v.ptr = this->ptr;
|
||||
value.t = game::hks::TUSERDATA;
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto top = state->m_apistack.top;
|
||||
|
||||
push_value(value);
|
||||
|
||||
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||
state->m_apistack.top = top;
|
||||
}
|
||||
|
||||
void userdata::release()
|
||||
{
|
||||
if (this->ref)
|
||||
{
|
||||
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref);
|
||||
}
|
||||
}
|
||||
|
||||
void userdata::set(const script_value& key, const script_value& value) const
|
||||
{
|
||||
set_field(*this, key, value);
|
||||
}
|
||||
|
||||
script_value userdata::get(const script_value& key) const
|
||||
{
|
||||
return get_field(*this, key);
|
||||
}
|
||||
|
||||
userdata_value userdata::operator[](const script_value& key) const
|
||||
{
|
||||
return { *this, key };
|
||||
}
|
||||
|
||||
userdata_value::userdata_value(const userdata& table, const script_value& key)
|
||||
: userdata_(table), key_(key)
|
||||
{
|
||||
this->value_ = this->userdata_.get(key).get_raw();
|
||||
}
|
||||
|
||||
void userdata_value::operator=(const script_value& value)
|
||||
{
|
||||
this->userdata_.set(this->key_, value);
|
||||
this->value_ = value.get_raw();
|
||||
}
|
||||
|
||||
bool userdata_value::operator==(const script_value& value)
|
||||
{
|
||||
return this->userdata_.get(this->key_) == value;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Table
|
||||
**************************************************************/
|
||||
|
||||
table::table()
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
this->ptr = game::hks::Hashtable_Create(state, 0, 0);
|
||||
this->add();
|
||||
}
|
||||
|
||||
table::table(game::hks::HashTable* ptr_)
|
||||
: ptr(ptr_)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
|
||||
table::table(const table& other)
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
table::table(table&& other) noexcept
|
||||
{
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
table::~table()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
table& table::operator=(const table& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
this->add();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
table& table::operator=(table&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void table::add()
|
||||
{
|
||||
game::hks::HksObject value{};
|
||||
value.v.table = this->ptr;
|
||||
value.t = game::hks::TTABLE;
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto top = state->m_apistack.top;
|
||||
|
||||
push_value(value);
|
||||
|
||||
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||
state->m_apistack.top = top;
|
||||
}
|
||||
|
||||
void table::release()
|
||||
{
|
||||
if (this->ref)
|
||||
{
|
||||
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref);
|
||||
}
|
||||
}
|
||||
|
||||
void table::set(const script_value& key, const script_value& value) const
|
||||
{
|
||||
set_field(*this, key, value);
|
||||
}
|
||||
|
||||
table_value table::operator[](const script_value& key) const
|
||||
{
|
||||
return { *this, key };
|
||||
}
|
||||
|
||||
script_value table::get(const script_value& key) const
|
||||
{
|
||||
return get_field(*this, key);
|
||||
}
|
||||
|
||||
table_value::table_value(const table& table, const script_value& key)
|
||||
: table_(table), key_(key)
|
||||
{
|
||||
this->value_ = this->table_.get(key).get_raw();
|
||||
}
|
||||
|
||||
void table_value::operator=(const script_value& value)
|
||||
{
|
||||
this->table_.set(this->key_, value);
|
||||
this->value_ = value.get_raw();
|
||||
}
|
||||
|
||||
void table_value::operator=(const table_value& value)
|
||||
{
|
||||
this->table_.set(this->key_, value);
|
||||
this->value_ = value.get_raw();
|
||||
}
|
||||
|
||||
bool table_value::operator==(const script_value& value)
|
||||
{
|
||||
return this->table_.get(this->key_) == value;
|
||||
}
|
||||
|
||||
bool table_value::operator==(const table_value& value)
|
||||
{
|
||||
return this->table_.get(this->key_) == value;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Function
|
||||
**************************************************************/
|
||||
|
||||
function::function(game::hks::lua_function func)
|
||||
{
|
||||
const auto state = *game::hks::lua_state;
|
||||
this->ptr = game::hks::cclosure_Create(state, func, 0, 0, 0);
|
||||
this->type = game::hks::HksObjectType::TCFUNCTION;
|
||||
this->add();
|
||||
}
|
||||
|
||||
function::function(game::hks::cclosure* ptr_, game::hks::HksObjectType type_)
|
||||
: ptr(ptr_), type(type_)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
|
||||
function::function(const function& other)
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
function::function(function&& other) noexcept
|
||||
{
|
||||
this->ptr = other.ptr;
|
||||
this->type = other.type;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
function::~function()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
function& function::operator=(const function& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->type = other.type;
|
||||
this->ref = other.ref;
|
||||
this->add();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
function& function::operator=(function&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->ptr = other.ptr;
|
||||
this->type = other.type;
|
||||
this->ref = other.ref;
|
||||
other.ref = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void function::add()
|
||||
{
|
||||
game::hks::HksObject value{};
|
||||
value.v.cClosure = this->ptr;
|
||||
value.t = this->type;
|
||||
|
||||
const auto state = *game::hks::lua_state;
|
||||
const auto top = state->m_apistack.top;
|
||||
|
||||
push_value(value);
|
||||
|
||||
this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000);
|
||||
state->m_apistack.top = top;
|
||||
}
|
||||
|
||||
void function::release()
|
||||
{
|
||||
if (this->ref)
|
||||
{
|
||||
game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref);
|
||||
}
|
||||
}
|
||||
|
||||
arguments function::call(const arguments& arguments) const
|
||||
{
|
||||
return call_script_function(*this, arguments);
|
||||
}
|
||||
|
||||
arguments function::operator()(const arguments& arguments) const
|
||||
{
|
||||
return this->call(arguments);
|
||||
}
|
||||
|
||||
arguments function::operator()() const
|
||||
{
|
||||
return this->call({});
|
||||
}
|
||||
}
|
142
src/client/game/ui_scripting/types.hpp
Normal file
142
src/client/game/ui_scripting/types.hpp
Normal file
@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
#include "script_value.hpp"
|
||||
|
||||
#include "component/ui_scripting.hpp"
|
||||
|
||||
namespace ui_scripting
|
||||
{
|
||||
class lightuserdata
|
||||
{
|
||||
public:
|
||||
lightuserdata(void*);
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
class userdata_value;
|
||||
|
||||
class userdata
|
||||
{
|
||||
public:
|
||||
userdata(void*);
|
||||
|
||||
userdata(const userdata& other);
|
||||
userdata(userdata&& other) noexcept;
|
||||
|
||||
~userdata();
|
||||
|
||||
userdata& operator=(const userdata& other);
|
||||
userdata& operator=(userdata&& other) noexcept;
|
||||
|
||||
script_value get(const script_value& key) const;
|
||||
void set(const script_value& key, const script_value& value) const;
|
||||
|
||||
userdata_value operator[](const script_value& key) const;
|
||||
|
||||
void* ptr;
|
||||
|
||||
private:
|
||||
void add();
|
||||
void release();
|
||||
|
||||
int ref{};
|
||||
};
|
||||
|
||||
class userdata_value : public script_value
|
||||
{
|
||||
public:
|
||||
userdata_value(const userdata& table, const script_value& key);
|
||||
void operator=(const script_value& value);
|
||||
bool operator==(const script_value& value);
|
||||
private:
|
||||
userdata userdata_;
|
||||
script_value key_;
|
||||
};
|
||||
|
||||
class table_value;
|
||||
|
||||
class table
|
||||
{
|
||||
public:
|
||||
table();
|
||||
table(game::hks::HashTable* ptr_);
|
||||
|
||||
table(const table& other);
|
||||
table(table&& other) noexcept;
|
||||
|
||||
~table();
|
||||
|
||||
table& operator=(const table& other);
|
||||
table& operator=(table&& other) noexcept;
|
||||
|
||||
[[nodiscard]] script_value get(const script_value& key) const;
|
||||
void set(const script_value& key, const script_value& value) const;
|
||||
|
||||
table_value operator[](const script_value& key) const;
|
||||
|
||||
game::hks::HashTable* ptr;
|
||||
|
||||
private:
|
||||
void add();
|
||||
void release();
|
||||
|
||||
int ref{};
|
||||
};
|
||||
|
||||
class table_value : public script_value
|
||||
{
|
||||
public:
|
||||
table_value(const table& table, const script_value& key);
|
||||
void operator=(const script_value& value);
|
||||
void operator=(const table_value& value);
|
||||
bool operator==(const script_value& value);
|
||||
bool operator==(const table_value& value);
|
||||
private:
|
||||
table table_;
|
||||
script_value key_;
|
||||
};
|
||||
|
||||
|
||||
class function
|
||||
{
|
||||
public:
|
||||
function(game::hks::lua_function);
|
||||
function(game::hks::cclosure*, game::hks::HksObjectType);
|
||||
|
||||
template <typename F>
|
||||
function(F f)
|
||||
{
|
||||
this->ptr = ui_scripting::convert_function(f);
|
||||
this->type = game::hks::TCFUNCTION;
|
||||
}
|
||||
|
||||
function(const function& other);
|
||||
function(function&& other) noexcept;
|
||||
|
||||
~function();
|
||||
|
||||
function& operator=(const function& other);
|
||||
function& operator=(function&& other) noexcept;
|
||||
|
||||
arguments call(const arguments& arguments) const;
|
||||
|
||||
arguments operator()(const arguments& arguments) const;
|
||||
|
||||
template<class ...T>
|
||||
arguments operator()(T... arguments) const
|
||||
{
|
||||
return this->call({ arguments... });
|
||||
}
|
||||
|
||||
arguments operator()() const;
|
||||
|
||||
game::hks::cclosure* ptr;
|
||||
game::hks::HksObjectType type;
|
||||
|
||||
private:
|
||||
void add();
|
||||
void release();
|
||||
|
||||
int ref{};
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user