diff --git a/OpenRA.Game/Network/Order.cs b/OpenRA.Game/Network/Order.cs
index 9bc9f3900b..4c037bfda6 100644
--- a/OpenRA.Game/Network/Order.cs
+++ b/OpenRA.Game/Network/Order.cs
@@ -11,6 +11,7 @@
using System;
using System.IO;
+using System.Linq;
using OpenRA.Network;
using OpenRA.Traits;
@@ -19,8 +20,7 @@ namespace OpenRA
[Flags]
enum OrderFields : byte
{
- TargetActor = 0x01,
- TargetLocation = 0x02,
+ Target = 0x01,
TargetString = 0x04,
Queued = 0x08,
ExtraLocation = 0x10,
@@ -40,8 +40,7 @@ namespace OpenRA
public readonly string OrderString;
public readonly Actor Subject;
public readonly bool Queued;
- public Actor TargetActor { get; private set; }
- public CPos TargetLocation { get; private set; }
+ public readonly Target Target;
public string TargetString;
public CPos ExtraLocation;
public uint ExtraData;
@@ -49,34 +48,35 @@ namespace OpenRA
public bool SuppressVisualFeedback;
public Actor VisualFeedbackTarget;
+ ///
+ /// DEPRECATED: Use Target instead.
+ ///
+ public Actor TargetActor { get { return Target.SerializableActor; } }
+
+ ///
+ /// DEPRECATED: Use Target instead.
+ ///
+ public CPos TargetLocation
+ {
+ get
+ {
+ return Target.SerializableCell.HasValue ? Target.SerializableCell.Value : CPos.Zero;
+ }
+ }
+
public Player Player { get { return Subject != null ? Subject.Owner : null; } }
- Order(string orderString, Actor subject,
- Actor targetActor, CPos targetLocation, string targetString, bool queued, CPos extraLocation, uint extraData)
+ Order(string orderString, Actor subject, Target target, string targetString, bool queued, CPos extraLocation, uint extraData)
{
OrderString = orderString;
Subject = subject;
- TargetActor = targetActor;
- TargetLocation = targetLocation;
+ Target = target;
TargetString = targetString;
Queued = queued;
ExtraLocation = extraLocation;
- ExtraData = extraData;
- }
- Order(string orderString, Actor subject, Target target, bool queued, CPos extraLocation, uint extraData)
- {
- var targetType = target.SerializableType;
-
- OrderString = orderString;
- Subject = subject;
- TargetActor = targetType == TargetType.Actor ? target.SerializableActor : null;
- TargetLocation = targetType == TargetType.Terrain ? target.SerializableCell.HasValue ?
- target.SerializableCell.Value : subject.World.Map.CellContaining(target.CenterPosition) : CPos.Zero;
- TargetString = null;
- Queued = queued;
- ExtraLocation = extraLocation;
- ExtraData = targetType == TargetType.FrozenActor ? target.FrozenActor.ID : extraData;
+ // TODO: remove FrozenActor ID after the various ResolveOrders that rely on it are updated
+ ExtraData = target.Type == TargetType.FrozenActor ? target.FrozenActor.ID : extraData;
}
public static Order Deserialize(World world, BinaryReader r)
@@ -90,21 +90,62 @@ namespace OpenRA
var subjectId = r.ReadUInt32();
var flags = (OrderFields)r.ReadByte();
- var targetActorId = flags.HasField(OrderFields.TargetActor) ? r.ReadUInt32() : uint.MaxValue;
- var targetLocation = (CPos)(flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero);
+ Actor subject = null;
+ if (world != null)
+ TryGetActorFromUInt(world, subjectId, out subject);
+
+ var target = Target.Invalid;
+ if (flags.HasField(OrderFields.Target))
+ {
+ switch ((TargetType)r.ReadByte())
+ {
+ case TargetType.Actor:
+ {
+ Actor targetActor;
+ if (world != null && TryGetActorFromUInt(world, r.ReadUInt32(), out targetActor))
+ target = Target.FromActor(targetActor);
+ break;
+ }
+
+ case TargetType.FrozenActor:
+ {
+ Actor playerActor;
+ if (world == null || !TryGetActorFromUInt(world, r.ReadUInt32(), out playerActor))
+ break;
+
+ var frozenLayer = playerActor.TraitOrDefault();
+ if (frozenLayer == null)
+ break;
+
+ var frozen = frozenLayer.FromID(r.ReadUInt32());
+ if (frozen != null)
+ target = Target.FromFrozenActor(frozen);
+
+ break;
+ }
+
+ case TargetType.Terrain:
+ {
+ if (world != null)
+ target = Target.FromCell(world, (CPos)r.ReadInt2());
+
+ break;
+ }
+ }
+ }
+
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
var queued = flags.HasField(OrderFields.Queued);
var extraLocation = (CPos)(flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero);
var extraData = flags.HasField(OrderFields.ExtraData) ? r.ReadUInt32() : 0;
if (world == null)
- return new Order(order, null, null, targetLocation, targetString, queued, extraLocation, extraData);
+ return new Order(order, null, target, targetString, queued, extraLocation, extraData);
- Actor subject, targetActor;
- if (!TryGetActorFromUInt(world, subjectId, out subject) || !TryGetActorFromUInt(world, targetActorId, out targetActor))
+ if (subject == null)
return null;
- return new Order(order, subject, targetActor, targetLocation, targetString, queued, extraLocation, extraData);
+ return new Order(order, subject, target, targetString, queued, extraLocation, extraData);
}
case 0xfe:
@@ -185,16 +226,16 @@ namespace OpenRA
// For scripting special powers
public Order()
- : this(null, null, null, CPos.Zero, null, false, CPos.Zero, 0) { }
+ : this(null, null, Target.Invalid, null, false, CPos.Zero, 0) { }
public Order(string orderString, Actor subject, bool queued)
- : this(orderString, subject, null, CPos.Zero, null, queued, CPos.Zero, 0) { }
+ : this(orderString, subject, Target.Invalid, null, queued, CPos.Zero, 0) { }
public Order(string orderString, Actor subject, Target target, bool queued)
- : this(orderString, subject, target, queued, CPos.Zero, 0) { }
+ : this(orderString, subject, target, null, queued, CPos.Zero, 0) { }
public Order(string orderstring, Order order)
- : this(orderstring, order.Subject, order.TargetActor, order.TargetLocation,
+ : this(orderstring, order.Subject, order.Target,
order.TargetString, order.Queued, order.ExtraLocation, order.ExtraData) { }
public byte[] Serialize()
@@ -218,7 +259,6 @@ namespace OpenRA
* varies: rest of order.
*/
default:
- // TODO: specific serializers for specific orders.
{
var ret = new MemoryStream();
var w = new BinaryWriter(ret);
@@ -227,8 +267,7 @@ namespace OpenRA
w.Write(UIntFromActor(Subject));
OrderFields fields = 0;
- if (TargetActor != null) fields |= OrderFields.TargetActor;
- if (TargetLocation != CPos.Zero) fields |= OrderFields.TargetLocation;
+ if (Target.SerializableType != TargetType.Invalid) fields |= OrderFields.Target;
if (TargetString != null) fields |= OrderFields.TargetString;
if (Queued) fields |= OrderFields.Queued;
if (ExtraLocation != CPos.Zero) fields |= OrderFields.ExtraLocation;
@@ -236,14 +275,30 @@ namespace OpenRA
w.Write((byte)fields);
- if (TargetActor != null)
- w.Write(UIntFromActor(TargetActor));
- if (TargetLocation != CPos.Zero)
- w.Write(TargetLocation);
+ if (Target.SerializableType != TargetType.Invalid)
+ w.Write((byte)Target.Type);
+
+ switch (Target.SerializableType)
+ {
+ case TargetType.Actor:
+ w.Write(UIntFromActor(Target.SerializableActor));
+ break;
+ case TargetType.FrozenActor:
+ w.Write(Target.FrozenActor.Owner.PlayerActor.ActorID);
+ w.Write(Target.FrozenActor.ID);
+ break;
+ case TargetType.Terrain:
+ // SerializableCell is guaranteed to be non-null if Type == TargetType.Terrain
+ w.Write(Target.SerializableCell.Value);
+ break;
+ }
+
if (TargetString != null)
w.Write(TargetString);
+
if (ExtraLocation != CPos.Zero)
w.Write(ExtraLocation);
+
if (ExtraData != 0)
w.Write(ExtraData);
diff --git a/OpenRA.Game/Traits/Target.cs b/OpenRA.Game/Traits/Target.cs
index 29a3a67bc5..e141fae7c1 100644
--- a/OpenRA.Game/Traits/Target.cs
+++ b/OpenRA.Game/Traits/Target.cs
@@ -15,7 +15,7 @@ using System.Linq;
namespace OpenRA.Traits
{
- public enum TargetType { Invalid, Actor, Terrain, FrozenActor }
+ public enum TargetType : byte { Invalid, Actor, Terrain, FrozenActor }
public struct Target
{
public static readonly Target[] None = { };
@@ -34,6 +34,10 @@ namespace OpenRA.Traits
return new Target { pos = w.Map.CenterOfSubCell(c, subCell), cell = c, type = TargetType.Terrain };
}
+ ///
+ /// DEPRECATED: Use Order.Target instead.
+ /// This method is kept to maintain compatibility with legacy code that may not understand TargetType.FrozenActor.
+ ///
public static Target FromOrder(World w, Order o)
{
return o.TargetActor != null