diff --git a/OpenRA.Game/Network/Order.cs b/OpenRA.Game/Network/Order.cs index ef683cbf18..cd70a06504 100644 --- a/OpenRA.Game/Network/Order.cs +++ b/OpenRA.Game/Network/Order.cs @@ -156,7 +156,18 @@ namespace OpenRA else { var pos = new WPos(r.ReadInt32(), r.ReadInt32(), r.ReadInt32()); - target = Target.FromPos(pos); + + var numberOfTerrainPositions = r.ReadByte(); + if (numberOfTerrainPositions == 0) + target = Target.FromPos(pos); + else + { + var terrainPositions = new WPos[numberOfTerrainPositions]; + for (var i = 0; i < numberOfTerrainPositions; i++) + terrainPositions[i] = new WPos(r.ReadInt32(), r.ReadInt32(), r.ReadInt32()); + + target = Target.FromSerializedTerrainPosition(pos, terrainPositions); + } } break; @@ -388,6 +399,21 @@ namespace OpenRA w.Write(targetState.Pos.X); w.Write(targetState.Pos.Y); w.Write(targetState.Pos.Z); + + // Don't send extra data over the network that will be restored by the Target ctor + var terrainPositions = targetState.TerrainPositions.Length; + if (terrainPositions == 1 && targetState.TerrainPositions[0] == targetState.Pos) + w.Write((byte)0); + else + { + w.Write((byte)terrainPositions); + foreach (var position in targetState.TerrainPositions) + { + w.Write(position.X); + w.Write(position.Y); + w.Write(position.Z); + } + } } break; diff --git a/OpenRA.Game/Server/ProtocolVersion.cs b/OpenRA.Game/Server/ProtocolVersion.cs index 91322c97cd..3e96651c1a 100644 --- a/OpenRA.Game/Server/ProtocolVersion.cs +++ b/OpenRA.Game/Server/ProtocolVersion.cs @@ -77,6 +77,6 @@ namespace OpenRA.Server // 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 = 20; + public const int Orders = 21; } } diff --git a/OpenRA.Game/Traits/Target.cs b/OpenRA.Game/Traits/Target.cs index c7ab5afb24..74741b0677 100644 --- a/OpenRA.Game/Traits/Target.cs +++ b/OpenRA.Game/Traits/Target.cs @@ -288,7 +288,8 @@ namespace OpenRA.Traits // Expose internal state for serialization by the orders code *only* internal static Target FromSerializedActor(Actor a, int generation) { return a != null ? new Target(a, generation) : Invalid; } - internal (TargetType Type, Actor Actor, int Generation, CPos? Cell, SubCell? SubCell, WPos Pos) SerializableState => - (type, Actor, generation, cell, subCell, terrainCenterPosition); + internal static Target FromSerializedTerrainPosition(WPos centerPosition, WPos[] terrainPositions) { return new Target(centerPosition, terrainPositions); } + internal (TargetType Type, Actor Actor, int Generation, CPos? Cell, SubCell? SubCell, WPos Pos, WPos[] TerrainPositions) SerializableState => + (type, Actor, generation, cell, subCell, terrainCenterPosition, terrainPositions); } }