1
0

DeviceNet.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. using Content.Server.DeviceNetwork.Components;
  2. using Robust.Shared.Random;
  3. using static Content.Server.DeviceNetwork.Components.DeviceNetworkComponent;
  4. namespace Content.Server.DeviceNetwork;
  5. /// <summary>
  6. /// Data class for storing and retrieving information about devices connected to a device network.
  7. /// </summary>
  8. /// <remarks>
  9. /// This basically just makes <see cref="DeviceNetworkComponent"/> accessible via their addresses and frequencies on
  10. /// some network.
  11. /// </remarks>
  12. public sealed class DeviceNet
  13. {
  14. /// <summary>
  15. /// Devices, mapped by their "Address", which is just an int that gets converted to Hex for displaying to users.
  16. /// This dictionary contains all devices connected to this network, though they may not be listening to any
  17. /// specific frequency.
  18. /// </summary>
  19. public readonly Dictionary<string, DeviceNetworkComponent> Devices = new();
  20. /// <summary>
  21. /// Devices listening on a given frequency.
  22. /// </summary>
  23. public readonly Dictionary<uint, HashSet<DeviceNetworkComponent>> ListeningDevices = new();
  24. /// <summary>
  25. /// Devices listening to all packets on a given frequency, regardless of the intended recipient.
  26. /// </summary>
  27. public readonly Dictionary<uint, HashSet<DeviceNetworkComponent>> ReceiveAllDevices = new();
  28. private readonly IRobustRandom _random;
  29. public readonly int NetId;
  30. public DeviceNet(int netId, IRobustRandom random)
  31. {
  32. _random = random;
  33. NetId = netId;
  34. }
  35. /// <summary>
  36. /// Add a device to the network.
  37. /// </summary>
  38. public bool Add(DeviceNetworkComponent device)
  39. {
  40. if (device.CustomAddress)
  41. {
  42. // Only add if the device's existing address is available.
  43. if (!Devices.TryAdd(device.Address, device))
  44. return false;
  45. }
  46. else
  47. {
  48. // Randomly generate a new address if the existing random one is invalid. Otherwise, keep the existing address
  49. if (string.IsNullOrWhiteSpace(device.Address) || Devices.ContainsKey(device.Address))
  50. device.Address = GenerateValidAddress(device.Prefix);
  51. Devices[device.Address] = device;
  52. }
  53. if (device.ReceiveFrequency is not uint freq)
  54. return true;
  55. if (!ListeningDevices.TryGetValue(freq, out var devices))
  56. ListeningDevices[freq] = devices = new();
  57. devices.Add(device);
  58. if (!device.ReceiveAll)
  59. return true;
  60. if (!ReceiveAllDevices.TryGetValue(freq, out var receiveAlldevices))
  61. ReceiveAllDevices[freq] = receiveAlldevices = new();
  62. receiveAlldevices.Add(device);
  63. return true;
  64. }
  65. /// <summary>
  66. /// Remove a device from the network.
  67. /// </summary>
  68. public bool Remove(DeviceNetworkComponent device)
  69. {
  70. if (device.Address == null || !Devices.Remove(device.Address))
  71. return false;
  72. if (device.ReceiveFrequency is not uint freq)
  73. return true;
  74. if (ListeningDevices.TryGetValue(freq, out var listening))
  75. {
  76. listening.Remove(device);
  77. if (listening.Count == 0)
  78. ListeningDevices.Remove(freq);
  79. }
  80. if (device.ReceiveAll && ReceiveAllDevices.TryGetValue(freq, out var receiveAll))
  81. {
  82. receiveAll.Remove(device);
  83. if (receiveAll.Count == 0)
  84. ListeningDevices.Remove(freq);
  85. }
  86. return true;
  87. }
  88. /// <summary>
  89. /// Give an existing device a new randomly generated address. Useful if the device's address prefix was updated
  90. /// and they want a new address to reflect that, or something like that.
  91. /// </summary>
  92. public bool RandomizeAddress(string oldAddress, string? prefix = null)
  93. {
  94. if (!Devices.Remove(oldAddress, out var device))
  95. return false;
  96. device.Address = GenerateValidAddress(prefix ?? device.Prefix);
  97. device.CustomAddress = false;
  98. Devices[device.Address] = device;
  99. return true;
  100. }
  101. /// <summary>
  102. /// Update the address of an existing device.
  103. /// </summary>
  104. public bool UpdateAddress(string oldAddress, string newAddress)
  105. {
  106. if (Devices.ContainsKey(newAddress))
  107. return false;
  108. if (!Devices.Remove(oldAddress, out var device))
  109. return false;
  110. device.Address = newAddress;
  111. device.CustomAddress = true;
  112. Devices[newAddress] = device;
  113. return true;
  114. }
  115. /// <summary>
  116. /// Make an existing network device listen to a new frequency.
  117. /// </summary>
  118. public bool UpdateReceiveFrequency(string address, uint? newFrequency)
  119. {
  120. if (!Devices.TryGetValue(address, out var device))
  121. return false;
  122. if (device.ReceiveFrequency == newFrequency)
  123. return true;
  124. if (device.ReceiveFrequency is uint freq)
  125. {
  126. if (ListeningDevices.TryGetValue(freq, out var listening))
  127. {
  128. listening.Remove(device);
  129. if (listening.Count == 0)
  130. ListeningDevices.Remove(freq);
  131. }
  132. if (device.ReceiveAll && ReceiveAllDevices.TryGetValue(freq, out var receiveAll))
  133. {
  134. receiveAll.Remove(device);
  135. if (receiveAll.Count == 0)
  136. ListeningDevices.Remove(freq);
  137. }
  138. }
  139. device.ReceiveFrequency = newFrequency;
  140. if (newFrequency == null)
  141. return true;
  142. if (!ListeningDevices.TryGetValue(newFrequency.Value, out var devices))
  143. ListeningDevices[newFrequency.Value] = devices = new();
  144. devices.Add(device);
  145. if (!device.ReceiveAll)
  146. return true;
  147. if (!ReceiveAllDevices.TryGetValue(newFrequency.Value, out var receiveAlldevices))
  148. ReceiveAllDevices[newFrequency.Value] = receiveAlldevices = new();
  149. receiveAlldevices.Add(device);
  150. return true;
  151. }
  152. /// <summary>
  153. /// Make an existing network device listen to a new frequency.
  154. /// </summary>
  155. public bool UpdateReceiveAll(string address, bool receiveAll)
  156. {
  157. if (!Devices.TryGetValue(address, out var device))
  158. return false;
  159. if (device.ReceiveAll == receiveAll)
  160. return true;
  161. device.ReceiveAll = receiveAll;
  162. if (device.ReceiveFrequency is not uint freq)
  163. return true;
  164. // remove or add to set of listening devices
  165. HashSet<DeviceNetworkComponent>? devices;
  166. if (receiveAll)
  167. {
  168. if (!ReceiveAllDevices.TryGetValue(freq, out devices))
  169. ReceiveAllDevices[freq] = devices = new();
  170. devices.Add(device);
  171. }
  172. else if (ReceiveAllDevices.TryGetValue(freq, out devices))
  173. {
  174. devices.Remove(device);
  175. if (devices.Count == 0)
  176. ReceiveAllDevices.Remove(freq);
  177. }
  178. return true;
  179. }
  180. /// <summary>
  181. /// Generates a valid address by randomly generating one and checking if it already exists on the network.
  182. /// </summary>
  183. private string GenerateValidAddress(string? prefix)
  184. {
  185. prefix = string.IsNullOrWhiteSpace(prefix) ? null : Loc.GetString(prefix);
  186. string address;
  187. do
  188. {
  189. var num = _random.Next();
  190. address = $"{prefix}{num >> 16:X4}-{num & 0xFFFF:X4}";
  191. }
  192. while (Devices.ContainsKey(address));
  193. return address;
  194. }
  195. }