Server gets the current save game from a player in the game (on join and every few minutes) instead of replaying actions; vehicle fire/smoke synced, also for parked cars
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+42
-2
@@ -16,6 +16,7 @@ var config = new ServerConfig { LicenseKey = "test", Name = "Test", Port = Port,
|
||||
config.Save(configPath);
|
||||
|
||||
var server = new GameServer(config, dir, configPath, "Tester", offline: true);
|
||||
server.SaveUploadTimeoutSeconds = 1; // Test-Spieler laden meist keinen Spielstand hoch - nicht lange warten
|
||||
if (!server.LoadSave()) { Console.WriteLine("FAIL: LoadSave"); return 1; }
|
||||
var serverThread = new Thread(server.Run) { IsBackground = true };
|
||||
serverThread.Start();
|
||||
@@ -176,6 +177,37 @@ try
|
||||
Check(rec != null && new BinaryReader(new MemoryStream(rec)).ReadString().Contains("reset"), "Players get the 'world is being reset' reconnect message");
|
||||
await Task.Delay(300);
|
||||
Check(r1.IsClosedByServer(), "Their connection is closed so they load the fresh world");
|
||||
|
||||
Console.WriteLine("== Joining gets the CURRENT save game from a player in the game");
|
||||
var inGame = await TestClient.Join("InGame", 0, null);
|
||||
inGame.Send(MsgType.Ready, Array.Empty<byte>());
|
||||
await inGame.WaitFor(MsgType.WorldSnapshot);
|
||||
inGame.Send(MsgType.FsmEvent, Wire.Build(w => { w.Write("SATSUMA|bolt#0"); w.Write("Screw"); w.Write("TIGHTEN"); w.Write("Tight"); w.Write(0f); w.Write(0f); w.Write(0f); }));
|
||||
await Task.Delay(200);
|
||||
var joinTask = TestClient.Join("Newcomer", 0, null);
|
||||
var request = await inGame.WaitFor(MsgType.SaveRequest, 5000);
|
||||
Check(request != null, "Server asks the player in the game for the current save");
|
||||
if (request != null)
|
||||
{
|
||||
int reqId = BitConverter.ToInt32(request, 0);
|
||||
byte[] fresh = System.Text.Encoding.UTF8.GetBytes(new string('S', 300_000) + "CURRENT-SAVE");
|
||||
for (int off = 0; off < fresh.Length; off += 100_000)
|
||||
{
|
||||
int len = Math.Min(100_000, fresh.Length - off);
|
||||
inGame.Send(MsgType.SaveUploadPart, Wire.Build(w => { w.Write(reqId); w.Write("defaultES2File.txt"); w.Write(fresh.Length); w.Write(off); w.Write(len); w.Write(fresh, off, len); }));
|
||||
}
|
||||
inGame.Send(MsgType.SaveUploadDone, Wire.Build(w => { w.Write(reqId); w.Write(1); }));
|
||||
}
|
||||
var newcomer = await joinTask;
|
||||
Check(newcomer.Files.TryGetValue("defaultES2File.txt", out var got) && System.Text.Encoding.UTF8.GetString(got).EndsWith("CURRENT-SAVE"),
|
||||
"Newcomer receives exactly the uploaded current save (" + (got?.Length ?? 0) + " bytes, sent in parts)");
|
||||
newcomer.Send(MsgType.Ready, Array.Empty<byte>());
|
||||
var fresh2 = Snapshot.Parse(await newcomer.WaitFor(MsgType.WorldSnapshot));
|
||||
Check(fresh2.Ok && fresh2.Info.Contains("0 events"), "Replayed actions are cleared - they are in the save now (" + fresh2.Info + ")");
|
||||
Check(Directory.Exists(Path.Combine(dir, "save_backups")) && Directory.GetDirectories(Path.Combine(dir, "save_backups")).Length > 0,
|
||||
"The previous save game is kept as a backup");
|
||||
inGame.Close();
|
||||
newcomer.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -255,6 +287,7 @@ sealed class TestClient
|
||||
public int SaveFiles;
|
||||
public bool GotStartGame;
|
||||
public string RejectReason;
|
||||
public Dictionary<string, byte[]> Files = new();
|
||||
|
||||
public static async Task<TestClient> Join(string name, ulong steamId, byte[] ticket, bool expectReject = false)
|
||||
{
|
||||
@@ -280,8 +313,15 @@ sealed class TestClient
|
||||
if (c.Welcome != null) c.Id = BitConverter.ToInt32(c.Welcome, 0);
|
||||
var admin = await c.WaitFor(MsgType.AdminStatus);
|
||||
if (admin != null) c.AdminStatus = admin[0] != 0;
|
||||
await c.WaitFor(MsgType.SaveBegin);
|
||||
while (await c.WaitFor(MsgType.SaveFile, 1500) != null) c.SaveFiles++;
|
||||
await c.WaitFor(MsgType.SaveBegin, 20000); // kann warten, bis ein anderer Spieler den aktuellen Spielstand hochlädt
|
||||
byte[] sf;
|
||||
while ((sf = await c.WaitFor(MsgType.SaveFile, 1500)) != null)
|
||||
{
|
||||
c.SaveFiles++;
|
||||
var fr = new BinaryReader(new MemoryStream(sf));
|
||||
string fname = fr.ReadString();
|
||||
c.Files[fname] = fr.ReadBytes(fr.ReadInt32());
|
||||
}
|
||||
c.GotStartGame = await c.WaitFor(MsgType.StartGame, 1500) != null || c.SaveFiles > 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user