Cap consumed-item reports per player (max 20/min); test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,8 @@ public sealed class GameServer
|
|||||||
/// <summary>SteamID von Steam bestätigt (Ticket per Web API geprüft). Nur dann gibt es Admin-Rechte.</summary>
|
/// <summary>SteamID von Steam bestätigt (Ticket per Web API geprüft). Nur dann gibt es Admin-Rechte.</summary>
|
||||||
public bool SteamVerified;
|
public bool SteamVerified;
|
||||||
public bool IsAdmin;
|
public bool IsAdmin;
|
||||||
|
public DateTime DestroyWindowStart;
|
||||||
|
public int DestroyCount;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ab wann die Position des Spielers gespeichert wird: erst nachdem er seinen Weltzustand (mit seiner letzten
|
/// Ab wann die Position des Spielers gespeichert wird: erst nachdem er seinen Weltzustand (mit seiner letzten
|
||||||
/// Position) bekommen und sich dorthin gesetzt hat - sonst überschreibt der Startpunkt des Spielstands
|
/// Position) bekommen und sich dorthin gesetzt hat - sonst überschreibt der Startpunkt des Spielstands
|
||||||
@@ -79,6 +81,7 @@ public sealed class GameServer
|
|||||||
const int KeepSaveBackups = 5;
|
const int KeepSaveBackups = 5;
|
||||||
/// <summary>So lange auf den hochgeladenen Spielstand warten, danach bekommen Wartende den gespeicherten.</summary>
|
/// <summary>So lange auf den hochgeladenen Spielstand warten, danach bekommen Wartende den gespeicherten.</summary>
|
||||||
public double SaveUploadTimeoutSeconds { get; set; } = 15;
|
public double SaveUploadTimeoutSeconds { get; set; } = 15;
|
||||||
|
const int MaxDestroyPerMinute = 20;
|
||||||
|
|
||||||
/// <summary>Ohne Master-Server (nur für automatische Tests): keine Heartbeats, keine Serverliste.</summary>
|
/// <summary>Ohne Master-Server (nur für automatische Tests): keine Heartbeats, keine Serverliste.</summary>
|
||||||
readonly bool offline;
|
readonly bool offline;
|
||||||
@@ -410,6 +413,9 @@ public sealed class GameServer
|
|||||||
break;
|
break;
|
||||||
case MsgType.ObjDestroy:
|
case MsgType.ObjDestroy:
|
||||||
if (m.Payload.Length != 4) return;
|
if (m.Payload.Length != 4) return;
|
||||||
|
// Niemand isst/verbraucht 20 Dinge pro Minute - mehr ist ein Fehler (z.B. Szene entladen) oder Absicht
|
||||||
|
if (DateTime.UtcNow - c.DestroyWindowStart > TimeSpan.FromMinutes(1)) { c.DestroyWindowStart = DateTime.UtcNow; c.DestroyCount = 0; }
|
||||||
|
if (++c.DestroyCount > MaxDestroyPerMinute) return;
|
||||||
world.AddDestroyed(BitConverter.ToInt32(m.Payload, 0));
|
world.AddDestroyed(BitConverter.ToInt32(m.Payload, 0));
|
||||||
break;
|
break;
|
||||||
case MsgType.Chat:
|
case MsgType.Chat:
|
||||||
|
|||||||
@@ -133,12 +133,14 @@ try
|
|||||||
Check(await alice.WaitFor(MsgType.TrafficStates, 800) == null, "Traffic from a player who is not the world authority is ignored");
|
Check(await alice.WaitFor(MsgType.TrafficStates, 800) == null, "Traffic from a player who is not the world authority is ignored");
|
||||||
alice.Send(MsgType.TrafficStates, trafficPayload);
|
alice.Send(MsgType.TrafficStates, trafficPayload);
|
||||||
Check(await bob.WaitFor(MsgType.TrafficStates) != null, "Traffic from the world authority is relayed");
|
Check(await bob.WaitFor(MsgType.TrafficStates) != null, "Traffic from the world authority is relayed");
|
||||||
|
for (int i = 0; i < 40; i++) { int id = 1000 + i; bob.Send(MsgType.ObjDestroy, Wire.Build(w => w.Write(id))); }
|
||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
var late = await TestClient.Join("Late", 0, null);
|
var late = await TestClient.Join("Late", 0, null);
|
||||||
late.Send(MsgType.Ready, Array.Empty<byte>());
|
late.Send(MsgType.Ready, Array.Empty<byte>());
|
||||||
var lateSnap = Snapshot.Parse(await late.WaitFor(MsgType.WorldSnapshot));
|
var lateSnap = Snapshot.Parse(await late.WaitFor(MsgType.WorldSnapshot));
|
||||||
Check(lateSnap.Ok && lateSnap.Appeared == 1 && lateSnap.Destroyed.Contains(777),
|
Check(lateSnap.Ok && lateSnap.Appeared == 1 && lateSnap.Destroyed.Contains(777),
|
||||||
"Players joining later get bought and consumed items: " + lateSnap.Info);
|
"Players joining later get bought and consumed items: " + lateSnap.Info);
|
||||||
|
Check(lateSnap.Destroyed.Count <= 21, "Mass 'consumed' reports (e.g. scene unload) are capped: " + lateSnap.Destroyed.Count + " stored");
|
||||||
late.Close();
|
late.Close();
|
||||||
|
|
||||||
Console.WriteLine("== Last position (spawn)");
|
Console.WriteLine("== Last position (spawn)");
|
||||||
|
|||||||
Reference in New Issue
Block a user