Magnetar server plugin for Space Engineers dedicated servers.
GridBackups exports ship/station grid blueprints on configurable backup triggers. Standalone servers keep backups in the Quasar data folder by default.
In a cluster, the plugin automatically uses PluginStorage.GetSharedDirectory
regardless of UseQuasarConfigFolder. Each node backs up the grids it sees into
the same plugin directory. Writes use temporary files and atomic rename;
per-grid file locks coordinate daily backups and retention across nodes. Normal
backup filenames include a unique suffix to avoid collisions across Hosts.
An automatic backup is counted only after its file is written successfully;
failed writes can be retried on the next scan.
The shared filesystem must support advisory file locks and atomic rename.
Quasar sets CLUSTER_SHARED_ROOT automatically for a single Host. A cluster on
several Hosts needs one shared filesystem mounted at the same path on each;
Quasar does not provision that mount. Without the shared root, the plugin fails
to load instead of writing separate per-Host backups.
The server plugin uses Magnetar PluginSdk configuration. Quasar can render the config UI from the schema generated by GridBackupsConfig. A GridBackups.cfg that fails to load is renamed to GridBackups.cfg.corrupted.<time>.txt and replaced by the defaults.
Important options:
- Standalone storage root defaults to the Quasar data folder (
QUASAR_DATA_DIR, derived fromQUASAR_DS_CONFIG_PATH, or the platform default Quasar config directory). WithUseQuasarConfigFolderoff it is the server's data folder instead. Cluster storage uses the SDK shared root. - Minimum and maximum minutes since last backup.
- Backup before concealment via public plugin entrypoint.
- Backup when steady after a configured unchanged block-count duration.
- Backup after a configured maximum block-count change.
- Connected-grid grouping, owner folder naming, NPC/nobody grid inclusion, and retention limits.
!gridbackup list <PlayerName|SteamID|IdentityID>lists backed up grids for a player.!gridbackup list <PlayerName|SteamID|IdentityID> <GridName|GridID|ListNumber>lists backup files for one grid.!gridbackup list faction <FactionTag>lists backed up grids for a faction.!gridbackup find <GridName|GridID>searches matching backed up grids across known owners.!gridbackup restore <PlayerName|SteamID|IdentityID> <GridName|GridID|ListNumber> [backupNumber] [keepOriginalPosition] [force]restores a backup.!gridbackup restore faction <FactionTag> <GridName|GridID|ListNumber> [backupNumber] [keepOriginalPosition] [force]restores from a faction member backup.!gridbackup runstarts a full backup scan.!gridbackup statusshows current backup service state.
Restore defaults to the latest backup, spawning near the caller. Console restores must use keepOriginalPosition=true. Use force=true to skip the occupation check.
Other plugins can call:
bool BackupBeforeConcealment(List<MyObjectBuilder_CubeGrid> grids, long ownerIdentity);
bool BackupGridsManuallyWithBuilders(List<MyObjectBuilder_CubeGrid> grids, long ownerIdentity);Requirements:
- Space Engineers Dedicated Server
- Magnetar
- .NET 10 SDK
- .NET Framework 4.8.1 Developer Pack on Windows
- Python 3.12 or newer, for
setup.py
Build:
dotnet build GridBackups.sln --configuration DebugDirectory.Build.props auto-detects the Dedicated Server (Dedicated64) and the Magnetar
installation (Magnetar). To override them, set them in Directory.Build.props.user, which
is not committed. setup.py writes that file with the auto-detected Dedicated Server folder.
The plugin version lives in Version.Build.props.
Load the working copy through a Magnetar development folder: start Magnetar with -sources
and add the repository with the Sources button. Magnetar then compiles the plugin from source.
Builds deploy nothing by default. To copy the build into <MagnetarData>/Local, set
MagnetarData (the Magnetar config folder) in Directory.Build.props.user or pass
-p:MagnetarData=... to the build.
tests/ holds the plugin's test suite. It runs on Linux only.
tests/unit has unit tests of the logic that needs no game: the storage root (Quasar
data folder, the server's data folder, cluster storage), a broken config file, the backup
triggers, retention, grid name matching and folder names. They build against the Dedicated
Server and Magnetar like the plugin does:
dotnet test tests/unitThe rest is an in-game suite. It starts a Magnetar server with this working copy of the plugin, joins it with two headless game clients and drives them through the Remote plugin: player A is an administrator, player B has no rights. The tests run the chat commands and check the backup files, the plugin's log and the grids on the server. What it covers:
- Backup triggers: the first scan, the minimum and maximum time since the last backup, a
steady block count, a large block count change, and the entry points other plugins call,
BackupBeforeConcealmentamong them (test_triggers.py) - What a backup holds and where it goes: grids joined by a rotor, owner folder names, NPC
and nobody grids, the original owners, retention of normal, daily and old backups
(
test_contents.py) - The
!gridbackupcommands, their permissions and bad input (test_commands.py) - Restores: a restored grid matching the backup, near the caller or in place, backup
numbers, faction restores, and the occupied-area check (
test_restore.py) - The Quasar data folder from
QUASAR_DATA_DIR,QUASAR_DS_CONFIG_PATHor the home folder, and a broken config file, each on a server of its own (test_storage.py) - Cluster storage: two servers started as cluster nodes that share one storage root
(
nodes.py), coordinating their backups through it (test_cluster.py) - Backups, config and listing across a server restart (
test_restart.py)
The test world is the game's Empty World with the test players, a faction and a row of
test grids, written fresh for every run. tests/probe is a test-only server plugin the
servers load next to Grid Backups. It puts a new config into the running plugin, moves a
grid's last backup back in time instead of waiting for minutes to pass, reports the state
of grids, calls the public entry points, and runs chat commands as the console from a
file, which is how the tests drive the servers that have no clients.
You need the Space Engineers client and Dedicated Server from Steam, Magnetar and Pulsar
installed, uv, and working copies of
Remote and
DirectTransport. The rig takes the
ports, client ids and folders from a test slot of the se workspace
(notes/parallel-test-work), and waits for free memory before each process it starts.
uv run pytestWhere GitHub's API rate limits Magnetar, export PULSAR_GITHUB_TOKEN for it to download
its hub plugins with. A full run takes about 40 minutes, most of it starting servers;
dotnet test tests/unit takes seconds. tests/rig.py lists the environment variables
that point the rig at other installations and working copies.
To keep the server and clients running between runs while you work on a test:
uv run python tests/session.py start
GB_ATTACH=1 GB_KEEP=1 uv run pytest tests/test_commands.py
uv run python tests/session.py stopFunctionality is inspired by and reimplements the original Torch plugin GridBackup by LordTylus (license: Apache-2.0): https://github.com/LordTylus/SE-Torch-Plugin-ALE-GridBackup