Quantcast
Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
    1. Welcome to GTAForums!   (92,063 visits to this link)

    2. News

    1. GTA Online

      1. Find Lobbies & Players
      2. Guides & Strategies
      3. Vehicles
      4. Content Creator
      5. Help & Support
    2. Crews

      1. Events
      2. Recruitment
    1. Grand Theft Auto Series

    2. GTA Next

    3. GTA V

      1. PC
      2. Guides & Strategies
      3. Help & Support
    4. GTA IV

      1. Episodes from Liberty City
      2. Multiplayer
      3. Guides & Strategies
      4. Help & Support
      5. GTA Mods
    5. GTA Chinatown Wars

    6. GTA Vice City Stories

    7. GTA Liberty City Stories

    8. GTA San Andreas

      1. Guides & Strategies
      2. Help & Support
      3. GTA Mods
    9. GTA Vice City

      1. Guides & Strategies
      2. Help & Support
      3. GTA Mods
    10. GTA III

      1. Guides & Strategies
      2. Help & Support
      3. GTA Mods
    11. Top Down Games

      1. GTA Advance
      2. GTA 2
      3. GTA
    12. Wiki

      1. Merchandising
    1. GTA Modding

      1. GTA V
      2. GTA IV
      3. GTA III, VC & SA
      4. Tutorials
    2. Mod Showroom

      1. Scripts & Plugins
      2. Maps
      3. Total Conversions
      4. Vehicles
      5. Textures
      6. Characters
      7. Tools
      8. Other
      9. Workshop
    3. Featured Mods

      1. DYOM
      2. OpenIV
      3. GTA: Underground
      4. GTA: Liberty City
      5. GTA: State of Liberty
    1. Red Dead Redemption 2

    2. Red Dead Redemption

    3. Rockstar Games

    1. Off-Topic

      1. General Chat
      2. Gaming
      3. Technology
      4. Programming
      5. Movies & TV
      6. Music
      7. Sports
      8. Vehicles
    2. Expression

      1. Graphics / Visual Arts
      2. GFX Requests & Tutorials
      3. Writers' Discussion
      4. Debates & Discussion
    1. Forum Support

    2. Site Suggestions

Sign in to follow this  
delusional

[Feature Request] RPF-less mod installation

Recommended Posts

delusional

I spent christmas looking into RPF-less modding for GTA V.

I'm not quite there, but with the use of dlcpacks (So proper mod packaging) I've managed to come up with a workable solution, it would be great if the OpenIV developers would pick it up. There's no need for yet another mod that deals with mod loading.

 

The rest of the post will be directed towards the OpenIV developers, and will therefore assume some familiarity with the GTA V source code. The hex values with denote offsets from the game base (as of 1.0.944.2) unless otherwise noted.

 

The function at 0x11E0E50 looks up a Packfile to serve a path. It supports multiple archives per path, and supports mapping subpaths with global path fallbacks. By default it maps common.rpf to common:/, update.rpf to update:/, and update.rpf/common to common:/ Some others are mapped as well, but unimportant in this context.

 

To support RPF-less mod installation we need to load some files from common.rpf and update.rpf.

To load files from disk instead of the rpf file, we simply need to attach some Devices to handle those paths.

 

Luckily GTA V also uses the function 0x11E0E50 to load HDD paths, meaning it already has a Device that does this. They call it DeviceRelative, and the vTable is located at 0x18512A8, It's a struct with a length of 0x118 bytes.

 

To initialize the Device relative we need to pass the struct to 0x11E28D8, it has the method signature setBackFsAndOtherStuff(DeviceRelative_rage *this, char *path, char assetType, device_rage path_handler) where passing null to path_handler will result in the program looking up what to mount the relative device to via the aforementioned lookup function. If you want a filesystem path, which we do, it's relative to the game root. I've found that an assetType value of 1 works well.

 

To make our new device handle the common path we need to call the function at 0x11E3E94, with the prototype of char __fastcall registerArchive(Device_rage *pkgfile, char *path) which will register our Device to the path we give it. To overwrite the common.rpf file we register our device on common:/. The great thing about doing it this way is that the code will automatically fall back if some file isn't in our directory. Allowing up to only copy the files we actually want to modify.

 

If we try and run the game now we find a problem. Some of the files in common.rpf are loaded via the commoncrc:/ path prefix. If we mount a new DeviceRelative, with the same backing path as the other one, it works.

 

I've hooked some functions and made a proof of concept. There's a lot of other research in there though, so I wont be posting it. The main procedure of mounting the devices looks like the following (mainload is 0x7B7B4C):

char __fastcall mainLoad_replace(){
	char ret = mainLoad_original();
    proxyCommon = static_cast<DeviceRelative*>(malloc(0x118));
    proxyCommon->vTable = reinterpret_cast<void*>(mainModuleBase + 0x18512A8);
    setBackAndOtherStuff(proxyCommon, "modloader/common.rpf/", 1, nullptr);
    registerArchive(proxyCommon, "common:/");
    proxyCommonrc = static_cast<DeviceRelative*>(malloc(0x118));
    proxyCommonrc->vTable = reinterpret_cast<void*>(mainModuleBase + 0x18512A8);
    setBackAndOtherStuff(proxyCommonrc, "modloader/common.rpf/", 1, nullptr);
    registerArchive(proxyCommonrc, "commoncrc:/");
    proxyUpdate = static_cast<DeviceRelative*>(malloc(0x118));
    proxyUpdate->vTable = reinterpret_cast<void*>(mainModuleBase + 0x18512A8);
    setBackAndOtherStuff(proxyUpdate, "modloader/update.rpf/", 1, nullptr);
    registerArchive(proxyUpdate, "update:/");
    DBGPRINT(L"Hooked it");	return ret;
}

With the quirk that the game reloads the update rpf file to force it on top of all the other rpfs, requiring me to hook another function and reload my mounts (refreshpriority is 0x8EB790):

char __fastcall refreshPriority_replace(){
	DBGPRINT(L"Refreshed it");
    char ret = refreshPriority_original();
    unregisterArchive(proxyCommon);
    registerArchive(proxyCommon, "common:/");
    unregisterArchive(proxyCommonrc);
    registerArchive(proxyCommonrc, "commoncrc:/");
    unregisterArchive(proxyUpdate);
    registerArchive(proxyUpdate, "update:/");
    return ret;
}

The unregister archive is located at 0x11E71F0.

 

I have my PoC working, loading a single dlcpack mod, and modifying the root handling.meta, all with stock rpf files!

Edited by delusional

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • 1 User Currently Viewing
    0 members, 0 Anonymous, 1 Guest

×

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.