Lua Scripting (#1334)

Closes #83
Fixes #1309
Fixes #1287
Fixes #1129 (actually fixed now)
This commit is contained in:
maybegreat48
2023-06-06 07:40:40 +00:00
committed by GitHub
parent a8750a30fb
commit 70efa40afe
202 changed files with 156693 additions and 839 deletions

View 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;
}
}

View 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?
}
}

View 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
View 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
View 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
}
}

View 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;
}
}

View 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();
};
}

View 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());
}
}
}
}

View 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;
};
}

View 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;
}
}

View 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);
};
}

View File

@ -0,0 +1,10 @@
#pragma once
namespace lua::gui
{
class gui_element
{
public:
virtual void draw() = 0;
};
}

View 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;
}
}

View 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);
};
}

View 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;
}
}

View 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);
};
}

View 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));
}
}

View 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);
};
}

View File

@ -0,0 +1,9 @@
#include "sameline.hpp"
namespace lua::gui
{
void sameline::draw()
{
ImGui::SameLine();
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "gui_element.hpp"
namespace lua::gui
{
class sameline : public gui_element
{
public:
sameline(){};
void draw() override;
};
}

View File

@ -0,0 +1,9 @@
#include "separator.hpp"
namespace lua::gui
{
void separator::draw()
{
ImGui::Separator();
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "gui_element.hpp"
namespace lua::gui
{
class separator : public gui_element
{
public:
separator(){};
void draw() override;
};
}

View 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;
}
}
}

View 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);
};
}

View 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
View 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;
}
}

View 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
View 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;
}
}

View 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();
}
}

View 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);
});
}
}

View 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;
}
}

View 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;
}
}

View 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>;
}
}

View 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
}
}