feat(lua): sprint 2

This commit is contained in:
maybegreat48
2025-06-27 21:35:10 -04:00
parent 1f1b924077
commit 59ae786c39
16 changed files with 13725 additions and 12850 deletions
+15
View File
@@ -43,6 +43,7 @@ namespace YimMenu
bool m_RunningScriptCallbacks = false;
ScriptCallback* m_CurrentlyExecutingCallback = nullptr;
std::unordered_map<std::uint32_t, std::vector<int>> m_EventHandlers;
bool m_NativesLoaded = false; // TODO: move this to a LuaResource
// Calls the function at the top of stack. If this returns false the stack would have nothing on it
bool CallFunction(int n_args, int n_results, lua_State* override_state = nullptr);
@@ -133,5 +134,19 @@ namespace YimMenu
void AddEventHandler(std::uint32_t event, int handler);
bool DispatchEvent(std::uint32_t event, const DispatchEventCallback& add_arguments_cb, bool handle_result = false);
// ------- TODO: move these into a resource
bool AreNativesLoaded() const
{
return m_NativesLoaded;
}
void SetNativesLoaded()
{
m_NativesLoaded = true;
}
// --------------
};
}
+24 -1
View File
@@ -1,4 +1,5 @@
#include "lua.hpp"
#include "core/util/Joaat.hpp"
#undef GetObject // another dumb Windows.h definition
namespace YimMenu::Lua
@@ -6,7 +7,7 @@ namespace YimMenu::Lua
template<typename T>
class Metatable
{
static int m_Index;
inline static int m_Index;
public:
static inline void Register(lua_State* state)
@@ -101,4 +102,26 @@ namespace YimMenu::Lua
lua_setmetatable(state, -2);
return reinterpret_cast<T*>(data);
}
inline std::uint32_t GetHashArgument(lua_State* state, int index)
{
if (lua_type(state, index) == LUA_TSTRING)
return Joaat(lua_tostring(state, index));
else
return luaL_checkinteger(state, index);
}
// luaL_checkstring automatically converts ints into strings, which we don't want
inline const char* CheckStringSafe(lua_State* state, int index)
{
luaL_checktype(state, index, LUA_TSTRING);
return lua_tostring(state, index);
}
// lua doesn't even offer a check function for bools
inline bool CheckBooleanSafe(lua_State* state, int index)
{
luaL_checktype(state, index, LUA_TBOOLEAN);
return lua_toboolean(state, index);
}
}
+2 -2
View File
@@ -54,12 +54,12 @@ namespace YimMenu::Lua
static int RegisterEventHandler(lua_State* state)
{
auto event_name = luaL_checkstring(state, 1);
auto event_name = GetHashArgument(state, 1);
luaL_checktype(state, 2, LUA_TFUNCTION);
lua_pushvalue(state, 2);
int handler = luaL_ref(state, LUA_REGISTRYINDEX);
LuaScript::GetScript(state).AddEventHandler(Joaat(event_name), handler);
LuaScript::GetScript(state).AddEventHandler(event_name, handler);
return 0;
}
+1 -1
View File
@@ -11,7 +11,7 @@ namespace YimMenu::Lua
static int Joaat(lua_State* state)
{
const char* string = luaL_checkstring(state, 1);
const char* string = CheckStringSafe(state, 1);
lua_pushinteger(state, (int)YimMenu::Joaat(string));
return 1;
}
+12764 -12730
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+99 -2
View File
@@ -118,9 +118,106 @@ enum class NativeIndex
{natives_buf}
// clang-format on
""")
# make sure we block obvious footguns
lua_blacklist = {
"WAIT": "Use script.yield instead",
"REGISTER_SCRIPT_VARIABLE": "Not allowed",
"UNREGISTER_SCRIPT_VARIABLE": "Not allowed",
"FORCE_CHECK_SCRIPT_VARIABLES": "Not allowed",
"NETWORK_DELETE_CHARACTER": "Not allowed",
"NETWORK_MANUAL_DELETE_CHARACTER": "Not allowed",
"NET_GAMESERVER_DELETE_CHARACTER": "Not allowed",
"NETWORK_REPORT_CODE_TAMPER": "Not allowed",
"ADD_OWNED_EXPLOSION": "ADD_OWNED_EXPLOSION is no longer safe to use",
# more telemetry
"START_BEING_BOSS": "Not allowed",
"START_BEING_GOON": "Not allowed",
"END_BEING_BOSS": "Not allowed",
"END_BEING_GOON": "Not allowed",
"HIRED_LIMO": "Not allowed",
"ORDER_BOSS_VEHICLE": "Not allowed",
"CHANGE_UNIFORM": "Not allowed",
"CHANGE_GOON_LOOKING_FOR_WORK": "Not allowed",
"SEND_METRIC_GHOSTING_TO_PLAYER": "Not allowed",
"SEND_METRIC_VIP_POACH": "Not allowed",
"SEND_METRIC_PUNISH_BODYGUARD": "Not allowed",
}
def get_blacklist_reason(native: str):
if native in lua_blacklist:
return lua_blacklist[native]
if "PLAYSTATS" in native:
return "Not allowed" # there's no good reason for scripts to call telemetry natives
return None
def native_type_to_lua_type(type: str):
if type == "void":
return "n" # nothing
elif type == "const char*" or type == "char*":
return "s" # string
elif type == "int" or type == "Any":
return "i" # int
elif type == "Hash":
return "h" # hash
elif type == "float":
return "f" # float
elif type == "BOOL":
return "b" # boolean
elif type == "Vector3" or type == "Vector3*":
return "v" # vector
elif "*" in type:
return "p" # pointer
else:
return "i" # Ped, Entity, etc.
def generate_lua_func_signature(native: NativeFunc):
sig = ""
n = 0
for arg in native.args:
sig += chr(97 + n) + ","
n += 1
if n >= 26:
n = -32 # switch to uppercase letters (97 - 30 = A)
sig = sig[:-1]
return sig
def generate_lua_param_string(native: NativeFunc):
string = ""
for arg in native.args:
string += native_type_to_lua_type(arg.type)
string += "=" + native_type_to_lua_type(native.return_type)
return string
def create_lua_func(native: NativeFunc):
blacklist_reason = get_blacklist_reason(native.name)
sign = generate_lua_func_signature(native)
if sign != "":
sign = ","+sign
using_varargs = len(native.args) > 2
if blacklist_reason:
return f"{native.name}=function()error('{blacklist_reason}')end,"
return f"{native.name}=function({"..." if using_varargs else generate_lua_func_signature(native)}){"" if native.return_type == "void" else "return "}_I({native.native_index},'{generate_lua_param_string(native)}'{",..." if using_varargs else sign})end,"
def create_lua_namespace(name: str, natives: list[NativeFunc]):
string = f"\t\"{name}={{"
for native in natives:
string += create_lua_func(native)
string = string[:-1] + "}\",\n"
return string
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"
for ns, natives_list in natives.items():
string += create_lua_namespace(ns, natives_list)
string += f"}};\n\nint g_NumLuaNativeDefs = {len(natives.items())};"
file.write(string)
if __name__ == "__main__":
load_natives_data()
load_crossmap_data()
write_crossmap_header()
write_natives_header()
write_natives_header()
create_lua_defs()
+7
View File
@@ -42,6 +42,13 @@ namespace YimMenu
m_CallContext.FixVectors();
}
constexpr void EndCall(int index, bool fix_vectors)
{
m_Handlers[index](&m_CallContext);
if (fix_vectors)
m_CallContext.FixVectors();
}
template<typename T>
constexpr void PushArg(T&& value)
{
+335 -99
View File
@@ -3313,7 +3313,7 @@
"0x3CDC1E622CCE0356": {
"name": "OVERRIDE_VEH_HORN",
"jhash": "0x2ACAB783",
"comment": "Overrides the vehicle's horn hash.\nWhen changing this hash on a vehicle, it will not return the 'overwritten' hash. It will still always return the default horn hash (same as GET_VEHICLE_DEFAULT_HORN)\n\nvehicle - the vehicle whose horn should be overwritten\nmute - p1 seems to be an option for muting the horn\np2 - maybe a horn id, since the function AUDIO::GET_VEHICLE_DEFAULT_HORN(veh) exists?",
"comment": "Overrides the vehicle's horn hash.\nWhen changing this hash on a vehicle, it will not return the 'overwritten' hash. It will still always return the default horn hash (same as GET_VEHICLE_DEFAULT_HORN)\n\nvehicle - the vehicle whose horn should be overwritten",
"params": [
{
"type": "Vehicle",
@@ -3373,7 +3373,7 @@
"0x58BB377BEC7CD5F4": {
"name": "SET_VEHICLE_CONVERSATIONS_PERSIST",
"jhash": "0x8CE63FA1",
"comment": "SET_VEHICLE_CONVERSATIONS_PERSIST?",
"comment": "",
"params": [
{
"type": "BOOL",
@@ -4193,7 +4193,7 @@
"0xBAC7FC81A75EC1A1": {
"name": "STOP_AUDIO_SCENES",
"jhash": "0xF6C7342A",
"comment": "??",
"comment": "",
"params": [],
"return_type": "void",
"build": "811"
@@ -4882,6 +4882,31 @@
"return_type": "void",
"build": "811"
},
"0xC9D623C5A3D8FD5D": {
"name": "SET_INDIVIDUAL_PORTAL_SETTINGS_OVERRIDE",
"jhash": "",
"comment": "",
"params": [
{
"type": "Hash",
"name": "interiorNameHash"
},
{
"type": "int",
"name": "roomIndex"
},
{
"type": "int",
"name": "doorIndex"
},
{
"type": "const char*",
"name": "newPortalSettingsName"
}
],
"return_type": "void",
"build": "889"
},
"0xB4BBFD9CD8B3922B": {
"name": "REMOVE_PORTAL_SETTINGS_OVERRIDE",
"jhash": "0xD24B4D0C",
@@ -4895,10 +4920,31 @@
"return_type": "void",
"build": "811"
},
"0x8EF105736194F80C": {
"name": "REMOVE_INDIVIDUAL_PORTAL_SETTINGS_OVERRIDE",
"jhash": "",
"comment": "",
"params": [
{
"type": "Hash",
"name": "interiorNameHash"
},
{
"type": "int",
"name": "roomIndex"
},
{
"type": "int",
"name": "doorIndex"
}
],
"return_type": "void",
"build": "889"
},
"0xE4E6DD5566D28C82": {
"name": "STOP_SMOKE_GRENADE_EXPLOSION_SOUNDS",
"jhash": "0x7262B5BA",
"comment": "STOP_S[MOKE_GRENADE_EXPLOSION_SOUNDS]?",
"comment": "",
"params": [],
"return_type": "void",
"build": "811"
@@ -9821,6 +9867,23 @@
"return_type": "void",
"build": "811"
},
"0x1FA904B60E492336": {
"name": "GET_CUT_FILE_OFFSET",
"jhash": "",
"comment": "",
"params": [
{
"type": "const char*",
"name": "cutsceneName"
},
{
"type": "int",
"name": "index"
}
],
"return_type": "Vector3",
"build": "889"
},
"0x0ABC54DE641DC0FC": {
"name": "GET_CUT_FILE_CONCAT_COUNT",
"jhash": "0xFD8B1AC2",
@@ -10319,11 +10382,11 @@
"0x2F137B508DE238F2": {
"name": "NETWORK_SET_MOCAP_CUTSCENE_CAN_BE_SKIPPED",
"jhash": "0x8338DA1D",
"comment": "Stops current cutscene with a fade transition\np0: always true in R* Scripts\nYou will need to manually fade the screen back in\nSET_CUTSCENE_INPUTS_PARTIALLY_FADE?",
"comment": "",
"params": [
{
"type": "BOOL",
"name": "p0"
"name": "toggle"
}
],
"return_type": "void",
@@ -13335,7 +13398,7 @@
"0x1218E6886D3D8327": {
"name": "IS_ENTITY_STATIC",
"jhash": "0x928E12E9",
"comment": "a static ped will not react to natives like \"APPLY_FORCE_TO_ENTITY\" or \"SET_ENTITY_VELOCITY\" and oftentimes will not react to task-natives like \"TASK::TASK_COMBAT_PED\". The only way I know of to make one of these peds react is to ragdoll them (or sometimes to use CLEAR_PED_TASKS_IMMEDIATELY(). Static peds include almost all far-away peds, beach-combers, peds in certain scenarios, peds crossing a crosswalk, peds walking to get back into their cars, and others. If anyone knows how to make a ped non-static without ragdolling them, please edit this with the solution.\n\nhow can I make an entity static???",
"comment": "a static ped will not react to natives like \"APPLY_FORCE_TO_ENTITY\" or \"SET_ENTITY_VELOCITY\" and oftentimes will not react to task-natives like \"TASK::TASK_COMBAT_PED\". The only way I know of to make one of these peds react is to ragdoll them (or sometimes to use CLEAR_PED_TASKS_IMMEDIATELY(). Static peds include almost all far-away peds, beach-combers, peds in certain scenarios, peds crossing a crosswalk, peds walking to get back into their cars, and others. If anyone knows how to make a ped non-static without ragdolling them, please edit this with the solution.",
"params": [
{
"type": "Entity",
@@ -14243,7 +14306,7 @@
"0x43D3807C077261E3": {
"name": "STOP_SYNCHRONIZED_ENTITY_ANIM",
"jhash": "0xE27D2FC1",
"comment": "p1 sync task id?",
"comment": "",
"params": [
{
"type": "Entity",
@@ -17619,6 +17682,23 @@
"_GET_PED_INSIDE_EXPLOSION_AREA",
"_GET_ENTITY_INSIDE_EXPLOSION_AREA"
]
},
"0x5241DB47A8B8AD54": {
"name": "_NETWORK_EXPECT_EXPLOSION_EVENTS_FOR_PLAYER",
"jhash": "",
"comment": "",
"params": [
{
"type": "BOOL",
"name": "expect"
},
{
"type": "Player",
"name": "player"
}
],
"return_type": "void",
"build": "889"
}
},
"GRAPHICS": {
@@ -20345,7 +20425,7 @@
"0x845BAD77CC770633": {
"name": "ATTACH_TV_AUDIO_TO_ENTITY",
"jhash": "0x784944DB",
"comment": "Might be more appropriate in AUDIO?",
"comment": "",
"params": [
{
"type": "Entity",
@@ -21040,7 +21120,7 @@
"0x6D955F6A9E0295B1": {
"name": "GRASSBATCH_ENABLE_FLATTENING_IN_SPHERE",
"jhash": "",
"comment": "Wraps 0xAAE9BE70EC7C69AB with FLT_MAX as p7, Jenkins: 0x73E96210?",
"comment": "Wraps 0xAAE9BE70EC7C69AB with FLT_MAX as p7",
"params": [
{
"type": "float",
@@ -25578,7 +25658,7 @@
"0xAE4E8157D9ECF087": {
"name": "END_TEXT_COMMAND_UNPARSED_SCALEFORM_STRING",
"jhash": "0x2E80DB52",
"comment": "Same as END_TEXT_COMMAND_SCALEFORM_STRING but does not perform HTML conversion for text tokens.\n\nEND_TEXT_COMMAND_VIA_SPECIAL_MODIFIABLE_STRING?",
"comment": "Same as END_TEXT_COMMAND_SCALEFORM_STRING but does not perform HTML conversion for text tokens.",
"params": [],
"return_type": "void",
"build": "811",
@@ -31056,7 +31136,7 @@
"0xA17784FCA9548D15": {
"name": "SET_FAKE_GPS_PLAYER_POSITION_THIS_FRAME",
"jhash": "",
"comment": "p2 maybe z float?",
"comment": "",
"params": [
{
"type": "float",
@@ -31067,8 +31147,8 @@
"name": "y"
},
{
"type": "Any",
"name": "p2"
"type": "float",
"name": "z"
}
],
"return_type": "void",
@@ -39374,6 +39454,14 @@
"return_type": "BOOL",
"build": "811"
},
"0xE2BCD0EFAE90D1F4": {
"name": "_IS_XBOXPC_VERSION",
"jhash": "",
"comment": "",
"params": [],
"return_type": "BOOL",
"build": "813"
},
"0x9F1935CA1F724008": {
"name": "IS_AUSSIE_VERSION",
"jhash": "0x944BA1DC",
@@ -51020,6 +51108,19 @@
"_NETWORK_SHOP_CHECKOUT_START"
]
},
"0x4B64CD6D18474126": {
"name": "NET_GAMESERVER_CHECKOUT_PENDING",
"jhash": "",
"comment": "",
"params": [
{
"type": "int",
"name": "transactionId"
}
],
"return_type": "BOOL",
"build": "889"
},
"0x3C5FD37B5499582E": {
"name": "NET_GAMESERVER_BEGIN_SERVICE",
"jhash": "",
@@ -51360,6 +51461,14 @@
"return_type": "BOOL",
"build": "811"
},
"0xA6BC0D9BCF9662FA": {
"name": "_NETWORK_MULTIPLAYER_CROSSPLAY_NOT_ALLOWED",
"jhash": "",
"comment": "For the XboxPC version this returns true if XPRIVILEGE_MULTIPLAYER_SESSIONS is granted but XPRIVILEGE_CROSS_PLAY is NOT granted.\nFor more information, see https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/live/features/identity/privileges/concepts/live-user-privileges-client#privilege-ids-to-check\n\nAlways returns false for non-XboxPC versions.",
"params": [],
"return_type": "BOOL",
"build": "889"
},
"0x1353F87E89946207": {
"name": "NETWORK_HAS_AGE_RESTRICTIONS",
"jhash": "",
@@ -51737,6 +51846,40 @@
"return_type": "BOOL",
"build": "811"
},
"0x6FA9825D0B5A721B": {
"name": "NETWORK_CHECK_CAN_ACCESS_AND_ALERT",
"jhash": "",
"comment": "",
"params": [],
"return_type": "BOOL",
"build": "889"
},
"0x967E6FB554E1B6DE": {
"name": "_NETWORK_GET_ACCESS_CODE_LABEL_HEADING",
"jhash": "",
"comment": "",
"params": [
{
"type": "int",
"name": "accessCode"
}
],
"return_type": "const char*",
"build": "889"
},
"0x214CA1730793EBA8": {
"name": "_NETWORK_GET_ACCESS_CODE_LABEL_BODY",
"jhash": "",
"comment": "",
"params": [
{
"type": "int",
"name": "accessCode"
}
],
"return_type": "const char*",
"build": "889"
},
"0x9747292807126EDA": {
"name": "NETWORK_IS_MULTIPLAYER_DISABLED",
"jhash": "0x05518C0F",
@@ -51962,23 +52105,6 @@
"return_type": "BOOL",
"build": "811"
},
"0xA02E59562D711006": {
"name": "NETWORK_SESSION_END",
"jhash": "0xBCACBEA2",
"comment": "p0 is always false and p1 varies.\nNETWORK_SESSION_END(0, 1)\nNETWORK_SESSION_END(0, 0)\nResults in: \"Connection to session lost due to an unknown network error. Please return to Grand Theft Auto V and try again later.\"",
"params": [
{
"type": "BOOL",
"name": "p0"
},
{
"type": "BOOL",
"name": "p1"
}
],
"return_type": "BOOL",
"build": "811"
},
"0xB9351A07A0D458B1": {
"name": "NETWORK_SESSION_LEAVE",
"jhash": "",
@@ -56501,9 +56627,9 @@
"build": "811"
},
"0xDBDF80673BBA3D65": {
"name": "_NETWORK_DOES_COMMUNICATION_GROUP_EXIST",
"name": "_NETWORK_DOES_COMMUNICATION_GROUP_HAVE_PERMISSION",
"jhash": "",
"comment": "communicationType: 0 = VOICE; 1 = TEXT_CHAT; 2 = TEXT_MESSAGE; 3 = EMAIL; 4 = USER_CONTENT; 5 = USER_TEXT",
"comment": "communicationType: 0 = VOICE; 1 = TEXT_CHAT; 2 = TEXT_MESSAGE; 3 = EMAIL; 4 = USER_CONTENT; 5 = USER_TEXT",
"params": [
{
"type": "int",
@@ -56511,7 +56637,23 @@
}
],
"return_type": "BOOL",
"build": "811"
"build": "811",
"old_names": [
"_NETWORK_DOES_COMMUNICATION_GROUP_EXIST"
]
},
"0x20C12650830A64EC": {
"name": "_NETWORK_DOES_COMMUNICATION_GROUP_HAVE_SETTINGS_ENABLED",
"jhash": "",
"comment": "",
"params": [
{
"type": "int",
"name": "communicationType"
}
],
"return_type": "BOOL",
"build": "889"
},
"0x40DF02F371F40883": {
"name": "_NETWORK_GET_COMMUNICATION_GROUP_FLAGS",
@@ -56526,6 +56668,32 @@
"return_type": "int",
"build": "811"
},
"0x97F35B898D2D067F": {
"name": "_NETWORK_GET_COMMUNICATION_GROUP_DEFAULT_FLAGS",
"jhash": "",
"comment": "",
"params": [
{
"type": "int",
"name": "communicationType"
}
],
"return_type": "int",
"build": "889"
},
"0xBF66ACD9AE81A99F": {
"name": "_NETWORK_GET_COMMUNICATION_GROUP_VALUE",
"jhash": "",
"comment": "",
"params": [
{
"type": "int",
"name": "communicationType"
}
],
"return_type": "int",
"build": "889"
},
"0xE549F846DE7D32D5": {
"name": "_NETWORK_SET_COMMUNICATION_GROUP_FLAGS",
"jhash": "",
@@ -58928,11 +59096,11 @@
"0xC6FCEE21C6FCEE21": {
"name": "NETWORK_SET_TASK_CUTSCENE_INSCOPE_MULTIPLER",
"jhash": "",
"comment": "A value between 1.0 and 5.0\n\n_NETWORK_SET_TASK_CUTSCENE_PROXIMITY_SCALE?",
"comment": "A value between 1.0 and 5.0",
"params": [
{
"type": "Any",
"name": "p0"
"type": "float",
"name": "multiplier"
}
],
"return_type": "void",
@@ -60280,6 +60448,14 @@
"return_type": "void",
"build": "811"
},
"0xCBD02360C5E16871": {
"name": "NETWORK_SYNC_CLOCK_TIME_OVERRIDE",
"jhash": "",
"comment": "Does nothing in final builds.",
"params": [],
"return_type": "void",
"build": "889"
},
"0xD7C95D322FF57522": {
"name": "NETWORK_IS_CLOCK_TIME_OVERRIDDEN",
"jhash": "0x2465296D",
@@ -61195,27 +61371,6 @@
"return_type": "void",
"build": "811"
},
"0x1775961C2FBBCB5C": {
"name": "NETWORK_SET_PROPERTY_ID",
"jhash": "0x5A74E873",
"comment": "value must be < 255",
"params": [
{
"type": "int",
"name": "id"
}
],
"return_type": "void",
"build": "811"
},
"0xC2B82527CA77053E": {
"name": "NETWORK_CLEAR_PROPERTY_ID",
"jhash": "0x38BC35C8",
"comment": "",
"params": [],
"return_type": "void",
"build": "811"
},
"0x367EF5E2F439B4C6": {
"name": "NETWORK_SET_PLAYER_MENTAL_STATE",
"jhash": "0x53C9563C",
@@ -67153,7 +67308,7 @@
"0xADBE4809F19F927A": {
"name": "ONLY_CLEAN_UP_OBJECT_WHEN_OUT_OF_RANGE",
"jhash": "0x2048A7DD",
"comment": "is this like setting is as no longer needed?",
"comment": "",
"params": [
{
"type": "Object",
@@ -78654,35 +78809,6 @@
"return_type": "void",
"build": "811"
},
"0x082D79E15302F0C2": {
"name": "IS_PED_IN_SPHERE_AREA_OF_ANY_ENEMY_PEDS",
"jhash": "",
"comment": "",
"params": [
{
"type": "Ped",
"name": "ped"
},
{
"type": "float",
"name": "x"
},
{
"type": "float",
"name": "y"
},
{
"type": "float",
"name": "z"
},
{
"type": "float",
"name": "range"
}
],
"return_type": "BOOL",
"build": "811"
},
"0xC158D28142A34608": {
"name": "STOP_PED_WEAPON_FIRING_WHEN_DROPPED",
"jhash": "0x4AC3421E",
@@ -81975,7 +82101,7 @@
"0x15F944730C832252": {
"name": "SET_USE_KINEMATIC_PHYSICS",
"jhash": "",
"comment": "PED_RAGDOLL_BUMP Proof?",
"comment": "",
"params": [
{
"type": "Entity",
@@ -82867,7 +82993,7 @@
"0x0032A6DBA562C518": {
"name": "RESET_LAW_RESPONSE_DELAY_OVERRIDE",
"jhash": "0x47CAB814",
"comment": "2 matches in 1 script - am_hold_up\n\nUsed in multiplayer scripts?",
"comment": "",
"params": [],
"return_type": "void",
"build": "811"
@@ -83754,6 +83880,14 @@
"return_type": "void",
"build": "811"
},
"0x875BDD898B99C8CE": {
"name": "GET_PLAYER_TARGETING_MODE",
"jhash": "",
"comment": "",
"params": [],
"return_type": "int",
"build": "889"
},
"0x5702B917B99DB1CD": {
"name": "SET_PLAYER_TARGET_LEVEL",
"jhash": "0x772DA539",
@@ -85094,7 +85228,7 @@
"0x11D5F725F0E780E0": {
"name": "SET_PLAYER_PHONE_PALETTE_IDX",
"jhash": "",
"comment": "example:\n\nflags: 0-6\n\nPLAYER::SET_PLAYER_RESET_FLAG_PREFER_REAR_SEATS(PLAYER::PLAYER_ID(), 6);\n\nwouldnt the flag be the seatIndex?",
"comment": "",
"params": [
{
"type": "Player",
@@ -85102,7 +85236,7 @@
},
{
"type": "int",
"name": "flags"
"name": "idx"
}
],
"return_type": "void",
@@ -94179,6 +94313,39 @@
"_PLAYSTATS_NJVS_VOTE"
]
},
"0x01D8B04D02F1217F": {
"name": "_PLAYSTATS_DEATH_INFO",
"jhash": "",
"comment": "",
"params": [
{
"type": "Ped",
"name": "victimPed"
},
{
"type": "Ped",
"name": "killerPed"
},
{
"type": "int",
"name": "mentalState"
},
{
"type": "BOOL",
"name": "revengeKill"
},
{
"type": "int",
"name": "victimKvK"
},
{
"type": "int",
"name": "killerKvK"
}
],
"return_type": "void",
"build": "889"
},
"0x46A70777BE6CEAB9": {
"name": "PLAYSTATS_FM_MISSION_END",
"jhash": "",
@@ -94918,6 +95085,19 @@
],
"return_type": "void",
"build": "811"
},
"0x574A7808450E141C": {
"name": "_PLAYSTATS_SCRIPT_EVENT_FPOM",
"jhash": "",
"comment": "",
"params": [
{
"type": "Any*",
"name": "data"
}
],
"return_type": "void",
"build": "889"
}
},
"STREAMING": {
@@ -96795,10 +96975,6 @@
{
"type": "const char*",
"name": "overrideEntryClipsetName"
},
{
"type": "Any",
"name": "p7"
}
],
"return_type": "void",
@@ -98734,6 +98910,19 @@
"return_type": "void",
"build": "811"
},
"0xF5D1F489147CB683": {
"name": "SET_SEQUENCE_PREVENT_MIGRATION",
"jhash": "",
"comment": "",
"params": [
{
"type": "int",
"name": "taskSequenceId"
}
],
"return_type": "void",
"build": "889"
},
"0x00A9010CFE1E3533": {
"name": "GET_SEQUENCE_PROGRESS",
"jhash": "0xA3419909",
@@ -103047,6 +103236,23 @@
"return_type": "int",
"build": "811"
},
"0x686ECCD99D4E61BB": {
"name": "SET_PED_WAYPOINT_PROGRESS",
"jhash": "",
"comment": "",
"params": [
{
"type": "Ped",
"name": "ped"
},
{
"type": "int",
"name": "progress"
}
],
"return_type": "void",
"build": "889"
},
"0xE6A877C64CAF1BC5": {
"name": "GET_PED_WAYPOINT_DISTANCE",
"jhash": "0x084B35B0",
@@ -103511,6 +103717,19 @@
"return_type": "void",
"build": "811"
},
"0xE435D3539EFDCD1B": {
"name": "VEHICLE_WAYPOINT_PLAYBACK_GET_IS_PAUSED",
"jhash": "",
"comment": "",
"params": [
{
"type": "Vehicle",
"name": "vehicle"
}
],
"return_type": "BOOL",
"build": "889"
},
"0xDC04FCAA7839D492": {
"name": "VEHICLE_WAYPOINT_PLAYBACK_RESUME",
"jhash": "0xBEB14C82",
@@ -104073,6 +104292,23 @@
"return_type": "void",
"build": "811"
},
"0x0EFE4834A2F40563": {
"name": "_SET_AMBIENT_PED_ENABLE_COLLISION_ON_NETWORK_CLONE_WHEN_FIXED",
"jhash": "",
"comment": "",
"params": [
{
"type": "Ped",
"name": "ped"
},
{
"type": "BOOL",
"name": "enable"
}
],
"return_type": "void",
"build": "889"
},
"0x349CE7B56DAFD95C": {
"name": "IS_MOVE_BLEND_RATIO_STILL",
"jhash": "0xE9DAF877",
@@ -104180,7 +104416,7 @@
"0xE45B7F222DE47E09": {
"name": "IS_PED_STRAFING",
"jhash": "0xEFEED13C",
"comment": "What's strafing?",
"comment": "",
"params": [
{
"type": "Ped",
@@ -108625,7 +108861,7 @@
"0xA178472EBB8AE60D": {
"name": "SET_HELI_BLADES_FULL_SPEED",
"jhash": "0x033A9408",
"comment": "Equivalent of SET_HELI_BLADES_SPEED(vehicleHandle, 1.0f);\n\nthis native works on planes to?",
"comment": "Equivalent of SET_HELI_BLADES_SPEED(vehicleHandle, 1.0f);",
"params": [
{
"type": "Vehicle",
@@ -108844,7 +109080,7 @@
"0x2497C4717C8B881E": {
"name": "SET_VEHICLE_ENGINE_ON",
"jhash": "0x7FBC86F1",
"comment": "Starts or stops the engine on the specified vehicle.\n\nvehicle: The vehicle to start or stop the engine on.\nvalue: true to turn the vehicle on; false to turn it off.\ninstantly: if true, the vehicle will be set to the state immediately; otherwise, the current driver will physically turn on or off the engine.\ndisableAutoStart: If true, the system will prevent the engine from starting when the player got into it.\n\nfrom what I've tested when I do this to a helicopter the propellers turn off after the engine has started. so is there any way to keep the heli propellers on?",
"comment": "Starts or stops the engine on the specified vehicle.\n\nvehicle: The vehicle to start or stop the engine on.\nvalue: true to turn the vehicle on; false to turn it off.\ninstantly: if true, the vehicle will be set to the state immediately; otherwise, the current driver will physically turn on or off the engine.\ndisableAutoStart: If true, the system will prevent the engine from starting when the player got into it.",
"params": [
{
"type": "Vehicle",
+213 -14
View File
@@ -1,13 +1,16 @@
#include "core/scripting/LuaLibrary.hpp"
#include "core/scripting/LuaScript.hpp"
#include "core/scripting/LuaUtils.hpp"
#include "core/scripting/LatentFunction.hpp"
#include "game/gta/Entity.hpp"
#include "Entity.hpp"
namespace YimMenu::Lua
{
// TODO: we need to automate this
class Entity : LuaLibrary
{
public:
using LuaLibrary::LuaLibrary;
static int New(lua_State* state)
@@ -100,26 +103,178 @@ namespace YimMenu::Lua
return 0;
}
static int GetHeading(lua_State* state)
{
lua_pushnumber(state, GetObject<YimMenu::Entity>(state, 1).GetHeading());
return 1;
}
static int SetHeading(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).SetHeading(luaL_checknumber(state, 2));
return 0;
}
static int GetSpeed(lua_State* state)
{
lua_pushnumber(state, GetObject<YimMenu::Entity>(state, 1).GetSpeed());
return 1;
}
static int SetCollision(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).SetCollision(lua_toboolean(state, 2));
return 0;
}
static int SetFrozen(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).SetFrozen(lua_toboolean(state, 2));
return 0;
}
static int Delete(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).Delete();
return 0;
}
// DeleteNetwork
static int IsNetworked(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Entity>(state, 1).IsNetworked());
return 1;
}
static int IsRemote(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Entity>(state, 1).IsRemote());
return 1;
}
static int HasControl(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Entity>(state, 1).HasControl());
return 1;
}
// GetNetworkObject
// GetOwner
static int GetNetworkObjectId(lua_State* state)
{
lua_pushinteger(state, GetObject<YimMenu::Entity>(state, 1).GetNetworkObjectId());
return 1;
}
static int PreventMigration(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).PreventMigration();
return 0;
}
static int ForceControl(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).ForceControl();
return 0;
}
static int RequestControl(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).RequestControl(lua_gettop(state) >= 2 ? luaL_checkinteger(state, 2) : 100);
return 0;
}
// ForceSync
static int IsInvincible(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Entity>(state, 1).IsInvincible());
return 1;
}
static int SetInvincible(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).SetInvincible(lua_toboolean(state, 2));
return 0;
}
static int IsDead(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Entity>(state, 1).IsDead());
return 1;
}
static int Kill(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).Kill();
return 0;
}
static int GetHealth(lua_State* state)
{
lua_pushinteger(state, GetObject<YimMenu::Entity>(state, 1).GetHealth());
return 1;
}
static int SetHealth(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).SetHealth(luaL_checkinteger(state, 2));
return 0;
}
static int GetMaxHealth(lua_State* state)
{
lua_pushinteger(state, GetObject<YimMenu::Entity>(state, 1).GetMaxHealth());
return 1;
}
static int IsVisible(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Entity>(state, 1).IsVisible());
return 1;
}
static int SetVisible(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).SetVisible(CheckBooleanSafe(state, 2));
return 0;
}
static int GetAlpha(lua_State* state)
{
lua_pushinteger(state, GetObject<YimMenu::Entity>(state, 1).GetAlpha());
return 1;
}
static int SetAlpha(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).SetAlpha(luaL_checkinteger(state, 2));
return 0;
}
static int ResetAlpha(lua_State* state)
{
GetObject<YimMenu::Entity>(state, 1).ResetAlpha();
return 0;
}
static int HasInterior(lua_State* state)
{
lua_pushboolean(state, GetObject<YimMenu::Entity>(state, 1).HasInterior());
return 1;
}
// Explode
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");
RegisterEntityMethods(state);
}
lua_setfield(state, -2, "__index"); // prototype
}
@@ -131,5 +286,49 @@ namespace YimMenu::Lua
}
};
void RegisterEntityMethods(lua_State* state)
{
SetFunction(state, Entity::GetHandle, "get_handle");
SetFunction(state, Entity::IsValid, "is_valid");
SetFunction(state, Entity::IsPed, "is_ped");
SetFunction(state, Entity::IsVehicle, "is_vehicle");
SetFunction(state, Entity::IsObject, "is_object");
SetFunction(state, Entity::IsPlayer, "is_player");
SetFunction(state, Entity::IsMissionEntity, "is_mission_entity");
SetFunction(state, Entity::GetModel, "get_model");
SetFunction(state, Entity::GetPosition, "get_position");
SetFunction(state, Entity::GetRotation, "get_rotation");
SetFunction(state, Entity::GetVelocity, "get_velocity");
SetFunction(state, Entity::SetPosition, "set_position");
SetFunction(state, Entity::SetRotation, "set_rotation");
SetFunction(state, Entity::SetVelocity, "set_velocity");
SetFunction(state, Entity::GetHeading, "get_heading");
SetFunction(state, Entity::SetHeading, "set_heading");
SetFunction(state, Entity::GetSpeed, "get_speed");
SetFunction(state, Entity::SetCollision, "set_collision");
SetFunction(state, Entity::SetFrozen, "set_frozen");
SetFunction(state, Entity::Delete, "delete");
SetFunction(state, Entity::IsNetworked, "is_networked");
SetFunction(state, Entity::IsRemote, "is_remote");
SetFunction(state, Entity::HasControl, "has_control");
SetFunction(state, Entity::GetNetworkObjectId, "get_network_object_id");
SetFunction(state, Entity::PreventMigration, "prevent_migration");
SetFunction(state, Entity::ForceControl, "force_control");
SetFunction(state, LatentFunction<Entity::RequestControl>, "request_control");
SetFunction(state, Entity::IsInvincible, "is_invincible");
SetFunction(state, Entity::SetInvincible, "set_invincible");
SetFunction(state, Entity::IsDead, "is_dead");
SetFunction(state, Entity::Kill, "kill");
SetFunction(state, Entity::GetHealth, "get_health");
SetFunction(state, Entity::SetHealth, "set_health");
SetFunction(state, Entity::GetMaxHealth, "get_max_health");
SetFunction(state, Entity::IsVisible, "is_visible");
SetFunction(state, Entity::SetVisible, "set_visible");
SetFunction(state, Entity::GetAlpha, "get_alpha");
SetFunction(state, Entity::SetAlpha, "set_alpha");
SetFunction(state, Entity::ResetAlpha, "reset_alpha");
SetFunction(state, Entity::HasInterior, "has_interior");
}
Entity _Entity;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "lua.hpp"
namespace YimMenu::Lua
{
void RegisterEntityMethods(lua_State* state);
}
+141
View File
@@ -0,0 +1,141 @@
#include "core/scripting/LuaLibrary.hpp"
#include "core/scripting/LuaScript.hpp"
#include "core/scripting/LuaUtils.hpp"
#include "game/gta/invoker/Invoker.hpp"
namespace YimMenu::Lua
{
class Invoker : LuaLibrary
{
using LuaLibrary::LuaLibrary;
static int GetInteger(lua_State* state, int idx)
{
if (lua_type(state, idx) == LUA_TBOOLEAN)
return static_cast<int>(lua_toboolean(state, idx)); // stand only coerces bools when an option is enabled, but I feel we should do it regardless
else
return luaL_checkinteger(state, idx);
}
static BOOL GetBoolean(lua_State* state, int idx)
{
if (lua_type(state, idx) == LUA_TNUMBER)
return static_cast<BOOL>(lua_tointeger(state, idx)); // coerce ints
else if (lua_type(state, idx) == LUA_TBOOLEAN)
return static_cast<BOOL>(lua_toboolean(state, idx));
else
return luaL_argerror(state, idx, "Expected boolean, got something else"); // lua can technically convert anything into a boolean, but it's a good idea to not do that
}
static const char* GetString(lua_State* state, int idx)
{
if (lua_type(state, idx) == LUA_TNIL || lua_type(state, idx) == LUA_TNONE)
return nullptr;
else
return CheckStringSafe(state, idx);
}
// thanks to Stand for the parameter string idea
// we're assuming that only trusted functions can call this directly (this assumption is incorrect, but would do for now)
static int InvokeNative(lua_State* state)
{
size_t params_len;
auto index = lua_tointeger(state, 1);
const char* parameters = lua_tolstring(state, 2, &params_len);
bool fix_vectors = false;
NativeInvoker invoker;
int vector_params = 0;
rage::fvector3* vectors_to_fix[4];
char return_type;
invoker.BeginCall();
for (int i = 0; i < params_len; i++)
{
auto type = parameters[i];
switch (type)
{
case 'i': // integer
invoker.PushArg<int>(GetInteger(state, 3 + i));
break;
case 'f': // float
invoker.PushArg<float>(luaL_checknumber(state, 3 + i));
break;
case 'h': // hash
invoker.PushArg<std::uint32_t>(GetHashArgument(state, 3 + i));
break;
case 'b': // boolean
invoker.PushArg<std::uint32_t>(GetBoolean(state, 3 + i));
break;
case 's': // string
invoker.PushArg<const char*>(GetString(state, 3 + i));
break;
case 'v': // Vector3* (not Vector3)
{
fix_vectors = true;
auto& vec = GetObject<rage::fvector3>(state, 3 + i);
auto script_vec = rage::scrVector(vec);
invoker.PushArg<void*>(&script_vec);
vectors_to_fix[vector_params++] = &vec;
break;
}
case 'p': // Any*
{
// idk what to do with this
luaL_argerror(state, 3 + i, "Pointers are not supported yet");
break;
}
case '=': // done + return
{
return_type = parameters[i + 1];
goto done; // can't break; out of the loop from here
}
}
}
done:
invoker.EndCall(index, false);
if (fix_vectors)
{
for (int i = 0; i < vector_params; i++)
{
*vectors_to_fix[i] = invoker.m_CallContext.GetSourceVector(i);
}
}
switch (return_type)
{
case 'n': // nothing ([v]oid is taken)
return 0;
case 'i': // integer
case 'h': // hash
lua_pushinteger(state, invoker.GetReturnValue<int>());
return 1;
case 'f': // float
lua_pushnumber(state, invoker.GetReturnValue<float>());
return 1;
case 'b': // boolean
lua_pushboolean(state, invoker.GetReturnValue<bool>());
return 1;
case 's': // string
lua_pushstring(state, invoker.GetReturnValue<const char*>());
return 1;
case 'v': // Vector3 (not Vector3*)
CreateObject<rage::fvector3>(state, invoker.GetReturnValue<rage::scrVector>());
return 1;
case 'p': // pointer
luaL_error(state, "Pointer returns are not supported"); // and probably never will be
}
return 0;
}
virtual void Register(lua_State* state) override
{
lua_pushcfunction(state, InvokeNative);
lua_setglobal(state, "_I"); // we're trying to keep the invoker code as short as possible
}
};
Invoker _Invoker;
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
#pragma once
extern const char* g_LuaNativeDefs[];
extern int g_NumLuaNativeDefs;
+52
View File
@@ -0,0 +1,52 @@
#include "core/scripting/LuaLibrary.hpp"
#include "core/scripting/LuaScript.hpp"
#include "core/scripting/LuaUtils.hpp"
#include "NativeDefs.hpp"
#include "core/util/Joaat.hpp"
namespace YimMenu::Lua
{
class Natives : LuaLibrary
{
using LuaLibrary::LuaLibrary;
static int LoadNatives(lua_State* state)
{
auto& script = LuaScript::GetScript(state);
if (script.AreNativesLoaded())
luaL_error(state, "Natives have already been loaded");
for (int i = 0; i < g_NumLuaNativeDefs; i++)
{
auto chunk = g_LuaNativeDefs[i];
if (luaL_dostring(state, chunk) != LUA_OK)
{
std::string err_copy = lua_tostring(state, -1);
lua_pop(state, 1);
luaL_error(state, "%s", err_copy.c_str());
}
}
script.SetNativesLoaded();
return 0;
}
static int AreNativesLoaded(lua_State* state)
{
auto& script = LuaScript::GetScript(state);
lua_pushboolean(state, script.AreNativesLoaded());
return 1;
}
virtual void Register(lua_State* state) override
{
lua_newtable(state);
SetFunction(state, LoadNatives, "load_natives");
SetFunction(state, AreNativesLoaded, "are_natives_loaded");
lua_setglobal(state, "natives");
}
};
Natives _Natives;
}
+5
View File
@@ -57,6 +57,11 @@ namespace rage
m_NumVectorRefs = 0;
}
rage::fvector3& GetSourceVector(int index)
{
return m_VectorRefSources[index];
}
protected:
void* m_ReturnValue; // 0x00
std::uint32_t m_ArgCount; // 0x08