reset-world restores the original save (reset point in data/save_original), set-reset-point; per-player needs stored and returned; tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+77
-5
@@ -93,6 +93,7 @@ public sealed class GameServer
|
||||
this.config = config;
|
||||
this.configPath = configPath;
|
||||
savePath = Path.Combine(dataDir, "save");
|
||||
originalPath = Path.Combine(dataDir, "save_original");
|
||||
worldPath = Path.Combine(dataDir, "world.json");
|
||||
master = new MasterClient(MasterServer.Url);
|
||||
steam = new SteamVerifier(config.SteamWebApiKey);
|
||||
@@ -137,6 +138,7 @@ public sealed class GameServer
|
||||
|
||||
public void Run()
|
||||
{
|
||||
EnsureResetPoint();
|
||||
listener = new TcpListener(IPAddress.Any, config.Port);
|
||||
listener.Start();
|
||||
Log($"Listening on port {config.Port} - {config.Name} (max {config.MaxPlayers} players)");
|
||||
@@ -347,6 +349,11 @@ public sealed class GameServer
|
||||
FinishSaveUpload(c, m.Reader());
|
||||
return;
|
||||
|
||||
case MsgType.PlayerNeeds:
|
||||
// Nur speichern, nicht weiterleiten - die Bedürfnisse gehören jedem selbst
|
||||
if (c.State == ClientState.Joined && DateTime.UtcNow >= c.TrackPositionFrom) world.ApplyNeeds(c.SteamId, m.Payload);
|
||||
return;
|
||||
|
||||
case MsgType.AdminListRequest:
|
||||
if (c.State != ClientState.Joined) return;
|
||||
if (!c.IsAdmin) { c.Conn.Send(MsgType.AdminResult, Wire.Build(w => w.Write("You are not an admin on this server"))); return; }
|
||||
@@ -384,6 +391,11 @@ public sealed class GameServer
|
||||
return;
|
||||
}
|
||||
else if (action == 6) result = BackupNow(c.Name);
|
||||
else if (action == 8)
|
||||
{
|
||||
result = SetResetPoint() ? "The current save game is now the reset point" : "No save game to use as reset point";
|
||||
if (result.StartsWith("The")) Log($"{c.Name} set the current save game as the reset point");
|
||||
}
|
||||
else if (!clients.TryGetValue(targetId, out var target) || target.State != ClientState.Joined) result = "Player not found";
|
||||
else if (action == 3)
|
||||
{
|
||||
@@ -670,14 +682,66 @@ public sealed class GameServer
|
||||
if (count > 0) Log($"{count} player(s) will reconnect");
|
||||
}
|
||||
|
||||
/// <summary>Weltzustand zurücksetzen (Konsole oder Admin im Spiel): alle verbinden neu und laden den reinen Spielstand.</summary>
|
||||
// ---------------------------------------------------------------- Reset-Punkt
|
||||
// Der Spielstand, so wie er dem Server gegeben wurde (Start, --import-save, reload-save). Das automatische
|
||||
// Hochladen alle paar Minuten überschreibt nur data/save - "reset-world" holt diesen Stand zurück.
|
||||
string originalPath;
|
||||
|
||||
/// <summary>Beim Start: gibt es noch keinen Reset-Punkt, ist es der aktuelle Spielstand.</summary>
|
||||
void EnsureResetPoint()
|
||||
{
|
||||
if (File.Exists(Path.Combine(originalPath, "defaultES2File.txt"))) return;
|
||||
if (SetResetPoint()) Log("Remembered the current save game as the reset point (reset-world goes back to it)");
|
||||
}
|
||||
|
||||
/// <summary>Aktuellen Spielstand als Reset-Punkt merken.</summary>
|
||||
bool SetResetPoint()
|
||||
{
|
||||
if (!File.Exists(Path.Combine(savePath, "defaultES2File.txt"))) return false;
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(originalPath)) Directory.Delete(originalPath, true);
|
||||
Directory.CreateDirectory(originalPath);
|
||||
foreach (string file in Directory.GetFiles(savePath))
|
||||
if (!file.EndsWith(".tmp")) File.Copy(file, Path.Combine(originalPath, Path.GetFileName(file)), true);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) { Log("Could not remember the reset point: " + e.Message); return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Welt komplett zurücksetzen (Konsole oder Admin im Spiel): Spielstand zurück auf den Reset-Punkt, alle
|
||||
/// gespeicherten Änderungen (Positionen, gekaufte Items, Türen, Fahrzeugwerte ...) weg, alle verbinden neu.
|
||||
/// Der Stand davor landet als Backup in save_backups.
|
||||
/// </summary>
|
||||
string ResetWorld(string by)
|
||||
{
|
||||
bool restored = false;
|
||||
if (File.Exists(Path.Combine(originalPath, "defaultES2File.txt")))
|
||||
{
|
||||
try
|
||||
{
|
||||
BackupSave();
|
||||
Directory.CreateDirectory(savePath);
|
||||
foreach (string name in SaveFiles)
|
||||
{
|
||||
string from = Path.Combine(originalPath, name), to = Path.Combine(savePath, name);
|
||||
if (File.Exists(from)) File.Copy(from, to, true);
|
||||
else if (File.Exists(to)) File.Delete(to); // gab es im Original nicht
|
||||
}
|
||||
restored = LoadSave();
|
||||
}
|
||||
catch (Exception e) { Log("Could not restore the reset point: " + e.Message); }
|
||||
}
|
||||
// Laufendes Hochladen eines Spielstands (alter Stand) verwerfen
|
||||
saveUpload = null;
|
||||
waitingForSave.Clear();
|
||||
world.Reset();
|
||||
SaveWorld();
|
||||
Log($"World state reset by {by} - new players get the plain save game again.");
|
||||
Log(restored ? $"World reset by {by} - back to the original save game (previous state backed up)."
|
||||
: $"World state reset by {by} - new players get the plain save game again.");
|
||||
ReconnectAll(by == "Console" ? "The world is being reset - reconnecting..." : $"{by} reset the world - reconnecting...");
|
||||
return "World reset";
|
||||
return restored ? "World reset to the original save game" : "World reset";
|
||||
}
|
||||
|
||||
/// <summary>Aktuellen Spielstand jetzt als Backup sichern.</summary>
|
||||
@@ -780,7 +844,7 @@ public sealed class GameServer
|
||||
switch (args[0].ToLowerInvariant())
|
||||
{
|
||||
case "help":
|
||||
Log("status | players | kick <id> [reason] | ban <id> [reason] | bans | unban <SteamID|name:x> | backups | backup | restore-save <n> | 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 | backup | restore-save <n> | set-reset-point | say <text> | op <id> | deop <id> | admins | save | reset-world | reload-save | stop");
|
||||
break;
|
||||
case "say":
|
||||
if (args.Length < 2) { Log("say <text>"); break; }
|
||||
@@ -875,7 +939,15 @@ public sealed class GameServer
|
||||
Log(RestoreSave(args.Length > 1 ? args[1].Trim() : "", "Console"));
|
||||
break;
|
||||
case "reload-save":
|
||||
if (LoadSave()) ReconnectAll("The server loaded a new save game - reconnecting...");
|
||||
if (LoadSave())
|
||||
{
|
||||
// Neuer Spielstand von Hand hineinkopiert: ab jetzt ist das der Reset-Punkt
|
||||
SetResetPoint();
|
||||
ReconnectAll("The server loaded a new save game - reconnecting...");
|
||||
}
|
||||
break;
|
||||
case "set-reset-point":
|
||||
Log(SetResetPoint() ? "The current save game is now the reset point" : "No save game to use as reset point");
|
||||
break;
|
||||
case "stop":
|
||||
case "quit":
|
||||
|
||||
Reference in New Issue
Block a user