lua: change the way native functions are binded (#1543)

This commit is contained in:
Quentin 2023-06-27 20:13:05 +02:00 committed by GitHub
parent 5fc6ef8fb5
commit c3121de8e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 6810 additions and 124885 deletions

View File

@ -32,6 +32,13 @@ file(GLOB_RECURSE SRC_MAIN
"${SRC_DIR}/**.cxx"
"${SRC_DIR}/**.asm"
)
if (MSVC)
add_compile_options(/bigobj)
else ()
add_compile_options(-Wa,-mbig-obj)
endif ()
add_library(YimMenu MODULE "${SRC_MAIN}")
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@ -56,4 +63,4 @@ add_compile_definitions(YimMenu
"_CRT_SECURE_NO_WARNINGS"
"NOMINMAX"
"WIN32_LEAN_AND_MEAN"
)
)

View File

@ -3,7 +3,7 @@ include(FetchContent)
FetchContent_Declare(
gtav_classes
GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git
GIT_TAG 7b8bfba701d70e6a503c0767a5bc3b6c4c0294b8
GIT_TAG d8304d3e608dac2c22754962420c19f6e74b2c47
GIT_PROGRESS TRUE
CONFIGURE_COMMAND ""
BUILD_COMMAND ""

View File

@ -1,78 +1,11 @@
#pragma once
#include "invoker.hpp"
#include "lua/lua_module.hpp"
#include "lua/natives/natives_data.hpp"
#include "memory.hpp"
#include "lua/sol.hpp"
#include "lua/natives/lua_native_binding.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();
init_native_binding(state);
}
}

View File

@ -1,15 +1,16 @@
#pragma once
#include "lua/sol.hpp"
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 off
state.new_usertype<Vector3>("vec3",
sol::constructors<Vector3(float, float, float)>(),
"x", &Vector3::x, "y", &Vector3::y, "z", &Vector3::z,
"__tostring", &Vector3::to_string
);
// clang-format on
//clang-format on
}
}

View File

@ -22,13 +22,13 @@ namespace big
{
std::lock_guard guard(m_module_lock);
for (auto& module : m_modules)
for (const auto& module : m_modules)
{
if (auto it = module->m_gui.find(tab_hash); it != module->m_gui.end())
if (const auto it = module->m_gui.find(tab_hash); it != module->m_gui.end())
{
ImGui::SameLine();
for (auto& element : it->second)
for (const auto& element : it->second)
element->draw();
}
}
@ -47,9 +47,9 @@ namespace big
{
std::lock_guard guard(m_module_lock);
auto id = rage::joaat(module_name);
const auto id = rage::joaat(module_name);
for (auto& module : m_modules)
for (const auto& module : m_modules)
if (module->module_id() == id)
return;
@ -58,14 +58,14 @@ namespace big
std::weak_ptr<lua_module> lua_manager::get_module(rage::joaat_t module_id)
{
for (auto& module : m_modules)
for (const 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()
const std::vector<std::shared_ptr<lua_module>>& lua_manager::get_modules() const
{
return m_modules;
}

View File

@ -15,7 +15,7 @@ namespace big
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();
const std::vector<std::shared_ptr<lua_module>>& get_modules() const;
void reload_all_modules();
void handle_error(const sol::error& error, const sol::state_view& state);

View File

@ -50,27 +50,19 @@ namespace big
{
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);
const auto scripts_folder = g_file_manager->get_project_folder("scripts");
add_folder_to_require_available_paths(scripts_folder);
init_lua_api();
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());
auto result = m_state.load_file(scripts_folder.get_file(module_name).get_path().string());
if (!result.valid())
{
@ -106,4 +98,28 @@ namespace big
{
return m_module_name;
}
void lua_module::add_folder_to_require_available_paths(const big::folder& scripts_folder)
{
const std::string package_path = m_state["package"]["path"];
const auto scripts_search_path = scripts_folder.get_path() / "?.lua";
m_state["package"]["path"] = package_path + (!package_path.empty() ? ";" : "") + scripts_search_path.string();
}
void lua_module::init_lua_api()
{
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["joaat"] = rage::joaat;
}
}

View File

@ -22,7 +22,13 @@ namespace big
lua_module(std::string module_name);
~lua_module();
rage::joaat_t module_id();
const std::string& module_name();
// used for adding our own paths to the search paths of the lua require function
void add_folder_to_require_available_paths(const big::folder& scripts_folder);
void init_lua_api();
};
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
#pragma once
#include "lua/sol.hpp"
namespace lua::native
{
void init_native_binding(sol::state& L);
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
#pragma once
extern char natives_data[];
extern int natives_size;

View File

@ -1,87 +1,164 @@
import json
import os
natives = json.load(open("natives.json"))
out_file : str = ""
natives_hpp = open("../../natives.hpp", "r")
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
cpp_print_buf = ""
hpp_print_buf = ""
def write_native(name, hash, params, return_type):
global out_file
def print_cpp(text):
global cpp_print_buf
cpp_print_buf += text + "\n"
out_file += f"{name}=function({make_param_listing(params)})"
invoke_type = "invoke_int"
def print_hpp(text):
global hpp_print_buf
hpp_print_buf += text + "\n"
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"
class Arg:
def __init__(self, name, type_):
self.name = name
self.type_ = type_
def write_namespace(name, data):
global out_file
def __str__(self) -> str:
return str(self.type_) + " " + str(self.name)
out_file += f"{name} = {{\n"
for (hash, more) in data.items():
write_native(more["name"], hash, more["params"], more["return_type"])
out_file += "};\n"
class NativeFunc:
def __init__(self, name, args, return_type):
self.name = name
self.args = args
self.return_type = return_type
def write_file():
for (namespace, data) in natives.items():
write_namespace(namespace, data)
def __str__(self) -> str:
if len(self.args) > 0:
return (
str(self.return_type)
+ " "
+ str(self.name)
+ "( "
+ str(self.args[0])
+ " )"
)
else:
return str(self.return_type) + " " + str(self.name) + "( )"
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"
def get_natives_func_from_natives_hpp_file(natives_hpp):
functions_per_namespaces = {}
current_namespace = ""
func_name = ""
start_parsing = False
for line in natives_hpp.readlines():
if "namespace SYSTEM" not in line and not start_parsing:
continue
else:
start_parsing = True
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)
if not start_parsing:
continue
def write_lua_file():
open("natives.lua", "w+").write(out_file)
if "namespace " in line:
current_namespace = line.replace("namespace ", "").strip()
functions_per_namespaces[current_namespace] = []
elif "NATIVE_DECL" in line:
words = line.split()
if __name__ == "__main__":
write_file()
convert_and_write_cpp_file()
# remove NATIVE_DECL from the words array
words.pop(0)
func_name = ""
return_type = [x for x in words if "(" not in x][0]
for word in words:
# function name + args
if "(" in word:
if func_name == "":
func_name_and_args = word.split("(")
func_name = func_name_and_args[0]
continue
functions_per_namespaces[current_namespace].append(
NativeFunc(func_name, [], return_type)
)
return functions_per_namespaces
functions_per_namespaces = get_natives_func_from_natives_hpp_file(natives_hpp)
def generate_native_binding_cpp_and_hpp_file(functions_per_namespaces):
generated_function_name = "void init_native_binding(sol::state& L)"
print_hpp("#pragma once")
print_hpp('#include "lua/sol.hpp"')
print_hpp("")
print_hpp("namespace lua::native")
print_hpp("{")
print_hpp("\t" + generated_function_name + ";")
print_hpp("}")
print_cpp('#include "lua_native_binding.hpp"')
print_cpp('#include "natives.hpp"')
print_cpp("")
print_cpp("namespace lua::native")
print_cpp("{")
print_cpp("\t" + generated_function_name)
print_cpp("\t{")
i = 0
for namespace_name, native_funcs in functions_per_namespaces.items():
print_cpp(
"\t\tauto "
+ namespace_name
+ ' = L["'
+ namespace_name
+ '"].get_or_create<sol::table>();'
)
for native_func in native_funcs:
i += 1
print_cpp(
"\t\t"
+ namespace_name
+ '.set_function("'
+ native_func.name
+ '", '
+ namespace_name
+ "::"
+ native_func.name
+ ");"
)
print_cpp("")
print(f"Wrote binding for {i} native functions")
print_cpp("\t}")
print_cpp("}")
generate_native_binding_cpp_and_hpp_file(functions_per_namespaces)
def write_cpp_code(cpp_print_buf):
file_name = "lua_native_binding.cpp"
if os.path.exists(file_name):
os.remove(file_name)
f = open(file_name, "a")
f.write(cpp_print_buf)
f.close()
def write_hpp_code(hpp_print_buf):
file_name = "lua_native_binding.hpp"
if os.path.exists(file_name):
os.remove(file_name)
f = open(file_name, "a")
f.write(hpp_print_buf)
f.close()
write_cpp_code(cpp_print_buf)
write_hpp_code(hpp_print_buf)