Aug 30th, 2022 at 10:12 pm (edited)
#772
FAST Racing League is an obscure, rarely talked about racing game for the Nintendo Wii. It is a game I am very passionate about, and I wish to give it modding support.

FRL was released as a WiiWare exclusive in May of 2011 by German second-party developer Shin'en Multimedia, who had previously released Jett Rocket onto WiiWare the year prior. Both games use a proprietary, undocumented in-house game engine called SHN4. The only reason I even know of this engine's name is because it's name was put in fine print on this movie-style promotional poster created by the developers:



This game can no longer be purchased and is considered abandonware with no clear plans to rerelease it. It can only be obtained through piracy. The IP still lives on however in FAST RMX, which was a launch title for the Nintendo Switch.

SHN4 (which I've dubbed "Shin'engine" since that rolls off the tongue easier) was an engine exclusive to the Wii and was designed to get the absolute best performance out of it's decade old hardware. Remember that the Wii was an extremely underpowered console even for it's time. It came out in 2006 with a low-power PPC CPU, an outdated AMD GPU, and rather interestingly an ARM slave CPU living inside of the GPU which acted as the system's boot hypervisor (and a very crappy one at that). All things considered it was just a slightly upgraded version of the Gamecube from 5 years earlier. Shin'en was somehow able to pull off real-time screen space reflections and hard realtime cascaded shadows on hardware that was 10 years old when FAST Racing League and Jett Rocket both came out, and at 60 FPS. The games didn't look great compared to the games of the era on other platforms (GTA 5, Wipeout HD, and Crysis to name a few), but by Nintendo standards it had never been done before.

What made this even more challenging was the size limit. WiiWare games had a maximum size of 40 MB. Prettymuch all of the Wii's budget went into motion controls, and so not only did the graphics suffer, but the internal storage was TINY. There are only 512 MB of NAND storage to work with on the Wii, and some of that is taken up by the operating system. This was in 2006 when SSDs were far less common and more expensive to produce. Nintendo wanted this console to be cheap, cost-effective, small and quiet so that families would feel more comfortable owning one, so loud hard drives or huge flash memory chips were not an option. In order to ensure customers could download more than one WiiWare game at a time without requiring an SD card to be inserted, Nintendo restricted the size of WiiWare games. This is why so many good Wii games were retail only and the Shop Channel mostly consisted of smaller games or just shovelware. These limits were just too hard to work with for most developers.

FAST Racing League is by far one of the most well optimized games on the Wii, and it's one of the most impressive WiiWare game to ever release. Despite this, it has it's obvious shortcomings. The game is lacking in some content and some of the tracks are a little too easy with not enough room for more technical circuits. Part of this is a game design issue, but a lot of it has to do with being unable to squeeze enough levels in without sacrificing beginner friendly ones. Sony's WipEout games managed to avoid the problem with replay value, but I don't blame Shin'en for struggling with it. FRL's mechanics, while simple, are more unforgiving. Shoving in highly complicated circuits in the beginning of the game's singleplayer campaign would be a bad decision. The later levels in the game are absolutely brutal with ice floors and spinning obstacles, so spending some time getting the player familiar with a calmer race track was neccessary. Otherwise it's basic driving mechanics were much simpler and resembled a dumbed down F-Zero, but unlike in other racing games, resource management is a big part of this game's main gimmick: phase shifting. If your driving is bad and you can't collect enough energy, you risk missing boosts or being forced into a bad scenario where your only choice is to fall off the track and crash. The game has good gameplay but it is short-lived. So yes, FAST Racing League only has 12 levels. And some of them are just really boring. The phase shift mechanic was interesting, but not always used to great effect.

But with this lack in content, and a potential for a good game made better, why don't we try to mod more content in?

The issue is with that proprietary game engine I was talking about. Because this is a WiiWare game, Shin'en had to compress the living hell out of it to make it fit in such a small space, as well as re-use assets between levels. Even then the game is still 5 MB above the limit so I don't know how it got past Nintendo's approval process.

Part of this includes using proprietary file formats. Many of these custom formats that the SHN4 engine uses are variants of pre-existing formats, or just well documented formats compressed into a confusing "CMPR" container. Despite this, they all retain common file extensions, which can be confusing for modders digging into the game for the first time.

Here's what we know so far:

- The game's sound effects are nothing special. It's a standard BRSAR sound bank just like in dozens of other Wii games. It can be extracted with BrawlBox with no hassle and even swapped out.
- The game's music, on the other hand, is encoded using a custom version of libvorbis. It is a variant of OGG Vorbis with slightly different parameters, just enough to confuse a standard audio player. I'm not sure why this was done, probably some weird encoding hack to make the files smaller. Maybe a audio/video codec engineer can answer that question. These files can be opened using vgmstream and are known as "Shin'en Vorbis", but they currently cannot be written to.
- The game's textures are in a standard TPL container wtih DXT1, standard in most Wii and Gamecube games. However, they are also compressed with CMPR on top of that. I don't know what CMPR is. It's not the CMPR texture format, it's something different. watto.org managed to figure it out and add it to their donationware tool Game Extractor, but they did not elaborate on the details of the compression when I discussed it with them through email. To my knowledge, Watto Game Extractor is the only program currently able to open these files.
- The same goes for the localization files and all other parts of the game. They are all wrapped with CMPR. The level objects, prefabs, mesh data, and levels are stored in the W3D format. This appears to be a proprietary format and not an Adobe Director file or whatever else the internet might suggest, as stated by the Watto devs yet again (I had some help from them here with identifying these formats, you'll see them brought up a few times). This is a binary format with occasional file paths or object names written in ASCII when viewed in a hex editor.

I decided to datamine whatever files are currently accessible to me, and I found some interesting stuff.

First off, there is this C++ header file "fx.h" which assigns every sound effect in the BRSAR bank to an integer. This is probably just the game's way of identifying each sound numerically with an ID. I'm not sure why they chose to do it this way.
static const unsigned int FX_bump2 = 0;
static const unsigned int FX_ceremony_drive = 1;
static const unsigned int FX_engine0 = 2;
static const unsigned int FX_engine1 = 3;
static const unsigned int FX_engine2 = 4;
static const unsigned int FX_engine3 = 5;
static const unsigned int FX_engine4 = 6;
static const unsigned int FX_engine5 = 7;
static const unsigned int FX_engine6 = 8;
static const unsigned int FX_engine7 = 9;
static const unsigned int FX_metal = 10;
static const unsigned int FX_rain = 11;
static const unsigned int FX_tornado = 12;
static const unsigned int FX_wind = 13;
static const unsigned int FX_bump1 = 14;
static const unsigned int FX_splash = 15;
static const unsigned int FX_switch2 = 16;
static const unsigned int FX_vo_ajia_x = 17;
static const unsigned int FX_vo_boost = 18;
static const unsigned int FX_vo_breeze_city = 19;
static const unsigned int FX_vo_challenge_failed = 20;
static const unsigned int FX_vo_challenge_ok = 21;
static const unsigned int FX_vo_congrat = 22;
static const unsigned int FX_vo_cove_harbour = 23;
static const unsigned int FX_vo_denku_qx = 24;
static const unsigned int FX_vo_dry_hill = 25;
static const unsigned int FX_vo_dt_bosutun = 26;
...


The file "fx.rsam" is a text file which contains another index of every sound effect used in the entire game (there aren't very many), and some metadata about them. At the end, we get a few hex pointers to some sound data in the BRSAR file.

What's really interesting are these unused screenshots stored in the game's texture folder, which provide some interesting views into the development process of the game. One of them has been squished down into a weird square resolution. These don't look like the final game, I believe these are beta screenshots taken by Shin'en employees. I'm not sure why they are in the game's files, it's possible they were used for some kind of level select screen, or possibly the Wii Shop Channel advertisement that shows at the end of the demo version. It was pretty common back in the day for demo versions of Wii and 3DS games to end the demo with a page asking you to buy the full game or return to the title screen, often featuring screenshots and some sales pitching to get you onboard, similar to what you'd see on the back of the box on a physical game cover.

Take a look at the finish line in the first screenshot here. It looks completely different from the final product. The frame is really thin, and looks somewhat like those pipes you see holding up road ads or stop lights in real life. The sign on it is green, and appears to say "1 UP!". The shading on the Ajia X ship here also appears to be slightly different, there are no dynamic shadows, and the track's texture has no color to it. This track doesn't exist anywhere in the game. It's a bit hard to see, but there are also some energy orbs in the distance shortly in front of the finish line, followed by that weird bumpy road that kinda reminds me of Citta Nuova from WipEout Pure (ugh, I fucking hate that track). This was probably just a test level and I'm guessing it was created in order to get a feel for the driving physics, which would explain the incredibly awkward twists down that left turn at the very end.


This next screenshot also has quite a few notable differences. This was likely much further in development, and you can tell from the map design. It's definitely not a test level, unlike the last one. It's much more detailed and even uses one of the skyboxes seen in the final game. The camera angle and the fact the player is in 8th place suggests this screenshot was taken in some sort of freecam mode, probably to send to Nintendo or a games journalist to showcase what the game might have looked like. The HUD looks quite a bit different and is probably the biggest change, and we're missing our energy meter and our minimap. The ships also do look slightly off here, and the speedometer is on the right side where the map should be instead of the left. The shadows cast on the ground have no cascades. They're very simple hard shadows like in the final game though, the blurriness is just a side-effect of the low casting resolution.

This is quite similar to some of the screenshots seen on the game's website, but those were much more polished and based off of the final version of the game shortly before release.


For comparison, this is what the final game looks like below:



There are more screenshots taken by developers and left in the game, but they prettymuch are just from the advertising and represent the final game, so they aren't much to write home about. They were most likely left in the game for that end-of-demo message I brought up earlier, but I sadly no longer have a copy of the demo version to confirm this with.

My goal is to find out what format the mesh data is stored in so I can create custom ships and levels. Until then, I'll keep writing down whatever I find.