feat(lua): add Vehicle

This commit is contained in:
maybegreat48 committed 2025-06-28 22:47:25 -04:00
1 parent 55f4e297a0
commit d14031fc6b
6 files changed
+251 -6

No files matched your search

+38 -4
View File
@@ -8,6 +8,7 @@ namespace YimMenu::Lua
class Metatable
{
inline static int m_Index;
inline static std::vector<int> m_Subclasses;
public:
static inline void Register(lua_State* state)
@@ -19,6 +20,17 @@ namespace YimMenu::Lua
{
return m_Index;
}
static inline const std::vector<int>& GetSubclasses()
{
return m_Subclasses;
}
template<typename T2>
static inline void AddSubclass()
{
m_Subclasses.push_back(Metatable<T2>::Get());
}
};
// Tries to get the userdata or errors out
@@ -34,12 +46,34 @@ namespace YimMenu::Lua
lua_rawgeti(state, LUA_REGISTRYINDEX, Metatable<T>::Get());
auto equals = lua_rawequal(state, -1, -2);
lua_pop(state, 2);
lua_pop(state, 1);
if (!equals)
luaL_argerror(state, idx, "the metatable for this userdata at this index is incorrect");
if (equals)
{
lua_pop(state, 1);
return *reinterpret_cast<T*>(data);
}
return *reinterpret_cast<T*>(data);
const auto& subclasses = Metatable<T>::GetSubclasses();
if (!equals && subclasses.size())
{
for (const auto subclass : subclasses)
{
lua_rawgeti(state, LUA_REGISTRYINDEX, subclass);
auto equals = lua_rawequal(state, -1, -2);
lua_pop(state, 1);
if (equals)
{
lua_pop(state, 1);
return *reinterpret_cast<T*>(data);
}
}
}
lua_pop(state, 1);
luaL_argerror(state, idx, "the metatable for this userdata at this index is incorrect");
std::unreachable();
}
inline void SetFunction(lua_State* state, lua_CFunction func, const char* name)
+60 -1
View File
@@ -21,13 +21,72 @@ namespace YimMenu::Lua
return 1;
}
// returns three values
static int GetCoords(lua_State* state)
{
lua_pushnumber(state, GetObject<rage::fvector3>(state, 1).x);
lua_pushnumber(state, GetObject<rage::fvector3>(state, 1).y);
lua_pushnumber(state, GetObject<rage::fvector3>(state, 1).z);
return 3;
}
static int GetX(lua_State* state)
{
lua_pushnumber(state, GetObject<rage::fvector3>(state, 1).x);
return 1;
}
static int GetY(lua_State* state)
{
lua_pushnumber(state, GetObject<rage::fvector3>(state, 1).y);
return 1;
}
static int GetZ(lua_State* state)
{
lua_pushnumber(state, GetObject<rage::fvector3>(state, 1).z);
return 1;
}
static int SetX(lua_State* state)
{
GetObject<rage::fvector3>(state, 1).x = luaL_checknumber(state, 2);
return 1;
}
static int SetY(lua_State* state)
{
GetObject<rage::fvector3>(state, 1).y = luaL_checknumber(state, 2);
return 1;
}
static int SetZ(lua_State* state)
{
GetObject<rage::fvector3>(state, 1).z = luaL_checknumber(state, 2);
return 1;
}
static int GetDistance(lua_State* state)
{
lua_pushnumber(state, GetObject<rage::fvector3>(state, 1).GetDistance(GetObject<rage::fvector3>(state, 2)));
return 1;
}
virtual void Register(lua_State* state) override
{
luaL_newmetatable(state, "Vector3");
{
lua_newtable(state);
{
// TODO?
SetFunction(state, GetCoords, "get_coords");
SetFunction(state, GetX, "get_x");
SetFunction(state, GetY, "get_y");
SetFunction(state, GetZ, "get_z");
SetFunction(state, SetX, "set_x");
SetFunction(state, SetY, "set_y");
SetFunction(state, SetZ, "set_z");
SetFunction(state, SetZ, "set_z");
SetFunction(state, GetDistance, "get_distance");
}
lua_setfield(state, -2, "__index"); // prototype
}
+7
View File
@@ -115,6 +115,13 @@ namespace YimMenu
VEHICLE::SET_VEHICLE_TYRES_CAN_BURST(veh, false);
}
std::string Vehicle::GetPlateText()
{
ENTITY_ASSERT_VALID();
return VEHICLE::GET_VEHICLE_NUMBER_PLATE_TEXT(GetHandle());
}
void Vehicle::SetPlateText(std::string_view text)
{
ENTITY_ASSERT_VALID();
+1
View File
@@ -21,6 +21,7 @@ namespace YimMenu
// mods
void Upgrade();
std::string GetPlateText();
void SetPlateText(std::string_view text);
std::map<int, int32_t> GetOwnedMods();
+1 -1
View File
@@ -218,7 +218,7 @@ def create_lua_namespace(name: str, natives: list[NativeFunc]):
def create_lua_defs():
with open("../../scripting/libraries/NativeDefs.cpp", "w+") as file:
string = "#pragma once\n#include \"NativeDefs.hpp\"\n\nconst char* g_LuaNativeDefs[] = \n{\n"
string = "#include \"NativeDefs.hpp\"\n\nconst char* g_LuaNativeDefs[] = \n{\n"
for ns, natives_list in natives.items():
string += create_lua_namespace(ns, natives_list)
string += f"}};\n\nint g_NumLuaNativeDefs = {len(natives.items())};"
+144
View File
@@ -0,0 +1,144 @@
#include "core/scripting/LuaLibrary.hpp"
#include "core/scripting/LuaScript.hpp"
#include "core/scripting/LuaUtils.hpp"
#include "core/scripting/LatentFunction.hpp"
#include "game/gta/Vehicle.hpp"
#include "Entity.hpp"
namespace YimMenu::Lua
{
// TODO: we need to automate this
class Vehicle : LuaLibrary
{
public:
using LuaLibrary::LuaLibrary;
static int New(lua_State* state)
{
CreateObject<YimMenu::Vehicle>(state, luaL_checkinteger(state, 1));
return 1;
}
static int Create(lua_State* state)
{
CopyObject<YimMenu::Vehicle>(state, YimMenu::Vehicle::Create(GetHashArgument(state, 1), GetObject<rage::fvector3>(state, 2), lua_gettop(state) >= 3 ? luaL_checknumber(state, 3) : 0.0f));
return 1;
}
static int Fix(lua_State* state)
{
GetObject<YimMenu::Vehicle>(state, 1).Fix();
return 0;
}
static int GetGear(lua_State* state)
{
lua_pushinteger(state, GetObject<YimMenu::Vehicle>(state, 1).GetGear());
return 1;
}
static int GetRevRatio(lua_State* state)
{
lua_pushnumber(state, GetObject<YimMenu::Vehicle>(state, 1).GetRevRatio());
return 1;
}
static int GetSpeed(lua_State* state)
{
lua_pushnumber(state, GetObject<YimMenu::Vehicle>(state, 1).GetSpeed());
return 1;
}
static int Upgrade(lua_State* state)
{
GetObject<YimMenu::Vehicle>(state, 1).Upgrade();
return 0;
}
static int GetPlateText(lua_State* state)
{
auto text = GetObject<YimMenu::Vehicle>(state, 1).GetPlateText();
lua_pushlstring(state, text.c_str(), text.size());
return 1;
}
static int SetPlateText(lua_State* state)
{
GetObject<YimMenu::Vehicle>(state, 1).SetPlateText(CheckStringSafe(state, 2));
return 0;
}
// GetOwnedMods
static int IsSeatFree(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Vehicle>(state, 1).IsSeatFree(luaL_checkinteger(state, 2)));
return 1;
}
static int SupportsBoost(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Vehicle>(state, 1).SupportsBoost());
return 1;
}
static int IsBoostActive(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Vehicle>(state, 1).IsBoostActive());
return 1;
}
static int SetBoostCharge(lua_State* state)
{
GetObject<YimMenu::Vehicle>(state, 1).SetBoostCharge(lua_gettop(state) >= 2 ? luaL_checkinteger(state, 3) : 100);
return 0;
}
static int LowerStance(lua_State* state)
{
GetObject<YimMenu::Vehicle>(state, 1).LowerStance(CheckBooleanSafe(state, 2));
return 0;
}
static int GetFullName(lua_State* state)
{
auto name = GetObject<YimMenu::Vehicle>(state, 1).GetFullName();
lua_pushlstring(state, name.c_str(), name.size());
return 1;
}
virtual void Register(lua_State* state) override
{
luaL_newmetatable(state, "Vehicle");
{
lua_newtable(state);
{
RegisterEntityMethods(state); // re-registering the entity methods under the vehicle table is more efficient than subclassing
SetFunction(state, Fix, "fix");
SetFunction(state, GetGear, "get_gear");
SetFunction(state, GetRevRatio, "get_rev_ratio");
SetFunction(state, GetSpeed, "get_speed");
SetFunction(state, Upgrade, "upgrade");
SetFunction(state, GetPlateText, "get_plate_text");
SetFunction(state, SetPlateText, "set_plate_text");
SetFunction(state, IsSeatFree, "is_seat_free");
SetFunction(state, SupportsBoost, "supports_boost");
SetFunction(state, IsBoostActive, "is_boost_active");
SetFunction(state, SetBoostCharge, "set_boost_charge");
SetFunction(state, LowerStance, "lower_stance");
SetFunction(state, GetFullName, "get_full_name");
}
lua_setfield(state, -2, "__index"); // prototype
}
Metatable<YimMenu::Vehicle>::Register(state);
Metatable<YimMenu::Entity>::AddSubclass<YimMenu::Vehicle>();
lua_newtable(state);
SetConstructor<New>(state);
SetFunction(state, LatentFunction<Create>, "create");
lua_setglobal(state, "Vehicle");
}
};
Vehicle _Vehicle;
}