Package File Format
The Unreal Engine uses a single file format to store all its game-content. You may have seen many different filetypes, like .utx (textures), .unr (maps), .umx (sound) and .u (code), but from a technical standpoint there is no difference between those files; the different file endings are only used to help organize the packages in the directory structure. The following article will describe the basic structure of his fileformat. It omits many details (such as tons of constants, for example), but there’s a good reference available on the net by Antonio Cordero Balcazar (see links).
Assumptions:
This is a rather technical article. It requires you to have a basic understanding of object oriented programming as well as the will to use an hex-editor, if needed. This is NOT intended to be a full documention of the fileformat, but only a brief introduction.
The Structure of the File
Overview
Every package file can be roughly split into three logical parts. The header, the three index tables (name-table, import-table and export-table) and the data itself. But only the header has a fixed position (at offset 0), all other parts can be found anywhere within the file without irritating the engine.
Most of the time, although, the layout looks like the following:
- Header
- Name-Table
- Import-Table
- Data
- Export-Table
It may be useful to read a bit about the concept of serialisation, which allows you to (rather) easily store the state of objects within a file. A brief introduction can be found on the Wiki: [Package File Format/Serialisation]?
Header
This global header can be found at the beginning of the file (offset 0). It is the starting point for every operation.
Type | Property | Description |
DWORD | Signature | Always: “0x9E2A83C1”; use this to verify that you indeed try to read an Unreal-Package |
DWORD | Version | Version of the file-format; Unreal1 uses mostly 61-63, UT 67-69; see the appendix for more details |
DWORD | Package Flags | Global package flags, i.e. if a package may be downloaded from a game server etc; described in the appendix |
DWORD | Name Count | No. Of entries in name-table |
DWORD | Name Offset | Offset of name-table within the file |
DWORD | Export Count | No. Of entries in export-table |
DWORD | Export Offset | Offset of export-table within the file |
DWORD | Import Count | No. Of entries in import-table |
DWORD | Import Offset | Offset of import-table within the file |
After the ImportOffset, the header differs between the versions. The only interesting fact, though, is that for fileformat versions => 68, a GUID has been introduced. It can be found right after the ImportOffset: | ||
16 BYTE | GUID | Unique identifier; used for package downloading from servers |
Index Tables
The Unreal-Engine introduces two new variable-types. The first one is a rather simple string type, called NAME from now on. The second one is a bit more tricky, these CompactIndices, or INDEX later on, compresses ordinary DWORDs downto one to five BYTEs. Both types, as well as the ObjectReference, are described in the following paper: Package File Format/Data Details
Name-Table
The first and most simple one of the three tables is the name-table. The name-table can be considered an index of all unique names used for objects and references within the file. Later on, you’ll often find indexes into this table instead of a string containing the object-name.
Type | Property | Description |
NAME | Object Name | |
DWORD | Object Flags | Flags for the object; described in the appendix |
Export-Table
The export-table is an index for all objects within the package. Every object in the body of the file has a corresponding entry in this table, with information like offset within the file etc.
Type | Property | Description |
INDEX | Class | Class of the object, i.e. ‘Texture’ or ‘Palette’ etc; stored as a ObjectReference |
INDEX | Super | Object Parent; again a ObjectReference |
DWORD | Group | Internal package/group of the object, i.e. ‘Floor’ for floor-textures; ObjectReference |
INDEX | Object Name | The name of the object; an index into the name-table |
DWORD | Object Flags | Flags for the object; described in the appendix |
INDEX | Serial Size | Total size of the object |
INDEX | Serial Offset | Offset of the object; this field only exists if the SerialSize is larger 0 |
Import-Table
The third table holds references to objects in external packages. For example, a texture might have a DetailTexture (which makes for the nice structure if have a very close look at a texture). Now, these DetailTextures are all stored in a single package (as they are used by many different textures in different package files). The property of the texture object only needs to store an index into the import-table then as the entry in the import-table already points to the DetailTexture in the other package.
Type | Property | Description |
INDEX | Class Package | Package file in which the class of the object is defined; an index into the name-table |
INDEX | Class Name | Class of the object, i.e. ‘Texture’ or ‘Palette’ etc; an index into the name-table |
DWORD | Package | Package file where the referenced object resides in (filename without ending) |
INDEX | Object Name | The name of the object; an index into the name-table |
Body/Object
Each object consists of a list of properties at the beginning and the actual object itself.
Object Properties
When jumping to the offset of an object, you'll first be confronted with the object properties before the actual object starts. The format is rather straightforward. The first byte is an INDEX-type reference into the Name-Table, giving you the property's name. The second byte does the magic of telling you what kind of data follows; for example 0x02 flags a DWORD sized integer type. Then comes the actual property-data. The procedure repeats itself until the reference into the Name-Table returns 'None' as the name.
That said, there are some bit-tricks to deal with arrays, booleans and such. For more info on these, as well as a full list of info-bytes, read Antonio's package docs.
Sample Objects (Texture Class)
After the properties are finished the object starts. It basically consists of a predefined set of properties. As an example, the texture class (for good old UT) will be explained below. The texture class is a native one, which means that it doesn't have a generic header in addition to its own data. The layout looks like this:
Type | Property | Description |
BYTE | MipMapCount | Count of MipMaps in object |
The next set of variables repeats itself for each MipMap.
Type | Property | Description |
DWORD | WidthOffset | Offset in file; should be the same as SerialOffset in the Export-Table. Only if PkgVer >= 63 |
INDEX | MipMapSize | Size of the image data (in bytes) |
n BYTEs | MipMapData | Image data; one byte per pixel; n = MipMapSize |
DWORD | Width | Texture-width |
DWORD | Height | Texture-height |
BYTE | BitsWidth | Number of bits of Width (e.g. 10 for 1024 pixels) |
BYTE | BitsHeight | Number of bits of Height (e.g. 10 for 1024 pixels) |
Appendix
A. Links
- http://www.acordero.org/: _The_ ressource regarding package files. A very detailed reference of the package format, the UT-Package-Tool and a Delphi-unit can be found there.
- ftp://tuubi51.adsl.netsonic.fi/docs/programming/UTCMS_source.zip: A C++ class for reading packages. Totally free for use.
B. Notes
The last part about the object properties and the texture class was written in a hurry. I'm sorry it took so long for me to finish that piece.
The fileformat itself, btw, has not changed between the versions of UT (except the odd new property and such). Many of the objects however have changed a lot or were replaced by enhanced types (such as my beloved texture class...).
Comments/Discussion
Jesco: I will continue after here tomorrow. Now it's time for some sleep
Mychaeel: Good start. Have a look at UMOD/File Format too if you haven't already. A common thing like the compact index format could move to a shared page, for instance.
Jesco: Ah, I haven't noticed that, yet. Saves me the hassle to explain the compact index Where should the page for the compact index be put to? I suggest making it either a subpage of UMOD/File Format or Package File Format.
Mychaeel: Putting it on a subpage of Package File Format sounds more obvious to me.
Tarquin: Other pages to grab material from / link to / etc:
- Package
- Package redirects to the above.
- UT Package Tool (just a link to a site)
Jesco: Ok, I'll work on it later today when I come back from university. Maybe I should also mail Antonio and ask im if I could post a copy of his reference docs for all those thousands of different objects that I don't have a clue of
Jesco: I haven't forgot about this article, it just went down my priority list, unfortunately.