Advertisement
LostProphet

RagePluginHook Natives

Dec 25th, 2017
236
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // NOTICE: This example is not meant to be executed, but is simply to show how to invoke natives.
  2.  
  3. /**
  4. * The RAGE Plugin Hook API includes a lot of functionality, but sometimes
  5. * you may need to invoke one of the game's natives for functionality not (or not yet) provided by
  6. * RAGE Plugin Hook.
  7. *
  8. * You can find lists of the game's natives using Google.
  9. *
  10. * Natives can be called using the dynamic object returned by NativeFunction.Natives.
  11. * Being dynamic, means that the compiler will not check whether an operation on the object is valid,
  12. * and any errors will only occur at runtime.
  13. *
  14. * This means that you can invoke members on it, as if any member existed.
  15. * Eg. NativeFunction.Natives.Yolo(1, 2, 3); would compile fine, despite no such method actually existing.
  16. *
  17. * The object will validate members at runtime, and you can use this to call natives.
  18. * Natives can be invoked using the method call syntax with the same name as the native.
  19. *
  20. * For example, to call GET_PLAYER_PED, you can type
  21. * NativeFunction.Natives.GET_PLAYER_PED(0);
  22. *
  23. * This will cause the API to invoke the native GET_PLAYER_PED with signed integer zero as the argument.
  24. **/
  25.  
  26. Ped playerPed = Game.LocalPlayer.Character;
  27.  
  28. // Technically, the API takes instances of Rage.Native.NativeArgument as arguments for the native invocations.
  29. NativeFunction.Natives.SET_ENTITY_HAS_GRAVITY(new NativeArgument(playerPed.Handle), new NativeArgument(true));
  30.  
  31. // However, NativeArgument has implicit operators to convert common types to a NativeArgument,
  32. // meaning you can pass an argument directly, and an instance of NativeArgument will be created implicitly.
  33. NativeFunction.Natives.SET_ENTITY_HAS_GRAVITY(playerPed.Handle, true); // Implicit conversions from int and bool to NativeArgument.
  34.  
  35. // While natives take the handles of entities like Peds, Vehicles, etc.
  36. // NativeArgument also has implicit operators for common API types like Ped, Vehicle, Blip, Player, Group, etc.
  37. // allowing you to pass objects of these types directly, without appending .Id, .Handle, etc.
  38. // Passing an entity will create an instance of NativeArgument with the entity's handle as value.
  39. NativeFunction.Natives.SET_ENTITY_HAS_GRAVITY(playerPed, true); // Implicit conversions from Ped and bool to NativeArgument.
  40.  
  41. // Some natives return a value. For these natives,
  42. // you must specify a return type if you want to get the returned value.
  43. // Return type is specfied as the one and only generic type on the method.
  44. int money = NativeFunction.Natives.GET_PED_MONEY<int>(playerPed, true);
  45.  
  46. // You can also specify common API types as the return type, like Ped, Vehicle, Group, Blip, Task, Vector3, etc.
  47. // When specifying one of these types as the return type, the API assumes that the native returns their corresponding handle or id.
  48. Ped ped = NativeFunction.Natives.x218297BF0CFD853B<Ped>(playerPed.CurrentVehicle, 0);
  49.  
  50. // If you use the method in an expression without specifying the return type, it will compile,
  51. // but at runtime you'll get an exception.
  52. money = NativeFunction.Natives.GET_PED_MONEY(playerPed, true);
  53.  
  54. // Some natives take a position as 3 separate parameters, consisting of the X, Y and Z components.
  55. System.Diagnostics.Debugger.Launch();
  56. Vector3 position = new Vector3(202.3442f, 3107.727f, 42.14632f);
  57. NativeFunction.Natives.SetEntityCoords(playerPed, position.X, position.Y, position.Z, true, true, true, false);
  58.  
  59. // However, if you pass a Vector3 specifically, the API will split it, and pass it as 3 separate parameters.
  60. // The following statement, and the one above both pass 8 arguments.
  61. NativeFunction.Natives.SetEntityCoords(playerPed, position, true, true, true, false);
  62.  
  63. // The same behaviour is supported for the following types: Vector2, Vector3, Vector4, Quaternion, Rotator.
  64. // When passing any of these types, their fields will be passed as separate arguments:
  65. NativeFunction.Natives.SetEntityQuaternion(playerPed, playerPed.CurrentVehicle.Orientation);
  66. // Is equivalent to:
  67. NativeFunction.Natives.SetEntityQuaternion(playerPed, playerPed.CurrentVehicle.Orientation.X, playerPed.CurrentVehicle.Orientation.Y, playerPed.CurrentVehicle.Orientation.Z);
  68.  
  69. // To conform to naming conventions (and simply to make the code prettier),
  70. // it is possible to specify the name in PascalCase.
  71. // The API will convert PascalCase names to the native name format.
  72. // Eg. if you type GetPedMoney, the API will convert this to GET_PED_MONEY, based on the upper case letters in the name.
  73. money = NativeFunction.Natives.GetPedMoney(playerPed, true);
  74.  
  75. // To call a native by name, its actual name must be used (guessed or speculated names will not work).
  76. // For some natives, the actual name is not known, and thus you must call these natives by their original 64-bit value (aka. hash).
  77. // The original hash of GET_PED_MONEY is 0x3F69145BBA87BAE7.
  78. // To call a native by its hash, start the method name with 'x', followed by the 64-bit value in hex.
  79. money = NativeFunction.Natives.x3F69145BBA87BAE7<int>(playerPed, true);
  80.  
  81. // Same natives outputs values by reference. That is, they take a pointer to a variable.
  82. // You can of course enable unsafe code, and then pass the address of your variables, as follows.
  83. // Note: Pointers cannot be passed to a dynamically dispatched operation, so you must cast it to IntPtr,
  84. // or another 64-bit type.
  85. unsafe
  86. {
  87.     uint boneId = 0;
  88.     bool value = NativeFunction.Natives.GetPedLastDamageBone<bool>(playerPed, (IntPtr)(&boneId));
  89. }
  90.  
  91. // Another way is to use the NativePointer class, which internally has a variable
  92. // which the API passes a pointer to, to the native.
  93. // After the call, the value can then be retrieved.
  94. // This allows the user of pointers, but without requiring unsafe code.
  95. using (NativePointer nativePointer = new NativePointer(sizeof(int)))
  96. {
  97.     bool value2 = NativeFunction.Natives.GetPedLastDamageBone<bool>(playerPed, nativePointer);
  98.     uint boneId2 = nativePointer.GetValue<uint>();
  99. }
  100.  
  101. // Of course, both of these methods are cumbersome.
  102. // Another, much more preferable way, is to use the ref and out keywords.
  103. // Whether a native uses the pointer as only in, or only out, you can use both ref and out, but if you use out, you cannot pass a value to the native.
  104. uint boneId3; // Doesn't need to be initialized, since the value will not be passed to the native.
  105. bool value3 = NativeFunction.Natives.GetPedLastDamageBone<bool>(playerPed, out boneId3);
  106.  
  107. uint boneId4 = 0; // Must be initialied, as its value will be passed to the native.
  108. bool value4 = NativeFunction.Natives.GetPedLastDamageBone<bool>(playerPed, ref boneId4);
  109.  
  110. // For natives taking a char*, it is not necessary to use pointers. Instead, simply pass a regular string,
  111. // and the API will take care of marshalling it to the native.
  112. uint hash = NativeFunction.Natives.GetHashKey<uint>("Hello World");
  113.  
  114. // For natives returning a char*, you can also pass string as the return type,
  115. // and the API will automatically marshal it for you.
  116. string liveryName = NativeFunction.Natives.GetLiveryName<string>(playerPed.CurrentVehicle, 0);
  117.  
  118. // Note, pointers cannot be used in generic types, so if you absolutely need the raw byte pointer returned by the native,
  119. // specify a 64-bit type, then cast it yourself.
  120. // You must cast to the return type first, since dynamic operations do not support casts to pointer types.
  121. // Note: char in C++ is byte in C#. a char in C# is a wchar_t in C++.
  122. unsafe
  123. {
  124.     byte* liveryName2 = (byte*)(IntPtr)NativeFunction.Natives.GetLiveryName<IntPtr>(playerPed.CurrentVehicle, 0);
  125.     IntPtr liveryNameAddress = NativeFunction.Natives.GetLiveryName<IntPtr>(playerPed.CurrentVehicle, 0);
  126. }
  127.  
  128. /**
  129.  * This concludes the guide for invoking natives. A couple of notes:
  130.  * Using PascalCase naming convention is prefered over original native names (GetPlayerPed vs GET_PLAYER_PED).
  131.  * Using the ref and out keywords is prefered over using raw pointers or NativePointer.
  132.  **/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement