Skip to content

Instantly share code, notes, and snippets.

@Loupau38
Last active March 4, 2026 20:44
Show Gist options
  • Select an option

  • Save Loupau38/08798aa54c4e666f26dc7069f2d24fa9 to your computer and use it in GitHub Desktop.

Select an option

Save Loupau38/08798aa54c4e666f26dc7069f2d24fa9 to your computer and use it in GitHub Desktop.

Shapez 2 Savegames File Format

NOT from the devs
aka Loupau's understanding of savegame files

Last updated : 1.0.0-alpha4-rc1

Stage 1 : File Location

In the 'Play' menu, click the 'Show Folder' button. The folder that opens contains all of your savegames.

image

Locate the UID at the top of your savegame in the ingame list.

image

In the folder that opened previously, open the folder whose name is that UID. This contains all backups of your savegame.

Stage 2 : File format

A savegame backup is a file whose name has the format backup-v{backup_number}-{timestamp}.spz2. Note that this file name format is only required when the file is in the savegame's folder, the file can have any name when you use the 'Import' button in the 'Play' menu. .spz2 files are zip archives, so to open one, you can open it like you would open a .zip file.

Stage 3 : Contained Files Format

The archive contains multiple files and folders. The files are either .json or .bin.

Common to all .bin files

The files are padded with null bytes to have a file size which is a power of two. This padding can be ignored and is also not required for the game to load the save.

Due to a language like C# being used, when an object is said to have a specific type, it can be either that specific type or null. When the game allows that object to be null, the encoding format will reflect that by having special cases for null objects. If the format doesn't specify how an object should be encoded if it's null, then that object shouldn't be able to be null in normal circumstances.

When a type's name begins with I, it means the type is a C# interface. An interface doesn't fully represent a data type, but instead is more like a blueprint for other types to inherit from and build upon. This means that when an object's type is an interface, in reality the object will have a type that inherits from that interface. As for the serialization of interfaces, two cases exist:

  • either the interface doesn't provide special serialization code, and the actual object's type's serialization code will be called directly
  • or the interface does provide serialization code, in that case it will be called, then that code will decide if it calls the actual type's code or not.

The names of data types in this documentation use the same names as the class names in the game's code, except when name changes or simplifications of the data structures help understandability.

The custom C# objects that make up the contents of a savegame are broken down into basic types to be serialized into the .bin files. The format of these basic types is described below.

Byte

A single byte is simply written as is. It can be used to represent an integer between 0 and 255 or a single ASCII character.

Integers

All integers are encoded as little endian.

Type Encoded on
(u)short 2 bytes
(u)int 4 bytes
(u)long 8 bytes

Bool

Booleans are encoded on a single byte, 0 for false and 1 for true.

String

Strings are encoded using a lookup table. What actually gets written is the string's index in the table as an int. However, if the string is null, it isn't added to the table and instead an index of -2^31 is written. The lookup table is then written to strings.bin.
Exception : if you ended up here from the blueprint codes specifications, since blueprints don't have a lookup table, the string is directly written in the data :

Type Description
short The string's length, or -1 if it's null
bytes The string encoded in UTF-8

Checkpoint

Checkpoints are markers along the data stream that ensure a reader is still reading the correct data to avoid creating dummy data if a format mismatch happens.
They are only used if enabled for the savegame, with that info being found in savegame.json. If they aren't enabled, nothing is written when a format specifies using a checkpoint.
They are initially defined with a string ID, that is then hashed using the below algorithm, with s the checkpoint ID :

uint hash = 523423;
for (int i = 0; i < s.Length; i++)
{
    hash += s[i];
    hash += hash << 10;
    hash ^= hash >> 6;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;

That algorithm produces a uint that is then written to represent the checkpoint.
The checkpoints currently used by the game and their hash can be found below for convenience.

ID hash (uint) hash (bytes)
blob:start 3295808852 54 0D 72 C4
blob:end 2225352737 21 30 A4 84
island 2971730586 9A 02 21 B1
buildings 2756275580 7C 6D 49 A4
building 899714533 E5 8D A0 35

Blob<Elem>

Blobs are used to wrap pieces of data. Since they store the length of their content, a reader can easily skip a blob if needed, in case of outdated data for example.

Type Description
Checkpoint blob:start
int The content's length in bytes
Elem The blob's content
Checkpoint blob:end

Array<Elem>

Arrays don't have special formatting, but they are referenced here for completeness.

Type Description
Elem Array element 0
Elem Array element 1
... ...
Elem Array element n

savegame.json

todo

research.json

todo

local-player.json

todo

strings.bin

The string lookup table for the savegame.

Type Description
int The number of entries in the table
Array<StringEntry> The strings in the table

StringEntry

Type Description
int The length of the string in bytes
bytes The string encoded in UTF-8

statistics.bin

todo

maps/main/simulation/state.bin

todo

maps/main/islands/[#].bin

The files in this folder encode the type, position and configuration of buildings and islands. Each file is an 'island bundle', i.e. a group of islands, with the maximum number of islands per bundle when generated by the game being determined by the formula ceil(4^log10(island_count)). When the game loads a save however, there is no restrictions to how many islands can be in each bundle nor in which order the islands are inside a bundle nor the order of bundles themselves.

Each file has the following format :

Type Description
int The number of islands in the bundle
Array<PlacedIsland> The islands inside the bundle

PlacedIsland

Type Description
Checkpoint island
GlobalChunkCoordinate The island's position
string The island's ID
Rotation The island's rotation
Blob<PlacedIslandData> The island's configuration and placed buildings

PlacedIslandData

Type Description
bool Whether the island has configuration data
Blob<IIslandConfiguration> The island's configuration data, only there if the previous value was true
Blob<BuildingsData> The buildings placed on the island

IIslandConfiguration

Represents an island configuration object, the type of which should be deduced from the previously decoded island ID. Can be RailConfig or TrainUnloaderConfig.

RailConfig

Applies to all rail types (regular, splitter, merger).

Type Description
int The number of connection color filters encoded
Array<int> The color filter for each connection of the rail (a connection being one of the possible input -> output paths), stored as a bit mask, where each color is 1 << colorIndex, with the colorIndex being determined by the RailColorsConfig key of the current scenario

TrainUnloaderConfig

Applies to shape and fluid train unloaders and transfer stations.

Type Description
int The lanes disabled for unloading, stored as a bit mask, where each lane is 1 << layerIndex

BuildingsData

Type Description
Checkpoint buildings
int The number of buildings placed on the island
Array<PlacedBuilding> The buildings placed on the island

PlacedBuilding

Type Description
Checkpoint building
IslandTileCoordinate The building's position
Rotation The building's rotation
string The building's ID
bool Whether the building has configuration data
Blob<IBuildingConfiguration> The building's configuration data, only there if the previous value was true

IBuildingConfiguration

Represents a building configuration object, the type of which should be deduced from the previously decoded building ID. Can be LabelConfig, SignalProducerConfig, ItemProducerConfig, FluidProducerConfig, ButtonConfig, CompareGateConfig or GlobalSignalReceiverConfig.

LabelConfig

Applies to labels.

Type Description
string The label's text

SignalProducerConfig

Applies to signal producers.

Type Description
ISignal The signal produced

ItemProducerConfig

Applies to item producers.

Type Description
IBeltItem The item produced

FluidProducerConfig

Applies to fluid producers.

Type Description
IFluid The fluid produced

ButtonConfig

Applies to buttons.

Type Description
bool Whether the button is activated

CompareGateConfig

Applies to comparison gates.

Type Description
byte The gate's compare mode :
1 Equal
2 GreaterEqual
3 Greater
4 Less
5 LessEqual
6 NotEqual

GlobalSignalReceiverConfig

Applies to global signal receivers and operator signal receivers.

Type Description
SignalChannelId For operator signal receivers, this represents the ROS line selected. TODO : is this representative for global signal receivers

maps/main/buildings/[#].bin

todo

maps/main/trains.bin

todo

maps/main/resource-chunks.bin

todo

maps/main/cargo.bin

todo

Other Game Objects

Some objects are not specific to one file in the save file, their format is described below.

GlobalChunkCoordinate

Represents an island level position.

Type Description
int The X coordinate
int The Y coordinate
short The Z coordinate

Rotation

Type Description
byte 0 : East, 1 : South, 2 : West, 3 : North

IslandTileCoordinate

Represents a building level positon relative the island center (see the 'Note' in this section).

Type Description
short The X coordinate
short The Y coordinate
byte The Z coordinate

ISignal

The encoded data starts with a byte representing the type of signal :

Byte value Type of signal Data encoded after Notes
0 null none This means a null object, which produces errors if actually loaded ingame
1 Null none This means a Null Signal, supported by the game
2 Conflict none
3 Integer int
4 Integer 0 none This produces the same type of Integer Signal as with a 3 byte
5 Integer 1 none This produces the same type of Integer Signal as with a 3 byte
6 Belt Item IBeltItem Ingame, this returns a Null Signal if the IBeltItem object is null
7 Fluid IFluid Ingame, this returns a Null Signal if the IFluid object is null

IBeltItem

The encoded data starts with a byte representing the type of belt item :

Byte value Data encoded after
0 null (nothing encoded)
1 ShapeItem
2 FluidPackageItem
3 FluidPackageOnTrack
4 ShapePackageOnTrack

ShapeItem

Type Description
bool false if the object is null, true otherwise
string The shape code, only there if the previous value was true

FluidPackageItem

Type Description
IFluid The type of fluid contained
FluidUnit The amount of fluid contained

FluidPackageOnTrack

Type Description
short The amount contained
IFluid The fluid contained, only present if the amount isn't 0

ShapePackageOnTrack

Type Description
short The amount contained
ShapeItem The shape contained, only present if the amount isn't 0

IFluid

The encoded data starts with a byte representing the type of fluid :

Byte value Data encoded after
0 null (nothing encoded)
1 ColorFluid

ColorFluid

Type Description
byte The color's color code (a single character)

FluidUnit

Type Description
long The amount of fluid, divide this number by 38419920000 to get the amount in liters

SignalChannelId

Type Description
int The channel ID. The upper byte represents the type of channel and the channel value is an int bitwise-OR'ed with the channel type (unexpected behavior can happen if the channel value needs more than 3 bytes to be encoded) :
Channel Type Byte Channel Type Name Channel Value
2 ROS The goal line index
3 Shape The shape's UID, internal to the game and generated at runtime
4 Fluid The fluid's color code, single character converted to a byte then to an int
5 Positive Integer The integer itself
6 Negative Integer The integer's opposite value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment