reverse-engineeringunreal-enginepythondataminingoodle

Undocumented, and the Wiki Says "Still Being Investigated": So I Opened the Game's 38GB Archive Myself

· 40 min read
Table of Contents
  1. 1. What I was up against
  2. 2. Five steps (plain English first, code after)
  3. Step 1: Find the table of contents
  4. Step 2: Unroll the map of 185,000 files
  5. Step 3: Unpack the "squeezed" location data
  6. Step 4: Decompress (using something I already had)
  7. Step 5: Route around the real wall
  8. 3. The step that matters most: proving I didn't get it wrong
  9. 4. The outcome
  10. 5. Why Ultra Lab writes about this
  11. Scope and disclaimers

Undocumented, and the Wiki Says "Still Being Investigated": So I Opened the Game's 38GB Archive Myself

It started small. I wanted to know which units in a game have hidden effects when you place them at your base.

Turns out: nobody knew.

  • No official documentation
  • The biggest community database, on that unit's page: "This Pal's abilities are still being investigated."
  • Another widely-cited database still lists the pre-update roster
  • In Chinese, nothing at all

That's when it clicked: I'm not someone waiting for an answer to be published. I'm someone who can go get it.

So I opened the game's data archive. Two hours later I had a list that existed nowhere else in the world.

This is the log of those two hours. If you don't code, keep reading anyway — because the important part isn't the 200 lines. It's the judgment call at the end.


1. What I was up against

When the game installs, everything — every unit's stats, every line of dialogue, every table — is packed into one 38GB file.

Think of it as a giant locked archive: 185,003 files inside, and no unzip tool, because it uses the engine's own format.

Tools do exist. That day I decided to write my own. Simple reason: I wanted to know how the lock actually worked.


2. Five steps (plain English first, code after)

Step 1: Find the table of contents

Plain English: Every archive ends with a small "manifest" telling you how many files there are, where the index lives, and whether it's encrypted. Read that first.

Three lines of output decide everything downstream:

version    = 11
encrypted  = no       ← lucky; no key to crack
compression = Oodle   ← annoying; proprietary format

"Encrypted = no" is why this worked at all. Had it been encrypted, I'd have needed to pull the key out of the running game's memory — a completely different tier of effort.

Show code
FOOTER = 16 + 1 + 4 + 4 + 8 + 8 + 20 + 32 * 5
f.seek(size - FOOTER)
foot = f.read(FOOTER)
guid, encflag = foot[:16], foot[16]
magic, ver, ioff, isize = struct.unpack("<IIQQ", foot[17:41])
assert magic == 0x5A6F12E1       # pak signature

Step 2: Unroll the map of 185,000 files

Plain English: With the manifest in hand, follow its pointer and you get the full file listing — a map of the entire game.

files       = 185,003
directories = 9,007

Why this matters: from here on, I can just search. What I needed surfaced on the first grep:

.../DataTable/Text/DT_PalFirstActivatedInfoText.uexp    ← official ability text
.../Config/DefaultPalWorldSettings.ini                  ← official defaults, plain text

Step 3: Unpack the "squeezed" location data

Plain English: To save space, the game crams each file's position, size, and compression into 4 bytes, at the bit level. The same field might be 4 bytes wide or 8, depending on a flag.

This is the easiest step to get wrong — one bit off and the whole map skews. You'll read garbage and conclude the file is corrupt.

Show code
v       = u32(encoded, o)
comp    = (v >> 23) & 0x3F      # compression method
nblocks = (v >> 6)  & 0xFFFF    # block count
offset  = u32 if v & (1<<31) else u64    # width depends on the flag!
usize   = u32 if v & (1<<30) else u64

Step 4: Decompress (using something I already had)

Plain English: The files are Oodle-compressed — a licensed, proprietary codec with no Python binding.

Most guides send you hunting for a DLL. I did something smarter first: I inventoried what was already on my machine.

I happened to have an open-source save editor for this game installed — and it ships its own Oodle decompressor. Borrowed it. Solved in five minutes.

The mindset matters more than the technique here: the capability you need is often already sitting inside a tool you installed for some other reason. Inventory before you build.

Step 5: Route around the real wall

Plain English: Decompressed, I had the files — and still couldn't read them.

Modern engine versions strip field names out of the data for performance. The file only has numbered slots; you need a separate mapping file to know what "field 3" is called. And that mapping is normally dumped out of a running game's memory.

This is the real wall on this path, and I did not get over it.

But what I wanted was text (ability descriptions), and text has a tell: it's stored as "length, then content", one after another. So I don't need the mapping — I can just sweep every string out of the file.

Better still, data tables store rows as name, value, name, value — so the strings come out already paired.

Show code
# positive = UTF-8, negative = UTF-16 — the engine's string format
ln = struct.unpack_from("<i", b, i)[0]
if 0 < ln < 400:
    s = b[i+4 : i+4+ln]
elif -400 < ln < 0:
    s = b[i+4 : i+4+(-ln*2)].decode("utf-16-le")

# rows are name/value interleaved, so the next string is the answer
for i, s in enumerate(strings):
    if s.endswith("_TextData"):
        rows[s[:-9]] = strings[i+1]

This isn't universal — structured numbers (the 30 in "+30%") still need the mapping file. But for text tables it's 100% sufficient.


3. The step that matters most: proving I didn't get it wrong

This section has nothing to do with code. It's the heart of the whole thing.

Extracting data is half the job. You have to prove it's complete and correct — otherwise you're just manufacturing better-looking misinformation.

Three layers:

① Did I miss anything? Does the number of parsed rows match the number of rows in the table? → 305 keys, 305 paired, zero dropped. A buggy parser fails loudly right here.

② Did I misread anything? I was about to claim "only one unit in the entire game has a defensive effect." So I re-swept the whole table with different keywords (intrude, bombard, intercept, patrol, defend), hunting for anything I'd missed. → Still just the one. Only then does the word "only" go into print.

③ Does anything contradict another source? I had planned to cite an outside site claiming a certain cap was 10. → I searched every text table in the game and found zero evidence for it.

So I cut the sentence.

Better to say one thing less than one thing wrong. The real risk in reverse engineering was never "failing to crack it." It's cracking it, misreading it, and publishing with confidence.


4. The outcome

  • A ~200-line, zero-dependency archive reader
  • 3 data tables + 1 official config file, pulled precisely out of 38GB
  • A list that is undocumented officially, absent from the wikis, and nonexistent in Chinese
  • One outside claim disproved and dropped

And the tool isn't specific to this game — anything packed with the same engine works.


5. Why Ultra Lab writes about this

On the surface: game trivia. Underneath: a miniature of what we do every day.

When the authoritative source says "unknown," go read the layer underneath.

That's exactly what UltraProbe (our open-source AI security scanner) is. We don't take a vendor's word that their AI is safe — we scan the actual prompts and watch what the agent actually does.

The answer usually isn't in the docs. It's in the binary, the traffic, the runtime behavior.

Tools go stale. The habit doesn't.


Scope and disclaimers

  • Read-only throughout. No game files were modified.
  • No redistribution of game assets or bulk text. This post presents my conclusions and the method.
  • Mechanics and numbers are statements of fact, fine to write guides about. Assets are copyrighted — a different matter. Know where the line is.

Weekly AI Automation Playbook

No fluff — just templates, SOPs, and technical breakdowns you can use right away.

Join the Solo Lab Community

Free resource packs, daily build logs, and AI agents you can talk to. A community for solo devs who build with AI.

Need Technical Help?

Free consultation — reply within 24 hours.