Client LuaCsForBarotrauma
BarotraumaShared/SharedSource/Networking/OrderChatMessage.cs
1 using Microsoft.Xna.Framework;
2 using System;
3 
4 namespace Barotrauma.Networking
5 {
6  partial class OrderChatMessage : ChatMessage
7  {
8  public readonly Order Order;
9 
10  //who was this order given to
11  public readonly Character TargetCharacter;
12 
13  //which entity is this order referring to (hull, reactor, railgun controller, etc)
15 
16  //additional instructions (power up, fire at will, etc)
17  public Identifier OrderOption => Order.Option;
18 
20 
25 
26  public bool IsNewOrder { get; }
27 
32  public OrderChatMessage(Order order, Character targetCharacter, Character sender, bool isNewOrder = true)
33  : this(order,
34  order?.GetChatMessage(targetCharacter?.Name,
35  (order.TargetEntity as Hull ?? sender?.CurrentHull)?.DisplayName?.Value,
36  givingOrderToSelf: targetCharacter == sender, orderOption: order.Option, isNewOrder: isNewOrder),
37  targetCharacter, sender, isNewOrder)
38  {
39 
40  }
41 
42  public OrderChatMessage(Order order, string text, Character targetCharacter, Entity sender, bool isNewOrder = true)
43  : base(NameFromEntityOrNull(sender), text, ChatMessageType.Order, sender, GameMain.NetworkMember.ConnectedClients.Find(c => c.Character == sender))
44  {
45  Order = order;
46  TargetCharacter = targetCharacter;
47  IsNewOrder = isNewOrder;
48  }
49 
50  public static string NameFromEntityOrNull(Entity entity)
51  => entity switch
52  {
53  null => null,
54  Character character => character.Name,
55  Item it => it.Name,
56  _ => throw new ArgumentException("Entity is not a character or item", nameof(entity))
57  };
58 
59  public static void WriteOrder(IWriteMessage msg, Order order, Entity targetCharacter, bool isNewOrder)
60  {
62  msg.WriteUInt16(targetCharacter == null ? (UInt16)0 : targetCharacter.ID);
63  msg.WriteUInt16(order.TargetSpatialEntity is Entity ? (order.TargetEntity as Entity).ID : (UInt16)0);
64 
65  // The option of a Dismiss order is written differently so we know what order we target
66  // now that the game supports multiple current orders simultaneously
67  if (!order.IsDismissal)
68  {
69  msg.WriteByte((byte)order.Options.IndexOf(order.Option));
70  }
71  else
72  {
73  if (order.Option != Identifier.Empty)
74  {
75  msg.WriteBoolean(true);
76  string[] dismissedOrder = order.Option.Value.Split('.');
77  msg.WriteByte((byte)dismissedOrder.Length);
78  if (dismissedOrder.Length > 0)
79  {
80  Identifier dismissedOrderIdentifier = dismissedOrder[0].ToIdentifier();
81  var orderPrefab = OrderPrefab.Prefabs[dismissedOrderIdentifier];
82  msg.WriteIdentifier(dismissedOrderIdentifier);
83  if (dismissedOrder.Length > 1)
84  {
85  Identifier dismissedOrderOption = dismissedOrder[1].ToIdentifier();
86  msg.WriteByte((byte)orderPrefab.Options.IndexOf(dismissedOrderOption));
87  }
88  }
89  }
90  else
91  {
92  // If the order option is not specified for a Dismiss order,
93  // we dismiss all current orders for the character
94  msg.WriteBoolean(false);
95  }
96  }
97 
98  msg.WriteByte((byte)order.ManualPriority);
99  msg.WriteByte((byte)order.TargetType);
100  if (order.TargetType == Order.OrderTargetType.Position && order.TargetSpatialEntity is OrderTarget orderTarget)
101  {
102  msg.WriteBoolean(true);
103  msg.WriteSingle(orderTarget.Position.X);
104  msg.WriteSingle(orderTarget.Position.Y);
105  msg.WriteUInt16(orderTarget.Hull == null ? (UInt16)0 : orderTarget.Hull.ID);
106  }
107  else
108  {
109  msg.WriteBoolean(false);
110  if (order.TargetType == Order.OrderTargetType.WallSection)
111  {
112  msg.WriteByte((byte)(order.WallSectionIndex ?? 0));
113  }
114  }
115 
116  msg.WriteBoolean(isNewOrder);
117  }
118 
119  private void WriteOrder(IWriteMessage msg)
120  {
122  }
123 
124  public readonly struct OrderMessageInfo
125  {
126  public Identifier OrderIdentifier { get; }
128  public Identifier OrderOption { get; }
129  public int? OrderOptionIndex { get; }
130  public Character TargetCharacter { get; }
132  public Entity TargetEntity { get; }
133  public OrderTarget TargetPosition { get; }
134  public int? WallSectionIndex { get; }
135  public int Priority { get; }
136  public bool IsNewOrder { get; }
137 
138  public OrderMessageInfo(Identifier orderIdentifier, Identifier orderOption, int? orderOptionIndex, Character targetCharacter,
139  Order.OrderTargetType targetType, Entity targetEntity, OrderTarget targetPosition, int? wallSectionIndex, int orderPriority, bool isNewOrder)
140  {
141  OrderIdentifier = orderIdentifier;
142  OrderOption = orderOption;
143  OrderOptionIndex = orderOptionIndex;
144  TargetCharacter = targetCharacter;
145  TargetType = targetType;
146  TargetEntity = targetEntity;
147  TargetPosition = targetPosition;
148  WallSectionIndex = wallSectionIndex;
149  Priority = orderPriority;
150  IsNewOrder = isNewOrder;
151  }
152  }
153 
155  {
156  Identifier orderIdentifier = msg.ReadIdentifier();
157  ushort targetCharacterId = msg.ReadUInt16();
158  Character targetCharacter = targetCharacterId != Entity.NullEntityID ? Entity.FindEntityByID(targetCharacterId) as Character : null;
159  ushort targetEntityId = msg.ReadUInt16();
160  Entity targetEntity = targetEntityId != Entity.NullEntityID ? Entity.FindEntityByID(targetEntityId) : null;
161 
162  int? optionIndex = null;
163  Identifier orderOption = Identifier.Empty;
164  // The option of a Dismiss order is written differently so we know what order we target
165  // now that the game supports multiple current orders simultaneously
166  if (orderIdentifier != Identifier.Empty)
167  {
168  var orderPrefab = OrderPrefab.Prefabs[orderIdentifier];
169  if (!orderPrefab.IsDismissal)
170  {
171  optionIndex = msg.ReadByte();
172  }
173  // Does the dismiss order have a specified target?
174  else if (msg.ReadBoolean())
175  {
176  int identifierCount = msg.ReadByte();
177  if (identifierCount > 0)
178  {
179  Identifier dismissedOrderIdentifier = msg.ReadIdentifier();
180  OrderPrefab dismissedOrderPrefab = null;
181  if (dismissedOrderIdentifier != Identifier.Empty)
182  {
183  dismissedOrderPrefab = OrderPrefab.Prefabs[dismissedOrderIdentifier];
184  orderOption = dismissedOrderPrefab.Identifier;
185  }
186  if (identifierCount > 1)
187  {
188  int dismissedOrderOptionIndex = msg.ReadByte();
189  if (dismissedOrderPrefab != null)
190  {
191  var options = dismissedOrderPrefab.Options;
192  if (options != null && dismissedOrderOptionIndex >= 0 && dismissedOrderOptionIndex < options.Length)
193  {
194  orderOption = $"{orderOption.Value}.{options[dismissedOrderOptionIndex]}".ToIdentifier();
195  }
196  }
197  }
198  }
199  }
200  }
201  else
202  {
203  optionIndex = msg.ReadByte();
204  }
205 
206  int orderPriority = msg.ReadByte();
207  OrderTarget orderTargetPosition = null;
208  Order.OrderTargetType orderTargetType = (Order.OrderTargetType)msg.ReadByte();
209  int? wallSectionIndex = null;
210  if (msg.ReadBoolean())
211  {
212  float x = msg.ReadSingle();
213  float y = msg.ReadSingle();
214  ushort hullId = msg.ReadUInt16();
215  var hull = hullId != Entity.NullEntityID ? Entity.FindEntityByID(hullId) as Hull : null;
216  orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, creatingFromExistingData: true);
217  }
218  else if (orderTargetType == Order.OrderTargetType.WallSection)
219  {
220  wallSectionIndex = msg.ReadByte();
221  }
222 
223  bool isNewOrder = msg.ReadBoolean();
224  return new OrderMessageInfo(orderIdentifier, orderOption, optionIndex, targetCharacter,
225  orderTargetType, targetEntity, orderTargetPosition, wallSectionIndex, orderPriority, isNewOrder);
226  }
227  }
228 }
const ushort NullEntityID
Definition: Entity.cs:14
readonly ushort ID
Unique, but non-persistent identifier. Stays the same if the entities are created in the exactly same...
Definition: Entity.cs:43
static Entity FindEntityByID(ushort ID)
Find an entity based on the ID
Definition: Entity.cs:204
override string Name
Note that this is not a LocalizedString instance, just the current name of the item as a string....
OrderChatMessage(Order order, string text, Character targetCharacter, Entity sender, bool isNewOrder=true)
static void WriteOrder(IWriteMessage msg, Order order, Entity targetCharacter, bool isNewOrder)
OrderChatMessage(Order order, Character targetCharacter, Character sender, bool isNewOrder=true)
Same as calling OrderChatMessage.OrderChatMessage(Order, string, int, string, ISpatialEntity,...
static string NameFromEntityOrNull(Entity entity)
readonly Entity TargetEntity
Definition: Order.cs:495
ISpatialEntity??? TargetSpatialEntity
Note this property doesn't return the follow target of the Follow objective, as expected!
Definition: Order.cs:509
ref readonly ImmutableArray< Identifier > Options
Definition: Order.cs:546
bool IsDismissal
Definition: Order.cs:487
readonly? int WallSectionIndex
Definition: Order.cs:536
readonly Identifier Option
Definition: Order.cs:482
readonly int ManualPriority
Definition: Order.cs:483
readonly OrderPrefab Prefab
Definition: Order.cs:481
readonly OrderTargetType TargetType
Definition: Order.cs:535
static readonly PrefabCollection< OrderPrefab > Prefabs
Definition: Order.cs:41
readonly ImmutableArray< Identifier > Options
Definition: Order.cs:106
readonly Identifier Identifier
Definition: Prefab.cs:34
void WriteIdentifier(Identifier val)
OrderMessageInfo(Identifier orderIdentifier, Identifier orderOption, int? orderOptionIndex, Character targetCharacter, Order.OrderTargetType targetType, Entity targetEntity, OrderTarget targetPosition, int? wallSectionIndex, int orderPriority, bool isNewOrder)