lua: change the way native functions are binded (#1543)
This commit is contained in:
parent
5fc6ef8fb5
commit
c3121de8e7
@ -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"
|
||||
)
|
||||
)
|
||||
|
@ -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 ""
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
};
|
||||
}
|
6593
src/lua/natives/lua_native_binding.cpp
Normal file
6593
src/lua/natives/lua_native_binding.cpp
Normal file
File diff suppressed because it is too large
Load Diff
7
src/lua/natives/lua_native_binding.hpp
Normal file
7
src/lua/natives/lua_native_binding.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "lua/sol.hpp"
|
||||
|
||||
namespace lua::native
|
||||
{
|
||||
void init_native_binding(sol::state& L);
|
||||
}
|
118122
src/lua/natives/natives.json
118122
src/lua/natives/natives.json
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
extern char natives_data[];
|
||||
extern int natives_size;
|
@ -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)
|
||||
|
Reference in New Issue
Block a user