The ReBUILD ProjectSVN directory: rebuild |
Home :: Transfusion :: Transfusion II :: BloodSource :: ReBUILD :: Files :: Snapshots |
Introduction :: Downloads :: File formats |
IntroductionReBUILD is a project founded in August 2000 by Timothy Hale and Mathieu Olivier, with the valuable help of Greg Enright of the BloodSource campaign. Those 3 fans of Monolith Productions' 3D-shooter Blood wanted to revitalize/modernize the editing tools for BUILD, the engine on which Blood is based, and to gather technical informations about Blood, so people would have a set of good tools to work with when the Blood source code would finally be released.At this time, Ken Silverman had just released the source code of his BUILD engine, and so many people thought the Blood source code release was a matter of weeks. Unfortunately, this release didn't happen. Timothy, Mathieu and Greg then decided to move on and founded qBlood (now known as the Transfusion Project) in March 2001. As a consequence, there isn't much activity on ReBUILD nowadays, although the project isn't officially dead. If you want to get support or information about the ReBUILD Project, contact Timothy Hale or Mathieu Olivier via the Transfusion Project. DownloadsThe utilities marked with an empty dot are now maintained in the Transfusion project's SVN tree and are the only ones that are really supported. Their source codes and binaries can be found here. Below is the complete list of the utilities the ReBUILD Project has created or modified:Tools released under the GNU GPL (source code and Win32 binaries are in the ZIP files)
Tools released under the BUILD license (source code and Win32 binaries are in the ZIP files)
File formatsOne of the goals of the ReBUILD project is to gather technical information about the file formats used by Blood. Some of them are standard BUILD formats and are well known and documented, but for the most part, the file formats have to be guessed from reverse-engineering technics and experiments. The contact the BloodSource campaign once maintained with Matt Saettler, one of the Blood developers, proved extremely valuable here since Matt provided us with some important information regarding several of those formats.The ART files and PALETTE.DAT: Blood uses the BUILD standard ART format for its picture packages. Blood's color palette, stored in PALETTE.DAT, is also in a standard BUILD format. The complete documentation of both formats is available in the source code release of the BUILD engine, mostly in BUILDINF.TXT. The DEM files: This is the documentation provided on the .dem format that Blood uses for it's demos. It came with 1.21 One Whole Unit. Blood's .DEM file format (1.10 and above) Copyright 1997, Monolith Productions. All Rights Reserved. 08/20/97 THIS IS ALL SUBJECT TO CHANGE. =============================================================================== WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! =============================================================================== The INPUT structure couuld change, causing the demos to be invalid. More often, however, AI or weapon changes cause the recorded actions to become 'not the intended action'. For example, 1.02 demos that use the Voo-Doo alt-fire were 'broken' in 1.10 when the alt-fire VooDoo action was changed. Monsters that were previously killed were now still alive. This could cause the player to run into them instead of proceeding safely to the next area, etc. All further actions would then be modified as the recorded re-actions of the player are now blindly responsding to events that don't happen. The usual result is early death. =============================================================================== File format: DEMOHEAHDER INPUT[nInputCount][nNetPlayers] // set of INPUT for each of the players. =============================================================================== DEMOHEADER Structure definition struct DEMOHEADER { DWORD signature; //'DEM\0x1a' BLOODVERSION nVersion; // version of Blood that created the demo long nBuild; // build of Blood that created the demo // builds are: // SW, SWCD: 2 // Registered: 3 // Plasma Pak: 4 long nInputCount; // number of INPUT structures recorded int nNetPlayers; // number of players recorded short nMyConnectIndex; // the ID of the player short nConnectHead; // index into connectPoints of Player short connectPoints[MAXPLAYERS]; // IDs of players GAMEOPTIONS gameOptions; // game options used for level }; =============================================================================== GAMEOPTIONS Structure definition struct GAMEOPTIONS { GAMETYPE nGameType; DIFFICULTY nDifficulty; int nEpisode; int nLevel; char zLevelName[ _MAX_PATH ]; char zLevelSong[ _MAX_PATH ]; int nTrackNumber; char szSaveGameName[kMaxFileKeyLen]; char szUserGameName[kMaxFileKeyLen]; short nSaveGameSlot; int picEntry; ulong uMapCRC; MONSTERSETTINGS nMonsterSettings; ulong uGameFlags; // net game options/data only ulong uNetGameFlags; WEAPONSETTINGS nWeaponSettings; ITEMSETTINGS nItemSettings; RESPAWNSETTINGS nRespawnSettings; TEAMSETTINGS nTeamSettings; // team and cooperative int nMonsterRespawnTime; int nWeaponRespawnTime; int nItemRespawnTime; int nSpecialRespawnTime; }; =============================================================================== INPUT Structure definition /*********************************************************************** * BUTTONFLAGS * * This structure is packetized and sent to other players. These keys * are used frequently during the game. The purpose for separating and * keeping this structure small, is to limit the amount of transferred * data. * **********************************************************************/ union BUTTONFLAGS { char byte; struct { unsigned jump : 1; // player is jumping (once!) unsigned crouch : 1; // player is crouching unsigned shoot : 1; // normal attack unsigned shoot2 : 1; // alternate attack unsigned lookUp : 1; // > glance or aim up/down unsigned lookDown : 1; // > if glancing then lookCenter is set }; }; union KEYFLAGS { short word; struct { unsigned action : 1; // open or activate unsigned jab : 1; // quick attack unsigned prevItem : 1; // next inventory item unsigned nextItem : 1; // prev inventory item unsigned useItem : 1; // use inventory item unsigned prevWeapon : 1; // prev useable weapon unsigned nextWeapon : 1; // next useable weapon unsigned holsterWeapon : 1; // holster current weapon unsigned lookCenter : 1; // used for lookUp/lookDown only unsigned lookLeft : 1; // > glance or aim up/down unsigned lookRight : 1; // > if glancing then lookCenter is set unsigned spin180 : 1; // spin 180 degrees unsigned pause : 1; // pause the game unsigned quit : 1; // quit the game unsigned restart : 1; // restart the level }; }; union USEFLAGS { char byte; struct { unsigned useBeastVision : 1; unsigned useCrystalBall : 1; unsigned useJumpBoots : 1; unsigned useMedKit : 1; }; }; union SYNCFLAGS { char byte; struct { unsigned buttonChange : 1; unsigned keyChange : 1; unsigned useChange : 1; unsigned weaponChange : 1; unsigned mlookChange : 1; unsigned run : 1; // player is running }; }; struct INPUT { SYNCFLAGS syncFlags; // always sent: indicates optional fields schar forward; // always sent sshort turn; // always sent schar strafe; // always sent // optional fields BUTTONFLAGS buttonFlags; KEYFLAGS keyFlags; USEFLAGS useFlags; uchar newWeapon; // sent as 0 every frame unless changed schar mlook; }; The MAP files: We started to study this complicated format to do a Blood to BUILD map converter, and we stopped working on it as soon as we got what we want: a converter that works. In other words, we don't know the Blood MAP format well, we just know enough of it. Our converter, BLUD2B, is more a series of hacks than a real tool. It's full of arbitrary constants and little tricks to do the job. For example, for a long period of time, it didn't know how to compute the decryption keys a map uses, but we had found a way to guess them! It was easily doable thanks to the simplicity of the encryption method (XOR based, with a 1-byte incrementing constant) and the fact that BUILD map data are mostly zeros. The current version of BLUD2B knows how to compute those decrypting keys though, so this hack is no longer needed. If you're interested in this format, take a look at BLUD2B source code and the following email by Matt Saettler. None of them contain "The Complete Truth" about the MAP format, but they should help you to figure it out if you need to. Typical header with signature. Header has version. Version 6.03 is unencrypted. Version 7.0 is encrypted (same xor encryption algorithm used in RFF file format). After header comes (possible encrypted) Information structure. This contains global information like map revision count, 'start' x,y,z, number of walls, sectors, etc. This is the same for 6.03 and 7.0 CryptKey: 0x7474614d Version 7.0 then has extra information. Info includes copyright. Not sure what else. CryptKey: numwalls Next comes skyofsetts (for moving skys) CryptKey: buffer size The Build info and the 'Extra' information. The Extra info is where the blood-specific information is stored. This info is kept in an array by type. The 'extra' member of the base build structure is the array offset into the extra array. If zero, then there is no extra information. see mapedit for access to what the info is; mapedit allows editing of all this structure). all valid sectors Sector CryptKey: map Rev * sizeof(SECTOR) (I was sneaky, using maprev.. So it changes each time you save it....) If extra: Xsector CryptKey: Unencrypted All valid walls wall CryptKey: map Rev * sizeof(SECTOR) | 0x7474614d if extra: xwall CryptKey: Unencrypted all valid sprites sprite CryptKey: map Rev * sizeof(SPRITE) | 0x7474614d if extra: xsprite CryptKey: UnEncrypted Last is a CRC of the entire file (to detect modifications) If you are converting to basic Build files, you can just read and ignore the 'extra' information. The RFF files: The following mail from Matt Saettler is a good summary of what we know about RFF files. The file format is a basic multi-file container. As such, it has a header for version #, etc, a list of files in a 'directory' and the actual file data. For the initial shareware release, the file data was just copied into the RFF file. After we noticed that there were readily available hacking programs available to extract file by type (by recognizing the signature bytes for that file format (for example, WAV files), I decided to encrypt the start of each file to prevent this from happening. Also, the dictionary is encrypted. There were two versions of BARF compiled from the same source. one for external release and one for internal only release. The internal release allowed the creation of encrypted files and marked the RFF as 'Monolith approved'. I believe that when a 'non-approved' map file was run, the monolith logo showed in the top right of the screen. The internal release also allows full extraction of all files. The external version only extracts files that we thought were likely to be modified by MOD makers. The first thing in the file is the header block. It consists of a signature block, version #, # of files and offset to the first 'directory' structure. There might be some other stuff in there. It is never encrypted. The directory block is an array of structures. I don't believe that sub-directories were allowed. The structure contains the information about each file. Info will be: Name, extension, flags, fileoffset, filesize, time (for update). There might be a few other things in the structure. Encryption. The older RFF file format did not use encryption. I believe that this was only in the shareware, but I'm not sure. It might have actually been used in the shipping Blood. Later version (and certainly all patches) used the encryption. The encryption is a simple XOR of each byte with a moving value starting at a given starting value. The starting value was variable based on file offset (I think). Getting this starting value will be the tough part. To reverse engineer the starting 'key', create a simple RFF file with a single file named AAAAAA.AAA. This sequence should be easy to find since there will be an increasing sequence of bytes in the file. You should be able to figure out the starting XOR from what the sequence is at. The first 256 (or maybe 255) bytes of files were alsoFirst, we have never found any clue of a compression scheme in any RFF file, so Matt's reference to compression was certainly a typo, hence the correction in the text. Most files are indeed partially encrypted, except in the RFF 2.0 format (the version of RFF format used in shareware Blood). A flag in the file properties controls whether or not a particular file is encrypted in later RFF versions. When it is the case, only the 256 first bytes are encrypted, using the position in the embedded file as the encryption key, as Matt explained. The directory block is also encrypted, using the directory offset in the RFF file. Depending on the version of RFF, the key is either the offset itself (for RFF version 3.0, used on the Blood original CD), or "offset x 2" (for RFF version 3.1, used by all patched versions of Blood). If you're a developer and are interested in having the exact structures of the RFF format, take a look at the source code of our RFF utility. The code is well commented and although some parts of the RFF format are still obscure to us, we know it enough to be able to extract any file from any RFF package. The SFX and RAW files: In Blood, each sound is stored in 2 files: a SFX file, containing the sound properties (such as volume and format), and a RAW file that contains the actual sound data. For an unknown reason, Blood's BARF utility dumps the SFX file format when you use the "-r" option ("Extract Script file"). Here is the contents of the file it dumps: // Resource script file generated by BARF script extractor // Copyright 1997, Monolith Productions. All Rights Reserved // SFX data format // int relVol; volume, 0-255 // int pitch; pitch change (fixed point) // int pitchrange; range of random pitch (fixed point) // int format; format of audio 1=11025 5=22050 // int loopStart; loop position (-1 means no looping) // char rawName[9]; name of RAW resource // end of generated fileNote that "rawName" is 0-terminated and that if it is shorter than 8 bytes, the file will actually end right after it finished. It means a valid SFX file is always between 22 and 29 bytes long. Although "format" is always 1 or 5 in Blood, Matt Saettler gave us the list of all possible formats. Here it is, copied from the course code of our Sfx2Wav utility: typedef enum { SND_FMT_DEFAULT, // 0 SND_FMT_1M08, // 1 SND_FMT_1S08, // 2 SND_FMT_1M16, // 3 SND_FMT_1S16, // 4 SND_FMT_2M08, // 5 SND_FMT_2S08, // 6 SND_FMT_2M16, // 7 SND_FMT_2S16, // 8 SND_FMT_4M08, // 9 SND_FMT_4S08, // 10 SND_FMT_4M16, // 11 SND_FMT_4S16 // 12 } SoundFormat_t;As you can see, Blood sounds are all 8 bit mono sounds, either at 11025Hz (SND_FMT_1M08) or 22050Hz (SND_FMT_2M08) |