diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index 9272683b..527d4315 100644 --- a/src/client/component/ui_scripting.cpp +++ b/src/client/component/ui_scripting.cpp @@ -16,6 +16,7 @@ #include "game/ui_scripting/lua/engine.hpp" #include "game/ui_scripting/execution.hpp" +#include "game/ui_scripting/lua/error.hpp" #include #include @@ -136,6 +137,7 @@ namespace ui_scripting } const auto results = function(sol::as_args(converted_args)); + lua::handle_error(results); for (const auto& result : results) { @@ -206,10 +208,7 @@ namespace ui_scripting command::add("reloadmenus", []() { - scheduler::once([]() - { - ui_scripting::lua::engine::start(); - }, scheduler::pipeline::renderer); + scheduler::once(ui_scripting::lua::engine::start, scheduler::pipeline::renderer); }); command::add("openluamenu", [](const command::params& params) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index da50796a..055dcc72 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -156,6 +156,7 @@ namespace game WEAK symbol hks_obj_getmetatable{0x2DA210}; WEAK symbol hks_obj_getfield{0x2D9E20}; WEAK symbol hks_obj_settable{0x2DB040}; + WEAK symbol hks_obj_gettable{0x2DA300}; WEAK symbol vm_call_internal{0x30AB60}; WEAK symbol hksi_lua_pushvalue{0x2DE040}; WEAK symbol Hashtable_Create{0x2C8290}; @@ -163,5 +164,7 @@ namespace game WEAK symbol hks_obj_next{0x2DA850}; WEAK symbol cclosure_Create{0x2C84B0}; + WEAK symbol hksi_luaL_ref{0x2E4520}; + WEAK symbol hksi_luaL_unref{0x2DCE50}; } } \ No newline at end of file diff --git a/src/client/game/ui_scripting/element.hpp b/src/client/game/ui_scripting/element.hpp index 737c3104..539b418b 100644 --- a/src/client/game/ui_scripting/element.hpp +++ b/src/client/game/ui_scripting/element.hpp @@ -1,6 +1,6 @@ #pragma once #include "game/game.hpp" -#include "value.hpp" +#include "script_value.hpp" namespace ui_scripting { @@ -76,7 +76,7 @@ namespace ui_scripting alignment horzalign = alignment::start; alignment vertalign = alignment::start; - std::unordered_map attributes = {}; + std::unordered_map attributes = {}; std::string font = "default"; std::string material = "white"; std::string border_material = "white"; diff --git a/src/client/game/ui_scripting/event.hpp b/src/client/game/ui_scripting/event.hpp index ae94311a..4655ea77 100644 --- a/src/client/game/ui_scripting/event.hpp +++ b/src/client/game/ui_scripting/event.hpp @@ -1,5 +1,5 @@ #pragma once -#include "value.hpp" +#include "script_value.hpp" namespace ui_scripting { diff --git a/src/client/game/ui_scripting/execution.cpp b/src/client/game/ui_scripting/execution.cpp index 158b4c62..b03604a4 100644 --- a/src/client/game/ui_scripting/execution.cpp +++ b/src/client/game/ui_scripting/execution.cpp @@ -7,7 +7,7 @@ namespace ui_scripting { - void push_value(const value& value) + void push_value(const script_value& value) { const auto state = *game::hks::lua_state; const auto value_ = value.get_raw(); @@ -15,7 +15,7 @@ namespace ui_scripting state->m_apistack.top++; } - value get_return_value(int offset) + script_value get_return_value(int offset) { const auto state = *game::hks::lua_state; return state->m_apistack.top[-1 - offset]; @@ -23,7 +23,7 @@ namespace ui_scripting arguments get_return_values(int count) { - std::vector values; + arguments values; for (auto i = count - 1; i >= 0; i--) { @@ -49,11 +49,8 @@ namespace ui_scripting push_value(*i); } + const auto _1 = gsl::finally(&disable_error_hook); enable_error_hook(); - const auto __ = gsl::finally([]() - { - disable_error_hook(); - }); try { @@ -67,18 +64,15 @@ namespace ui_scripting } } - value get_field(const userdata& self, const value& key) + script_value get_field(const userdata& self, const script_value& key) { const auto state = *game::hks::lua_state; stack_isolation _; push_value(key); + const auto _1 = gsl::finally(&disable_error_hook); enable_error_hook(); - const auto __ = gsl::finally([]() - { - disable_error_hook(); - }); game::hks::HksObject value{}; game::hks::HksObject userdata{}; @@ -87,7 +81,7 @@ namespace ui_scripting try { - game::hks::hks_obj_getfield(&value, state, &userdata, &state->m_apistack.top[-1]); + game::hks::hks_obj_gettable(&value, state, &userdata, &state->m_apistack.top[-1]); return value; } catch (const std::exception& e) @@ -96,18 +90,15 @@ namespace ui_scripting } } - value get_field(const table& self, const value& key) + script_value get_field(const table& self, const script_value& key) { const auto state = *game::hks::lua_state; stack_isolation _; push_value(key); + const auto _1 = gsl::finally(&disable_error_hook); enable_error_hook(); - const auto __ = gsl::finally([]() - { - disable_error_hook(); - }); game::hks::HksObject value{}; game::hks::HksObject userdata{}; @@ -116,7 +107,7 @@ namespace ui_scripting try { - game::hks::hks_obj_getfield(&value, state, &userdata, &state->m_apistack.top[-1]); + game::hks::hks_obj_gettable(&value, state, &userdata, &state->m_apistack.top[-1]); return value; } catch (const std::exception& e) @@ -125,17 +116,14 @@ namespace ui_scripting } } - void set_field(const userdata& self, const value& key, const value& value) + void set_field(const userdata& self, const script_value& key, const script_value& value) { const auto state = *game::hks::lua_state; stack_isolation _; + const auto _1 = gsl::finally(&disable_error_hook); enable_error_hook(); - const auto __ = gsl::finally([]() - { - disable_error_hook(); - }); game::hks::HksObject userdata{}; userdata.t = game::hks::TUSERDATA; @@ -151,17 +139,14 @@ namespace ui_scripting } } - void set_field(const table& self, const value& key, const value& value) + void set_field(const table& self, const script_value& key, const script_value& value) { const auto state = *game::hks::lua_state; stack_isolation _; + const auto _1 = gsl::finally(&disable_error_hook); enable_error_hook(); - const auto __ = gsl::finally([]() - { - disable_error_hook(); - }); game::hks::HksObject userdata{}; userdata.t = game::hks::TTABLE; diff --git a/src/client/game/ui_scripting/execution.hpp b/src/client/game/ui_scripting/execution.hpp index 3a85ff2b..1ec7c8bf 100644 --- a/src/client/game/ui_scripting/execution.hpp +++ b/src/client/game/ui_scripting/execution.hpp @@ -1,20 +1,20 @@ #pragma once #include "game/game.hpp" #include "types.hpp" -#include "value.hpp" +#include "script_value.hpp" namespace ui_scripting { - void push_value(const value& value); - value get_return_value(int offset); + void push_value(const script_value& value); + script_value get_return_value(int offset); arguments get_return_values(int count); arguments call_script_function(const function& function, const arguments& arguments); - value get_field(const userdata& self, const value& key); - value get_field(const table& self, const value& key); - void set_field(const userdata& self, const value& key, const value& value); - void set_field(const table& self, const value& key, const value& value); + script_value get_field(const userdata& self, const script_value& key); + script_value get_field(const table& self, const script_value& key); + void set_field(const userdata& self, const script_value& key, const script_value& value); + void set_field(const table& self, const script_value& key, const script_value& value); arguments call_method(const userdata& self, const std::string& name, const arguments& arguments); arguments call(const std::string& name, const arguments& arguments); diff --git a/src/client/game/ui_scripting/lua/context.cpp b/src/client/game/ui_scripting/lua/context.cpp index 88f75bd7..3c3c5503 100644 --- a/src/client/game/ui_scripting/lua/context.cpp +++ b/src/client/game/ui_scripting/lua/context.cpp @@ -3,7 +3,7 @@ #include "error.hpp" #include "value_conversion.hpp" #include "../../scripting/execution.hpp" -#include "../value.hpp" +#include "../script_value.hpp" #include "../execution.hpp" #include "../../../component/ui_scripting.hpp" @@ -1008,6 +1008,17 @@ namespace ui_scripting::lua auto userdata_type = state.new_usertype("userdata_"); + userdata_type["new"] = sol::property( + [](const userdata& userdata, const sol::this_state s) + { + return convert(s, userdata.get("new")); + }, + [](const userdata& userdata, const sol::this_state s, const sol::lua_value& value) + { + userdata.set("new", convert({s, value})); + } + ); + for (const auto method : methods) { const auto name = method.first; @@ -1047,6 +1058,17 @@ namespace ui_scripting::lua auto table_type = state.new_usertype("table_"); + table_type["new"] = sol::property( + [](const table& table, const sol::this_state s) + { + return convert(s, table.get("new")); + }, + [](const table& table, const sol::this_state s, const sol::lua_value& value) + { + table.set("new", convert({s, value})); + } + ); + table_type["get"] = [](const table& table, const sol::this_state s, const std::string& name) { diff --git a/src/client/game/ui_scripting/lua/value_conversion.cpp b/src/client/game/ui_scripting/lua/value_conversion.cpp index ce9d9d6b..48392552 100644 --- a/src/client/game/ui_scripting/lua/value_conversion.cpp +++ b/src/client/game/ui_scripting/lua/value_conversion.cpp @@ -20,7 +20,7 @@ namespace ui_scripting::lua return res; } - value convert_function(const sol::protected_function& function) + script_value convert_function(const sol::protected_function& function) { const auto closure = game::hks::cclosure_Create(*game::hks::lua_state, main_function_handler, 0, 0, 0); add_converted_function(closure, function); @@ -33,8 +33,13 @@ namespace ui_scripting::lua } } - value convert(const sol::lua_value& value) + script_value convert(const sol::lua_value& value) { + if (value.is()) + { + return {value.as()}; + } + if (value.is()) { return {value.as()}; @@ -45,11 +50,6 @@ namespace ui_scripting::lua return {value.as()}; } - if (value.is()) - { - return {value.as()}; - } - if (value.is()) { return {value.as()}; @@ -98,7 +98,7 @@ namespace ui_scripting::lua return {}; } - sol::lua_value convert(lua_State* state, const value& value) + sol::lua_value convert(lua_State* state, const script_value& value) { if (value.is()) { @@ -110,6 +110,11 @@ namespace ui_scripting::lua return {state, value.as()}; } + if (value.is()) + { + return {state, value.as()}; + } + if (value.is()) { return {state, value.as()}; diff --git a/src/client/game/ui_scripting/lua/value_conversion.hpp b/src/client/game/ui_scripting/lua/value_conversion.hpp index 83328935..21a67e33 100644 --- a/src/client/game/ui_scripting/lua/value_conversion.hpp +++ b/src/client/game/ui_scripting/lua/value_conversion.hpp @@ -1,9 +1,9 @@ #pragma once - #include "context.hpp" +#include "../script_value.hpp" namespace ui_scripting::lua { - value convert(const sol::lua_value& value); - sol::lua_value convert(lua_State* state, const value& value); + script_value convert(const sol::lua_value& value); + sol::lua_value convert(lua_State* state, const script_value& value); } diff --git a/src/client/game/ui_scripting/value.cpp b/src/client/game/ui_scripting/script_value.cpp similarity index 64% rename from src/client/game/ui_scripting/value.cpp rename to src/client/game/ui_scripting/script_value.cpp index d48d12e9..88edfa0e 100644 --- a/src/client/game/ui_scripting/value.cpp +++ b/src/client/game/ui_scripting/script_value.cpp @@ -2,7 +2,7 @@ #include "execution.hpp" #include "types.hpp" #include "stack_isolation.hpp" -#include "value.hpp" +#include "script_value.hpp" namespace ui_scripting { @@ -10,12 +10,12 @@ namespace ui_scripting * Constructors **************************************************************/ - value::value(const game::hks::HksObject& value) + script_value::script_value(const game::hks::HksObject& value) : value_(value) { } - value::value(const int value) + script_value::script_value(const int value) { game::hks::HksObject obj{}; obj.t = game::hks::TNUMBER; @@ -24,7 +24,7 @@ namespace ui_scripting this->value_ = obj; } - value::value(const unsigned int value) + script_value::script_value(const unsigned int value) { game::hks::HksObject obj{}; obj.t = game::hks::TNUMBER; @@ -33,12 +33,16 @@ namespace ui_scripting this->value_ = obj; } - value::value(const bool value) - : value(static_cast(value)) + script_value::script_value(const bool value) { + game::hks::HksObject obj{}; + obj.t = game::hks::TBOOLEAN; + obj.v.boolean = value; + + this->value_ = obj; } - value::value(const float value) + script_value::script_value(const float value) { game::hks::HksObject obj{}; obj.t = game::hks::TNUMBER; @@ -47,12 +51,12 @@ namespace ui_scripting this->value_ = obj; } - value::value(const double value) - : value(static_cast(value)) + script_value::script_value(const double value) + : script_value(static_cast(value)) { } - value::value(const char* value) + script_value::script_value(const char* value) { game::hks::HksObject obj{}; stack_isolation _; @@ -64,30 +68,30 @@ namespace ui_scripting this->value_ = obj; } - value::value(const std::string& value) - : value(value.data()) + script_value::script_value(const std::string& value) + : script_value(value.data()) { } - value::value(const lightuserdata& value) + script_value::script_value(const lightuserdata& value) { this->value_.t = game::hks::TLIGHTUSERDATA; this->value_.v.ptr = value.ptr; } - value::value(const userdata& value) + script_value::script_value(const userdata& value) { this->value_.t = game::hks::TUSERDATA; this->value_.v.ptr = value.ptr; } - value::value(const table& value) + script_value::script_value(const table& value) { this->value_.t = game::hks::TTABLE; this->value_.v.ptr = value.ptr; } - value::value(const function& value) + script_value::script_value(const function& value) { this->value_.t = value.type; this->value_.v.ptr = value.ptr; @@ -98,39 +102,44 @@ namespace ui_scripting **************************************************************/ template <> - bool value::is() const + bool script_value::is() const { - return this->get_raw().t == game::hks::TNUMBER; + const auto number = this->get_raw().v.number; + return this->get_raw().t == game::hks::TNUMBER && static_cast(number) == number; } template <> - bool value::is() const + bool script_value::is() const { return this->is(); } template <> - bool value::is() const - { - return this->is(); - } - - template <> - int value::get() const + int script_value::get() const { return static_cast(this->get_raw().v.number); } template <> - unsigned int value::get() const + unsigned int script_value::get() const { return static_cast(this->get_raw().v.number); } + /*************************************************************** + * Boolean + **************************************************************/ + template <> - bool value::get() const + bool script_value::is() const { - return this->get_raw().v.native != 0; + return this->get_raw().t == game::hks::TBOOLEAN; + } + + template <> + bool script_value::get() const + { + return this->get_raw().v.boolean; } /*************************************************************** @@ -138,25 +147,25 @@ namespace ui_scripting **************************************************************/ template <> - bool value::is() const + bool script_value::is() const { return this->get_raw().t == game::hks::TNUMBER; } template <> - bool value::is() const + bool script_value::is() const { return this->is(); } template <> - float value::get() const + float script_value::get() const { return this->get_raw().v.number; } template <> - double value::get() const + double script_value::get() const { return static_cast(this->get_raw().v.number); } @@ -166,30 +175,104 @@ namespace ui_scripting **************************************************************/ template <> - bool value::is() const + bool script_value::is() const { return this->get_raw().t == game::hks::TSTRING; } template <> - bool value::is() const + bool script_value::is() const { return this->is(); } template <> - const char* value::get() const + const char* script_value::get() const { return this->get_raw().v.str->m_data; } template <> - std::string value::get() const + std::string script_value::get() const { return this->get(); } - bool value::operator==(const value& other) + /*************************************************************** + * Lightuserdata + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().t == game::hks::TLIGHTUSERDATA; + } + + template <> + lightuserdata script_value::get() const + { + return this->get_raw().v.ptr; + } + + /*************************************************************** + * Userdata + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().t == game::hks::TUSERDATA; + } + + template <> + userdata script_value::get() const + { + return this->get_raw().v.ptr; + } + + /*************************************************************** + * Table + **************************************************************/ + + template <> + bool script_value::is
() const + { + return this->get_raw().t == game::hks::TTABLE; + } + + template <> + table script_value::get() const + { + return this->get_raw().v.table; + } + + /*************************************************************** + * Function + **************************************************************/ + + template <> + bool script_value::is() const + { + return this->get_raw().t == game::hks::TIFUNCTION + || this->get_raw().t == game::hks::TCFUNCTION; + } + + template <> + function script_value::get() const + { + return { this->get_raw().v.cClosure, this->get_raw().t }; + } + + /*************************************************************** + * + **************************************************************/ + + const game::hks::HksObject& script_value::get_raw() const + { + return this->value_; + } + + bool script_value::operator==(const script_value& other) { if (this->get_raw().t != other.get_raw().t) { @@ -203,78 +286,4 @@ namespace ui_scripting return this->get_raw().v.native == other.get_raw().v.native; } - - /*************************************************************** - * Lightuserdata - **************************************************************/ - - template <> - bool value::is() const - { - return this->get_raw().t == game::hks::TLIGHTUSERDATA; - } - - template <> - lightuserdata value::get() const - { - return this->get_raw().v.ptr; - } - - /*************************************************************** - * Userdata - **************************************************************/ - - template <> - bool value::is() const - { - return this->get_raw().t == game::hks::TUSERDATA; - } - - template <> - userdata value::get() const - { - return this->get_raw().v.ptr; - } - - /*************************************************************** - * Table - **************************************************************/ - - template <> - bool value::is
() const - { - return this->get_raw().t == game::hks::TTABLE; - } - - template <> - table value::get() const - { - return this->get_raw().v.table; - } - - /*************************************************************** - * Function - **************************************************************/ - - template <> - bool value::is() const - { - return this->get_raw().t == game::hks::TIFUNCTION - || this->get_raw().t == game::hks::TCFUNCTION; - } - - template <> - function value::get() const - { - return {this->get_raw().v.cClosure, this->get_raw().t}; - } - - /*************************************************************** - * - **************************************************************/ - - const game::hks::HksObject& value::get_raw() const - { - return this->value_; - } } diff --git a/src/client/game/ui_scripting/script_value.hpp b/src/client/game/ui_scripting/script_value.hpp new file mode 100644 index 00000000..b1495848 --- /dev/null +++ b/src/client/game/ui_scripting/script_value.hpp @@ -0,0 +1,58 @@ +#pragma once +#include "game/game.hpp" + +namespace ui_scripting +{ + class lightuserdata; + class userdata; + class table; + class function; + + class script_value + { + public: + script_value() = default; + script_value(const game::hks::HksObject& value); + + script_value(int value); + script_value(unsigned int value); + script_value(bool value); + + script_value(float value); + script_value(double value); + + script_value(const char* value); + script_value(const std::string& value); + + script_value(const lightuserdata& value); + script_value(const userdata& value); + script_value(const table& value); + script_value(const function& value); + + bool operator==(const script_value& other); + + template + bool is() const; + + template + T as() const + { + if (!this->is()) + { + throw std::runtime_error("Invalid type"); + } + + return get(); + } + + const game::hks::HksObject& get_raw() const; + + private: + template + T get() const; + + game::hks::HksObject value_{}; + }; + + using arguments = std::vector; +} diff --git a/src/client/game/ui_scripting/stack_isolation.cpp b/src/client/game/ui_scripting/stack_isolation.cpp index 473d8098..d50dd355 100644 --- a/src/client/game/ui_scripting/stack_isolation.cpp +++ b/src/client/game/ui_scripting/stack_isolation.cpp @@ -6,25 +6,6 @@ namespace ui_scripting stack_isolation::stack_isolation() { const auto state = *game::hks::lua_state; - - this->top_ = state->m_apistack.top; - this->base_ = state->m_apistack.base; - this->alloc_top_ = state->m_apistack.alloc_top; - this->bottom_ = state->m_apistack.bottom; - - state->m_apistack.top = this->stack_; - state->m_apistack.base = state->m_apistack.top; - state->m_apistack.alloc_top = &this->stack_[ARRAYSIZE(this->stack_) - 1]; - state->m_apistack.bottom = state->m_apistack.top; - } - - stack_isolation::~stack_isolation() - { - const auto state = *game::hks::lua_state; - - state->m_apistack.top = this->top_; - state->m_apistack.base = this->base_; - state->m_apistack.alloc_top = this->alloc_top_; - state->m_apistack.bottom = this->bottom_; + state->m_apistack.top = state->m_apistack.base; } } diff --git a/src/client/game/ui_scripting/stack_isolation.hpp b/src/client/game/ui_scripting/stack_isolation.hpp index 035e8d54..f13a7129 100644 --- a/src/client/game/ui_scripting/stack_isolation.hpp +++ b/src/client/game/ui_scripting/stack_isolation.hpp @@ -7,19 +7,10 @@ namespace ui_scripting { public: stack_isolation(); - ~stack_isolation(); - stack_isolation(stack_isolation&&) = delete; stack_isolation(const stack_isolation&) = delete; stack_isolation& operator=(stack_isolation&&) = delete; stack_isolation& operator=(const stack_isolation&) = delete; - private: - game::hks::HksObject stack_[512]{}; - - game::hks::HksObject* top_; - game::hks::HksObject* base_; - game::hks::HksObject* alloc_top_; - game::hks::HksObject* bottom_; }; } diff --git a/src/client/game/ui_scripting/types.cpp b/src/client/game/ui_scripting/types.cpp index e9ab451c..daaf0010 100644 --- a/src/client/game/ui_scripting/types.cpp +++ b/src/client/game/ui_scripting/types.cpp @@ -1,6 +1,7 @@ #include #include "types.hpp" #include "execution.hpp" +#include "stack_isolation.hpp" namespace ui_scripting { @@ -22,21 +23,16 @@ namespace ui_scripting { } - void userdata::set(const value& key, const value& value) const + void userdata::set(const script_value& key, const script_value& value) const { set_field(*this, key, value); } - value userdata::get(const value& key) const + script_value userdata::get(const script_value& key) const { return get_field(*this, key); } - arguments userdata::call(const std::string& name, const arguments& arguments) const - { - return call_method(this->ptr, name, arguments); - } - /*************************************************************** * Table **************************************************************/ @@ -45,19 +41,83 @@ namespace ui_scripting { const auto state = *game::hks::lua_state; this->ptr = game::hks::Hashtable_Create(state, 0, 0); + this->add(); } table::table(game::hks::HashTable* ptr_) : ptr(ptr_) { + this->add(); } - void table::set(const value& key, const value& value) const + table::table(const table& other) : table(other.ptr) + { + } + + table::table(table&& other) noexcept + { + this->ptr = other.ptr; + this->ref = other.ref; + other.ref = 0; + } + + table::~table() + { + this->release(); + } + + table& table::operator=(const table& other) + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->ref = other.ref; + this->add(); + } + + return *this; + } + + table& table::operator=(table&& other) noexcept + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->ref = other.ref; + other.ref = 0; + } + + return *this; + } + + void table::add() + { + game::hks::HksObject value{}; + value.v.table = this->ptr; + value.t = game::hks::TTABLE; + + stack_isolation _; + push_value(value); + + this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000); + } + + void table::release() + { + if (this->ref) + { + game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref); + } + } + + void table::set(const script_value& key, const script_value& value) const { set_field(*this, key, value); } - value table::get(const value& key) const + script_value table::get(const script_value& key) const { return get_field(*this, key); } @@ -70,6 +130,72 @@ namespace ui_scripting : ptr(ptr_) , type(type_) { + this->add(); + } + + function::function(const function& other) : function(other.ptr, other.type) + { + } + + function::function(function&& other) noexcept + { + this->ptr = other.ptr; + this->type = other.type; + this->ref = other.ref; + other.ref = 0; + } + + function::~function() + { + this->release(); + } + + function& function::operator=(const function& other) + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->type = other.type; + this->ref = other.ref; + this->add(); + } + + return *this; + } + + function& function::operator=(function&& other) noexcept + { + if (&other != this) + { + this->release(); + this->ptr = other.ptr; + this->type = other.type; + this->ref = other.ref; + other.ref = 0; + } + + return *this; + } + + void function::add() + { + game::hks::HksObject value{}; + value.v.cClosure = this->ptr; + value.t = this->type; + + stack_isolation _; + push_value(value); + + this->ref = game::hks::hksi_luaL_ref(*game::hks::lua_state, -10000); + } + + void function::release() + { + if (this->ref) + { + game::hks::hksi_luaL_unref(*game::hks::lua_state, -10000, this->ref); + } } arguments function::call(const arguments& arguments) const diff --git a/src/client/game/ui_scripting/types.hpp b/src/client/game/ui_scripting/types.hpp index 0e2590ca..330c0be6 100644 --- a/src/client/game/ui_scripting/types.hpp +++ b/src/client/game/ui_scripting/types.hpp @@ -1,6 +1,6 @@ #pragma once #include "game/game.hpp" -#include "value.hpp" +#include "script_value.hpp" namespace ui_scripting { @@ -16,9 +16,8 @@ namespace ui_scripting public: userdata(void*); - value get(const value& key) const; - void set(const value& key, const value& value) const; - arguments call(const std::string& name, const arguments& arguments) const; + script_value get(const script_value& key) const; + void set(const script_value& key, const script_value& value) const; void* ptr; }; @@ -29,10 +28,24 @@ namespace ui_scripting table(); table(game::hks::HashTable* ptr_); - value get(const value& key) const; - void set(const value& key, const value& value) const; + table(const table& other); + table(table&& other) noexcept; + + ~table(); + + table& operator=(const table& other); + table& operator=(table&& other) noexcept; + + script_value get(const script_value& key) const; + void set(const script_value& key, const script_value& value) const; game::hks::HashTable* ptr; + + private: + void add(); + void release(); + + int ref; }; class function @@ -40,9 +53,23 @@ namespace ui_scripting public: function(game::hks::cclosure*, game::hks::HksObjectType); + function(const function& other); + function(function&& other) noexcept; + + ~function(); + + function& operator=(const function& other); + function& operator=(function&& other) noexcept; + arguments call(const arguments& arguments) const; game::hks::cclosure* ptr; game::hks::HksObjectType type; + + private: + void add(); + void release(); + + int ref; }; } diff --git a/src/client/game/ui_scripting/value.hpp b/src/client/game/ui_scripting/value.hpp deleted file mode 100644 index 29274c58..00000000 --- a/src/client/game/ui_scripting/value.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace ui_scripting -{ - class lightuserdata; - class userdata; - class table; - class function; - - class value - { - public: - value() = default; - value(const game::hks::HksObject& value); - - value(int value); - value(unsigned int value); - value(bool value); - - value(float value); - value(double value); - - value(const char* value); - value(const std::string& value); - - value(const lightuserdata& value); - value(const userdata& value); - value(const table& value); - value(const function& value); - - bool operator==(const value& other); - - template - bool is() const; - - template - T as() const - { - if (!this->is()) - { - throw std::runtime_error("Invalid type"); - } - - return get(); - } - - const game::hks::HksObject& get_raw() const; - - private: - template - T get() const; - - game::hks::HksObject value_{}; - }; - - using arguments = std::vector; -}