Add lui key events + fixes

This commit is contained in:
Federico Cecchetto 2022-04-05 21:41:02 +02:00
parent 684028bc95
commit 0915c68fd1
5 changed files with 112 additions and 27 deletions

View File

@ -4,6 +4,7 @@
#include "game/game.hpp"
#include "game_console.hpp"
#include "game/ui_scripting/execution.hpp"
#include <utils/hook.hpp>
@ -16,6 +17,12 @@ namespace input
void cl_char_event_stub(const int local_client_num, const int key)
{
ui_scripting::notify("keypress",
{
{"keynum", key},
{"key", game::Key_KeynumToString(key, 0, 1)},
});
if (!game_console::console_char_event(local_client_num, key))
{
return;
@ -26,6 +33,12 @@ namespace input
void cl_key_event_stub(const int local_client_num, const int key, const int down)
{
ui_scripting::notify(down ? "keydown" : "keyup",
{
{"keynum", key},
{"key", game::Key_KeynumToString(key, 0, 1)},
});
if (!game_console::console_key_event(local_client_num, key, down))
{
return;

View File

@ -153,6 +153,8 @@ namespace game
int a3, int a4, unsigned int a5)> LUI_OpenMenu{0x14039D5F0, 0x1404CD210};
WEAK symbol<bool(int clientNum, const char* name, hks::lua_State* s)> LUI_BeginEvent{0x1400D27F0, 0x140161A00};
WEAK symbol<void(hks::lua_State* s)> LUI_EndEvent{0x1400D3A80, 0x140162CD0};
WEAK symbol<void()> LUI_EnterCriticalSection{0x1400D3B70, 0x140162DC0};
WEAK symbol<void()> LUI_LeaveCriticalSection{0x1400D8DB0, 0x140168150};
WEAK symbol<bool(int clientNum, const char* menu)> Menu_IsMenuOpenAndVisible{0x1404709C0, 0x1404C7320};
@ -273,5 +275,6 @@ namespace game
int internal_, int profilerTreatClosureAsFunc)> cclosure_Create{0x14008B5D0, 0x14011B540};
WEAK symbol<int(lua_State* s, int t)> hksi_luaL_ref{0x1400A64D0, 0x140136D30};
WEAK symbol<void(lua_State* s, int t, int ref)> hksi_luaL_unref{0x14009EF10, 0x14012F610};
WEAK symbol<void(lua_State* s, HksObject* lfp)> closePendingUpvalues{0x14008EA00, 0x14011E970};
}
}

View File

@ -40,53 +40,53 @@ namespace ui_scripting
bool notify(const std::string& name, const event_arguments& arguments)
{
const auto state = *game::hks::lua_state;
if (!game::LUI_BeginEvent(0, name.data(), state))
if (!state)
{
return false;
}
const auto _1 = gsl::finally(&disable_error_hook);
enable_error_hook();
const auto _1 = gsl::finally(game::LUI_LeaveCriticalSection);
game::LUI_EnterCriticalSection();
const auto top = state->m_apistack.top;
try
{
const auto event = get_return_value(0).as<table>();
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").as<function>().call({})[0].as<userdata>();
const auto process_event = root.get("processEvent").as<function>();
table event{};
event.set("name", name);
for (const auto& arg : arguments)
{
event.set(arg.first, arg.second);
}
}
catch (...)
{
}
state->m_apistack.top = top;
try
{
game::LUI_EndEvent(state);
process_event.call({root, event});
return true;
}
catch (const std::exception& e)
{
throw std::runtime_error(std::string("Error while processing event: ") + e.what());
printf("Error processing event '%s' %s\n", name.data(), e.what());
return false;
}
return true;
}
arguments call_script_function(const function& function, const arguments& arguments)
{
const auto state = *game::hks::lua_state;
state->m_apistack.top = state->m_apistack.base;
stack stack;
push_value(function);
for (auto i = arguments.begin(); i != arguments.end(); ++i)
{
push_value(*i);
}
const auto num_args = static_cast<int>(arguments.size());
stack.save(num_args + 1);
const auto _1 = gsl::finally(&disable_error_hook);
enable_error_hook();
@ -98,6 +98,7 @@ namespace ui_scripting
}
catch (const std::exception& e)
{
stack.fix();
throw std::runtime_error(std::string("Error executing script function: ") + e.what());
}
}
@ -105,9 +106,10 @@ namespace ui_scripting
script_value get_field(const userdata& self, const script_value& key)
{
const auto state = *game::hks::lua_state;
state->m_apistack.top = state->m_apistack.base;
stack stack;
push_value(key);
stack.save(1);
const auto _1 = gsl::finally(&disable_error_hook);
enable_error_hook();
@ -124,16 +126,18 @@ namespace ui_scripting
}
catch (const std::exception& e)
{
throw std::runtime_error(std::string("Error getting userdata field: ") + e.what());
stack.fix();
throw std::runtime_error("Error getting userdata field: "s + e.what());
}
}
script_value get_field(const table& self, const script_value& key)
{
const auto state = *game::hks::lua_state;
state->m_apistack.top = state->m_apistack.base;
stack stack;
push_value(key);
stack.save(1);
const auto _1 = gsl::finally(&disable_error_hook);
enable_error_hook();
@ -150,14 +154,17 @@ namespace ui_scripting
}
catch (const std::exception& e)
{
throw std::runtime_error(std::string("Error getting table field: ") + e.what());
stack.fix();
throw std::runtime_error("Error getting table field: "s + e.what());
}
}
void set_field(const userdata& self, const script_value& key, const script_value& value)
{
const auto state = *game::hks::lua_state;
state->m_apistack.top = state->m_apistack.base;
stack stack;
stack.save(0);
const auto _1 = gsl::finally(&disable_error_hook);
enable_error_hook();
@ -172,14 +179,17 @@ namespace ui_scripting
}
catch (const std::exception& e)
{
throw std::runtime_error(std::string("Error setting userdata field: ") + e.what());
stack.fix();
throw std::runtime_error("Error setting userdata field: "s + e.what());
}
}
void set_field(const table& self, const script_value& key, const script_value& value)
{
const auto state = *game::hks::lua_state;
state->m_apistack.top = state->m_apistack.base;
stack stack;
stack.save(0);
const auto _1 = gsl::finally(&disable_error_hook);
enable_error_hook();
@ -194,7 +204,8 @@ namespace ui_scripting
}
catch (const std::exception& e)
{
throw std::runtime_error(std::string("Error setting table field: ") + e.what());
stack.fix();
throw std::runtime_error("Error setting table field: "s + e.what());
}
}
}

View File

@ -273,4 +273,38 @@ namespace ui_scripting
{
return call_script_function(*this, arguments);
}
/***************************************************************
* Stack
**************************************************************/
stack::stack()
{
this->state = *game::hks::lua_state;
this->state->m_apistack.top = this->state->m_apistack.base;
}
void stack::save(int num_args)
{
this->num_args_ = num_args;
this->num_calls_ = state->m_numberOfCCalls;
this->base_bottom_ = state->m_apistack.base - state->m_apistack.bottom;
this->top_bottom_ = state->m_apistack.top - state->m_apistack.bottom;
this->callstack_ = state->m_callStack.m_current - state->m_callStack.m_records;
}
void stack::fix()
{
this->state->m_numberOfCCalls = this->num_calls_;
game::hks::closePendingUpvalues(this->state, &this->state->m_apistack.bottom[this->top_bottom_ - this->num_args_]);
this->state->m_callStack.m_current = &this->state->m_callStack.m_records[this->callstack_];
this->state->m_apistack.base = &this->state->m_apistack.bottom[this->base_bottom_];
this->state->m_apistack.top = &this->state->m_apistack.bottom[this->top_bottom_ - static_cast<uint64_t>(this->num_args_ + 1)];
this->state->m_apistack.bottom[this->top_bottom_].t = this->state->m_apistack.top[-1].t;
this->state->m_apistack.bottom[this->top_bottom_].v.ptr = this->state->m_apistack.top[-1].v.ptr;
this->state->m_apistack.top = &this->state->m_apistack.bottom[this->top_bottom_ + 1];
}
}

View File

@ -86,4 +86,28 @@ namespace ui_scripting
int ref{};
};
class stack final
{
public:
stack();
void save(int num_args);
void fix();
stack(stack&&) = delete;
stack(const stack&) = delete;
stack& operator=(stack&&) = delete;
stack& operator=(const stack&) = delete;
private:
game::hks::lua_State* state;
int num_args_;
int num_calls_;
uint64_t base_bottom_;
uint64_t top_bottom_;
uint64_t callstack_;
};
}