Lua Scripting (#1334)
Closes #83 Fixes #1309 Fixes #1287 Fixes #1129 (actually fixed now)
This commit is contained in:
41
src/lua/bindings/command.hpp
Normal file
41
src/lua/bindings/command.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "backend/command.hpp"
|
||||
#include "backend/player_command.hpp"
|
||||
#include "network.hpp" // for convert_sequence
|
||||
|
||||
namespace lua::command
|
||||
{
|
||||
static void call(const std::string& command_name, std::optional<sol::table> _args)
|
||||
{
|
||||
auto args = convert_sequence<uint64_t>(_args.value_or(sol::table()));
|
||||
|
||||
auto command = big::command::get(rage::joaat(command_name));
|
||||
|
||||
if (command)
|
||||
command->call(args, {});
|
||||
}
|
||||
|
||||
static void call_player(int player_idx, const std::string& command_name, std::optional<sol::table> _args)
|
||||
{
|
||||
auto args = convert_sequence<uint64_t>(_args.value_or(sol::table()));
|
||||
|
||||
auto command = (big::player_command*)big::command::get(rage::joaat(command_name));
|
||||
|
||||
if (command)
|
||||
{
|
||||
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<sol::table>();
|
||||
ns["call"] = call;
|
||||
ns["call_player"] = call_player;
|
||||
}
|
||||
}
|
23
src/lua/bindings/event.hpp
Normal file
23
src/lua/bindings/event.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "fiber_pool.hpp"
|
||||
#include "lua/lua_module.hpp"
|
||||
#include "script_mgr.hpp"
|
||||
|
||||
namespace lua::event
|
||||
{
|
||||
static void register_handler(const std::string& name, sol::function func, sol::this_state state)
|
||||
{
|
||||
auto module = sol::state_view(state)["!this"].get<big::lua_module*>();
|
||||
|
||||
auto hash = rage::joaat(name);
|
||||
module->m_event_callbacks.emplace(hash, std::vector<sol::function>());
|
||||
module->m_event_callbacks[hash].push_back(func);
|
||||
}
|
||||
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["event"].get_or_create<sol::table>();
|
||||
ns["register_handler"] = register_handler;
|
||||
// TODO: triggering events through script?
|
||||
}
|
||||
}
|
53
src/lua/bindings/globals.hpp
Normal file
53
src/lua/bindings/globals.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include "memory.hpp"
|
||||
#include "script_global.hpp"
|
||||
|
||||
namespace lua::globals
|
||||
{
|
||||
static int get_int(int global)
|
||||
{
|
||||
return *big::script_global(global).as<int*>();
|
||||
}
|
||||
|
||||
static int get_float(int global)
|
||||
{
|
||||
return *big::script_global(global).as<float*>();
|
||||
}
|
||||
|
||||
static std::string get_string(int global)
|
||||
{
|
||||
return std::string(big::script_global(global).as<char*>());
|
||||
}
|
||||
|
||||
static void set_int(int global, int val)
|
||||
{
|
||||
*big::script_global(global).as<int*>() = val;
|
||||
}
|
||||
|
||||
static void set_float(int global, float val)
|
||||
{
|
||||
*big::script_global(global).as<float*>() = val;
|
||||
}
|
||||
|
||||
static void set_string(int global, const std::string& str, int max_length)
|
||||
{
|
||||
strncpy(big::script_global(global).as<char*>(), str.data(), max_length);
|
||||
}
|
||||
|
||||
static memory::pointer get_pointer(int global)
|
||||
{
|
||||
return memory::pointer((uint64_t)big::script_global(global).as<void*>());
|
||||
}
|
||||
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["globals"].get_or_create<sol::table>();
|
||||
ns["get_int"] = get_int;
|
||||
ns["get_float"] = get_float;
|
||||
ns["get_string"] = get_string;
|
||||
ns["set_int"] = set_int;
|
||||
ns["set_float"] = set_float;
|
||||
ns["set_string"] = set_string;
|
||||
ns["get_pointer"] = get_pointer;
|
||||
}
|
||||
}
|
12
src/lua/bindings/gui.cpp
Normal file
12
src/lua/bindings/gui.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "gui.hpp"
|
||||
|
||||
#include "../../gui.hpp"
|
||||
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
bool is_open()
|
||||
{
|
||||
return big::g_gui->is_open();
|
||||
}
|
||||
}
|
178
src/lua/bindings/gui.hpp
Normal file
178
src/lua/bindings/gui.hpp
Normal file
@ -0,0 +1,178 @@
|
||||
#pragma once
|
||||
#include "gui/button.hpp"
|
||||
#include "gui/checkbox.hpp"
|
||||
#include "gui/gui_element.hpp"
|
||||
#include "gui/input_float.hpp"
|
||||
#include "gui/input_int.hpp"
|
||||
#include "gui/input_string.hpp"
|
||||
#include "gui/sameline.hpp"
|
||||
#include "gui/separator.hpp"
|
||||
#include "gui/text.hpp"
|
||||
#include "lua/lua_module.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
static void add_element(lua_State* state, std::uint32_t hash, std::shared_ptr<lua::gui::gui_element> element)
|
||||
{
|
||||
auto module = sol::state_view(state)["!this"].get<big::lua_module*>();
|
||||
|
||||
if (!module->m_gui.contains(hash))
|
||||
module->m_gui[hash] = {};
|
||||
|
||||
module->m_gui[hash].push_back(std::move(element));
|
||||
}
|
||||
|
||||
class tab
|
||||
{
|
||||
rage::joaat_t m_tab_hash;
|
||||
|
||||
public:
|
||||
tab(rage::joaat_t hash) :
|
||||
m_tab_hash(hash)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<lua::gui::button> add_button(const std::string& name, sol::function callback, sol::this_state state)
|
||||
{
|
||||
auto element = std::make_shared<lua::gui::button>(name, callback);
|
||||
add_element(state, m_tab_hash, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
std::shared_ptr<lua::gui::text> add_text(const std::string& name, sol::this_state state)
|
||||
{
|
||||
auto element = std::make_shared<lua::gui::text>(name);
|
||||
add_element(state, m_tab_hash, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
std::shared_ptr<lua::gui::checkbox> add_checkbox(const std::string& name, sol::this_state state)
|
||||
{
|
||||
auto element = std::make_shared<lua::gui::checkbox>(name);
|
||||
add_element(state, m_tab_hash, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
std::shared_ptr<lua::gui::sameline> add_sameline(sol::this_state state)
|
||||
{
|
||||
auto element = std::make_shared<lua::gui::sameline>();
|
||||
add_element(state, m_tab_hash, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
std::shared_ptr<lua::gui::separator> add_separator(sol::this_state state)
|
||||
{
|
||||
auto element = std::make_shared<lua::gui::separator>();
|
||||
add_element(state, m_tab_hash, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
std::shared_ptr<lua::gui::input_int> add_input_int(const std::string& name, sol::this_state state)
|
||||
{
|
||||
auto element = std::make_shared<lua::gui::input_int>(name);
|
||||
add_element(state, m_tab_hash, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
std::shared_ptr<lua::gui::input_float> add_input_float(const std::string& name, sol::this_state state)
|
||||
{
|
||||
auto element = std::make_shared<lua::gui::input_float>(name);
|
||||
add_element(state, m_tab_hash, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
std::shared_ptr<lua::gui::input_string> add_input_string(const std::string& name, sol::this_state state)
|
||||
{
|
||||
auto element = std::make_shared<lua::gui::input_string>(name);
|
||||
add_element(state, m_tab_hash, element);
|
||||
return element;
|
||||
}
|
||||
};
|
||||
|
||||
static tab get_tab(const std::string& tab_name)
|
||||
{
|
||||
return tab(rage::joaat(tab_name));
|
||||
}
|
||||
|
||||
static void show_message(const std::string& title, const std::string& message)
|
||||
{
|
||||
big::g_notification_service->push(title, message);
|
||||
}
|
||||
|
||||
static void show_warning(const std::string& title, const std::string& message)
|
||||
{
|
||||
big::g_notification_service->push_warning(title, message);
|
||||
}
|
||||
|
||||
static void show_error(const std::string& title, const std::string& message)
|
||||
{
|
||||
big::g_notification_service->push_error(title, message);
|
||||
}
|
||||
|
||||
bool is_open();
|
||||
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["gui"].get_or_create<sol::table>();
|
||||
ns["get_tab"] = get_tab;
|
||||
ns["show_message"] = show_message;
|
||||
ns["show_warning"] = show_warning;
|
||||
ns["show_error"] = show_error;
|
||||
ns["is_open"] = is_open;
|
||||
|
||||
// clang-format off
|
||||
ns.new_usertype<lua::gui::button>("button",
|
||||
"set_text", &lua::gui::button::set_text,
|
||||
"get_text", &lua::gui::button::get_text
|
||||
);
|
||||
|
||||
ns.new_usertype<lua::gui::text>("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<lua::gui::checkbox>("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<lua::gui::sameline>("sameline");
|
||||
ns.new_usertype<lua::gui::separator>("separator");
|
||||
|
||||
ns.new_usertype<lua::gui::input_int>("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<lua::gui::input_float>("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<lua::gui::input_string>("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>("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
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
}
|
19
src/lua/bindings/gui/base_text_element.cpp
Normal file
19
src/lua/bindings/gui/base_text_element.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "base_text_element.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
base_text_element::base_text_element(std::string text) :
|
||||
m_text(text)
|
||||
{
|
||||
}
|
||||
|
||||
void base_text_element::set_text(std::string new_text)
|
||||
{
|
||||
m_text = new_text;
|
||||
}
|
||||
|
||||
std::string base_text_element::get_text()
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
}
|
17
src/lua/bindings/gui/base_text_element.hpp
Normal file
17
src/lua/bindings/gui/base_text_element.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "gui_element.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class base_text_element : public gui_element
|
||||
{
|
||||
protected:
|
||||
std::string m_text;
|
||||
|
||||
public:
|
||||
base_text_element(std::string text);
|
||||
|
||||
void set_text(std::string new_text);
|
||||
std::string get_text();
|
||||
};
|
||||
}
|
34
src/lua/bindings/gui/button.cpp
Normal file
34
src/lua/bindings/gui/button.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "button.hpp"
|
||||
|
||||
#include "fiber_pool.hpp"
|
||||
#include "lua/lua_manager.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
button::button(std::string text, sol::function callback) :
|
||||
base_text_element(text),
|
||||
m_callback(callback)
|
||||
{
|
||||
}
|
||||
|
||||
void button::draw()
|
||||
{
|
||||
if (ImGui::Button(m_text.data()))
|
||||
{
|
||||
if (m_execute_in_fiber_pool)
|
||||
{
|
||||
big::g_fiber_pool->queue_job([this] {
|
||||
auto res = m_callback();
|
||||
if (!res.valid())
|
||||
big::g_lua_manager->handle_error(res, res.lua_state());
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
auto res = m_callback();
|
||||
if (!res.valid())
|
||||
big::g_lua_manager->handle_error(res, res.lua_state());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
src/lua/bindings/gui/button.hpp
Normal file
17
src/lua/bindings/gui/button.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "base_text_element.hpp"
|
||||
#include "lua/sol.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class button : public base_text_element
|
||||
{
|
||||
sol::function m_callback;
|
||||
bool m_execute_in_fiber_pool = true;
|
||||
|
||||
public:
|
||||
button(std::string text, sol::function callback);
|
||||
|
||||
void draw() override;
|
||||
};
|
||||
}
|
24
src/lua/bindings/gui/checkbox.cpp
Normal file
24
src/lua/bindings/gui/checkbox.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "checkbox.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
checkbox::checkbox(std::string text) :
|
||||
base_text_element(text)
|
||||
{
|
||||
}
|
||||
|
||||
void checkbox::draw()
|
||||
{
|
||||
ImGui::Checkbox(m_text.data(), &m_enabled);
|
||||
}
|
||||
|
||||
bool checkbox::is_enabled()
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void checkbox::set_enabled(bool enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
}
|
||||
}
|
18
src/lua/bindings/gui/checkbox.hpp
Normal file
18
src/lua/bindings/gui/checkbox.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "base_text_element.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class checkbox : public base_text_element
|
||||
{
|
||||
bool m_enabled = false;
|
||||
|
||||
public:
|
||||
checkbox(std::string text);
|
||||
|
||||
void draw() override;
|
||||
|
||||
bool is_enabled();
|
||||
void set_enabled(bool enabled);
|
||||
};
|
||||
}
|
10
src/lua/bindings/gui/gui_element.hpp
Normal file
10
src/lua/bindings/gui/gui_element.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class gui_element
|
||||
{
|
||||
public:
|
||||
virtual void draw() = 0;
|
||||
};
|
||||
}
|
24
src/lua/bindings/gui/input_float.cpp
Normal file
24
src/lua/bindings/gui/input_float.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "input_float.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
input_float::input_float(std::string text) :
|
||||
base_text_element(text)
|
||||
{
|
||||
}
|
||||
|
||||
void input_float::draw()
|
||||
{
|
||||
ImGui::InputFloat(m_text.c_str(), &m_value);
|
||||
}
|
||||
|
||||
int input_float::get_value()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void input_float::set_value(float val)
|
||||
{
|
||||
m_value = val;
|
||||
}
|
||||
}
|
19
src/lua/bindings/gui/input_float.hpp
Normal file
19
src/lua/bindings/gui/input_float.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "base_text_element.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class input_float : public base_text_element
|
||||
{
|
||||
bool m_enabled = false;
|
||||
float m_value = 0;
|
||||
|
||||
public:
|
||||
input_float(std::string text);
|
||||
|
||||
void draw() override;
|
||||
|
||||
int get_value();
|
||||
void set_value(float val);
|
||||
};
|
||||
}
|
24
src/lua/bindings/gui/input_int.cpp
Normal file
24
src/lua/bindings/gui/input_int.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "input_int.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
input_int::input_int(std::string text) :
|
||||
base_text_element(text)
|
||||
{
|
||||
}
|
||||
|
||||
void input_int::draw()
|
||||
{
|
||||
ImGui::InputInt(m_text.c_str(), &m_value);
|
||||
}
|
||||
|
||||
int input_int::get_value()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void input_int::set_value(int val)
|
||||
{
|
||||
m_value = val;
|
||||
}
|
||||
}
|
19
src/lua/bindings/gui/input_int.hpp
Normal file
19
src/lua/bindings/gui/input_int.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "base_text_element.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class input_int : public base_text_element
|
||||
{
|
||||
bool m_enabled = false;
|
||||
int m_value = 0;
|
||||
|
||||
public:
|
||||
input_int(std::string text);
|
||||
|
||||
void draw() override;
|
||||
|
||||
int get_value();
|
||||
void set_value(int val);
|
||||
};
|
||||
}
|
24
src/lua/bindings/gui/input_string.cpp
Normal file
24
src/lua/bindings/gui/input_string.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "input_string.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
input_string::input_string(std::string text) :
|
||||
base_text_element(text)
|
||||
{
|
||||
}
|
||||
|
||||
void input_string::draw()
|
||||
{
|
||||
ImGui::InputText(m_text.c_str(), m_value, sizeof(m_value));
|
||||
}
|
||||
|
||||
std::string input_string::get_value()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void input_string::set_value(std::string val)
|
||||
{
|
||||
strncpy(m_value, val.c_str(), sizeof(m_value));
|
||||
}
|
||||
}
|
19
src/lua/bindings/gui/input_string.hpp
Normal file
19
src/lua/bindings/gui/input_string.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "base_text_element.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class input_string : public base_text_element
|
||||
{
|
||||
bool m_enabled = false;
|
||||
char m_value[255] = {};
|
||||
|
||||
public:
|
||||
input_string(std::string text);
|
||||
|
||||
void draw() override;
|
||||
|
||||
std::string get_value();
|
||||
void set_value(std::string val);
|
||||
};
|
||||
}
|
9
src/lua/bindings/gui/sameline.cpp
Normal file
9
src/lua/bindings/gui/sameline.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "sameline.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
void sameline::draw()
|
||||
{
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
13
src/lua/bindings/gui/sameline.hpp
Normal file
13
src/lua/bindings/gui/sameline.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "gui_element.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class sameline : public gui_element
|
||||
{
|
||||
public:
|
||||
sameline(){};
|
||||
|
||||
void draw() override;
|
||||
};
|
||||
}
|
9
src/lua/bindings/gui/separator.cpp
Normal file
9
src/lua/bindings/gui/separator.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "separator.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
void separator::draw()
|
||||
{
|
||||
ImGui::Separator();
|
||||
}
|
||||
}
|
13
src/lua/bindings/gui/separator.hpp
Normal file
13
src/lua/bindings/gui/separator.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "gui_element.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class separator : public gui_element
|
||||
{
|
||||
public:
|
||||
separator(){};
|
||||
|
||||
void draw() override;
|
||||
};
|
||||
}
|
32
src/lua/bindings/gui/text.cpp
Normal file
32
src/lua/bindings/gui/text.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "text.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
text::text(std::string text) :
|
||||
base_text_element(text)
|
||||
{
|
||||
}
|
||||
|
||||
void text::draw()
|
||||
{
|
||||
if (m_font)
|
||||
ImGui::PushFont(m_font);
|
||||
ImGui::Text(m_text.data());
|
||||
if (m_font)
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
void text::set_font(std::string font)
|
||||
{
|
||||
auto hash = rage::joaat(font);
|
||||
|
||||
switch (hash)
|
||||
{
|
||||
case RAGE_JOAAT("title"): m_font = big::g.window.font_title; break;
|
||||
case RAGE_JOAAT("subtitle"): m_font = big::g.window.font_sub_title; break;
|
||||
case RAGE_JOAAT("small"): m_font = big::g.window.font_small; break;
|
||||
case RAGE_JOAAT("icon"): m_font = big::g.window.font_icon; break;
|
||||
default: m_font = nullptr; break;
|
||||
}
|
||||
}
|
||||
}
|
17
src/lua/bindings/gui/text.hpp
Normal file
17
src/lua/bindings/gui/text.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "base_text_element.hpp"
|
||||
#include "lua/sol.hpp"
|
||||
|
||||
namespace lua::gui
|
||||
{
|
||||
class text : public base_text_element
|
||||
{
|
||||
ImFont* m_font = nullptr;
|
||||
|
||||
public:
|
||||
text(std::string text);
|
||||
|
||||
void draw() override;
|
||||
void set_font(std::string font);
|
||||
};
|
||||
}
|
53
src/lua/bindings/locals.hpp
Normal file
53
src/lua/bindings/locals.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include "gta_util.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "script_local.hpp"
|
||||
|
||||
namespace lua::locals
|
||||
{
|
||||
template<typename T>
|
||||
inline T get(const std::string& script, int index)
|
||||
{
|
||||
static std::remove_pointer_t<T> null{};
|
||||
auto thread = big::gta_util::find_script_thread(rage::joaat(script));
|
||||
if (thread)
|
||||
return big::script_local(thread->m_stack, index).as<T>();
|
||||
|
||||
return &null;
|
||||
}
|
||||
|
||||
static int get_int(const std::string& script, int index)
|
||||
{
|
||||
return *get<int*>(script, index);
|
||||
}
|
||||
|
||||
static int get_float(const std::string& script, int index)
|
||||
{
|
||||
return *get<float*>(script, index);
|
||||
}
|
||||
|
||||
static void set_int(const std::string& script, int index, int val)
|
||||
{
|
||||
*get<int*>(script, index) = val;
|
||||
}
|
||||
|
||||
static void set_float(const std::string& script, int index, float val)
|
||||
{
|
||||
*get<float*>(script, index) = val;
|
||||
}
|
||||
|
||||
static memory::pointer get_pointer(const std::string& script, int index)
|
||||
{
|
||||
return memory::pointer((uint64_t)get<int*>(script, index));
|
||||
}
|
||||
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["locals"].get_or_create<sol::table>();
|
||||
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;
|
||||
}
|
||||
}
|
27
src/lua/bindings/log.hpp
Normal file
27
src/lua/bindings/log.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
namespace lua::log
|
||||
{
|
||||
static void info(const std::string& data, sol::this_state state)
|
||||
{
|
||||
LOG(INFO) << sol::state_view(state)["!module_name"].get<std::string>() << ": " << data;
|
||||
}
|
||||
|
||||
static void warning(const std::string& data, sol::this_state state)
|
||||
{
|
||||
LOG(WARNING) << sol::state_view(state)["!module_name"].get<std::string>() << ": " << data;
|
||||
}
|
||||
|
||||
static void debug(const std::string& data, sol::this_state state)
|
||||
{
|
||||
LOG(VERBOSE) << sol::state_view(state)["!module_name"].get<std::string>() << ": " << data;
|
||||
}
|
||||
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["log"].get_or_create<sol::table>();
|
||||
ns["info"] = info;
|
||||
ns["warning"] = warning;
|
||||
ns["debug"] = debug;
|
||||
}
|
||||
}
|
44
src/lua/bindings/memory.cpp
Normal file
44
src/lua/bindings/memory.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "memory.hpp"
|
||||
|
||||
#include "memory/module.hpp"
|
||||
#include "memory/pattern.hpp"
|
||||
#include "pointers.hpp"
|
||||
|
||||
namespace lua::memory
|
||||
{
|
||||
pointer scan_pattern(const std::string& pattern)
|
||||
{
|
||||
return pointer(::memory::module("GTA5.exe").scan(::memory::pattern(pattern)).value().as<uint64_t>());
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (mem_addr.is_null())
|
||||
return 0;
|
||||
|
||||
return big::g_pointers->m_gta.m_ptr_to_handle((void*)mem_addr.get_address());
|
||||
}
|
||||
|
||||
pointer allocate(int size, sol::this_state state)
|
||||
{
|
||||
void* mem = new uint8_t[](size);
|
||||
auto module = sol::state_view(state)["!this"].get<big::lua_module*>();
|
||||
module->m_allocated_memory.push_back(mem);
|
||||
return pointer((uint64_t)mem);
|
||||
}
|
||||
|
||||
void free(pointer ptr, sol::this_state state)
|
||||
{
|
||||
delete[] (void*)ptr.get_address();
|
||||
auto module = sol::state_view(state)["!this"].get<big::lua_module*>();
|
||||
std::erase_if(module->m_allocated_memory, [ptr](void* addr) {
|
||||
return ptr.get_address() == (uint64_t)addr;
|
||||
});
|
||||
}
|
||||
}
|
142
src/lua/bindings/memory.hpp
Normal file
142
src/lua/bindings/memory.hpp
Normal file
@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
#include "lua/lua_module.hpp"
|
||||
#include "lua/lua_patch.hpp"
|
||||
#include "lua/sol.hpp"
|
||||
#include "memory/byte_patch.hpp"
|
||||
|
||||
namespace lua::memory
|
||||
{
|
||||
struct pointer
|
||||
{
|
||||
private:
|
||||
std::uint64_t m_address;
|
||||
|
||||
public:
|
||||
explicit pointer(std::uint64_t address) :
|
||||
m_address(address)
|
||||
{
|
||||
}
|
||||
|
||||
explicit pointer() :
|
||||
m_address(0)
|
||||
{
|
||||
}
|
||||
|
||||
pointer add(uint64_t offset)
|
||||
{
|
||||
return pointer(m_address + offset);
|
||||
}
|
||||
|
||||
pointer sub(uint64_t offset)
|
||||
{
|
||||
return pointer(m_address - offset);
|
||||
}
|
||||
|
||||
pointer rip()
|
||||
{
|
||||
return add(*(std::int32_t*)m_address).add(4);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T get()
|
||||
{
|
||||
return *(T*)m_address;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set(T value)
|
||||
{
|
||||
*(T*)m_address = value;
|
||||
}
|
||||
|
||||
std::string get_string()
|
||||
{
|
||||
return std::string((char*)m_address);
|
||||
}
|
||||
|
||||
void set_string(const std::string& string, int max_length)
|
||||
{
|
||||
strncpy((char*)m_address, string.data(), max_length);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
big::lua_patch* patch(T value, sol::this_state state)
|
||||
{
|
||||
auto module = sol::state_view(state)["!this"].get<big::lua_module*>();
|
||||
auto patch = std::make_shared<big::lua_patch>(::memory::byte_patch::make((T*)m_address, value).get());
|
||||
auto raw = patch.get();
|
||||
module->m_registered_patches.push_back(std::move(patch));
|
||||
return raw;
|
||||
}
|
||||
|
||||
bool is_null()
|
||||
{
|
||||
return m_address == 0;
|
||||
}
|
||||
|
||||
bool is_valid()
|
||||
{
|
||||
return !is_null();
|
||||
}
|
||||
|
||||
pointer deref()
|
||||
{
|
||||
return pointer(*(uint64_t*)m_address);
|
||||
}
|
||||
|
||||
uint64_t get_address() const
|
||||
{
|
||||
return m_address;
|
||||
}
|
||||
};
|
||||
|
||||
pointer scan_pattern(const std::string& pattern);
|
||||
pointer handle_to_ptr(int entity);
|
||||
int ptr_to_handle(pointer mem_addr);
|
||||
pointer allocate(int size, sol::this_state state);
|
||||
void free(pointer ptr, sol::this_state state);
|
||||
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["memory"].get_or_create<sol::table>();
|
||||
|
||||
// clang-format off
|
||||
ns.new_usertype<pointer>("pointer", sol::constructors<pointer(std::uint64_t)>(),
|
||||
"add", &pointer::add,
|
||||
"sub", &pointer::sub,
|
||||
"rip", &pointer::rip,
|
||||
"get_byte", &pointer::get<uint8_t>,
|
||||
"get_word", &pointer::get<uint16_t>,
|
||||
"get_dword", &pointer::get<uint32_t>,
|
||||
"get_float", &pointer::get<float>,
|
||||
"get_qword", &pointer::get<uint64_t>,
|
||||
"get_string", &pointer::get_string,
|
||||
"set_byte", &pointer::set<uint8_t>,
|
||||
"set_word", &pointer::set<uint16_t>,
|
||||
"set_dword", &pointer::set<uint32_t>,
|
||||
"set_float", &pointer::set<float>,
|
||||
"set_qword", &pointer::set<uint64_t>,
|
||||
"set_string", &pointer::set_string,
|
||||
"patch_byte", &pointer::patch<uint8_t>,
|
||||
"patch_word", &pointer::patch<uint16_t>,
|
||||
"patch_dword", &pointer::patch<uint32_t>,
|
||||
"patch_qword", &pointer::patch<uint64_t>,
|
||||
"is_null", &pointer::is_null,
|
||||
"is_valid", &pointer::is_valid,
|
||||
"deref", &pointer::deref,
|
||||
"get_address", &pointer::get_address
|
||||
);
|
||||
|
||||
ns.new_usertype<big::lua_patch>("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;
|
||||
}
|
||||
}
|
78
src/lua/bindings/native.hpp
Normal file
78
src/lua/bindings/native.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
#include "invoker.hpp"
|
||||
#include "lua/lua_module.hpp"
|
||||
#include "lua/natives/natives_data.hpp"
|
||||
#include "memory.hpp"
|
||||
|
||||
namespace lua::native
|
||||
{
|
||||
template<typename T>
|
||||
T invoke(sol::variadic_args args)
|
||||
{
|
||||
big::g_native_invoker.begin_call();
|
||||
|
||||
for (int i = 1; i < args.size(); i++)
|
||||
{
|
||||
if (args[i].is<memory::pointer>())
|
||||
big::g_native_invoker.push_arg(args[i].get<memory::pointer>().get_address());
|
||||
else if (args[i].is<int>())
|
||||
big::g_native_invoker.push_arg(args[i].get<int>());
|
||||
else if (args[i].is<float>())
|
||||
big::g_native_invoker.push_arg(args[i].get<float>());
|
||||
else if (args[i].is<bool>())
|
||||
big::g_native_invoker.push_arg(args[i].get<bool>());
|
||||
else if (args[i].is<const char*>())
|
||||
big::g_native_invoker.push_arg(args[i].get<const char*>());
|
||||
else if (args[i].is<rage::fvector3>())
|
||||
{
|
||||
auto vec = args[i].get<rage::fvector3>();
|
||||
big::g_native_invoker.push_arg(vec.x);
|
||||
big::g_native_invoker.push_arg(vec.y);
|
||||
big::g_native_invoker.push_arg(vec.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(FATAL) << "Unhandled parameter";
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
big::g_native_invoker.end_call(args[0].as<std::uint64_t>());
|
||||
|
||||
if constexpr (std::is_same_v<T, std::string>)
|
||||
{
|
||||
return std::string(big::g_native_invoker.get_return_value<const char*>());
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, rage::fvector3>)
|
||||
{
|
||||
auto& vec = big::g_native_invoker.get_return_value<Vector3>();
|
||||
return {vec.x, vec.y, vec.z};
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, memory::pointer>)
|
||||
{
|
||||
return memory::pointer(big::g_native_invoker.get_return_value<std::uint64_t>());
|
||||
}
|
||||
else if constexpr (!std::is_void_v<T>)
|
||||
{
|
||||
return big::g_native_invoker.get_return_value<T>();
|
||||
}
|
||||
}
|
||||
|
||||
void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["_natives"].get_or_create<sol::table>();
|
||||
ns["invoke_void"] = invoke<void>;
|
||||
ns["invoke_int"] = invoke<int>;
|
||||
ns["invoke_float"] = invoke<float>;
|
||||
ns["invoke_bool"] = invoke<bool>;
|
||||
ns["invoke_str"] = invoke<std::string>;
|
||||
ns["invoke_vec3"] = invoke<rage::fvector3>;
|
||||
ns["invoke_ptr"] = invoke<memory::pointer>;
|
||||
|
||||
auto result = state.load_buffer(natives_data, natives_size);
|
||||
if (!result.valid())
|
||||
LOG(FATAL) << "Failed to load natives data: " << result.get<sol::error>().what();
|
||||
|
||||
result();
|
||||
}
|
||||
}
|
97
src/lua/bindings/network.cpp
Normal file
97
src/lua/bindings/network.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include "network.hpp"
|
||||
|
||||
#include "hooking.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
#include "util/system.hpp"
|
||||
#include "util/teleport.hpp"
|
||||
|
||||
namespace lua::network
|
||||
{
|
||||
void trigger_script_event(int bitset, sol::table _args)
|
||||
{
|
||||
auto args = convert_sequence<int32_t>(_args);
|
||||
|
||||
if (args.size() >= 1)
|
||||
args[1] = self::id;
|
||||
|
||||
std::vector<std::int64_t> actual_args;
|
||||
|
||||
for (auto arg : args)
|
||||
actual_args.push_back((uint32_t)arg);
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
for (auto& player : big::g_player_service->players())
|
||||
big::g_fiber_pool->queue_job([player, x, y, z]() {
|
||||
big::teleport::teleport_player_to_coords(player.second, {x, y, z});
|
||||
});
|
||||
}
|
||||
|
||||
int get_selected_player()
|
||||
{
|
||||
if (big::g_player_service->get_selected()->is_valid())
|
||||
return big::g_player_service->get_selected()->id();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_selected_database_player_rockstar_id()
|
||||
{
|
||||
if (auto pers = big::g_player_database_service->get_selected())
|
||||
return pers->rockstar_id;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void flag_player_as_modder(int player_idx)
|
||||
{
|
||||
if (auto player = big::g_player_service->get_by_id(player_idx))
|
||||
{
|
||||
auto pers = big::g_player_database_service->get_or_create_player(player);
|
||||
pers->is_modder = true;
|
||||
big::g_player_database_service->save();
|
||||
player->is_modder = true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
big::g_fiber_pool->queue_job([msg, team_only] {
|
||||
if (big::g_hooking->get_original<big::hooks::send_chat_message>()(*big::g_pointers->m_gta.m_send_chat_ptr,
|
||||
big::g_player_service->get_self()->get_net_data(),
|
||||
(char*)msg.c_str(),
|
||||
team_only))
|
||||
big::notify::draw_chat((char*)msg.data(), big::g_player_service->get_self()->get_name(), team_only);
|
||||
});
|
||||
}
|
||||
}
|
48
src/lua/bindings/network.hpp
Normal file
48
src/lua/bindings/network.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include "lua/sol.hpp"
|
||||
|
||||
// https://stackoverflow.com/a/40777268
|
||||
/**
|
||||
* Convert a Lua sequence into a C++ vector
|
||||
* Throw exception on errors or wrong types
|
||||
*/
|
||||
template<typename elementType>
|
||||
inline std::vector<elementType> convert_sequence(sol::table t)
|
||||
{
|
||||
std::size_t sz = t.size();
|
||||
std::vector<elementType> res(sz);
|
||||
for (int i = 1; i <= sz; i++)
|
||||
{
|
||||
res[i - 1] = t[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace lua::network
|
||||
{
|
||||
void trigger_script_event(int bitset, sol::table _args);
|
||||
void give_pickup_rewards(int player, int reward);
|
||||
void set_player_coords(int player_idx, float x, float y, float z);
|
||||
void set_all_player_coords(float x, float y, float z);
|
||||
int get_selected_player();
|
||||
int get_selected_database_player_rockstar_id();
|
||||
void flag_player_as_modder(int player_idx);
|
||||
bool is_player_flagged_as_modder(int player_idx);
|
||||
void force_script_host(const std::string& script_name);
|
||||
void send_chat_message(const std::string& msg, bool team_only);
|
||||
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["network"].get_or_create<sol::table>();
|
||||
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;
|
||||
}
|
||||
}
|
54
src/lua/bindings/script.hpp
Normal file
54
src/lua/bindings/script.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include "fiber_pool.hpp"
|
||||
#include "lua/lua_manager.hpp"
|
||||
#include "lua/lua_module.hpp"
|
||||
#include "script_mgr.hpp"
|
||||
|
||||
namespace lua::script
|
||||
{
|
||||
static void register_looped(const std::string& name, sol::function func, sol::this_state state)
|
||||
{
|
||||
auto module = sol::state_view(state)["!this"].get<big::lua_module*>();
|
||||
|
||||
module->m_registered_scripts.push_back(big::g_script_mgr.add_script(std::make_unique<big::script>(
|
||||
[func] {
|
||||
while (big::g_running)
|
||||
{
|
||||
auto res = func();
|
||||
if (!res.valid())
|
||||
big::g_lua_manager->handle_error(res, res.lua_state());
|
||||
|
||||
big::script::get_current()->yield();
|
||||
}
|
||||
},
|
||||
name)));
|
||||
}
|
||||
|
||||
static void run_in_fiber(sol::function func)
|
||||
{
|
||||
big::g_fiber_pool->queue_job([func] {
|
||||
auto res = func();
|
||||
if (!res.valid())
|
||||
big::g_lua_manager->handle_error(res, res.lua_state());
|
||||
});
|
||||
}
|
||||
|
||||
static void yield()
|
||||
{
|
||||
big::script::get_current()->yield();
|
||||
}
|
||||
|
||||
static void sleep(int ms)
|
||||
{
|
||||
big::script::get_current()->yield(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["script"].get_or_create<sol::table>();
|
||||
ns["register_looped"] = register_looped;
|
||||
ns["run_in_fiber"] = run_in_fiber;
|
||||
ns["yield"] = yield;
|
||||
ns["sleep"] = sleep;
|
||||
}
|
||||
}
|
31
src/lua/bindings/tunables.hpp
Normal file
31
src/lua/bindings/tunables.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "services/tunables/tunables_service.hpp"
|
||||
|
||||
namespace lua::tunables
|
||||
{
|
||||
template<typename T>
|
||||
static T get(const std::string tunable_name)
|
||||
{
|
||||
if (auto tunable = big::g_tunables_service->get_tunable<T*>(rage::joaat(tunable_name)))
|
||||
return *tunable;
|
||||
|
||||
return T();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void set(const std::string tunable_name, T val)
|
||||
{
|
||||
big::g_tunables_service->set_tunable<T>(rage::joaat(tunable_name), val);
|
||||
}
|
||||
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["tunables"].get_or_create<sol::table>();
|
||||
ns["get_int"] = get<int>;
|
||||
ns["get_float"] = get<float>;
|
||||
ns["get_bool"] = get<bool>;
|
||||
ns["set_int"] = set<int>;
|
||||
ns["set_float"] = set<float>;
|
||||
ns["set_bool"] = set<bool>;
|
||||
}
|
||||
}
|
15
src/lua/bindings/vector.hpp
Normal file
15
src/lua/bindings/vector.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace lua::vector
|
||||
{
|
||||
static void bind(sol::state& state)
|
||||
{
|
||||
// clang-format off
|
||||
state.new_usertype<rage::fvector3>("vec3", sol::constructors<rage::fvector3(float, float, float)>(),
|
||||
"x", &rage::fvector3::x,
|
||||
"y", &rage::fvector3::y,
|
||||
"z", &rage::fvector3::z
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
}
|
99
src/lua/lua_manager.cpp
Normal file
99
src/lua/lua_manager.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "lua_manager.hpp"
|
||||
|
||||
#include "file_manager.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
lua_manager::lua_manager()
|
||||
{
|
||||
load_all_modules();
|
||||
|
||||
g_lua_manager = this;
|
||||
}
|
||||
|
||||
lua_manager::~lua_manager()
|
||||
{
|
||||
unload_all_modules();
|
||||
|
||||
g_lua_manager = nullptr;
|
||||
}
|
||||
|
||||
void lua_manager::draw_gui(rage::joaat_t tab_hash)
|
||||
{
|
||||
std::lock_guard guard(m_module_lock);
|
||||
|
||||
for (auto& module : m_modules)
|
||||
{
|
||||
if (auto it = module->m_gui.find(tab_hash); it != module->m_gui.end())
|
||||
{
|
||||
ImGui::SameLine();
|
||||
|
||||
for (auto& element : it->second)
|
||||
element->draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lua_manager::unload_module(rage::joaat_t module_id)
|
||||
{
|
||||
std::lock_guard guard(m_module_lock);
|
||||
|
||||
std::erase_if(m_modules, [module_id](auto& module) {
|
||||
return module_id == module->module_id();
|
||||
});
|
||||
}
|
||||
|
||||
void lua_manager::load_module(const std::string& module_name)
|
||||
{
|
||||
std::lock_guard guard(m_module_lock);
|
||||
|
||||
auto id = rage::joaat(module_name);
|
||||
|
||||
for (auto& module : m_modules)
|
||||
if (module->module_id() == id)
|
||||
return;
|
||||
|
||||
m_modules.push_back(std::make_shared<lua_module>(module_name));
|
||||
}
|
||||
|
||||
std::weak_ptr<lua_module> lua_manager::get_module(rage::joaat_t module_id)
|
||||
{
|
||||
for (auto& module : m_modules)
|
||||
if (module->module_id() == module_id)
|
||||
return module;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<lua_module>>& lua_manager::get_modules()
|
||||
{
|
||||
return m_modules;
|
||||
}
|
||||
|
||||
void lua_manager::reload_all_modules()
|
||||
{
|
||||
unload_all_modules();
|
||||
load_all_modules();
|
||||
}
|
||||
|
||||
void lua_manager::handle_error(const sol::error& error, const sol::state_view& state)
|
||||
{
|
||||
LOG(WARNING) << state["!module_name"].get<std::string_view>() << ": " << error.what();
|
||||
}
|
||||
|
||||
void lua_manager::load_all_modules()
|
||||
{
|
||||
for (const auto& entry : std::filesystem::directory_iterator(g_file_manager->get_project_folder("scripts").get_path()))
|
||||
if (entry.is_regular_file())
|
||||
load_module(entry.path().filename().string());
|
||||
}
|
||||
void lua_manager::unload_all_modules()
|
||||
{
|
||||
std::lock_guard guard(m_module_lock);
|
||||
|
||||
for (auto& module : m_modules)
|
||||
module.reset();
|
||||
|
||||
m_modules.clear();
|
||||
}
|
||||
}
|
67
src/lua/lua_manager.hpp
Normal file
67
src/lua/lua_manager.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include "lua_module.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class lua_manager
|
||||
{
|
||||
std::mutex m_module_lock;
|
||||
|
||||
public:
|
||||
lua_manager();
|
||||
~lua_manager();
|
||||
|
||||
void draw_gui(rage::joaat_t tab_hash);
|
||||
void unload_module(rage::joaat_t module_id);
|
||||
void load_module(const std::string& module_name);
|
||||
std::weak_ptr<lua_module> get_module(rage::joaat_t module_id);
|
||||
const std::vector<std::shared_ptr<lua_module>>& get_modules();
|
||||
void reload_all_modules();
|
||||
void handle_error(const sol::error& error, const sol::state_view& state);
|
||||
|
||||
template<template_str hash_str, typename Return = void, typename... Args>
|
||||
inline std::conditional_t<std::is_void_v<Return>, void, std::optional<Return>> trigger_event(Args&&... args)
|
||||
{
|
||||
constexpr auto hash = rage::joaat(hash_str.value);
|
||||
|
||||
for (auto& modules : get_modules())
|
||||
{
|
||||
if (auto vec = modules->m_event_callbacks.find(hash); vec != modules->m_event_callbacks.end())
|
||||
{
|
||||
for (auto& cb : vec->second)
|
||||
{
|
||||
auto result = cb(args...);
|
||||
|
||||
if (!result.valid())
|
||||
{
|
||||
handle_error(result, result.lua_state());
|
||||
continue;
|
||||
}
|
||||
|
||||
if constexpr (!std::is_void_v<Return>)
|
||||
{
|
||||
if (result.return_count() == 0)
|
||||
continue;
|
||||
|
||||
if (!result[0].is<Return>())
|
||||
continue;
|
||||
|
||||
return result[0].get<Return>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (!std::is_void_v<Return>)
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
void load_all_modules();
|
||||
void unload_all_modules();
|
||||
|
||||
std::vector<std::shared_ptr<lua_module>> m_modules;
|
||||
};
|
||||
|
||||
inline lua_manager* g_lua_manager;
|
||||
}
|
109
src/lua/lua_module.cpp
Normal file
109
src/lua/lua_module.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
#include "lua_module.hpp"
|
||||
|
||||
#include "bindings/command.hpp"
|
||||
#include "bindings/event.hpp"
|
||||
#include "bindings/globals.hpp"
|
||||
#include "bindings/gui.hpp"
|
||||
#include "bindings/locals.hpp"
|
||||
#include "bindings/log.hpp"
|
||||
#include "bindings/memory.hpp"
|
||||
#include "bindings/native.hpp"
|
||||
#include "bindings/network.hpp"
|
||||
#include "bindings/script.hpp"
|
||||
#include "bindings/tunables.hpp"
|
||||
#include "bindings/vector.hpp"
|
||||
#include "file_manager.hpp"
|
||||
#include "script_mgr.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
inline int exception_handler(lua_State* L, sol::optional<const std::exception&> exception, std::string_view what)
|
||||
{
|
||||
if (exception)
|
||||
LOG(WARNING) << exception->what();
|
||||
else
|
||||
LOG(WARNING) << what;
|
||||
|
||||
lua_pushlstring(L, what.data(), what.size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline int panic_handler(lua_State* L)
|
||||
{
|
||||
size_t messagesize;
|
||||
const char* message = lua_tolstring(L, -1, &messagesize);
|
||||
if (message)
|
||||
{
|
||||
std::string err(message, messagesize);
|
||||
lua_settop(L, 0);
|
||||
LOG(FATAL) << err;
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
LOG(FATAL) << "An unexpected error occurred and panic has been invoked";
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_module::lua_module(std::string module_name) :
|
||||
m_state(),
|
||||
m_module_name(module_name),
|
||||
m_module_id(rage::joaat(module_name))
|
||||
{
|
||||
m_state.open_libraries();
|
||||
|
||||
lua::log::bind(m_state);
|
||||
lua::globals::bind(m_state);
|
||||
lua::script::bind(m_state);
|
||||
lua::native::bind(m_state);
|
||||
lua::memory::bind(m_state);
|
||||
lua::gui::bind(m_state);
|
||||
lua::network::bind(m_state);
|
||||
lua::command::bind(m_state);
|
||||
lua::tunables::bind(m_state);
|
||||
lua::locals::bind(m_state);
|
||||
lua::event::bind(m_state);
|
||||
lua::vector::bind(m_state);
|
||||
|
||||
m_state["!module_name"] = module_name;
|
||||
m_state["!this"] = this;
|
||||
m_state["joaat"] = rage::joaat;
|
||||
|
||||
m_state.set_exception_handler((sol::exception_handler_function)exception_handler);
|
||||
m_state.set_panic(panic_handler);
|
||||
|
||||
auto result = m_state.load_file(g_file_manager->get_project_folder("scripts").get_file(module_name).get_path().string());
|
||||
|
||||
if (!result.valid())
|
||||
{
|
||||
LOG(WARNING) << module_name << " failed to load: " << result.get<sol::error>().what();
|
||||
}
|
||||
else
|
||||
{
|
||||
result();
|
||||
}
|
||||
}
|
||||
|
||||
lua_module::~lua_module()
|
||||
{
|
||||
for (auto script : m_registered_scripts)
|
||||
g_script_mgr.remove_script(script);
|
||||
|
||||
for (auto& patch : m_registered_patches)
|
||||
patch.reset();
|
||||
|
||||
for (auto memory : m_allocated_memory)
|
||||
delete[] memory;
|
||||
|
||||
m_registered_scripts.clear();
|
||||
m_registered_patches.clear();
|
||||
}
|
||||
|
||||
rage::joaat_t lua_module::module_id()
|
||||
{
|
||||
return m_module_id;
|
||||
}
|
||||
|
||||
const std::string& lua_module::module_name()
|
||||
{
|
||||
return m_module_name;
|
||||
}
|
||||
}
|
28
src/lua/lua_module.hpp
Normal file
28
src/lua/lua_module.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "bindings/gui/gui_element.hpp"
|
||||
#include "lua_patch.hpp"
|
||||
#include "sol.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class script;
|
||||
|
||||
class lua_module
|
||||
{
|
||||
sol::state m_state;
|
||||
std::string m_module_name;
|
||||
rage::joaat_t m_module_id;
|
||||
|
||||
public:
|
||||
std::vector<script*> m_registered_scripts;
|
||||
std::vector<std::shared_ptr<lua_patch>> m_registered_patches;
|
||||
std::unordered_map<rage::joaat_t, std::vector<std::shared_ptr<lua::gui::gui_element>>> m_gui;
|
||||
std::unordered_map<rage::joaat_t, std::vector<sol::function>> m_event_callbacks;
|
||||
std::vector<void*> m_allocated_memory;
|
||||
|
||||
lua_module(std::string module_name);
|
||||
~lua_module();
|
||||
rage::joaat_t module_id();
|
||||
const std::string& module_name();
|
||||
};
|
||||
}
|
27
src/lua/lua_patch.cpp
Normal file
27
src/lua/lua_patch.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "lua_patch.hpp"
|
||||
|
||||
#include "memory/byte_patch.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
lua_patch::lua_patch(memory::byte_patch* patch) :
|
||||
m_byte_patch(patch)
|
||||
{
|
||||
}
|
||||
|
||||
lua_patch::~lua_patch()
|
||||
{
|
||||
m_byte_patch->restore();
|
||||
m_byte_patch->remove();
|
||||
}
|
||||
|
||||
void lua_patch::apply()
|
||||
{
|
||||
m_byte_patch->apply();
|
||||
}
|
||||
|
||||
void lua_patch::restore()
|
||||
{
|
||||
m_byte_patch->restore();
|
||||
}
|
||||
}
|
21
src/lua/lua_patch.hpp
Normal file
21
src/lua/lua_patch.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace memory
|
||||
{
|
||||
class byte_patch;
|
||||
}
|
||||
|
||||
namespace big
|
||||
{
|
||||
class lua_patch
|
||||
{
|
||||
memory::byte_patch* m_byte_patch;
|
||||
|
||||
public:
|
||||
lua_patch(memory::byte_patch* patch);
|
||||
~lua_patch();
|
||||
|
||||
void apply();
|
||||
void restore();
|
||||
};
|
||||
}
|
118122
src/lua/natives/natives.json
Normal file
118122
src/lua/natives/natives.json
Normal file
File diff suppressed because one or more lines are too long
6590
src/lua/natives/natives_data.cpp
Normal file
6590
src/lua/natives/natives_data.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3
src/lua/natives/natives_data.hpp
Normal file
3
src/lua/natives/natives_data.hpp
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
extern char natives_data[];
|
||||
extern int natives_size;
|
87
src/lua/natives/natives_gen.py
Normal file
87
src/lua/natives/natives_gen.py
Normal file
@ -0,0 +1,87 @@
|
||||
import json
|
||||
|
||||
natives = json.load(open("natives.json"))
|
||||
out_file : str = ""
|
||||
|
||||
def sanitize_param(name):
|
||||
if name in ["repeat", "end"]:
|
||||
return "_"+name
|
||||
else:
|
||||
return name
|
||||
|
||||
def make_param_listing(params):
|
||||
pms = ""
|
||||
for param in params:
|
||||
pms += sanitize_param(param["name"])
|
||||
pms += ","
|
||||
pms = pms.rstrip(",")
|
||||
return pms
|
||||
|
||||
def is_string(type: str):
|
||||
return type.find("char*") != -1
|
||||
|
||||
def is_pointer(type: str):
|
||||
"""also returns true for string"""
|
||||
return type.find('*') != -1
|
||||
|
||||
|
||||
def write_native(name, hash, params, return_type):
|
||||
global out_file
|
||||
|
||||
out_file += f"{name}=function({make_param_listing(params)})"
|
||||
|
||||
invoke_type = "invoke_int"
|
||||
|
||||
if (return_type == "void"):
|
||||
invoke_type = "invoke_void"
|
||||
elif (return_type == "float"):
|
||||
invoke_type = "invoke_float"
|
||||
elif (return_type == "BOOL"):
|
||||
invoke_type = "invoke_bool"
|
||||
elif (return_type == "const char*"):
|
||||
invoke_type = "invoke_str"
|
||||
elif (return_type == "Vector3"):
|
||||
invoke_type = "invoke_vec3"
|
||||
elif (return_type.endswith("*")):
|
||||
invoke_type = "invoke_ptr"
|
||||
|
||||
out_file += f"return _natives.{invoke_type}({hash},"
|
||||
for param in params:
|
||||
out_file += f"{sanitize_param(param['name'])},"
|
||||
out_file = out_file.removesuffix(",")
|
||||
out_file += ");end,\n"
|
||||
|
||||
def write_namespace(name, data):
|
||||
global out_file
|
||||
|
||||
out_file += f"{name} = {{\n"
|
||||
|
||||
for (hash, more) in data.items():
|
||||
write_native(more["name"], hash, more["params"], more["return_type"])
|
||||
|
||||
out_file += "};\n"
|
||||
|
||||
def write_file():
|
||||
for (namespace, data) in natives.items():
|
||||
write_namespace(namespace, data)
|
||||
|
||||
def convert_and_write_cpp_file():
|
||||
global out_file
|
||||
|
||||
cpp_data = "#pragma once\n// clang-format off\n// Generated by natives_gen.py. DO NOT EDIT\nchar natives_data[] = \n"
|
||||
|
||||
lines = out_file.rstrip('\n').splitlines()
|
||||
for line in lines:
|
||||
cpp_data += f"\"{line}\\n\"\\\n"
|
||||
|
||||
cpp_data = cpp_data.rstrip('\n\\')
|
||||
cpp_data += ";\n// clang-format on\n"
|
||||
cpp_data += "int natives_size = sizeof(natives_data)-1;"
|
||||
open("natives_data.cpp", "w+").write(cpp_data)
|
||||
|
||||
def write_lua_file():
|
||||
open("natives.lua", "w+").write(out_file)
|
||||
|
||||
if __name__ == "__main__":
|
||||
write_file()
|
||||
convert_and_write_cpp_file()
|
28917
src/lua/sol.hpp
Normal file
28917
src/lua/sol.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user