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:
2026-09-27 17:48:28 +02:00
co-authored by Claude Opus 5.5
parent bd45a6e70c
commit f23671704d
6 changed files with 162 additions and 8 deletions
+40
View File
@@ -145,6 +145,29 @@ try
Check(lateSnap.Destroyed.Count <= 21, "Mass 'consumed' reports (e.g. scene unload) are capped: " + lateSnap.Destroyed.Count + " stored");
late.Close();
Console.WriteLine("== Own needs (hunger, thirst ...) are stored per player");
var hungry = await TestClient.Join("Hungry", 0, null);
hungry.Send(MsgType.Ready, Array.Empty<byte>());
await hungry.WaitFor(MsgType.WorldSnapshot);
server.EnqueueCommand("save"); // (Zeitfenster TrackPositionFrom abwarten)
await Task.Delay(8500);
hungry.Send(MsgType.PlayerNeeds, Wire.Build(w => { w.Write(2); w.Write("PlayerHunger"); w.Write(77f); w.Write("PlayerThirst"); w.Write(12.5f); }));
await Task.Delay(300);
hungry.Close();
await Task.Delay(500);
var hungry2 = await TestClient.Join("Hungry", 0, null);
hungry2.Send(MsgType.Ready, Array.Empty<byte>());
var needsSnap = Snapshot.Parse(await hungry2.WaitFor(MsgType.WorldSnapshot));
Check(needsSnap.Ok && needsSnap.Needs.TryGetValue("PlayerHunger", out float hunger) && Math.Abs(hunger - 77f) < 0.01f,
"Rejoining player gets their own needs back: " + string.Join(", ", needsSnap.Needs.Select(kv => kv.Key + "=" + kv.Value)));
var otherSnapClient = await TestClient.Join("NotHungry", 0, null);
otherSnapClient.Send(MsgType.Ready, Array.Empty<byte>());
var otherSnap = Snapshot.Parse(await otherSnapClient.WaitFor(MsgType.WorldSnapshot));
Check(otherSnap.Ok && otherSnap.Needs.Count == 0, "Other players do not get someone else's needs");
hungry2.Close();
otherSnapClient.Close();
await Task.Delay(300);
Console.WriteLine("== Last position (spawn)");
var pos1 = await TestClient.Join("Walker", 0, null);
pos1.Send(MsgType.Player, PlayerPos(-15.6f, -0.3f, 7f)); // Startpunkt des Spielstands (Toilette) - vor Ready
@@ -253,6 +276,17 @@ try
var restoreMsg = await newcomer.WaitFor(MsgType.Reconnect);
Check(restoreMsg != null, "Restoring a backup makes everyone reconnect");
Check(File.ReadAllText(Path.Combine(dir, "save", "defaultES2File.txt")).EndsWith("CURRENT-SAVE"), "The backup's files are back in the active save");
Console.WriteLine("== reset-world goes back to the ORIGINAL save (not the auto-uploaded one)");
var r2 = await TestClient.Join("Resetter2", 0, null);
server.EnqueueCommand("reset-world");
Check(await r2.WaitFor(MsgType.Reconnect) != null, "Players reconnect after the reset");
Check(File.ReadAllText(Path.Combine(dir, "save", "defaultES2File.txt")) == "test defaultES2File.txt",
"The active save is the original one again: " + File.ReadAllText(Path.Combine(dir, "save", "defaultES2File.txt")).Length + " chars");
var afterReset = await TestClient.Join("AfterReset", 0, null);
Check(afterReset.Files.TryGetValue("defaultES2File.txt", out var orig) && System.Text.Encoding.UTF8.GetString(orig) == "test defaultES2File.txt",
"Joining players download the original save");
afterReset.Close();
inGame.Close();
newcomer.Close();
}
@@ -292,6 +326,7 @@ sealed class Snapshot
public int Spawns = -1;
public int Appeared = -1;
public List<int> Destroyed = new();
public Dictionary<string, float> Needs = new();
public int Vars = -1;
public static Snapshot Parse(byte[] data)
@@ -317,6 +352,11 @@ sealed class Snapshot
for (int i = 0; i < s.Appeared; i++) r.ReadBytes(r.ReadInt32());
int destroyed = r.ReadInt32();
for (int i = 0; i < destroyed; i++) s.Destroyed.Add(r.ReadInt32());
if (r.ReadBoolean())
{
int needs = r.ReadInt32();
for (int i = 0; i < needs; i++) s.Needs[r.ReadString()] = r.ReadSingle();
}
s.Ok = r.BaseStream.Position == r.BaseStream.Length;
s.Info = $"{objects} objects, {events} events, money {money}, {doors} doors, {s.Vars} vars";
}