NB file woes

This post documents my experience with Sonic Adventure NB files and my attempts to reverse engineer the format.

NB is some kind of container format for models and animations. It’s different from container formats used in the Katana SDK, and I haven’t seen any other games use it. There are only two NB files in Sonic Adventure/DX that are used in all versions of the game: E101R.NB and EROBO.NB. As you may guess from their names, they contain models and animations for ZERO and E-101R MK II boss fights. A lot of stuff in these NB files can be found elsewhere in the game – for example, Zero’s model and animations also exist in the main binary in the 2004 version of SADX, and E101R has a cutscene model that can be ripped easily. But NB files also contain miscellaneous models for things used in these fights, such as explosions, projectiles and electric barriers, as well as some unique boss animations.

On the Gamecube the NB files are byteswapped and called E101R_GC.NB and EROBO_GC.NB, but in the PC version they are Little Endian despite the “_GC” in the filenames. Apart from Endianness the format itself is the same between all versions, and files from the Dreamcast version will work with the PC version if you simply rename them.

The NB file is composed of binary sections preceded by an 8-byte header. A section can contain models, motions or shape motions (the NB files in SA1/SADX do not contain shape motions, but I found some shape motion loading code associated with one of the section types). Each section is divided into subsections, which have their own headers and contain various types of data. For models it’s vertices, normals, materials, meshsets, UVs, model and object structures. For animations it’s rotations, positions, motion data structures and finally the motion structure itself.

So first I wanted to extract models and animations from NB files. I started with the program called SplitNB in SA Tools, which was already capable of splitting out individual binary sections from the NB file. Getting the models out of those sections was easy because the root model is always at the end of the file, so just loading a model at its address got the whole model hierarchy covered. Animations were a lot more involved, since the motion at the end of the file wouldn’t load without modifications. After a few attempts I managed to reconstruct the full animation from those individual subsections, and you can now use SplitNB in SA Tools to extract both models and animations from NB files.

The next logical step was to try and recreate those NB files from actual models and animations. That was pretty complicated since I couldn’t just write out the whole model – I needed to break all its data into sections. Same with animations, which had to have rotations and positions stored in separate sections with correct pointers to them in the motion data section.

So I managed to rebuild NB files from models and animations extracted from them previously. ZERO worked right away, but with E101R the game froze while still playing the music. After comparing original and recreated sections I found the culprit – one of the motion sections didn’t match. The original motion’s rotations section contained two rotation keyframes that my code wasn’t picking up, and the resulting section was 32 bytes smaller. But when I looked at those rotations I found out why they weren’t being picked up – they weren’t referenced anywhere in the file. Unused/leftover animation data? I don’t know, but because it’s unused, the program doesn’t include it in the extracted animation, so the rebuilt section doesn’t have it either.

But even then, why would the game freeze if the data included in the file is correct and all pointers are valid? I open the disassembly and I see this shit:

So yes, despite being able to load a pretty elaborate container format, the game uses hardcoded offsets for models in NB files, which makes any NB file rebuilding useless without additional modification of the game’s code.

Can this be worked around? Sure, if you change the offsets in code to match those in your NB file it might work. Also it will certainly work if you rebuild the file in a way that keeps original offsets for models, though it limits the possible scope of modification quite a lot. It’s disappointing because I wanted to make SA Tools support splitting and building these files for easy modification, but this hardcoded stuff is too much effort to change such specific parts of the game. I’m still going to update SA Tools with a tool to rebuild these files for lighter edits, so at least we can have that. Oh, and if you just wanted the models or animations for use in other projects, you can already have them.

This concludes my investigation into SA1/DX NB files. If you’re interested in the specifics of the format, SplitNB source code has some documentation.