Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.
Zero Tolerance for Disrespect

Indiana Jones and the Great Circle - .resources

Featured Replies

  • Replies 83
  • Views 17.5k
  • Created
  • Last Reply

Top Posters In This Topic

Most Popular Posts

  • NoobInCoding
    NoobInCoding

    My job is not to do YOUR work. My comment is for other people so they don't have the hope for something that not exist

  • Thank @Franco for help me test importing text into gameresources_patch1_pc2.resources. It will be completed at least by next week or later.

  • @Franco @PlounchBoyTry it, pack text to resources. if you need more information, read README. IndyRes TextInjector.zip

Posted Images

  • Localization
On 2/1/2025 at 5:58 AM, Datura2 said:

Okay, but you need to know its position, which is obtained from QuickBMS

Do we need to import the strings texts only to the gameresources_pc.resources file or do we need to import them to the gameresources_patch1_pc.resources file? Because importing only to the gameresources_pc.resources file did not work. When I import to the patch1 folder, the texts do not appear. It would be nice if there was a more descriptive README, thanks Datura.

Edited by PlounchBoy

  • Localization
3 hours ago, PlounchBoy said:

Do we need to import the strings texts only to the gameresources_pc.resources file or do we need to import them to the gameresources_patch1_pc.resources file? Because importing only to the gameresources_pc.resources file did not work. When I import to the patch1 folder, the texts do not appear. It would be nice if there was a more descriptive README, thanks Datura.

You need to import them into the original gameresources_patch1_pc.resources file.

It only works with version V1.3.1.0 of the game

Note: Each time you import, only use the original .resources file and do not reuse a previously imported .resources file.

  • Localization
4 hours ago, Datura2 said:

You need to import them into the original gameresources_patch1_pc.resources file.

It only works with version V1.3.1.0 of the game

Note: Each time you import, only use the original .resources file and do not reuse a previously imported .resources file.

I regret not backing it up. I had to delete the game. I'll download it again, unfortunately. You wrote this part before and you rewrote it, So we will only import to gameresources_patch1_pc.resources file? So should we extract the strings from the gameresources_patch1_pc.resources file?

Edited by PlounchBoy

On 2/1/2025 at 3:54 AM, Datura2 said:

@Franco @PlounchBoyTry it, pack text to resources. if you need more information, read README.

IndyRes TextInjector.zip 8.33 MB · 28 downloads

Many thanks Datura2
It works perfectly. I like the way you solved the hash at addresses 8-15 and 128-135... 😉 which you mentioned in another place regarding the Indiana Jones game. And it more or less went unnoticed there...

Thanks again and admiration. 😉

11 hours ago, MadMan_Sk said:

Many thanks Datura2
It works perfectly. I like the way you solved the hash at addresses 8-15 and 128-135... 😉 which you mentioned in another place regarding the Indiana Jones game. And it more or less went unnoticed there...

Thanks again and admiration. 😉

does this work for the steam game version?

Edited by Devandrason200

3 hours ago, Devandrason200 said:

does this work for the steam game version?

Yes. No problem.

  • 4 weeks later...

I'm sorry for bothering you, guys. @Datura2, thanks a lot for you tools.
I have a question: does anybody know how to extract and import font files? After extracting via Henry resulted OTFs and TTFs are not valid (seems like they're wrapped in some in-game format). I need to add specific characters of my language. WIthout it the modified text shows only squares (which is expected). Thanks.

  • 1 month later...
On 2/1/2025 at 2:58 AM, Datura2 said:

Okay, but you need to know its position, which is obtained from QuickBMS

Hey, so I tried running this on my Steam Deck, but it doesn’t seem to do anything after I select the file I want to reimport… Is there any other way to get it working?

  • 2 weeks later...
  • Supporter

Changed the game file structure the tool no longer works. 🙂 Just thought I'd let you know.. It was a nice update.

  • 3 weeks later...
On 2/2/2025 at 5:32 PM, Datura2 said:

You need to import them into the original gameresources_patch1_pc.resources file.

It only works with version V1.3.1.0 of the game

Note: Each time you import, only use the original .resources file and do not reuse a previously imported .resources file.

where download this version of game?

  • 5 months later...
  • 2 months later...
On 10/4/2025 at 6:02 PM, RAVA MULYA said:

Is there a new tool that works for the latest Indiana Jones update after September 2025?
This tool no longer works.

IndyRes TextInjector.zip 8.33 MB · 10 downloads

I don’t think so no 😞 I wish I could do some more mods for this game but I sadly can’t atm as I’d love to do new outfits 😞

Edited by Blayer98

  • Localization
On 12/5/2025 at 2:31 AM, Blayer98 said:

I don’t think so no 😞 I wish I could do some more mods for this game but I sadly can’t atm as I’d love to do new outfits 😞

Thanks, bro, for your support.

Good luck with what you're working on now.

  • Localization
On 12/6/2025 at 10:58 PM, Ameer said:

any news? or download link of that version

That version doesn't work anymore, bro.

I'm waiting for the latest version of the tools that supports the latest game version.

  • 2 months later...

Hi. Anybode knows how generate hashes at addresses 8-15 and 128-135? Thanks

  • Localization

Its all FarmHash64. Need first create file hash, update in ResourcesEntry, generate metaHash form  ResourcesEntries table and finally generate header hash with metaHash value.
File structure
https://github.com/jandk/valen/blob/main/valen-game-greatcircle/templates/Resources.bt
So c# code example

using System;
using System.IO;
using System.Runtime.InteropServices;
using Farmhash.Sharp;

public class CircleResourcePatcher
{
    // IDCL Magic: "IDCL" in Little Endian
    private const uint IDCL_MAGIC = 0x4C444349;

    private const int HEADER_TOTAL_SIZE = 136;
    private const int RESOURCE_ENTRY_SIZE = 144;

    // Header Offsets
    private const int OFFSET_HEADER_HASH = 8;
    private const int OFFSET_NUM_RESOURCES = 80;
    private const int OFFSET_META_ENTRIES_PTR = 104;
    private const int OFFSET_META_SIZE = 120;
    private const int OFFSET_META_HASH = 128;

    public void PatchResource(string resourcePath, string newDataPath, int targetEntryIndex)
    {
        // Calculate the FarmHash64 for the new data file first
        byte[] newData = File.ReadAllBytes(newDataPath);
        ulong newDataHash = Farmhash.Sharp.Farmhash.Hash64(newData, newData.Length);

        using (var fs = new FileStream(resourcePath, FileMode.Open, FileAccess.ReadWrite))
        using (var reader = new BinaryReader(fs))
        using (var writer = new BinaryWriter(fs))
        {
            // Verify if the file is a valid IDCL container
            fs.Seek(0, SeekOrigin.Begin);
            if (reader.ReadUInt32() != IDCL_MAGIC)
                throw new Exception("Invalid file format: Magic 'IDCL' not found.");

            // Read necessary table pointers from the header
            fs.Seek(OFFSET_NUM_RESOURCES, SeekOrigin.Begin);
            uint numResources = reader.ReadUInt32();

            fs.Seek(OFFSET_META_ENTRIES_PTR, SeekOrigin.Begin);
            ulong metaEntriesOffset = reader.ReadUInt64();
            ulong resourceEntriesOffset = reader.ReadUInt64();

            fs.Seek(OFFSET_META_SIZE, SeekOrigin.Begin);
            ulong metaSize = reader.ReadUInt64();

            // Align the end of the file to a 16-byte boundary
            long alignmentPadding = (16 - (fs.Length % 16)) % 16;
            fs.Seek(0, SeekOrigin.End);
            for (int i = 0; i < (int)alignmentPadding; i++)
            {
                writer.Write((byte)0);
            }

            // Append the new data to the end of the container
            long newDataOffset = fs.Position;
            writer.Write(newData);

            // Update the specific ResourceEntry in the metadata table
            // Each entry is 144 bytes long
            long entryPos = (long)resourceEntriesOffset + (targetEntryIndex * RESOURCE_ENTRY_SIZE);

            // dataOffset (Where the file is located)
            fs.Seek(entryPos + 56, SeekOrigin.Begin);
            writer.Write((ulong)newDataOffset);

            // dataSize
            writer.Write((ulong)newData.Length);

            // uncompressedSize
            writer.Write((ulong)newData.Length);

            //dataCheckSum
            writer.Write(newDataHash);

            Console.WriteLine($"Data injected at 0x{newDataOffset:X}. Entry DataHash updated.");

            // Meta Hash Update
            // The MetaHash covers all tables (Entries, Dependencies, Strings, etc.)
            // We must recalculate it because we modified a ResourceEntry within this block.
            fs.Seek((long)metaEntriesOffset, SeekOrigin.Begin);
            byte[] metaDataBlock = reader.ReadBytes((int)metaSize);
            ulong newMetaHash = Farmhash.Sharp.Farmhash.Hash64(metaDataBlock, metaDataBlock.Length);

            // Write the new MetaHash into the header at offset 128
            fs.Seek(OFFSET_META_HASH, SeekOrigin.Begin);
            writer.Write(newMetaHash);

            Console.WriteLine($"MetaHash recalculated and updated: 0x{newMetaHash:X}");

            // Header Hash Update
            // The HeaderHash covers the header body (from offset 20 to the end of the header at 136).
            // We must recalculate it because we just updated the MetaHash value inside the header.
            fs.Seek(20, SeekOrigin.Begin);
            byte[] headerBody = reader.ReadBytes(HEADER_TOTAL_SIZE - 20);
            ulong newHeaderHash = Farmhash.Sharp.Farmhash.Hash64(headerBody, headerBody.Length);

            // Write the final HeaderHash at offset 8
            fs.Seek(OFFSET_HEADER_HASH, SeekOrigin.Begin);
            writer.Write(newHeaderHash);

            Console.WriteLine($"HeaderHash recalculated and updated: 0x{newHeaderHash:X}");
            Console.WriteLine("Patching successful!");
        }
    }
}

it's my not unfinished and not untested patcher. Only based on reverse engineering game exe

6 hours ago, MrIkso said:

Its all FarmHash64. Need first create file hash, update in ResourcesEntry, generate metaHash form  ResourcesEntries table and finally generate header hash with metaHash value.
File structure
https://github.com/jandk/valen/blob/main/valen-game-greatcircle/templates/Resources.bt
So c# code example

using System;
using System.IO;
using System.Runtime.InteropServices;
using Farmhash.Sharp;

public class CircleResourcePatcher
{
    // IDCL Magic: "IDCL" in Little Endian
    private const uint IDCL_MAGIC = 0x4C444349;

    private const int HEADER_TOTAL_SIZE = 136;
    private const int RESOURCE_ENTRY_SIZE = 144;

    // Header Offsets
    private const int OFFSET_HEADER_HASH = 8;
    private const int OFFSET_NUM_RESOURCES = 80;
    private const int OFFSET_META_ENTRIES_PTR = 104;
    private const int OFFSET_META_SIZE = 120;
    private const int OFFSET_META_HASH = 128;

    public void PatchResource(string resourcePath, string newDataPath, int targetEntryIndex)
    {
        // Calculate the FarmHash64 for the new data file first
        byte[] newData = File.ReadAllBytes(newDataPath);
        ulong newDataHash = Farmhash.Sharp.Farmhash.Hash64(newData, newData.Length);

        using (var fs = new FileStream(resourcePath, FileMode.Open, FileAccess.ReadWrite))
        using (var reader = new BinaryReader(fs))
        using (var writer = new BinaryWriter(fs))
        {
            // Verify if the file is a valid IDCL container
            fs.Seek(0, SeekOrigin.Begin);
            if (reader.ReadUInt32() != IDCL_MAGIC)
                throw new Exception("Invalid file format: Magic 'IDCL' not found.");

            // Read necessary table pointers from the header
            fs.Seek(OFFSET_NUM_RESOURCES, SeekOrigin.Begin);
            uint numResources = reader.ReadUInt32();

            fs.Seek(OFFSET_META_ENTRIES_PTR, SeekOrigin.Begin);
            ulong metaEntriesOffset = reader.ReadUInt64();
            ulong resourceEntriesOffset = reader.ReadUInt64();

            fs.Seek(OFFSET_META_SIZE, SeekOrigin.Begin);
            ulong metaSize = reader.ReadUInt64();

            // Align the end of the file to a 16-byte boundary
            long alignmentPadding = (16 - (fs.Length % 16)) % 16;
            fs.Seek(0, SeekOrigin.End);
            for (int i = 0; i < (int)alignmentPadding; i++)
            {
                writer.Write((byte)0);
            }

            // Append the new data to the end of the container
            long newDataOffset = fs.Position;
            writer.Write(newData);

            // Update the specific ResourceEntry in the metadata table
            // Each entry is 144 bytes long
            long entryPos = (long)resourceEntriesOffset + (targetEntryIndex * RESOURCE_ENTRY_SIZE);

            // dataOffset (Where the file is located)
            fs.Seek(entryPos + 56, SeekOrigin.Begin);
            writer.Write((ulong)newDataOffset);

            // dataSize
            writer.Write((ulong)newData.Length);

            // uncompressedSize
            writer.Write((ulong)newData.Length);

            //dataCheckSum
            writer.Write(newDataHash);

            Console.WriteLine($"Data injected at 0x{newDataOffset:X}. Entry DataHash updated.");

            // Meta Hash Update
            // The MetaHash covers all tables (Entries, Dependencies, Strings, etc.)
            // We must recalculate it because we modified a ResourceEntry within this block.
            fs.Seek((long)metaEntriesOffset, SeekOrigin.Begin);
            byte[] metaDataBlock = reader.ReadBytes((int)metaSize);
            ulong newMetaHash = Farmhash.Sharp.Farmhash.Hash64(metaDataBlock, metaDataBlock.Length);

            // Write the new MetaHash into the header at offset 128
            fs.Seek(OFFSET_META_HASH, SeekOrigin.Begin);
            writer.Write(newMetaHash);

            Console.WriteLine($"MetaHash recalculated and updated: 0x{newMetaHash:X}");

            // Header Hash Update
            // The HeaderHash covers the header body (from offset 20 to the end of the header at 136).
            // We must recalculate it because we just updated the MetaHash value inside the header.
            fs.Seek(20, SeekOrigin.Begin);
            byte[] headerBody = reader.ReadBytes(HEADER_TOTAL_SIZE - 20);
            ulong newHeaderHash = Farmhash.Sharp.Farmhash.Hash64(headerBody, headerBody.Length);

            // Write the final HeaderHash at offset 8
            fs.Seek(OFFSET_HEADER_HASH, SeekOrigin.Begin);
            writer.Write(newHeaderHash);

            Console.WriteLine($"HeaderHash recalculated and updated: 0x{newHeaderHash:X}");
            Console.WriteLine("Patching successful!");
        }
    }
}

it's my not unfinished and not untested patcher. Only based on reverse engineering game exe

Very grateful, MrIkso. Thanks

10 hours ago, MrIkso said:

Its all FarmHash64. Need first create file hash, update in ResourcesEntry, generate metaHash form  ResourcesEntries table and finally generate header hash with metaHash value.
File structure
https://github.com/jandk/valen/blob/main/valen-game-greatcircle/templates/Resources.bt
So c# code example

using System;
using System.IO;
using System.Runtime.InteropServices;
using Farmhash.Sharp;

public class CircleResourcePatcher
{
    // IDCL Magic: "IDCL" in Little Endian
    private const uint IDCL_MAGIC = 0x4C444349;

    private const int HEADER_TOTAL_SIZE = 136;
    private const int RESOURCE_ENTRY_SIZE = 144;

    // Header Offsets
    private const int OFFSET_HEADER_HASH = 8;
    private const int OFFSET_NUM_RESOURCES = 80;
    private const int OFFSET_META_ENTRIES_PTR = 104;
    private const int OFFSET_META_SIZE = 120;
    private const int OFFSET_META_HASH = 128;

    public void PatchResource(string resourcePath, string newDataPath, int targetEntryIndex)
    {
        // Calculate the FarmHash64 for the new data file first
        byte[] newData = File.ReadAllBytes(newDataPath);
        ulong newDataHash = Farmhash.Sharp.Farmhash.Hash64(newData, newData.Length);

        using (var fs = new FileStream(resourcePath, FileMode.Open, FileAccess.ReadWrite))
        using (var reader = new BinaryReader(fs))
        using (var writer = new BinaryWriter(fs))
        {
            // Verify if the file is a valid IDCL container
            fs.Seek(0, SeekOrigin.Begin);
            if (reader.ReadUInt32() != IDCL_MAGIC)
                throw new Exception("Invalid file format: Magic 'IDCL' not found.");

            // Read necessary table pointers from the header
            fs.Seek(OFFSET_NUM_RESOURCES, SeekOrigin.Begin);
            uint numResources = reader.ReadUInt32();

            fs.Seek(OFFSET_META_ENTRIES_PTR, SeekOrigin.Begin);
            ulong metaEntriesOffset = reader.ReadUInt64();
            ulong resourceEntriesOffset = reader.ReadUInt64();

            fs.Seek(OFFSET_META_SIZE, SeekOrigin.Begin);
            ulong metaSize = reader.ReadUInt64();

            // Align the end of the file to a 16-byte boundary
            long alignmentPadding = (16 - (fs.Length % 16)) % 16;
            fs.Seek(0, SeekOrigin.End);
            for (int i = 0; i < (int)alignmentPadding; i++)
            {
                writer.Write((byte)0);
            }

            // Append the new data to the end of the container
            long newDataOffset = fs.Position;
            writer.Write(newData);

            // Update the specific ResourceEntry in the metadata table
            // Each entry is 144 bytes long
            long entryPos = (long)resourceEntriesOffset + (targetEntryIndex * RESOURCE_ENTRY_SIZE);

            // dataOffset (Where the file is located)
            fs.Seek(entryPos + 56, SeekOrigin.Begin);
            writer.Write((ulong)newDataOffset);

            // dataSize
            writer.Write((ulong)newData.Length);

            // uncompressedSize
            writer.Write((ulong)newData.Length);

            //dataCheckSum
            writer.Write(newDataHash);

            Console.WriteLine($"Data injected at 0x{newDataOffset:X}. Entry DataHash updated.");

            // Meta Hash Update
            // The MetaHash covers all tables (Entries, Dependencies, Strings, etc.)
            // We must recalculate it because we modified a ResourceEntry within this block.
            fs.Seek((long)metaEntriesOffset, SeekOrigin.Begin);
            byte[] metaDataBlock = reader.ReadBytes((int)metaSize);
            ulong newMetaHash = Farmhash.Sharp.Farmhash.Hash64(metaDataBlock, metaDataBlock.Length);

            // Write the new MetaHash into the header at offset 128
            fs.Seek(OFFSET_META_HASH, SeekOrigin.Begin);
            writer.Write(newMetaHash);

            Console.WriteLine($"MetaHash recalculated and updated: 0x{newMetaHash:X}");

            // Header Hash Update
            // The HeaderHash covers the header body (from offset 20 to the end of the header at 136).
            // We must recalculate it because we just updated the MetaHash value inside the header.
            fs.Seek(20, SeekOrigin.Begin);
            byte[] headerBody = reader.ReadBytes(HEADER_TOTAL_SIZE - 20);
            ulong newHeaderHash = Farmhash.Sharp.Farmhash.Hash64(headerBody, headerBody.Length);

            // Write the final HeaderHash at offset 8
            fs.Seek(OFFSET_HEADER_HASH, SeekOrigin.Begin);
            writer.Write(newHeaderHash);

            Console.WriteLine($"HeaderHash recalculated and updated: 0x{newHeaderHash:X}");
            Console.WriteLine("Patching successful!");
        }
    }
}

it's my not unfinished and not untested patcher. Only based on reverse engineering game exe

Hi. Code not works... I tried to patch gameresources_patch1_pc.resources for steam game with new data enus/strings (orig size compressed/uncompresed). So, I changed code, but I got error - gameresources_patch1_pc.resources has corrupt metaData: (metadata hash mismatch). Perhaps you have some ideas about what could be improved in the new code? 

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using Farmhash.Sharp;

public class CircleResourcePatcher
{
    // IDCL Magic: "IDCL" in Little Endian
    private const uint IDCL_MAGIC = 0x4C434449;

    private const int HEADER_TOTAL_SIZE = 136;
    private const int RESOURCE_ENTRY_SIZE = 144;

    // Header Offsets
    private const int OFFSET_HEADER_HASH = 8;
    private const int OFFSET_NUM_RESOURCES = 80;
    private const int OFFSET_META_ENTRIES_PTR = 84; //104;
    private const int OFFSET_META_SIZE = 120;
    private const int OFFSET_META_HASH = 128;

    public static void Main()
    {
        string resourcePathOld  = "G:\\gameresources_patch1_pc.resources_orig";
        string resourcePathNew = "G:\\gameresources_patch1_pc.resources";
        File.Copy(resourcePathOld, resourcePathNew, overwrite: true);
        string newDataPath = "G:\\strings";
        PatchResource(resourcePathNew, newDataPath, 1749);

    }
    public static void PatchResource(string resourcePath, string newDataPath, int targetEntryIndex)
    {
        // Calculate the FarmHash64 for the new data file first
        byte[] newData = File.ReadAllBytes(newDataPath);
        ulong newDataHash = Farmhash.Sharp.Farmhash.Hash64(newData, newData.Length);

        using (var fs = new FileStream(resourcePath, FileMode.Open, FileAccess.ReadWrite))
        using (var reader = new BinaryReader(fs))
        using (var writer = new BinaryWriter(fs))
        {
            // Verify if the file is a valid IDCL container
            fs.Seek(0, SeekOrigin.Begin);
            if (reader.ReadUInt32() != IDCL_MAGIC)
                throw new Exception("Invalid file format: Magic 'IDCL' not found.");

            // Read necessary table pointers from the header
            fs.Seek(OFFSET_NUM_RESOURCES, SeekOrigin.Begin);
            uint numResources = reader.ReadUInt32();

            fs.Seek(OFFSET_META_ENTRIES_PTR, SeekOrigin.Begin);
            ulong metaEntriesOffset = reader.ReadUInt64();
            //ulong resourceEntriesOffset = reader.ReadUInt64();

            fs.Seek(OFFSET_META_SIZE, SeekOrigin.Begin);
            ulong metaSize = reader.ReadUInt64();

            // Align the end of the file to a 16-byte boundary
            long alignmentPadding = (16 - (fs.Length % 16)) % 16;
            fs.Seek(0, SeekOrigin.End);
            for (int i = 0; i < (int)alignmentPadding; i++)
            {
                writer.Write((byte)0);
            }

            // Append the new data to the end of the container
            long newDataOffset = fs.Position;
            writer.Write(newData);

            // Update the specific ResourceEntry in the metadata table
            // Each entry is 144 bytes long
            //long entryPos = (long)resourceEntriesOffset + (targetEntryIndex * RESOURCE_ENTRY_SIZE);
            long entryPos = (long)metaEntriesOffset + (targetEntryIndex * RESOURCE_ENTRY_SIZE);

            // dataOffset (Where the file is located)
            fs.Seek(entryPos + 56, SeekOrigin.Begin);
            writer.Write((ulong)newDataOffset);

            // dataSize
            //writer.Write((ulong)newData.Length);

            // uncompressedSize
            //writer.Write((ulong)newData.Length);

            //dataCheckSum
            //writer.Write(newDataHash);
            fs.Seek(entryPos + 80, SeekOrigin.Begin);
            writer.Write(newDataHash);
            fs.Seek(entryPos + 96, SeekOrigin.Begin);
            writer.Write(newDataHash);

            Console.WriteLine($"Data injected at 0x{newDataOffset:X}. Entry DataHash updated.");

            // Meta Hash Update
            // The MetaHash covers all tables (Entries, Dependencies, Strings, etc.)
            // We must recalculate it because we modified a ResourceEntry within this block.
            fs.Seek((long)metaEntriesOffset, SeekOrigin.Begin);
            //byte[] metaDataBlock = reader.ReadBytes((int)metaSize);
            byte[] metaDataBlock = reader.ReadBytes(((int)metaSize-(int)metaEntriesOffset)); //MetaSize is offset 605672 before IDCL. is Metadata  from 136 to 605672??
            ulong newMetaHash = Farmhash.Sharp.Farmhash.Hash64(metaDataBlock, metaDataBlock.Length);

            // Write the new MetaHash into the header at offset 128
            fs.Seek(OFFSET_META_HASH, SeekOrigin.Begin);
            writer.Write(newMetaHash);

            Console.WriteLine($"MetaHash recalculated and updated: 0x{newMetaHash:X}");

            // Header Hash Update
            // The HeaderHash covers the header body (from offset 20 to the end of the header at 136).
            // We must recalculate it because we just updated the MetaHash value inside the header.
            fs.Seek(20, SeekOrigin.Begin);
            byte[] headerBody = reader.ReadBytes(HEADER_TOTAL_SIZE - 20);
            ulong newHeaderHash = Farmhash.Sharp.Farmhash.Hash64(headerBody, headerBody.Length);

            // Write the final HeaderHash at offset 8
            fs.Seek(OFFSET_HEADER_HASH, SeekOrigin.Begin);
            writer.Write(newHeaderHash);

            Console.WriteLine($"HeaderHash recalculated and updated: 0x{newHeaderHash:X}");
            Console.WriteLine("Patching successful!");
        }
    }
}

 

Header gameresources_patch1_pc.resources (steam version, not patched)

uint magic;         00-03    49 44 43 4C 
uint version;         04-07    0D 00 00 00 -13
uquad headerHash;    08-15    09 71 D2 3D 56 BA BB AB
uint  headerSize;    16-19    74 00 00 00 -116
uint  flags;        20-23    00 00 00 00 -0
uint  numSegments;    24-27    01 00 00 00 -1
uquad segmentSize;    28-35    FF FF FF FF FF 00 00 00
uint  numResources;    36-39    A6 0A 00 00 -2726
uint  numDependencies;     40-43    52 00 00 00 -82
uint  numDepIndices;    44-47    52 00 00 00 -82
uint  numStringIndices;    48-51    46 15 00 00 -5446
uint  numSpecialHashes; 52-55    0E 00 00 00 -14
uint  numMetaEntries;    56-59    00 00 00 00 -0
uint  stringTableSize;    60-63    68 89 02 00 -166248 (from 392680, +166248=558928)
uint  metaEntriesSize;    64-67    00 00 00 00 -0
uquad stringTableOffset;        68-75    E8 FD 05 00 00 00 00 00 -392680
uquad metaEntriesOffset;        76-83    50 87 08 00 00 00 00 00 -558928
uquad resourceEntriesOffset;        84-91    88 00 00 00 00 00 00 00 -136
uquad resourceDepsOffset;        92-99    50 87 08 00 00 00 00 00 -558928
uquad resourceSpecialHashOffset;    100-107    90 91 08 00 00 00 00 00    -561552
uquad dataOffset;            108-115    00 40 09 00 00 00 00 00 -606208
uint  unknown;    116-119    00 00 00 00 -0
uquad metaSize;    120-127    E8 3D 09 00 00 00 00 00 -605672
uquad metaHash; 128-135    5F C2 E7 BC 6F 56 FC 8D

 

RESOURCE id 1749 - offset 251992

quad   resourceTypeString;        00 00 00 00 00 00 00 00
quad   nameString;            01 00 00 00 00 00 00 00
quad   descString;            FF FF FF FF FF FF FF FF
uquad  depIndices;            33 00 00 00 00 00 00 00 -51
uquad  strings;                A8 0D 00 00 00 00 00 00 -3496
uquad  specialHashes;            00 00 00 00 00 00 00 00
uquad  metaEntries;            00 00 00 00 00 00 00 00
uquad  dataOffset;        +56    80 96 33 00 00 00 00 00 -3380864
uquad  dataSize;        +64    45 7F 13 00 00 00 00 00 -1277765
uquad  uncompressedSize;    +72    13 3C 4C 00 00 00 00 00 -4996115
uquad  dataCheckSum;        +80    39 7C B7 F1 E2 74 F9 E0
uquad  generationTimeStamp;    +88    C0 74 25 80 E7 42 06 00
uquad  defaultHash;        +96    39 7C B7 F1 E2 74 F9 E0
uint   version;                05 00 00 00 -5

 

UPD

c# code works for header hash, but not works for metadata

Edited by dmg2u

  • 3 weeks later...

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.