From owdev
Revision as of 15:01, 19 June 2017 by Yukimono (talk | contribs) (Format 11)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

.0bc - level map file format

General .0BC format

The .0BC files contain varying #Formats of data. All files start with the same header:

struct Header_0bc {
	u32 countRecords;
	u32 byteSizeRecords;
	u32 offsetToSomething;
	u32 maybeDataType;


  • countRecords - count of records for formats 0x01-0x0f and 0x12. For format 0x10 - always 0. For format 0x11 it's non-zero, TODO.
  • byteSizeRecords is the size of records for formats 0x01 - 0x0f. For 0x11 and 0x12 it's always 0. For 0x10 it's non-zero, TODO.
  • offsetToSomething is usually has value 0x10. It's where data for formats 0x01 - 0x0f and 0x12 starts.

For format 0x11 it also points to the start of one of the STUD files, TODO. But for format 0x10 it seems to point somewhere in the middle of data, TODO.

  • maybeDataType is always 0. Only for format 0x10 it has 1.


Looks like every level contains 18 .0bc files, from 0001*.0bc to 0012*.0bc. This first 2 bytes of name is key identifier Key and defines datatype format inside file.

Common data types

Common data types seen inside .0BC files.

type u64 Key; // see Key definition, sizeof(Key) == sizeof(u64)

strcut Guid {
	u8 guid[16];

struct vec3 {
	f32 x, y, z;

struct quat {
	f32 x, y, z, w;

Record default header

Most of the formats are arrays of records and all records there use the same common record header:

struct CommonRecordHeader {
	Guid guid;      // guess: a guid used by editor/game to reference specific object on the level
	u16 unk;        // guess: might be some bitmask
	u16 type;       // record format type - same as in filename
	u32 recordSize; // record size in bytes (including 24 bytes of the header)

Format 01

Guess: Format 01 is probably placement of static props - models which build most of the level.

So far, CommonRecordHeader.guid is always 0.

Each Format_01 record is a reference to one .00C model file and then of one or several groups of many object positions. Each group references one .01A material file.

strcut Format_01 {
	struct Group {
		struct ObjectRecord {
			vec3 pos;
			vec3 scl;
			quat quat;
			u32 unkBitmask[7];
			i32 unkInts[5];
		Key keyRef01a;                // reference to .01A material files
		u32 groupSizeBytes;
		u32 groupRecordsCount;
		ObjectRecord records[groupRecordsCount];

	CommonRecordHeader header;
	Key keyRef00c;                    // reference to .00C model files
	u32 groupsCount;
	u32 totalGroupRecordsCount;
	u32 unkBitmask;
	// offset 56
	Group groups[groupsCount];
sizeof(Format_01) >= 56
sizeof(Format_01) >= 160             // more likely, because 160 = 56 + sizeof(Group with 1 record)

Format 02

References some models. 'detail' models and guessed particle systems (1B references). Looks like format 02 and format 08 are same.

struct Format_02_08 {
	CommonRecordHeader header;
	Key keyRef00c;                  // reference to .00C model files
	Key keyRef01a;                  // reference to .01A material files
	vec3 pos;
	vec3 scl;
	quat quat;
	u32 unk[4];
sizeof(Format_02_08) == 96

Format 03

struct Format_03 {
	CommonRecordHeader header;
	quat quat;
	vec3 pos;
	vec3 unk; // guess: always positive and seems too big to be scale, maybe bbox max
sizeof(Format_03) == 64

Format 04

Cubemap Assignment Volumes/Influence range definitons

struct Format_04 {
	CommonRecordHeader header;
	vec3 pos;
	vec3 scl;
	quat quat;
	vec3 pos2;  // guess: always identity?
	vec3 scl2;  // guess: always identity?
	quat quat2; // guess: always identity?
	vec3 unk;   // guess: always positive and seems too big to be scale, maybe bbox max
	u32 unk2;
	Key key1Ref004;          // reference to .004 texture files
	Key key2Ref004;          // reference to .004 texture files
	u32 unk3;
	u32 unk4;
	f32 unk5[7];
	i32 unk6[5];
sizeof(Format_04) == 192

Format 05

Unknown - always empty so far

Format 06

Unknown - always empty so far

Format 07

Some kind of placement of voice lines or localization closed captions, or other kind of scripts. For example on Illios, it's always on the greek signs on the buildings and shops.

struct Format_07 {
	CommonRecordHeader header;
	f32 unk0[4];
	vec3 pos;
	u32 unk1;        // guess: always 0 so far
	Key key1Ref0a9;  // reference to .0A9 files
	Key key2Ref0aa;  // reference to .0AA files
	Key key3Ref008;  // reference to .008 files
	f32 unk2;
	u32 unk3;        // guess: always 0 so far
sizeof(Format_07) == 88

Format 08

See Format 02 guessed dynamic models

Format 09

The Lights (at least point lights and spot-lights) for the maps. Cannot confirm if distant (sun) lights are in here.

struct Format_09 {
	CommonRecordHeader header;
	quat Rotation;
	vec3 Position;
	u32 unk1[2];
	u8 unk2[4];
	u32 unk3[2];
	u32 LightType;      // 1 = Spot Light, 2 = Point Light, 0 = Directional?
	f32 Color[3];
	vec3 unknownPos1;
	quat unknownQuat1;
	f32 LightFOV;       // Cone angle, in degrees. Set to -1.0 for Point Lights
	vec3 unknownPos2;
	quat unknownQuat2;
	vec3 unknownPos3;
	quat unknownQuat3;
	f32 unk4[2];
	i32 unk5[4];
sizeof(Format_09) == 200

Format 0A

Records have variable size.

struct Format_0A {
	struct Value_0A {
		quat quat;
		vec3 pos;
		vec3 unk;              // guess: always positive, scale of bboxMax

	CommonRecordHeader header;
	u32 valuesCount;
	u32 unk1;                  // guess: bitmask
	u32 unk2;                  // guess: so far always 24
	u32 valuesSize1;           // byte size of values array
	u32 valuesSize2;           // guess: so far valuesSize1 == valuesSize2
	u32 unk3;
	Value_0A values[valuesCount];
sizeof(Format_0A) >= 88

Format 0B

Record have variable size. TODO: Files have some more data after records table.

struct Format_0B {
	struct Extra_0B {
		u32 unk1;
		u32 unk2;              // guess: might be an offset into that additional data after records table

	CommonRecordHeader header;
	Key keyRef003;             // reference to .003 files
	ulong unk;		   // added in
	vec3 pos;
	vec3 scl;
	quat scl;
	u16 extraCount;            // 0 is valid, means no extraRecords
        u16 unk;
	u32 unk[11];
	Extra_0B extraRecords[extraCount];
sizeof(Format_0B) >= 120

Format 0C

struct Format_0C {
	CommonRecordHeader header;
	Key keyRef02c;            // reference to .02C files
	vec3 pos;
	vec3 scl;
	quat quat;
sizeof(Format_0C) == 72

Format 0D

Guess: lights?

struct Format_0D {
	CommonRecordHeader header;
	Key keyRef00d;           // reference to .00D files
	vec3 pos;
	vec3 scl;
	quat quat;
	u32 unk[4];              // guess: always 0?
sizeof(Format_0D) == 88

Format 0E

Guess: referneces textures - can be asumed being lightmaps cache wip or dump?

struct Format_0E {
	CommonRecordHeader header;
	vec3 pos;
	vec3 scl;
	quat quat;
	vec3 unk1;         // guess: always positive, scale or bboxMax?
	f32 unk2[7];
	Key keyRef004;     // reference to .004 texture files, but sometimes .001 - might beempty record?
	f32 unk3[6];
sizeof(Format_0D) == 136

Format 0F

strcut Format_0F {
	CommonRecordHeader header;
	vec3 pos;
	vec3 scl;
	quat quat;
	vec3 unk1;         // guess: always positive, scale or bboxMax?
	u32 unk2;          // guess: always 0 so far

Format 10

Special format, contains physical collision model.

strcut PhysHeader {
	u64 unkOffset1;
	u64 unkOffset2;
	u64 unkOffset3;
	u64 physFooterOffset;    // file offset to PhysFooter

Guess: PhysHeader is always placed at offset 0x10 right after Header_0bc.

strcut PhysFooter {
	u64 bboxesDataOffset;
	u64 verticesOffset;
	u64 indicesOffset;
	u32 countBboxes;
	u32 countVertices;
	u32 countIndices;
	u32 unk[15];          // guess: or 14, there might be just some padding bytes. Or it's W coord in offset vector.
struct PhysVertex {
	vec3 pos;
	f32 unk;            // guess: might be padding and always 0.0
struct PhysFace {
	i32 index[3];
	i32 unk1[3];         // guess: values range is like indices, but often have -1, why?
	i32 unk2[2];         // guess: might be some bitmasks for physical system flags
struct PhysBBox {
	vec3 bboxMin;
	vec3 bboxMax;
	u32 unk1;
	u32 unk2;

Guess: whole array of bboxes is likely some kind of BVH, so unk1 or unk2 are used to build the tree.

TODO: There is much more data in file, which can be accessed through file offsets from PhysHeader.

Format 11

Special format, doesn't use common record header.

 long offsetMainSTUD;
 long offsetSecondSTUD;
 long count; // ?
 long offsetUnknown;

Format 12

Special format, doesn't use common record header.

struct Format_12 {
	Guid guid;
	Key keyRef055;      // reference to .055 files

List of maps

Package Map name
06111D3552663A20EF89AC14D4C9413C hanamura
06157AEEE625F516C2DEA0DA9F35CC3A numbani
0DBE27A5224458C9D5CEAEB86AC5FA1E training map
1E6EE3845D0F77AD62EACC08C7D114FF temple of anubis
1F169CCB6D420E6593D41FE00B781491 temple of anubis (partial)
22273C55DD1631F25C91E75D4B1D0172 dorado
2BC36653610E5217E38C3F8F901746B7 lijiang tower
2F3900FD7D9FDBCFA868C07BC089FFF7 numbani (partial)
3318DE187FB17B7FFCEA1DB8E06D5A94 hanamura (partial)
4084CDDEF5349478DBE7D6077312DB58 kings row (partial, old version of the map or just broken export)
40CD173A6A46BF8A8E6AA0EE4A31B0D8 hollywood
4C4C41DF6A1B3A50FEF2D796EE5E6B15 nepal
4F7DC12FC87F8FBDE4F88B6D6101ACE7 kings row (partial)
63EA746191B0C76CF7349BFBC5B345BC route 66
86E13984AFD7CB1C854DDE8187DC1886 volskaya industries
8B79091735A20C086C54C35FA6C51BB7 illios
8EEAFB5ED61499731F3B201AC247ECB1 tutorial map
BF9CFB75477CAAC1954A4285C3285598 dorado (partial)
C0E2E8AE63C6B3095C3465DE03E16560 volskaya industries (partial)
C3793839761DA0CE173AF0E8F41566E4 hollywood (partial)
DACD064EB7520923CF07D66327143439 watchpoing gibraltar
F827F80106B011775CF247AEA158ED73 watchpoing gibraltar (partial)
FA4AA934E5E0FC5F2F857C3EDEC349FD kings row


See [[1]] for a script, which was used to research .0BC file format.