Page 1 of 1

Neopets Mobile .pak File

Posted: Sat Aug 27, 2022 2:34 am
by ProbPeriPlum
This was an old Java phone game that gave access to Lutari Island which was only available throigh T Mobile.

These files store the .midis and bitmaps and such for the game and I wanted to recover them for preservation's sake. Since .pak files can vary I'm not sure if an existing method for this already exists or not, but help would be of great appreciation!

The original game (change the extension to zip to unpack): https://cdn.discordapp.com/attachments/ ... 6uczoa.jar

Just the .pak files: https://cdn.discordapp.com/attachments/ ... _Files.zip

Re: Neopets Mobile .pak File

Posted: Sun Aug 28, 2022 10:13 pm
by barncastle
This is a pretty straight forward format that is built around loading files by their archive index. Each pak is named after the first file index they contain (e.g. r026.pak's first file is file number 26) with the pack.ifo storing this information in a binary format allowing for quick pak identification. When a file is needed, the game finds the closest previous pak, does some quick math to calculate the fileOffset index, and loads it.

Images are stored as stripped PNGs that the game rebuilds at runtime with only the important metadata and compressed data being stored with the paks. One thing to note; they've employed bit values (e.g. nibbles) instead of int8/16/32s for certain fields to squeeze out some extra space.

I've reimplemented the games code for file loading almost 1:1 in C# here including the PNG conversion. There is a tool at the end of the page that will dump all files from these archives - just put it in a folder with the pack.ifo and *.pak files and run. I've added code to correctly set the file extensions for png and midi files however everything else is set to ".bin" as I couldn't identify them (likely custom formats). Unfortunately there are no file names so everything is dumped as it's file index.

Code: Select all

struct PackIfo {
   int16_BE count;
   int16_BE unused;
   byte archiveDeltas[count]; // difference between each pak's ordinal e.g. [r000, r014, r024] => [14, 10]
}

struct Pak {
   byte fileCount;
   int16_BE fileOffsets[fileCount]; // relative
   byte data[x];
}