Jump to content

[Zeebo] Crash Bandicoot Nitro Kart 3D ( .vfs files )


Recommended Posts

Posted (edited)

I'm wanting to make some modifications to the Crash Nitro Kart 3D game for Zeebo. (it was also released for iOS, N.Gage 2.0 and Symbiam)

But everything I looked for related to .vfs files didn't work, I read on a forum about a guy who managed to extract the data.vfs with a script in QuickBMS, I managed to find one from Porlabit Crash Nitro Kart 2 but it didn't work with Nitro Kart 1 so I ended up running out of options.

Also, after extracting the file, is it possible to compress it again so that the game can work with the new modified file?

 

[EDIT]

Kurabupengin sent me the script to extract the data.vfs and it worked without problems:

image.thumb.png.52daee2fa358c5b681d5099c0a56486f.png

But the problem I'm facing now is that I didn't get any way to compress it again.

So even if I can change these files I won't be able to turn them into a new "data.vfs" for the game to read.

Can anyone help me with this ?

 

data.vfs.zip

QuickBMS Script + data.vfs.zip

Edited by moonsarito1
Link to comment
Share on other sites

Considering the files you extracted are because you decompressed them from an archive, its really hard to re-compress that data into the formats read in game. Its most likely not direct extracting of .png files, its most likely a different format that was inside the .vfs file. Ill try to find a compression tool for you on xentax or smtn.

  • Like 1
Link to comment
Share on other sites

Posted (edited)
12 minutes ago, Rypie109 said:

Considering the files you extracted are because you decompressed them from an archive, its really hard to re-compress that data into the formats read in game. Its most likely not direct extracting of .png files, its most likely a different format that was inside the .vfs file. Ill try to find a compression tool for you on xentax or smtn.

Can you also send me the bms file you used? It seems like the bms attached is the one for nitro kart 2. I want to try to see how the data is decompressed, which will help me with recompression.

Edited by Rypie109
Realised something
  • Like 1
Link to comment
Share on other sites

6 hours ago, Rypie109 said:

Can you also send me the bms file you used? It seems like the bms attached is the one for nitro kart 2. I want to try to see how the data is decompressed, which will help me with recompression.

Hello, I'm at work right now so I can't upload the extracted file folder right now, but the data.vfs I posted I took directly from the game files on Zeebo.

The BMS Script that I used to extract the data.vfs was the one I made available above that Kurabupengin had sent me (I think it's the same one from Crash Nitro Kart 2, I'm not sure but it worked with Zeebo's Crash Bandicoot Nitro Kart 1), keep in mind you'll need func_getTYPE.bms for the crash.bms script to work, It needs to be in the same folder as the crash.bms script too.

Link to comment
Share on other sites

12 hours ago, Rypie109 said:

Can you also send me the bms file you used? It seems like the bms attached is the one for nitro kart 2. I want to try to see how the data is decompressed, which will help me with recompression.

Here is the extracted data.vfs and all the files I used:

https://www.mediafire.com/file/bjc5bmvexvro2gl/data.vfs_extracted_and_bms_script.zip/file

Link to comment
Share on other sites

  • 1 month later...
  • 2 weeks later...
11 hours ago, Rypie109 said:

I am assuming the uploads you did was for the ios version?

Nope, Zeebo version.

But from what I researched, it's basically the same structure as the iOS and N-Gage version.

In fact it seems that all Polarbit games have a .vfs file (more specifically a "data.vfs"), Crash Nitro Kart 3D, Ranging Thunder 2 and Reckless Racing for example all have this file.

This here is the data.vfs taken directly from the Zeebo version (You can play the Zeebo version on PC via the Infuse emulator):

https://www.mediafire.com/file/ouayuol8p6z0h1c/data.vfs/file

As I said before, I managed to find a script made for Crash Nitro Kart 2 (it is the successor to Crash Nitro Kart 3D) to extract the .vfs file and thus be able to access the image and sound files (music and sound effects). , but after analyzing it I think that the extraction was not completely successful because it has some files with unknown formats (I believe they are related to 3D modeling since all the other files are image and audio files)

image.thumb.png.debb743bd5edd669fe534f6280b44abb.png

So now I have two problems.

1. The script I used to extract the data.vfs from Crash Nitro Kart 3D may not be working correctly.

2. I still haven't found any "repack" or anything like that to test in the game.

 

I could only find two related things.

> A Reckless Racing mod where the member made changes to the data.vfs of that game (I tried to contact him, but without success)

> An old Russian forum where apparently someone managed to unpack/pack the data.vfs file of several porlabit games. (I tried to get in touch too, without success)

 

So now I'm back to where I started without any progress. 😕

 

Link to comment
Share on other sites

Hmmm... Do you mind linking me to the reckless racing mod? I will try myself to get intouch with him, and also try to get in touch with the person who made the script that you have, to see if I can get him to refine it (the more people taking interest, the more likely they will listen)

I will also try to see the offsets the script digs through, to see how the files are even packed in the first place.

Link to comment
Share on other sites

11 hours ago, Rypie109 said:

Hmmm... Do you mind linking me to the reckless racing mod? I will try myself to get intouch with him, and also try to get in touch with the person who made the script that you have, to see if I can get him to refine it (the more people taking interest, the more likely they will listen)

I will also try to see the offsets the script digs through, to see how the files are even packed in the first place.

Sure, here it is:
https://xdaforums.com/t/mod-3-1-2013-game-modification-for-tegra-3-mod.1845993/

He made a Reckless Racing 2 texture mod (which perhaps has a more updated .vfs file than other Porlabit games, but still maintains the same "data.vfs" structure), from what I've seen his data.vfs is adding higher quality textures in the game and reduced file size.

If you make any progress on how to pack/unpack the .vfs files please let me know.

Link to comment
Share on other sites

I sent him this message:

Quote

Hi, I have a question about how you made one of your mods, specifically reckless racing 2 by polarbit. Me and a few other people have been wondering how to extract then repack (after changing stuff) the data.vfs file. It seems that you know how to repack it, which is what we are most interested in. Thanks in advance! -Rypie

Oh god, I just saw when he was last online... 2015. I will try to get ahold of him on other platforms

Link to comment
Share on other sites

tbh, i dont know how the files were even decompressed out of it, but im assuming that the script isnt just ripping .pngs and other stuff straight from the file, i think its being converted to the file formats. If we can get something to rip the already compressed data, then it will be easier.

  • Like 1
Link to comment
Share on other sites

The game uses zlib compression.

I did a simply python script, that separate compressed files and no compression files, decompressing them.

need to make another script to compress and reimport again.

the unknow files is descompressed from the original file.

 

import struct
import zlib
import os

def read_long(file):
    data = file.read(4)
    if len(data) < 4:
        raise struct.error("unpack requires a buffer of 4 bytes")
    return struct.unpack('<I', data)[0]

def read_byte(file):
    data = file.read(1)
    if len(data) < 1:
        raise struct.error("unpack requires a buffer of 1 byte")
    return struct.unpack('<B', data)[0]

def read_dstring(file, length):
    data = file.read(length)
    if len(data) < length:
        raise ValueError("Not enough bytes to read the expected string")
    return data.decode('utf-8')

def process_file(input_file, output_dir):
    with open(input_file, 'rb') as f:
        fufs = f.read(4).decode('utf-8')
        if fufs != 'FUFS':
            raise ValueError("Invalid file format")

        unk = read_long(f)
        files = read_long(f)

        for i in range(files):
            try:
                offset = read_long(f)
                name_crc = read_long(f)
                size = read_long(f)
            except struct.error as e:
                print(f"Error reading file metadata for file {i}: {e}")
                break

            current_pos = f.tell()
            if offset >= os.path.getsize(input_file):
                print(f"Offset {offset} is beyond file size.")
                continue

            f.seek(offset)

            try:
                test = read_byte(f)
            except struct.error:
                print(f"Failed to read byte at offset {offset}")
                continue

            comp = 0
            zsize = 0

            if test == 0x78:
                comp = 1
                zsize = size * 0x300
            elif test == 0x50:
                f.seek(offset)
                test = read_dstring(f, 4)
                if test == "PLZP":
                    comp = 1
                    zsize = read_long(f) * 0x10
                    offset += 0x0c
            else:
                f.seek(offset)
                data = f.read(size)
                with open(os.path.join(output_dir, f"unknown_{name_crc:08x}.bin"), 'wb') as out_file:
                    out_file.write(data)

            if comp == 1:
                f.seek(offset)
                data = f.read(size)
                try:
                    decompressed_data = zlib.decompress(data)
                    with open(os.path.join(output_dir, f"compressed_{name_crc:08x}.bin"), 'wb') as out_file:
                        out_file.write(decompressed_data)
                except zlib.error as e:
                    print(f"Error decompressing file with name_crc {name_crc:08x}: {e}")
                    continue

            f.seek(current_pos)

if __name__ == "__main__":
    input_file = 'data.vfs'  # Path to the input FUFS file
    output_dir = 'output'  # Directory to save the extracted files

    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    process_file(input_file, output_dir)

 

Edited by Rabatini
  • Like 1
Link to comment
Share on other sites

On 7/21/2024 at 1:31 PM, Rabatini said:

The game uses zlib compression.

I did a simply python script, that separate compressed files and no compression files, decompressing them.

need to make another script to compress and reimport again.

the unknow files is descompressed from the original file.

 

import struct
import zlib
import os

def read_long(file):
    data = file.read(4)
    if len(data) < 4:
        raise struct.error("unpack requires a buffer of 4 bytes")
    return struct.unpack('<I', data)[0]

def read_byte(file):
    data = file.read(1)
    if len(data) < 1:
        raise struct.error("unpack requires a buffer of 1 byte")
    return struct.unpack('<B', data)[0]

def read_dstring(file, length):
    data = file.read(length)
    if len(data) < length:
        raise ValueError("Not enough bytes to read the expected string")
    return data.decode('utf-8')

def process_file(input_file, output_dir):
    with open(input_file, 'rb') as f:
        fufs = f.read(4).decode('utf-8')
        if fufs != 'FUFS':
            raise ValueError("Invalid file format")

        unk = read_long(f)
        files = read_long(f)

        for i in range(files):
            try:
                offset = read_long(f)
                name_crc = read_long(f)
                size = read_long(f)
            except struct.error as e:
                print(f"Error reading file metadata for file {i}: {e}")
                break

            current_pos = f.tell()
            if offset >= os.path.getsize(input_file):
                print(f"Offset {offset} is beyond file size.")
                continue

            f.seek(offset)

            try:
                test = read_byte(f)
            except struct.error:
                print(f"Failed to read byte at offset {offset}")
                continue

            comp = 0
            zsize = 0

            if test == 0x78:
                comp = 1
                zsize = size * 0x300
            elif test == 0x50:
                f.seek(offset)
                test = read_dstring(f, 4)
                if test == "PLZP":
                    comp = 1
                    zsize = read_long(f) * 0x10
                    offset += 0x0c
            else:
                f.seek(offset)
                data = f.read(size)
                with open(os.path.join(output_dir, f"unknown_{name_crc:08x}.bin"), 'wb') as out_file:
                    out_file.write(data)

            if comp == 1:
                f.seek(offset)
                data = f.read(size)
                try:
                    decompressed_data = zlib.decompress(data)
                    with open(os.path.join(output_dir, f"compressed_{name_crc:08x}.bin"), 'wb') as out_file:
                        out_file.write(decompressed_data)
                except zlib.error as e:
                    print(f"Error decompressing file with name_crc {name_crc:08x}: {e}")
                    continue

            f.seek(current_pos)

if __name__ == "__main__":
    input_file = 'data.vfs'  # Path to the input FUFS file
    output_dir = 'output'  # Directory to save the extracted files

    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    process_file(input_file, output_dir)

 

Thank you very much, I tried using the script you made but it generated several .bin files this time instead of the extracted files like before.

Is this correct?, I'm not sure if it's supposed to work like this. (to be honest, my knowledge of Python is very basic)

image.thumb.png.fea975bd866aef112b2924f18923f1a2.png

Link to comment
Share on other sites

Your file have compressed and non compressed files inside of it.

i don´t know what you tried to do.
What´s is your goal?
localization?

The script i made it´s just to separete the files compressed x non compressed.

As per the file is zblib compression, you can uses offzip to extract and reimport

donwload offzip in aluigi site.

and uses a.bat offzip -a yourfile.vsf

this should extract every file, offzip has a option to reimport -r

 

Edited by Rabatini
Link to comment
Share on other sites

12 hours ago, Rabatini said:

Your file have compressed and non compressed files inside of it.

i don´t know what you tried to do.
What´s is your goal?
localization?

The script i made it´s just to separete the files compressed x non compressed.

As per the file is zblib compression, you can uses offzip to extract and reimport

donwload offzip in aluigi site.

and uses a.bat offzip -a yourfile.vsf

this should extract every file, offzip has a option to reimport -r

 

Sorry, I'm a bit of a newbie at this thing.

My goal is to modify textures, sound effects and sounds in Crash Nitro Kart 3D (maybe in other Polarbit and Zeebo games as well since they also have a "data.vfs"), I've even created some new textures using Photoshop with based on the original textures when I managed to extract the files for the first time at the beginning of the post.

YayaPanda.thumb.jpg.d84f84129a042405364c81519cfc5dc2.jpg

But I'm having trouble inserting it back to use in the game, so I needed something that could pack and unpack the .vfs files so that the game would continue to work with the new data.vfs file.

But then, do I just use your script to extract the data.vfs and then use offzip to extract the .bin files so I can modify them?

Link to comment
Share on other sites

3 hours ago, Rabatini said:

Send me a file edited by you, to make a test.

Sure, here it is, this is the modification I made to Yaya Panda's texture, I just redesigned her face and hair to bring it closer to her design in the Crash Team Racing remake.

data_0x65876fbf.zip

I intended to make more modifications if I found a more practical way to pack/unpack the data.vfs, perhaps improve the textures of other characters and bring them closer to the design of the originals, improve the sound effects (which are of very low quality). , maybe even swap 3D models. (I actually don't know if this is possible, I have no idea what the 3D models are in this game)

data_0x65876fbf.png

data_0x65876fbf.png

data_0x65876fbf.zip data_0x65876fbf.zip

Link to comment
Share on other sites

Mostly, PNG files are decompressed, so it's fairly easy to edit and reimport them.

However, you need to compress your PNG files using the site iLoveIMG.

For example, if the original PNG is 10 KB, your PNG must be 10 KB or less, so you will need to compress it on the site.

I’ve attached 3 files:

Two BMS scripts:

One script will unpack the data, decompressing all files.
The other script will unpack the file without decompressing it (this is the one you should use for reimporting; reimport with -r, not reimport 2 in quick bms).

A Python script (.py):

This program decompresses and compresses zlib files individually. I have set a compression level to reduce the file size even further. Use this if you need to handle compressed files.

zlib_DeCompressor.py

BMS.ZIP

Edited by Rabatini
Link to comment
Share on other sites

3 hours ago, Rabatini said:

Mostly, PNG files are decompressed, so it's fairly easy to edit and reimport them.

However, you need to compress your PNG files using the site iLoveIMG.

For example, if the original PNG is 10 KB, your PNG must be 10 KB or less, so you will need to compress it on the site.

I’ve attached 3 files:

Two BMS scripts:

One script will unpack the data, decompressing all files.
The other script will unpack the file without decompressing it (this is the one you should use for reimporting; reimport with -r, not reimport 2 in quick bms).

A Python script (.py):

This program decompresses and compresses zlib files individually. I have set a compression level to reduce the file size even further. Use this if you need to handle compressed files.

zlib_DeCompressor.py 4.01 kB · 0 downloads

BMS.ZIP 1.1 kB · 1 download

Thank you very much, really, this will be a great help for me to be able to mod this game.

Just one question, the data.vfs cannot exceed the size of the original file? Does this mean that it is not possible to add sound effects (.wav) or music (.mp3) with higher quality to the game?

1 hour ago, Rypie109 said:

@moonsarito1 Hey, I see this is figured out, this is far better than anything I could figure out!

Yeah, still, thank you very much for your interest and help, for real.

Link to comment
Share on other sites

Quote

Just one question, the data.vfs cannot exceed the size of the original file? Does this mean that it is not possible to add sound effects (.wav) or music (.mp3) with higher quality to the game?

In QuickBMS reimport mode, yes!, The game does not accept reimport 2 or 3 provided by QuickBMS because, for larger files, QuickBMS puts them at the end of the file and redirects to them, which the game does not accept. The solution that might work is to create a tool that unpacks and packs the files, recalculating all pointers.

Example of What Happens with QuickBMS

Original:

File number 10 = offset 0x00, size = 16 bytes

File number 11 = offset 0x10, size = 16 bytes

File number 12 = offset 0x20, size = 16 bytes

File number 13 = offset 0x30, size = 16 bytes

File number 666 (last file) = offset 0x400, size = until the end of the file

QuickBMS Reimport 2:

File number 10 = offset 0x00, size = 16 bytes

File number 11 = offset 0x10, size = 18 bytes (the file that was edited and is now larger)

File number 12 = offset 0x410, size = 16 bytes

File number 13 = offset 0x30, size = 16 bytes

File number 666 (last file) = offset 0x400, size = 16 bytes

The Correct Sequence Should Be:

File number 10 = offset 0x00, size = 16 bytes

File number 11 = offset 0x10, size = 18 bytes (the file that was edited and is now larger)

File number 12 = offset 0x22, size = 16 bytes

File number 13 = offset 0x32, size = 16 bytes

File number 666 (last file) = offset 0x402, size = until the end of the file

All pointers need to point sequentially.

Edited by Rabatini
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...