EPB Empyrion Blueprint - ApanLoon/EmpyrionStuff GitHub Wiki
The Empyrion Blueprint format is used to save blueprints of models in the game.
The files of this format comprise two parts, one for quick and immediate access and one zipped part that defies detais suck as blocks, colours, textures and signal logic.
The structure is somewhat close to this:
EPB
{
UInt32 identifier; // = 0x78945245
UInt32 version;
UInt8 bluePrintType; //0 = Voxel, 2 = Base, 4 = SmallVessel, 8 = CapitalVessel, 16 = HoverVessel
UInt32 width;
UInt32 height;
UInt32 depth;
UInt16 unknown01;
UInt16 nMetaTags;
EPBMetaTag[] metaTags;
UInt16 unknown02;
UInt32 lightCount;
UInt32 doorCount;
UInt32 deviceCount;
UInt32 unknownCount02;
UInt32 solidsCount;
#if version >= 13
UInt32 unknownCount03;
#endif
#if version >= 18
UInt32 triangleCount;
#endif
UInt16 nBlockCounts;
EPBBlockCount[nBlockCount] blockCounts;
#if version > 8
UInt8 deviceGroupVersion;
UInt16 nDeviceGroups;
EPBDeviceGroup[nDeviceGroups] deviceGroups;
#endif
#if version >= 23
UInt32 dataLength;
UInt16 dataFlags; //Zipped = 0x0100
UInt8[dataLength] data; // If dataFlags.Zipped is set, the data is zipped
#else
UInt8[rest] zippedData; // PKZipped block, In versions < 22, replace the two zero bytes before 0x03, 0x04, ... with 'PK' (0x50, 0x4b) before unzipping
#endif
#if version >= 23
UInt32 matricesLength; // Number of bytes for data matrices following the next unknown.
UInt16 matrixUnknown01;
EPBTypedMatrix[] matrices;
#endif
#if buildVersion < 2197
UInt8[rest] unknown; // Probably erroneous stuff caused by a bug. Some data is repeated from the data block above.
#endif
}
EPBString
{
UInt8[] len; // As long as top bit is set, interpret the next byte as part of the length indicator - shift and add.
UInt8[] utf8Characters; // len number of bytes worth of UTF8 character data
}
EPBBlockCount
{
#if version < 13
UInt32 blockType;
#else
UInt16 blockType;
#endif
UInt32 count; // Total number of blocks of this type in the blueprint
}
EPBDeviceGroup
{
EPBString name;
#if deviceGroupVersion >= 5
UInt8 deviceGroupUnknown03;
#endif
UInt8 deviceGroupUnknown01;
#if deviceGroupVersion >= 4
UInt8 shortcut; // Index of the custom switch in the main control panel or 0xff for "none"
#endif
UInt16 nDevices;
EPBDeviceGroupEntry[nDevices] entries;
}
EPBDeviceGroupEntry
{
#if version >= 13
EPBBlockPos pos;
#else
UInt32 x;
UInt32 y;
UInt32 z;
#endif
EPBString name;
}
EPBBlockPos
{
UInt32 u1 : 4, // uuuu---- -------- -------- --------
x : 8, // ----xxxx xxxx---- -------- --------
y : 8, // -------- ----yyyy yyyy---- --------
u2 : 4, // -------- -------- ----uuuu --------
z : 8; // -------- -------- -------- zzzzzzzz
}
EPBTypedMatrix
{
UInt16 id; // Identifier of the matrix. Seen values: 0=Filler, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
EPBMatrix<bool> matrix; // So far I have only seen matrices without additional data here
}
To see the details of the model, the zippedData block must be unzipped. In version < 22, the first two zero bytes must be replaced with 'PK' (0x50, 0x4b) before running the PK unzip algorithm. The resulting structure is close to something like this:
EPBBlocks
{
#if version <= 4
EPBlock[depth, height, width] blocks;
#else
EPBMatrix<EPBBlock> blocks;
#endif
#if version > 10
EPBMatrix<EPBDamageState> damageStateMatrix;
#endif
UInt8 nUnknown02; // If 0, replace with width * height * depth
UInt8[nUnknown02] unknown02;
#if version >= 8
EPBMatrix<EPBColour> colours;
#elseif version > 4
EPBRawMatrix<UInt8> colours; //TODO: Check the format of this
#endif
#if version >= 8
EPBMatrix<EPBTexture> textures;
#elseif version > 4
EPBRawMatrix<UInt8> textures; //TODO: Check the format of this
#endif
#if version >= 20
EPBMatrix<EPBTextureFlip> textureFlips;
#endif
#if version >= 8
EPBMatrix<EPBSymbol> symbols;
#endif
#if version >= 8
EPBMatrix<EPBSymbolRotation> symbolRotations;
#endif
#if version > 10
UInt16 nBlockTags;
EPBBlockPosTag[nBlockTags] blockTags; // Specifies additional information per block using tags.
#endif
#if version > 10
UInt16 nLockCodes;
EPBLockCode[nLockCodes] lockCodes;
#endif
#if version > 13
UInt16 nSignalSources;
EPBSignalSource[nSignalSources] signalSources;
#endif
#if version > 13
UInt16 nSignalTargetMappings;
EPBSignalTargetMapping[nSignalTargets] signalTargetMappings;
#endif
#if version > 16
UInt16 nSignalOperators;
EPBSignalOperator[nSignalOperators] signalOperators;
#endif
#if version > 14
UInt16 nCustomNames; // Number of names assigned to the "Custom" switches in the main control panel
EPBString[nCustomNames] customNames;
#endif
#if version > 18
UInt16 nUnknown08;
EPBUnknown08[nUnknown08] unknown08;
#endif
#if version > 20
UInt8 nCustomPalettes;
EPBPalette[nCustomPalettes] customPalettes;
#endif
}
EPBRawMatrix<T>
{
UInt32 matrixSize; // width * height * depth
UInt8[matrixSize * sizeof(T)] matrix;
}
EPBMatrix<T>
{
UInt32 matrixSize; // width * height * depth / 8
UInt8[matrixSize] matrix; //One bit per possible position in the voxel space, if true the data for this position follows
T[x] data; // x = the total number of bits set to 1 in the matrix
}
EPBMatrix<EPBBlock>
{
UInt32 matrixSize;
UInt8[matrixSize] matrix;
EPBBlock[x] blocks;
}
EPBMatrix<bool>
{
UInt32 matrixSize;
UInt8[matrixSize] matrix;
}
EPBBlock
{
UInt32 data; // Bit mask: xxvvvvvu uuuuuuuu rrrrrbbb bbbbbbbb x and u = unknown, v = variant, r = rotation code, b = block type (This is not entirely correct)
}
EPBMatrix<EPBDamageState>
{
UInt32 matrixSize;
UInt8[matrixSize] matrix;
EPBDamageState[x] damageState;
}
EPBDamageState
{
UInt16 damage; // Number of hit points removed from the "fully healed state" of the corresponding block type
}
EPBMatrix<EPBColour>
{
UInt32 matrixSize;
UInt8[matrixSize] matrix;
EPBColour[x] colours;
}
EPBColour
{
UInt32 data; // Five bit colour indices for six sides, padded with zero
}
EPBMatrix<EPBTexture>
{
UInt32 matrixSize;
UInt8[matrixSize] matrix;
EPBTexture[x] textures;
}
EPBTexture
{
UInt64 data; // Six bit texture indices for six sides, padded with zero
}
EPBMatrix<EPBTextureFlip>
{
UInt32 matrixSize;
UInt8[matrixSize] matrix;
EPBTextureFlip[x] textureFlips;
}
EPBTextureFlip
{
UInt8 data; // One bit for six sides, padded with zero. If 1, the texture is flipped.
}
EPBMatrix<EPBSymbol>
{
UInt32 matrixSize;
UInt8[matrixSize] matrix;
EPBSymbol[x] symbols;
}
EPBSymbol
{
UInt32 data; // Five bit symbol indices for six sides and a two bit symbol page index
}
EPBMatrix<EPBSymbolRotation>
{
UInt32 matrixSize;
UInt8[matrixSize] matrix;
EPBSymbolRotation[x] symbolRotations;
}
EPBSymbolRotation
{
#if version >= 20
UInt32 data; // Two bit symbol rotation codes for six sides, padded with zero
#elseif version >= 8
UInt32 data; // Five bit symbol rotation codes for six sides, padded with zero
#endif
}
EPBBlockPosTag
{
EPBBlockPos pos;
UInt8 unknown06;
UInt16 nTags;
EPBBlockTag[nTags] tags;
}
EPBLockCode
{
EPBBlockPos pos;
UInt16 code;
}
EPBSignalSource
{
#if version > 14
UInt8 signalSourceUnknown01;
UInt16 nTags;
EPBBlockTag[nTags] tags;
#elseif version > 13
EPBBlockPos pos;
EPBString name;
#endif
}
EPBSignalTargetMapping
{
EPBString signal;
UInt16 nTargets;
EPBSignalTarget[nTargets] targets;
}
EPBSignalTarget
{
UInt8 targetUnknown01;
UInt16 nTags;
EPBBlockTag[nTags] tags;
}
EPBSignalOperator
{
UInt8 signalOperatorUnknown01;
UInt16 nTags;
EPBBlockTag[nTags] tags;
}
EPBUnknown08
{
UInt8[8] unknown;
}
EPBPalette
{
UInt32 nColours;
EPBColourRGB[nColours] colours;
}
EPBColourRGB
{
UInt8 red;
UInt8 green;
UInt8 blue;
}