Relay vehicle controls; on shutdown tell players to reconnect (restart) instead of a final disconnect
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+4
-3
@@ -162,8 +162,9 @@ public sealed class GameServer
|
|||||||
|
|
||||||
foreach (var c in clients.Values)
|
foreach (var c in clients.Values)
|
||||||
{
|
{
|
||||||
// Grund mitschicken: die Spieler sehen ihn im Hauptmenü
|
// Meist ein Neustart (Update, docker compose up): die Spieler verbinden sich automatisch neu, sobald der
|
||||||
if (c.State == ClientState.Joined) c.Conn.Send(MsgType.Reject, Wire.Build(w => w.Write("The server was shut down.")));
|
// Server wieder da ist. Bleibt er aus, bekommen sie nach ein paar Versuchen einen Hinweis im Hauptmenü.
|
||||||
|
if (c.State == ClientState.Joined) c.Conn.Send(MsgType.Reconnect, Wire.Build(w => w.Write("The server is restarting - reconnecting...")));
|
||||||
c.Conn.CloseAfterSend("Server shutting down");
|
c.Conn.CloseAfterSend("Server shutting down");
|
||||||
}
|
}
|
||||||
// Kurz warten, bis die Spieler die Meldung gelesen haben (sauber trennen statt hart abbrechen)
|
// Kurz warten, bis die Spieler die Meldung gelesen haben (sauber trennen statt hart abbrechen)
|
||||||
@@ -291,7 +292,7 @@ public sealed class GameServer
|
|||||||
t is MsgType.Player or MsgType.ObjStates or MsgType.ObjOwn or MsgType.ObjRelease or MsgType.FsmEvent
|
t is MsgType.Player or MsgType.ObjStates or MsgType.ObjOwn or MsgType.ObjRelease or MsgType.FsmEvent
|
||||||
or MsgType.VehicleFx or MsgType.WorldTime or MsgType.MoneyDelta or MsgType.DoorState or MsgType.Chat or MsgType.VarSync
|
or MsgType.VehicleFx or MsgType.WorldTime or MsgType.MoneyDelta or MsgType.DoorState or MsgType.Chat or MsgType.VarSync
|
||||||
or MsgType.SpawnItem or MsgType.ItemAppeared or MsgType.ObjDestroy or MsgType.VehicleDamage
|
or MsgType.SpawnItem or MsgType.ItemAppeared or MsgType.ObjDestroy or MsgType.VehicleDamage
|
||||||
or MsgType.TrafficStates or MsgType.WorldVars or MsgType.HingeStates;
|
or MsgType.TrafficStates or MsgType.WorldVars or MsgType.HingeStates or MsgType.VehicleControls;
|
||||||
|
|
||||||
/// <summary>Uhrzeit/Wetter gibt der Spieler mit der kleinsten ID vor (so rechnen es auch die Clients).</summary>
|
/// <summary>Uhrzeit/Wetter gibt der Spieler mit der kleinsten ID vor (so rechnen es auch die Clients).</summary>
|
||||||
int WorldAuthorityId => clients.Values.Where(c => c.State == ClientState.Joined).Select(c => c.Id).DefaultIfEmpty(-1).Min();
|
int WorldAuthorityId => clients.Values.Where(c => c.State == ClientState.Joined).Select(c => c.Id).DefaultIfEmpty(-1).Min();
|
||||||
|
|||||||
+2
-1
@@ -46,7 +46,8 @@ public enum MsgType : byte
|
|||||||
VehicleDamage = 39, // Unfallschaden (verformte Karosserie): int Mesh-Schlüssel, int Eckpunkte, int n, je [int Index, 3 float]
|
VehicleDamage = 39, // Unfallschaden (verformte Karosserie): int Mesh-Schlüssel, int Eckpunkte, int n, je [int Index, 3 float]
|
||||||
TrafficStates = 40, // Verkehr, nur von der Welt-Autorität: int n, je [int Schlüssel, 3 float Pos, 4 float Rot, 3 float Geschw.]
|
TrafficStates = 40, // Verkehr, nur von der Welt-Autorität: int n, je [int Schlüssel, 3 float Pos, 4 float Rot, 3 float Geschw.]
|
||||||
WorldVars = 41, // Jobs/Laden: int n, je [int Schlüssel, byte Typ, Wert]
|
WorldVars = 41, // Jobs/Laden: int n, je [int Schlüssel, byte Typ, Wert]
|
||||||
HingeStates = 42 // Autotüren/Haube/Kofferraum: int n, je [int Schlüssel, 3 float Pos, 4 float Rot relativ zum Auto]
|
HingeStates = 42, // Autotüren/Haube/Kofferraum: int n, je [int Schlüssel, 3 float Pos, 4 float Rot relativ zum Auto]
|
||||||
|
VehicleControls = 43 // Zündung/Motor/Licht ...: int n, je [int FSM-Schlüssel, string Zustand]
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly record struct Message(MsgType Type, byte[] Payload)
|
public readonly record struct Message(MsgType Type, byte[] Payload)
|
||||||
|
|||||||
@@ -128,6 +128,8 @@ try
|
|||||||
Check(await bob.WaitFor(MsgType.WorldVars) != null, "Job/shop values are relayed");
|
Check(await bob.WaitFor(MsgType.WorldVars) != null, "Job/shop values are relayed");
|
||||||
alice.Send(MsgType.HingeStates, Wire.Build(w => { w.Write(0); }));
|
alice.Send(MsgType.HingeStates, Wire.Build(w => { w.Write(0); }));
|
||||||
Check(await bob.WaitFor(MsgType.HingeStates) != null, "Car door angles are relayed");
|
Check(await bob.WaitFor(MsgType.HingeStates) != null, "Car door angles are relayed");
|
||||||
|
alice.Send(MsgType.VehicleControls, Wire.Build(w => { w.Write(1); w.Write(123); w.Write("Lights"); }));
|
||||||
|
Check(await bob.WaitFor(MsgType.VehicleControls) != null, "Vehicle controls (ignition, lights ...) are relayed");
|
||||||
byte[] trafficPayload = Wire.Build(w => { w.Write(0); });
|
byte[] trafficPayload = Wire.Build(w => { w.Write(0); });
|
||||||
bob.Send(MsgType.TrafficStates, trafficPayload);
|
bob.Send(MsgType.TrafficStates, trafficPayload);
|
||||||
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");
|
||||||
|
|||||||
Reference in New Issue
Block a user