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:
+38
-1
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user