I'm surprised I found a thread that was contributed to so recently. I've been wondering if the iOS version uses 3D models, or if it at least would be possible to get the higher res sprites so I downloaded the app and went to town. I noticed allMotionPack3.pac and tried to extract it. I tried using QuickBMS and the Ghost Trick script that was made for it, but that one errored out. It did manage to produce 1.dat, which seems to have some sort of structure.
View attachment 286301
I then tried to make my own parser based on the script, and tried saving each chunk as a separate file and got something that looked like this: (first 3 chunks of the first "file")
View attachment 286302View attachment 286304View attachment 286305
There's an 11 close to the beginning of each of those files, so I tried removing the first 4 bytes and running it through DSDecomp, but it complained about the input containing more data then necessary. Nevertheless, I got an output that matched the first one (except that it was shorter because the script seemingly merges the chunks into one file) so I probably did something right.
Afterwards, I tried opening the pac file in CrystalTile2, and it almost worked, but it apparently can't handle such large files. I then tried just extracting each "file" from the archive, which meant that the resulting files had the chunk information. I opened that in CrystalTile2, which managed to recognize it (ignore the LZ one, that was just because that chunk started with 10):
View attachment 286306
Extracting through it produced the same result as my own parser, so that wasn't too helpful. Although after writing that parser, I noticed what the error in the original script was. It seems that the first file offset is repeated twice, probably meaning that the first offset is meant to be for the end of the offset table. Notice the E4 47 repeating:
View attachment 286307
After I accounted for that in the original script, it worked all the way to file 1501 (out of 4600) where it errored out (something to do with file size and compression). I got files of varying sizes, but most of them seem to have the same overall structure:
View attachment 286308View attachment 286309View attachment 286310View attachment 286311View attachment 286312
That structure continues all the way down, until:
View attachment 286313View attachment 286314View attachment 286315View attachment 286316
While most of the files go around up to 2MB, there's one that's 16MB, and its structure also looks very different:
View attachment 286318View attachment 286319
My theory is that those files might just be images, or rather frames of the videos that play in the game. I'm still hoping for 3D models though!
For anyone interested, search for QuickBMS (Luigi Auriemma) and on that same page, you can find the Ghost Trick script. You'll then have to modify the script (it's a text file) by changing the lines:
Code:
if EXT == "pac"
get FILES long
for i = 0 < FILES
to:
Code:
if EXT == "pac"
get FILES long
get TEST long
math FILES - 1
for i = 0 < FILES
Oddly enough, the script seems to be using lz77wii, and I have absolutely no idea what that compression method is like.
Also if you want to use my absolute abomination of a code, here:
C#:
using System.IO;
namespace GhostTrickPAC
{
class Program
{
static int FileCount;
static int[] Offsets;
// Drag and drop allMotionPack3.pac onto the exe, or for lazy debugging replace args[0] with the path to the file
static void Main(string[] args)
{
using (BinaryReader reader = new BinaryReader(new FileStream(args[0], FileMode.Open)))
{
FileCount = reader.ReadInt32()-1;
reader.ReadInt32();
Offsets = new int[FileCount];
for (int i = 0; i < FileCount; i++)
{
Offsets[i] = reader.ReadInt32();
}
for (int i = 0; i < FileCount; i++)
{
int NextOffset = (int)reader.BaseStream.Length;
int CurrentOffset = Offsets[i];
if (i + 1 < FileCount)
{
NextOffset = Offsets[i + 1];
}
reader.BaseStream.Seek(CurrentOffset, SeekOrigin.Begin);
// Comment this to instead write each chunk as file
var ChunkSize = NextOffset - CurrentOffset;
var data = reader.ReadBytes(ChunkSize);
File.WriteAllBytes($"out2/{i}.dat", data);
// to here, just use /* */
/* And uncomment this too
var ChunkCount = reader.ReadInt32();
var ChunkOffsets = new int[ChunkCount];
for (int c = 0; c < ChunkCount; c++)
{
ChunkOffsets[c] = reader.ReadInt32();
}
for (int c = 0; c < ChunkCount; c++)
{
int NextChunk = NextOffset;
if (c + 1 < ChunkCount)
{
NextChunk = CurrentOffset + ChunkOffsets[c + 1];
}
var CurrentChunk = ChunkOffsets[c];
reader.BaseStream.Seek(CurrentChunk + CurrentOffset, SeekOrigin.Begin);
var ChunkSize = NextChunk - CurrentChunk;
var data = reader.ReadBytes(ChunkSize);
File.WriteAllBytes($"out/{i}_{c}.dat", data);
}
*/
}
}
}
}
}