diff --git a/src/core/scripting/LuaManager.hpp b/src/core/scripting/LuaManager.hpp index 5cf5072..1ef8429 100644 --- a/src/core/scripting/LuaManager.hpp +++ b/src/core/scripting/LuaManager.hpp @@ -8,10 +8,6 @@ namespace YimMenu class LuaManager { public: - enum class ScriptPermission - { - }; - struct UnloadedScript { std::string m_Name; diff --git a/src/core/scripting/LuaUtils.hpp b/src/core/scripting/LuaUtils.hpp new file mode 100644 index 0000000..e0395c8 --- /dev/null +++ b/src/core/scripting/LuaUtils.hpp @@ -0,0 +1,104 @@ +#include "lua.hpp" +#undef GetObject // another dumb Windows.h definition + +namespace YimMenu::Lua +{ + template + class Metatable + { + static int m_Index; + + public: + static inline void Register(lua_State* state) + { + m_Index = luaL_ref(state, LUA_REGISTRYINDEX); + } + + static inline int Get() + { + return m_Index; + } + }; + + // Tries to get the userdata or errors out + template + inline T& GetObject(lua_State* state, int idx) + { + auto data = lua_touserdata(state, idx); + if (!data) + luaL_argerror(state, idx, "cannot get userdata at this index"); + + if (!lua_getmetatable(state, idx)) + luaL_argerror(state, idx, "cannot get metatable for the userdata at this index"); + + lua_rawgeti(state, LUA_REGISTRYINDEX, Metatable::Get()); + auto equals = lua_rawequal(state, -1, -2); + lua_pop(state, 2); + + if (!equals) + luaL_argerror(state, idx, "the metatable for this userdata at this index is incorrect"); + + return *reinterpret_cast(data); + } + + inline void SetFunction(lua_State* state, lua_CFunction func, const char* name) + { + lua_pushcfunction(state, func); + lua_setfield(state, -2, name); + } + + // This is a terrible hack + template + inline int DropSelf(lua_State* state) + { + lua_remove(state, 1); + return actual_func(state); + } + + // Requires your table to be at the top of stack + // Creates a metatable for the table, which might not desirable + template + inline void SetConstructor(lua_State* state) + { + SetFunction(state, ctor, "new"); + + lua_newtable(state); + SetFunction(state, DropSelf, "__call"); + lua_setmetatable(state, -2); + } + + // Creates an object and pushes it on the stack + template + inline T* CreateObject(lua_State* state, Args&& ...args) + { + void* data = lua_newuserdata(state, sizeof(T)); + new (data) T(std::forward(args)...); // construct in-place + lua_rawgeti(state, LUA_REGISTRYINDEX, Metatable::Get()); + lua_setmetatable(state, -2); + return reinterpret_cast(data); + } + + // Copies an existing object and pushes it on the stack + // A copy ctor must be defined or something like that + template + inline T* CopyObject(lua_State* state, const T& existing) + { + void* data = lua_newuserdata(state, sizeof(T)); + *reinterpret_cast(data) = existing; + lua_rawgeti(state, LUA_REGISTRYINDEX, Metatable::Get()); + lua_setmetatable(state, -2); + return reinterpret_cast(data); + } + + // Moves an existing object and pushes it on the stack + // A move ctor must be defined or something like that + template + inline T* MoveObject(lua_State* state, T&& existing) + { + void* data = lua_newuserdata(state, sizeof(T)); + *reinterpret_cast(data) = std::move(existing); + lua_rawgeti(state, LUA_REGISTRYINDEX, Metatable::Get()); + lua_setmetatable(state, -2); + return reinterpret_cast(data); + } +} \ No newline at end of file diff --git a/src/core/scripting/libraries/Logging.cpp b/src/core/scripting/libraries/Logging.cpp index 0de3ccd..a35c979 100644 --- a/src/core/scripting/libraries/Logging.cpp +++ b/src/core/scripting/libraries/Logging.cpp @@ -1,5 +1,6 @@ #include "core/scripting/LuaLibrary.hpp" #include "core/scripting/LuaScript.hpp" +#include "core/scripting/LuaUtils.hpp" namespace YimMenu::Lua { @@ -47,22 +48,11 @@ namespace YimMenu::Lua virtual void Register(lua_State* state) override { lua_newtable(state); - - lua_pushcfunction(state, Verbose); - lua_setfield(state, -2, "verbose"); - - lua_pushcfunction(state, Info); - lua_setfield(state, -2, "info"); - - lua_pushcfunction(state, Warn); - lua_setfield(state, -2, "warn"); - - lua_pushcfunction(state, Error); - lua_setfield(state, -2, "error"); - - lua_pushcfunction(state, Trace); - lua_setfield(state, -2, "trace"); - + SetFunction(state, Verbose, "verbose"); + SetFunction(state, Info, "info"); + SetFunction(state, Warn, "warn"); + SetFunction(state, Error, "error"); + SetFunction(state, Trace, "trace"); lua_setglobal(state, "log"); } }; diff --git a/src/core/scripting/libraries/Script.cpp b/src/core/scripting/libraries/Script.cpp index c24a928..38069e3 100644 --- a/src/core/scripting/libraries/Script.cpp +++ b/src/core/scripting/libraries/Script.cpp @@ -1,5 +1,6 @@ #include "core/scripting/LuaLibrary.hpp" #include "core/scripting/LuaScript.hpp" +#include "core/scripting/LuaUtils.hpp" #include "core/util/Joaat.hpp" namespace YimMenu::Lua @@ -65,19 +66,10 @@ namespace YimMenu::Lua virtual void Register(lua_State* state) override { lua_newtable(state); - - lua_pushcfunction(state, RunInCallback); - lua_setfield(state, -2, "run_in_callback"); - - lua_pushcfunction(state, Yield); - lua_setfield(state, -2, "yield"); - - lua_pushcfunction(state, IsInsideCallback); - lua_setfield(state, -2, "is_inside_callback"); - - lua_pushcfunction(state, RegisterEventHandler); - lua_setfield(state, -2, "register_event_handler"); - + SetFunction(state, RunInCallback, "run_in_callback"); + SetFunction(state, Yield, "yield"); + SetFunction(state, IsInsideCallback, "is_inside_callback"); + SetFunction(state, RegisterEventHandler, "register_event_handler"); lua_setglobal(state, "script"); } }; diff --git a/src/core/scripting/libraries/Util.cpp b/src/core/scripting/libraries/Util.cpp new file mode 100644 index 0000000..5485739 --- /dev/null +++ b/src/core/scripting/libraries/Util.cpp @@ -0,0 +1,28 @@ +#include "core/scripting/LuaLibrary.hpp" +#include "core/scripting/LuaScript.hpp" +#include "core/scripting/LuaUtils.hpp" +#include "core/util/Joaat.hpp" + +namespace YimMenu::Lua +{ + class Util : LuaLibrary + { + using LuaLibrary::LuaLibrary; + + static int Joaat(lua_State* state) + { + const char* string = luaL_checkstring(state, 1); + lua_pushinteger(state, (int)YimMenu::Joaat(string)); + return 1; + } + + virtual void Register(lua_State* state) override + { + lua_newtable(state); + SetFunction(state, Joaat, "joaat"); + lua_setglobal(state, "util"); + } + }; + + Util _Util; +} \ No newline at end of file diff --git a/src/core/scripting/libraries/Vector3.cpp b/src/core/scripting/libraries/Vector3.cpp new file mode 100644 index 0000000..2b00306 --- /dev/null +++ b/src/core/scripting/libraries/Vector3.cpp @@ -0,0 +1,43 @@ +#include "core/scripting/LuaLibrary.hpp" +#include "core/scripting/LuaScript.hpp" +#include "core/scripting/LuaUtils.hpp" +#include "types/rage/vector.hpp" + +namespace YimMenu::Lua +{ + class Vector3 : LuaLibrary + { + using LuaLibrary::LuaLibrary; + + static int New(lua_State* state) + { + auto args = lua_gettop(state); + if (args == 0) + CreateObject(state); + else if (args == 3) + CreateObject(state, luaL_checknumber(state, 1), luaL_checknumber(state, 2), luaL_checknumber(state, 3)); + else + luaL_error(state, "Invalid amount of arguments passed to Vector3::New"); + return 1; + } + + virtual void Register(lua_State* state) override + { + luaL_newmetatable(state, "Vector3"); + { + lua_newtable(state); + { + // TODO? + } + lua_setfield(state, -2, "__index"); // prototype + } + Metatable::Register(state); + + lua_newtable(state); + SetConstructor(state); + lua_setglobal(state, "Vector3"); + } + }; + + Vector3 _Vector3; +} \ No newline at end of file diff --git a/src/game/scripting/libraries/Entity.cpp b/src/game/scripting/libraries/Entity.cpp new file mode 100644 index 0000000..1e1fdc1 --- /dev/null +++ b/src/game/scripting/libraries/Entity.cpp @@ -0,0 +1,135 @@ +#include "core/scripting/LuaLibrary.hpp" +#include "core/scripting/LuaScript.hpp" +#include "core/scripting/LuaUtils.hpp" +#include "game/gta/Entity.hpp" + +namespace YimMenu::Lua +{ + // TODO: we need to automate this + class Entity : LuaLibrary + { + using LuaLibrary::LuaLibrary; + + static int New(lua_State* state) + { + CreateObject(state, luaL_checkinteger(state, 1)); + return 1; + } + + static int GetHandle(lua_State* state) + { + lua_pushinteger(state, GetObject(state, 1).GetHandle()); + return 1; + } + + static int IsValid(lua_State* state) + { + lua_pushboolean(state, GetObject(state, 1).IsValid()); + return 1; + } + + static int IsPed(lua_State* state) + { + lua_pushboolean(state, GetObject(state, 1).IsPed()); + return 1; + } + + static int IsVehicle(lua_State* state) + { + lua_pushboolean(state, GetObject(state, 1).IsVehicle()); + return 1; + } + + static int IsObject(lua_State* state) + { + lua_pushboolean(state, GetObject(state, 1).IsObject()); + return 1; + } + + static int IsPlayer(lua_State* state) + { + lua_pushboolean(state, GetObject(state, 1).IsPlayer()); + return 1; + } + + static int IsMissionEntity(lua_State* state) + { + lua_pushboolean(state, GetObject(state, 1).IsMissionEntity()); + return 1; + } + + static int GetModel(lua_State* state) + { + lua_pushinteger(state, (int)GetObject(state, 1).GetModel()); + return 1; + } + + static int GetPosition(lua_State* state) + { + CopyObject(state, GetObject(state, 1).GetPosition()); + return 1; + } + + static int GetRotation(lua_State* state) + { + CopyObject(state, GetObject(state, 1).GetRotation(lua_gettop(state) >= 2 ? luaL_checkinteger(state, 2) : 2)); + return 1; + } + + static int GetVelocity(lua_State* state) + { + CopyObject(state, GetObject(state, 1).GetVelocity()); + return 1; + } + + static int SetPosition(lua_State* state) + { + GetObject(state, 1).SetPosition(GetObject(state, 2)); + return 0; + } + + static int SetRotation(lua_State* state) + { + GetObject(state, 1).SetRotation(GetObject(state, 2), lua_gettop(state) >= 3 ? luaL_checkinteger(state, 3) : 2); + return 0; + } + + static int SetVelocity(lua_State* state) + { + GetObject(state, 1).SetVelocity(GetObject(state, 2)); + return 0; + } + + virtual void Register(lua_State* state) override + { + luaL_newmetatable(state, "Entity"); + { + lua_newtable(state); + { + SetFunction(state, GetHandle, "get_handle"); + SetFunction(state, IsValid, "is_valid"); + SetFunction(state, IsPed, "is_ped"); + SetFunction(state, IsVehicle, "is_vehicle"); + SetFunction(state, IsObject, "is_object"); + SetFunction(state, IsPlayer, "is_player"); + SetFunction(state, IsMissionEntity, "is_mission_entity"); + SetFunction(state, GetModel, "get_model"); + SetFunction(state, GetPosition, "get_position"); + SetFunction(state, GetRotation, "get_rotation"); + SetFunction(state, GetVelocity, "get_velocity"); + SetFunction(state, SetPosition, "set_position"); + SetFunction(state, SetRotation, "set_rotation"); + SetFunction(state, SetVelocity, "set_velocity"); + } + lua_setfield(state, -2, "__index"); // prototype + } + Metatable::Register(state); + + lua_newtable(state); + SetConstructor(state); + lua_setglobal(state, "Entity"); + } + }; + + Entity _Entity; +} \ No newline at end of file diff --git a/src/game/scripting/libraries/ScriptGlobal.cpp b/src/game/scripting/libraries/ScriptGlobal.cpp new file mode 100644 index 0000000..5ffd2d9 --- /dev/null +++ b/src/game/scripting/libraries/ScriptGlobal.cpp @@ -0,0 +1,99 @@ +#include "core/scripting/LuaLibrary.hpp" +#include "core/scripting/LuaScript.hpp" +#include "core/scripting/LuaUtils.hpp" +#include "game/gta/ScriptGlobal.hpp" + +namespace YimMenu::Lua +{ + // TODO: we need to automate this + class ScriptGlobal : LuaLibrary + { + using LuaLibrary::LuaLibrary; + + static int New(lua_State* state) + { + CreateObject(state, luaL_checkinteger(state, 1)); + return 1; + } + + static int At(lua_State* state) + { + auto num_args = lua_gettop(state) - 1; // first argument is self + auto& global = GetObject(state, 1); + + auto size = num_args > 1 ? luaL_checkinteger(state, 3) : 0; + if (size != 0) + CopyObject(state, global.At(luaL_checkinteger(state, 2), size)); + else + CopyObject(state, global.At(luaL_checkinteger(state, 2))); + + return 1; + } + + static int CanAccess(lua_State* state) + { + lua_pushboolean(state, GetObject(state, 1).CanAccess()); + return 1; + } + + static int GetInt(lua_State* state) + { + auto& global = GetObject(state, 1); + int value = 0; + if (global.CanAccess()) + value = *global.As(); + lua_pushinteger(state, value); + return 1; + } + + static int GetFloat(lua_State* state) + { + auto& global = GetObject(state, 1); + float value = 0; + if (global.CanAccess()) + value = *global.As(); + lua_pushnumber(state, value); + return 1; + } + + static int SetInt(lua_State* state) + { + auto& global = GetObject(state, 1); + if (global.CanAccess()) + *global.As() = luaL_checkinteger(state, 2); + return 0; + } + + static int SetFloat(lua_State* state) + { + auto& global = GetObject(state, 1); + if (global.CanAccess()) + *global.As() = static_cast(luaL_checknumber(state, 2)); + return 0; + } + + virtual void Register(lua_State* state) override + { + luaL_newmetatable(state, "ScriptGlobal"); + { + lua_newtable(state); + { + SetFunction(state, At, "at"); + SetFunction(state, CanAccess, "can_access"); + SetFunction(state, GetInt, "get_int"); + SetFunction(state, GetFloat, "get_float"); + SetFunction(state, SetInt, "set_int"); + SetFunction(state, SetFloat, "set_float"); + } + lua_setfield(state, -2, "__index"); // prototype + } + Metatable::Register(state); + + lua_newtable(state); + SetConstructor(state); + lua_setglobal(state, "ScriptGlobal"); + } + }; + + ScriptGlobal _ScriptGlobal; +} \ No newline at end of file