Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
    1. Welcome to GTAForums!

    1. Red Dead Redemption 2

      1. PC
      2. Gameplay
      3. Missions
      4. Help & Support
    2. Red Dead Online

      1. Gameplay
      2. Find Lobbies & Outlaws
      3. Help & Support
      4. Frontier Pursuits
    1. Crews & Posses

      1. Recruitment
    2. Events

    1. GTA Online

      1. Diamond Casino & Resort
      2. DLC
      3. Find Lobbies & Players
      4. Guides & Strategies
      5. Vehicles
      6. Content Creator
      7. Help & Support
    2. Grand Theft Auto Series

    3. GTA 6

    4. GTA V

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

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

    7. GTA Vice City Stories

    8. GTA Liberty City Stories

    9. GTA San Andreas

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

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

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

      1. GTA Advance
      2. GTA 2
      3. GTA
    13. 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. 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. News

    2. Forum Support

    3. Site Suggestions

Sign in to follow this  

[Feature Request] RPF-less mod installation

Recommended Posts


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();
    registerArchive(proxyCommon, "common:/");
    registerArchive(proxyCommonrc, "commoncrc:/");
    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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

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.

Sign in to follow this  

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

  • Create New...

Important Information

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