Stuck bodies are placed on top instead of being reset into the same spot (no fling loop); reset message shown in-game before reconnecting; server: backups / restore-save

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-27 13:27:34 +02:00
co-authored by Claude Opus 5.5
parent 2deb6d2d1e
commit b9c7d33294
2 changed files with 39 additions and 1 deletions
+38 -1
View File
@@ -603,6 +603,13 @@ public sealed class GameServer
SendSaveToWaiting(); SendSaveToWaiting();
} }
/// <summary>Vorhandene Spielstand-Backups, neueste zuerst.</summary>
List<string> SaveBackups()
{
string backups = Path.Combine(Path.GetDirectoryName(savePath)!, "save_backups");
return Directory.Exists(backups) ? Directory.GetDirectories(backups).OrderByDescending(d => d).ToList() : new List<string>();
}
/// <summary>Bisherigen Spielstand nach data/save_backups/Zeitstempel kopieren, die letzten Stände behalten.</summary> /// <summary>Bisherigen Spielstand nach data/save_backups/Zeitstempel kopieren, die letzten Stände behalten.</summary>
void BackupSave() void BackupSave()
{ {
@@ -669,7 +676,7 @@ public sealed class GameServer
switch (args[0].ToLowerInvariant()) switch (args[0].ToLowerInvariant())
{ {
case "help": case "help":
Log("status | players | kick <id> [reason] | ban <id> [reason] | bans | unban <SteamID|name:x> | say <text> | op <id> | deop <id> | admins | save | reset-world | reload-save | stop"); Log("status | players | kick <id> [reason] | ban <id> [reason] | bans | unban <SteamID|name:x> | backups | restore-save <n> | say <text> | op <id> | deop <id> | admins | save | reset-world | reload-save | stop");
break; break;
case "say": case "say":
if (args.Length < 2) { Log("say <text>"); break; } if (args.Length < 2) { Log("say <text>"); break; }
@@ -752,6 +759,36 @@ public sealed class GameServer
Log("World state reset - new players get the plain save game again."); Log("World state reset - new players get the plain save game again.");
ReconnectAll("The world is being reset - reconnecting..."); ReconnectAll("The world is being reset - reconnecting...");
break; break;
case "backups":
{
var list = SaveBackups();
if (list.Count == 0) { Log("No save backups yet (they are created when the server takes over a save game)"); break; }
Log("Save backups (newest first) - restore with: restore-save <number>");
for (int i = 0; i < list.Count; i++) Log($" [{i + 1}] {Path.GetFileName(list[i])}");
break;
}
case "restore-save":
{
var list = SaveBackups();
string arg = args.Length > 1 ? args[1].Trim() : "";
string chosen = int.TryParse(arg, out int n) && n >= 1 && n <= list.Count ? list[n - 1]
: list.FirstOrDefault(d => Path.GetFileName(d) == arg);
if (chosen == null) { Log("restore-save <number> (see 'backups')"); break; }
try
{
BackupSave(); // aktuellen Stand ebenfalls sichern, falls man zurück will
foreach (string file in Directory.GetFiles(chosen)) File.Copy(file, Path.Combine(savePath, Path.GetFileName(file)), true);
if (LoadSave())
{
world.ResetForNewSave();
SaveWorld();
Log($"Restored save game {Path.GetFileName(chosen)}");
ReconnectAll("The server restored an older save game - reconnecting...");
}
}
catch (Exception e) { Log("Could not restore: " + e.Message); }
break;
}
case "reload-save": case "reload-save":
if (LoadSave()) ReconnectAll("The server loaded a new save game - reconnecting..."); if (LoadSave()) ReconnectAll("The server loaded a new save game - reconnecting...");
break; break;
+1
View File
@@ -132,6 +132,7 @@ Fehlende Einstellungen ergänzt der Server beim Start automatisch. Umgebungsvari
| `save` | Weltzustand jetzt speichern | | `save` | Weltzustand jetzt speichern |
| `reset-world` | alle Änderungen seit dem Spielstand verwerfen – verbundene Spieler bekommen eine Meldung und verbinden sich automatisch neu | | `reset-world` | alle Änderungen seit dem Spielstand verwerfen – verbundene Spieler bekommen eine Meldung und verbinden sich automatisch neu |
| `reload-save` | Spielstand-Dateien neu einlesen – verbundene Spieler verbinden sich automatisch neu | | `reload-save` | Spielstand-Dateien neu einlesen – verbundene Spieler verbinden sich automatisch neu |
| `backups`, `restore-save <nr>` | gesicherte Spielstände anzeigen / einen davon zurückholen (z.B. wenn der aktuelle kaputt ist) – alle verbinden sich neu |
| `stop` | speichern und beenden | | `stop` | speichern und beenden |
Im Spiel öffnen Admins mit `/admin` (Chat, Taste T) oder `admin` (F7-Konsole) das Admin-Menü: Kick/Ban, Im Spiel öffnen Admins mit `/admin` (Chat, Taste T) oder `admin` (F7-Konsole) das Admin-Menü: Kick/Ban,