New game from the panel instead of an uploaded save (2.9.3)
World & Backups -> Start new game (console: new-game, also when stopped): the save is backed up and replaced by a new-game marker (also as reset point). Joining players are told to start a new game; the server pulls the first player's save and from then on runs normally. Reset world returns to a new game when the reset point is one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+68
-3
@@ -136,6 +136,14 @@ public sealed class GameServer
|
||||
Log(PermissionHint());
|
||||
return false;
|
||||
}
|
||||
if (loaded.All(f => f.Key != "defaultES2File.txt") && SaveStore.IsNewGame(DataDir))
|
||||
{
|
||||
// Neues Spiel: es gibt (noch) keinen Spielstand - der erste Spieler startet im Spiel ein neues Spiel
|
||||
saveFiles = new List<KeyValuePair<string, byte[]>>();
|
||||
NewGame = true;
|
||||
Log("New game: the first player to join creates a fresh world, the server then takes over its save game");
|
||||
return true;
|
||||
}
|
||||
if (loaded.All(f => f.Key != "defaultES2File.txt"))
|
||||
{
|
||||
Log("No save game found in " + savePath);
|
||||
@@ -143,6 +151,7 @@ public sealed class GameServer
|
||||
return false;
|
||||
}
|
||||
saveFiles = loaded;
|
||||
NewGame = false;
|
||||
Log("Loaded save game (" + saveFiles.Count + " files, " + saveFiles.Sum(f => f.Value.Length) / 1024 + " KB)");
|
||||
return true;
|
||||
}
|
||||
@@ -257,6 +266,7 @@ public sealed class GameServer
|
||||
|
||||
void Timers()
|
||||
{
|
||||
PullNewGameSave();
|
||||
double now = clock.Elapsed.TotalSeconds;
|
||||
if (now >= nextAutosave)
|
||||
{
|
||||
@@ -583,7 +593,40 @@ public sealed class GameServer
|
||||
c.Conn.Send(MsgType.SaveBegin);
|
||||
foreach (var f in saveFiles)
|
||||
c.Conn.Send(MsgType.SaveFile, Wire.Build(w => { w.Write(f.Key); w.Write(f.Value.Length); w.Write(f.Value); }));
|
||||
c.Conn.Send(MsgType.StartGame, Wire.Build(w => w.Write(false)));
|
||||
// [bool neben den Host setzen, bool neues Spiel] - ältere Mods lesen nur den ersten Wert
|
||||
bool newGame = NewGame && saveFiles.Count == 0;
|
||||
c.Conn.Send(MsgType.StartGame, Wire.Build(w => { w.Write(false); w.Write(newGame); }));
|
||||
}
|
||||
|
||||
/// <summary>Neues Spiel: noch kein Spielstand - der erste Spieler legt die Welt im Spiel an.</summary>
|
||||
public bool NewGame { get; private set; }
|
||||
DateTime nextNewGameSave = DateTime.MinValue;
|
||||
|
||||
/// <summary>Neues Spiel läuft: den Spielstand des ersten Spielers holen, sobald einer im Spiel ist.</summary>
|
||||
void PullNewGameSave()
|
||||
{
|
||||
if (!NewGame || saveUpload != null || DateTime.UtcNow < nextNewGameSave) return;
|
||||
nextNewGameSave = DateTime.UtcNow.AddSeconds(20);
|
||||
RequestSave("new game - taking over the fresh world");
|
||||
}
|
||||
|
||||
/// <summary>Panel/Konsole: aktuellen Spielstand sichern und ein neues Spiel starten. Alle verbinden neu.</summary>
|
||||
string StartNewGame(string by)
|
||||
{
|
||||
try
|
||||
{
|
||||
SaveStore.MakeNewGame(DataDir, alsoResetPoint: true);
|
||||
if (!LoadSave()) return "Could not start a new game";
|
||||
}
|
||||
catch (Exception e) { return "Could not start a new game: " + e.Message; }
|
||||
saveUpload = null;
|
||||
waitingForSave.Clear();
|
||||
world.Reset();
|
||||
SaveWorld();
|
||||
nextNewGameSave = DateTime.UtcNow.AddSeconds(30); // erst laden lassen
|
||||
Log($"New game started by {by} - the previous save game is in the backups");
|
||||
ReconnectAll(by == "Console" ? "The server starts a new game - reconnecting..." : $"{by} started a new game - reconnecting...");
|
||||
return "New game started - the first player to join creates the new world";
|
||||
}
|
||||
|
||||
void SendSaveToWaiting()
|
||||
@@ -656,6 +699,9 @@ public sealed class GameServer
|
||||
File.WriteAllBytes(tmp, f.Value);
|
||||
File.Move(tmp, target, true);
|
||||
}
|
||||
bool wasNewGame = NewGame;
|
||||
SaveStore.ClearNewGameMarker(DataDir);
|
||||
if (wasNewGame) Log($"The new game is running - took over the fresh world from {c.Name}");
|
||||
if (LoadSave())
|
||||
{
|
||||
world.ResetForNewSave();
|
||||
@@ -700,7 +746,7 @@ public sealed class GameServer
|
||||
/// <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 (SaveStore.HasResetPoint(DataDir)) return;
|
||||
if (SetResetPoint()) Log("Remembered the current save game as the reset point (reset-world goes back to it)");
|
||||
}
|
||||
|
||||
@@ -719,6 +765,20 @@ public sealed class GameServer
|
||||
/// </summary>
|
||||
string ResetWorld(string by)
|
||||
{
|
||||
if (SaveStore.ResetPointIsNewGame(DataDir))
|
||||
{
|
||||
// Reset-Punkt ist ein neues Spiel
|
||||
try { SaveStore.MakeNewGame(DataDir, alsoResetPoint: false); LoadSave(); }
|
||||
catch (Exception e) { Log("Could not reset to a new game: " + e.Message); }
|
||||
saveUpload = null;
|
||||
waitingForSave.Clear();
|
||||
world.Reset();
|
||||
SaveWorld();
|
||||
nextNewGameSave = DateTime.UtcNow.AddSeconds(30);
|
||||
Log($"World reset by {by} - back to a new game (previous state backed up).");
|
||||
ReconnectAll(by == "Console" ? "The world is being reset - reconnecting..." : $"{by} reset the world - reconnecting...");
|
||||
return "World reset to a new game";
|
||||
}
|
||||
bool restored = false;
|
||||
if (File.Exists(Path.Combine(originalPath, "defaultES2File.txt")))
|
||||
{
|
||||
@@ -859,7 +919,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> | set-reset-point | panel | restart | stop | exit | 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 | panel | restart | stop | exit | say <text> | op <id> | deop <id> | admins | save | reset-world | new-game | reload-save | stop");
|
||||
break;
|
||||
case "say":
|
||||
if (args.Length < 2) { Log("say <text>"); break; }
|
||||
@@ -943,6 +1003,9 @@ public sealed class GameServer
|
||||
case "reset-world":
|
||||
ResetWorld("Console");
|
||||
break;
|
||||
case "new-game":
|
||||
Log(StartNewGame("Console"));
|
||||
break;
|
||||
case "backups":
|
||||
{
|
||||
var list = SaveBackups();
|
||||
@@ -1060,6 +1123,7 @@ public sealed class GameServer
|
||||
? File.GetLastWriteTimeUtc(Path.Combine(originalPath, "defaultES2File.txt")).ToString("o") : null;
|
||||
return new
|
||||
{
|
||||
newGame = NewGame,
|
||||
name = config.Name,
|
||||
description = config.Description,
|
||||
version = ModVersion,
|
||||
@@ -1264,6 +1328,7 @@ public sealed class GameServer
|
||||
case "save": SaveWorld(); return "World state saved";
|
||||
case "backup": return BackupNow(by);
|
||||
case "reset": return ResetWorld(by);
|
||||
case "newgame": return StartNewGame(by);
|
||||
case "restore": return RestoreSave(arg ?? "", by);
|
||||
case "resetpoint":
|
||||
if (!SetResetPoint()) return "No save game to use as reset point";
|
||||
|
||||
Reference in New Issue
Block a user