Jump to content

Can we edit .gfx from an .rpf at this point? (hitmarker mod)


 Share

Recommended Posts

Hey everyone,

 

I'm very new to modding, so forgive me if I'm going about this in a hamfisted way.

 

Taking inspiration from a similar GTA5 mod, I was able to locate the sprite images for the X-hitmarker using OpenIV and a Flash decompiler. In the GTA5 mod, the author simply replaced the hitmarker sprite with a transparent image.

 

However, unlike GTA5's OpenIV support, RDR2 doesn't have edit mode, so even though I'm able to extract the .gfx file and edit it, I have no means of reinserting it into the .rpf.

 

Is there any way to accomplish this? Worst case, if I copied every file contained within the .rpf and replaced the original .gfx with the edited file, would I be able to recompile all of them back into an .rpf that RDR2 would recognize as legitimate?

Link to comment
Share on other sites

RDR2 > update.rpf > x64 > patch > data > cdimages > scaleform_generic.rpf > 0xE3E0C0B9.gfx

 

I've opened the file in JPEX's Free Flash Decompiler & found the white hitmarker saved as DefineShape4(8), DefineSprite (9) and DefineSprite (29). I haven't located the red version of the hitmarker, but there's a solid red image that they might combine with the white hitmarker.

 

The .gfx file also seems to have animation data related to hitmarkers, eg. DefineSprite (12: hitmarkers).

 

I appreciate someone else taking a look at this; I'd love to hear your thought process on how something like this works if it leads to anything tangible.

Link to comment
Share on other sites

Seems to work great!

 

I'm fascinated by how this works, by the way; is there any posts or reading material you can suggest if I wanted to take a deeper look into subject / methods you might have used?

 

I'd love to tinker around & try to prevent the reticle from turning red when aiming at an enemy. At first I thought preventing that might be a more complicated process, but it might be handled the same way the color change for the hitmarker was handled.

Link to comment
Share on other sites

Preventing it from turning red is actually easier and was what I managed to do before I was able to just disable the hitmarker. There are a few internal states of the reticle (for valid targets, invalid targets, enemy targets etc.). I am not sure how easy it is to remove just the enemy bit but I could add an option to disable any reticle change altogether which is very simple. It will then no longer be grayed out for your personal horse for instance, though.

 

If you want to try it yourself, you would need to be at least somewhat proficient with reverse engineering and x64 assembly as I am changing game code to prevent the hitmarker from rendering. I am happy to give you some pointers if that's what you are looking for.

 

Link to comment
Share on other sites

If it's no trouble, I'd absolutely love a version of the mod that disabled the reticle changes altogether.


As for the x64 assembly, I appreciate your offer for pointers and I'll be sure to take you up on it once I'm more knowledgeable on the subject, but as a high-level programmer I'm absolutely mortified at the concept of assembly :P

 

I'd love to learn, and I'm sure some of the fundamentals would carry between high to low level programming, but would you consider the coding involved in this mod to be reasonable for an amateur-enthusiast, or do you really need to grok the whole architecture before you can make sense of anything?

Link to comment
Share on other sites

Sure, I'll add an ini option in the next version to allow you to toggle the "no change at all" behavior.

 

The coding itself is very simple (can be reduced to a one liner of actual mod-specific code), but the research required to figure out what to patch and where, I wouldn't recommend for a beginner. It is a highly abstracted UI system that you need to delve through for quite a bit. There are many other things you can work on first instead if you just want to play around with memory patching.

Link to comment
Share on other sites

That's awesome, appreciated!

 

At the risk of sounding spoon-fed, do you have any suggestions on what sort of stuff a beginner could work on? I love seeing how games/computers work on a practical level, and I have almost as much fun digging around in OpenIV as I do playing the actual games; I'd love to contribute to the modding scene, just not sure where to get started.

 

Just out of curiosity, are you affiliated with OpenIV?

Link to comment
Share on other sites

I have updated the mod and included an option to disable any reticle changes.

 

Ideally you would work on a smaller game with less DRM as it can be quite frustrating. Maybe pick an older shooter game and see if you can find the code that changes your ammo or health. RDR2 uses DRM which might make it less accessible for beginners. If you want to skip all that and just write some code, you can use one of the available script hooks (such as the C++ ScriptHook by Alexander Blade or RAGE Plugin Hook by MulleDK19 and myself targeting .NET) to interact with the game's scripting engine. You can create a lot of cool stuff that way! We have some tutorials here: https://www.mod-rdr.com/wiki/tutorials/

 

And no, I am not affiliated with OpenIV.

Link to comment
Share on other sites

Beautiful work; to think this time last week I was griping about how Rockstar would never add this feature, and how I would just need to get used to it.

 

You've helped a great deal at this point, so once I've used up your goodwill & patience, kindly say the word and I'll stop bugging you & try to find some youtube videos to point me in the right direction, but until that point...

 

I'm not sure if it's related to memory patching per se, but I'm getting flashbacks of using the debug feature on my N64's gameshark (fire a shot, check for changes, highlight differences, rinse & repeat); sometimes I wouldn't even know what I was trying to change, I was just exploring how certain values effected the game. I'd love to rediscover that feeling on PC.

 

I'm interested in picking away at some older games for practice, but can you suggest a basic toolkit? Is it just your flavor of IDE + whatever tool is needed for the game's archive (.pak, .dat, .etc)?

Link to comment
Share on other sites

Glad to hear you enjoy it! 

 

That sounds a lot like memory scanning for an unknown initial value, then looking for a decreased value etc. This process will (usually) allow you to find the address in memory that stores the ammo count. From there on, by setting a breakpoint on it, you can find the code that modifies it and for instance NOP it so that it no longer does anything. Cheat Engine is a great tool for that and all you really need initially. A more powerful debugger would be x64dbg (which is free). For static analysis you could use Ghidra (free) or IDA Pro (very expensive), but I'd recommend starting out with just Cheat Engine initially.

 

Once you know what to patch, you could just write a small C++ library that scans the game's memory for the location to patch and then applies the patch. I use Visual Studio for that. Game archives vary wildly and you usually have to rely on a third party tool (like OpenIV) or try to document it yourself, usually by using a Hex Editor and studying the code to parse the files. That's a different story, though. For the hitmarker no files are touched, but only game code (compiled code) is modified to skip a certain portion used to render the hitmarker (essentially removing an if-block).

  • Like 1
Link to comment
Share on other sites

I've used CE in the past with great results. I've been trying to find the story mode mission timers and have had no luck though. I saw in the NativeDB that there were different timer calls (timer A, timer B, Get_Game_Timer etc), but couldn't get it to work as a rage plugin.

 

I was trying something simple as

 

var Timer = Game.CallNative<int>("GET_GAME_TIMER")

 

and then trying to write it either in the Rage Console or using Game.DisplayHelp or something. I went through the tutorials as I'm a beginner, just haven't been able to put it together in a way that Rage can compile.  

 

Would you have any thoughts on how to find something like that?

 

Edited by OnyxDog78
Link to comment
Share on other sites

On 6/18/2020 at 6:33 PM, LMS said:

I'd recommend starting out with just Cheat Engine initially.

 

Just finished the tutorials & successfully added unlimited lives to Space Cadet Pinball 3D; thanks for the recommendations, that's definitely kickstarted a new hobby!

 

edit. and froze player health in Enter the Gungeon; I'm giddy like a kid

Edited by theharber
  • Like 1
Link to comment
Share on other sites

@HughJanus Thank you! I'm trying to test something now. Does this look like anything close?

 

I've been searching all over for ASI tutorials, and you mentioned "helper files". I get that it's C++ vs. C# which is fine, but where would one go to specifically for a plugin tutorial outside of the one LMS did?

 

      public static void Process()
        {
            var Timer = Game.CallNative<int>("GET_GAME_TIMER");
            var TimerA = Game.CallNative<int>("TIMERA");
            var TimerB = Game.CallNative<int>("TIMERB");
            
         // Testing to see what comes up if anything
            Game.CallNative<int>("DRAW_TEXT",Timer);

        }

 

I think this is off topic, lmk if I need to move or start another thread

Edited by OnyxDog78
Off topic for the thread
Link to comment
Share on other sites

@OnyxDog78 Alexander Blade's ScriptHook includes helper libraries in which he already wrote wrapper functions for the natves, so you dont have to use hashes, but can write natives in clear text (which helps a lot, I think).

Outside of your main logic you would need stuff like this:

void DrawText(float x, float y, char* str) //method you will use to draw text on the screen
{
	UI::DRAW_TEXT(GAMEPLAY::CREATE_STRING(10, "LITERAL_STRING", str), x, y); //wrapper for 0xD79334A4BB99BAD1
}

char c[50]; //char array for storing your text
int timer; //int for storing your game timer
string text; //the text to be displayed in front of your timer variable

 

And in you main method, you can use it like:

timer = GAMEPLAY::GET_GAME_TIMER() //wrapper for 0x4F67E8ECA7D3F667
text = "Gameplay Timer: " + std::to_string(timer); //adding the timer variable to your string
strcpy(c, text.c_str()); //copying the string to the char array
DrawText(0.5, 0.5, c); //displaying the char array

 

The thing with the char array is a bit uncomfortable, but since you cant pass a string to the DRAW_TEXT method, thats the way I have been using it.

The alternative would be include the "copying a string into a char array" portion into the DRAW_TEXT method, but then you would have to have a fixed char array size, which I prefer to specify outside of the method itself (in case I need more space).

 

Bear in mind that I am a noob and others might be able to give better advice 😛

Edited by HughJanus
  • Like 1
Link to comment
Share on other sites

@HughJanus Thank you! I found the files you were talking about. I got the timers to display but they weren't the mission goal timers i thought they might be. I got TIMERA and TIMERB both to display as well, and then used SET_TIMERA & SET_TIMERB to set them to 0 to see if it affected the timed mission goals, but it didn't 😕

 

Thank you for your help though. 

Link to comment
Share on other sites

On 6/19/2020 at 8:57 PM, theharber said:

 

Just finished the tutorials & successfully added unlimited lives to Space Cadet Pinball 3D; thanks for the recommendations, that's definitely kickstarted a new hobby!

 

edit. and froze player health in Enter the Gungeon; I'm giddy like a kid

 

Glad to hear it's so much fun!

 

6 hours ago, OnyxDog78 said:

@HughJanus Thank you! I found the files you were talking about. I got the timers to display but they weren't the mission goal timers i thought they might be. I got TIMERA and TIMERB both to display as well, and then used SET_TIMERA & SET_TIMERB to set them to 0 to see if it affected the timed mission goals, but it didn't 😕

 

Thank you for your help though. 

 

It probably is stored in a local variable in the script that just stores the starting time.

  • Like 1
Link to comment
Share on other sites

@LMS would a local variable be one of the arguments for one of the native functions? i realize you say scripts, but I'm not sure i understand.

 

I'm guessing what you're saying is that when a mission is started the game pulls and stores the start time from somewhere (my guess would be either the local system or network) and then compares it to the completion time to determine if you passed that part of the medal. Is that correct?

Link to comment
Share on other sites

Yes, all missions are script based. They will get the current game time, store it inside a (script) local variable and then compare to it. Now it could also be a global variable, but I assume for most missions it will be local. You will have a hard time changing those as they are not easily accessible.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...