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