diff --git a/src/lua/bindings/command.cpp b/src/lua/bindings/command.cpp new file mode 100644 index 00000000..34b67bff --- /dev/null +++ b/src/lua/bindings/command.cpp @@ -0,0 +1,59 @@ +#pragma once +#include "command.hpp" +#include "backend/command.hpp" +#include "backend/player_command.hpp" +#include "network.hpp" // for convert_sequence + +namespace lua::command +{ + // Lua API: Table + // Name: command + // Table for calling menu commands. + + // Lua API: Function + // Table: command + // Name: call + // Param: command_name: string: The name of the command that will be called. + // Param: _args: table: Optional. List of arguments for the command. + // Call a menu command. + static void call(const std::string& command_name, std::optional _args) + { + const auto args = convert_sequence(_args.value_or(sol::table())); + + const auto command = big::command::get(rage::joaat(command_name)); + + if (command) + command->call(args); + } + + // Lua API: Function + // Table: command + // Name: call_player + // Param: player_idx: integer: Index of the player on which the menu command will be executed. + // Param: command_name: string: The name of the command that will be called. + // Param: _args: table: Optional. List of arguments for the command. + // Call a menu command on a given player. + static void call_player(int player_idx, const std::string& command_name, std::optional _args) + { + const auto args = convert_sequence(_args.value_or(sol::table())); + + const auto command = (big::player_command*)big::command::get(rage::joaat(command_name)); + + if (command) + { + const auto player = big::g_player_service->get_by_id(player_idx); + + if (player) + { + command->call(player, args); + } + } + } + + void bind(sol::state& state) + { + auto ns = state["command"].get_or_create(); + ns["call"] = call; + ns["call_player"] = call_player; + } +} \ No newline at end of file diff --git a/src/lua/bindings/command.hpp b/src/lua/bindings/command.hpp index 49229641..3885716c 100644 --- a/src/lua/bindings/command.hpp +++ b/src/lua/bindings/command.hpp @@ -1,58 +1,7 @@ #pragma once -#include "backend/command.hpp" -#include "backend/player_command.hpp" -#include "network.hpp" // for convert_sequence +#include "lua/sol.hpp" namespace lua::command { - // Lua API: Table - // Name: command - // Table for calling menu commands. - - // Lua API: Function - // Table: command - // Name: call - // Param: command_name: string: The name of the command that will be called. - // Param: _args: table: Optional. List of arguments for the command. - // Call a menu command. - static void call(const std::string& command_name, std::optional _args) - { - const auto args = convert_sequence(_args.value_or(sol::table())); - - const auto command = big::command::get(rage::joaat(command_name)); - - if (command) - command->call(args); - } - - // Lua API: Function - // Table: command - // Name: call_player - // Param: player_idx: integer: Index of the player on which the menu command will be executed. - // Param: command_name: string: The name of the command that will be called. - // Param: _args: table: Optional. List of arguments for the command. - // Call a menu command on a given player. - static void call_player(int player_idx, const std::string& command_name, std::optional _args) - { - const auto args = convert_sequence(_args.value_or(sol::table())); - - const auto command = (big::player_command*)big::command::get(rage::joaat(command_name)); - - if (command) - { - const auto player = big::g_player_service->get_by_id(player_idx); - - if (player) - { - command->call(player, args); - } - } - } - - static void bind(sol::state& state) - { - auto ns = state["command"].get_or_create(); - ns["call"] = call; - ns["call_player"] = call_player; - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/event.cpp b/src/lua/bindings/event.cpp new file mode 100644 index 00000000..fd7c1b7f --- /dev/null +++ b/src/lua/bindings/event.cpp @@ -0,0 +1,116 @@ +#pragma once +#include "event.hpp" +#include "fiber_pool.hpp" +#include "lua/lua_module.hpp" +#include "script_mgr.hpp" + +namespace lua::event +{ + // Lua API: Table + // Name: menu_event + // Table containing all possible events to which you can respond. + + // Lua API: Field + // Table: menu_event + // Field: PlayerLeave: integer + // Event that is triggered when a player leave the game session. + // **Example Usage:** + // ```lua + // event.register_handler(menu_event.PlayerLeave, function (player_name) + // log.info(player_name) + // end) + // ``` + + // Lua API: Field + // Table: menu_event + // Field: PlayerJoin: integer + // Event that is triggered when a player join the game session. + // **Example Usage:** + // ```lua + // event.register_handler(menu_event.PlayerJoin, function (player_name, player_id) + // log.info(player_name) + // log.info(player_id) + // end) + // ``` + + // Lua API: Field + // Table: menu_event + // Field: PlayerMgrInit: integer + // Event that is triggered when the player manager initialize. Usually called when we are joining a session. + // **Example Usage:** + // ```lua + // event.register_handler(menu_event.PlayerMgrInit, function () + // log.info("Player manager inited, we just joined a session.") + // end) + // ``` + + // Lua API: Field + // Table: menu_event + // Field: PlayerMgrShutdown: integer + // Event that is triggered when the player manager shutdown. Usually called when we are leaving a session. + // **Example Usage:** + // ```lua + // event.register_handler(menu_event.PlayerMgrShutdown, function () + // log.info("Player manager inited, we just left a session.") + // end) + // ``` + + // Lua API: Field + // Table: menu_event + // Field: ChatMessageReceived: integer + // Event that is triggered when we receive a in-game chat message. + // **Example Usage:** + // ```lua + // event.register_handler(menu_event.ChatMessageReceived, function (player_id, chat_message) + // log.info(player_id) + // log.info(chat_message) + // end) + // ``` + + // Lua API: Field + // Table: menu_event + // Field: ScriptedGameEventReceived: integer + // Event that is triggered when we receive a scripted game event. + // **Example Usage:** + // ```lua + // event.register_handler(menu_event.ScriptedGameEventReceived, function (player_id, script_event_args) + // log.info(player_id) + // log.info(script_event_args) + // end) + // ``` + + // Lua API: Table + // Name: event + // Table for responding to various events. The list of events is available in the menu_event table. + + // Lua API: Function + // Table: event + // Name: register_handler + // Param: menu_event: menu_event: The menu_event that we want to respond to. + // Param: func: function: The function that will be called. + // Register a function that will be called each time the corresponding menu_event is triggered. + static void register_handler(const menu_event& menu_event, sol::protected_function func, sol::this_state state) + { + const auto module = sol::state_view(state)["!this"].get(); + + module->m_event_callbacks[menu_event].push_back(func); + } + + void bind(sol::state& state) + { + state.new_enum("menu_event", + { + {"PlayerLeave", menu_event::PlayerLeave}, + {"PlayerJoin", menu_event::PlayerJoin}, + {"PlayerMgrInit", menu_event::PlayerMgrInit}, + {"PlayerMgrShutdown", menu_event::PlayerMgrShutdown}, + {"ChatMessageReceived", menu_event::ChatMessageReceived}, + {"ScriptedGameEventReceived", menu_event::ScriptedGameEventReceived}, + }); + + + auto ns = state["event"].get_or_create(); + ns["register_handler"] = register_handler; + // TODO: triggering events through script? + } +} \ No newline at end of file diff --git a/src/lua/bindings/event.hpp b/src/lua/bindings/event.hpp index aaadf970..30cd79a7 100644 --- a/src/lua/bindings/event.hpp +++ b/src/lua/bindings/event.hpp @@ -1,115 +1,7 @@ #pragma once -#include "fiber_pool.hpp" -#include "lua/lua_module.hpp" -#include "script_mgr.hpp" +#include "lua/sol.hpp" namespace lua::event { - // Lua API: Table - // Name: menu_event - // Table containing all possible events to which you can respond. - - // Lua API: Field - // Table: menu_event - // Field: PlayerLeave: integer - // Event that is triggered when a player leave the game session. - // **Example Usage:** - // ```lua - // event.register_handler(menu_event.PlayerLeave, function (player_name) - // log.info(player_name) - // end) - // ``` - - // Lua API: Field - // Table: menu_event - // Field: PlayerJoin: integer - // Event that is triggered when a player join the game session. - // **Example Usage:** - // ```lua - // event.register_handler(menu_event.PlayerJoin, function (player_name, player_id) - // log.info(player_name) - // log.info(player_id) - // end) - // ``` - - // Lua API: Field - // Table: menu_event - // Field: PlayerMgrInit: integer - // Event that is triggered when the player manager initialize. Usually called when we are joining a session. - // **Example Usage:** - // ```lua - // event.register_handler(menu_event.PlayerMgrInit, function () - // log.info("Player manager inited, we just joined a session.") - // end) - // ``` - - // Lua API: Field - // Table: menu_event - // Field: PlayerMgrShutdown: integer - // Event that is triggered when the player manager shutdown. Usually called when we are leaving a session. - // **Example Usage:** - // ```lua - // event.register_handler(menu_event.PlayerMgrShutdown, function () - // log.info("Player manager inited, we just left a session.") - // end) - // ``` - - // Lua API: Field - // Table: menu_event - // Field: ChatMessageReceived: integer - // Event that is triggered when we receive a in-game chat message. - // **Example Usage:** - // ```lua - // event.register_handler(menu_event.ChatMessageReceived, function (player_id, chat_message) - // log.info(player_id) - // log.info(chat_message) - // end) - // ``` - - // Lua API: Field - // Table: menu_event - // Field: ScriptedGameEventReceived: integer - // Event that is triggered when we receive a scripted game event. - // **Example Usage:** - // ```lua - // event.register_handler(menu_event.ScriptedGameEventReceived, function (player_id, script_event_args) - // log.info(player_id) - // log.info(script_event_args) - // end) - // ``` - - // Lua API: Table - // Name: event - // Table for responding to various events. The list of events is available in the menu_event table. - - // Lua API: Function - // Table: event - // Name: register_handler - // Param: menu_event: menu_event: The menu_event that we want to respond to. - // Param: func: function: The function that will be called. - // Register a function that will be called each time the corresponding menu_event is triggered. - static void register_handler(const menu_event& menu_event, sol::protected_function func, sol::this_state state) - { - const auto module = sol::state_view(state)["!this"].get(); - - module->m_event_callbacks[menu_event].push_back(func); - } - - static void bind(sol::state& state) - { - state.new_enum("menu_event", - { - {"PlayerLeave", menu_event::PlayerLeave}, - {"PlayerJoin", menu_event::PlayerJoin}, - {"PlayerMgrInit", menu_event::PlayerMgrInit}, - {"PlayerMgrShutdown", menu_event::PlayerMgrShutdown}, - {"ChatMessageReceived", menu_event::ChatMessageReceived}, - {"ScriptedGameEventReceived", menu_event::ScriptedGameEventReceived}, - }); - - - auto ns = state["event"].get_or_create(); - ns["register_handler"] = register_handler; - // TODO: triggering events through script? - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/global_table.cpp b/src/lua/bindings/global_table.cpp new file mode 100644 index 00000000..a96ea4ef --- /dev/null +++ b/src/lua/bindings/global_table.cpp @@ -0,0 +1,20 @@ +#pragma once +#include "lua/sol.hpp" + +namespace lua::global_table +{ + // Lua API: Table + // Name: Global Table + // Custom fields, functions, etc added to The Lua [Global Table](https://www.lua.org/pil/15.4.html). + + // Lua API: Function + // Table: Global Table + // Name: joaat + // Param: str: string: The string that needs to be joaat hashed. + // Returns: integer: The joaat hashed input string. + + void bind(sol::state& state) + { + state["joaat"] = rage::joaat; + } +} \ No newline at end of file diff --git a/src/lua/bindings/global_table.hpp b/src/lua/bindings/global_table.hpp index 471f7812..3ea3bec6 100644 --- a/src/lua/bindings/global_table.hpp +++ b/src/lua/bindings/global_table.hpp @@ -3,18 +3,5 @@ namespace lua::global_table { - // Lua API: Table - // Name: Global Table - // Custom fields, functions, etc added to The Lua [Global Table](https://www.lua.org/pil/15.4.html). - - // Lua API: Function - // Table: Global Table - // Name: joaat - // Param: str: string: The string that needs to be joaat hashed. - // Returns: integer: The joaat hashed input string. - - static void bind(sol::state& state) - { - state["joaat"] = rage::joaat; - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/globals.cpp b/src/lua/bindings/globals.cpp new file mode 100644 index 00000000..a730ea77 --- /dev/null +++ b/src/lua/bindings/globals.cpp @@ -0,0 +1,124 @@ +#pragma once +#include "globals.hpp" +#include "memory.hpp" +#include "script_global.hpp" + +namespace lua::globals +{ + // Lua API: Table + // Name: globals + // Table containing functions for manipulating gta script globals. + + // Lua API: Function + // Table: globals + // Name: get_int + // Param: global: integer: index of the global + // Returns: integer: value of the global + // Retrieves an int global value. + static int get_int(int global) + { + return *big::script_global(global).as(); + } + + // Lua API: Function + // Table: globals + // Name: get_uint + // Param: global: integer: index of the global + // Returns: integer: value of the global + // Retrieves an uint global value. + static int get_uint(int global) + { + return *big::script_global(global).as(); + } + + // Lua API: Function + // Table: globals + // Name: get_float + // Param: global: integer: index of the global + // Returns: float: value of the global + // Retrieves a float global value. + static int get_float(int global) + { + return *big::script_global(global).as(); + } + + // Lua API: Function + // Table: globals + // Name: get_string + // Param: global: integer: index of the global + // Returns: string: value of the global + // Retrieves a string global value. + static std::string get_string(int global) + { + return std::string(big::script_global(global).as()); + } + + // Lua API: Function + // Table: globals + // Name: set_int + // Param: global: integer: index of the global + // Param: val: integer: new value for the global + // Sets an int global value. + static void set_int(int global, int val) + { + *big::script_global(global).as() = val; + } + + // Lua API: Function + // Table: globals + // Name: set_uint + // Param: global: integer: index of the global + // Param: val: integer: new value for the global + // Sets an uint global value. + static void set_uint(int global, unsigned int val) + { + *big::script_global(global).as() = val; + } + + // Lua API: Function + // Table: globals + // Name: set_float + // Param: global: integer: index of the global + // Param: val: float: new value for the global + // Sets a float global value. + static void set_float(int global, float val) + { + *big::script_global(global).as() = val; + } + + // Lua API: Function + // Table: globals + // Name: set_string + // Param: global: integer: index of the global + // Param: str: string: new value for the global + // Sets a string global value. + static void set_string(int global, const std::string& str, int max_length) + { + strncpy(big::script_global(global).as(), str.data(), max_length); + } + + // Lua API: Function + // Table: globals + // Name: get_pointer + // Param: global: integer: index of the global + // Returns: pointer: value of the global + // Retrieves a pointer global. + static memory::pointer get_pointer(int global) + { + return memory::pointer((uint64_t)big::script_global(global).as()); + } + + void bind(sol::state& state) + { + auto ns = state["globals"].get_or_create(); + ns["get_int"] = get_int; + ns["get_uint"] = get_uint; + ns["get_float"] = get_float; + ns["get_string"] = get_string; + ns["set_int"] = set_int; + ns["set_uint"] = set_uint; + ns["set_float"] = set_float; + ns["set_string"] = set_string; + ns["get_pointer"] = get_pointer; + } +} \ No newline at end of file diff --git a/src/lua/bindings/globals.hpp b/src/lua/bindings/globals.hpp index 8b978b82..f64d90cf 100644 --- a/src/lua/bindings/globals.hpp +++ b/src/lua/bindings/globals.hpp @@ -1,123 +1,7 @@ #pragma once -#include "memory.hpp" -#include "script_global.hpp" +#include "lua/sol.hpp" namespace lua::globals { - // Lua API: Table - // Name: globals - // Table containing functions for manipulating gta script globals. - - // Lua API: Function - // Table: globals - // Name: get_int - // Param: global: integer: index of the global - // Returns: integer: value of the global - // Retrieves an int global value. - static int get_int(int global) - { - return *big::script_global(global).as(); - } - - // Lua API: Function - // Table: globals - // Name: get_uint - // Param: global: integer: index of the global - // Returns: integer: value of the global - // Retrieves an uint global value. - static int get_uint(int global) - { - return *big::script_global(global).as(); - } - - // Lua API: Function - // Table: globals - // Name: get_float - // Param: global: integer: index of the global - // Returns: float: value of the global - // Retrieves a float global value. - static int get_float(int global) - { - return *big::script_global(global).as(); - } - - // Lua API: Function - // Table: globals - // Name: get_string - // Param: global: integer: index of the global - // Returns: string: value of the global - // Retrieves a string global value. - static std::string get_string(int global) - { - return std::string(big::script_global(global).as()); - } - - // Lua API: Function - // Table: globals - // Name: set_int - // Param: global: integer: index of the global - // Param: val: integer: new value for the global - // Sets an int global value. - static void set_int(int global, int val) - { - *big::script_global(global).as() = val; - } - - // Lua API: Function - // Table: globals - // Name: set_uint - // Param: global: integer: index of the global - // Param: val: integer: new value for the global - // Sets an uint global value. - static void set_uint(int global, unsigned int val) - { - *big::script_global(global).as() = val; - } - - // Lua API: Function - // Table: globals - // Name: set_float - // Param: global: integer: index of the global - // Param: val: float: new value for the global - // Sets a float global value. - static void set_float(int global, float val) - { - *big::script_global(global).as() = val; - } - - // Lua API: Function - // Table: globals - // Name: set_string - // Param: global: integer: index of the global - // Param: str: string: new value for the global - // Sets a string global value. - static void set_string(int global, const std::string& str, int max_length) - { - strncpy(big::script_global(global).as(), str.data(), max_length); - } - - // Lua API: Function - // Table: globals - // Name: get_pointer - // Param: global: integer: index of the global - // Returns: pointer: value of the global - // Retrieves a pointer global. - static memory::pointer get_pointer(int global) - { - return memory::pointer((uint64_t)big::script_global(global).as()); - } - - static void bind(sol::state& state) - { - auto ns = state["globals"].get_or_create(); - ns["get_int"] = get_int; - ns["get_uint"] = get_uint; - ns["get_float"] = get_float; - ns["get_string"] = get_string; - ns["set_int"] = set_int; - ns["set_uint"] = set_uint; - ns["set_float"] = set_float; - ns["set_string"] = set_string; - ns["get_pointer"] = get_pointer; - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/gui.cpp b/src/lua/bindings/gui.cpp index 97c880ba..5158e73b 100644 --- a/src/lua/bindings/gui.cpp +++ b/src/lua/bindings/gui.cpp @@ -2,11 +2,360 @@ #include "../../gui.hpp" - namespace lua::gui { - bool is_open() + static void add_independent_element(lua_State* state, std::shared_ptr element) + { + auto module = sol::state_view(state)["!this"].get(); + + module->m_independent_gui.push_back(std::move(element)); + } + + static void add_element(lua_State* state, std::uint32_t hash, std::shared_ptr element) + { + auto module = sol::state_view(state)["!this"].get(); + + if (!module->m_gui.contains(hash)) + module->m_gui[hash] = {}; + + module->m_gui[hash].push_back(std::move(element)); + } + + big::tabs tab::id() const + { + return m_id; + } + + rage::joaat_t tab::hash() const + { + return m_tab_hash; + } + + bool tab::check_if_existing_tab_and_fill_id(const std::map& nav) + { + for (const auto& nav_item : nav) + { + if (nav_item.second.hash == m_tab_hash) + { + m_id = nav_item.first; + return true; + } + + if (check_if_existing_tab_and_fill_id(nav_item.second.sub_nav)) + { + return true; + } + } + + return false; + } + + static void add_to_existing_tab(std::map& nav, const rage::joaat_t existing_tab_hash, const std::pair& new_tab, const sol::this_state& state) + { + for (auto& nav_item : nav) + { + if (nav_item.second.hash == existing_tab_hash) + { + auto module = sol::state_view(state)["!this"].get(); + module->m_tab_to_sub_tabs[nav_item.first].push_back(new_tab.first); + + nav_item.second.sub_nav.emplace(new_tab); + return; + } + + add_to_existing_tab(nav_item.second.sub_nav, existing_tab_hash, new_tab, state); + } + } + + std::pair tab::make_tab_nav(const std::string& name, const rage::joaat_t tab_hash, const sol::this_state& state) + { + static size_t custom_tab_count = size_t(big::tabs::RUNTIME_CUSTOM); + m_id = big::tabs(custom_tab_count); + + custom_tab_count++; + + big::navigation_struct new_navigation_struct{}; + strcpy(new_navigation_struct.name, name.c_str()); + new_navigation_struct.hash = tab_hash; + + return std::make_pair(m_id, new_navigation_struct); + } + + tab::tab(const std::string& name, const sol::this_state& state) : + m_tab_hash(rage::joaat(name)) + { + auto& nav = big::g_gui_service->get_navigation(); + + if (check_if_existing_tab_and_fill_id(nav)) + { + return; + } + + // add top tab + nav.emplace(make_tab_nav(name, m_tab_hash, state)); + + auto module = sol::state_view(state)["!this"].get(); + module->m_owned_tabs.push_back(id()); + } + + tab::tab(const std::string& name, const rage::joaat_t parent_tab_hash, const sol::this_state& state) : + m_tab_hash(rage::joaat(name)) + { + auto& nav = big::g_gui_service->get_navigation(); + + if (check_if_existing_tab_and_fill_id(nav)) + { + return; + } + + const auto sub_tab = make_tab_nav(name, m_tab_hash, state); + add_to_existing_tab(nav, parent_tab_hash, sub_tab, state); + + auto module = sol::state_view(state)["!this"].get(); + module->m_owned_tabs.push_back(id()); + } + + void tab::clear(sol::this_state state) + { + auto module = sol::state_view(state)["!this"].get(); + + if (module->m_gui.contains(m_tab_hash)) + module->m_gui[m_tab_hash] = {}; + + for (auto sub_tab : module->m_tab_to_sub_tabs[id()]) + { + for (const auto owned_tab : module->m_owned_tabs) + { + if (sub_tab == owned_tab) + { + big::g_gui_service->remove_from_nav(sub_tab); + } + } + } + } + + tab tab::add_tab(const std::string& name, sol::this_state state) + { + const auto sub_tab = tab(name, m_tab_hash, state); + + return sub_tab; + } + + std::shared_ptr tab::add_button(const std::string& name, sol::protected_function callback, sol::this_state state) + { + auto element = std::make_shared(name, callback); + add_element(state, m_tab_hash, element); + return element; + } + + std::shared_ptr tab::add_text(const std::string& name, sol::this_state state) + { + auto element = std::make_shared(name); + add_element(state, m_tab_hash, element); + return element; + } + + std::shared_ptr tab::add_checkbox(const std::string& name, sol::this_state state) + { + auto element = std::make_shared(name); + add_element(state, m_tab_hash, element); + return element; + } + + std::shared_ptr tab::add_sameline(sol::this_state state) + { + auto element = std::make_shared(); + add_element(state, m_tab_hash, element); + return element; + } + + std::shared_ptr tab::add_separator(sol::this_state state) + { + auto element = std::make_shared(); + add_element(state, m_tab_hash, element); + return element; + } + + std::shared_ptr tab::add_input_int(const std::string& name, sol::this_state state) + { + auto element = std::make_shared(name); + add_element(state, m_tab_hash, element); + return element; + } + + std::shared_ptr tab::add_input_float(const std::string& name, sol::this_state state) + { + auto element = std::make_shared(name); + add_element(state, m_tab_hash, element); + return element; + } + + std::shared_ptr tab::add_input_string(const std::string& name, sol::this_state state) + { + auto element = std::make_shared(name); + add_element(state, m_tab_hash, element); + return element; + } + + std::shared_ptr tab::add_imgui(sol::protected_function imgui_rendering, sol::this_state state) + { + auto element = std::make_shared(imgui_rendering); + add_element(state, m_tab_hash, element); + return element; + } + + // Lua API: Table + // Name: gui + // Table containing functions for modifying the menu GUI. + + // Lua API: Function + // Table: gui + // Name: get_tab + // Param: tab_name: string: Name of the tab to get. + // Returns: tab: A tab instance which corresponds to the tab in the GUI. + static tab get_tab(const std::string& tab_name, sol::this_state state) + { + return tab(tab_name, state); + } + + // Lua API: Function + // Table: gui + // Name: add_tab + // Param: tab_name: string: Name of the tab to add. + // Returns: tab: A tab instance which corresponds to the new tab in the GUI. + static tab add_tab(const std::string& tab_name, sol::this_state state) + { + const auto new_tab = tab(tab_name, state); + + return new_tab; + } + + // Lua API: Function + // Table: gui + // Name: show_message + // Param: title: string + // Param: message: string + // Shows a message to the user with the given title and message. + static void show_message(const std::string& title, const std::string& message) + { + big::g_notification_service->push(title, message); + } + + // Lua API: Function + // Table: gui + // Name: show_warning + // Param: title: string + // Param: message: string + // Shows a warning to the user with the given title and message. + static void show_warning(const std::string& title, const std::string& message) + { + big::g_notification_service->push_warning(title, message); + } + + // Lua API: Function + // Table: gui + // Name: show_error + // Param: title: string + // Param: message: string + // Shows an error to the user with the given title and message. + static void show_error(const std::string& title, const std::string& message) + { + big::g_notification_service->push_error(title, message); + } + + // Lua API: Function + // Table: gui + // Name: is_open + // Returns: bool: Returns true if the GUI is open. + static bool is_open() { return big::g_gui->is_open(); } + + // Lua API: Function + // Table: gui + // Name: add_imgui + // Param: imgui_rendering: function: Function that will be called every rendering frame, you can call ImGui functions in it, please check the ImGui.md documentation file for more info. + // Registers a function that will be called every rendering frame, you can call ImGui functions in it, please check the ImGui.md documentation file for more info. + // **Example Usage:** + // ```lua + // gui.add_imgui(function() + // if ImGui.Begin("My Custom Window") then + // if ImGui.Button("Label") then + // script.run_in_fiber(function(script) + // -- call natives in there + // end) + // end + // + // ImGui.End() + // end + // end) + // ``` + static std::shared_ptr add_imgui(sol::protected_function imgui_rendering, sol::this_state state) + { + auto element = std::make_shared(imgui_rendering); + add_independent_element(state, element); + return element; + } + + void bind(sol::state& state) + { + auto ns = state["gui"].get_or_create(); + ns["get_tab"] = get_tab; + ns["add_tab"] = add_tab; + ns["show_message"] = show_message; + ns["show_warning"] = show_warning; + ns["show_error"] = show_error; + ns["is_open"] = is_open; + ns["add_imgui"] = add_imgui; + + auto button_ut = ns.new_usertype("button"); + button_ut["get_text"] = &lua::gui::button::get_text; + button_ut["set_text"] = &lua::gui::button::set_text; + + auto text_ut = ns.new_usertype("text"); + text_ut["get_text"] = &lua::gui::text::get_text; + text_ut["set_text"] = &lua::gui::text::set_text; + text_ut["set_font"] = &lua::gui::text::set_font; + + auto checkbox_ut = ns.new_usertype("checkbox"); + checkbox_ut["get_text"] = &lua::gui::checkbox::get_text; + checkbox_ut["set_text"] = &lua::gui::checkbox::set_text; + checkbox_ut["is_enabled"] = &lua::gui::checkbox::is_enabled; + checkbox_ut["set_enabled"] = &lua::gui::checkbox::set_enabled; + + ns.new_usertype("sameline"); + ns.new_usertype("separator"); + + auto input_int_ut = ns.new_usertype("input_int"); + input_int_ut["get_text"] = &lua::gui::input_int::get_text; + input_int_ut["set_text"] = &lua::gui::input_int::set_text; + input_int_ut["get_value"] = &lua::gui::input_int::get_value; + input_int_ut["set_value"] = &lua::gui::input_int::set_value; + + auto input_float_ut = ns.new_usertype("input_float"); + input_float_ut["get_text"] = &lua::gui::input_float::get_text; + input_float_ut["set_text"] = &lua::gui::input_float::set_text; + input_float_ut["get_value"] = &lua::gui::input_float::get_value; + input_float_ut["set_value"] = &lua::gui::input_float::set_value; + + auto input_string_ut = ns.new_usertype("input_string"); + input_string_ut["get_text"] = &lua::gui::input_string::get_text; + input_string_ut["set_text"] = &lua::gui::input_string::set_text; + input_string_ut["get_value"] = &lua::gui::input_string::get_value; + input_string_ut["set_value"] = &lua::gui::input_string::set_value; + + auto tab_ut = ns.new_usertype("tab"); + tab_ut["clear"] = &tab::clear; + tab_ut["add_tab"] = &tab::add_tab; + tab_ut["add_button"] = &tab::add_button; + tab_ut["add_text"] = &tab::add_text; + tab_ut["add_checkbox"] = &tab::add_checkbox; + tab_ut["add_sameline"] = &tab::add_sameline; + tab_ut["add_separator"] = &tab::add_separator; + tab_ut["add_input_int"] = &tab::add_input_int; + tab_ut["add_input_float"] = &tab::add_input_float; + tab_ut["add_input_string"] = &tab::add_input_string; + tab_ut["add_imgui"] = &tab::add_imgui; + } } \ No newline at end of file diff --git a/src/lua/bindings/gui.hpp b/src/lua/bindings/gui.hpp index 2af344d2..d383f11e 100644 --- a/src/lua/bindings/gui.hpp +++ b/src/lua/bindings/gui.hpp @@ -14,23 +14,6 @@ namespace lua::gui { - static void add_independent_element(lua_State* state, std::shared_ptr element) - { - auto module = sol::state_view(state)["!this"].get(); - - module->m_independent_gui.push_back(std::move(element)); - } - - static void add_element(lua_State* state, std::uint32_t hash, std::shared_ptr element) - { - auto module = sol::state_view(state)["!this"].get(); - - if (!module->m_gui.contains(hash)) - module->m_gui[hash] = {}; - - module->m_gui[hash].push_back(std::move(element)); - } - // Lua API: Class // Name: tab // Class for representing a tab within the GUI. @@ -40,133 +23,29 @@ namespace lua::gui rage::joaat_t m_tab_hash; public: - inline big::tabs id() const - { - return m_id; - } + big::tabs id() const; - inline rage::joaat_t hash() const - { - return m_tab_hash; - } + rage::joaat_t hash() const; - bool check_if_existing_tab_and_fill_id(const std::map& nav) - { - for (const auto& nav_item : nav) - { - if (nav_item.second.hash == m_tab_hash) - { - m_id = nav_item.first; - return true; - } + bool check_if_existing_tab_and_fill_id(const std::map& nav); - if (check_if_existing_tab_and_fill_id(nav_item.second.sub_nav)) - { - return true; - } - } + std::pair make_tab_nav(const std::string& name, const rage::joaat_t tab_hash, const sol::this_state& state); - return false; - } + tab(const std::string& name, const sol::this_state& state); - static void add_to_existing_tab(std::map& nav, const rage::joaat_t existing_tab_hash, const std::pair& new_tab, const sol::this_state& state) - { - for (auto& nav_item : nav) - { - if (nav_item.second.hash == existing_tab_hash) - { - auto module = sol::state_view(state)["!this"].get(); - module->m_tab_to_sub_tabs[nav_item.first].push_back(new_tab.first); - - nav_item.second.sub_nav.emplace(new_tab); - return; - } - - add_to_existing_tab(nav_item.second.sub_nav, existing_tab_hash, new_tab, state); - } - } - - std::pair make_tab_nav(const std::string& name, const rage::joaat_t tab_hash, const sol::this_state& state) - { - static size_t custom_tab_count = size_t(big::tabs::RUNTIME_CUSTOM); - m_id = big::tabs(custom_tab_count); - - custom_tab_count++; - - big::navigation_struct new_navigation_struct{}; - strcpy(new_navigation_struct.name, name.c_str()); - new_navigation_struct.hash = tab_hash; - - return std::make_pair(m_id, new_navigation_struct); - } - - tab(const std::string& name, const sol::this_state& state) : - m_tab_hash(rage::joaat(name)) - { - auto& nav = big::g_gui_service->get_navigation(); - - if (check_if_existing_tab_and_fill_id(nav)) - { - return; - } - - // add top tab - nav.emplace(make_tab_nav(name, m_tab_hash, state)); - - auto module = sol::state_view(state)["!this"].get(); - module->m_owned_tabs.push_back(id()); - } - - tab(const std::string& name, const rage::joaat_t parent_tab_hash, const sol::this_state& state) : - m_tab_hash(rage::joaat(name)) - { - auto& nav = big::g_gui_service->get_navigation(); - - if (check_if_existing_tab_and_fill_id(nav)) - { - return; - } - - const auto sub_tab = make_tab_nav(name, m_tab_hash, state); - add_to_existing_tab(nav, parent_tab_hash, sub_tab, state); - - auto module = sol::state_view(state)["!this"].get(); - module->m_owned_tabs.push_back(id()); - } + tab(const std::string& name, const rage::joaat_t parent_tab_hash, const sol::this_state& state); // Lua API: Function // Class: tab // Name: clear // Clear the tab of all its custom lua content that you own. - void clear(sol::this_state state) - { - auto module = sol::state_view(state)["!this"].get(); - - if (module->m_gui.contains(m_tab_hash)) - module->m_gui[m_tab_hash] = {}; - - for (auto sub_tab : module->m_tab_to_sub_tabs[id()]) - { - for (const auto owned_tab : module->m_owned_tabs) - { - if (sub_tab == owned_tab) - { - big::g_gui_service->remove_from_nav(sub_tab); - } - } - } - } + void clear(sol::this_state state); // Lua API: Function // Class: tab // Name: add_tab // Add a sub tab to this tab. - tab add_tab(const std::string& name, sol::this_state state) - { - const auto sub_tab = tab(name, m_tab_hash, state); - - return sub_tab; - } + tab add_tab(const std::string& name, sol::this_state state); // Lua API: Function // Class: tab @@ -174,12 +53,7 @@ namespace lua::gui // Param: name: string: Text written inside the button. // Param: callback: function: function that will be called when the button is clicked. // Add a button to the gui tab. - std::shared_ptr add_button(const std::string& name, sol::protected_function callback, sol::this_state state) - { - auto element = std::make_shared(name, callback); - add_element(state, m_tab_hash, element); - return element; - } + std::shared_ptr add_button(const std::string& name, sol::protected_function callback, sol::this_state state); // Lua API: Function // Class: tab @@ -187,12 +61,7 @@ namespace lua::gui // Param: name: string: Text that will be written. // Returns: text: The text object instance. // Add text to the gui tab. - std::shared_ptr add_text(const std::string& name, sol::this_state state) - { - auto element = std::make_shared(name); - add_element(state, m_tab_hash, element); - return element; - } + std::shared_ptr add_text(const std::string& name, sol::this_state state); // Lua API: Function // Class: tab @@ -200,36 +69,21 @@ namespace lua::gui // Param: name: string: Text that will be written next to the checkbox. // Returns: checkbox: The checkbox object instance. // Add a checkbox widget to the gui tab. - std::shared_ptr add_checkbox(const std::string& name, sol::this_state state) - { - auto element = std::make_shared(name); - add_element(state, m_tab_hash, element); - return element; - } + std::shared_ptr add_checkbox(const std::string& name, sol::this_state state); // Lua API: Function // Class: tab // Name: add_sameline // Returns: sameline: The sameline object instance. // Add a ImGui::SameLine. - std::shared_ptr add_sameline(sol::this_state state) - { - auto element = std::make_shared(); - add_element(state, m_tab_hash, element); - return element; - } + std::shared_ptr add_sameline(sol::this_state state); // Lua API: Function // Class: tab // Name: add_separator // Returns: separator: The separator object instance. // Add a ImGui::Separator. - std::shared_ptr add_separator(sol::this_state state) - { - auto element = std::make_shared(); - add_element(state, m_tab_hash, element); - return element; - } + std::shared_ptr add_separator(sol::this_state state); // Lua API: Function // Class: tab @@ -237,12 +91,7 @@ namespace lua::gui // Param: name: string: Text that will be written next to the input field. // Returns: input_int: The input_int object instance. // Add a ImGui::InputInt. - std::shared_ptr add_input_int(const std::string& name, sol::this_state state) - { - auto element = std::make_shared(name); - add_element(state, m_tab_hash, element); - return element; - } + std::shared_ptr add_input_int(const std::string& name, sol::this_state state); // Lua API: Function // Class: tab @@ -250,12 +99,7 @@ namespace lua::gui // Param: name: string: Text that will be written next to the input field. // Returns: input_float: The input_float object instance. // Add a ImGui::InputFloat. - std::shared_ptr add_input_float(const std::string& name, sol::this_state state) - { - auto element = std::make_shared(name); - add_element(state, m_tab_hash, element); - return element; - } + std::shared_ptr add_input_float(const std::string& name, sol::this_state state); // Lua API: Function // Class: tab @@ -263,12 +107,7 @@ namespace lua::gui // Param: name: string: Text that will be written next to the input field. // Returns: input_string: The input_string object instance. // Add a ImGui::InputText. - std::shared_ptr add_input_string(const std::string& name, sol::this_state state) - { - auto element = std::make_shared(name); - add_element(state, m_tab_hash, element); - return element; - } + std::shared_ptr add_input_string(const std::string& name, sol::this_state state); // Lua API: Function // Class: tab @@ -289,172 +128,8 @@ namespace lua::gui // end // end) // ``` - std::shared_ptr add_imgui(sol::protected_function imgui_rendering, sol::this_state state) - { - auto element = std::make_shared(imgui_rendering); - add_element(state, m_tab_hash, element); - return element; - } + std::shared_ptr add_imgui(sol::protected_function imgui_rendering, sol::this_state state); }; - // Lua API: Table - // Name: gui - // Table containing functions for modifying the menu GUI. - - // Lua API: Function - // Table: gui - // Name: get_tab - // Param: tab_name: string: Name of the tab to get. - // Returns: tab: A tab instance which corresponds to the tab in the GUI. - static tab get_tab(const std::string& tab_name, sol::this_state state) - { - return tab(tab_name, state); - } - - // Lua API: Function - // Table: gui - // Name: add_tab - // Param: tab_name: string: Name of the tab to add. - // Returns: tab: A tab instance which corresponds to the new tab in the GUI. - static tab add_tab(const std::string& tab_name, sol::this_state state) - { - const auto new_tab = tab(tab_name, state); - - return new_tab; - } - - // Lua API: Function - // Table: gui - // Name: show_message - // Param: title: string - // Param: message: string - // Shows a message to the user with the given title and message. - static void show_message(const std::string& title, const std::string& message) - { - big::g_notification_service->push(title, message); - } - - // Lua API: Function - // Table: gui - // Name: show_warning - // Param: title: string - // Param: message: string - // Shows a warning to the user with the given title and message. - static void show_warning(const std::string& title, const std::string& message) - { - big::g_notification_service->push_warning(title, message); - } - - // Lua API: Function - // Table: gui - // Name: show_error - // Param: title: string - // Param: message: string - // Shows an error to the user with the given title and message. - static void show_error(const std::string& title, const std::string& message) - { - big::g_notification_service->push_error(title, message); - } - - // Lua API: Function - // Table: gui - // Name: is_open - // Returns: bool: Returns true if the GUI is open. - bool is_open(); - - // Lua API: Function - // Table: gui - // Name: add_imgui - // Param: imgui_rendering: function: Function that will be called every rendering frame, you can call ImGui functions in it, please check the ImGui.md documentation file for more info. - // Registers a function that will be called every rendering frame, you can call ImGui functions in it, please check the ImGui.md documentation file for more info. - // **Example Usage:** - // ```lua - // gui.add_imgui(function() - // if ImGui.Begin("My Custom Window") then - // if ImGui.Button("Label") then - // script.run_in_fiber(function(script) - // -- call natives in there - // end) - // end - // - // ImGui.End() - // end - // end) - // ``` - static std::shared_ptr add_imgui(sol::protected_function imgui_rendering, sol::this_state state) - { - auto element = std::make_shared(imgui_rendering); - add_independent_element(state, element); - return element; - } - - static void bind(sol::state& state) - { - auto ns = state["gui"].get_or_create(); - ns["get_tab"] = get_tab; - ns["add_tab"] = add_tab; - ns["show_message"] = show_message; - ns["show_warning"] = show_warning; - ns["show_error"] = show_error; - ns["is_open"] = is_open; - ns["add_imgui"] = add_imgui; - - // clang-format off - ns.new_usertype("button", - "set_text", &lua::gui::button::set_text, - "get_text", &lua::gui::button::get_text - ); - - ns.new_usertype("text", - "set_text", &lua::gui::text::set_text, - "get_text", &lua::gui::text::get_text, - "set_font", &lua::gui::text::set_font - ); - - ns.new_usertype("checkbox", - "set_text", &lua::gui::checkbox::set_text, - "get_text", &lua::gui::checkbox::get_text, - "is_enabled", &lua::gui::checkbox::is_enabled, - "set_enabled", &lua::gui::checkbox::set_enabled - ); - - ns.new_usertype("sameline"); - ns.new_usertype("separator"); - - ns.new_usertype("input_int", - "set_text", &lua::gui::input_int::set_text, - "get_text", &lua::gui::input_int::get_text, - "get_value", &lua::gui::input_int::get_value, - "set_value", &lua::gui::input_int::set_value - ); - - ns.new_usertype("input_float", - "set_text", &lua::gui::input_float::set_text, - "get_text", &lua::gui::input_float::get_text, - "get_value", &lua::gui::input_float::get_value, - "set_value", &lua::gui::input_float::set_value - ); - - ns.new_usertype("input_string", - "set_text", &lua::gui::input_string::set_text, - "get_text", &lua::gui::input_string::get_text, - "get_value", &lua::gui::input_string::get_value, - "set_value", &lua::gui::input_string::set_value - ); - - ns.new_usertype("tab", - "clear", &tab::clear, - "add_tab", &tab::add_tab, - "add_button", &tab::add_button, - "add_text", &tab::add_text, - "add_checkbox", &tab::add_checkbox, - "add_sameline", &tab::add_sameline, - "add_separator", &tab::add_separator, - "add_input_int", &tab::add_input_int, - "add_input_float", &tab::add_input_float, - "add_input_string", &tab::add_input_string, - "add_imgui", &tab::add_imgui - ); - // clang-format on - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/locals.cpp b/src/lua/bindings/locals.cpp new file mode 100644 index 00000000..84d803e1 --- /dev/null +++ b/src/lua/bindings/locals.cpp @@ -0,0 +1,75 @@ +#pragma once +#include "locals.hpp" +#include "memory.hpp" + +namespace lua::locals +{ + // Lua API: Table + // Name: locals + // Table for manipulating GTA scripts locals. + + // Lua API: Function + // Table: locals + // Name: get_int + // Param: script: string: The name of the script + // Param: index: index: Index of the script local. + // Returns: integer: The value of the given local. + static int get_int(const std::string& script, int index) + { + return *get(script, index); + } + + // Lua API: Function + // Table: locals + // Name: get_float + // Param: script: string: The name of the script + // Param: index: index: Index of the script local. + // Returns: float: The value of the given local. + static int get_float(const std::string& script, int index) + { + return *get(script, index); + } + + // Lua API: Function + // Table: locals + // Name: set_int + // Param: script: string: The name of the script + // Param: index: index: Index of the script local. + // Param: val: integer: The new value of the given local. + static void set_int(const std::string& script, int index, int val) + { + *get(script, index) = val; + } + + // Lua API: Function + // Table: locals + // Name: set_float + // Param: script: string: The name of the script + // Param: index: index: Index of the script local. + // Param: val: float: The new value of the given local. + static void set_float(const std::string& script, int index, float val) + { + *get(script, index) = val; + } + + // Lua API: Function + // Table: locals + // Name: get_pointer + // Param: script: string: The name of the script + // Param: index: index: Index of the script local. + // Returns: pointer: The pointer to the given local. + static memory::pointer get_pointer(const std::string& script, int index) + { + return memory::pointer((uint64_t)get(script, index)); + } + + void bind(sol::state& state) + { + auto ns = state["locals"].get_or_create(); + ns["get_int"] = get_int; + ns["get_float"] = get_float; + ns["set_int"] = set_int; + ns["set_float"] = set_float; + ns["get_pointer"] = get_pointer; + } +} \ No newline at end of file diff --git a/src/lua/bindings/locals.hpp b/src/lua/bindings/locals.hpp index 4e14553f..295181e2 100644 --- a/src/lua/bindings/locals.hpp +++ b/src/lua/bindings/locals.hpp @@ -1,14 +1,10 @@ #pragma once #include "gta_util.hpp" -#include "memory.hpp" #include "script_local.hpp" +#include "lua/sol.hpp" namespace lua::locals { - // Lua API: Table - // Name: locals - // Table for manipulating GTA scripts locals. - template inline T get(const std::string& script, int index) { @@ -20,68 +16,5 @@ namespace lua::locals return &null; } - // Lua API: Function - // Table: locals - // Name: get_int - // Param: script: string: The name of the script - // Param: index: index: Index of the script local. - // Returns: integer: The value of the given local. - static int get_int(const std::string& script, int index) - { - return *get(script, index); - } - - // Lua API: Function - // Table: locals - // Name: get_float - // Param: script: string: The name of the script - // Param: index: index: Index of the script local. - // Returns: float: The value of the given local. - static int get_float(const std::string& script, int index) - { - return *get(script, index); - } - - // Lua API: Function - // Table: locals - // Name: set_int - // Param: script: string: The name of the script - // Param: index: index: Index of the script local. - // Param: val: integer: The new value of the given local. - static void set_int(const std::string& script, int index, int val) - { - *get(script, index) = val; - } - - // Lua API: Function - // Table: locals - // Name: set_float - // Param: script: string: The name of the script - // Param: index: index: Index of the script local. - // Param: val: float: The new value of the given local. - static void set_float(const std::string& script, int index, float val) - { - *get(script, index) = val; - } - - // Lua API: Function - // Table: locals - // Name: get_pointer - // Param: script: string: The name of the script - // Param: index: index: Index of the script local. - // Returns: pointer: The pointer to the given local. - static memory::pointer get_pointer(const std::string& script, int index) - { - return memory::pointer((uint64_t)get(script, index)); - } - - static void bind(sol::state& state) - { - auto ns = state["locals"].get_or_create(); - ns["get_int"] = get_int; - ns["get_float"] = get_float; - ns["set_int"] = set_int; - ns["set_float"] = set_float; - ns["get_pointer"] = get_pointer; - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/log.cpp b/src/lua/bindings/log.cpp new file mode 100644 index 00000000..26011d92 --- /dev/null +++ b/src/lua/bindings/log.cpp @@ -0,0 +1,47 @@ +#pragma once +#include "log.hpp" + +namespace lua::log +{ + // Lua API: Table + // Name: log + // Table containing functions for printing to console / log file. + + // Lua API: Function + // Table: log + // Name: info + // Param: data: string + // Logs an informational message. + static void info(const std::string& data, sol::this_state state) + { + LOG(INFO) << sol::state_view(state)["!module_name"].get() << ": " << data; + } + + // Lua API: Function + // Table: log + // Name: warning + // Param: data: string + // Logs a warning message. + static void warning(const std::string& data, sol::this_state state) + { + LOG(WARNING) << sol::state_view(state)["!module_name"].get() << ": " << data; + } + + // Lua API: Function + // Table: log + // Name: debug + // Param: data: string + // Logs a debug message. + static void debug(const std::string& data, sol::this_state state) + { + LOG(VERBOSE) << sol::state_view(state)["!module_name"].get() << ": " << data; + } + + void bind(sol::state& state) + { + auto ns = state["log"].get_or_create(); + ns["info"] = info; + ns["warning"] = warning; + ns["debug"] = debug; + } +} \ No newline at end of file diff --git a/src/lua/bindings/log.hpp b/src/lua/bindings/log.hpp index ae1b1970..ebb9c946 100644 --- a/src/lua/bindings/log.hpp +++ b/src/lua/bindings/log.hpp @@ -3,45 +3,5 @@ namespace lua::log { - // Lua API: Table - // Name: log - // Table containing functions for printing to console / log file. - - // Lua API: Function - // Table: log - // Name: info - // Param: data: string - // Logs an informational message. - static void info(const std::string& data, sol::this_state state) - { - LOG(INFO) << sol::state_view(state)["!module_name"].get() << ": " << data; - } - - // Lua API: Function - // Table: log - // Name: warning - // Param: data: string - // Logs a warning message. - static void warning(const std::string& data, sol::this_state state) - { - LOG(WARNING) << sol::state_view(state)["!module_name"].get() << ": " << data; - } - - // Lua API: Function - // Table: log - // Name: debug - // Param: data: string - // Logs a debug message. - static void debug(const std::string& data, sol::this_state state) - { - LOG(VERBOSE) << sol::state_view(state)["!module_name"].get() << ": " << data; - } - - static void bind(sol::state& state) - { - auto ns = state["log"].get_or_create(); - ns["info"] = info; - ns["warning"] = warning; - ns["debug"] = debug; - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/memory.cpp b/src/lua/bindings/memory.cpp index 0bf43549..7bdd6e4f 100644 --- a/src/lua/bindings/memory.cpp +++ b/src/lua/bindings/memory.cpp @@ -6,18 +6,93 @@ namespace lua::memory { - pointer scan_pattern(const std::string& pattern) + pointer::pointer(std::uint64_t address) : + m_address(address) + { + } + + pointer::pointer() : + m_address(0) + { + } + + pointer pointer::add(uint64_t offset) + { + return pointer(m_address + offset); + } + + pointer pointer::sub(uint64_t offset) + { + return pointer(m_address - offset); + } + + pointer pointer::rip() + { + return add(*(std::int32_t*)m_address).add(4); + } + + std::string pointer::get_string() + { + return std::string((char*)m_address); + } + + void pointer::set_string(const std::string& string, int max_length) + { + strncpy((char*)m_address, string.data(), max_length); + } + + bool pointer::is_null() + { + return m_address == 0; + } + + bool pointer::is_valid() + { + return !is_null(); + } + + pointer pointer::deref() + { + return pointer(*(uint64_t*)m_address); + } + + uint64_t pointer::get_address() const + { + return m_address; + } + + // Lua API: Table + // Name: memory + // Table containing helper functions related to process memory. + + // Lua API: Function + // Table: memory + // Name: scan_pattern + // Param: pattern: string: byte pattern (IDA format) + // Returns: pointer: A pointer to the found address. + // Scans the specified memory pattern within the "GTA5.exe" module and returns a pointer to the found address. + static pointer scan_pattern(const std::string& pattern) { return pointer(::memory::module("GTA5.exe").scan(::memory::pattern(pattern)).value().as()); } - pointer handle_to_ptr(int entity) + // Lua API: Function + // Table: memory + // Name: handle_to_ptr + // Param: entity: number: script game entity handle + // Returns: pointer: A rage::CDynamicEntity pointer to the script game entity handle + static pointer handle_to_ptr(int entity) { auto ptr = big::g_pointers->m_gta.m_handle_to_ptr(entity); return pointer((uint64_t)ptr); } - int ptr_to_handle(pointer mem_addr) + // Lua API: Function + // Table: memory + // Name: ptr_to_handle + // Param: mem_addr: pointer: A rage::CDynamicEntity pointer. + // Returns: number: The script game entity handle linked to the given rage::CDynamicEntity pointer. + static int ptr_to_handle(pointer mem_addr) { if (mem_addr.is_null()) return 0; @@ -25,7 +100,12 @@ namespace lua::memory return big::g_pointers->m_gta.m_ptr_to_handle((void*)mem_addr.get_address()); } - pointer allocate(int size, sol::this_state state) + // Lua API: Function + // Table: memory + // Name: allocate + // Param: size: integer: The number of bytes to allocate on the heap. + // Returns: pointer: A pointer to the newly allocated memory. + static pointer allocate(int size, sol::this_state state) { void* mem = new uint8_t[](size); auto module = sol::state_view(state)["!this"].get(); @@ -33,7 +113,11 @@ namespace lua::memory return pointer((uint64_t)mem); } - void free(pointer ptr, sol::this_state state) + // Lua API: Function + // Table: memory + // Name: free + // Param: ptr: pointer: The pointer that must be freed. + static void free(pointer ptr, sol::this_state state) { delete[] (void*)ptr.get_address(); auto module = sol::state_view(state)["!this"].get(); @@ -41,4 +125,45 @@ namespace lua::memory return ptr.get_address() == (uint64_t)addr; }); } + + void bind(sol::state& state) + { + auto ns = state["memory"].get_or_create(); + + auto pointer_ut = ns.new_usertype("pointer", sol::constructors()); + + pointer_ut["add"] = &pointer::add; + pointer_ut["sub"] = &pointer::sub; + pointer_ut["rip"] = &pointer::rip; + pointer_ut["get_byte"] = &pointer::get; + pointer_ut["get_word"] = &pointer::get; + pointer_ut["get_dword"] = &pointer::get; + pointer_ut["get_qword"] = &pointer::get; + pointer_ut["get_float"] = &pointer::get; + pointer_ut["get_string"] = &pointer::get_string; + pointer_ut["set_byte"] = &pointer::set; + pointer_ut["set_word"] = &pointer::set; + pointer_ut["set_dword"] = &pointer::set; + pointer_ut["set_qword"] = &pointer::set; + pointer_ut["set_float"] = &pointer::set; + pointer_ut["set_string"] = &pointer::set_string; + pointer_ut["patch_byte"] = &pointer::patch; + pointer_ut["patch_word"] = &pointer::patch; + pointer_ut["patch_dword"] = &pointer::patch; + pointer_ut["patch_qword"] = &pointer::patch; + pointer_ut["is_null"] = &pointer::is_null; + pointer_ut["is_valid"] = &pointer::is_valid; + pointer_ut["deref"] = &pointer::deref; + pointer_ut["get_address"] = &pointer::get_address; + + auto patch_ut = ns.new_usertype("patch", sol::no_constructor); + patch_ut["apply"] = &big::lua_patch::apply; + patch_ut["restore"] = &big::lua_patch::restore; + + ns["scan_pattern"] = scan_pattern; + ns["handle_to_ptr"] = handle_to_ptr; + ns["ptr_to_handle"] = ptr_to_handle; + ns["allocate"] = allocate; + ns["free"] = free; + } } \ No newline at end of file diff --git a/src/lua/bindings/memory.hpp b/src/lua/bindings/memory.hpp index 136a3c62..2ab104f0 100644 --- a/src/lua/bindings/memory.hpp +++ b/src/lua/bindings/memory.hpp @@ -1,8 +1,6 @@ #pragma once #include "lua/lua_module.hpp" -#include "lua/lua_patch.hpp" #include "lua/sol.hpp" -#include "memory/byte_patch.hpp" namespace lua::memory { @@ -21,15 +19,9 @@ namespace lua::memory // Class: pointer // Param: address: integer: Address // Returns a memory instance, with the given address. - explicit pointer(std::uint64_t address) : - m_address(address) - { - } + explicit pointer(std::uint64_t address); - explicit pointer() : - m_address(0) - { - } + explicit pointer(); // Lua API: Function // Class: pointer @@ -37,10 +29,7 @@ namespace lua::memory // Param: offset: integer: offset // Returns: pointer: new pointer object. // Adds an offset to the current memory address and returns a new pointer object. - pointer add(uint64_t offset) - { - return pointer(m_address + offset); - } + pointer add(uint64_t offset); // Lua API: Function // Class: pointer @@ -48,10 +37,7 @@ namespace lua::memory // Param: offset: integer: offset // Returns: pointer: new pointer object. // Subs an offset to the current memory address and returns a new pointer object. - pointer sub(uint64_t offset) - { - return pointer(m_address - offset); - } + pointer sub(uint64_t offset); // Lua API: Function // Class: pointer @@ -59,10 +45,7 @@ namespace lua::memory // Param: offset: integer: offset // Returns: pointer: new pointer object. // Rips the current memory address and returns a new pointer object. - pointer rip() - { - return add(*(std::int32_t*)m_address).add(4); - } + pointer rip(); // Lua API: Function // Class: pointer @@ -141,20 +124,14 @@ namespace lua::memory // Name: get_string // Returns: string: the value stored at the memory address as the specified type. // Retrieves the value stored at the memory address as the specified type. - std::string get_string() - { - return std::string((char*)m_address); - } + std::string get_string(); // Lua API: Function // Class: pointer // Name: set_string // Param: value: string: new value. // Sets the value at the memory address to the specified value of the given type. - void set_string(const std::string& string, int max_length) - { - strncpy((char*)m_address, string.data(), max_length); - } + void set_string(const std::string& string, int max_length); // Lua API: Function // Class: pointer @@ -206,121 +183,28 @@ namespace lua::memory // Class: pointer // Name: is_null // Returns: boolean: Returns true if the address is null. - bool is_null() - { - return m_address == 0; - } + bool is_null(); // Lua API: Function // Class: pointer // Name: is_valid // Returns: boolean: Returns true if the address is not null. - bool is_valid() - { - return !is_null(); - } + bool is_valid(); // Lua API: Function // Class: pointer // Name: deref // Returns: pointer: A new pointer object pointing to the value at that address. // Dereferences the memory address and returns a new pointer object pointing to the value at that address. - pointer deref() - { - return pointer(*(uint64_t*)m_address); - } + pointer deref(); // Lua API: Function // Class: pointer // Name: get_address // Returns: number: The memory address stored in the pointer object as a number. // Retrieves the memory address stored in the pointer object. - uint64_t get_address() const - { - return m_address; - } + uint64_t get_address() const; }; - // Lua API: Table - // Name: memory - // Table containing helper functions related to process memory. - - // Lua API: Function - // Table: memory - // Name: scan_pattern - // Param: pattern: string: byte pattern (IDA format) - // Returns: pointer: A pointer to the found address. - // Scans the specified memory pattern within the "GTA5.exe" module and returns a pointer to the found address. - pointer scan_pattern(const std::string& pattern); - - // Lua API: Function - // Table: memory - // Name: handle_to_ptr - // Param: entity: number: script game entity handle - // Returns: pointer: A rage::CDynamicEntity pointer to the script game entity handle - pointer handle_to_ptr(int entity); - - // Lua API: Function - // Table: memory - // Name: ptr_to_handle - // Param: mem_addr: pointer: A rage::CDynamicEntity pointer. - // Returns: number: The script game entity handle linked to the given rage::CDynamicEntity pointer. - int ptr_to_handle(pointer mem_addr); - - // Lua API: Function - // Table: memory - // Name: allocate - // Param: size: integer: The number of bytes to allocate on the heap. - // Returns: pointer: A pointer to the newly allocated memory. - pointer allocate(int size, sol::this_state state); - - // Lua API: Function - // Table: memory - // Name: free - // Param: ptr: pointer: The pointer that must be freed. - void free(pointer ptr, sol::this_state state); - - static void bind(sol::state& state) - { - auto ns = state["memory"].get_or_create(); - - // clang-format off - ns.new_usertype("pointer", sol::constructors(), - "add", &pointer::add, - "sub", &pointer::sub, - "rip", &pointer::rip, - "get_byte", &pointer::get, - "get_word", &pointer::get, - "get_dword", &pointer::get, - "get_float", &pointer::get, - "get_qword", &pointer::get, - "get_string", &pointer::get_string, - "set_byte", &pointer::set, - "set_word", &pointer::set, - "set_dword", &pointer::set, - "set_float", &pointer::set, - "set_qword", &pointer::set, - "set_string", &pointer::set_string, - "patch_byte", &pointer::patch, - "patch_word", &pointer::patch, - "patch_dword", &pointer::patch, - "patch_qword", &pointer::patch, - "is_null", &pointer::is_null, - "is_valid", &pointer::is_valid, - "deref", &pointer::deref, - "get_address", &pointer::get_address - ); - - ns.new_usertype("patch", sol::no_constructor, - "apply", &big::lua_patch::apply, - "restore", &big::lua_patch::restore - ); - // clang-format on - - ns["scan_pattern"] = scan_pattern; - ns["handle_to_ptr"] = handle_to_ptr; - ns["ptr_to_handle"] = ptr_to_handle; - ns["allocate"] = allocate; - ns["free"] = free; - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/network.cpp b/src/lua/bindings/network.cpp index 53cfbcd5..d3d3c5cc 100644 --- a/src/lua/bindings/network.cpp +++ b/src/lua/bindings/network.cpp @@ -1,5 +1,6 @@ #include "network.hpp" +#include "../../script.hpp" #include "hooking.hpp" #include "pointers.hpp" #include "services/player_database/player_database_service.hpp" @@ -10,7 +11,17 @@ namespace lua::network { - void trigger_script_event(int bitset, sol::table _args) + // Lua API: Table + // Name: network + // Table containing helper functions for network related features. + + // Lua API: Function + // Table: network + // Name: trigger_script_event + // Param: bitset: integer + // Param: _args: table + // Call trigger_script_event (TSE) + static void trigger_script_event(int bitset, sol::table _args) { auto args = convert_sequence(_args); @@ -25,18 +36,39 @@ namespace lua::network big::g_pointers->m_gta.m_trigger_script_event(1, actual_args.data(), actual_args.size(), bitset); } - void give_pickup_rewards(int player, int reward) + // Lua API: Function + // Table: network + // Name: give_pickup_rewards + // Param: player: integer: Index of the player. + // Param: reward: integer: Index of the reward pickup. + // Give the given pickup reward to the given player. + static void give_pickup_rewards(int player, int reward) { big::g_pointers->m_gta.m_give_pickup_rewards(1 << player, reward); } - void set_player_coords(int player_idx, float x, float y, float z) + // Lua API: Function + // Table: network + // Name: set_player_coords + // Param: player_idx: integer: Index of the player. + // Param: x: float: New x position. + // Param: y: float: New y position. + // Param: z: float: New z position. + // Teleport the given player to the given position. + static void set_player_coords(int player_idx, float x, float y, float z) { if (auto player = big::g_player_service->get_by_id(player_idx)) big::teleport::teleport_player_to_coords(player, {x, y, z}); } - void set_all_player_coords(float x, float y, float z) + // Lua API: Function + // Table: network + // Name: set_all_player_coords + // Param: x: float: New x position. + // Param: y: float: New y position. + // Param: z: float: New z position. + // Teleport all players to the given position. + static void set_all_player_coords(float x, float y, float z) { for (auto& player : big::g_player_service->players()) big::g_fiber_pool->queue_job([player, x, y, z]() { @@ -44,7 +76,11 @@ namespace lua::network }); } - int get_selected_player() + // Lua API: Function + // Table: network + // Name: get_selected_player + // Returns: integer: Returns the index of the currently selected player in the GUI. + static int get_selected_player() { if (big::g_player_service->get_selected()->is_valid()) return big::g_player_service->get_selected()->id(); @@ -52,7 +88,11 @@ namespace lua::network return -1; } - int get_selected_database_player_rockstar_id() + // Lua API: Function + // Table: network + // Name: get_selected_database_player_rockstar_id + // Returns: integer: Returns the rockstar id of the currently selected player in the GUI. + static int get_selected_database_player_rockstar_id() { if (auto pers = big::g_player_database_service->get_selected()) return pers->rockstar_id; @@ -60,7 +100,12 @@ namespace lua::network return -1; } - void flag_player_as_modder(int player_idx) + // Lua API: Function + // Table: network + // Name: flag_player_as_modder + // Param: player_idx: integer: Index of the player. + // Flags the given player as a modder in our local database. + static void flag_player_as_modder(int player_idx) { if (auto player = big::g_player_service->get_by_id(player_idx)) { @@ -71,7 +116,12 @@ namespace lua::network } } - bool is_player_flagged_as_modder(int player_idx) + // Lua API: Function + // Table: network + // Name: is_player_flagged_as_modder + // Param: player_idx: integer: Index of the player. + // Returns: boolean: Returns true if the given player is flagged as a modder. + static bool is_player_flagged_as_modder(int player_idx) { if (auto player = big::g_player_service->get_by_id(player_idx)) return player->is_modder; @@ -79,12 +129,23 @@ namespace lua::network return false; } - void force_script_host(const std::string& script_name) + // Lua API: Function + // Table: network + // Name: force_script_host + // Param: script_name: string: Name of the script + // Try to force ourself to be host for the given GTA Script. + static void force_script_host(const std::string& script_name) { big::scripts::force_host(rage::joaat(script_name)); } - void send_chat_message(const std::string& msg, bool team_only) + // Lua API: Function + // Table: network + // Name: send_chat_message + // Param: msg: string: Message to be sent. + // Param: team_only: boolean: Should be true if the msg should only be sent to our team. + // Sends a message to the in game chat. + static void send_chat_message(const std::string& msg, bool team_only) { big::g_fiber_pool->queue_job([msg, team_only] { if (big::g_hooking->get_original()(*big::g_pointers->m_gta.m_send_chat_ptr, @@ -94,4 +155,19 @@ namespace lua::network big::notify::draw_chat((char*)msg.data(), big::g_player_service->get_self()->get_name(), team_only); }); } + + void bind(sol::state& state) + { + auto ns = state["network"].get_or_create(); + ns["trigger_script_event"] = trigger_script_event; + ns["give_pickup_rewards"] = give_pickup_rewards; + ns["set_player_coords"] = set_player_coords; + ns["set_all_player_coords"] = set_all_player_coords; + ns["get_selected_player"] = get_selected_player; + ns["get_selected_database_player_rockstar_id"] = get_selected_database_player_rockstar_id; + ns["flag_player_as_modder"] = flag_player_as_modder; + ns["is_player_flagged_as_modder"] = is_player_flagged_as_modder; + ns["force_script_host"] = force_script_host; + ns["send_chat_message"] = send_chat_message; + } } \ No newline at end of file diff --git a/src/lua/bindings/network.hpp b/src/lua/bindings/network.hpp index 7144bb56..2c0e2fc9 100644 --- a/src/lua/bindings/network.hpp +++ b/src/lua/bindings/network.hpp @@ -20,98 +20,5 @@ inline std::vector convert_sequence(sol::table t) namespace lua::network { - // Lua API: Table - // Name: network - // Table containing helper functions for network related features. - - // Lua API: Function - // Table: network - // Name: trigger_script_event - // Param: bitset: integer - // Param: _args: table - // Call trigger_script_event (TSE) - void trigger_script_event(int bitset, sol::table _args); - - // Lua API: Function - // Table: network - // Name: give_pickup_rewards - // Param: player: integer: Index of the player. - // Param: reward: integer: Index of the reward pickup. - // Give the given pickup reward to the given player. - void give_pickup_rewards(int player, int reward); - - // Lua API: Function - // Table: network - // Name: set_player_coords - // Param: player_idx: integer: Index of the player. - // Param: x: float: New x position. - // Param: y: float: New y position. - // Param: z: float: New z position. - // Teleport the given player to the given position. - void set_player_coords(int player_idx, float x, float y, float z); - - // Lua API: Function - // Table: network - // Name: set_all_player_coords - // Param: x: float: New x position. - // Param: y: float: New y position. - // Param: z: float: New z position. - // Teleport all players to the given position. - void set_all_player_coords(float x, float y, float z); - - // Lua API: Function - // Table: network - // Name: get_selected_player - // Returns: integer: Returns the index of the currently selected player in the GUI. - int get_selected_player(); - - // Lua API: Function - // Table: network - // Name: get_selected_database_player_rockstar_id - // Returns: integer: Returns the rockstar id of the currently selected player in the GUI. - int get_selected_database_player_rockstar_id(); - - // Lua API: Function - // Table: network - // Name: flag_player_as_modder - // Param: player_idx: integer: Index of the player. - // Flags the given player as a modder in our local database. - void flag_player_as_modder(int player_idx); - - // Lua API: Function - // Table: network - // Name: is_player_flagged_as_modder - // Param: player_idx: integer: Index of the player. - // Returns: boolean: Returns true if the given player is flagged as a modder. - bool is_player_flagged_as_modder(int player_idx); - - // Lua API: Function - // Table: network - // Name: force_script_host - // Param: script_name: string: Name of the script - // Try to force ourself to be host for the given GTA Script. - void force_script_host(const std::string& script_name); - - // Lua API: Function - // Table: network - // Name: send_chat_message - // Param: msg: string: Message to be sent. - // Param: team_only: boolean: Should be true if the msg should only be sent to our team. - // Sends a message to the in game chat. - void send_chat_message(const std::string& msg, bool team_only); - - static void bind(sol::state& state) - { - auto ns = state["network"].get_or_create(); - ns["trigger_script_event"] = trigger_script_event; - ns["give_pickup_rewards"] = give_pickup_rewards; - ns["set_player_coords"] = set_player_coords; - ns["set_all_player_coords"] = set_all_player_coords; - ns["get_selected_player"] = get_selected_player; - ns["get_selected_database_player_rockstar_id"] = get_selected_database_player_rockstar_id; - ns["flag_player_as_modder"] = flag_player_as_modder; - ns["is_player_flagged_as_modder"] = is_player_flagged_as_modder; - ns["force_script_host"] = force_script_host; - ns["send_chat_message"] = send_chat_message; - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/script.cpp b/src/lua/bindings/script.cpp new file mode 100644 index 00000000..72b4d625 --- /dev/null +++ b/src/lua/bindings/script.cpp @@ -0,0 +1,164 @@ +#pragma once +#include "script.hpp" + +#include "lua/lua_manager.hpp" +#include "script_mgr.hpp" + +namespace lua::script +{ + static script_util dummy_script_util; + + int script_util::yield() + { + return 0; + } + + int script_util::sleep(int ms) + { + return ms; + } + + // Lua API: Table + // Name: script + // Table containing helper functions related to gta scripts. + + // Lua API: Function + // Table: script + // Name: register_looped + // Param: name: string: name of your new looped script + // Param: func: function: function that will be executed in a forever loop. + // Registers a function that will be looped as a gta script. + // **Example Usage:** + // ```lua + // script.register_looped("nameOfMyLoopedScript", function (script) + // -- sleep until next game frame + // script:yield() + // + // local ModelHash = joaat("adder") + // if not STREAMING.IS_MODEL_IN_CDIMAGE(ModelHash) then return end + // STREAMING.REQUEST_MODEL(ModelHash) -- Request the model + // while not STREAMING.HAS_MODEL_LOADED(ModelHash) do -- Waits for the model to load + // script:yield() + // end + // local myPed = PLAYER.PLAYER_PED_ID() + // local myCoords = ENTITY.GET_ENTITY_COORDS(myPed, true) + // -- Spawns a networked vehicle on your current coords + // local spawnedVehicle = VEHICLE.CREATE_VEHICLE(ModelHash, myCoords.x, myCoords.y, myCoords.z, ENTITY.GET_ENTITY_HEADING(myPed), true, false) + // -- removes model from game memory as we no longer need it + // STREAMING.SET_MODEL_AS_NO_LONGER_NEEDED(ModelHash) + // -- sleep for 2s + // script:sleep(2000) + // ENTITY.DELETE_ENTITY(spawnedVehicle) + // end) + // ``` + static void register_looped(const std::string& name, sol::protected_function func_, sol::this_state state) + { + auto module = sol::state_view(state)["!this"].get(); + + std::unique_ptr lua_script = std::make_unique( + [func_, state]() mutable { + sol::thread t = sol::thread::create(state); + sol::coroutine func = sol::coroutine(t.state(), func_); + + while (big::g_running) + { + auto res = func(dummy_script_util); + + if (!res.valid()) + big::g_lua_manager->handle_error(res, res.lua_state()); + + if (func.runnable()) + { + big::script::get_current()->yield(std::chrono::milliseconds(res.return_count() ? res[0] : 0)); + } + else + { + big::script::get_current()->yield(); + } + } + }, + name); + + const auto registered_script = big::g_script_mgr.add_script(std::move(lua_script)); + + module->m_registered_scripts.push_back(registered_script); + } + + // Lua API: Function + // Table: script + // Name: run_in_fiber + // Param: func: function: function that will be executed once in the fiber pool. + // Executes a function once inside the fiber pool, you can call natives inside it and yield or sleep. + // **Example Usage:** + // ```lua + // script.run_in_fiber(function (script) + // -- sleep until next game frame + // script:yield() + // + // local ModelHash = joaat("adder") + // if not STREAMING.IS_MODEL_IN_CDIMAGE(ModelHash) then return end + // STREAMING.REQUEST_MODEL(ModelHash) -- Request the model + // while not STREAMING.HAS_MODEL_LOADED(ModelHash) do -- Waits for the model to load + // script:yield() + // end + // local myPed = PLAYER.PLAYER_PED_ID() + // local myCoords = ENTITY.GET_ENTITY_COORDS(myPed, true) + // -- Spawns a networked vehicle on your current coords + // local spawnedVehicle = VEHICLE.CREATE_VEHICLE(ModelHash, myCoords.x, myCoords.y, myCoords.z, ENTITY.GET_ENTITY_HEADING(myPed), true, false) + // -- removes model from game memory as we no longer need it + // STREAMING.SET_MODEL_AS_NO_LONGER_NEEDED(ModelHash) + // -- sleep for 2s + // script:sleep(2000) + // ENTITY.DELETE_ENTITY(spawnedVehicle) + // end) + // ``` + static void run_in_fiber(sol::protected_function func_, sol::this_state state) + { + auto module = sol::state_view(state)["!this"].get(); + + static size_t name_i = 0; + std::string job_name = module->module_name() + std::to_string(name_i++); + + // We make a new script for lua state destruction timing purposes, see lua_module dctor for more info. + std::unique_ptr lua_script = std::make_unique( + [func_, state]() mutable { + sol::thread t = sol::thread::create(state); + sol::coroutine func = sol::coroutine(t.state(), func_); + + while (big::g_running) + { + auto res = func(dummy_script_util); + + if (!res.valid()) + big::g_lua_manager->handle_error(res, res.lua_state()); + + if (func.runnable()) + { + big::script::get_current()->yield(std::chrono::milliseconds(res.return_count() ? res[0] : 0)); + } + else + { + big::g_script_mgr.remove_script(big::script::get_current()); + break; + } + } + }, + job_name); + + const auto registered_script = big::g_script_mgr.add_script(std::move(lua_script)); + + module->m_registered_scripts.push_back(registered_script); + } + + void bind(sol::state& state) + { + auto ns = state["script"].get_or_create(); + ns["register_looped"] = register_looped; + ns["run_in_fiber"] = run_in_fiber; + + auto usertype = state.new_usertype("script_util"); + + usertype["yield"] = sol::yielding(&script_util::yield); + usertype["sleep"] = sol::yielding(&script_util::sleep); + } +} \ No newline at end of file diff --git a/src/lua/bindings/script.hpp b/src/lua/bindings/script.hpp index 03c37d2e..b316154e 100644 --- a/src/lua/bindings/script.hpp +++ b/src/lua/bindings/script.hpp @@ -1,8 +1,5 @@ #pragma once -#include "fiber_pool.hpp" -#include "lua/lua_manager.hpp" -#include "lua/lua_module.hpp" -#include "script_mgr.hpp" +#include "lua/sol.hpp" namespace lua::script { @@ -20,164 +17,15 @@ namespace lua::script // Class: script_util // Name: yield // Yield execution. - int yield() - { - return 0; - } + int yield(); // Lua API: Function // Class: script_util // Name: sleep // Param: ms: integer: The amount of time in milliseconds that we will sleep for. // Sleep for the given amount of time, time is in milliseconds. - int sleep(int ms) - { - return ms; - } + int sleep(int ms); }; - static script_util dummy_script_util; - // Lua API: Table - // Name: script - // Table containing helper functions related to gta scripts. - - // Lua API: Function - // Table: script - // Name: register_looped - // Param: name: string: name of your new looped script - // Param: func: function: function that will be executed in a forever loop. - // Registers a function that will be looped as a gta script. - // **Example Usage:** - // ```lua - // script.register_looped("nameOfMyLoopedScript", function (script) - // -- sleep until next game frame - // script:yield() - // - // local ModelHash = joaat("adder") - // if not STREAMING.IS_MODEL_IN_CDIMAGE(ModelHash) then return end - // STREAMING.REQUEST_MODEL(ModelHash) -- Request the model - // while not STREAMING.HAS_MODEL_LOADED(ModelHash) do -- Waits for the model to load - // script:yield() - // end - // local myPed = PLAYER.PLAYER_PED_ID() - // local myCoords = ENTITY.GET_ENTITY_COORDS(myPed, true) - // -- Spawns a networked vehicle on your current coords - // local spawnedVehicle = VEHICLE.CREATE_VEHICLE(ModelHash, myCoords.x, myCoords.y, myCoords.z, ENTITY.GET_ENTITY_HEADING(myPed), true, false) - // -- removes model from game memory as we no longer need it - // STREAMING.SET_MODEL_AS_NO_LONGER_NEEDED(ModelHash) - // -- sleep for 2s - // script:sleep(2000) - // ENTITY.DELETE_ENTITY(spawnedVehicle) - // end) - // ``` - static void register_looped(const std::string& name, sol::protected_function func_, sol::this_state state) - { - auto module = sol::state_view(state)["!this"].get(); - - std::unique_ptr lua_script = std::make_unique( - [func_, state]() mutable { - sol::thread t = sol::thread::create(state); - sol::coroutine func = sol::coroutine(t.state(), func_); - - while (big::g_running) - { - auto res = func(dummy_script_util); - - if (!res.valid()) - big::g_lua_manager->handle_error(res, res.lua_state()); - - if (func.runnable()) - { - big::script::get_current()->yield(std::chrono::milliseconds(res.return_count() ? res[0] : 0)); - } - else - { - big::script::get_current()->yield(); - } - } - }, - name); - - const auto registered_script = big::g_script_mgr.add_script(std::move(lua_script)); - - module->m_registered_scripts.push_back(registered_script); - } - - // Lua API: Function - // Table: script - // Name: run_in_fiber - // Param: func: function: function that will be executed once in the fiber pool. - // Executes a function once inside the fiber pool, you can call natives inside it and yield or sleep. - // **Example Usage:** - // ```lua - // script.run_in_fiber(function (script) - // -- sleep until next game frame - // script:yield() - // - // local ModelHash = joaat("adder") - // if not STREAMING.IS_MODEL_IN_CDIMAGE(ModelHash) then return end - // STREAMING.REQUEST_MODEL(ModelHash) -- Request the model - // while not STREAMING.HAS_MODEL_LOADED(ModelHash) do -- Waits for the model to load - // script:yield() - // end - // local myPed = PLAYER.PLAYER_PED_ID() - // local myCoords = ENTITY.GET_ENTITY_COORDS(myPed, true) - // -- Spawns a networked vehicle on your current coords - // local spawnedVehicle = VEHICLE.CREATE_VEHICLE(ModelHash, myCoords.x, myCoords.y, myCoords.z, ENTITY.GET_ENTITY_HEADING(myPed), true, false) - // -- removes model from game memory as we no longer need it - // STREAMING.SET_MODEL_AS_NO_LONGER_NEEDED(ModelHash) - // -- sleep for 2s - // script:sleep(2000) - // ENTITY.DELETE_ENTITY(spawnedVehicle) - // end) - // ``` - static void run_in_fiber(sol::protected_function func_, sol::this_state state) - { - auto module = sol::state_view(state)["!this"].get(); - - static size_t name_i = 0; - std::string job_name = module->module_name() + std::to_string(name_i++); - - // We make a new script for lua state destruction timing purposes, see lua_module dctor for more info. - std::unique_ptr lua_script = std::make_unique( - [func_, state]() mutable { - sol::thread t = sol::thread::create(state); - sol::coroutine func = sol::coroutine(t.state(), func_); - - while (big::g_running) - { - auto res = func(dummy_script_util); - - if (!res.valid()) - big::g_lua_manager->handle_error(res, res.lua_state()); - - if (func.runnable()) - { - big::script::get_current()->yield(std::chrono::milliseconds(res.return_count() ? res[0] : 0)); - } - else - { - big::g_script_mgr.remove_script(big::script::get_current()); - break; - } - } - }, - job_name); - - const auto registered_script = big::g_script_mgr.add_script(std::move(lua_script)); - - module->m_registered_scripts.push_back(registered_script); - } - - static void bind(sol::state& state) - { - auto ns = state["script"].get_or_create(); - ns["register_looped"] = register_looped; - ns["run_in_fiber"] = run_in_fiber; - - state.new_usertype("script_util"); - - state["script_util"]["yield"] = sol::yielding(&script_util::yield); - state["script_util"]["sleep"] = sol::yielding(&script_util::sleep); - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/tunables.cpp b/src/lua/bindings/tunables.cpp new file mode 100644 index 00000000..48e6b17f --- /dev/null +++ b/src/lua/bindings/tunables.cpp @@ -0,0 +1,17 @@ +#pragma once +#include "../../script.hpp" +#include "tunables.hpp" + +namespace lua::tunables +{ + void bind(sol::state& state) + { + auto ns = state["tunables"].get_or_create(); + ns["get_int"] = get; + ns["get_float"] = get; + ns["get_bool"] = get; + ns["set_int"] = set; + ns["set_float"] = set; + ns["set_bool"] = set; + } +} \ No newline at end of file diff --git a/src/lua/bindings/tunables.hpp b/src/lua/bindings/tunables.hpp index 0e4acfda..d9c6b0c0 100644 --- a/src/lua/bindings/tunables.hpp +++ b/src/lua/bindings/tunables.hpp @@ -26,7 +26,7 @@ namespace lua::tunables // Returns: boolean: The value of the given tunable. template - static T get(const std::string tunable_name) + T get(const std::string tunable_name) { if (auto tunable = big::g_tunables_service->get_tunable(rage::joaat(tunable_name))) return *tunable; @@ -53,19 +53,10 @@ namespace lua::tunables // Param: val: boolean: The new value of the given tunable. template - static void set(const std::string tunable_name, T val) + void set(const std::string tunable_name, T val) { big::g_tunables_service->set_tunable(rage::joaat(tunable_name), val); } - static void bind(sol::state& state) - { - auto ns = state["tunables"].get_or_create(); - ns["get_int"] = get; - ns["get_float"] = get; - ns["get_bool"] = get; - ns["set_int"] = set; - ns["set_float"] = set; - ns["set_bool"] = set; - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/bindings/vector.cpp b/src/lua/bindings/vector.cpp new file mode 100644 index 00000000..cd9d3e9a --- /dev/null +++ b/src/lua/bindings/vector.cpp @@ -0,0 +1,15 @@ +#pragma once +#include "vector.hpp" + +namespace lua::vector +{ + void bind(sol::state& state) + { + auto usertype = state.new_usertype("vec3", sol::constructors()); + + usertype["x"] = &Vector3::x; + usertype["y"] = &Vector3::y; + usertype["z"] = &Vector3::z; + usertype["__tostring"] = &Vector3::to_string; + } +} \ No newline at end of file diff --git a/src/lua/bindings/vector.hpp b/src/lua/bindings/vector.hpp index aa751d41..3fe34593 100644 --- a/src/lua/bindings/vector.hpp +++ b/src/lua/bindings/vector.hpp @@ -29,14 +29,5 @@ namespace lua::vector // Field: z: float // z component of the vector. - static void bind(sol::state& state) - { - //clang-format off - state.new_usertype("vec3", - sol::constructors(), - "x", &Vector3::x, "y", &Vector3::y, "z", &Vector3::z, - "__tostring", &Vector3::to_string - ); - //clang-format on - } + void bind(sol::state& state); } \ No newline at end of file diff --git a/src/lua/lua_manager.cpp b/src/lua/lua_manager.cpp index 4bc70805..f03d8b89 100644 --- a/src/lua/lua_manager.cpp +++ b/src/lua/lua_manager.cpp @@ -99,7 +99,7 @@ namespace big if (module->module_id() == id) return; - m_modules.push_back(std::make_shared(module_name)); + m_modules.push_back(std::make_shared(module_name, m_scripts_folder)); } void lua_manager::reload_changed_scripts() diff --git a/src/lua/lua_module.cpp b/src/lua/lua_module.cpp index fe50b815..0367ecb8 100644 --- a/src/lua/lua_module.cpp +++ b/src/lua/lua_module.cpp @@ -56,7 +56,7 @@ namespace big // When this function exits, Lua will exhibit default behavior and abort() } - lua_module::lua_module(std::string module_name) : + lua_module::lua_module(std::string module_name, folder& scripts_folder) : m_module_name(module_name), m_module_id(rage::joaat(module_name)) { @@ -78,7 +78,7 @@ namespace big ); // clang-format on - init_lua_api(); + init_lua_api(scripts_folder); state["!module_name"] = module_name; state["!this"] = this; @@ -86,7 +86,7 @@ namespace big state.set_exception_handler(exception_handler); state.set_panic(sol::c_call); - const auto script_file_path = g_lua_manager->get_scripts_folder().get_file(module_name).get_path(); + const auto script_file_path = scripts_folder.get_file(module_name).get_path(); m_last_write_time = std::filesystem::last_write_time(script_file_path); auto result = state.safe_script_file(script_file_path.string(), &sol::script_pass_on_error, sol::load_mode::text); @@ -137,11 +137,11 @@ namespace big return m_last_write_time; } - void lua_module::set_folder_for_lua_require() + void lua_module::set_folder_for_lua_require(folder& scripts_folder) { auto& state = *m_state; - const auto scripts_search_path = g_lua_manager->get_scripts_folder().get_path() / "?.lua"; + const auto scripts_search_path = scripts_folder.get_path() / "?.lua"; state["package"]["path"] = scripts_search_path.string(); } @@ -171,7 +171,7 @@ namespace big }; } - void lua_module::sandbox_lua_loads() + void lua_module::sandbox_lua_loads(folder& scripts_folder) { auto& state = *m_state; @@ -191,17 +191,17 @@ namespace big state["package"]["searchers"][3] = not_supported_lua_function("package.searcher C"); state["package"]["searchers"][4] = not_supported_lua_function("package.searcher Croot"); - set_folder_for_lua_require(); + set_folder_for_lua_require(scripts_folder); } - void lua_module::init_lua_api() + void lua_module::init_lua_api(folder& scripts_folder) { auto& state = *m_state; // https://blog.rubenwardy.com/2020/07/26/sol3-script-sandbox/ // https://www.lua.org/manual/5.4/manual.html#pdf-require sandbox_lua_os_library(); - sandbox_lua_loads(); + sandbox_lua_loads(scripts_folder); lua::log::bind(state); lua::globals::bind(state); diff --git a/src/lua/lua_module.hpp b/src/lua/lua_module.hpp index ec97d932..8aa09cbf 100644 --- a/src/lua/lua_module.hpp +++ b/src/lua/lua_module.hpp @@ -31,7 +31,7 @@ namespace big std::unordered_map> m_event_callbacks; std::vector m_allocated_memory; - lua_module(std::string module_name); + lua_module(std::string module_name, folder& scripts_folder); ~lua_module(); rage::joaat_t module_id() const; @@ -39,11 +39,11 @@ namespace big const std::chrono::time_point last_write_time() const; // used for sandboxing and limiting to only our custom search path for the lua require function - void set_folder_for_lua_require(); + void set_folder_for_lua_require(folder& scripts_folder); void sandbox_lua_os_library(); - void sandbox_lua_loads(); + void sandbox_lua_loads(folder& scripts_folder); - void init_lua_api(); + void init_lua_api(folder& scripts_folder); }; } \ No newline at end of file diff --git a/src/lua/natives/lua_native_binding.cpp b/src/lua/natives/lua_native_binding.cpp index 3985236d..8e1ebedb 100644 --- a/src/lua/natives/lua_native_binding.cpp +++ b/src/lua/natives/lua_native_binding.cpp @@ -1,5 +1,4 @@ #include "lua_native_binding.hpp" -#include "natives.hpp" namespace lua::native { diff --git a/src/lua/natives/natives_gen.py b/src/lua/natives/natives_gen.py index d56bd996..de3ecee9 100644 --- a/src/lua/natives/natives_gen.py +++ b/src/lua/natives/natives_gen.py @@ -237,7 +237,6 @@ def generate_native_binding_cpp_and_hpp_files(functions_per_namespaces): print_hpp("}") print_cpp('#include "lua_native_binding.hpp"') - print_cpp('#include "natives.hpp"') print_cpp("") print_cpp("namespace lua::native") print_cpp("{")