Repository navigation
Game tables file formats
The three file formats the server reads at start-up, as its own readers read them: game tables (.tbl), text tables (.bin), and the map files NexusForever.MapGenerator writes (.nfmap). All integers are little-endian. How the server uses the tables is on Game tables.
96 bytes. Every offset after it counts from the end of the header.
| Offset | Field | Type | Read as |
|---|---|---|---|
| 0 | Signature |
u32 | Must be 0x4454424C, DTBL
|
| 4 | Version |
u32 | Not checked |
| 8 | NameLength |
u64 | Unused |
| 16 | Unknown1 |
u64 | Unused |
| 24 | RecordSize |
u64 | Bytes per row |
| 32 | FieldCount |
u64 | Number of column descriptors |
| 40 | FieldOffset |
u64 | Where the column descriptors start |
| 48 | RecordCount |
u64 | Number of rows |
| 56 | TotalRecordSize |
u64 | Rows plus the string table, in bytes |
| 64 | RecordOffset |
u64 | Where the first row starts |
| 72 | MaxId |
u64 | Size of the id lookup the reader builds |
| 80 | LookupOffset |
u64 | Unused; the reader builds its own lookup |
| 88 | Unknown2 |
u64 | Unused |
24 bytes each, FieldCount of them.
| Offset | Field | Type | Read as |
|---|---|---|---|
| 0 | NameLength |
u64 | Unused |
| 8 | NameOffset |
u64 | Unused: the reader never reads column names |
| 16 | Type |
u16 | The column's data type, below |
| 18 | Unknown2 |
u16 | Unused |
| 20 | Unknown3 |
u32 | Unused |
| Value | Name | Bytes in the row | Row model field |
|---|---|---|---|
| 3 | UInt |
4 |
uint, or any enum |
| 4 | Single |
4 | float |
| 11 | Boolean |
4 |
bool, true when non-zero |
| 20 | ULong |
8 | ulong |
| 130 | String |
8 |
string, see below |
- Row
istarts atRecordOffset + i * RecordSize, and each row is read from its own start, so a bad row can't shift the next one. - The first column is the row's id.
- The string table starts right after the last row. A string column holds two u32 offsets; the string is at the larger one, less the size of all the rows, read as null-terminated UTF-16.
- After a string column whose first offset is 0, the reader skips 4 more bytes unless the next field is also a string.
| Condition | Result |
|---|---|
| File shorter than the header, or a wrong signature | InvalidDataException |
| Debug: field count differs from column count |
GameTableException, "GameTable model has an invalid field count" |
| Debug: a field's type differs from its column's |
GameTableException, "Invalid GameTable model field type" |
| Release: either of the above | No check. Values are read into the wrong fields |
An id of MaxId or more |
IndexOutOfRangeException |
96 bytes.
| Offset | Field | Type | Read as |
|---|---|---|---|
| 0 | Signature |
u32 | Must be 0x4C544558, LTEX
|
| 4 | Version |
u32 | Not checked |
| 8 | Language |
i32 | 1 English, 2 German, 3 French, 5 Chinese |
| 12 | Unknown1 |
u32 | Unused |
| 16 |
TagNameLength, TagNameOffset
|
u64, u64 | Unused |
| 32 |
ShortNameLength, ShortNameOffset
|
u64, u64 | Unused |
| 48 |
LongNameLength, LongNameOffset
|
u64, u64 | Unused |
| 64 | RecordCount |
u64 | Number of strings |
| 72 | RecordOffset |
u64 | Where the records start |
| 80 | StringTableLength |
u64 | Length of the string table, in UTF-16 characters |
| 88 | StringTableOffset |
u64 | Where the string table starts |
Each record is a u32 id and a u32 offset into the string table, counted in UTF-16 characters. The reader sizes its lookup from the last record's id, so it expects records in id order.
| File | Language | Required |
|---|---|---|
en-US.bin |
English | Yes |
de-DE.bin |
German | No; a warning when missing |
fr-FR.bin |
French | No; a warning when missing |
One .nfmap per world, named after the world's asset folder.
| Part | Fields |
|---|---|
| Header | u32 magic 0x504D464E, NFMP; u32 version, which must be 4; u32 client build, which must be 16042 |
| Asset | The world's asset path, as a length-prefixed string |
| Grids | u32 count, then each grid |
| Grid | u32 X, u32 Y, u32 cell count, then each cell |
| Cell | u32 X, u32 Y, u32 flags, then a block for each flag set, in bit order |
The file must end exactly after the last grid.
| Flag | Name | Block |
|---|---|---|
0x01 |
Zone |
4 u32 world zone ids |
0x02 |
Height |
17 × 17 half-precision heights |
0x10 |
ZoneBound |
64 × 64 bytes of zone and aura flags |
0x04 (Aura) and 0x08 (Liquid) are declared but have no block, and the reader throws on either.
| Constant | Value |
|---|---|
| Grids per axis | 128, with grid 64 at world position 0 |
| Grid size | 512 world units |
| Cell size | 32 world units, so 16 cells per grid axis |
| Piece | Path |
|---|---|
| Table header and descriptors |
Source/NexusForever.GameTable/GameTableHeader.cs, GameTableField.cs
|
| Data types | Source/NexusForever.GameTable/DataType.cs |
| Table reader and layout check | Source/NexusForever.GameTable/GameTable.cs |
| Text table reader |
Source/NexusForever.GameTable/TextTable.cs, TextTableHeader.cs
|
| Map file reader |
Source/NexusForever.IO/Map/MapFile.cs, MapFileGrid.cs, MapFileCell.cs
|
| Map constants | Source/NexusForever.IO/Map/MapDefines.cs |
| Map file writer | Source/NexusForever.MapGenerator/ |
Guides
- Running it locally
- Using the web console
- Adding a player feature
- Verifying a feature
- Taking a change upstream
- Syncing with upstream
Explanation
- Server architecture
- Login handshake
- Game tables
- Branches and workflow
- Upstream branches
- Contributing
- Galactic Archive
- Account entitlements
Reference
- Processes and projects
- File formats
- Databases
- Web console
- Galactic Archive messages and storage
- Code style
- Code patterns
- Pull requests
Design
About this wiki