using Content.Server.DeviceNetwork.Components; using Robust.Shared.Random; using static Content.Server.DeviceNetwork.Components.DeviceNetworkComponent; namespace Content.Server.DeviceNetwork; /// /// Data class for storing and retrieving information about devices connected to a device network. /// /// /// This basically just makes accessible via their addresses and frequencies on /// some network. /// public sealed class DeviceNet { /// /// Devices, mapped by their "Address", which is just an int that gets converted to Hex for displaying to users. /// This dictionary contains all devices connected to this network, though they may not be listening to any /// specific frequency. /// public readonly Dictionary Devices = new(); /// /// Devices listening on a given frequency. /// public readonly Dictionary> ListeningDevices = new(); /// /// Devices listening to all packets on a given frequency, regardless of the intended recipient. /// public readonly Dictionary> ReceiveAllDevices = new(); private readonly IRobustRandom _random; public readonly int NetId; public DeviceNet(int netId, IRobustRandom random) { _random = random; NetId = netId; } /// /// Add a device to the network. /// public bool Add(DeviceNetworkComponent device) { if (device.CustomAddress) { // Only add if the device's existing address is available. if (!Devices.TryAdd(device.Address, device)) return false; } else { // Randomly generate a new address if the existing random one is invalid. Otherwise, keep the existing address if (string.IsNullOrWhiteSpace(device.Address) || Devices.ContainsKey(device.Address)) device.Address = GenerateValidAddress(device.Prefix); Devices[device.Address] = device; } if (device.ReceiveFrequency is not uint freq) return true; if (!ListeningDevices.TryGetValue(freq, out var devices)) ListeningDevices[freq] = devices = new(); devices.Add(device); if (!device.ReceiveAll) return true; if (!ReceiveAllDevices.TryGetValue(freq, out var receiveAlldevices)) ReceiveAllDevices[freq] = receiveAlldevices = new(); receiveAlldevices.Add(device); return true; } /// /// Remove a device from the network. /// public bool Remove(DeviceNetworkComponent device) { if (device.Address == null || !Devices.Remove(device.Address)) return false; if (device.ReceiveFrequency is not uint freq) return true; if (ListeningDevices.TryGetValue(freq, out var listening)) { listening.Remove(device); if (listening.Count == 0) ListeningDevices.Remove(freq); } if (device.ReceiveAll && ReceiveAllDevices.TryGetValue(freq, out var receiveAll)) { receiveAll.Remove(device); if (receiveAll.Count == 0) ListeningDevices.Remove(freq); } return true; } /// /// Give an existing device a new randomly generated address. Useful if the device's address prefix was updated /// and they want a new address to reflect that, or something like that. /// public bool RandomizeAddress(string oldAddress, string? prefix = null) { if (!Devices.Remove(oldAddress, out var device)) return false; device.Address = GenerateValidAddress(prefix ?? device.Prefix); device.CustomAddress = false; Devices[device.Address] = device; return true; } /// /// Update the address of an existing device. /// public bool UpdateAddress(string oldAddress, string newAddress) { if (Devices.ContainsKey(newAddress)) return false; if (!Devices.Remove(oldAddress, out var device)) return false; device.Address = newAddress; device.CustomAddress = true; Devices[newAddress] = device; return true; } /// /// Make an existing network device listen to a new frequency. /// public bool UpdateReceiveFrequency(string address, uint? newFrequency) { if (!Devices.TryGetValue(address, out var device)) return false; if (device.ReceiveFrequency == newFrequency) return true; if (device.ReceiveFrequency is uint freq) { if (ListeningDevices.TryGetValue(freq, out var listening)) { listening.Remove(device); if (listening.Count == 0) ListeningDevices.Remove(freq); } if (device.ReceiveAll && ReceiveAllDevices.TryGetValue(freq, out var receiveAll)) { receiveAll.Remove(device); if (receiveAll.Count == 0) ListeningDevices.Remove(freq); } } device.ReceiveFrequency = newFrequency; if (newFrequency == null) return true; if (!ListeningDevices.TryGetValue(newFrequency.Value, out var devices)) ListeningDevices[newFrequency.Value] = devices = new(); devices.Add(device); if (!device.ReceiveAll) return true; if (!ReceiveAllDevices.TryGetValue(newFrequency.Value, out var receiveAlldevices)) ReceiveAllDevices[newFrequency.Value] = receiveAlldevices = new(); receiveAlldevices.Add(device); return true; } /// /// Make an existing network device listen to a new frequency. /// public bool UpdateReceiveAll(string address, bool receiveAll) { if (!Devices.TryGetValue(address, out var device)) return false; if (device.ReceiveAll == receiveAll) return true; device.ReceiveAll = receiveAll; if (device.ReceiveFrequency is not uint freq) return true; // remove or add to set of listening devices HashSet? devices; if (receiveAll) { if (!ReceiveAllDevices.TryGetValue(freq, out devices)) ReceiveAllDevices[freq] = devices = new(); devices.Add(device); } else if (ReceiveAllDevices.TryGetValue(freq, out devices)) { devices.Remove(device); if (devices.Count == 0) ReceiveAllDevices.Remove(freq); } return true; } /// /// Generates a valid address by randomly generating one and checking if it already exists on the network. /// private string GenerateValidAddress(string? prefix) { prefix = string.IsNullOrWhiteSpace(prefix) ? null : Loc.GetString(prefix); string address; do address = $"{prefix}{_random.Next():x}"; while (Devices.ContainsKey(address)); return address; } }