Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor server orders #19447

Merged
merged 1 commit into from Jul 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions OpenRA.Game/Network/Order.cs
Expand Up @@ -52,6 +52,9 @@ public sealed class Order
// Length of orders with type OrderType.SyncHash
public const int SyncHashOrderLength = 13;

// Length of orders with type OrderType.Disconnect
public const int DisconnectOrderLength = 5;

public readonly string OrderString;
public readonly Actor Subject;
public readonly bool Queued;
Expand Down
6 changes: 4 additions & 2 deletions OpenRA.Game/Network/OrderManager.cs
Expand Up @@ -131,8 +131,10 @@ public void TickImmediate()
return;

var frame = BitConverter.ToInt32(packet, 0);
if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect)
pendingPackets.Remove(clientId);
if (packet.Length == Order.DisconnectOrderLength + 4 && packet[4] == (byte)OrderType.Disconnect)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird that the server code treats OrderType as the first byte in the data payload rather than as part of the framing. Fixing this isn't trivial because the OrderType handling is split half between the network code and half inside Order, so best that we leave this to a future PR.

{
pendingPackets.Remove(BitConverter.ToInt32(packet, 5));
}
else if (packet.Length > 4 && packet[4] == (byte)OrderType.SyncHash)
{
if (packet.Length != 4 + Order.SyncHashOrderLength)
Expand Down
2 changes: 1 addition & 1 deletion OpenRA.Game/Network/ReplayConnection.cs
Expand Up @@ -115,7 +115,7 @@ public ReplayConnection(string replayFilename)
continue;

var packet = tmpPacketPair.Packet;
if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect)
if (packet.Length == Order.DisconnectOrderLength + 4 && packet[4] == (byte)OrderType.Disconnect)
{
var lastClientFrame = lastClientsFrame[client];
var lastFramePacket = BitConverter.GetBytes(lastClientFrame);
Expand Down
2 changes: 1 addition & 1 deletion OpenRA.Game/Server/ProtocolVersion.cs
Expand Up @@ -68,6 +68,6 @@ public static class ProtocolVersion
// The protocol for server and world orders
// This applies after the handshake has completed, and is provided to support
// alternative server implementations that wish to support multiple versions in parallel
public const int Orders = 12;
public const int Orders = 13;
}
}
54 changes: 39 additions & 15 deletions OpenRA.Game/Server/Server.cs
Expand Up @@ -482,7 +482,7 @@ void ValidateClient(Connection newConn, string data)
Log.Write("server", "{0} ({1}) has joined the game.", client.Name, newConn.EndPoint);

// Report to all other players
SendMessage($"{client.Name} has joined the game.", newConn);
SendMessage($"{client.Name} has joined the game.");

// Send initial ping
SendOrderTo(newConn, "Ping", Game.RunTime.ToString(CultureInfo.InvariantCulture));
Expand Down Expand Up @@ -737,12 +737,17 @@ void HandleSyncOrder(int frame, byte[] packet)

public void DispatchOrdersToClients(Connection conn, int frame, byte[] data)
{
var from = conn?.PlayerIndex ?? 0;
var from = conn.PlayerIndex;
teinarss marked this conversation as resolved.
Show resolved Hide resolved
var frameData = CreateFrame(from, frame, data);
foreach (var c in Conns.ToList())
if (c != conn && c.Validated)
DispatchFrameToClient(c, from, frameData);

RecordOrder(frame, data, from);
}

void RecordOrder(int frame, byte[] data, int from)
{
if (recorder != null)
{
recorder.ReceiveFrame(from, frame, data);
Expand All @@ -757,14 +762,31 @@ public void DispatchOrdersToClients(Connection conn, int frame, byte[] data)
}
}

public void DispatchServerOrdersToClients(Order order)
teinarss marked this conversation as resolved.
Show resolved Hide resolved
{
DispatchServerOrdersToClients(order.Serialize());
}

public void DispatchServerOrdersToClients(byte[] data)
teinarss marked this conversation as resolved.
Show resolved Hide resolved
{
var from = 0;
var frame = 0;
var frameData = CreateFrame(from, frame, data);
foreach (var c in Conns.ToList())
if (c.Validated)
DispatchFrameToClient(c, from, frameData);

RecordOrder(frame, data, from);
}

public void DispatchOrders(Connection conn, int frame, byte[] data)
{
if (frame == 0 && conn != null)
if (frame == 0)
InterpretServerOrders(conn, data);
else
DispatchOrdersToClients(conn, frame, data);

if (GameSave != null && conn != null)
if (GameSave != null)
GameSave.DispatchOrders(conn, frame, data);
}

Expand All @@ -791,9 +813,9 @@ public void SendOrderTo(Connection conn, string order, string data)
DispatchOrdersToClient(conn, 0, 0, Order.FromTargetString(order, data, true).Serialize());
}

public void SendMessage(string text, Connection conn = null)
public void SendMessage(string text)
{
DispatchOrdersToClients(conn, 0, Order.FromTargetString("Message", text, true).Serialize());
DispatchServerOrdersToClients(Order.FromTargetString("Message", text, true));

if (Type == ServerType.Dedicated)
Console.WriteLine($"[{DateTime.Now.ToString(Settings.TimestampFormat)}] {text}");
Expand Down Expand Up @@ -903,7 +925,7 @@ void InterpretServerOrder(Connection conn, Order o)
Directory.CreateDirectory(baseSavePath);

GameSave.Save(Path.Combine(baseSavePath, filename));
DispatchOrdersToClients(null, 0, Order.FromTargetString("GameSaved", filename, true).Serialize());
DispatchServerOrdersToClients(Order.FromTargetString("GameSaved", filename, true));
}

break;
Expand Down Expand Up @@ -1039,7 +1061,10 @@ public void DropClient(Connection toDrop)
}
}

DispatchOrders(toDrop, toDrop.MostRecentFrame, new[] { (byte)OrderType.Disconnect });
var disconnectPacket = new MemoryStream(5);
disconnectPacket.WriteByte((byte)OrderType.Disconnect);
disconnectPacket.Write(toDrop.PlayerIndex);
DispatchServerOrdersToClients(disconnectPacket.ToArray());

// All clients have left: clean up
if (!Conns.Any(c => c.Validated))
Expand All @@ -1061,7 +1086,7 @@ public void SyncLobbyInfo()
lock (LobbyInfo)
{
if (State == ServerState.WaitingPlayers) // Don't do this while the game is running, it breaks things!
DispatchOrders(null, 0, Order.FromTargetString("SyncInfo", LobbyInfo.Serialize(), true).Serialize());
DispatchServerOrdersToClients(Order.FromTargetString("SyncInfo", LobbyInfo.Serialize(), true));

foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>())
t.LobbyInfoSynced(this);
Expand All @@ -1078,7 +1103,7 @@ public void SyncLobbyClients()
// TODO: Only need to sync the specific client that has changed to avoid conflicts!
var clientData = LobbyInfo.Clients.Select(client => client.Serialize()).ToList();

DispatchOrders(null, 0, Order.FromTargetString("SyncLobbyClients", clientData.WriteToString(), true).Serialize());
DispatchServerOrdersToClients(Order.FromTargetString("SyncLobbyClients", clientData.WriteToString(), true));

foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>())
t.LobbyInfoSynced(this);
Expand All @@ -1095,7 +1120,7 @@ public void SyncLobbySlots()
// TODO: Don't sync all the slots if just one changed!
var slotData = LobbyInfo.Slots.Select(slot => slot.Value.Serialize()).ToList();

DispatchOrders(null, 0, Order.FromTargetString("SyncLobbySlots", slotData.WriteToString(), true).Serialize());
DispatchServerOrdersToClients(Order.FromTargetString("SyncLobbySlots", slotData.WriteToString(), true));

foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>())
t.LobbyInfoSynced(this);
Expand All @@ -1111,7 +1136,7 @@ public void SyncLobbyGlobalSettings()
{
var sessionData = new List<MiniYamlNode> { LobbyInfo.GlobalSettings.Serialize() };

DispatchOrders(null, 0, Order.FromTargetString("SyncLobbyGlobalSettings", sessionData.WriteToString(), true).Serialize());
DispatchServerOrdersToClients(Order.FromTargetString("SyncLobbyGlobalSettings", sessionData.WriteToString(), true));

foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>())
t.LobbyInfoSynced(this);
Expand All @@ -1126,7 +1151,7 @@ public void SyncClientPing()
var clientPings = LobbyInfo.ClientPings.Select(ping => ping.Serialize()).ToList();

// Note that syncing pings doesn't trigger INotifySyncLobbyInfo
DispatchOrders(null, 0, Order.FromTargetString("SyncClientPings", clientPings.WriteToString(), true).Serialize());
DispatchServerOrdersToClients(Order.FromTargetString("SyncClientPings", clientPings.WriteToString(), true));
}
}

Expand Down Expand Up @@ -1194,8 +1219,7 @@ public void StartGame()
}
}

DispatchOrders(null, 0,
Order.FromTargetString("StartGame", startGameData, true).Serialize());
DispatchServerOrdersToClients(Order.FromTargetString("StartGame", startGameData, true));

foreach (var t in serverTraits.WithInterface<IStartGame>())
t.GameStarted(this);
Expand Down