Skip to content

MapLoaderSystem compression support, new commands for saving/loading full game state - #6956

Open
Roudenn wants to merge 38 commits into
space-wizards:masterfrom
Roudenn:game-saving
Open

MapLoaderSystem compression support, new commands for saving/loading full game state#6956
Roudenn wants to merge 38 commits into
space-wizards:masterfrom
Roudenn:game-saving

Conversation

@Roudenn

@Roudenn Roudenn commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Overview

Added support for ZStd compression for files saved and loaded by MapLoaderSystem, using the new file extension: .rtsave.
Added savegame and loadgame commands that can save and load all entities to a save file, by calling an already existing method in the maploader system, and convertsavefile that converts YAML files into RTSAVE and backwards, which is useful for debugging.

Why

Fixes #2406 since now save files are very cheap memory-wise and have official support, starting from here content can eventually implement full persistence

ZStd compression can provide up to 97% file size reduction, which can be used for packaged server builds on Content, or even in the repository itself if you're crazy and don't care about readability.
Also it's useful for servers that support persistent rounds since SS14's serializers are sometimes not efficient for post map-init entities, so file compression saves a lot of disk space and makes them practically free.

Test plan

New file format support should be covered by MapLoaderTest

New commands can be easily tested in-game by just running them on a devmap

Media

Convert command works correctly in both ways, and the file is compressed correctly:

image image

Demonstration of the new commands:

2026-08-11.19-02-17.mp4

@Roudenn
Roudenn requested a review from DrSmugleaf as a code owner August 9, 2026 10:14
Comment thread Robust.Shared/GameSaves/GameSavesSystem.cs Outdated
Comment thread Robust.Shared/GameSaves/GameSavesSystem.cs Outdated

@metalgearsloth metalgearsloth left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tests please.

Also not really sure why compression isn't rolled into existing maploader instead of a bespoke system.

@Roudenn

This comment was marked as outdated.

@Roudenn Roudenn changed the title Full server snapshot/reload support (attempt 2) MapLoader compression support, new commands for saving/loading full game state Aug 11, 2026
@Roudenn Roudenn changed the title MapLoader compression support, new commands for saving/loading full game state MapLoaderSystem compression support, new commands for saving/loading full game state Aug 11, 2026

@Roudenn Roudenn left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically the full entity serialization should be incompatable with adminbus prototype loading, so I wonder if having adminbus should be controlled by a CVar that if enabled disallows full entity serialization

/// <param name="data">Mapping data node to compress into the specified path.</param>
private void WriteCompressedZstd(ResPath path, MappingDataNode data)
{
using var uncompressedStream = new MemoryStream(Encoding.UTF8.GetBytes(data.ToString()));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to do that with a IRobustSerializer, but it seems to return a prefix with an arbitrary byte length depending on how large the file is, so I've resorted to using Encoding.UTF8.GetBytes instead

Comment on lines +90 to +93
if (!uncompressedStream.TryGetBuffer(out var uncompressed))
{
uncompressed = new ArraySegment<byte>(uncompressedStream.ToArray());
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I debugged this it looks like this never fails, is this fail-safe redundant here?

Comment on lines +135 to +143
if (path.Extension == SaveExtension)
{
WriteCompressedZstd(path, data);
}
else
{
using var writer = _resourceManager.UserData.OpenWriteText(path);
WriteYaml(writer, data);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay to run compression when a special file format is specified? Maybe it should be a boolean passed as a parameter everywhere instead

@Roudenn

Roudenn commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Reworked the PR entirely to work around maploader, now uses safe methods for file reading and writing, and also included a test to confirm that the new file format works as intended

@Roudenn
Roudenn requested a review from metalgearsloth August 11, 2026 17:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Full server snapshot/reload

3 participants