Fix crash in OrderManager

This commit is contained in:
teinarss
2021-05-21 18:19:58 +02:00
committed by Paul Chote
parent acccb01c76
commit d10c592987
3 changed files with 41 additions and 25 deletions

View File

@@ -491,6 +491,20 @@ namespace OpenRA
{ {
var shellmap = ChooseShellmap(); var shellmap = ChooseShellmap();
// Add a spectator client for the local player,
// who is controlling the map via scripted orders
OrderManager.LobbyInfo.Clients.Add(new Session.Client
{
Index = OrderManager.Connection.LocalClientId,
Name = Settings.Player.Name,
PreferredColor = Settings.Player.Color,
Color = Settings.Player.Color,
Faction = "Random",
SpawnPoint = 0,
Team = 0,
State = Session.ClientState.Ready
});
using (new PerfTimer("StartGame")) using (new PerfTimer("StartGame"))
{ {
StartGame(shellmap, WorldType.Shellmap); StartGame(shellmap, WorldType.Shellmap);

View File

@@ -22,9 +22,6 @@ namespace OpenRA.Network
{ {
readonly SyncReport syncReport; readonly SyncReport syncReport;
// These are the clients who we expect to receive orders / sync from before we can simulate the next tick
readonly HashSet<int> activeClients = new HashSet<int>();
readonly Dictionary<int, Queue<byte[]>> pendingPackets = new Dictionary<int, Queue<byte[]>>(); readonly Dictionary<int, Queue<byte[]>> pendingPackets = new Dictionary<int, Queue<byte[]>>();
public Session LobbyInfo = new Session(); public Session LobbyInfo = new Session();
@@ -52,7 +49,6 @@ namespace OpenRA.Network
readonly List<Order> localOrders = new List<Order>(); readonly List<Order> localOrders = new List<Order>();
readonly List<Order> localImmediateOrders = new List<Order>(); readonly List<Order> localImmediateOrders = new List<Order>();
readonly List<(int ClientId, byte[] Packet)> immediatePackets = new List<(int ClientId, byte[] Packet)>();
readonly List<ChatLine> chatCache = new List<ChatLine>(); readonly List<ChatLine> chatCache = new List<ChatLine>();
@@ -83,6 +79,10 @@ namespace OpenRA.Network
if (GameStarted) if (GameStarted)
return; return;
foreach (var client in LobbyInfo.Clients)
if (!client.IsBot)
pendingPackets.Add(client.Index, new Queue<byte[]>());
// Generating sync reports is expensive, so only do it if we have // Generating sync reports is expensive, so only do it if we have
// other players to compare against if a desync did occur // other players to compare against if a desync did occur
generateSyncReport = !(Connection is ReplayConnection) && LobbyInfo.GlobalSettings.EnableSyncReports; generateSyncReport = !(Connection is ReplayConnection) && LobbyInfo.GlobalSettings.EnableSyncReports;
@@ -132,9 +132,13 @@ namespace OpenRA.Network
Connection.Receive( Connection.Receive(
(clientId, packet) => (clientId, packet) =>
{ {
// HACK: The shellmap relies on ticking a disposed OM
if (disposed && World.Type != WorldType.Shellmap)
return;
var frame = BitConverter.ToInt32(packet, 0); var frame = BitConverter.ToInt32(packet, 0);
if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect) if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect)
activeClients.Remove(clientId); pendingPackets.Remove(clientId);
else if (packet.Length > 4 && packet[4] == (byte)OrderType.SyncHash) else if (packet.Length > 4 && packet[4] == (byte)OrderType.SyncHash)
{ {
if (packet.Length != 4 + Order.SyncHashOrderLength) if (packet.Length != 4 + Order.SyncHashOrderLength)
@@ -146,27 +150,24 @@ namespace OpenRA.Network
CheckSync(packet); CheckSync(packet);
} }
else if (frame == 0) else if (frame == 0)
immediatePackets.Add((clientId, packet));
else
{ {
activeClients.Add(clientId); foreach (var o in packet.ToOrderList(World))
pendingPackets.GetOrAdd(clientId).Enqueue(packet);
}
});
foreach (var p in immediatePackets)
{ {
foreach (var o in p.Packet.ToOrderList(World)) UnitOrders.ProcessOrder(this, World, clientId, o);
{
UnitOrders.ProcessOrder(this, World, p.ClientId, o);
// A mod switch or other event has pulled the ground from beneath us // A mod switch or other event has pulled the ground from beneath us
if (disposed) if (disposed)
return; return;
} }
} }
else
immediatePackets.Clear(); {
if (pendingPackets.TryGetValue(clientId, out var queue))
queue.Enqueue(packet);
else
Log.Write("debug", $"Received packet from disconnected client '{clientId}'");
}
});
} }
Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>(); Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>();
@@ -187,7 +188,7 @@ namespace OpenRA.Network
syncForFrame.Add(frame, packet); syncForFrame.Add(frame, packet);
} }
public bool IsReadyForNextFrame => GameStarted && activeClients.All(client => pendingPackets[client].Count > 0); public bool IsReadyForNextFrame => GameStarted && pendingPackets.All(p => p.Value.Count > 0);
public void Tick() public void Tick()
{ {
@@ -201,10 +202,10 @@ namespace OpenRA.Network
var clientOrders = new List<ClientOrder>(); var clientOrders = new List<ClientOrder>();
foreach (var clientId in activeClients) foreach (var (clientId, clientPackets) in pendingPackets)
{ {
// The IsReadyForNextFrame check above guarantees that all clients have sent a packet // The IsReadyForNextFrame check above guarantees that all clients have sent a packet
var frameData = pendingPackets[clientId].Dequeue(); var frameData = clientPackets.Dequeue();
// Orders are synchronised by sending an initial FramesAhead set of empty packets // Orders are synchronised by sending an initial FramesAhead set of empty packets
// and then making sure that we enqueue and process exactly one packet for each player each tick. // and then making sure that we enqueue and process exactly one packet for each player each tick.

View File

@@ -153,6 +153,7 @@ namespace OpenRA.Network
public bool IsReady => State == ClientState.Ready; public bool IsReady => State == ClientState.Ready;
public bool IsInvalid => State == ClientState.Invalid; public bool IsInvalid => State == ClientState.Invalid;
public bool IsObserver => Slot == null; public bool IsObserver => Slot == null;
public bool IsBot => Bot != null;
// Linked to the online player database // Linked to the online player database
public string Fingerprint; public string Fingerprint;