Merge pull request #170 from fedddddd/develop

Release v2.0.3
This commit is contained in:
fed 2022-02-17 23:42:55 +01:00 committed by GitHub
commit 886bd3f714
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 229 additions and 2346 deletions

View File

@ -11,7 +11,7 @@ on:
jobs: jobs:
build: build:
name: Build binaries name: Build binaries
runs-on: windows-latest runs-on: windows-2022
strategy: strategy:
matrix: matrix:
configuration: configuration:
@ -38,8 +38,8 @@ jobs:
uses: microsoft/setup-msbuild@v1.0.2 uses: microsoft/setup-msbuild@v1.0.2
- name: Generate project files - name: Generate project files
#run: tools/premake5 vs2019 --ci-build #run: tools/premake5 vs2022 --ci-build
run: tools/premake5 vs2019 run: tools/premake5 vs2022
- name: Set up problem matching - name: Set up problem matching
uses: ammaraskar/msvc-problem-matcher@master uses: ammaraskar/msvc-problem-matcher@master

View File

@ -39,3 +39,10 @@ This software has been created purely for the purposes of
academic research. It is not intended to be used to attack academic research. It is not intended to be used to attack
other systems. Project maintainers are not responsible or other systems. Project maintainers are not responsible or
liable for misuse of the software. Use responsibly. liable for misuse of the software. Use responsibly.
## Credits
This project is based on [IW6x](https://github.com/XLabsProject/iw6x-client) and [S1x](https://github.com/XLabsProject/s1x-client)
* [momo5502](https://github.com/momo5502)
* [JariKCoding](https://github.com/JariKCoding/CoDLuaDecompiler)
* [xensik](https://github.com/xensik/gsc-tool/)

View File

@ -4,8 +4,8 @@ version: "#{build} ({branch})"
environment: environment:
matrix: matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
PREMAKE_ACTION: vs2019 PREMAKE_ACTION: vs2022
CI: 1 CI: 1
branches: branches:

View File

@ -85,6 +85,7 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
if (io.directoryexists("mods")) then if (io.directoryexists("mods")) then
local mods = io.listfiles("mods/") local mods = io.listfiles("mods/")
for i = 1, #mods do for i = 1, #mods do
if (io.directoryexists(mods[i]) and not io.directoryisempty(mods[i])) then
local name, desc = getmodname(mods[i]) local name, desc = getmodname(mods[i])
if (mods[i] ~= modfolder) then if (mods[i] ~= modfolder) then
@ -96,6 +97,7 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
end end
end end
end end
end
menu:AddBackButton(function(a1) menu:AddBackButton(function(a1)
Engine.PlaySound(CoD.SFX.MenuBack) Engine.PlaySound(CoD.SFX.MenuBack)

2
deps/asmjit vendored

@ -1 +1 @@
Subproject commit 9a92d2f97260749f6f29dc93e53c743448f0137a Subproject commit 28c4d8c528527141955006f09124ce672ddfbe3f

2
deps/curl vendored

@ -1 +1 @@
Subproject commit 9f1d29ecacffe3e94349bcef6e9fafa62b1cc431 Subproject commit 049f3765c7016a3f7a92b7f88aae6405c49b84fb

2
deps/imgui vendored

@ -1 +1 @@
Subproject commit f07df31745296090ac7ecc01811f88c85766028a Subproject commit fc84214988b74179b3941d35393c24ee8ba7a794

2
deps/libtommath vendored

@ -1 +1 @@
Subproject commit bea9270646303baf683f4ba2ddf0d70721f0e55d Subproject commit 04e9d1e7a0493910b2eb5e757d623870692ada04

2
deps/protobuf vendored

@ -1 +1 @@
Subproject commit 3ea30d80847cd9561db570ae7f673afc15523545 Subproject commit 2f7ee91e326d95915b63918f968244cfefbc022a

2
deps/rapidjson vendored

@ -1 +1 @@
Subproject commit fd3dc29a5c2852df569e1ea81dbde2c412ac5051 Subproject commit e4bde977440d4a00f820b6586899e48a972d2493

View File

@ -1,3 +1,4 @@
@echo off @echo off
git submodule update --init --recursive git submodule update --init --recursive
tools\premake5 %* vs2019 tools\premake5 %* vs2022
pause

View File

@ -248,25 +248,23 @@ end
flags {"NoIncrementalLink", "NoMinimalRebuild", "MultiProcessorCompile", "No64BitChecks"} flags {"NoIncrementalLink", "NoMinimalRebuild", "MultiProcessorCompile", "No64BitChecks"}
filter "platforms:x64"
defines {"_WINDOWS", "WIN32"}
filter {}
configuration "windows" filter "configurations:Release"
defines {"_WINDOWS", "WIN32"} optimize "Size"
buildoptions {"/GL"}
linkoptions { "/IGNORE:4702", "/LTCG" }
defines {"NDEBUG"}
flags {"FatalCompileWarnings"}
filter {}
configuration "Release" filter "configurations:Debug"
optimize "Size" optimize "Debug"
buildoptions {"/GL"} buildoptions {"/bigobj"}
linkoptions { "/IGNORE:4702", "/LTCG" } defines {"DEBUG", "_DEBUG"}
filter {}
defines {"NDEBUG"}
flags {"FatalCompileWarnings"}
configuration "Debug"
optimize "Debug"
buildoptions {"/bigobj"}
defines {"DEBUG", "_DEBUG"}
configuration {}
project "common" project "common"
kind "StaticLib" kind "StaticLib"
@ -280,20 +278,6 @@ resincludedirs {"$(ProjectDir)src"}
dependencies.imports() dependencies.imports()
project "runner"
kind "WindowedApp"
language "C++"
files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"}
includedirs {"./src/runner", "./src/common", "%{prj.location}/src"}
resincludedirs {"$(ProjectDir)src"}
links {"common"}
dependencies.imports()
project "client" project "client"
kind "ConsoleApp" kind "ConsoleApp"
language "C++" language "C++"
@ -311,7 +295,7 @@ includedirs {"./src/client", "./src/common", "%{prj.location}/src"}
resincludedirs {"$(ProjectDir)src"} resincludedirs {"$(ProjectDir)src"}
dependson {"tlsdll", "runner"} dependson {"tlsdll"}
links {"common"} links {"common"}
@ -335,22 +319,6 @@ links {"common"}
resincludedirs {"$(ProjectDir)src"} resincludedirs {"$(ProjectDir)src"}
project "runner"
kind "WindowedApp"
language "C++"
files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"}
includedirs {"./src/runner", "./src/common", "%{prj.location}/src"}
links {"common"}
resincludedirs {"$(ProjectDir)src"}
links {"common"}
dependencies.imports()
group "Dependencies" group "Dependencies"
dependencies.projects() dependencies.projects()

View File

@ -5,6 +5,8 @@
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
#define ORIGINAL_BIND_COUNT 110
namespace binding namespace binding
{ {
namespace namespace
@ -24,7 +26,7 @@ namespace binding
const auto* const key_button = game::Key_KeynumToString(key_index, 0, 1); const auto* const key_button = game::Key_KeynumToString(key_index, 0, 1);
auto value = game::playerKeys->keys[key_index].binding; auto value = game::playerKeys->keys[key_index].binding;
if (value && value < 100) if (value && value < ORIGINAL_BIND_COUNT)
{ {
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
"bind %s \"%s\"\n", key_button, game::command_whitelist[value]); "bind %s \"%s\"\n", key_button, game::command_whitelist[value]);
@ -36,9 +38,9 @@ namespace binding
bytes_used += len; bytes_used += len;
} }
else if (value >= 100) else if (value >= ORIGINAL_BIND_COUNT)
{ {
value -= 100; value -= ORIGINAL_BIND_COUNT;
if (static_cast<size_t>(value) < custom_binds.size() && !custom_binds[value].empty()) if (static_cast<size_t>(value) < custom_binds.size() && !custom_binds[value].empty())
{ {
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
@ -80,7 +82,7 @@ namespace binding
int key_get_binding_for_cmd_stub(const char* command) int key_get_binding_for_cmd_stub(const char* command)
{ {
// original binds // original binds
for (auto i = 0; i <= 100; i++) for (auto i = 0; i <= ORIGINAL_BIND_COUNT; i++)
{ {
if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i])) if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i]))
{ {
@ -89,14 +91,14 @@ namespace binding
} }
// custom binds // custom binds
return 100 + get_binding_for_custom_command(command); return ORIGINAL_BIND_COUNT + get_binding_for_custom_command(command);
} }
void cl_execute_key_stub(const int local_client_num, int key, const int down, const unsigned int time) void cl_execute_key_stub(const int local_client_num, int key, const int down, const unsigned int time)
{ {
if (key >= 100) if (key >= ORIGINAL_BIND_COUNT)
{ {
key -= 100; key -= ORIGINAL_BIND_COUNT;
if (static_cast<size_t>(key) < custom_binds.size() && !custom_binds[key].empty()) if (static_cast<size_t>(key) < custom_binds.size() && !custom_binds[key].empty())
{ {

View File

@ -22,7 +22,6 @@ namespace branding
ui_scripting::push_value(VERSION); ui_scripting::push_value(VERSION);
return 1; return 1;
} }
}
void draw() void draw()
{ {
@ -31,12 +30,15 @@ namespace branding
15.f + static_cast<float>(font->pixelHeight), 15.f + static_cast<float>(font->pixelHeight),
1.f, 1.f, 0.f, color, 0); 1.f, 1.f, 0.f, color, 0);
} }
}
class component final : public component_interface class component final : public component_interface
{ {
public: public:
void post_unpack() override void post_unpack() override
{ {
scheduler::loop(draw, scheduler::pipeline::renderer);
localized_strings::override("MENU_SP_CAMPAIGN", "H2-MOD"); localized_strings::override("MENU_SP_CAMPAIGN", "H2-MOD");
localized_strings::override("MENU_SYSINFO_CUSTOMER_SUPPORT_LINK", "Github Page:"); localized_strings::override("MENU_SYSINFO_CUSTOMER_SUPPORT_LINK", "Github Page:");
localized_strings::override("MENU_SYSINFO_CUSTOMER_SUPPORT_URL", "https://github.com/fedddddd/h2-mod"); localized_strings::override("MENU_SYSINFO_CUSTOMER_SUPPORT_URL", "https://github.com/fedddddd/h2-mod");

View File

@ -1,6 +0,0 @@
#pragma once
namespace branding
{
void draw();
}

View File

@ -279,7 +279,6 @@ namespace fps
game::R_AddCmdDrawText(pos_string, 0x7FFFFFFF, font, x, game::R_AddCmdDrawText(pos_string, 0x7FFFFFFF, font, x,
60.f, 1.0f, 1.0f, 0.0f, fps_color_ok, 0); 60.f, 1.0f, 1.0f, 0.0f, fps_color_ok, 0);
} }
}
void draw() void draw()
{ {
@ -295,12 +294,15 @@ namespace fps
draw_speed(); draw_speed();
draw_speed_graph(); draw_speed_graph();
} }
}
class component final : public component_interface class component final : public component_interface
{ {
public: public:
void post_unpack() override void post_unpack() override
{ {
scheduler::loop(draw, scheduler::pipeline::renderer);
sub_7C55D0_hook.create(0x7C55D0_b, perf_update); sub_7C55D0_hook.create(0x7C55D0_b, perf_update);
cg_drawSpeed = dvars::register_bool("cg_drawSpeed", 0, game::DVAR_FLAG_SAVED); cg_drawSpeed = dvars::register_bool("cg_drawSpeed", 0, game::DVAR_FLAG_SAVED);

View File

@ -1,6 +0,0 @@
#pragma once
namespace fps
{
void draw();
}

View File

@ -354,7 +354,6 @@ namespace game_console
draw_output_scrollbar(x, y, width, height); draw_output_scrollbar(x, y, width, height);
draw_output_text(x, y); draw_output_text(x, y);
} }
}
void draw_console() void draw_console()
{ {
@ -375,6 +374,7 @@ namespace game_console
draw_input(); draw_input();
} }
} }
}
void print(const int type, const char* fmt, ...) void print(const int type, const char* fmt, ...)
{ {
@ -719,6 +719,8 @@ namespace game_console
public: public:
void post_unpack() override void post_unpack() override
{ {
scheduler::loop(draw_console, scheduler::pipeline::renderer);
con.cursor = 0; con.cursor = 0;
con.visible_line_count = 0; con.visible_line_count = 0;
con.output_visible = false; con.output_visible = false;

View File

@ -9,8 +9,6 @@ namespace game_console
con_type_info = 7 con_type_info = 7
}; };
void draw_console();
void print(int type, const char* fmt, ...); void print(int type, const char* fmt, ...);
bool console_char_event(int local_client_num, int key); bool console_char_event(int local_client_num, int key);

View File

@ -37,14 +37,22 @@ namespace patches
gscr_set_save_dvar_hook.invoke<void>(); gscr_set_save_dvar_hook.invoke<void>();
} }
game::dvar_t* cg_fov = nullptr;
game::dvar_t* cg_fovScale = nullptr;
game::dvar_t* dvar_register_float_stub(int hash, const char* dvarName, float value, float min, float max, unsigned int flags) game::dvar_t* dvar_register_float_stub(int hash, const char* dvarName, float value, float min, float max, unsigned int flags)
{ {
static const auto cg_fov_hash = game::generateHashValue("cg_fov"); static const auto cg_fov_hash = game::generateHashValue("cg_fov");
static const auto cg_fov_scale_hash = game::generateHashValue("cg_fovscale"); static const auto cg_fov_scale_hash = game::generateHashValue("cg_fovscale");
if (hash == cg_fov_hash || hash == cg_fov_scale_hash) if (hash == cg_fov_hash)
{ {
flags = game::DvarFlags::DVAR_FLAG_SAVED; return cg_fov;
}
if (hash == cg_fov_scale_hash)
{
return cg_fovScale;
} }
return dvar_register_float_hook.invoke<game::dvar_t*>(hash, dvarName, value, min, max, flags); return dvar_register_float_hook.invoke<game::dvar_t*>(hash, dvarName, value, min, max, flags);
@ -75,7 +83,12 @@ namespace patches
// Prevent game from overriding cg_fov and cg_fovscale values // Prevent game from overriding cg_fov and cg_fovscale values
gscr_set_save_dvar_hook.create(0x504C60_b, &gscr_set_save_dvar_stub); gscr_set_save_dvar_hook.create(0x504C60_b, &gscr_set_save_dvar_stub);
// Make cg_fov and cg_fovscale saved dvars // Make cg_fov and cg_fovscale saved dvars
cg_fov = dvars::register_float("cg_fov", 65.f, 40.f, 200.f, game::DvarFlags::DVAR_FLAG_SAVED);
cg_fovScale = dvars::register_float("cg_fovScale", 1.f, 0.1f, 2.f, game::DvarFlags::DVAR_FLAG_SAVED);
dvar_register_float_hook.create(game::Dvar_RegisterFloat.get(), dvar_register_float_stub); dvar_register_float_hook.create(game::Dvar_RegisterFloat.get(), dvar_register_float_stub);
} }
}; };

View File

@ -97,6 +97,11 @@ namespace scheduler
void r_end_frame_stub() void r_end_frame_stub()
{ {
execute(pipeline::renderer); execute(pipeline::renderer);
if (game::Sys_IsMainThread())
{
execute(pipeline::lui);
}
r_end_frame_hook.invoke<void>(); r_end_frame_hook.invoke<void>();
} }

View File

@ -10,6 +10,8 @@ namespace scheduler
// The game's rendering pipeline // The game's rendering pipeline
renderer, renderer,
lui,
// The game's server thread // The game's server thread
server, server,

View File

@ -8,10 +8,6 @@
#include "scheduler.hpp" #include "scheduler.hpp"
#include "command.hpp" #include "command.hpp"
#include "game_console.hpp"
#include "fps.hpp"
#include "branding.hpp"
#include "ui_scripting.hpp" #include "ui_scripting.hpp"
#include "game/ui_scripting/lua/engine.hpp" #include "game/ui_scripting/lua/engine.hpp"
@ -23,41 +19,17 @@
namespace ui_scripting namespace ui_scripting
{ {
std::unordered_map<std::string, game::hks::lua_function> functions;
std::unordered_map<std::string, game::hks::lua_function> methods;
namespace namespace
{ {
std::unordered_map<game::hks::cclosure*, sol::protected_function> converted_functions; std::unordered_map<game::hks::cclosure*, sol::protected_function> converted_functions;
utils::hook::detour hksi_open_lib_hook;
utils::hook::detour hksi_lual_error_hook; utils::hook::detour hksi_lual_error_hook;
utils::hook::detour hksi_lual_error_hook2; utils::hook::detour hksi_lual_error_hook2;
utils::hook::detour hksi_add_function_hook;
utils::hook::detour hks_start_hook; utils::hook::detour hks_start_hook;
utils::hook::detour hks_shutdown_hook; utils::hook::detour hks_shutdown_hook;
bool error_hook_enabled = false; bool error_hook_enabled = false;
void* hksi_open_lib_stub(game::hks::lua_State* s, const char* libname, game::hks::luaL_Reg* l)
{
for (auto i = l; i->name; ++i)
{
if (i->name == "__gc"s)
{
continue;
}
const auto lower = utils::string::to_lower(i->name);
libname
? functions[lower] = i->function
: methods[lower] = i->function;
}
return hksi_open_lib_hook.invoke<void*>(s, libname, l);
}
void hksi_lual_error_stub(game::hks::lua_State* s, const char* fmt, ...) void hksi_lual_error_stub(game::hks::lua_State* s, const char* fmt, ...)
{ {
char va_buffer[2048] = {0}; char va_buffer[2048] = {0};
@ -86,8 +58,6 @@ namespace ui_scripting
ui_scripting::lua::engine::start(); ui_scripting::lua::engine::start();
}); });
functions = {};
methods = {};
return hks_start_hook.invoke<void*>(a1); return hks_start_hook.invoke<void*>(a1);
} }
@ -96,18 +66,6 @@ namespace ui_scripting
ui_scripting::lua::engine::stop(); ui_scripting::lua::engine::stop();
hks_shutdown_hook.invoke<void*>(); hks_shutdown_hook.invoke<void*>();
} }
void hksi_add_function_stub(game::hks::lua_State* s, game::hks::lua_function f, int a3, const char* name, int a5)
{
if (name != "( lua_CFunction )LUI_CoD_LuaCall_UIExpression"s)
{
std::string name_ = name;
const auto sub = utils::string::to_lower(name_.substr(13, name_.size() - 14));
functions[sub] = f;
}
hksi_add_function_hook.invoke<void>(s, f, a3, name, a5);
}
} }
int main_function_handler(game::hks::lua_State* state) int main_function_handler(game::hks::lua_State* state)
@ -167,26 +125,6 @@ namespace ui_scripting
error_hook_enabled = false; error_hook_enabled = false;
} }
game::hks::lua_function find_function(const std::string& name)
{
const auto lower = utils::string::to_lower(name);
if (functions.find(lower) == functions.end())
{
return 0;
}
return functions[lower];
}
game::hks::lua_function find_method(const std::string& name)
{
const auto lower = utils::string::to_lower(name);
if (methods.find(lower) == methods.end())
{
return 0;
}
return methods[lower];
}
void notify(const event& e) void notify(const event& e)
{ {
lua::engine::notify(e); lua::engine::notify(e);
@ -198,47 +136,12 @@ namespace ui_scripting
void post_unpack() override void post_unpack() override
{ {
scheduler::loop([]() scheduler::loop(ui_scripting::lua::engine::run_frame, scheduler::pipeline::lui);
{
if (game::Sys_IsMainThread())
{
ui_scripting::lua::engine::run_frame();
}
fps::draw();
branding::draw();
game_console::draw_console();
}, scheduler::pipeline::renderer);
command::add("reloadmenus", []()
{
scheduler::once(ui_scripting::lua::engine::start, scheduler::pipeline::renderer);
});
command::add("openluamenu", [](const command::params& params)
{
const std::string name = params.get(1);
scheduler::once([name]()
{
ui_scripting::lua::engine::open_menu(name);
}, scheduler::pipeline::renderer);
});
command::add("closeluamenu", [](const command::params& params)
{
const std::string name = params.get(1);
scheduler::once([name]()
{
ui_scripting::lua::engine::close_menu(name);
}, scheduler::pipeline::renderer);
});
hks_start_hook.create(0x328BE0_b, hks_start_stub); hks_start_hook.create(0x328BE0_b, hks_start_stub);
hks_shutdown_hook.create(0x3203B0_b, hks_shutdown_stub); hks_shutdown_hook.create(0x3203B0_b, hks_shutdown_stub);
hksi_open_lib_hook.create(0x2E4530_b, hksi_open_lib_stub);
hksi_lual_error_hook.create(0x2E3E40_b, hksi_lual_error_stub); hksi_lual_error_hook.create(0x2E3E40_b, hksi_lual_error_stub);
hksi_lual_error_hook2.create(0x2DCB40_b, hksi_lual_error_stub); hksi_lual_error_hook2.create(0x2DCB40_b, hksi_lual_error_stub);
hksi_add_function_hook.create(0x2DB570_b, hksi_add_function_stub);
} }
}; };
} }

View File

@ -1,13 +1,9 @@
#pragma once #pragma once
#include "game/ui_scripting/lua/value_conversion.hpp" #include "game/ui_scripting/lua/value_conversion.hpp"
#include "game/ui_scripting/menu.hpp"
#include "game/ui_scripting/event.hpp" #include "game/ui_scripting/event.hpp"
namespace ui_scripting namespace ui_scripting
{ {
extern std::unordered_map<std::string, game::hks::lua_function> functions;
extern std::unordered_map<std::string, game::hks::lua_function> methods;
int main_function_handler(game::hks::lua_State* state); int main_function_handler(game::hks::lua_State* state);
void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function); void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function);
void clear_converted_functions(); void clear_converted_functions();
@ -15,8 +11,5 @@ namespace ui_scripting
void enable_error_hook(); void enable_error_hook();
void disable_error_hook(); void disable_error_hook();
game::hks::lua_function find_function(const std::string& name);
game::hks::lua_function find_method(const std::string& name);
void notify(const event& e); void notify(const event& e);
} }

View File

@ -264,8 +264,6 @@ namespace scripting
void array::set(const std::string& key, const script_value& _value) const void array::set(const std::string& key, const script_value& _value) const
{ {
const auto value = _value.get_raw(); const auto value = _value.get_raw();
const auto string_value = game::SL_GetString(key.data(), 0);
const auto variable_id = this->get_value_id(key); const auto variable_id = this->get_value_id(key);
if (!variable_id) if (!variable_id)

View File

@ -30,7 +30,20 @@ namespace scripting::lua
); );
} }
void setup_entity_type(sol::state& state, event_handler& handler, scheduler& scheduler) void setup_io(sol::state& state)
{
state["io"]["fileexists"] = utils::io::file_exists;
state["io"]["writefile"] = utils::io::write_file;
state["io"]["filesize"] = utils::io::file_size;
state["io"]["createdirectory"] = utils::io::create_directory;
state["io"]["directoryexists"] = utils::io::directory_exists;
state["io"]["directoryisempty"] = utils::io::directory_is_empty;
state["io"]["listfiles"] = utils::io::list_files;
state["io"]["copyfolder"] = utils::io::copy_folder;
state["io"]["readfile"] = static_cast<std::string(*)(const std::string&)>(utils::io::read_file);
}
void setup_vector_type(sol::state& state)
{ {
state["level"] = entity{*::game::levelEntityId}; state["level"] = entity{*::game::levelEntityId};
state["player"] = call("getentbynum", {0}).as<entity>(); state["player"] = call("getentbynum", {0}).as<entity>();
@ -181,6 +194,12 @@ namespace scripting::lua
{ {
return call("anglestoforward", {a}).as<vector>(); return call("anglestoforward", {a}).as<vector>();
}; };
}
void setup_entity_type(sol::state& state, event_handler& handler, scheduler& scheduler)
{
state["level"] = entity{ *::game::levelEntityId };
state["player"] = call("getentbynum", { 0 }).as<entity>();
auto entity_type = state.new_usertype<entity>("entity"); auto entity_type = state.new_usertype<entity>("entity");
@ -307,7 +326,10 @@ namespace scripting::lua
std::vector<unsigned int> returns = {entref.entnum, entref.classnum}; std::vector<unsigned int> returns = {entref.entnum, entref.classnum};
return sol::as_returns(returns); return sol::as_returns(returns);
}; };
}
void setup_game_type(sol::state& state, event_handler& handler, scheduler& scheduler)
{
struct game struct game
{ {
}; };
@ -407,7 +429,7 @@ namespace scripting::lua
return detour; return detour;
}; };
game_type["getfunctions"] = [entity_type](const game&, const sol::this_state s, const std::string& filename) game_type["getfunctions"] = [](const game&, const sol::this_state s, const std::string& filename)
{ {
if (scripting::script_function_table.find(filename) == scripting::script_function_table.end()) if (scripting::script_function_table.find(filename) == scripting::script_function_table.end())
{ {
@ -611,7 +633,10 @@ namespace scripting::lua
return this->folder_; return this->folder_;
}; };
setup_io(this->state_);
setup_vector_type(this->state_);
setup_entity_type(this->state_, this->event_handler_, this->scheduler_); setup_entity_type(this->state_, this->event_handler_, this->scheduler_);
setup_game_type(this->state_, this->event_handler_, this->scheduler_);
printf("Loading script '%s'\n", this->folder_.data()); printf("Loading script '%s'\n", this->folder_.data());
this->load_script("__init__"); this->load_script("__init__");

View File

@ -1,409 +0,0 @@
#include <std_include.hpp>
#include "element.hpp"
#include <utils/string.hpp>
#define fps_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 25)
namespace ui_scripting
{
namespace
{
uint64_t next_id;
float screen_max[2];
struct point
{
float x;
float y;
float f2;
float f3;
};
struct rectangle
{
point p0;
point p1;
point p2;
point p3;
};
std::unordered_map<std::string, std::string> font_map =
{
{"bank", "fonts/bank.ttf"},
{"fira_mono_bold", "fonts/fira_mono_bold.ttf"},
{"fira_mono_regular", "fonts/fira_mono_regular.ttf"},
{"defaultbold", "fonts/defaultbold.otf"},
{"objective", "fonts/defaultbold.otf"},
{"default", "fonts/default.otf"},
};
std::unordered_map<std::string, alignment> alignment_map =
{
{"left", alignment::start},
{"top", alignment::start},
{"center", alignment::middle},
{"right", alignment::end},
{"bottom", alignment::end},
};
float get_align_value(alignment align, float text_width, float w)
{
switch (align)
{
case (alignment::start):
return 0.f;
case (alignment::middle):
return (w / 2.f) - (text_width / 2.f);
case (alignment::end):
return w - text_width;
default:
return 0.f;
}
}
void draw_image(float x, float y, float w, float h, float* transform, float* color, game::Material* material)
{
game::rectangle rect;
rect.p0.x = x;
rect.p0.y = y;
rect.p0.f2 = 0.f;
rect.p0.f3 = 1.f;
rect.p1.x = x + w;
rect.p1.y = y;
rect.p1.f2 = 0.f;
rect.p1.f3 = 1.f;
rect.p2.x = x + w;
rect.p2.y = y + h;
rect.p2.f2 = 0.f;
rect.p2.f3 = 1.f;
rect.p3.x = x;
rect.p3.y = y + h;
rect.p3.f2 = 0.f;
rect.p3.f3 = 1.f;
game::R_DrawRectangle(&rect, transform[0], transform[1], transform[2], transform[3], color, material);
}
void check_resize()
{
screen_max[0] = game::ScrPlace_GetViewPlacement()->realViewportSize[0];
screen_max[1] = game::ScrPlace_GetViewPlacement()->realViewportSize[1];
}
float relative(float value)
{
return ceil((value / 1920.f) * screen_max[0]);
}
int relative(int value)
{
return (int)ceil(((float)value / 1920.f) * screen_max[0]);
}
game::rgba float_to_rgba(const float* color)
{
game::rgba rgba;
rgba.r = (uint8_t)(color[0] * 255.f);
rgba.g = (uint8_t)(color[1] * 255.f);
rgba.b = (uint8_t)(color[2] * 255.f);
rgba.a = (uint8_t)(color[3] * 255.f);
return rgba;
}
void draw_text(const char* text, game::Font_s* font, float x, float y, float x_scale, float y_scale, float rotation,
int style, float* color, float* second_color, float* glow_color)
{
const auto result = (uint64_t)game::R_AddCmdDrawText(text, 0x7FFFFFFF, font, x, y, x_scale, y_scale, rotation, color, style);
if (result)
{
*reinterpret_cast<float*>(result + 188) = glow_color[0];
*reinterpret_cast<float*>(result + 192) = glow_color[1];
*reinterpret_cast<float*>(result + 196) = glow_color[2];
*reinterpret_cast<float*>(result + 200) = glow_color[3];
*reinterpret_cast<game::rgba*>(result + 228) = float_to_rgba(second_color);
}
}
}
element::element()
: id(next_id++)
{
}
void element::set_horzalign(const std::string& value)
{
const auto lower = utils::string::to_lower(value);
if (alignment_map.find(lower) == alignment_map.end())
{
this->horzalign = alignment::start;
return;
}
const auto align = alignment_map[lower];
this->horzalign = align;
}
void element::set_vertalign(const std::string& value)
{
const auto lower = utils::string::to_lower(value);
if (alignment_map.find(lower) == alignment_map.end())
{
this->vertalign = alignment::start;
return;
}
const auto align = alignment_map[lower];
this->vertalign = align;
}
void element::set_text(const std::string& _text)
{
this->text = _text;
}
void element::set_font(const std::string& _font, const int _fontsize)
{
this->fontsize = _fontsize;
const auto lowercase = utils::string::to_lower(_font);
if (font_map.find(lowercase) == font_map.end())
{
this->font = "default";
}
else
{
this->font = lowercase;
}
}
void element::set_font(const std::string& _font)
{
const auto lowercase = utils::string::to_lower(_font);
if (font_map.find(lowercase) == font_map.end())
{
this->font = "default";
}
else
{
this->font = lowercase;
}
}
void element::set_text_offset(float _x, float _y)
{
this->text_offset[0] = _x;
this->text_offset[1] = _y;
}
void element::set_scale(float _x, float _y)
{
this->x_scale = _x;
this->y_scale = _y;
}
void element::set_rotation(float _rotation)
{
this->rotation = _rotation;
}
void element::set_style(int _style)
{
this->style = _style;
}
void element::set_background_color(float r, float g, float b, float a)
{
this->background_color[0] = r;
this->background_color[1] = g;
this->background_color[2] = b;
this->background_color[3] = a;
}
void element::set_color(float r, float g, float b, float a)
{
this->color[0] = r;
this->color[1] = g;
this->color[2] = b;
this->color[3] = a;
}
void element::set_second_color(float r, float g, float b, float a)
{
this->use_gradient = true;
this->second_color[0] = r;
this->second_color[1] = g;
this->second_color[2] = b;
this->second_color[3] = a;
}
void element::set_glow_color(float r, float g, float b, float a)
{
this->glow_color[0] = r;
this->glow_color[1] = g;
this->glow_color[2] = b;
this->glow_color[3] = a;
}
void element::set_border_material(const std::string& _material)
{
this->border_material = _material;
}
void element::set_border_color(float r, float g, float b, float a)
{
this->border_color[0] = r;
this->border_color[1] = g;
this->border_color[2] = b;
this->border_color[3] = a;
}
void element::set_border_width(float top)
{
this->border_width[0] = top;
this->border_width[1] = top;
this->border_width[2] = top;
this->border_width[3] = top;
}
void element::set_border_width(float top, float right)
{
this->border_width[0] = top;
this->border_width[1] = right;
this->border_width[2] = top;
this->border_width[3] = right;
}
void element::set_border_width(float top, float right, float bottom)
{
this->border_width[0] = top;
this->border_width[1] = right;
this->border_width[2] = bottom;
this->border_width[3] = bottom;
}
void element::set_border_width(float top, float right, float bottom, float left)
{
this->border_width[0] = top;
this->border_width[1] = right;
this->border_width[2] = bottom;
this->border_width[3] = left;
}
void element::set_slice(float left_percent, float top_percent, float right_percent, float bottom_percent)
{
this->slice[0] = left_percent;
this->slice[1] = top_percent;
this->slice[2] = right_percent;
this->slice[3] = bottom_percent;
}
void element::set_material(const std::string& _material)
{
this->material = _material;
}
void element::set_rect(const float _x, const float _y, const float _w, const float _h)
{
this->x = _x;
this->y = _y;
this->w = _w;
this->h = _h;
}
void element::render() const
{
check_resize();
if (this->background_color[3] > 0)
{
const auto background_material = game::Material_RegisterHandle(this->material.data());
draw_image(
relative(this->x) + relative(this->border_width[3]),
relative(this->y) + relative(this->border_width[0]),
relative(this->w) - relative(this->border_width[1]) - relative(this->border_width[3]),
relative(this->h) - relative(this->border_width[0]) - relative(this->border_width[2]),
(float*)this->slice,
(float*)this->background_color,
background_material
);
}
if (this->border_color[3] > 0)
{
const auto _border_material = game::Material_RegisterHandle(this->border_material.data());
draw_image(
relative(this->x),
relative(this->y),
relative(this->w),
relative(this->border_width[0]),
(float*)this->slice,
(float*)this->border_color,
_border_material
);
draw_image(
relative(this->x) + relative(this->w) - relative(this->border_width[1]),
relative(this->y) + relative(this->border_width[0]),
relative(this->border_width[1]),
relative(this->h) - relative(this->border_width[0]) - relative(this->border_width[2]),
(float*)this->slice,
(float*)this->border_color,
_border_material
);
draw_image(
relative(this->x),
relative(this->y) + relative(this->h) - relative(this->border_width[2]),
relative(this->w),
relative(this->border_width[2]),
(float*)this->slice,
(float*)this->border_color,
_border_material
);
draw_image(
relative(this->x),
relative(this->y) + relative(this->border_width[0]),
relative(this->border_width[3]),
relative(this->h) - relative(this->border_width[0]) - relative(this->border_width[2]),
(float*)this->slice,
(float*)this->border_color,
_border_material
);
}
if (!this->text.empty())
{
const auto fontname = font_map[this->font];
const auto _font = game::R_RegisterFont(fontname.data(), relative(this->fontsize));
const auto text_width = game::R_TextWidth(this->text.data(), 0x7FFFFFFF, _font);
const auto _horzalign = get_align_value(this->horzalign, (float)text_width, relative(this->w));
const auto _vertalign = get_align_value(this->vertalign, (float)relative(this->fontsize), relative(this->h));
const auto _x = relative(this->x) + relative(this->text_offset[0]) + _horzalign + relative(this->border_width[3]);
const auto _y = relative(this->y) + relative(this->text_offset[1]) + _vertalign + relative(this->fontsize) + relative(this->border_width[0]);
draw_text(
this->text.data(),
_font,
_x, _y,
this->x_scale,
this->y_scale,
this->rotation,
this->style,
(float*)this->color,
(float*)(this->use_gradient ? this->second_color : this->color),
(float*)this->glow_color
);
}
}
}

View File

@ -1,85 +0,0 @@
#pragma once
#include "game/game.hpp"
#include "script_value.hpp"
namespace ui_scripting
{
enum alignment
{
start,
middle,
end,
};
class element final
{
public:
element();
void set_horzalign(const std::string& value);
void set_vertalign(const std::string& value);
void set_text(const std::string& text);
void set_font(const std::string& _font);
void set_font(const std::string& _font, const int _fontsize);
void set_color(float r, float g, float b, float a);
void set_second_color(float r, float g, float b, float a);
void set_glow_color(float r, float g, float b, float a);
void set_text_offset(float x, float y);
void set_scale(float x, float y);
void set_rotation(float rotation);
void set_style(int style);
void set_background_color(float r, float g, float b, float a);
void set_material(const std::string& material);
void set_border_material(const std::string& material);
void set_border_color(float r, float g, float b, float a);
void set_border_width(float top);
void set_border_width(float top, float right);
void set_border_width(float top, float right, float bottom);
void set_border_width(float top, float right, float bottom, float left);
void set_slice(float left_percent, float top_percent, float right_percent, float bottom_percent);
void set_rect(const float _x, const float _y, const float _w, const float _h);
uint64_t id;
void render() const;
bool hidden = false;
bool use_gradient = false;
float x = 0.f;
float y = 0.f;
float w = 0.f;
float h = 0.f;
float rotation = 0;
float x_scale = 1.f;
float y_scale = 1.f;
int style = 0;
int fontsize = 20;
float text_offset[2] = {0.f, 0.f};
float color[4] = {1.f, 1.f, 1.f, 1.f};
float second_color[4] = {1.f, 1.f, 1.f, 1.f};
float glow_color[4] = {0.f, 0.f, 0.f, 0.f};
float background_color[4] = {0.f, 0.f, 0.f, 0.f};
float border_color[4] = {0.f, 0.f, 0.f, 0.f};
float border_width[4] = {0.f, 0.f, 0.f, 0.f};
float slice[4] = {0.f, 0.f, 1.f, 1.f};
alignment horzalign = alignment::start;
alignment vertalign = alignment::start;
std::unordered_map<std::string, script_value> attributes = {};
std::string font = "default";
std::string material = "white";
std::string border_material = "white";
std::string text{};
};
}

View File

@ -6,7 +6,6 @@ namespace ui_scripting
struct event struct event
{ {
std::string name; std::string name;
const void* element{};
arguments arguments; arguments arguments;
}; };
} }

View File

@ -158,71 +158,4 @@ namespace ui_scripting
throw std::runtime_error(std::string("Error setting table field: ") + e.what()); throw std::runtime_error(std::string("Error setting table field: ") + e.what());
} }
} }
arguments call_method(const userdata& self, const std::string& name, const arguments& arguments)
{
const auto function = ui_scripting::find_method(name);
if (!function)
{
throw std::runtime_error("Function " + name + " not found");
}
const auto state = *game::hks::lua_state;
state->m_apistack.top = state->m_apistack.base;
push_value(self);
for (auto i = arguments.begin(); i != arguments.end(); ++i)
{
push_value(*i);
}
enable_error_hook();
const auto __ = gsl::finally([]()
{
disable_error_hook();
});
try
{
const auto count = function(*game::hks::lua_state);
return get_return_values(count);
}
catch (const std::exception& e)
{
throw std::runtime_error("Error executing method " + name + ": " + e.what());
}
}
arguments call(const std::string& name, const arguments& arguments)
{
const auto function = ui_scripting::find_function(name);
if (!function)
{
throw std::runtime_error("Function " + name + " not found");
}
const auto state = *game::hks::lua_state;
state->m_apistack.top = state->m_apistack.base;
for (auto i = arguments.begin(); i != arguments.end(); ++i)
{
push_value(*i);
}
enable_error_hook();
const auto __ = gsl::finally([]()
{
disable_error_hook();
});
try
{
const auto count = function(*game::hks::lua_state);
return get_return_values(count);
}
catch (const std::exception& e)
{
throw std::runtime_error("Error executing function " + name + ": " + e.what());
}
}
} }

View File

@ -15,7 +15,4 @@ namespace ui_scripting
script_value get_field(const table& 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 userdata& self, const script_value& key, const script_value& value);
void set_field(const table& self, const script_value& key, const script_value& value); void set_field(const table& self, const script_value& key, const script_value& value);
arguments call_method(const userdata& self, const std::string& name, const arguments& arguments);
arguments call(const std::string& name, const arguments& arguments);
} }

View File

@ -23,14 +23,8 @@
namespace ui_scripting::lua namespace ui_scripting::lua
{ {
std::unordered_map<std::string, menu> menus;
std::vector<element*> elements;
element ui_element;
int mouse[2];
namespace namespace
{ {
const auto animation_script = utils::nt::load_resource(LUA_ANIMATION_SCRIPT);
const auto json_script = utils::nt::load_resource(LUA_JSON_SCRIPT); const auto json_script = utils::nt::load_resource(LUA_JSON_SCRIPT);
scripting::script_value script_convert(const sol::lua_value& value) scripting::script_value script_convert(const sol::lua_value& value)
@ -213,506 +207,6 @@ namespace ui_scripting::lua
}; };
} }
void setup_element_type(sol::state& state, event_handler& handler, scheduler& scheduler)
{
auto element_type = state.new_usertype<element>("element", "new", []()
{
const auto el = new element();
elements.push_back(el);
return el;
});
element_type["setvertalign"] = &element::set_vertalign;
element_type["sethorzalign"] = &element::set_horzalign;
element_type["setrect"] = &element::set_rect;
element_type["setfont"] = sol::overload(
static_cast<void(element::*)(const std::string&)>(&element::set_font),
static_cast<void(element::*)(const std::string&, int)>(&element::set_font)
);
element_type["settext"] = &element::set_text;
element_type["setmaterial"] = &element::set_material;
element_type["setcolor"] = &element::set_color;
element_type["setsecondcolor"] = &element::set_second_color;
element_type["setglowcolor"] = &element::set_glow_color;
element_type["setbackcolor"] = &element::set_background_color;
element_type["setbordercolor"] = &element::set_border_color;
element_type["setborderwidth"] = sol::overload(
static_cast<void(element::*)(float)>(&element::set_border_width),
static_cast<void(element::*)(float, float)>(&element::set_border_width),
static_cast<void(element::*)(float, float, float)>(&element::set_border_width),
static_cast<void(element::*)(float, float, float, float)>(&element::set_border_width)
);
element_type["settextoffset"] = &element::set_text_offset;
element_type["setscale"] = &element::set_scale;
element_type["setrotation"] = &element::set_rotation;
element_type["setyle"] = &element::set_style;
element_type["setslice"] = &element::set_slice;
element_type["getrect"] = [](const sol::this_state s, element& element)
{
auto rect = sol::table::create(s.lua_state());
rect["x"] = element.x;
rect["y"] = element.y;
rect["w"] = element.w + element.border_width[1] + element.border_width[3];
rect["h"] = element.h + element.border_width[0] + element.border_width[2];
return rect;
};
element_type["x"] = sol::property(
[](element& element)
{
return element.x;
},
[](element& element, float x)
{
element.x = x;
}
);
element_type["y"] = sol::property(
[](element& element)
{
return element.y;
},
[](element& element, float y)
{
element.y = y;
}
);
element_type["w"] = sol::property(
[](element& element)
{
return element.w;
},
[](element& element, float w)
{
element.w = w;
}
);
element_type["h"] = sol::property(
[](element& element)
{
return element.h;
},
[](element& element, float h)
{
element.h = h;
}
);
element_type["scalex"] = sol::property(
[](element& element)
{
return element.x_scale;
},
[](element& element, float x_scale)
{
element.x_scale = x_scale;
}
);
element_type["scaley"] = sol::property(
[](element& element)
{
return element.y_scale;
},
[](element& element, float y_scale)
{
element.y_scale = y_scale;
}
);
element_type["rotation"] = sol::property(
[](element& element)
{
return element.rotation;
},
[](element& element, float rotation)
{
element.rotation = rotation;
}
);
element_type["style"] = sol::property(
[](element& element)
{
return element.style;
},
[](element& element, int style)
{
element.style = style;
}
);
element_type["color"] = sol::property(
[](element& element, const sol::this_state s)
{
auto color = sol::table::create(s.lua_state());
color["r"] = element.color[0];
color["g"] = element.color[1];
color["b"] = element.color[2];
color["a"] = element.color[3];
return color;
},
[](element& element, const sol::lua_table color)
{
element.color[0] = color["r"].get_type() == sol::type::number ? color["r"].get<float>() : 0.f;
element.color[1] = color["g"].get_type() == sol::type::number ? color["g"].get<float>() : 0.f;
element.color[2] = color["b"].get_type() == sol::type::number ? color["b"].get<float>() : 0.f;
element.color[3] = color["a"].get_type() == sol::type::number ? color["a"].get<float>() : 0.f;
}
);
element_type["secondcolor"] = sol::property(
[](element& element, const sol::this_state s)
{
auto color = sol::table::create(s.lua_state());
color["r"] = element.second_color[0];
color["g"] = element.second_color[1];
color["b"] = element.second_color[2];
color["a"] = element.second_color[3];
return color;
},
[](element& element, const sol::lua_table color)
{
element.use_gradient = true;
element.second_color[0] = color["r"].get_type() == sol::type::number ? color["r"].get<float>() : 0.f;
element.second_color[1] = color["g"].get_type() == sol::type::number ? color["g"].get<float>() : 0.f;
element.second_color[2] = color["b"].get_type() == sol::type::number ? color["b"].get<float>() : 0.f;
element.second_color[3] = color["a"].get_type() == sol::type::number ? color["a"].get<float>() : 0.f;
}
);
element_type["usegradient"] = sol::property(
[](element& element, const sol::this_state s)
{
return element.use_gradient;
},
[](element& element, bool use_gradient)
{
element.use_gradient = use_gradient;
}
);
element_type["glowcolor"] = sol::property(
[](element& element, const sol::this_state s)
{
auto color = sol::table::create(s.lua_state());
color["r"] = element.glow_color[0];
color["g"] = element.glow_color[1];
color["b"] = element.glow_color[2];
color["a"] = element.glow_color[3];
return color;
},
[](element& element, const sol::lua_table color)
{
element.glow_color[0] = color["r"].get_type() == sol::type::number ? color["r"].get<float>() : 0.f;
element.glow_color[1] = color["g"].get_type() == sol::type::number ? color["g"].get<float>() : 0.f;
element.glow_color[2] = color["b"].get_type() == sol::type::number ? color["b"].get<float>() : 0.f;
element.glow_color[3] = color["a"].get_type() == sol::type::number ? color["a"].get<float>() : 0.f;
}
);
element_type["backcolor"] = sol::property(
[](element& element, const sol::this_state s)
{
auto color = sol::table::create(s.lua_state());
color["r"] = element.background_color[0];
color["g"] = element.background_color[1];
color["b"] = element.background_color[2];
color["a"] = element.background_color[3];
return color;
},
[](element& element, const sol::lua_table color)
{
element.background_color[0] = color["r"].get_type() == sol::type::number ? color["r"].get<float>() : 0.f;
element.background_color[1] = color["g"].get_type() == sol::type::number ? color["g"].get<float>() : 0.f;
element.background_color[2] = color["b"].get_type() == sol::type::number ? color["b"].get<float>() : 0.f;
element.background_color[3] = color["a"].get_type() == sol::type::number ? color["a"].get<float>() : 0.f;
}
);
element_type["bordercolor"] = sol::property(
[](element& element, const sol::this_state s)
{
auto color = sol::table::create(s.lua_state());
color["r"] = element.border_color[0];
color["g"] = element.border_color[1];
color["b"] = element.border_color[2];
color["a"] = element.border_color[3];
return color;
},
[](element& element, const sol::lua_table color)
{
element.border_color[0] = color["r"].get_type() == sol::type::number ? color["r"].get<float>() : 0.f;
element.border_color[1] = color["g"].get_type() == sol::type::number ? color["g"].get<float>() : 0.f;
element.border_color[2] = color["b"].get_type() == sol::type::number ? color["b"].get<float>() : 0.f;
element.border_color[3] = color["a"].get_type() == sol::type::number ? color["a"].get<float>() : 0.f;
}
);
element_type["borderwidth"] = sol::property(
[](element& element, const sol::this_state s)
{
auto color = sol::table::create(s.lua_state());
color["top"] = element.border_width[0];
color["right"] = element.border_width[1];
color["bottom"] = element.border_width[2];
color["left"] = element.border_width[3];
return color;
},
[](element& element, const sol::lua_table color)
{
element.border_width[0] = color["top"].get_type() == sol::type::number ? color["top"].get<float>() : 0.f;
element.border_width[1] = color["right"].get_type() == sol::type::number ? color["right"].get<float>() : element.border_width[1];
element.border_width[2] = color["bottom"].get_type() == sol::type::number ? color["bottom"].get<float>() : element.border_width[2];
element.border_width[3] = color["left"].get_type() == sol::type::number ? color["left"].get<float>() : element.border_width[3];
}
);
element_type["font"] = sol::property(
[](element& element)
{
return element.font;
},
[](element& element, const std::string& font)
{
element.set_font(font);
}
);
element_type["fontsize"] = sol::property(
[](element& element)
{
return element.fontsize;
},
[](element& element, float fontsize)
{
element.fontsize = (int)fontsize;
}
);
element_type["onnotify"] = [&handler](element& element, const std::string& event,
const event_callback& callback)
{
event_listener listener{};
listener.callback = callback;
listener.element = &element;
listener.event = event;
listener.is_volatile = false;
return handler.add_event_listener(std::move(listener));
};
element_type["onnotifyonce"] = [&handler](element& element, const std::string& event,
const event_callback& callback)
{
event_listener listener{};
listener.callback = callback;
listener.element = &element;
listener.event = event;
listener.is_volatile = true;
return handler.add_event_listener(std::move(listener));
};
element_type["notify"] = [&handler](element& element, const sol::this_state s, const std::string& _event,
sol::variadic_args va)
{
event event;
event.element = &element;
event.name = _event;
for (auto arg : va)
{
event.arguments.push_back(convert({s, arg}));
}
notify(event);
};
element_type["hidden"] = sol::property(
[](element& element)
{
return element.hidden;
},
[](element& element, bool hidden)
{
element.hidden = hidden;
}
);
element_type[sol::meta_function::new_index] = [](element& element, const sol::this_state s, const std::string& attribute, const sol::lua_value& value)
{
element.attributes[attribute] = convert({s, value});
};
element_type[sol::meta_function::index] = [](element& element, const sol::this_state s, const std::string& attribute)
{
if (element.attributes.find(attribute) == element.attributes.end())
{
return sol::lua_value{s, sol::lua_nil};
}
return sol::lua_value{s, convert(s, element.attributes[attribute])};
};
}
void setup_menu_type(sol::state& state, event_handler& handler, scheduler& scheduler)
{
auto menu_type = state.new_usertype<menu>("menu");
menu_type["onnotify"] = [&handler](menu& menu, const std::string& event,
const event_callback& callback)
{
event_listener listener{};
listener.callback = callback;
listener.element = &menu;
listener.event = event;
listener.is_volatile = false;
return handler.add_event_listener(std::move(listener));
};
menu_type["onnotifyonce"] = [&handler](menu& menu, const std::string& event,
const event_callback& callback)
{
event_listener listener{};
listener.callback = callback;
listener.element = &menu;
listener.event = event;
listener.is_volatile = true;
return handler.add_event_listener(std::move(listener));
};
menu_type["notify"] = [&handler](menu& element, const sol::this_state s, const std::string& _event,
sol::variadic_args va)
{
event event;
event.element = &element;
event.name = _event;
for (auto arg : va)
{
event.arguments.push_back(convert({s, arg}));
}
notify(event);
};
menu_type["addchild"] = [](const sol::this_state s, menu& menu, element& element)
{
menu.add_child(&element);
};
menu_type["cursor"] = sol::property(
[](menu& menu)
{
return menu.cursor;
},
[](menu& menu, bool cursor)
{
menu.cursor = cursor;
}
);
menu_type["hidden"] = sol::property(
[](menu& menu)
{
return menu.hidden;
},
[](menu& menu, bool hidden)
{
menu.hidden = hidden;
}
);
menu_type["ignoreevents"] = sol::property(
[](menu& menu)
{
return menu.ignoreevents;
},
[](menu& menu, bool ignoreevents)
{
menu.ignoreevents = ignoreevents;
}
);
menu_type["isopen"] = [](menu& menu)
{
return menu.visible || (menu.type == menu_type::overlay && game::Menu_IsMenuOpenAndVisible(0, menu.overlay_menu.data()));
};
menu_type["open"] = [&handler](menu& menu)
{
event event;
event.element = &menu;
event.name = "close";
notify(event);
menu.open();
};
menu_type["close"] = [&handler](menu& menu)
{
event event;
event.element = &menu;
event.name = "close";
notify(event);
menu.close();
};
menu_type["getelement"] = [](menu& menu, const sol::this_state s, const sol::lua_value& value, const std::string& attribute)
{
const auto value_ = convert({s, value});
for (const auto& element : menu.children)
{
if (element->attributes.find(attribute) != element->attributes.end() && element->attributes[attribute] == value_)
{
return sol::lua_value{s, element};
}
}
return sol::lua_value{s, sol::lua_nil};
};
menu_type["getelements"] = sol::overload
(
[](menu& menu, const sol::this_state s, const sol::lua_value& value, const std::string& attribute)
{
const auto value_ = convert({s, value});
auto result = sol::table::create(s.lua_state());
for (const auto& element : menu.children)
{
if (element->attributes.find(attribute) != element->attributes.end() && element->attributes[attribute] == value_)
{
result.add(element);
}
}
return result;
},
[](menu& menu, const sol::this_state s)
{
auto result = sol::table::create(s.lua_state());
for (const auto& element : menu.children)
{
result.add(element);
}
return result;
}
);
}
void setup_game_type(sol::state& state, event_handler& handler, scheduler& scheduler) void setup_game_type(sol::state& state, event_handler& handler, scheduler& scheduler)
{ {
struct game struct game
@ -721,137 +215,17 @@ namespace ui_scripting::lua
auto game_type = state.new_usertype<game>("game_"); auto game_type = state.new_usertype<game>("game_");
state["game"] = game(); state["game"] = game();
game_type["getmenu"] = [](const game&, const sol::this_state s, const std::string& name)
{
if (menus.find(name) == menus.end())
{
return sol::lua_value{s, sol::lua_nil};
}
return sol::lua_value{s, &menus[name]};
};
game_type["getelement"] = [](const game&, const sol::this_state s, const sol::lua_value& value, const std::string& attribute)
{
const auto value_ = convert({s, value});
for (const auto& element : elements)
{
if (element->attributes.find(attribute) != element->attributes.end() && element->attributes[attribute] == value_)
{
return sol::lua_value{s, element};
}
}
return sol::lua_value{s, sol::lua_nil};
};
game_type["getelements"] = sol::overload
(
[](const game&, const sol::this_state s, const sol::lua_value& value, const std::string& attribute)
{
const auto value_ = convert({s, value});
auto result = sol::table::create(s.lua_state());
for (const auto& element : elements)
{
if (element->attributes.find(attribute) != element->attributes.end() && element->attributes[attribute] == value_)
{
result.add(element);
}
}
return result;
},
[](const game&, const sol::this_state s)
{
auto result = sol::table::create(s.lua_state());
for (const auto& element : elements)
{
result.add(element);
}
return result;
}
);
game_type["time"] = []() game_type["time"] = []()
{ {
const auto now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()); const auto now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
return now.count(); return now.count();
}; };
game_type["newmenu"] = [](const game&, const std::string& name)
{
menus[name] = {};
return &menus[name];
};
game_type["executecommand"] = [](const game&, const std::string& command) game_type["executecommand"] = [](const game&, const std::string& command)
{ {
command::execute(command, false); command::execute(command, false);
}; };
game_type["luiopen"] = [](const game&, const std::string& menu)
{
::scheduler::once([menu]()
{
::game::LUI_OpenMenu(0, menu.data(), 0, 0, 0);
}, ::scheduler::pipeline::renderer);
};
game_type["newmenuoverlay"] = [](const game&, const std::string& name, const std::string& menu_name)
{
menus[name] = {};
menus[name].type = menu_type::overlay;
menus[name].overlay_menu = menu_name;
return &menus[name];
};
game_type["getmouseposition"] = [](const sol::this_state s, const game&)
{
auto pos = sol::table::create(s.lua_state());
pos["x"] = mouse[0];
pos["y"] = mouse[1];
return pos;
};
game_type["openmenu"] = [&handler](const game&, const std::string& name)
{
if (menus.find(name) == menus.end())
{
return;
}
const auto menu = &menus[name];
event event;
event.element = menu;
event.name = "open";
notify(event);
menu->open();
};
game_type["closemenu"] = [&handler](const game&, const std::string& name)
{
if (menus.find(name) == menus.end())
{
return;
}
const auto menu = &menus[name];
event event;
event.element = menu;
event.name = "close";
notify(event);
menu->close();
};
game_type["onframe"] = [&scheduler](const game&, const sol::protected_function& callback) game_type["onframe"] = [&scheduler](const game&, const sol::protected_function& callback)
{ {
return scheduler.add(callback, 0, false); return scheduler.add(callback, 0, false);
@ -874,7 +248,6 @@ namespace ui_scripting::lua
{ {
event_listener listener{}; event_listener listener{};
listener.callback = callback; listener.callback = callback;
listener.element = &ui_element;
listener.event = event; listener.event = event;
listener.is_volatile = false; listener.is_volatile = false;
@ -886,7 +259,6 @@ namespace ui_scripting::lua
{ {
event_listener listener{}; event_listener listener{};
listener.callback = callback; listener.callback = callback;
listener.element = &ui_element;
listener.event = event; listener.event = event;
listener.is_volatile = true; listener.is_volatile = true;
@ -991,49 +363,6 @@ namespace ui_scripting::lua
(0x71B970_b)(video.data(), 64, 0); (0x71B970_b)(video.data(), 64, 0);
}; };
game_type[sol::meta_function::index] = [](const game&, const std::string& name)
{
return [name](const game&, const sol::this_state s, sol::variadic_args va)
{
arguments arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
const auto values = call(name, arguments);
std::vector<sol::lua_value> returns;
for (const auto& value : values)
{
returns.push_back(convert(s, value));
}
return sol::as_returns(returns);
};
};
game_type["call"] = [](const game&, const sol::this_state s, const std::string& name, sol::variadic_args va)
{
arguments arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
const auto values = call(name, arguments);
std::vector<sol::lua_value> returns;
for (const auto& value : values)
{
returns.push_back(convert(s, value));
}
return sol::as_returns(returns);
};
game_type["sharedset"] = [](const game&, const std::string& key, const std::string& value) game_type["sharedset"] = [](const game&, const std::string& key, const std::string& value)
{ {
scripting::shared_table.access([key, value](scripting::shared_table_t& table) scripting::shared_table.access([key, value](scripting::shared_table_t& table)
@ -1116,7 +445,6 @@ namespace ui_scripting::lua
::scheduler::once([result, id] ::scheduler::once([result, id]
{ {
event event; event event;
event.element = &ui_element;
event.name = "http_request_done"; event.name = "http_request_done";
if (result.has_value()) if (result.has_value())
@ -1129,7 +457,7 @@ namespace ui_scripting::lua
} }
notify(event); notify(event);
}, ::scheduler::pipeline::renderer); }, ::scheduler::pipeline::lui);
}, ::scheduler::pipeline::async); }, ::scheduler::pipeline::async);
return id; return id;
}; };
@ -1140,25 +468,55 @@ namespace ui_scripting::lua
const auto id = request_id++; const auto id = request_id++;
::scheduler::once([url, id, dest]() ::scheduler::once([url, id, dest]()
{ {
const auto result = utils::http::get_data(url); auto last_report = std::chrono::high_resolution_clock::now();
::scheduler::once([result, id, dest] const auto result = utils::http::get_data(url, {}, [&last_report, id](size_t progress, size_t total, size_t speed)
{
const auto now = std::chrono::high_resolution_clock::now();
if (now - last_report < 100ms && progress < total)
{
return;
}
last_report = now;
::scheduler::once([id, progress, total, speed]
{ {
event event; event event;
event.element = &ui_element; event.name = "http_request_progress";
event.name = "http_request_done"; event.arguments = {
id,
static_cast<int>(progress),
static_cast<int>(total),
static_cast<int>(speed)
};
notify(event);
}, ::scheduler::pipeline::lui);
});
if (result.has_value()) if (result.has_value())
{ {
const auto write = utils::io::write_file(dest, result.value(), false); const auto write = utils::io::write_file(dest, result.value(), false);
::scheduler::once([result, id, write]()
{
event event;
event.name = "http_request_done";
event.arguments = {id, true, write}; event.arguments = {id, true, write};
notify(event);
}, ::scheduler::pipeline::lui);
} }
else else
{ {
::scheduler::once([result, id]()
{
event event;
event.name = "http_request_done";
event.arguments = {id, false}; event.arguments = {id, false};
}
notify(event); notify(event);
}, ::scheduler::pipeline::renderer); }, ::scheduler::pipeline::lui);
}
}, ::scheduler::pipeline::async); }, ::scheduler::pipeline::async);
return id; return id;
}; };
@ -1243,31 +601,6 @@ namespace ui_scripting::lua
} }
); );
for (const auto method : methods)
{
const auto name = method.first;
userdata_type[name] = [name](const userdata& userdata, const sol::this_state s, sol::variadic_args va)
{
arguments arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
const auto values = call_method(userdata, name, arguments);
std::vector<sol::lua_value> returns;
for (const auto& value : values)
{
returns.push_back(convert(s, value));
}
return sol::as_returns(returns);
};
}
userdata_type[sol::meta_function::index] = [](const userdata& userdata, const sol::this_state s, userdata_type[sol::meta_function::index] = [](const userdata& userdata, const sol::this_state s,
const std::string& name) const std::string& name)
{ {
@ -1344,8 +677,6 @@ namespace ui_scripting::lua
state["LUI"] = state["luiglobals"]["LUI"]; state["LUI"] = state["luiglobals"]["LUI"];
state["Engine"] = state["luiglobals"]["Engine"]; state["Engine"] = state["luiglobals"]["Engine"];
state["Game"] = state["luiglobals"]["Game"]; state["Game"] = state["luiglobals"]["Game"];
state.script(animation_script);
} }
} }
@ -1365,8 +696,6 @@ namespace ui_scripting::lua
setup_io(this->state_); setup_io(this->state_);
setup_json(this->state_); setup_json(this->state_);
setup_vector_type(this->state_); setup_vector_type(this->state_);
setup_element_type(this->state_, this->event_handler_, this->scheduler_);
setup_menu_type(this->state_, this->event_handler_, this->scheduler_);
setup_game_type(this->state_, this->event_handler_, this->scheduler_); setup_game_type(this->state_, this->event_handler_, this->scheduler_);
setup_lui_types(this->state_, this->event_handler_, this->scheduler_); setup_lui_types(this->state_, this->event_handler_, this->scheduler_);

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "../event.hpp" #include "../event.hpp"
#include "../menu.hpp"
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4702) #pragma warning(disable: 4702)
@ -21,11 +20,6 @@ namespace ui_scripting::lua
code code
}; };
extern std::unordered_map<std::string, menu> menus;
extern std::vector<element*> elements;
extern element ui_element;
extern int mouse[2];
class context class context
{ {
public: public:

View File

@ -15,290 +15,27 @@ namespace ui_scripting::lua::engine
{ {
const auto updater_script = utils::nt::load_resource(LUI_UPDATER_MENU); const auto updater_script = utils::nt::load_resource(LUI_UPDATER_MENU);
float screen_max[2];
void check_resize()
{
screen_max[0] = game::ScrPlace_GetViewPlacement()->realViewportSize[0];
screen_max[1] = game::ScrPlace_GetViewPlacement()->realViewportSize[1];
}
int relative_mouse(int value)
{
return (int)ceil(((float)value / screen_max[0]) * 1920.f);
}
int relative(int value)
{
return (int)ceil(((float)value / 1920.f) * screen_max[0]);
}
float relative(float value)
{
return ceil((value / 1920.f) * screen_max[0]);
}
bool point_in_rect(int px, int py, int x, int y, int w, int h)
{
return (px > x && px < x + w && py > y && py < y + h);
}
bool is_menu_visible(const menu& menu)
{
return menu.visible && !menu.hidden || (!menu.hidden && menu.type == menu_type::overlay && game::Menu_IsMenuOpenAndVisible(0, menu.overlay_menu.data()));
}
std::vector<element*> elements_in_point(int x, int y)
{
std::vector<element*> result;
for (const auto& menu : menus)
{
if (!is_menu_visible(menu.second) || menu.second.ignoreevents)
{
continue;
}
for (const auto& child : menu.second.children)
{
if (child->hidden)
{
continue;
}
const auto in_rect = point_in_rect(
x, y,
(int)child->x,
(int)child->y,
(int)child->w + (int)child->border_width[1] + (int)child->border_width[3],
(int)child->h + (int)child->border_width[0] + (int)child->border_width[2]
);
if (in_rect)
{
result.push_back(child);
}
}
}
return result;
}
void handle_key_event(const int key, const int down) void handle_key_event(const int key, const int down)
{
const auto _elements = elements_in_point(mouse[0], mouse[1]);
switch (key)
{
case game::K_MOUSE2:
case game::K_MOUSE1:
{
const auto click_name = key == game::K_MOUSE1
? "click"
: "rightclick";
const auto key_name = key == game::K_MOUSE1
? "mouse"
: "rightmouse";
{
event main_event;
main_event.element = &ui_element;
main_event.name = utils::string::va("%s%s", key_name, down ? "down" : "up");
main_event.arguments =
{
mouse[0],
mouse[1],
};
engine::notify(main_event);
for (const auto& element : _elements)
{ {
event event; event event;
event.element = element;
event.name = utils::string::va("%s%s", key_name, down ? "down" : "up");
event.arguments =
{
mouse[0],
mouse[1],
};
engine::notify(event);
}
}
if (!down)
{
event main_event;
main_event.element = &ui_element;
main_event.name = click_name;
main_event.arguments =
{
mouse[0],
mouse[1],
};
engine::notify(main_event);
for (const auto& element : _elements)
{
event event;
event.element = element;
event.name = click_name;
event.arguments =
{
mouse[0],
mouse[1],
};
engine::notify(event);
}
}
break;
}
case game::K_MWHEELUP:
case game::K_MWHEELDOWN:
{
const auto key_name = key == game::K_MWHEELUP
? "scrollup"
: "scrolldown";
if (!down)
{
break;
}
{
event main_event;
main_event.element = &ui_element;
main_event.name = key_name;
main_event.arguments =
{
mouse[0],
mouse[1],
};
engine::notify(main_event);
for (const auto& element : _elements)
{
event event;
event.element = element;
event.name = key_name;
event.arguments = {mouse[0], mouse[1]};
engine::notify(event);
}
}
break;
}
default:
{
event event;
event.element = &ui_element;
event.name = down event.name = down
? "keydown" ? "keydown"
: "keyup"; : "keyup";
event.arguments = {key}; event.arguments = {key};
engine::notify(event); engine::notify(event);
break;
}
}
} }
void handle_char_event(const int key) void handle_char_event(const int key)
{ {
std::string key_str = {(char)key}; std::string key_str = {(char)key};
event event; event event;
event.element = &ui_element;
event.name = "keypress"; event.name = "keypress";
event.arguments = {key_str}; event.arguments = {key_str};
engine::notify(event); engine::notify(event);
} }
std::vector<element*> previous_elements;
void handle_mousemove_event(const int x, const int y)
{
if (mouse[0] == x && mouse[1] == y)
{
return;
}
mouse[0] = x;
mouse[1] = y;
{
event event;
event.element = &ui_element;
event.name = "mousemove";
event.arguments = {x, y};
engine::notify(event);
}
const auto _elements = elements_in_point(x, y);
for (const auto& element : _elements)
{
event event;
event.element = element;
event.name = "mouseover";
engine::notify(event);
}
for (const auto& element : previous_elements)
{
auto found = false;
for (const auto& _element : _elements)
{
if (element == _element)
{
found = true;
}
}
if (!found)
{
event event;
event.element = element;
event.name = "mouseleave";
engine::notify(event);
}
}
for (const auto& element : _elements)
{
auto found = false;
for (const auto& _element : previous_elements)
{
if (element == _element)
{
found = true;
}
}
if (!found)
{
event event;
event.element = element;
event.name = "mouseenter";
engine::notify(event);
}
}
previous_elements = _elements;
}
auto& get_scripts() auto& get_scripts()
{ {
static std::vector<std::unique_ptr<context>> scripts{}; static std::vector<std::unique_ptr<context>> scripts{};
@ -327,91 +64,12 @@ namespace ui_scripting::lua::engine
{ {
get_scripts().push_back(std::make_unique<context>(code, script_type::code)); get_scripts().push_back(std::make_unique<context>(code, script_type::code));
} }
void render_menus()
{
check_resize();
for (auto& menu : menus)
{
if (is_menu_visible(menu.second))
{
menu.second.render();
}
}
}
void close_all_menus()
{
for (auto& menu : menus)
{
if (!is_menu_visible(menu.second))
{
continue;
}
event event;
event.element = &menu.second;
event.name = "close";
engine::notify(event);
menu.second.close();
}
}
void clear_menus()
{
menus.clear();
for (const auto element : elements)
{
delete element;
}
elements.clear();
}
}
void open_menu(const std::string& name)
{
if (menus.find(name) == menus.end())
{
return;
}
const auto menu = &menus[name];
event event;
event.element = menu;
event.name = "open";
engine::notify(event);
menu->open();
}
void close_menu(const std::string& name)
{
if (menus.find(name) == menus.end())
{
return;
}
const auto menu = &menus[name];
event event;
event.element = menu;
event.name = "close";
engine::notify(event);
menu->close();
} }
void start() void start()
{ {
clear_converted_functions(); clear_converted_functions();
close_all_menus();
get_scripts().clear(); get_scripts().clear();
clear_menus();
load_code(updater_script); load_code(updater_script);
@ -428,9 +86,7 @@ namespace ui_scripting::lua::engine
void stop() void stop()
{ {
clear_converted_functions(); clear_converted_functions();
close_all_menus();
get_scripts().clear(); get_scripts().clear();
clear_menus();
} }
void ui_event(const std::string& type, const std::vector<int>& arguments) void ui_event(const std::string& type, const std::vector<int>& arguments)
@ -444,11 +100,6 @@ namespace ui_scripting::lua::engine
{ {
handle_char_event(arguments[0]); handle_char_event(arguments[0]);
} }
if (type == "mousemove")
{
handle_mousemove_event(relative_mouse(arguments[0]), relative_mouse(arguments[1]));
}
} }
void notify(const event& e) void notify(const event& e)
@ -461,9 +112,6 @@ namespace ui_scripting::lua::engine
void run_frame() void run_frame()
{ {
check_resize();
render_menus();
for (auto& script : get_scripts()) for (auto& script : get_scripts())
{ {
script->run_frame(); script->run_frame();

View File

@ -7,9 +7,6 @@ namespace ui_scripting::lua::engine
void start(); void start();
void stop(); void stop();
void close_menu(const std::string& name);
void open_menu(const std::string& name);
void ui_event(const std::string&, const std::vector<int>&); void ui_event(const std::string&, const std::vector<int>&);
void notify(const event& e); void notify(const event& e);
void run_frame(); void run_frame();

View File

@ -17,9 +17,9 @@ namespace ui_scripting::lua
this->remove(handle); this->remove(handle);
}; };
event_listener_handle_type["endon"] = [this](const event_listener_handle& handle, const element* entity, const std::string& event) event_listener_handle_type["endon"] = [this](const event_listener_handle& handle, const std::string& event)
{ {
this->add_endon_condition(handle, entity, event); this->add_endon_condition(handle, event);
}; };
} }
@ -35,7 +35,7 @@ namespace ui_scripting::lua
for (auto i = tasks.begin(); i != tasks.end();) for (auto i = tasks.begin(); i != tasks.end();)
{ {
if (i->event != event.name || i->element != event.element) if (i->event != event.name)
{ {
++i; ++i;
continue; continue;
@ -78,8 +78,7 @@ namespace ui_scripting::lua
return {id}; return {id};
} }
void event_handler::add_endon_condition(const event_listener_handle& handle, const element* element, void event_handler::add_endon_condition(const event_listener_handle& handle, const std::string& event)
const std::string& event)
{ {
auto merger = [&](task_list& tasks) auto merger = [&](task_list& tasks)
{ {
@ -87,7 +86,7 @@ namespace ui_scripting::lua
{ {
if (task.id == handle.id) if (task.id == handle.id)
{ {
task.endon_conditions.emplace_back((uint64_t)element, event); task.endon_conditions.emplace_back(event);
} }
} }
}; };
@ -150,7 +149,7 @@ namespace ui_scripting::lua
{ {
for (auto& condition : task.endon_conditions) for (auto& condition : task.endon_conditions)
{ {
if (condition.first == (uint64_t)event.element && condition.second == event.name) if (condition == event.name)
{ {
task.is_deleted = true; task.is_deleted = true;
break; break;

View File

@ -16,11 +16,10 @@ namespace ui_scripting::lua
{ {
public: public:
std::string event = {}; std::string event = {};
void* element{};
event_callback callback = {}; event_callback callback = {};
bool is_volatile = false; bool is_volatile = false;
bool is_deleted = false; bool is_deleted = false;
std::vector<std::pair<uint64_t, std::string>> endon_conditions{}; std::vector<std::string> endon_conditions{};
}; };
class event_handler final class event_handler final
@ -52,7 +51,7 @@ namespace ui_scripting::lua
void merge_callbacks(); void merge_callbacks();
void handle_endon_conditions(const event& event); void handle_endon_conditions(const event& event);
void add_endon_condition(const event_listener_handle& handle, const element* element, const std::string& event); void add_endon_condition(const event_listener_handle& handle, const std::string& event);
event_arguments build_arguments(const event& event) const; event_arguments build_arguments(const event& event) const;
}; };

View File

@ -13,9 +13,9 @@ namespace ui_scripting::lua
this->remove(handle); this->remove(handle);
}; };
task_handle_type["endon"] = [this](const task_handle& handle, const element* element, const std::string& event) task_handle_type["endon"] = [this](const task_handle& handle, const std::string& event)
{ {
this->add_endon_condition(handle, element, event); this->add_endon_condition(handle, event);
}; };
} }
@ -27,7 +27,7 @@ namespace ui_scripting::lua
{ {
for (auto& condition : task.endon_conditions) for (auto& condition : task.endon_conditions)
{ {
if (condition.first == (uint64_t)event.element && condition.second == event.name) if (condition == event.name)
{ {
task.is_deleted = true; task.is_deleted = true;
break; break;
@ -118,7 +118,7 @@ namespace ui_scripting::lua
return {id}; return {id};
} }
void scheduler::add_endon_condition(const task_handle& handle, const element* element, const std::string& event) void scheduler::add_endon_condition(const task_handle& handle, const std::string& event)
{ {
auto merger = [&](task_list& tasks) auto merger = [&](task_list& tasks)
{ {
@ -126,7 +126,7 @@ namespace ui_scripting::lua
{ {
if (task.id == handle.id) if (task.id == handle.id)
{ {
task.endon_conditions.emplace_back(element->id, event); task.endon_conditions.emplace_back(event);
} }
} }
}; };

View File

@ -19,7 +19,7 @@ namespace ui_scripting::lua
std::chrono::milliseconds delay{}; std::chrono::milliseconds delay{};
bool is_volatile = false; bool is_volatile = false;
bool is_deleted = false; bool is_deleted = false;
std::vector<std::pair<uint64_t, std::string>> endon_conditions{}; std::vector<std::string> endon_conditions{};
}; };
class scheduler final class scheduler final
@ -46,7 +46,7 @@ namespace ui_scripting::lua
utils::concurrency::container<task_list, std::recursive_mutex> callbacks_; utils::concurrency::container<task_list, std::recursive_mutex> callbacks_;
std::atomic_int64_t current_task_id_ = 0; std::atomic_int64_t current_task_id_ = 0;
void add_endon_condition(const task_handle& handle, const element* element, const std::string& event); void add_endon_condition(const task_handle& handle, const std::string& event);
void remove(const task_handle& handle); void remove(const task_handle& handle);
void merge_callbacks(); void merge_callbacks();

View File

@ -1,66 +0,0 @@
#include <std_include.hpp>
#include "menu.hpp"
#include "lua/engine.hpp"
#include "component/ui_scripting.hpp"
namespace ui_scripting
{
menu::menu()
{
}
void menu::add_child(element* el)
{
this->children.push_back(el);
}
void menu::open()
{
if (this->visible)
{
return;
}
this->cursor_was_enabled = *game::keyCatchers & 0x40;
if (this->cursor)
{
*game::keyCatchers |= 0x40;
}
this->visible = true;
}
void menu::close()
{
if (!this->visible)
{
return;
}
if (this->cursor && !this->cursor_was_enabled)
{
*game::keyCatchers &= ~0x40;
}
this->visible = false;
}
void menu::render()
{
if (this->cursor && !(*game::keyCatchers & 0x40))
{
this->visible = false;
return;
}
for (auto& element : this->children)
{
if (element->hidden)
{
continue;
}
element->render();
}
}
}

View File

@ -1,35 +0,0 @@
#pragma once
#include "game/game.hpp"
#include "element.hpp"
namespace ui_scripting
{
enum menu_type
{
normal,
overlay
};
class menu final
{
public:
menu();
bool visible = false;
bool hidden = false;
bool cursor = false;
bool ignoreevents = false;
bool cursor_was_enabled = false;
void open();
void close();
void add_child(element* el);
void render();
menu_type type = normal;
std::string overlay_menu;
std::vector<element*> children{};
};
}

View File

@ -17,10 +17,8 @@
#define MENU_MAIN 310 #define MENU_MAIN 310
#define TLS_DLL 311 #define TLS_DLL 311
#define RUNNER 312
#define ICON_IMAGE 313 #define ICON_IMAGE 312
#define LUA_ANIMATION_SCRIPT 314 #define LUA_JSON_SCRIPT 313
#define LUA_JSON_SCRIPT 315 #define LUI_UPDATER_MENU 314
#define LUI_UPDATER_MENU 316

View File

@ -97,9 +97,7 @@ ID_ICON ICON "resources/icon.ico"
MENU_MAIN RCDATA "resources/main.html" MENU_MAIN RCDATA "resources/main.html"
LUA_ANIMATION_SCRIPT RCDATA "resources/animation.lua"
LUA_JSON_SCRIPT RCDATA "resources/json.lua" LUA_JSON_SCRIPT RCDATA "resources/json.lua"
LUI_UPDATER_MENU RCDATA "resources/updater.lua" LUI_UPDATER_MENU RCDATA "resources/updater.lua"
#ifdef _DEBUG #ifdef _DEBUG
@ -108,12 +106,6 @@ TLS_DLL RCDATA "../../build/bin/x64/Debug/tlsdll.dll"
TLS_DLL RCDATA "../../build/bin/x64/Release/tlsdll.dll" TLS_DLL RCDATA "../../build/bin/x64/Release/tlsdll.dll"
#endif #endif
#ifdef _DEBUG
RUNNER RCDATA "../../build/bin/x64/Debug/runner.exe"
#else
RUNNER RCDATA "../../build/bin/x64/Release/runner.exe"
#endif
ICON_IMAGE RCDATA "resources/icon.png" ICON_IMAGE RCDATA "resources/icon.png"
#endif // English (United States) resources #endif // English (United States) resources

View File

@ -1,92 +0,0 @@
function element:animate(name, state, animationtime)
local start = {
x = self.x,
y = self.y,
w = self.w,
h = self.h,
color = self.color,
backcolor = self.backcolor,
bordercolor = self.bordercolor,
borderwidth = self.borderwidth,
fontsize = self.fontsize
}
local _end = {}
for k, v in pairs(start) do
_end[k] = state[k] or v
end
local diffs = {}
for k, v in pairs(_end) do
if (type(v) == "table") then
local value = {}
local different = false
for _k, _v in pairs(v) do
value[_k] = _v - start[k][_k]
if (value[_k] ~= 0) then
different = true
end
end
if (different) then
diffs[k] = value
end
else
local value = v - start[k]
if (value ~= 0) then
diffs[k] = v - start[k]
end
end
end
local timeout = nil
local interval = nil
local starttime = game:time()
interval = game:onframe(function()
local time = game:time()
local percentage = (time - starttime) / animationtime
if (percentage >= 1) then
for k, v in pairs(diffs) do
self[k] = _end[k]
end
else
for k, v in pairs(diffs) do
if (type(v) == "table") then
local value = {}
for _k, _v in pairs(v) do
value[_k] = start[k][_k] + _v * percentage
end
self[k] = value
else
self[k] = start[k] + v * percentage
end
end
end
end)
timeout = game:ontimeout(function()
interval:clear()
for k, v in pairs(diffs) do
self[k] = _end[k]
end
end, animationtime)
self:onnotifyonce("cancel_animation", function(_name)
if (name == _name) then
timeout:clear()
interval:clear()
end
end)
end
function element:cancelanimations(name, callback)
self:notify("cancel_animation", name)
if (type(callback) == "function") then
game:ontimeout(callback, 0)
end
end

View File

@ -10,6 +10,7 @@
#pragma warning(disable: 4702) #pragma warning(disable: 4702)
#pragma warning(disable: 4996) #pragma warning(disable: 4996)
#pragma warning(disable: 5054) #pragma warning(disable: 5054)
#pragma warning(disable: 5056)
#pragma warning(disable: 6011) #pragma warning(disable: 6011)
#pragma warning(disable: 6297) #pragma warning(disable: 6297)
#pragma warning(disable: 6385) #pragma warning(disable: 6385)

View File

@ -10,19 +10,25 @@ namespace utils::http
{ {
struct progress_helper struct progress_helper
{ {
const std::function<void(size_t)>* callback{}; const std::function<void(size_t, size_t, size_t)>* callback{};
std::exception_ptr exception{}; std::exception_ptr exception{};
std::chrono::high_resolution_clock::time_point start{};
}; };
int progress_callback(void *clientp, const curl_off_t /*dltotal*/, const curl_off_t dlnow, const curl_off_t /*ultotal*/, const curl_off_t /*ulnow*/) int progress_callback(void *clientp, const curl_off_t dltotal, const curl_off_t dlnow, const curl_off_t /*ultotal*/, const curl_off_t /*ulnow*/)
{ {
auto* helper = static_cast<progress_helper*>(clientp); auto* helper = static_cast<progress_helper*>(clientp);
try try
{ {
const auto now = std::chrono::high_resolution_clock::now();
const auto count = std::chrono::duration_cast<
std::chrono::milliseconds>(now - helper->start).count();
const auto speed = dlnow / count;
if (*helper->callback) if (*helper->callback)
{ {
(*helper->callback)(dlnow); (*helper->callback)(dlnow, dltotal, speed);
} }
} }
catch(...) catch(...)
@ -44,7 +50,8 @@ namespace utils::http
} }
} }
std::optional<std::string> get_data(const std::string& url, const headers& headers, const std::function<void(size_t)>& callback) std::optional<std::string> get_data(const std::string& url, const headers& headers,
const std::function<void(size_t, size_t, size_t)>& callback)
{ {
curl_slist* header_list = nullptr; curl_slist* header_list = nullptr;
auto* curl = curl_easy_init(); auto* curl = curl_easy_init();
@ -68,6 +75,7 @@ namespace utils::http
std::string buffer{}; std::string buffer{};
progress_helper helper{}; progress_helper helper{};
helper.callback = &callback; helper.callback = &callback;
helper.start = std::chrono::high_resolution_clock::now();
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
curl_easy_setopt(curl, CURLOPT_URL, url.data()); curl_easy_setopt(curl, CURLOPT_URL, url.data());
@ -82,7 +90,7 @@ namespace utils::http
return {std::move(buffer)}; return {std::move(buffer)};
} }
if(helper.exception) if (helper.exception)
{ {
std::rethrow_exception(helper.exception); std::rethrow_exception(helper.exception);
} }

View File

@ -8,6 +8,7 @@ namespace utils::http
{ {
using headers = std::unordered_map<std::string, std::string>; using headers = std::unordered_map<std::string, std::string>;
std::optional<std::string> get_data(const std::string& url, const headers& headers = {}, const std::function<void(size_t)>& callback = {}); std::optional<std::string> get_data(const std::string& url, const headers& headers = {},
const std::function<void(size_t, size_t, size_t)>& callback = {});
std::future<std::optional<std::string>> get_data_async(const std::string& url, const headers& headers = {}); std::future<std::optional<std::string>> get_data_async(const std::string& url, const headers& headers = {});
} }

View File

@ -1,95 +0,0 @@
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "debugger.hpp"
namespace
{
bool acquire_debug_privilege()
{
TOKEN_PRIVILEGES token_privileges;
ZeroMemory(&token_privileges, sizeof(token_privileges));
token_privileges.PrivilegeCount = 1;
HANDLE token;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token))
{
return false;
}
if (!LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &token_privileges.Privileges[0].Luid))
{
CloseHandle(token);
return false;
}
token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
DWORD size;
if (!AdjustTokenPrivileges(token, FALSE, &token_privileges, 0, nullptr, &size))
{
CloseHandle(token);
return false;
}
return CloseHandle(token) != FALSE;
}
}
debugger::debugger(const unsigned long process_id, const bool start)
{
if (!start)
{
return;
}
this->runner_ = std::thread([this, process_id]()
{
this->terminate_ = false;
this->run(process_id);
});
}
debugger::~debugger()
{
this->terminate_ = true;
if (this->runner_.joinable())
{
this->runner_.join();
}
}
void debugger::run(const unsigned long process_id) const
{
acquire_debug_privilege();
if (!DebugActiveProcess(process_id))
{
return;
}
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
DEBUG_EVENT event;
while (!this->terminate_ && WaitForDebugEvent(&event,INFINITE))
{
if (event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
{
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
continue;
}
if (event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
{
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
break;
}
#ifdef DEV_BUILD
if (event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
{
OutputDebugStringA("Debugger attached!\n");
}
#endif
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
}
}

View File

@ -1,15 +0,0 @@
#pragma once
#include <thread>
class debugger
{
public:
debugger(unsigned long process_id, bool start);
~debugger();
private:
volatile bool terminate_ = false;
std::thread runner_;
void run(unsigned long process_id) const;
};

View File

@ -1,100 +0,0 @@
// Microsoft Visual C++ generated resource script.
//
#pragma code_page(65001)
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"#include ""windows.h""\r\n"
"\0"
END
2 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "X Labs"
VALUE "FileDescription", "Steam mod runner"
VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", "Runner"
VALUE "LegalCopyright", "All rights reserved."
VALUE "OriginalFilename", "runner.exe"
VALUE "ProductName", "runner"
VALUE "ProductVersion", "1.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Binary Data
//
102 ICON "../client/resources/icon.ico"
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -1,26 +0,0 @@
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <cstdlib>
#include "debugger.hpp"
int __stdcall WinMain(HINSTANCE, HINSTANCE, PSTR, int)
{
const auto* const command = "-proc ";
const char* parent_proc = strstr(GetCommandLineA(), command);
if (parent_proc)
{
const auto pid = DWORD(atoi(parent_proc + strlen(command)));
auto* const process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid);
if (process_handle)
{
//debugger _(pid, strstr(GetCommandLineA(), "-debug ") != nullptr);
WaitForSingleObject(process_handle, INFINITE);
CloseHandle(process_handle);
return 0;
}
}
return 1;
}

Binary file not shown.