Category Archives: GTA V

[V] Dynamically adding carcols

Hello everyone,

today we’re going to have a look at how to add carcol settings in GTA V to vehicles at runtime. The file contains the siren patterns for emergency vehicles among others and people have been using it to create their own pattern with the most recent research being made here: //www.lcpdfr.com/forums/topic/66806-researchwip-custom-light-patterns-through-carcolsymt/. When I stumbled across that post I decided to revisit my research on that topic as it was obvious that the current system was heavily limited, since it only allowed changes to be made before you start the game and only share patterns across a vehicle model.

MulleDK19 and I both had already made some interesting research on this topic and with the new information revealed in the topic, we felt it was time to complete it. Due to my ELS research I had large parts of the siren functions reversed already, so it wasn’t really a cold start. We also knew about the function retrieving the siren settings. At first I wanted to find out whether these settings could be altered in memory during runtime and would immediately reflect in-game.

First tests in memory

At first, I navigated to the siren settings instance in memory and played around with the values a little bit. It was immediately clear that no further work was needed to make those changes take effect in-game, as the pattern adjusted directly. So changing the pattern while in-game was no problem and exposing a function to do that seemed pretty easy. Now it was time to test how deeply wired the memory instance of the siren setting was, i.e. if it just contained the raw data and could be moved or whether there were various references we had to account for. Luckily, it just contains the data, so allocating memory, copying the instance and adjusting the pointer worked fine for any vehicles. At this point I was sure that adding custom patterns at runtime shouldn’t be too hard. But we still needed to solve the problem that it was limited to models instead of single vehicle instances.

Adding per vehicle support

To make it work on a per vehicle basis, we had to check where the siren settings were being used. Using a list to keep track of vehicles with a custom pattern seemed like a good idea. Thus, we intercepted the usage of the siren settings and checked whether the vehicle currently being processed had a custom pattern assigned. If that was the case, we would supply our own pattern, otherwise we would let the original call do its work and use the vanilla settings. This proved to be a really solid setup. You can see the result here:

We could now not only change a pattern at runtime, but also create new patterns and modify those. On top of that we are now also able to assign a specific pattern to a single vehicle instead of it being assigned to all vehicles of a certain model. This will be available for everyone to play around with soon in RAGE Plugin Hook!

GTA V native invocation

I’ve spent some time recently to have a look at the script VM in V as a preparation for its upcoming release. Since IV is pretty old chances are the scripting engine got some updates, as it was the case for Max Payne 3. One example of a change in MP3 is the native context, which is used to send parameters of a native function from a script to the engine and to pass back return values. Every native function basically has a wrapper function whose only argument is the native context.

Native context in GTA IV

In IV it looked like this (excerpt from C++ ScriptHook by aru)

    class scrNativeCallContext
    {
    public:
        ptr m_pReturn;
        u32 m_nArgCount;
        ptr m_pArgs;
    };

So we have two pointers here that point at memory containing the (possible) return values and the arguments. We also have an argument specifying the argument’s count. This is really simple to understand and to implement in your own code. Note that to return values, R* makes heavy use of arguments passed by reference instead of using the return section of the native context.

Native context in Max Payne 3

Things became a little different in Max Payne 3. One of the changes involved the passing by reference. R* now almost always used the return section instead of pointers. So void GetMaxAmmo(Ped ped, int weapon, u32 *pMaxAmmo) became int GetMaxAmmo(Ped ped, int weapon). While this is definitely a nice change, it doesn’t really affect the implementation and thus can be neglected when creating a script hook. One other change however, may definitely not. The native context‘s structure has changed:

    class scrNativeCallContext
    {
    public:
        GtaThread* m_pCurrentThread;
        ptr m_pReturn;
        u32 m_nArgCount;
        ptr m_pArgs;
    };

 

Right, it now also has a pointer to a GtaThread. This alone however wouldn’t be something to worry about, if this didn’t introduce some other major change: Pointers in arguments are now passed via the thread’s stack. Say one wants to pass a char* to a native function, it will no longer just push the string. However it will generate an offset, which is a 32-bit value whose first 3 bit indicate the type of the offset/pointer and the other 29-bit specify the offset from the beginning of the stack in bytes. Yes, in bytes, so the stack is definitely not a 4 bytes type array or anything, but looks more like a plain byte array. Maybe even used to pass smaller types/data or prevent alignment to save space. For a string at offset zero (because it’s the first pointer pushed this way this call), the value would look like this: 0xA0000000  The first three bits have the value of five, which is the type for strings. The remaining 29 bits have the value of zero, since it should point at the beginning of the stack.

In the wrapper of a native function, this value is then retrieved like this (before calling the real native):

INT32* stack = thread->Stack;

switch (type)
{
    case STACK_TYPE_STRING:
        // Return the actual value
        return stack[byteOffset / 4];
        break;
}

This will return the char* pointer stored at stack[offset]. So this is a rather major change one has to take into account when trying to invoke native functions in Max Payne 3.

Native context in V

During my research (note that I’m far away from being a PowerPC expert, so please bear with me in case I got something wrong) on V, I found out that this seems not to be used by V. While the wrapper of a native in Max Payne would call a function similar to the code shown above, this is not the case in V. Take a look at the wrapper of GET_MAX_AMMO in V:


.text:82DFC948 n_GET_MAX_AMMO:                         # DATA XREF: sub_82E0A3E0+2F0o
.text:82DFC948
.text:82DFC948 .set var_10, -0x10
.text:82DFC948 .set var_8, -8
.text:82DFC948
.text:82DFC948                 mflr      r12           # set up stack
.text:82DFC94C                 stw       r12, var_8(r1)
.text:82DFC950                 std       r31, var_10(r1)
.text:82DFC954                 stwu      r1, -0x60(r1) # end stack setup
.text:82DFC958                 lwz       r11, NativeContext.m_pArguments(r3) # load native arguments pointer (load [arg_0+8] into r11. this is the native arguments pointer, used to be +0xC in MP3)
.text:82DFC95C                 mr        r31, r3       # move native context into r31
.text:82DFC960                 lwz       r3, NativeArguments(r11) # move first native argument into r3
.text:82DFC964                 lwz       r4, NativeArguments.argument_2(r11) # move second native argument into r4
.text:82DFC968                 lwz       r5, NativeArguments.argument_3(r11) # move third native argument into r5
.text:82DFC96C                 bl        GET_MAX_AMMO
.text:82DFC970                 lwz       r10, 0(r31)   # move native context back into r10
.text:82DFC974                 clrlwi    r9, r3, 24    #  Store result in r9
.text:82DFC978                 stw       r9, NativeContext(r10) # move return value to pReturnValue in native context
.text:82DFC97C                 addi      r1, r1, 0x60  # destroy stack frame
.text:82DFC980                 lwz       r12, var_8(r1)
.text:82DFC984                 mtlr      r12
.text:82DFC988                 ld        r31, var_10(r1)
.text:82DFC98C                 blr                     # return

There is no call prior to calling the native and the arguments are just retrieved from the native context and pushed to the real native. So for some reason, R* didn’t implement this into GTA V, this might be due to different teams working on Max Payne 3 and GTA V, but it might also have proven not to be of any use, I don’t really know.

Script VM native invocation

The script VM now features a whole of 127 instructions, up from 77 in Max Payne 3. Invoking natives however (opcode 45) hasn’t really changed and seems to work the same way it did before. So if this is to remain the same for V’s PC release, there probably isn’t much work needed to adjust our current tool’s (ScriptHook) to work with V.