Client LuaCsForBarotrauma
BarotraumaClient/ClientSource/Items/Components/Signal/ConnectionPanel.cs
2 using Barotrauma.Sounds;
3 using Microsoft.Xna.Framework;
4 using Microsoft.Xna.Framework.Graphics;
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 
10 {
11  partial class ConnectionPanel : ItemComponent, IServerSerializable, IClientSerializable
12  {
13  public static bool DebugWiringMode;
14  public static double DebugWiringEnabledUntil;
15  public static bool ShouldDebugDrawWiring => DebugWiringMode || Timing.TotalTimeUnpaused < DebugWiringEnabledUntil;
16 
17  //how long the rewiring sound plays after doing changes to the wiring
18  const float RewireSoundDuration = 5.0f;
19 
20  public static Wire HighlightedWire;
21 
22  private SoundChannel rewireSoundChannel;
23  private float rewireSoundTimer;
24 
25  private Point originalMaxSize;
26  private Vector2 originalRelativeSize;
27 
28  private GUIComponent dragArea;
29 
30  public override bool RecreateGUIOnResolutionChange => true;
31 
32  partial void InitProjSpecific()
33  {
34  if (GuiFrame == null) { return; }
35  originalMaxSize = GuiFrame.RectTransform.MaxSize;
36  originalRelativeSize = GuiFrame.RectTransform.RelativeSize;
37  CreateGUI();
38  }
39 
40  protected override void CreateGUI()
41  {
42  if (GuiFrame == null) { return; }
43 
44  CheckForLabelOverlap();
45  var content = new GUICustomComponent(new RectTransform(Vector2.One, GuiFrame.RectTransform), DrawConnections, null)
46  {
47  UserData = this
48  };
50 
51  //prevents inputs from going through the GUICustomComponent to the drag handle
52  dragArea = new GUIFrame(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center)
53  { AbsoluteOffset = GUIStyle.ItemFrameOffset }, style: null);
54  }
55 
56  public void TriggerRewiringSound()
57  {
58  rewireSoundTimer = RewireSoundDuration;
59  }
60 
61  partial void UpdateProjSpecific(float deltaTime)
62  {
63  foreach (var _ in DisconnectedWires)
64  {
65  if (Rand.Range(0.0f, 500.0f) < 1.0f)
66  {
67  SoundPlayer.PlaySound("zap", item.WorldPosition, hullGuess: item.CurrentHull);
68  Vector2 baseVel = new Vector2(0.0f, -100.0f);
69  for (int i = 0; i < 5; i++)
70  {
71  var particle = GameMain.ParticleManager.CreateParticle("spark", item.WorldPosition,
72  baseVel + Rand.Vector(100.0f), 0.0f, item.CurrentHull);
73  if (particle != null) { particle.Size *= Rand.Range(0.5f, 1.0f); }
74  }
75  }
76  }
77 
78  rewireSoundTimer -= deltaTime;
79  if (user != null && user.SelectedItem == item && rewireSoundTimer > 0.0f)
80  {
81  if (rewireSoundChannel == null || !rewireSoundChannel.IsPlaying)
82  {
83  rewireSoundChannel = SoundPlayer.PlaySound("rewire", item.WorldPosition, hullGuess: item.CurrentHull);
84  }
85  }
86  else
87  {
88  rewireSoundChannel?.FadeOutAndDispose();
89  rewireSoundChannel = null;
90  rewireSoundTimer = 0.0f;
91  }
92  }
93 
94  public override void Move(Vector2 amount, bool ignoreContacts = false)
95  {
96  if (item.Submarine == null || item.Submarine.Loading || Screen.Selected != GameMain.SubEditorScreen) { return; }
97  MoveConnectedWires(amount);
98  }
99 
100  public override bool ShouldDrawHUD(Character character)
101  {
102  return character == Character.Controlled && character == user && (character.SelectedItem == item || character.SelectedSecondaryItem == item);
103  }
104 
105  public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
106  {
107  if (character != Character.Controlled || character != user || character.SelectedItem != item) { return; }
108 
109  if (HighlightedWire != null)
110  {
114  }
115  }
116 
117  private void DrawConnections(SpriteBatch spriteBatch, GUICustomComponent container)
118  {
119  if (user != Character.Controlled || user == null) { return; }
120 
121  HighlightedWire = null;
122  Connection.DrawConnections(spriteBatch, this, dragArea.Rect, user, out (Vector2 tooltipPos, LocalizedString text) tooltip);
123  foreach (UISprite sprite in GUIStyle.GetComponentStyle("ConnectionPanelFront").Sprites[GUIComponent.ComponentState.None])
124  {
125  sprite.Draw(spriteBatch, GuiFrame.Rect, Color.White, SpriteEffects.None);
126  }
127  if (!tooltip.text.IsNullOrEmpty())
128  {
129  GUIComponent.DrawToolTip(spriteBatch, tooltip.text, tooltip.tooltipPos);
130  }
131  }
132 
133  private void CheckForLabelOverlap()
134  {
135  GuiFrame.RectTransform.MaxSize = originalMaxSize;
136  GuiFrame.RectTransform.Resize(originalRelativeSize);
137  if (Connection.CheckConnectionLabelOverlap(this, out Point newRectSize))
138  {
139  int xCenter = (int)(GameMain.GraphicsWidth / 2.0f);
140  int maxNewWidth = 2 * Math.Min(xCenter - HUDLayoutSettings.CrewArea.Right, xCenter - HUDLayoutSettings.ChatBoxArea.Right);
141  int yCenter = (int)(GameMain.GraphicsHeight / 2.0f);
142  int maxNewHeight = 2 * Math.Min(yCenter - HUDLayoutSettings.MessageAreaTop.Bottom, HUDLayoutSettings.InventoryTopY - yCenter);
143  // Make sure we don't expand the panel interface too much
144  newRectSize = new Point(Math.Min(newRectSize.X, maxNewWidth), Math.Min(newRectSize.Y, maxNewHeight));
145  GuiFrame.RectTransform.MaxSize = new Point(
146  Math.Max(GuiFrame.RectTransform.MaxSize.X, newRectSize.X),
147  Math.Max(GuiFrame.RectTransform.MaxSize.Y, newRectSize.Y));
148  GuiFrame.RectTransform.Resize(newRectSize);
149  }
150  }
151 
152  public void ClientEventRead(IReadMessage msg, float sendingTime)
153  {
155  {
156  //delay reading the state until midround syncing is done
157  //because some of the wires connected to the panel may not exist yet
158  long msgStartPos = msg.BitPosition;
159  msg.ReadUInt16(); //user ID
160  byte connectionCount = msg.ReadByte();
161  for (int i = 0; i < connectionCount; i++)
162  {
163  uint wireCount = msg.ReadVariableUInt32();
164  for (int j = 0; j < wireCount; j++)
165  {
166  msg.ReadUInt16();
167  }
168  }
169  ushort disconnectedWireCount = msg.ReadUInt16();
170  for (int i = 0; i < disconnectedWireCount; i++)
171  {
172  msg.ReadUInt16();
173  }
174  int msgLength = (int)(msg.BitPosition - msgStartPos);
175  msg.BitPosition = (int)msgStartPos;
176  StartDelayedCorrection(msg.ExtractBits(msgLength), sendingTime, waitForMidRoundSync: true);
177  }
178  else
179  {
180  //don't trigger rewiring sounds if the rewiring is being done by the local user (in that case we'll trigger it locally)
181  if (Character.Controlled == null || user != Character.Controlled) { TriggerRewiringSound(); }
182  ApplyRemoteState(msg);
183  }
184  }
185 
186  private void ApplyRemoteState(IReadMessage msg)
187  {
188  List<Wire> prevWires = Connections.SelectMany(c => c.Wires).ToList();
189 
190  ushort userID = msg.ReadUInt16();
191 
192  if (userID == 0)
193  {
194  user = null;
195  }
196  else
197  {
198  user = Entity.FindEntityByID(userID) as Character;
199  base.IsActive = true;
200  }
201 
202  foreach (Connection connection in Connections)
203  {
204  connection.ClearConnections();
205  }
206 
207  byte connectionCount = msg.ReadByte();
208  for (int i = 0; i < connectionCount; i++)
209  {
210  HashSet<Wire> newWires = new HashSet<Wire>();
211  uint wireCount = msg.ReadVariableUInt32();
212  for (int j = 0; j < wireCount; j++)
213  {
214  ushort wireId = msg.ReadUInt16();
215  if (Entity.FindEntityByID(wireId) is not Item wireItem) { continue; }
216  Wire wireComponent = wireItem.GetComponent<Wire>();
217  if (wireComponent == null) { continue; }
218 
219  newWires.Add(wireComponent);
220  }
221 
222  //this may happen if the item has been deleted server-side at the point the server is writing this event to the client
223  if (i >= Connections.Count) { continue; }
224 
225  var connection = Connections[i];
226  Wire[] oldWires = connection.Wires.Where(w => !newWires.Contains(w)).ToArray();
227  foreach (var wire in oldWires)
228  {
229  connection.DisconnectWire(wire);
230  }
231 
232  foreach (var wire in newWires.Where(w => !connection.Wires.Contains(w)).ToArray())
233  {
234  connection.ConnectWire(wire);
235  wire.TryConnect(connection, false);
236  }
237  }
238 
239  List<Wire> previousDisconnectedWires = new List<Wire>(DisconnectedWires);
240  DisconnectedWires.Clear();
241  ushort disconnectedWireCount = msg.ReadUInt16();
242  for (int i = 0; i < disconnectedWireCount; i++)
243  {
244  ushort wireId = msg.ReadUInt16();
245  if (!(Entity.FindEntityByID(wireId) is Item wireItem)) { continue; }
246  Wire wireComponent = wireItem.GetComponent<Wire>();
247  if (wireComponent == null) { continue; }
248  DisconnectedWires.Add(wireComponent);
249  base.IsActive = true;
250  }
251 
252  foreach (Wire wire in prevWires)
253  {
254  bool connected = wire.Connections[0] != null || wire.Connections[1] != null;
255  if (!connected)
256  {
257  foreach (Item item in Item.ItemList)
258  {
259  var connectionPanel = item.GetComponent<ConnectionPanel>();
260  if (connectionPanel != null && connectionPanel.DisconnectedWires.Contains(wire))
261  {
262  connected = true;
263  break;
264  }
265  }
266  }
267  if (wire.Item.ParentInventory == null && !connected)
268  {
269  wire.Item.Drop(null);
270  }
271  }
272 
273  foreach (Wire disconnectedWire in previousDisconnectedWires)
274  {
275  if (disconnectedWire.Connections[0] == null &&
276  disconnectedWire.Connections[1] == null &&
277  !DisconnectedWires.Contains(disconnectedWire))
278  {
279  disconnectedWire.Item.Drop(dropper: null);
280  }
281  }
282  }
283  }
284 }
Item????????? SelectedItem
The primary selected item. It can be any device that character interacts with. This excludes items li...
Item SelectedSecondaryItem
The secondary selected item. It's an item other than a device (see SelectedItem), e....
Submarine Submarine
Definition: Entity.cs:53
static Entity FindEntityByID(ushort ID)
Find an entity based on the ID
Definition: Entity.cs:204
virtual Rectangle Rect
void DrawToolTip(SpriteBatch spriteBatch)
Creates and draws a tooltip.
RectTransform RectTransform
GUIComponent that can be used to render custom content on the UI
static SubEditorScreen SubEditorScreen
Definition: GameMain.cs:68
static ParticleManager ParticleManager
Definition: GameMain.cs:101
static GameClient Client
Definition: GameMain.cs:188
static readonly List< Item > ItemList
readonly HashSet< Wire > DisconnectedWires
Wires that have been disconnected from the panel, but not removed completely (visible at the bottom o...
override void CreateGUI()
Overload this method and implement. The method is automatically called when the resolution changes.
override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
void StartDelayedCorrection(IReadMessage buffer, float sendingTime, bool waitForMidRoundSync=false)
Vector2 RelativeSize
Relative to the parent rect.
void Resize(Point absoluteSize, bool resizeChildren=true)
Point?? MaxSize
Max size in pixels. Does not affect scaling.
void Draw(SpriteBatch spriteBatch, RectangleF rect, Color color, SpriteEffects spriteEffects=SpriteEffects.None, Vector2? uvOffset=null)
Interface for entities that the clients can send events to the server
Interface for entities that the server can send events to the clients