diff --git a/Content.Benchmarks/DeviceNetworkingBenchmark.cs b/Content.Benchmarks/DeviceNetworkingBenchmark.cs index fcde4feb64..cbfe002757 100644 --- a/Content.Benchmarks/DeviceNetworkingBenchmark.cs +++ b/Content.Benchmarks/DeviceNetworkingBenchmark.cs @@ -6,7 +6,6 @@ using Content.IntegrationTests; using Content.IntegrationTests.Pair; using Content.IntegrationTests.Tests.DeviceNetwork; using Content.Server.DeviceNetwork.Systems; -using Content.Shared.DeviceNetwork; using Robust.Shared; using Robust.Shared.Analyzers; using Robust.Shared.GameObjects; @@ -26,9 +25,6 @@ public class DeviceNetworkingBenchmark private readonly List _targetEntities = new(); private readonly List _targetWirelessEntities = new(); - - private NetworkPayload _payload = default!; - [TestPrototypes] private const string Prototypes = @" - type: entity @@ -54,7 +50,7 @@ public class DeviceNetworkingBenchmark //public static IEnumerable EntityCountSource { get; set; } //[ParamsSource(nameof(EntityCountSource))] - public int EntityCount = 500; + public int EntityCount = 1000; [GlobalSetup] public async Task SetupAsync() @@ -70,14 +66,6 @@ public class DeviceNetworkingBenchmark _deviceNetworkSystem = entityManager.EntitySysManager.GetEntitySystem(); _deviceNetTestSystem = entityManager.EntitySysManager.GetEntitySystem(); - var testValue = "test"; - _payload = new NetworkPayload - { - ["Test"] = testValue, - ["testnumber"] = 1, - ["testbool"] = true - }; - _sourceEntity = entityManager.SpawnEntity("DummyNetworkDevicePrivate", MapCoordinates.Nullspace); _sourceWirelessEntity = entityManager.SpawnEntity("DummyWirelessNetworkDevice", MapCoordinates.Nullspace); @@ -120,7 +108,13 @@ public class DeviceNetworkingBenchmark _pair.Server.Post(() => { - _deviceNetworkSystem.QueuePacket(_sourceEntity, null, _payload, 100); + var payload = new TestPayload + { + TestString = "test", + TestNumber = 1, + TestBool = true, + }; + _deviceNetworkSystem.SendPacket(_sourceEntity, null, ref payload, 100); }); await server.WaitRunTicks(1); @@ -134,7 +128,53 @@ public class DeviceNetworkingBenchmark _pair.Server.Post(() => { - _deviceNetworkSystem.QueuePacket(_sourceWirelessEntity, null, _payload, 100); + var payload = new TestPayload + { + TestString = "test", + TestNumber = 1, + TestBool = true, + }; + _deviceNetworkSystem.SendPacket(_sourceWirelessEntity, null, ref payload, 100); + }); + + await server.WaitRunTicks(1); + await server.WaitIdleAsync(); + } + + [Benchmark(Description = "Device Net Broadcast No Connection Checks (Class payload)")] + public async Task DeviceNetworkBroadcastNoConnectionChecksClass() + { + var server = _pair.Server; + + _pair.Server.Post(() => + { + var payload = new TestPayloadClass + { + TestString = "test", + TestNumber = 1, + TestBool = true, + }; + _deviceNetworkSystem.SendPacket(_sourceEntity, null, ref payload, 100); + }); + + await server.WaitRunTicks(1); + await server.WaitIdleAsync(); + } + + [Benchmark(Description = "Device Net Broadcast Wireless Connection Checks (Class payload)")] + public async Task DeviceNetworkBroadcastWirelessConnectionChecksClass() + { + var server = _pair.Server; + + _pair.Server.Post(() => + { + var payload = new TestPayloadClass + { + TestString = "test", + TestNumber = 1, + TestBool = true, + }; + _deviceNetworkSystem.SendPacket(_sourceWirelessEntity, null, ref payload, 100); }); await server.WaitRunTicks(1); diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs b/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs index 650f96eec9..2ef97504d8 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs @@ -33,14 +33,14 @@ public sealed class AirAlarmBoundUserInterface : BoundUserInterface SendMessage(new AirAlarmResyncAllDevicesMessage()); } - private void OnDeviceDataChanged(string address, IAtmosDeviceData data) + private void OnDeviceDataChanged(string address, IAtmosDeviceData dataPayload) { - SendMessage(new AirAlarmUpdateDeviceDataMessage(address, data)); + SendMessage(new AirAlarmUpdateDeviceDataMessage(address, dataPayload)); } - private void OnDeviceDataCopied(IAtmosDeviceData data) + private void OnDeviceDataCopied(IAtmosDeviceData dataPayload) { - SendMessage(new AirAlarmCopyDeviceDataMessage(data)); + SendMessage(new AirAlarmCopyDeviceDataMessage(dataPayload)); } private void OnAirAlarmModeChanged(AirAlarmMode mode) diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs index 60e06e98ce..efc970ff8d 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs @@ -17,7 +17,7 @@ namespace Content.Client.Atmos.Monitor.UI; public sealed partial class AirAlarmWindow : FancyWindow { public event Action? AtmosDeviceDataChanged; - public event Action? AtmosDeviceDataCopied; + public event Action? AtmosDeviceDataCopied; public event Action? AtmosAlarmThresholdChanged; public event Action? AirAlarmModeChanged; public event Action? AutoModeChanged; @@ -158,7 +158,7 @@ public sealed partial class AirAlarmWindow : FancyWindow } break; - case AtmosSensorData sensor: + case AtmosMonitorData sensor: if (!_sensors.TryGetValue(addr, out var sensorControl)) { var control = new SensorInfo(sensor, addr); diff --git a/Content.Client/Atmos/Monitor/UI/Widgets/PumpControl.xaml.cs b/Content.Client/Atmos/Monitor/UI/Widgets/PumpControl.xaml.cs index 8586049cb1..41336faba0 100644 --- a/Content.Client/Atmos/Monitor/UI/Widgets/PumpControl.xaml.cs +++ b/Content.Client/Atmos/Monitor/UI/Widgets/PumpControl.xaml.cs @@ -1,4 +1,4 @@ -using Content.Shared.Atmos.Monitor.Components; +using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Piping.Unary.Components; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.Controls; @@ -9,7 +9,7 @@ namespace Content.Client.Atmos.Monitor.UI.Widgets; [GenerateTypedNameReferences] public sealed partial class PumpControl : BoxContainer { - private GasVentPumpData _data; + private GasVentPumpData _dataPayload; private string _address; public event Action? PumpDataChanged; @@ -23,37 +23,37 @@ public sealed partial class PumpControl : BoxContainer private FloatSpinBox _internalBound => CInternalBound; private Button _copySettings => CCopySettings; - public PumpControl(GasVentPumpData data, string address) + public PumpControl(GasVentPumpData dataPayload, string address) { RobustXamlLoader.Load(this); Name = address; - _data = data; + _dataPayload = dataPayload; _address = address; _addressLabel.Title = Loc.GetString("air-alarm-ui-atmos-net-device-label", ("address", $"{address}")); - _enabled.Pressed = data.Enabled; + _enabled.Pressed = dataPayload.Enabled; _enabled.OnToggled += _ => { - _data.Enabled = _enabled.Pressed; - PumpDataChanged?.Invoke(_address, _data); + _dataPayload.Enabled = _enabled.Pressed; + PumpDataChanged?.Invoke(_address, _dataPayload); }; - _internalBound.Value = _data.InternalPressureBound; + _internalBound.Value = _dataPayload.InternalPressureBound; _internalBound.OnValueChanged += _ => { - _data.InternalPressureBound = _internalBound.Value; - PumpDataChanged?.Invoke(_address, _data); + _dataPayload.InternalPressureBound = _internalBound.Value; + PumpDataChanged?.Invoke(_address, _dataPayload); }; _internalBound.IsValid += value => value >= 0; - _externalBound.Value = _data.ExternalPressureBound; + _externalBound.Value = _dataPayload.ExternalPressureBound; _externalBound.OnValueChanged += _ => { - _data.ExternalPressureBound = _externalBound.Value; - PumpDataChanged?.Invoke(_address, _data); + _dataPayload.ExternalPressureBound = _externalBound.Value; + PumpDataChanged?.Invoke(_address, _dataPayload); }; _externalBound.IsValid += value => value >= 0; @@ -62,12 +62,12 @@ public sealed partial class PumpControl : BoxContainer _pumpDirection.AddItem(Loc.GetString($"air-alarm-ui-pump-direction-{value.ToString().ToLower()}"), (int) value); } - _pumpDirection.SelectId((int) _data.PumpDirection); + _pumpDirection.SelectId((int) _dataPayload.PumpDirection); _pumpDirection.OnItemSelected += args => { _pumpDirection.SelectId(args.Id); - _data.PumpDirection = (VentPumpDirection) args.Id; - PumpDataChanged?.Invoke(_address, _data); + _dataPayload.PumpDirection = (VentPumpDirection) args.Id; + PumpDataChanged?.Invoke(_address, _dataPayload); }; foreach (var value in Enum.GetValues()) @@ -75,35 +75,35 @@ public sealed partial class PumpControl : BoxContainer _pressureCheck.AddItem(Loc.GetString($"air-alarm-ui-pressure-bound-{value.ToString().ToLower()}"), (int) value); } - _pressureCheck.SelectId((int) _data.PressureChecks); + _pressureCheck.SelectId((int) _dataPayload.PressureChecks); _pressureCheck.OnItemSelected += args => { _pressureCheck.SelectId(args.Id); - _data.PressureChecks = (VentPressureBound) args.Id; - PumpDataChanged?.Invoke(_address, _data); + _dataPayload.PressureChecks = (VentPressureBound) args.Id; + PumpDataChanged?.Invoke(_address, _dataPayload); }; _copySettings.OnPressed += _ => { - PumpDataCopied?.Invoke(_data); + PumpDataCopied?.Invoke(_dataPayload); }; } - public void ChangeData(GasVentPumpData data) + public void ChangeData(GasVentPumpData dataPayload) { - _data.Enabled = data.Enabled; - _enabled.Pressed = _data.Enabled; + _dataPayload.Enabled = dataPayload.Enabled; + _enabled.Pressed = _dataPayload.Enabled; - _data.PumpDirection = data.PumpDirection; - _pumpDirection.SelectId((int) _data.PumpDirection); + _dataPayload.PumpDirection = dataPayload.PumpDirection; + _pumpDirection.SelectId((int) _dataPayload.PumpDirection); - _data.PressureChecks = data.PressureChecks; - _pressureCheck.SelectId((int) _data.PressureChecks); + _dataPayload.PressureChecks = dataPayload.PressureChecks; + _pressureCheck.SelectId((int) _dataPayload.PressureChecks); - _data.ExternalPressureBound = data.ExternalPressureBound; - _externalBound.Value = _data.ExternalPressureBound; + _dataPayload.ExternalPressureBound = dataPayload.ExternalPressureBound; + _externalBound.Value = _dataPayload.ExternalPressureBound; - _data.InternalPressureBound = data.InternalPressureBound; - _internalBound.Value = _data.InternalPressureBound; + _dataPayload.InternalPressureBound = dataPayload.InternalPressureBound; + _internalBound.Value = _dataPayload.InternalPressureBound; } } diff --git a/Content.Client/Atmos/Monitor/UI/Widgets/ScrubberControl.xaml.cs b/Content.Client/Atmos/Monitor/UI/Widgets/ScrubberControl.xaml.cs index e197c72855..a339dad358 100644 --- a/Content.Client/Atmos/Monitor/UI/Widgets/ScrubberControl.xaml.cs +++ b/Content.Client/Atmos/Monitor/UI/Widgets/ScrubberControl.xaml.cs @@ -1,6 +1,6 @@ using Content.Shared.Atmos; using Content.Shared.Atmos.EntitySystems; -using Content.Shared.Atmos.Monitor.Components; +using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Atmos.Prototypes; using Robust.Client.AutoGenerated; @@ -16,7 +16,7 @@ public sealed partial class ScrubberControl : BoxContainer [Dependency] private IPrototypeManager _prototypeManager = default!; [Dependency] private IEntityManager _entMan = default!; - private GasVentScrubberData _data; + private GasVentScrubberData _dataPayload; private string _address; public event Action? ScrubberDataChanged; @@ -34,7 +34,7 @@ public sealed partial class ScrubberControl : BoxContainer private GridContainer _gases => CGasContainer; private Dictionary _gasControls = new(); - public ScrubberControl(GasVentScrubberData data, string address) + public ScrubberControl(GasVentScrubberData dataPayload, string address) { IoCManager.InjectDependencies(this); @@ -44,30 +44,30 @@ public sealed partial class ScrubberControl : BoxContainer Name = address; - _data = data; + _dataPayload = dataPayload; _address = address; _addressLabel.Title = Loc.GetString("air-alarm-ui-atmos-net-device-label", ("address", $"{address}")); - _enabled.Pressed = data.Enabled; + _enabled.Pressed = dataPayload.Enabled; _enabled.OnToggled += _ => { - _data.Enabled = _enabled.Pressed; - ScrubberDataChanged?.Invoke(_address, _data); + _dataPayload.Enabled = _enabled.Pressed; + ScrubberDataChanged?.Invoke(_address, _dataPayload); }; - _wideNet.Pressed = data.WideNet; + _wideNet.Pressed = dataPayload.WideNet; _wideNet.OnToggled += _ => { - _data.WideNet = _wideNet.Pressed; - ScrubberDataChanged?.Invoke(_address, _data); + _dataPayload.WideNet = _wideNet.Pressed; + ScrubberDataChanged?.Invoke(_address, _dataPayload); }; - _volumeRate.Value = _data.VolumeRate; + _volumeRate.Value = _dataPayload.VolumeRate; _volumeRate.OnValueChanged += _ => { - _data.VolumeRate = _volumeRate.Value; - ScrubberDataChanged?.Invoke(_address, _data); + _dataPayload.VolumeRate = _volumeRate.Value; + ScrubberDataChanged?.Invoke(_address, _dataPayload); }; _volumeRate.IsValid += value => value >= 0; @@ -76,31 +76,31 @@ public sealed partial class ScrubberControl : BoxContainer _pumpDirection.AddItem(Loc.GetString($"air-alarm-ui-pump-direction-{value.ToString().ToLower()}"), (int) value); } - _pumpDirection.SelectId((int) _data.PumpDirection); + _pumpDirection.SelectId((int) _dataPayload.PumpDirection); _pumpDirection.OnItemSelected += args => { _pumpDirection.SelectId(args.Id); - _data.PumpDirection = (ScrubberPumpDirection) args.Id; - ScrubberDataChanged?.Invoke(_address, _data); + _dataPayload.PumpDirection = (ScrubberPumpDirection) args.Id; + ScrubberDataChanged?.Invoke(_address, _dataPayload); }; - _pumpDirection.Disabled = data.AirAlarmPanicWireCut; + _pumpDirection.Disabled = dataPayload.AirAlarmPanicWireCut; _copySettings.OnPressed += _ => { - ScrubberDataCopied?.Invoke(_data); + ScrubberDataCopied?.Invoke(_dataPayload); }; var allGases = Enum.GetValues(); _selectAll.OnPressed += _ => { - _data.FilterGases = new HashSet(allGases); - ScrubberDataChanged?.Invoke(_address, _data); + _dataPayload.FilterGases = new HashSet(allGases); + ScrubberDataChanged?.Invoke(_address, _dataPayload); }; _deselectAll.OnPressed += _ => { - _data.FilterGases = []; - ScrubberDataChanged?.Invoke(_address, _data); + _dataPayload.FilterGases = []; + ScrubberDataChanged?.Invoke(_address, _dataPayload); }; foreach (var value in allGases) @@ -114,16 +114,16 @@ public sealed partial class ScrubberControl : BoxContainer Text = Loc.GetString(gasName), ToggleMode = true, HorizontalExpand = true, - Pressed = _data.FilterGases.Contains(value) + Pressed = _dataPayload.FilterGases.Contains(value) }; gasButton.OnToggled += args => { if (args.Pressed) - _data.FilterGases.Add(value); + _dataPayload.FilterGases.Add(value); else - _data.FilterGases.Remove(value); + _dataPayload.FilterGases.Remove(value); - ScrubberDataChanged?.Invoke(_address, _data); + ScrubberDataChanged?.Invoke(_address, _dataPayload); }; _gasControls.Add(value, gasButton); _gases.AddChild(gasButton); @@ -131,25 +131,25 @@ public sealed partial class ScrubberControl : BoxContainer } - public void ChangeData(GasVentScrubberData data) + public void ChangeData(GasVentScrubberData dataPayload) { - _data.Enabled = data.Enabled; - _enabled.Pressed = _data.Enabled; + _dataPayload.Enabled = dataPayload.Enabled; + _enabled.Pressed = _dataPayload.Enabled; - _data.PumpDirection = data.PumpDirection; - _pumpDirection.Select((int) _data.PumpDirection); - _pumpDirection.Disabled = data.AirAlarmPanicWireCut; + _dataPayload.PumpDirection = dataPayload.PumpDirection; + _pumpDirection.Select((int) _dataPayload.PumpDirection); + _pumpDirection.Disabled = dataPayload.AirAlarmPanicWireCut; - _data.VolumeRate = data.VolumeRate; - _volumeRate.Value = _data.VolumeRate; + _dataPayload.VolumeRate = dataPayload.VolumeRate; + _volumeRate.Value = _dataPayload.VolumeRate; - _data.WideNet = data.WideNet; - _wideNet.Pressed = _data.WideNet; - _data.FilterGases = data.FilterGases; + _dataPayload.WideNet = dataPayload.WideNet; + _wideNet.Pressed = _dataPayload.WideNet; + _dataPayload.FilterGases = dataPayload.FilterGases; foreach (var value in Enum.GetValues()) { - _gasControls[value].Pressed = data.FilterGases.Contains(value); + _gasControls[value].Pressed = dataPayload.FilterGases.Contains(value); } } } diff --git a/Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs b/Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs index ed7a9022e5..871338e119 100644 --- a/Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs +++ b/Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs @@ -18,7 +18,7 @@ public sealed partial class SensorInfo : BoxContainer [Dependency] private IEntityManager _entMan = default!; public Action? OnThresholdUpdate; - public event Action? SensorDataCopied; + public event Action? SensorDataCopied; private string _address; private ThresholdControl _pressureThreshold; @@ -27,7 +27,7 @@ public sealed partial class SensorInfo : BoxContainer private Dictionary _gasLabels = new(); private Button _copySettings => CCopySettings; - public SensorInfo(AtmosSensorData data, string address) + public SensorInfo(AtmosMonitorData dataPayload, string address) { IoCManager.InjectDependencies(this); var atmosphereSystem = _entMan.System(); @@ -36,37 +36,37 @@ public sealed partial class SensorInfo : BoxContainer _address = address; - SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState)); + SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", dataPayload.AlarmState)); AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator", - ("color", AirAlarmWindow.ColorForAlarm(data.AlarmState)), - ("state", data.AlarmState))); + ("color", AirAlarmWindow.ColorForAlarm(dataPayload.AlarmState)), + ("state", dataPayload.AlarmState))); PressureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure-indicator", - ("color", AirAlarmWindow.ColorForThreshold(data.Pressure, data.PressureThreshold)), - ("pressure", $"{data.Pressure:0.##}"))); + ("color", AirAlarmWindow.ColorForThreshold(dataPayload.Pressure, dataPayload.PressureThreshold)), + ("pressure", $"{dataPayload.Pressure:0.##}"))); TemperatureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-temperature-indicator", - ("color", AirAlarmWindow.ColorForThreshold(data.Temperature, data.TemperatureThreshold)), - ("tempC", $"{TemperatureHelpers.KelvinToCelsius(data.Temperature):0.#}"), - ("temperature", $"{data.Temperature:0.##}"))); + ("color", AirAlarmWindow.ColorForThreshold(dataPayload.Temperature, dataPayload.TemperatureThreshold)), + ("tempC", $"{TemperatureHelpers.KelvinToCelsius(dataPayload.Temperature):0.#}"), + ("temperature", $"{dataPayload.Temperature:0.##}"))); - foreach (var (gas, amount) in data.Gases) + foreach (var (gas, amount) in dataPayload.Gases) { var label = new RichTextLabel(); - var fractionGas = amount / data.TotalMoles; + var fractionGas = amount / dataPayload.TotalMoles; ProtoId gasProtoId = atmosphereSystem.GetGas(gas); var gasName = _prototypeManager.Index(gasProtoId).Name; label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", ("gas", Loc.GetString(gasName)), - ("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])), + ("color", AirAlarmWindow.ColorForThreshold(fractionGas, dataPayload.GasThresholds[gas])), ("amount", $"{amount:0.####}"), ("percentage", $"{(100 * fractionGas):0.##}"))); GasContainer.AddChild(label); _gasLabels.Add(gas, label); - var threshold = data.GasThresholds[gas]; + var threshold = dataPayload.GasThresholds[gas]; var gasThresholdControl = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title"), threshold, AtmosMonitorThresholdType.Gas, gas, 100); gasThresholdControl.Margin = new Thickness(20, 2, 2, 2); gasThresholdControl.ThresholdDataChanged += (type, alarmThreshold, arg3) => @@ -78,10 +78,10 @@ public sealed partial class SensorInfo : BoxContainer GasContainer.AddChild(gasThresholdControl); } - _pressureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-pressure-title"), data.PressureThreshold, AtmosMonitorThresholdType.Pressure); + _pressureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-pressure-title"), dataPayload.PressureThreshold, AtmosMonitorThresholdType.Pressure); PressureThresholdContainer.AddChild(_pressureThreshold); _temperatureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-temperature-title"), - data.TemperatureThreshold, + dataPayload.TemperatureThreshold, AtmosMonitorThresholdType.Temperature); TemperatureThresholdContainer.AddChild(_temperatureThreshold); @@ -97,58 +97,58 @@ public sealed partial class SensorInfo : BoxContainer _copySettings.OnPressed += _ => { - SensorDataCopied?.Invoke(data); + SensorDataCopied?.Invoke(dataPayload); }; } - public void ChangeData(AtmosSensorData data) + public void ChangeData(AtmosMonitorData dataPayload) { IoCManager.InjectDependencies(this); var atmosphereSystem = _entMan.System(); - SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState)); + SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", dataPayload.AlarmState)); AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator", - ("color", AirAlarmWindow.ColorForAlarm(data.AlarmState)), - ("state", data.AlarmState))); + ("color", AirAlarmWindow.ColorForAlarm(dataPayload.AlarmState)), + ("state", dataPayload.AlarmState))); PressureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure-indicator", - ("color", AirAlarmWindow.ColorForThreshold(data.Pressure, data.PressureThreshold)), - ("pressure", $"{data.Pressure:0.##}"))); + ("color", AirAlarmWindow.ColorForThreshold(dataPayload.Pressure, dataPayload.PressureThreshold)), + ("pressure", $"{dataPayload.Pressure:0.##}"))); TemperatureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-temperature-indicator", - ("color", AirAlarmWindow.ColorForThreshold(data.Temperature, data.TemperatureThreshold)), - ("tempC", $"{TemperatureHelpers.KelvinToCelsius(data.Temperature):0.#}"), - ("temperature", $"{data.Temperature:0.##}"))); + ("color", AirAlarmWindow.ColorForThreshold(dataPayload.Temperature, dataPayload.TemperatureThreshold)), + ("tempC", $"{TemperatureHelpers.KelvinToCelsius(dataPayload.Temperature):0.#}"), + ("temperature", $"{dataPayload.Temperature:0.##}"))); - foreach (var (gas, amount) in data.Gases) + foreach (var (gas, amount) in dataPayload.Gases) { if (!_gasLabels.TryGetValue(gas, out var label)) { continue; } - var fractionGas = amount / data.TotalMoles; + var fractionGas = amount / dataPayload.TotalMoles; ProtoId gasProtoId = atmosphereSystem.GetGas(gas); var gasName = _prototypeManager.Index(gasProtoId).Name; label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", ("gas", Loc.GetString(gasName)), - ("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])), + ("color", AirAlarmWindow.ColorForThreshold(fractionGas, dataPayload.GasThresholds[gas])), ("amount", $"{amount:0.####}"), ("percentage", $"{(100 * fractionGas):0.##}"))); } - _pressureThreshold.UpdateThresholdData(data.PressureThreshold, data.Pressure); - _temperatureThreshold.UpdateThresholdData(data.TemperatureThreshold, data.Temperature); + _pressureThreshold.UpdateThresholdData(dataPayload.PressureThreshold, dataPayload.Pressure); + _temperatureThreshold.UpdateThresholdData(dataPayload.TemperatureThreshold, dataPayload.Temperature); foreach (var (gas, control) in _gasThresholds) { - if (!data.GasThresholds.TryGetValue(gas, out var threshold)) + if (!dataPayload.GasThresholds.TryGetValue(gas, out var threshold)) { continue; } - control.UpdateThresholdData(threshold, data.Gases[gas] / data.TotalMoles); + control.UpdateThresholdData(threshold, dataPayload.Gases[gas] / dataPayload.TotalMoles); } } diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs index ad7c2dad02..ef0b22097a 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs @@ -4,7 +4,7 @@ using System.Numerics; using Content.Client.Pinpointer.UI; using Content.Client.Stylesheets; using Content.Client.UserInterface.Controls; -using Content.Shared.Medical.SuitSensor; +using Content.Shared.Medical.SuitSensors; using Content.Shared.StatusIcon; using Robust.Client.AutoGenerated; using Robust.Client.GameObjects; @@ -98,8 +98,9 @@ public sealed partial class CrewMonitoringWindow : FancyWindow var uniqueSensors = uniqueSensorsMap.Values.ToList(); // Order sensor data - var orderedSensors = uniqueSensors.OrderBy(n => n.Name).OrderBy(j => j.Job); - var assignedSensors = new HashSet(); + // TODO too much evil LINQ going on here + var orderedSensors = uniqueSensors.OrderBy(n => n.Name).ThenBy(j => j.Job); + var assignedSensors = new List(); var departments = uniqueSensors.SelectMany(d => d.JobDepartments).Distinct().OrderBy(n => n); // Create department labels and populate lists diff --git a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorWindow.xaml.cs b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorWindow.xaml.cs index bcd899a029..58dd9b0728 100644 --- a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorWindow.xaml.cs +++ b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorWindow.xaml.cs @@ -180,9 +180,10 @@ public sealed partial class SurveillanceCameraMonitorWindow : DefaultWindow private int AddSubnet(ProtoId subnet) { var name = subnet; - if (_prototypeManager.TryIndex(subnet, out var frequency)) + if (_prototypeManager.TryIndex(subnet, out var frequency) + && frequency.Name != null) { - name = Loc.GetString(frequency.Name ?? subnet); + name = Loc.GetString(frequency.Name); } SubnetSelector.AddItem(name); diff --git a/Content.IntegrationTests/Tests/DeviceLinking/DeviceLinkingTest.cs b/Content.IntegrationTests/Tests/DeviceLinking/DeviceLinkingTest.cs index 695f16f65c..9b3c6efdeb 100644 --- a/Content.IntegrationTests/Tests/DeviceLinking/DeviceLinkingTest.cs +++ b/Content.IntegrationTests/Tests/DeviceLinking/DeviceLinkingTest.cs @@ -70,7 +70,7 @@ public sealed class DeviceLinkingTest : GameTest sinkComp); // Send a signal to the port - Assert.DoesNotThrow(() => { deviceLinkSys.InvokePort(sourceEnt, "Output", null, sourceComp); }, + Assert.DoesNotThrow(() => { deviceLinkSys.InvokePort((sourceEnt, sourceComp), "Output"); }, $"Exception thrown while triggering port {port.Id} of the sink device."); mapSys.DeleteMap(mapId); diff --git a/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs index d3719a262b..c5712bd608 100644 --- a/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs +++ b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs @@ -2,7 +2,6 @@ using System.Numerics; using Content.IntegrationTests.Fixtures; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; -using Content.Shared.DeviceNetwork; using Robust.Shared.GameObjects; using Robust.Shared.Map; using Content.Shared.DeviceNetwork.Components; @@ -58,22 +57,20 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork var deviceNetSystem = entityManager.EntitySysManager.GetEntitySystem(); var deviceNetTestSystem = entityManager.EntitySysManager.GetEntitySystem(); - EntityUid device1 = default; EntityUid device2 = default; DeviceNetworkComponent networkComponent1 = null; DeviceNetworkComponent networkComponent2 = null; - var testValue = "test"; - var payload = new NetworkPayload - { - ["Test"] = testValue, - ["testnumber"] = 1, - ["testbool"] = true - }; - await server.WaitAssertion(() => { + var payload = new TestPayload + { + TestString = "test", + TestNumber = 1, + TestBool = true + }; + device1 = entityManager.SpawnEntity("DummyNetworkDevice", MapCoordinates.Nullspace); Assert.That(entityManager.TryGetComponent(device1, out networkComponent1), Is.True); @@ -94,15 +91,8 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork Assert.That(networkComponent1.Address, Is.Not.EqualTo(networkComponent2.Address)); }); - deviceNetSystem.QueuePacket(device1, networkComponent2.Address, payload, networkComponent2.ReceiveFrequency.Value); - }); - - await server.WaitRunTicks(2); - await server.WaitIdleAsync(); - - await server.WaitAssertion(() => - { - Assert.That(payload, Is.EquivalentTo(deviceNetTestSystem.LastPayload)); + deviceNetSystem.SendPacket(device1, networkComponent2.Address, ref payload, networkComponent2.ReceiveFrequency.Value); + Assert.That(payload, Is.EqualTo(deviceNetTestSystem.LastPayload)); }); } @@ -124,14 +114,6 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork DeviceNetworkComponent networkComponent2 = null; WirelessNetworkComponent wirelessNetworkComponent = null; - var testValue = "test"; - var payload = new NetworkPayload - { - ["Test"] = testValue, - ["testnumber"] = 1, - ["testbool"] = true - }; - await server.WaitAssertion(() => { device1 = entityManager.SpawnEntity("WirelessNetworkDeviceDummy", coordinates); @@ -158,33 +140,28 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork Assert.That(networkComponent1.Address, Is.Not.EqualTo(networkComponent2.Address)); }); - - deviceNetSystem.QueuePacket(device1, networkComponent2.Address, payload, networkComponent2.ReceiveFrequency.Value); - }); - - await server.WaitRunTicks(2); - await server.WaitIdleAsync(); - - await server.WaitAssertion(() => - { - Assert.That(payload, Is.EqualTo(deviceNetTestSystem.LastPayload).AsCollection); - - payload = new NetworkPayload + var payload = new TestPayload { - ["Wirelesstest"] = 5 + TestString = "test", + TestNumber = 1, + TestBool = true }; + deviceNetSystem.SendPacket(device1, networkComponent2.Address, ref payload, networkComponent2.ReceiveFrequency.Value); + + Assert.That(payload, Is.EqualTo(deviceNetTestSystem.LastPayload)); + wirelessNetworkComponent.Range = 0; - deviceNetSystem.QueuePacket(device1, networkComponent2.Address, payload, networkComponent2.ReceiveFrequency.Value); - }); + var secondPayload = new SecondTestPayload + { + TestString = "test", + TestNumber = 1, + TestBool = true + }; - await server.WaitRunTicks(1); - await server.WaitIdleAsync(); - - await server.WaitAssertion(() => - { - Assert.That(payload, Is.Not.EqualTo(deviceNetTestSystem.LastPayload).AsCollection); + deviceNetSystem.SendPacket(device1, networkComponent2.Address, ref secondPayload, networkComponent2.ReceiveFrequency.Value); + Assert.That(secondPayload, Is.Not.EqualTo(deviceNetTestSystem.LastPayloadSecond)); }); } @@ -205,15 +182,6 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork DeviceNetworkComponent networkComponent1 = null; DeviceNetworkComponent networkComponent2 = null; WiredNetworkComponent wiredNetworkComponent = null; - var grid = testMap.Grid.Comp; - - var testValue = "test"; - var payload = new NetworkPayload - { - ["Test"] = testValue, - ["testnumber"] = 1, - ["testbool"] = true - }; await server.WaitRunTicks(2); await server.WaitIdleAsync(); @@ -244,27 +212,20 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork Assert.That(networkComponent1.Address, Is.Not.EqualTo(networkComponent2.Address)); }); - deviceNetSystem.QueuePacket(device1, networkComponent2.Address, payload, networkComponent2.ReceiveFrequency.Value); - }); + var payload = new TestPayload + { + TestString = "test", + TestNumber = 1, + TestBool = true + }; - await server.WaitRunTicks(1); - await server.WaitIdleAsync(); - - await server.WaitAssertion(() => - { - //CollectionAssert.AreNotEqual(deviceNetTestSystem.LastPayload, payload); + deviceNetSystem.SendPacket(device1, networkComponent2.Address, ref payload, networkComponent2.ReceiveFrequency.Value); entityManager.SpawnEntity("CableApcExtension", coordinates); - deviceNetSystem.QueuePacket(device1, networkComponent2.Address, payload, networkComponent2.ReceiveFrequency.Value); - }); + deviceNetSystem.SendPacket(device1, networkComponent2.Address, ref payload, networkComponent2.ReceiveFrequency.Value); - await server.WaitRunTicks(1); - await server.WaitIdleAsync(); - - await server.WaitAssertion(() => - { - Assert.That(payload, Is.EqualTo(deviceNetTestSystem.LastPayload).AsCollection); + Assert.That(payload, Is.EqualTo(deviceNetTestSystem.LastPayload)); }); } } diff --git a/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTestSystem.cs b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTestSystem.cs index 2076cce9d6..891cf6dc9a 100644 --- a/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTestSystem.cs +++ b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTestSystem.cs @@ -1,30 +1,71 @@ +#nullable enable using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using Robust.Shared.GameObjects; using Robust.Shared.Reflection; using Content.Shared.DeviceNetwork.Components; +using Robust.Shared.Serialization.Manager.Attributes; namespace Content.IntegrationTests.Tests.DeviceNetwork; [Reflect(false)] public sealed partial class DeviceNetworkTestSystem : EntitySystem { - public NetworkPayload LastPayload = default; - public override void Initialize() { base.Initialize(); - - SubscribeLocalEvent(OnPacketReceived); + SubscribeLocalEvent(OnBaselinePacketReceived); + SubscribeLocalEvent>(OnTypedPacketReceived); + SubscribeLocalEvent>(OnTypedPacketReceived); } + public TestPayload LastPayload = default; + public SecondTestPayload LastPayloadSecond = default; + public TestPayloadClass LastPayloadClass = default!; + public void SendBaselineTestEvent(EntityUid uid) { - RaiseLocalEvent(uid, new DeviceNetworkPacketEvent(0, "", 0, "", uid, new NetworkPayload())); + var ev = new DeviceNetworkPacketData(0, "", 0, "", uid, new TestPayloadClass()); + RaiseLocalEvent(uid, ref ev); } - private void OnPacketReceived(EntityUid uid, DeviceNetworkComponent component, DeviceNetworkPacketEvent args) + private void OnBaselinePacketReceived(Entity ent, ref DeviceNetworkPacketData args) + { + LastPayloadClass = (TestPayloadClass) args.Data; + } + + private void OnTypedPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) { LastPayload = args.Data; } + + private void OnTypedPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) + { + LastPayloadSecond = args.Data; + } +} + +[ByRefEvent] +public record struct DeviceNetworkPacketData( + int NetId, + string? Address, + uint Frequency, + string SenderAddress, + EntityUid Sender, + INetworkPayload Data); + +public readonly partial record struct TestPayload(string TestString, int TestNumber, bool TestBool) : INetworkPayload; + +public readonly partial record struct SecondTestPayload(string TestString, int TestNumber, bool TestBool) : INetworkPayload; + +public sealed partial class TestPayloadClass : INetworkPayload +{ + [DataField] + public string TestString; + + [DataField] + public int TestNumber; + + [DataField] + public bool TestBool; } diff --git a/Content.Server/Anomaly/Effects/TechAnomalySystem.cs b/Content.Server/Anomaly/Effects/TechAnomalySystem.cs index 512879c0db..d7eb940c9e 100644 --- a/Content.Server/Anomaly/Effects/TechAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/TechAnomalySystem.cs @@ -128,6 +128,6 @@ public sealed partial class TechAnomalySystem : EntitySystem private void OnPulse(Entity tech, ref AnomalyPulseEvent args) { - _signal.InvokePort(tech, tech.Comp.PulsePort); + _signal.InvokePort(tech.Owner, tech.Comp.PulsePort); } } diff --git a/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs b/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs index bebc50dd68..a8cf63cb5a 100644 --- a/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs +++ b/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs @@ -253,8 +253,8 @@ public sealed partial class AtmosAlertsComputerSystem : SharedAtmosAlertsCompute // Create entry var netEnt = GetNetEntity(ent); - var entry = new AtmosAlertsComputerEntry - (netEnt, + var entry = new AtmosAlertsComputerEntry( + netEnt, GetNetCoordinates(entXform.Coordinates), entDevice.Group, alarmState, diff --git a/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs b/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs index 8c02218a95..8b6a1a427b 100644 --- a/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs +++ b/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs @@ -20,7 +20,7 @@ public sealed partial class AirAlarmComponent : Component public readonly HashSet KnownDevices = new(); public readonly Dictionary VentData = new(); public readonly Dictionary ScrubberData = new(); - public readonly Dictionary SensorData = new(); + public readonly Dictionary SensorData = new(); public bool CanSync = true; diff --git a/Content.Server/Atmos/Monitor/Payloads/AirAlarmPayloads.cs b/Content.Server/Atmos/Monitor/Payloads/AirAlarmPayloads.cs new file mode 100644 index 0000000000..ed8d159c30 --- /dev/null +++ b/Content.Server/Atmos/Monitor/Payloads/AirAlarmPayloads.cs @@ -0,0 +1,23 @@ +using Content.Shared.Atmos.Monitor; +using Content.Shared.Atmos.Monitor.Components; +using Content.Shared.DeviceNetwork; + +namespace Content.Server.Atmos.Monitor.Payloads; + +/// +/// A network payload sent to an air alarm to set its mode. +/// +public partial record struct AirAlarmSetModePayload : INetworkPayload +{ + [DataField] + public AirAlarmMode Mode; +} + +/// +/// A network payload sent from an atmos device to an air alarm to update its UI. +/// +public partial record struct AirAlarmSetDataPayload : INetworkPayload +{ + [DataField] + public IAtmosDeviceData Payload; +} diff --git a/Content.Server/Atmos/Monitor/Payloads/AtmosAlarmablePayloads.cs b/Content.Server/Atmos/Monitor/Payloads/AtmosAlarmablePayloads.cs new file mode 100644 index 0000000000..e2c99bb8cd --- /dev/null +++ b/Content.Server/Atmos/Monitor/Payloads/AtmosAlarmablePayloads.cs @@ -0,0 +1,48 @@ +using Content.Shared.Atmos.Monitor; +using Content.Shared.DeviceNetwork; +using Content.Shared.Tag; +using Robust.Shared.Prototypes; + +namespace Content.Server.Atmos.Monitor.Payloads; + +[ImplicitDataDefinitionForInheritors] +public partial interface IAtmosAlarmableSourcePayload : INetworkPayload +{ + HashSet> Source { get; set; } +} + +/// +/// Broadcasts an atmos alarm. +/// +public partial record struct AtmosAlarmPayload : IAtmosAlarmableSourcePayload +{ + [DataField] + public AtmosAlarmType Type; + + [DataField] + public AtmosMonitorThresholdTypeFlags? TrippedThresholds; + + [DataField] + public HashSet> Source { get; set; } = new(); +} + +/// +/// Synchronizes the data of an atmos alarmable to all other alarmable devices. +/// +public partial record struct AtmosAlarmableSyncAlertsPayload : IAtmosAlarmableSourcePayload +{ + [DataField] + public Dictionary AlarmStates = new(); + + [DataField] + public HashSet> Source { get; set; } = new(); +} + +/// +/// Resets the state of an atmos alarmable to Normal. +/// +public partial record struct AtmosAlarmableResetAllPayload : IAtmosAlarmableSourcePayload +{ + [DataField] + public HashSet> Source { get; set; } = new(); +} diff --git a/Content.Server/Atmos/Monitor/Payloads/AtmosMonitorPayloads.cs b/Content.Server/Atmos/Monitor/Payloads/AtmosMonitorPayloads.cs new file mode 100644 index 0000000000..5a54eac918 --- /dev/null +++ b/Content.Server/Atmos/Monitor/Payloads/AtmosMonitorPayloads.cs @@ -0,0 +1,46 @@ +using Content.Server.Atmos.Monitor.Components; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Monitor; +using Content.Shared.DeviceNetwork; + +namespace Content.Server.Atmos.Monitor.Payloads; + +/// +/// Used for synchronizing the sender device and adding its address to all listeners. +/// +public partial record struct AtmosMonitorRegisterDevicePayload : INetworkPayload; + +/// +/// Removes the sender device from all listeners of this payload. +/// +public partial record struct AtmosMonitorDeregisterDevicePayload : INetworkPayload; + +/// +/// Sets specific threshold on the target atmos device. +/// +public partial record struct AtmosMonitorSetThresholdPayload : INetworkPayload +{ + [DataField] + public AtmosMonitorThresholdType Type; + + [DataField] + public AtmosAlarmThreshold Threshold; + + [DataField] + public Gas? Gas; +} + +/// +/// Sets thresholds on all connected devices. +/// +public partial record struct AtmosMonitorSetAllThresholdsPayload : INetworkPayload +{ + [DataField] + public AtmosMonitorData Data; +} + +/// +/// Sets the alarm state of a to Normal +/// and broadcasts it to all listening . +/// +public partial record struct AtmosMonitorResetPayload : INetworkPayload; diff --git a/Content.Server/Atmos/Monitor/Payloads/AtmosSyncPayload.cs b/Content.Server/Atmos/Monitor/Payloads/AtmosSyncPayload.cs new file mode 100644 index 0000000000..885b5602f5 --- /dev/null +++ b/Content.Server/Atmos/Monitor/Payloads/AtmosSyncPayload.cs @@ -0,0 +1,8 @@ +using Content.Shared.DeviceNetwork; + +namespace Content.Server.Atmos.Monitor.Payloads; + +/// +/// A general payload that when sent to an atmos device forces it to respond with its data payload. +/// +public partial record struct AtmosSyncPayload : INetworkPayload; diff --git a/Content.Server/Atmos/Monitor/Systems/AirAlarmModes.cs b/Content.Server/Atmos/Monitor/Systems/AirAlarmModes.cs index fd702c209a..f192b04113 100644 --- a/Content.Server/Atmos/Monitor/Systems/AirAlarmModes.cs +++ b/Content.Server/Atmos/Monitor/Systems/AirAlarmModes.cs @@ -1,7 +1,6 @@ using Content.Server.Atmos.Monitor.Components; using Content.Server.Atmos.Monitor.Systems; using Content.Server.DeviceNetwork.Systems; -using Content.Shared.Atmos; using Content.Shared.Atmos.Monitor.Components; using Content.Shared.Atmos.Piping.Unary.Components; diff --git a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs index 830f6a6262..4a259c6031 100644 --- a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs +++ b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs @@ -12,28 +12,22 @@ using Content.Shared.Atmos.Monitor.Components; using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Database; using Content.Shared.DeviceLinking; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Systems; using Content.Shared.Interaction; using Content.Shared.Power; using Content.Shared.Wires; using Robust.Server.GameObjects; using System.Linq; +using Content.Server.Atmos.Monitor.Payloads; using Content.Shared.Atmos.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared.DeviceNetwork.Components; +using Content.Shared.UserInterface; namespace Content.Server.Atmos.Monitor.Systems; // AirAlarm system - specific for atmos devices, rather than // atmos monitors. -// -// oh boy, message passing! -// -// Commands should always be sent into packet's Command -// data key. In response, a packet will be transmitted -// with the response type as its command, and the -// response data in its data key. public sealed partial class AirAlarmSystem : EntitySystem { [Dependency] private AccessReaderSystem _access = default!; @@ -45,26 +39,31 @@ public sealed partial class AirAlarmSystem : EntitySystem [Dependency] private DeviceListSystem _deviceList = default!; [Dependency] private PopupSystem _popup = default!; [Dependency] private UserInterfaceSystem _ui = default!; + [Dependency] private EntityQuery _deviceNetworkQuery = default!; #region Device Network API - /// - /// Command to set an air alarm's mode. - /// - public const string AirAlarmSetMode = "air_alarm_set_mode"; - // -- API -- - /// - /// Set the data for an air alarm managed device. - /// - /// The address of the device. - /// The data to send to the device. - public void SetData(EntityUid uid, string address, IAtmosDeviceData data) + public void SetData(EntityUid uid, string address, GasVentPumpData payload) { - _atmosDevNet.SetDeviceState(uid, address, data); - _atmosDevNet.Sync(uid, address); + var sendPayload = new GasVentPumpSetDataPayload { Data = payload }; + _deviceNet.SendPacket(uid, address, ref sendPayload); + SetDeviceDataInternal(uid, address, payload); + } + + public void SetData(EntityUid uid, string address, GasVentScrubberData payload) + { + var sendPayload = new GasVentScrubberSetDataPayload { Data = payload }; + _deviceNet.SendPacket(uid, address, ref sendPayload); + SetDeviceDataInternal(uid, address, payload); + } + + private void SetDeviceDataInternal(EntityUid uid, string address, IAtmosDeviceData payload) + { + var setPayload = new AirAlarmSetDataPayload { Payload = payload }; + _deviceNet.SendPacket(uid, address, ref setPayload); } /// @@ -116,32 +115,26 @@ public sealed partial class AirAlarmSystem : EntitySystem private void SetThreshold(EntityUid uid, string address, AtmosMonitorThresholdType type, AtmosAlarmThreshold threshold, Gas? gas = null) { - var payload = new NetworkPayload + var payload = new AtmosMonitorSetThresholdPayload { - [DeviceNetworkConstants.Command] = AtmosMonitorSystem.AtmosMonitorSetThresholdCmd, - [AtmosMonitorSystem.AtmosMonitorThresholdDataType] = type, - [AtmosMonitorSystem.AtmosMonitorThresholdData] = threshold, + Type = type, + Threshold = threshold, + Gas = gas, }; - if (gas != null) - { - payload.Add(AtmosMonitorSystem.AtmosMonitorThresholdGasType, gas); - } - - _deviceNet.QueuePacket(uid, address, payload); + _deviceNet.SendPacket(uid, address, ref payload); SyncDevice(uid, address); } - private void SetAllThresholds(EntityUid uid, string address, AtmosSensorData data) + private void SetAllThresholds(EntityUid uid, string address, AtmosMonitorData dataPayload) { - var payload = new NetworkPayload + var payload = new AtmosMonitorSetAllThresholdsPayload { - [DeviceNetworkConstants.Command] = AtmosMonitorSystem.AtmosMonitorSetAllThresholdsCmd, - [AtmosMonitorSystem.AtmosMonitorAllThresholdData] = data + Data = dataPayload }; - _deviceNet.QueuePacket(uid, address, payload); + _deviceNet.SendPacket(uid, address, ref payload); SyncDevice(uid, address); } @@ -155,13 +148,12 @@ public sealed partial class AirAlarmSystem : EntitySystem if (TryComp(uid, out var monitor) && !monitor.NetEnabled) return; - var payload = new NetworkPayload + var payload = new AirAlarmSetModePayload { - [DeviceNetworkConstants.Command] = AirAlarmSetMode, - [AirAlarmSetMode] = mode + Mode = mode, }; - _deviceNet.QueuePacket(uid, null, payload); + _deviceNet.SendPacket(uid, null, ref payload); } #endregion @@ -170,7 +162,7 @@ public sealed partial class AirAlarmSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent(OnPacketRecv); + base.Initialize(); SubscribeLocalEvent(OnAtmosUpdate); SubscribeLocalEvent(OnAtmosAlarm); SubscribeLocalEvent(OnPowerChanged); @@ -178,7 +170,7 @@ public sealed partial class AirAlarmSystem : EntitySystem SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnActivate); + SubscribeLocalEvent(OnActivate); Subs.BuiEvents(SharedAirAlarmInterfaceKey.Key, subs => { @@ -252,21 +244,8 @@ public sealed partial class AirAlarmSystem : EntitySystem _activeUserInterfaces.Remove(uid); } - private void OnActivate(EntityUid uid, AirAlarmComponent component, ActivateInWorldEvent args) + private void OnActivate(EntityUid uid, AirAlarmComponent component, AfterActivatableUIOpenEvent args) { - if (!args.Complex) - return; - - if (TryComp(uid, out var panel) && panel.Open) - { - args.Handled = false; - return; - } - - if (!this.IsPowered(uid, EntityManager)) - return; - - _ui.OpenUi(uid, SharedAirAlarmInterfaceKey.Key, args.User); AddActiveInterface(uid); SyncAllDevices(uid); UpdateUI(uid, component); @@ -360,7 +339,7 @@ public sealed partial class AirAlarmSystem : EntitySystem foreach (string addr in component.VentData.Keys) { _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(args.Actor)} copied settings to vent {addr}"); - SetData(uid, addr, args.Data); + SetData(uid, addr, ventData); } break; @@ -368,11 +347,11 @@ public sealed partial class AirAlarmSystem : EntitySystem foreach (string addr in component.ScrubberData.Keys) { _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(args.Actor)} copied settings to scrubber {addr}"); - SetData(uid, addr, args.Data); + SetData(uid, addr, scrubberData); } break; - case AtmosSensorData sensorData: + case AtmosMonitorData sensorData: foreach (string addr in component.SensorData.Keys) { SetAllThresholds(uid, addr, sensorData); @@ -430,14 +409,12 @@ public sealed partial class AirAlarmSystem : EntitySystem if (component.State != args.AlarmType) { - TryComp(uid, out var source); - // send low to old state's port - _deviceLink.SendSignal(uid, GetPort(component), false, source); + _deviceLink.SendSignal(uid, GetPort(component), false); // send high to new state's port, along with updating the cached state component.State = args.AlarmType; - _deviceLink.SendSignal(uid, GetPort(component), true, source); + _deviceLink.SendSignal(uid, GetPort(component), true); } UpdateUI(uid, component); @@ -517,7 +494,7 @@ public sealed partial class AirAlarmSystem : EntitySystem } /// - /// Sets device data. Practically a wrapper around the packet sending function, SetData. + /// Sets device data. /// /// The address to send the new data to. /// The device data to be sent. @@ -529,52 +506,44 @@ public sealed partial class AirAlarmSystem : EntitySystem } devData.Dirty = true; - SetData(uid, address, devData); + + devData.RaisePayload(uid, address, _deviceNet); + SetDeviceDataInternal(uid, address, devData); } - private void OnPacketRecv(EntityUid uid, AirAlarmComponent controller, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSetData(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd)) + var (uid, controller) = ent; + if (!controller.CanSync) return; - switch (cmd) + // Save into component. + // Sync data to interface. + switch (args.Data.Payload) { - case AtmosDeviceNetworkSystem.SyncData: - if (!args.Data.TryGetValue(AtmosDeviceNetworkSystem.SyncData, out IAtmosDeviceData? data) - || !controller.CanSync) - break; - - // Save into component. - // Sync data to interface. - switch (data) - { - case GasVentPumpData ventData: - if (!controller.VentData.TryAdd(args.SenderAddress, ventData)) - controller.VentData[args.SenderAddress] = ventData; - break; - case GasVentScrubberData scrubberData: - if (!controller.ScrubberData.TryAdd(args.SenderAddress, scrubberData)) - controller.ScrubberData[args.SenderAddress] = scrubberData; - break; - case AtmosSensorData sensorData: - if (!controller.SensorData.TryAdd(args.SenderAddress, sensorData)) - controller.SensorData[args.SenderAddress] = sensorData; - break; - } - - controller.KnownDevices.Add(args.SenderAddress); - - UpdateUI(uid, controller); - - return; - case AirAlarmSetMode: - if (!args.Data.TryGetValue(AirAlarmSetMode, out AirAlarmMode alarmMode)) - break; - - SetMode(uid, args.SenderAddress, alarmMode, uiOnly: false); - - return; + case GasVentPumpData ventData: + if (!controller.VentData.TryAdd(args.SenderAddress, ventData)) + controller.VentData[args.SenderAddress] = ventData; + break; + case GasVentScrubberData scrubberData: + if (!controller.ScrubberData.TryAdd(args.SenderAddress, scrubberData)) + controller.ScrubberData[args.SenderAddress] = scrubberData; + break; + case AtmosMonitorData sensorData: + if (!controller.SensorData.TryAdd(args.SenderAddress, sensorData)) + controller.SensorData[args.SenderAddress] = sensorData; + break; } + + controller.KnownDevices.Add(args.SenderAddress); + UpdateUI(uid, controller); + } + + [SubscribeLocalEvent] + private void OnSetMode(Entity ent, ref DeviceNetworkPacketEvent args) + { + SetMode(ent, args.SenderAddress, args.Data.Mode, uiOnly: false); } #endregion diff --git a/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs b/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs index f5dfe1486d..5ffd226153 100644 --- a/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs +++ b/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs @@ -1,16 +1,15 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.Atmos.Monitor.Components; +using Content.Server.Atmos.Monitor.Payloads; using Content.Server.DeviceNetwork.Systems; using Content.Shared.Atmos.Monitor; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; using Content.Shared.Tag; using Robust.Server.Audio; using Robust.Server.GameObjects; using Robust.Shared.Audio; -using Robust.Shared.Prototypes; using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Atmos.Monitor.Systems; @@ -22,30 +21,10 @@ public sealed partial class AtmosAlarmableSystem : EntitySystem [Dependency] private DeviceNetworkSystem _deviceNet = default!; [Dependency] private AtmosDeviceNetworkSystem _atmosDevNetSystem = default!; - /// - /// An alarm. Has three valid states: Normal, Warning, Danger. - /// Will attempt to fetch the tags from the alarming entity - /// to send over. - /// - public const string AlertCmd = "atmos_alarm"; - - public const string AlertSource = "atmos_alarm_source"; - - public const string AlertTypes = "atmos_alarm_types"; - - /// - /// Syncs alerts from this alarm receiver to other alarm receivers. - /// Creates a network effect as a result. Note: if the alert receiver - /// is not aware of the device beforehand, it will not sync. - /// - public const string SyncAlerts = "atmos_alarmable_sync_alerts"; - - public const string ResetAll = "atmos_alarmable_reset_all"; - public override void Initialize() { + base.Initialize(); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnPacketRecv); SubscribeLocalEvent(OnPowerChange); } @@ -78,92 +57,73 @@ public sealed partial class AtmosAlarmableSystem : EntitySystem } } - private void OnPacketRecv(EntityUid uid, AtmosAlarmableComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnAlarmPayload(Entity ent, ref DeviceNetworkPacketEvent args) { - if (component.IgnoreAlarms) return; - - if (!TryComp(uid, out DeviceNetworkComponent? netConn)) + var payload = args.Data; + if (!CheckTags(ent, payload)) return; - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd) - || !args.Data.TryGetValue(AlertSource, out HashSet>? sourceTags)) + var (uid, component) = ent; + + var isValid = payload.TrippedThresholds == null + || component.MonitorAlertTypes == AtmosMonitorThresholdTypeFlags.None + || (payload.TrippedThresholds & component.MonitorAlertTypes) != 0; + + if (!component.NetworkAlarmStates.ContainsKey(args.SenderAddress)) { + if (!isValid) + return; + + component.NetworkAlarmStates.Add(args.SenderAddress, payload.Type); + } + else + { + // This is because if the alert is no longer valid, + // it may mean that the threshold we need to look at has + // been removed from the threshold types passed: + // basically, we need to reset this state to normal here. + component.NetworkAlarmStates[args.SenderAddress] = isValid ? payload.Type : AtmosAlarmType.Normal; + } + + if (!TryGetHighestAlert(uid, out var netMax, component)) + { + netMax = AtmosAlarmType.Normal; + } + + TryUpdateAlert(uid, netMax.Value, component); + } + + [SubscribeLocalEvent] + private void OnResetAllPayload(Entity ent, ref DeviceNetworkPacketEvent args) + { + if (!CheckTags(ent, args.Data)) return; - } - var isValid = sourceTags.Any(source => component.SyncWithTags.Contains(source)); + Reset(ent.Owner, ent.Comp); + } - if (!isValid) - { + [SubscribeLocalEvent] + private void OnSyncAlertsPayload(Entity ent, ref DeviceNetworkPacketEvent args) + { + if (!CheckTags(ent, args.Data)) return; - } - switch (cmd) + foreach (var (key, alarm) in args.Data.AlarmStates) { - case AlertCmd: - // Set the alert state, and then cache it so we can calculate - // the maximum alarm state at all times. - if (!args.Data.TryGetValue(DeviceNetworkConstants.CmdSetState, out AtmosAlarmType state)) - { - break; - } - - if (args.Data.TryGetValue(AlertTypes, out AtmosMonitorThresholdTypeFlags types) && component.MonitorAlertTypes != AtmosMonitorThresholdTypeFlags.None) - { - isValid = (types & component.MonitorAlertTypes) != 0; - } - - if (!component.NetworkAlarmStates.ContainsKey(args.SenderAddress)) - { - if (!isValid) - { - break; - } - - component.NetworkAlarmStates.Add(args.SenderAddress, state); - } - else - { - // This is because if the alert is no longer valid, - // it may mean that the threshold we need to look at has - // been removed from the threshold types passed: - // basically, we need to reset this state to normal here. - component.NetworkAlarmStates[args.SenderAddress] = isValid ? state : AtmosAlarmType.Normal; - } - - if (!TryGetHighestAlert(uid, out var netMax, component)) - { - netMax = AtmosAlarmType.Normal; - } - - TryUpdateAlert(uid, netMax.Value, component); - - break; - case ResetAll: - Reset(uid, component); - break; - case SyncAlerts: - if (!args.Data.TryGetValue(SyncAlerts, - out IReadOnlyDictionary? alarms)) - { - break; - } - - foreach (var (key, alarm) in alarms) - { - if (!component.NetworkAlarmStates.TryAdd(key, alarm)) - { - component.NetworkAlarmStates[key] = alarm; - } - } - - if (TryGetHighestAlert(uid, out var maxAlert, component)) - { - TryUpdateAlert(uid, maxAlert.Value, component); - } - - break; + ent.Comp.NetworkAlarmStates.TryAdd(key, alarm); + ent.Comp.NetworkAlarmStates[key] = alarm; } + + if (TryGetHighestAlert(ent, out var maxAlert, ent.Comp)) + { + TryUpdateAlert(ent, maxAlert.Value, ent.Comp); + } + } + + private static bool CheckTags(Entity ent, T payload) where T : IAtmosAlarmableSourcePayload + { + return !ent.Comp.IgnoreAlarms && payload.Source.Any(source => ent.Comp.SyncWithTags.Contains(source)); } private void TryUpdateAlert(EntityUid uid, AtmosAlarmType type, AtmosAlarmableComponent alarmable, bool sync = true) @@ -191,14 +151,13 @@ public sealed partial class AtmosAlarmableSystem : EntitySystem return; } - var payload = new NetworkPayload + var payload = new AtmosAlarmableSyncAlertsPayload { - [DeviceNetworkConstants.Command] = SyncAlerts, - [SyncAlerts] = alarmable.NetworkAlarmStates, - [AlertSource] = tags.Tags + AlarmStates = alarmable.NetworkAlarmStates, + Source = tags.Tags, }; - _deviceNet.QueuePacket(uid, address, payload); + _deviceNet.SendPacket(uid, address, ref payload); } /// @@ -228,41 +187,36 @@ public sealed partial class AtmosAlarmableSystem : EntitySystem alarmable.NetworkAlarmStates[devNet.Address] = alarmType; } - var payload = new NetworkPayload + var payload = new AtmosAlarmPayload { - [DeviceNetworkConstants.Command] = AlertCmd, - [DeviceNetworkConstants.CmdSetState] = alarmType, - [AlertSource] = tags.Tags + Type = alarmType, + Source = tags.Tags, }; - _deviceNet.QueuePacket(uid, null, payload); + _deviceNet.SendPacket(uid, null, ref payload); } /// /// Resets the state of this alarmable to normal. /// - /// - /// - public void Reset(EntityUid uid, AtmosAlarmableComponent? alarmable = null, TagComponent? tags = null) + public void Reset(EntityUid uid, AtmosAlarmableComponent? alarmable = null, TagComponent? tags = null, DeviceNetworkComponent? device = null) { - if (!Resolve(uid, ref alarmable, ref tags, false) || alarmable.LastAlarmState == AtmosAlarmType.Normal) + if (!Resolve(uid, ref alarmable, ref tags, ref device, false) || alarmable.LastAlarmState == AtmosAlarmType.Normal) { return; } - alarmable.NetworkAlarmStates.Clear(); - TryUpdateAlert(uid, AtmosAlarmType.Normal, alarmable); + if (alarmable.NetworkAlarmStates.ContainsKey(device.Address)) + alarmable.NetworkAlarmStates[device.Address] = AtmosAlarmType.Normal; if (!alarmable.ReceiveOnly) { - var payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = ResetAll, - [AlertSource] = tags.Tags - }; - - _deviceNet.QueuePacket(uid, null, payload); + var payload = new AtmosMonitorResetPayload(); + _deviceNet.SendPacket(uid, null, ref payload); } + + TryUpdateAlert(uid, AtmosAlarmType.Normal, alarmable); + alarmable.NetworkAlarmStates.Clear(); } public void ResetAllOnNetwork(EntityUid uid, AtmosAlarmableComponent? alarmable = null) diff --git a/Content.Server/Atmos/Monitor/Systems/AtmosDeviceNetwork.cs b/Content.Server/Atmos/Monitor/Systems/AtmosDeviceNetwork.cs index 55978b2303..30154d8233 100644 --- a/Content.Server/Atmos/Monitor/Systems/AtmosDeviceNetwork.cs +++ b/Content.Server/Atmos/Monitor/Systems/AtmosDeviceNetwork.cs @@ -1,6 +1,10 @@ +using Content.Server.Atmos.Monitor.Payloads; using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Systems; +using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Monitor.Components; +using Content.Shared.Atmos.Piping.Binary.Components; +using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.DeviceNetwork; namespace Content.Server.Atmos.Monitor.Systems; @@ -11,61 +15,23 @@ namespace Content.Server.Atmos.Monitor.Systems; /// public sealed partial class AtmosDeviceNetworkSystem : EntitySystem { - /// - /// Register a device's address on this device. - /// - public const string RegisterDevice = "atmos_register_device"; - - /// - /// Deregister a device's address on this device. - /// - public const string DeregisterDevice = "atmos_deregister_device"; - - /// - /// Synchronize the data this device has with the sender. - /// - public const string SyncData = "atmos_sync_data"; - [Dependency] private DeviceNetworkSystem _deviceNet = default!; public void Register(EntityUid uid, string? address) { - var registerPayload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = RegisterDevice - }; - - _deviceNet.QueuePacket(uid, address, registerPayload); + var registerPayload = new AtmosMonitorRegisterDevicePayload(); + _deviceNet.SendPacket(uid, address, ref registerPayload); } public void Deregister(EntityUid uid, string? address) { - var deregisterPayload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = DeregisterDevice - }; - - _deviceNet.QueuePacket(uid, address, deregisterPayload); + var deregisterPayload = new AtmosMonitorDeregisterDevicePayload(); + _deviceNet.SendPacket(uid, address, ref deregisterPayload); } public void Sync(EntityUid uid, string? address) { - var syncPayload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = SyncData - }; - - _deviceNet.QueuePacket(uid, address, syncPayload); - } - - public void SetDeviceState(EntityUid uid, string address, IAtmosDeviceData data) - { - var payload = new NetworkPayload() - { - [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdSetState, - [DeviceNetworkConstants.CmdSetState] = data - }; - - _deviceNet.QueuePacket(uid, address, payload); + var payload = new AtmosSyncPayload(); + _deviceNet.SendPacket(uid, address, ref payload); } } diff --git a/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs b/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs index ff34828877..52d22899d0 100644 --- a/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs +++ b/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Monitor.Components; +using Content.Server.Atmos.Monitor.Payloads; using Content.Server.Atmos.Piping.EntitySystems; using Content.Server.DeviceNetwork.Systems; using Content.Server.NodeContainer.EntitySystems; @@ -12,7 +13,6 @@ using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Piping.Components; using Content.Shared.Database; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; using Content.Shared.Tag; @@ -31,26 +31,15 @@ public sealed partial class AtmosMonitorSystem : EntitySystem [Dependency] private DeviceNetworkSystem _deviceNetSystem = default!; [Dependency] private NodeContainerSystem _nodeContainerSystem = default!; - // Commands - public const string AtmosMonitorSetThresholdCmd = "atmos_monitor_set_threshold"; - public const string AtmosMonitorSetAllThresholdsCmd = "atmos_monitor_set_all_thresholds"; - - // Packet data - public const string AtmosMonitorThresholdData = "atmos_monitor_threshold_data"; - public const string AtmosMonitorAllThresholdData = "atmos_monitor_all_threshold_data"; - public const string AtmosMonitorThresholdDataType = "atmos_monitor_threshold_type"; - - public const string AtmosMonitorThresholdGasType = "atmos_monitor_threshold_gas"; - public override void Initialize() { + base.Initialize(); SubscribeLocalEvent(OnAtmosMonitorStartup); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnAtmosUpdate); SubscribeLocalEvent(OnFireEvent); SubscribeLocalEvent(OnPowerChangedEvent); SubscribeLocalEvent(BeforePacketRecv); - SubscribeLocalEvent(OnPacketRecv); SubscribeLocalEvent(OnAtmosDeviceLeaveAtmosphere); SubscribeLocalEvent(OnAtmosDeviceEnterAtmosphere); SubscribeLocalEvent(OnAtmosDeviceTileChangedEvent); @@ -112,74 +101,73 @@ public sealed partial class AtmosMonitorSystem : EntitySystem } } - private void BeforePacketRecv(EntityUid uid, AtmosMonitorComponent component, BeforePacketSentEvent args) + private void BeforePacketRecv(Entity ent, ref BeforePacketSentEvent args) { - if (!component.NetEnabled) args.Cancel(); + if (!ent.Comp.NetEnabled) + args.Cancelled = true; } - private void OnPacketRecv(EntityUid uid, AtmosMonitorComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnRegisterDevice(Entity ent, ref DeviceNetworkPacketEvent args) { - // sync the internal 'last alarm state' from - // the other alarms, so that we can calculate - // the highest network alarm state at any time - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd)) + ent.Comp.RegisteredDevices.Add(args.SenderAddress); + } + + [SubscribeLocalEvent] + private void OnDeregisterDevice(Entity ent, ref DeviceNetworkPacketEvent args) + { + ent.Comp.RegisteredDevices.Remove(args.SenderAddress); + } + + [SubscribeLocalEvent] + private void OnReset(Entity ent, ref DeviceNetworkPacketEvent args) + { + Reset(ent); + } + + [SubscribeLocalEvent] + private void OnSetThreshold(Entity ent, ref DeviceNetworkPacketEvent args) + { + SetThreshold(ent, args.Data.Type, args.Data.Threshold, args.Data.Gas); + } + + [SubscribeLocalEvent] + private void OnSetAllThresholds(Entity ent, ref DeviceNetworkPacketEvent args) + { + SetAllThresholds(ent, args.Data.Data); + } + + [SubscribeLocalEvent] + private void OnSyncPayload(Entity ent, ref DeviceNetworkPacketEvent args) + { + var dataPayload = new AtmosMonitorData(); + if (ent.Comp.TileGas != null) { - return; + var gases = new Dictionary(); + foreach (var gas in Enum.GetValues()) + { + gases.Add(gas, ent.Comp.TileGas.GetMoles(gas)); + } + + dataPayload = new AtmosMonitorData( + ent.Comp.TileGas.Pressure, + ent.Comp.TileGas.Temperature, + ent.Comp.TileGas.TotalMoles, + ent.Comp.LastAlarmState, + gases, + ent.Comp.PressureThreshold ?? new(), + ent.Comp.TemperatureThreshold ?? new(), + ent.Comp.GasThresholds ?? new()); } - switch (cmd) + var airAlarm = new AirAlarmSetDataPayload { - case AtmosDeviceNetworkSystem.RegisterDevice: - component.RegisteredDevices.Add(args.SenderAddress); - break; - case AtmosDeviceNetworkSystem.DeregisterDevice: - component.RegisteredDevices.Remove(args.SenderAddress); - break; - case AtmosAlarmableSystem.ResetAll: - Reset(uid); - // Don't clear alarm states here. - break; - case AtmosMonitorSetThresholdCmd: - if (args.Data.TryGetValue(AtmosMonitorThresholdData, out AtmosAlarmThreshold? thresholdData) - && args.Data.TryGetValue(AtmosMonitorThresholdDataType, out AtmosMonitorThresholdType? thresholdType)) - { - args.Data.TryGetValue(AtmosMonitorThresholdGasType, out Gas? gas); - SetThreshold(uid, thresholdType.Value, thresholdData, gas); - } - break; - case AtmosMonitorSetAllThresholdsCmd: - if (args.Data.TryGetValue(AtmosMonitorAllThresholdData, out AtmosSensorData? allThresholdData)) - { - SetAllThresholds(uid, allThresholdData); - } - break; - case AtmosDeviceNetworkSystem.SyncData: - var payload = new NetworkPayload(); - payload.Add(DeviceNetworkConstants.Command, AtmosDeviceNetworkSystem.SyncData); - if (component.TileGas != null) - { - var gases = new Dictionary(); - foreach (var gas in Enum.GetValues()) - { - gases.Add(gas, component.TileGas.GetMoles(gas)); - } + Payload = dataPayload, + }; - payload.Add(AtmosDeviceNetworkSystem.SyncData, new AtmosSensorData( - component.TileGas.Pressure, - component.TileGas.Temperature, - component.TileGas.TotalMoles, - component.LastAlarmState, - gases, - component.PressureThreshold ?? new(), - component.TemperatureThreshold ?? new(), - component.GasThresholds ?? new() - )); - } - - _deviceNetSystem.QueuePacket(uid, args.SenderAddress, payload); - Alert(uid, component.LastAlarmState); - break; - } + dataPayload.RaisePayload(ent.Owner, args.SenderAddress, _deviceNetSystem); + _deviceNetSystem.SendPacket(ent.Owner, args.SenderAddress, ref airAlarm); + Alert(ent, ent.Comp.LastAlarmState); } private void OnPowerChangedEvent(Entity ent, ref PowerChangedEvent args) @@ -375,17 +363,16 @@ public sealed partial class AtmosMonitorSystem : EntitySystem return; } - var payload = new NetworkPayload + var payload = new AtmosAlarmPayload { - [DeviceNetworkConstants.Command] = AtmosAlarmableSystem.AlertCmd, - [DeviceNetworkConstants.CmdSetState] = monitor.LastAlarmState, - [AtmosAlarmableSystem.AlertSource] = tags.Tags, - [AtmosAlarmableSystem.AlertTypes] = monitor.TrippedThresholds + Type = monitor.LastAlarmState, + Source = tags.Tags, + TrippedThresholds = monitor.TrippedThresholds, }; foreach (var addr in monitor.RegisteredDevices) { - _deviceNetSystem.QueuePacket(owner, addr, payload); + _deviceNetSystem.SendPacket(owner, addr, ref payload); } } @@ -475,14 +462,14 @@ public sealed partial class AtmosMonitorSystem : EntitySystem /// AtmosSensorData object's thresholds. /// /// The entity's uid - /// An AtmosSensorData object from which the thresholds will be loaded. - public void SetAllThresholds(EntityUid uid, AtmosSensorData allThresholdData) + /// An AtmosSensorData object from which the thresholds will be loaded. + public void SetAllThresholds(EntityUid uid, AtmosMonitorData allThresholdDataPayload) { - SetThreshold(uid, AtmosMonitorThresholdType.Temperature, allThresholdData.TemperatureThreshold); - SetThreshold(uid, AtmosMonitorThresholdType.Pressure, allThresholdData.PressureThreshold); + SetThreshold(uid, AtmosMonitorThresholdType.Temperature, allThresholdDataPayload.TemperatureThreshold); + SetThreshold(uid, AtmosMonitorThresholdType.Pressure, allThresholdDataPayload.PressureThreshold); foreach (var gas in Enum.GetValues()) { - SetThreshold(uid, AtmosMonitorThresholdType.Gas, allThresholdData.GasThresholds[gas], gas); + SetThreshold(uid, AtmosMonitorThresholdType.Gas, allThresholdDataPayload.GasThresholds[gas], gas); } } } diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs index 8729bd18fa..977ee1d611 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs @@ -1,5 +1,5 @@ using Content.Server.Atmos.EntitySystems; -using Content.Server.Atmos.Monitor.Systems; +using Content.Server.Atmos.Monitor.Payloads; using Content.Server.DeviceNetwork.Systems; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NodeContainer.Nodes; @@ -9,11 +9,9 @@ using Content.Shared.Atmos.Piping.Binary.Components; using Content.Shared.Atmos.Piping.Binary.Systems; using Content.Shared.Atmos.Piping.Components; using Content.Shared.Audio; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using JetBrains.Annotations; using Robust.Server.GameObjects; -using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Atmos.Piping.Binary.EntitySystems { @@ -32,8 +30,6 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems SubscribeLocalEvent(OnVolumePumpUpdated); SubscribeLocalEvent(OnVolumePumpLeaveAtmosphere); - - SubscribeLocalEvent(OnPacketRecv); } private void OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, ref AtmosDeviceUpdateEvent args) @@ -107,25 +103,15 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems _userInterfaceSystem.CloseUi(uid, GasVolumePumpUiKey.Key); } - private void OnPacketRecv(EntityUid uid, GasVolumePumpComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSyncPayload(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!TryComp(uid, out DeviceNetworkComponent? netConn) - || !args.Data.TryGetValue(DeviceNetworkConstants.Command, out var cmd)) + var data = new GasVolumePumpDataPayload { - return; - } + LastMolesTransferred = ent.Comp.LastMolesTransferred, + }; - var payload = new NetworkPayload(); - - switch (cmd) - { - case AtmosDeviceNetworkSystem.SyncData: - payload.Add(DeviceNetworkConstants.Command, AtmosDeviceNetworkSystem.SyncData); - payload.Add(AtmosDeviceNetworkSystem.SyncData, new GasVolumePumpData(component.LastMolesTransferred)); - - _deviceNetwork.QueuePacket(uid, args.SenderAddress, payload, device: netConn); - return; - } + _deviceNetwork.SendPacket(ent.Owner, args.SenderAddress, ref data); } } } diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs index 175629076a..2bbe6ab70e 100644 --- a/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs +++ b/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs @@ -169,15 +169,15 @@ namespace Content.Server.Atmos.Piping.Unary.Components }; } - public void FromAirAlarmData(GasVentPumpData data) + public void FromAirAlarmData(GasVentPumpData dataPayload) { - Enabled = data.Enabled; - IsDirty = data.Dirty; - PumpDirection = data.PumpDirection; - PressureChecks = data.PressureChecks; - ExternalPressureBound = data.ExternalPressureBound; - InternalPressureBound = data.InternalPressureBound; - PressureLockoutOverride = data.PressureLockoutOverride; + Enabled = dataPayload.Enabled; + IsDirty = dataPayload.Dirty; + PumpDirection = dataPayload.PumpDirection; + PressureChecks = dataPayload.PressureChecks; + ExternalPressureBound = dataPayload.ExternalPressureBound; + InternalPressureBound = dataPayload.InternalPressureBound; + PressureLockoutOverride = dataPayload.PressureLockoutOverride; } #region GuidebookData diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs index 4a9437bc1f..21b4fbb87a 100644 --- a/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs +++ b/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs @@ -66,18 +66,18 @@ namespace Content.Server.Atmos.Piping.Unary.Components }; } - public void FromAirAlarmData(GasVentScrubberData data) + public void FromAirAlarmData(GasVentScrubberData dataPayload) { - Enabled = data.Enabled; - IsDirty = data.Dirty; - PumpDirection = data.PumpDirection; - TransferRate = data.VolumeRate; - WideNet = data.WideNet; + Enabled = dataPayload.Enabled; + IsDirty = dataPayload.Dirty; + PumpDirection = dataPayload.PumpDirection; + TransferRate = dataPayload.VolumeRate; + WideNet = dataPayload.WideNet; - if (!data.FilterGases.SequenceEqual(FilterGases)) + if (!dataPayload.FilterGases.SequenceEqual(FilterGases)) { FilterGases.Clear(); - foreach (var gas in data.FilterGases) + foreach (var gas in dataPayload.FilterGases) FilterGases.Add(gas); } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs index f4af8e6f9b..950aeb7491 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs @@ -1,5 +1,5 @@ using Content.Server.Atmos.EntitySystems; -using Content.Server.Atmos.Monitor.Systems; +using Content.Server.Atmos.Monitor.Payloads; using Content.Server.DeviceNetwork.Systems; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NodeContainer.Nodes; @@ -10,9 +10,7 @@ using JetBrains.Annotations; using Content.Server.Power.EntitySystems; using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Piping.Unary.Systems; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; -using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Atmos.Piping.Unary.EntitySystems { @@ -27,11 +25,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnThermoMachineUpdated); - - // Device network - SubscribeLocalEvent(OnPacketRecv); } private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, ref AtmosDeviceUpdateEvent args) @@ -117,24 +111,15 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems } } - private void OnPacketRecv(EntityUid uid, GasThermoMachineComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSyncPayload(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!TryComp(uid, out DeviceNetworkComponent? netConn) - || !args.Data.TryGetValue(DeviceNetworkConstants.Command, out var cmd)) - return; - - var payload = new NetworkPayload(); - - switch (cmd) + var data = new GasThermoMachineDataPayload { - case AtmosDeviceNetworkSystem.SyncData: - payload.Add(DeviceNetworkConstants.Command, AtmosDeviceNetworkSystem.SyncData); - payload.Add(AtmosDeviceNetworkSystem.SyncData, new GasThermoMachineData(component.LastEnergyDelta)); + EnergyDelta = ent.Comp.LastEnergyDelta, + }; - _deviceNetwork.QueuePacket(uid, args.SenderAddress, payload, device: netConn); - - return; - } + _deviceNetwork.SendPacket(ent.Owner, args.SenderAddress, ref data); } } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs index e9d1c36a16..4b93c3cc84 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Atmos.EntitySystems; +using Content.Server.Atmos.Monitor.Payloads; using Content.Server.Atmos.Monitor.Systems; using Content.Server.Atmos.Piping.Unary.Components; using Content.Server.DeviceLinking.Systems; @@ -17,8 +18,6 @@ using Content.Shared.Atmos.Visuals; using Content.Shared.Audio; using Content.Shared.Database; using Content.Shared.DeviceLinking.Events; -using Content.Shared.DeviceNetwork; -using Content.Shared.DeviceNetwork.Components; using Content.Shared.DoAfter; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Examine; @@ -45,6 +44,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems [Dependency] private SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private IGameTiming _timing = default!; [Dependency] private PowerReceiverSystem _powerReceiverSystem = default!; + public override void Initialize() { base.Initialize(); @@ -54,7 +54,6 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems SubscribeLocalEvent(OnGasVentPumpEnterAtmosphere); SubscribeLocalEvent(OnAtmosAlarm); SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnPacketRecv); SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(OnSignalReceived); @@ -216,70 +215,67 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems UpdateState(uid, component); } - private void OnPacketRecv(EntityUid uid, GasVentPumpComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSyncPayload(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!TryComp(uid, out DeviceNetworkComponent? netConn) - || !args.Data.TryGetValue(DeviceNetworkConstants.Command, out var cmd)) - return; - - var payload = new NetworkPayload(); - - switch (cmd) + var data = ent.Comp.ToAirAlarmData(); + var airAlarm = new AirAlarmSetDataPayload { - case AtmosDeviceNetworkSystem.SyncData: - payload.Add(DeviceNetworkConstants.Command, AtmosDeviceNetworkSystem.SyncData); - payload.Add(AtmosDeviceNetworkSystem.SyncData, component.ToAirAlarmData()); + Payload = data, + }; + _deviceNetSystem.SendPacket(ent.Owner, args.SenderAddress, ref airAlarm); + } - _deviceNetSystem.QueuePacket(uid, args.SenderAddress, payload, device: netConn); + [SubscribeLocalEvent] + private void OnSetPayload(Entity ent, ref DeviceNetworkPacketEvent args) + { + var setData = args.Data.Data; + var previous = ent.Comp.ToAirAlarmData(); - return; - case DeviceNetworkConstants.CmdSetState: - if (!args.Data.TryGetValue(DeviceNetworkConstants.CmdSetState, out GasVentPumpData? setData)) - break; - - var previous = component.ToAirAlarmData(); - - if (previous.Enabled != setData.Enabled) - { - string enabled = setData.Enabled ? "enabled" : "disabled" ; - _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(uid)} {enabled}"); - } - - if (previous.PumpDirection != setData.PumpDirection) - _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(uid)} direction changed to {setData.PumpDirection}"); - - if (previous.PressureChecks != setData.PressureChecks) - _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(uid)} pressure check changed to {setData.PressureChecks}"); - - if (previous.ExternalPressureBound != setData.ExternalPressureBound) - { - _adminLogger.Add( - LogType.AtmosDeviceSetting, - LogImpact.Medium, - $"{ToPrettyString(uid)} external pressure bound changed from {previous.ExternalPressureBound} kPa to {setData.ExternalPressureBound} kPa" - ); - } - - if (previous.InternalPressureBound != setData.InternalPressureBound) - { - _adminLogger.Add( - LogType.AtmosDeviceSetting, - LogImpact.Medium, - $"{ToPrettyString(uid)} internal pressure bound changed from {previous.InternalPressureBound} kPa to {setData.InternalPressureBound} kPa" - ); - } - - if (previous.PressureLockoutOverride != setData.PressureLockoutOverride) - { - string enabled = setData.PressureLockoutOverride ? "enabled" : "disabled" ; - _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(uid)} pressure lockout override {enabled}"); - } - - component.FromAirAlarmData(setData); - UpdateState(uid, component); - - return; + if (previous.Enabled != setData.Enabled) + { + string enabled = setData.Enabled ? "enabled" : "disabled"; + _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(ent)} {enabled}"); } + + if (previous.PumpDirection != setData.PumpDirection) + _adminLogger.Add(LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} direction changed to {setData.PumpDirection}"); + + if (previous.PressureChecks != setData.PressureChecks) + _adminLogger.Add(LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} pressure check changed to {setData.PressureChecks}"); + + if (previous.ExternalPressureBound != setData.ExternalPressureBound) + { + _adminLogger.Add( + LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} external pressure bound changed from {previous.ExternalPressureBound} kPa to {setData.ExternalPressureBound} kPa" + ); + } + + if (previous.InternalPressureBound != setData.InternalPressureBound) + { + _adminLogger.Add( + LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} internal pressure bound changed from {previous.InternalPressureBound} kPa to {setData.InternalPressureBound} kPa" + ); + } + + if (previous.PressureLockoutOverride != setData.PressureLockoutOverride) + { + string enabled = setData.PressureLockoutOverride ? "enabled" : "disabled"; + _adminLogger.Add(LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} pressure lockout override {enabled}"); + } + + ent.Comp.FromAirAlarmData(setData); + UpdateState(ent, ent.Comp); } private void OnInit(EntityUid uid, GasVentPumpComponent component, ComponentInit args) diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs index 81e94e6ab7..94fea1758b 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Atmos.EntitySystems; +using Content.Server.Atmos.Monitor.Payloads; using Content.Server.Atmos.Monitor.Systems; using Content.Server.Atmos.Piping.Unary.Components; using Content.Server.DeviceNetwork.Systems; @@ -14,8 +15,6 @@ using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Atmos.Piping.Unary.Visuals; using Content.Shared.Audio; using Content.Shared.Database; -using Content.Shared.DeviceNetwork; -using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; using Content.Shared.Tools.Systems; @@ -46,7 +45,6 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems SubscribeLocalEvent(OnVentScrubberLeaveAtmosphere); SubscribeLocalEvent(OnAtmosAlarm); SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnPacketRecv); SubscribeLocalEvent(OnWeldChanged); } @@ -146,69 +144,68 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems UpdateState(uid, component); } - private void OnPacketRecv(EntityUid uid, GasVentScrubberComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSyncPayload(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!TryComp(uid, out DeviceNetworkComponent? netConn) - || !args.Data.TryGetValue(DeviceNetworkConstants.Command, out var cmd)) - return; - - var payload = new NetworkPayload(); - - switch (cmd) + var data = ent.Comp.ToAirAlarmData(); + var airAlarm = new AirAlarmSetDataPayload { - case AtmosDeviceNetworkSystem.SyncData: - payload.Add(DeviceNetworkConstants.Command, AtmosDeviceNetworkSystem.SyncData); - payload.Add(AtmosDeviceNetworkSystem.SyncData, component.ToAirAlarmData()); + Payload = data, + }; + _deviceNetSystem.SendPacket(ent.Owner, args.SenderAddress, ref airAlarm); + } - _deviceNetSystem.QueuePacket(uid, args.SenderAddress, payload, device: netConn); + [SubscribeLocalEvent] + private void OnSetPayload(Entity ent, ref DeviceNetworkPacketEvent args) + { + var setData = args.Data.Data; + var previous = ent.Comp.ToAirAlarmData(); - return; - case DeviceNetworkConstants.CmdSetState: - if (!args.Data.TryGetValue(DeviceNetworkConstants.CmdSetState, out GasVentScrubberData? setData)) - break; - - var previous = component.ToAirAlarmData(); - - if (previous.Enabled != setData.Enabled) - { - string enabled = setData.Enabled ? "enabled" : "disabled" ; - _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(uid)} {enabled}"); - } - - // TODO: IgnoreAlarms? - - if (previous.PumpDirection != setData.PumpDirection) - _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(uid)} direction changed to {setData.PumpDirection}"); - - // TODO: This is iterating through both sets, it could probably be faster but they're both really small sets anyways - foreach (Gas gas in previous.FilterGases) - if (!setData.FilterGases.Contains(gas)) - _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(uid)} {gas} filtering disabled"); - - foreach (Gas gas in setData.FilterGases) - if (!previous.FilterGases.Contains(gas)) - _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(uid)} {gas} filtering enabled"); - - if (previous.VolumeRate != setData.VolumeRate) - { - _adminLogger.Add( - LogType.AtmosDeviceSetting, - LogImpact.Medium, - $"{ToPrettyString(uid)} volume rate changed from {previous.VolumeRate} L to {setData.VolumeRate} L" - ); - } - - if (previous.WideNet != setData.WideNet) - { - string enabled = setData.WideNet ? "enabled" : "disabled" ; - _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(uid)} WideNet {enabled}"); - } - - component.FromAirAlarmData(setData); - UpdateState(uid, component); - - return; + if (previous.Enabled != setData.Enabled) + { + string enabled = setData.Enabled ? "enabled" : "disabled"; + _adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium, $"{ToPrettyString(ent)} {enabled}"); } + + // TODO: IgnoreAlarms? + + if (previous.PumpDirection != setData.PumpDirection) + _adminLogger.Add(LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} direction changed to {setData.PumpDirection}"); + + // TODO: This is iterating through both sets, it could probably be faster but they're both really small sets anyways + foreach (Gas gas in previous.FilterGases) + if (!setData.FilterGases.Contains(gas)) + _adminLogger.Add(LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} {gas} filtering disabled"); + + foreach (Gas gas in setData.FilterGases) + if (!previous.FilterGases.Contains(gas)) + _adminLogger.Add(LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} {gas} filtering enabled"); + + if (previous.VolumeRate != setData.VolumeRate) + { + _adminLogger.Add( + LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} volume rate changed from {previous.VolumeRate} L to {setData.VolumeRate} L" + ); + } + + if (previous.WideNet != setData.WideNet) + { + string enabled = setData.WideNet ? "enabled" : "disabled"; + _adminLogger.Add(LogType.AtmosDeviceSetting, + LogImpact.Medium, + $"{ToPrettyString(ent)} WideNet {enabled}"); + } + + ent.Comp.FromAirAlarmData(setData); + UpdateState(ent, ent.Comp); } /// diff --git a/Content.Server/Communications/CommunicationsConsoleSystem.cs b/Content.Server/Communications/CommunicationsConsoleSystem.cs index 3a0879fcc2..afb465916e 100644 --- a/Content.Server/Communications/CommunicationsConsoleSystem.cs +++ b/Content.Server/Communications/CommunicationsConsoleSystem.cs @@ -3,7 +3,6 @@ using Content.Server.Chat.Systems; using Content.Server.DeviceNetwork.Systems; using Content.Server.Popups; using Content.Server.RoundEnd; -using Content.Server.Screens.Components; using Content.Server.Shuttles.Systems; using Content.Server.Station.Systems; using Content.Shared.Access.Components; @@ -13,10 +12,10 @@ using Content.Shared.CCVar; using Content.Shared.Chat; using Content.Shared.Communications; using Content.Shared.Database; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.IdentityManagement; using Content.Shared.Popups; +using Content.Shared.Screens; using Robust.Server.GameObjects; using Robust.Shared.Configuration; using Robust.Shared.Prototypes; @@ -252,12 +251,12 @@ namespace Content.Server.Communications if (!TryComp(uid, out var net)) return; - var payload = new NetworkPayload + var payload = new ScreenTextPayload { - [ScreenMasks.Text] = message.Message + Text = message.Message, }; - _deviceNetworkSystem.QueuePacket(uid, null, payload, net.TransmitFrequency); + _deviceNetworkSystem.SendPacket(uid, null, ref payload, net.TransmitFrequency); _adminLogger.Add(LogType.DeviceNetwork, LogImpact.Low, $"{ToPrettyString(message.Actor):player} has sent the following broadcast: {message.Message:msg}"); } diff --git a/Content.Server/DeviceLinking/Components/Overload/SpawnOnOverloadComponent.cs b/Content.Server/DeviceLinking/Components/Overload/SpawnOnOverloadComponent.cs index aff1c5639c..0ca9018fab 100644 --- a/Content.Server/DeviceLinking/Components/Overload/SpawnOnOverloadComponent.cs +++ b/Content.Server/DeviceLinking/Components/Overload/SpawnOnOverloadComponent.cs @@ -16,5 +16,5 @@ public sealed partial class SpawnOnOverloadComponent : Component /// The entity prototype to spawn when the device overloads /// [DataField("spawnedPrototype")] - public EntProtoId Prototype = "PuddleSparkle"; + public EntProtoId Prototype = "EffectSparks"; } diff --git a/Content.Server/DeviceLinking/Systems/DeviceLinkSystem.cs b/Content.Server/DeviceLinking/Systems/DeviceLinkSystem.cs index 3f1289cb5c..08acf09fa0 100644 --- a/Content.Server/DeviceLinking/Systems/DeviceLinkSystem.cs +++ b/Content.Server/DeviceLinking/Systems/DeviceLinkSystem.cs @@ -1,6 +1,3 @@ -using Content.Server.DeviceLinking.Components; -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Shared.DeviceLinking; using Content.Shared.DeviceLinking.Events; @@ -18,28 +15,65 @@ public sealed partial class DeviceLinkSystem : SharedDeviceLinkSystem { base.Initialize(); - SubscribeLocalEvent(OnPacketReceived); - SubscribeLocalEvent(OnNewLink); + // TODO: make an engine PR to allow for auto-generated relay subscriptions + // Should be doable by using reflection on marker interfaces and then adding them to the auto-generated subscriptions + // I know it looks absolutely hilarious and horrible, but uuuhhhh anything to avoid boxing allocations!!!!!!!! :godo: + SubscribeLocalEvent>>(OnSignalReceived); + } + + private void OnSignalReceived(Entity ent, + ref DeviceNetworkPacketEvent> args) where T : ISignalNetworkPayload + { + var (uid, component) = ent; + if (!component.Ports.Contains(args.Data.InvokedPort)) + return; + + var eventArgs = new SignalReceivedEvent(args.Data.InvokedPort, args.Data.Payload, args.Sender); + RaiseLocalEvent(uid, ref eventArgs); } #region Sending & Receiving - public override void InvokePort(EntityUid uid, string port, NetworkPayload? data = null, DeviceLinkSourceComponent? sourceComponent = null) + + public override void InvokePort(Entity ent, string port) { - if (!Resolve(uid, ref sourceComponent) || !sourceComponent.Outputs.TryGetValue(port, out var sinks)) + if (!DeviceLinkSourceQuery.Resolve(ent.Owner, ref ent.Comp) || + !ent.Comp.Outputs.TryGetValue(port, out var sinks)) return; foreach (var sinkUid in sinks) { - if (!sourceComponent.LinkedPorts.TryGetValue(sinkUid, out var links)) + if (!ent.Comp.LinkedPorts.TryGetValue(sinkUid, out var links)) continue; - if (!TryComp(sinkUid, out var sinkComponent)) + if (!DeviceLinkSinkQuery.TryComp(sinkUid, out var sinkComponent)) continue; foreach (var (source, sink) in links) { if (source == port) - InvokeDirect((uid, sourceComponent), (sinkUid, sinkComponent), source, sink, data); + InvokeDirect((ent.Owner, ent.Comp), (sinkUid, sinkComponent), sink); + } + } + } + + public override void InvokePort(Entity ent, string port, ref T data) + { + if (!DeviceLinkSourceQuery.Resolve(ent.Owner, ref ent.Comp) || + !ent.Comp.Outputs.TryGetValue(port, out var sinks)) + return; + + foreach (var sinkUid in sinks) + { + if (!ent.Comp.LinkedPorts.TryGetValue(sinkUid, out var links)) + continue; + + if (!DeviceLinkSinkQuery.TryComp(sinkUid, out var sinkComponent)) + continue; + + foreach (var (source, sink) in links) + { + if (source == port) + InvokeDirect(ent!, (sinkUid, sinkComponent), sink, ref data); } } } @@ -47,9 +81,11 @@ public sealed partial class DeviceLinkSystem : SharedDeviceLinkSystem /// /// Raises an event on or sends a network packet directly to a sink from a source. /// - private void InvokeDirect(Entity source, Entity sink, string sourcePort, string sinkPort, NetworkPayload? data) + private void InvokeDirect(Entity source, + Entity sink, + string sinkPort) { - if (!Resolve(sink, ref sink.Comp)) + if (!DeviceLinkSinkQuery.Resolve(sink, ref sink.Comp)) return; var invokeCounter = GetEffectiveInvokeCounter(sink.Comp); @@ -72,41 +108,79 @@ public sealed partial class DeviceLinkSystem : SharedDeviceLinkSystem return; } - var payload = new NetworkPayload() + var payload = new SignalPayload { - [InvokedPort] = sinkPort + InvokedPort = sinkPort, }; - if (data != null) + // force using wireless network so things like atmos devices are able to send signals + _deviceNetworkSystem.SendPacket(source.Owner, + sinkNetwork.Address, + ref payload, + sinkNetwork.ReceiveFrequency, + (int)DeviceNetIdDefaults.Wireless); + } + + /// + /// Raises an event on or sends a network packet directly to a sink from a source. + /// + private void InvokeDirect(Entity source, + Entity sink, + string sinkPort, + ref T data) where T : ISignalNetworkPayload + { + if (!DeviceLinkSinkQuery.Resolve(sink, ref sink.Comp)) + return; + + var invokeCounter = GetEffectiveInvokeCounter(sink.Comp); + if (invokeCounter > sink.Comp.InvokeLimit) { - //Prevent overriding the invoked port - data.Remove(InvokedPort); - foreach (var (key, value) in data) - { - payload.Add(key, value); - } + SetInvokeCounter(sink.Comp, 0); + var args = new DeviceLinkOverloadedEvent(); + RaiseLocalEvent(sink, ref args); + RemoveAllFromSink(sink, sink.Comp); + return; } + SetInvokeCounter(sink.Comp, invokeCounter + 1); + + //Just skip using device networking if the source or the sink doesn't support it + if (!HasComp(source) || !TryComp(sink, out var sinkNetwork)) + { + var eventArgs = new SignalReceivedEvent(sinkPort, source); + RaiseLocalEvent(sink, ref eventArgs); + return; + } + + var payload = new SignalPayload + { + InvokedPort = sinkPort, + Payload = data, + }; + // force using wireless network so things like atmos devices are able to send signals - var network = (int) DeviceNetworkComponent.DeviceNetIdDefaults.Wireless; - _deviceNetworkSystem.QueuePacket(source, sinkNetwork.Address, payload, sinkNetwork.ReceiveFrequency, network); + _deviceNetworkSystem.SendPacket(source.Owner, + sinkNetwork.Address, + ref payload, + sinkNetwork.ReceiveFrequency, + (int)DeviceNetIdDefaults.Wireless); } /// /// Helper function that invokes a port with a high/low binary logic signal. /// - public void SendSignal(EntityUid uid, string port, bool signal, DeviceLinkSourceComponent? comp = null) + public void SendSignal(Entity ent, string port, bool signal) { - if (!Resolve(uid, ref comp)) + if (!DeviceLinkSourceQuery.Resolve(ent.Owner, ref ent.Comp)) return; - var data = new NetworkPayload + var data = new LogicStatePayload { - [DeviceNetworkConstants.LogicState] = signal ? SignalState.High : SignalState.Low + State = signal ? SignalState.High : SignalState.Low }; - InvokePort(uid, port, data, comp); + InvokePort(ent, port, ref data); - comp.LastSignals[port] = signal; + ent.Comp.LastSignals[port] = signal; } /// @@ -116,7 +190,7 @@ public sealed partial class DeviceLinkSystem : SharedDeviceLinkSystem /// public void ClearSignal(Entity ent, string port) { - if (!Resolve(ent, ref ent.Comp)) + if (!DeviceLinkSourceQuery.Resolve(ent, ref ent.Comp)) return; ent.Comp.LastSignals.Remove(port); @@ -126,18 +200,21 @@ public sealed partial class DeviceLinkSystem : SharedDeviceLinkSystem /// Checks if the payload has a port defined and if the port is present on the sink. /// Raises a containing the payload when the check passes /// - private void OnPacketReceived(EntityUid uid, DeviceLinkSinkComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSignalReceived(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!args.Data.TryGetValue(InvokedPort, out string? port) || !(component.Ports?.Contains(port) ?? false)) + var (uid, component) = ent; + if (!component.Ports.Contains(args.Data.InvokedPort)) return; - var eventArgs = new SignalReceivedEvent(port, args.Sender, args.Data); - RaiseLocalEvent(uid, ref eventArgs); + var eventArgs = new SignalReceivedEvent(args.Data.InvokedPort, args.Sender); + RaiseLocalEvent(uid, ref eventArgs); } /// /// When linking from a port that currently has a signal being sent, invoke the new link with that signal. /// + [SubscribeLocalEvent] private void OnNewLink(Entity ent, ref NewLinkEvent args) { if (args.Source != ent.Owner) @@ -147,11 +224,12 @@ public sealed partial class DeviceLinkSystem : SharedDeviceLinkSystem if (!ent.Comp.LastSignals.TryGetValue(args.SourcePort, out var signal)) return; - var payload = new NetworkPayload() + var payload = new LogicStatePayload { - [DeviceNetworkConstants.LogicState] = signal ? SignalState.High : SignalState.Low + State = signal ? SignalState.High : SignalState.Low }; - InvokeDirect(ent, args.Sink, args.SourcePort, args.SinkPort, payload); + InvokeDirect(ent, args.Sink, args.SinkPort, ref payload); } + #endregion } diff --git a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs index 39c84057d9..af3fe102d2 100644 --- a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs +++ b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs @@ -1,9 +1,7 @@ using Content.Server.DeviceLinking.Components; -using Content.Server.DeviceNetwork; using Content.Server.Doors.Systems; using Content.Shared.DeviceLinking; using Content.Shared.DeviceLinking.Events; -using Content.Shared.DeviceNetwork; using Content.Shared.Doors.Components; using Content.Shared.Doors; using JetBrains.Annotations; @@ -36,10 +34,38 @@ namespace Content.Server.DeviceLinking.Systems if (!TryComp(uid, out DoorComponent? door)) return; - var state = SignalState.Momentary; - args.Data?.TryGetValue(DeviceNetworkConstants.LogicState, out state); + if (args.Port == component.OpenPort) + { + if (door.State == DoorState.Closed) + _doorSystem.TryOpen(uid, door); + } + else if (args.Port == component.ClosePort) + { + if (door.State == DoorState.Open) + _doorSystem.TryClose(uid, door); + } + else if (args.Port == component.TogglePort) + { + _doorSystem.TryToggleDoor(uid, door); + } + else if (args.Port == component.InBolt) + { + if (!TryComp(uid, out var bolts)) + return; + // if its a pulse toggle, otherwise set bolts to high/low + var bolt = !bolts.BoltsDown; + _doorSystem.SetBoltsDown((uid, bolts), bolt); + } + } + [SubscribeLocalEvent] + private void OnSignalReceived(EntityUid uid, DoorSignalControlComponent component, ref SignalReceivedEvent args) + { + if (!TryComp(uid, out DoorComponent? door)) + return; + + var state = args.Data.State; if (args.Port == component.OpenPort) { if (state == SignalState.High || state == SignalState.Momentary) diff --git a/Content.Server/DeviceLinking/Systems/EdgeDetectorSystem.cs b/Content.Server/DeviceLinking/Systems/EdgeDetectorSystem.cs index 6e6fc18d0f..e5cb203368 100644 --- a/Content.Server/DeviceLinking/Systems/EdgeDetectorSystem.cs +++ b/Content.Server/DeviceLinking/Systems/EdgeDetectorSystem.cs @@ -1,7 +1,6 @@ using Content.Server.DeviceLinking.Components; using Content.Shared.DeviceLinking; using Content.Shared.DeviceLinking.Events; -using Content.Shared.DeviceNetwork; namespace Content.Server.DeviceLinking.Systems; @@ -14,7 +13,6 @@ public sealed partial class EdgeDetectorSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnSignalReceived); } private void OnInit(EntityUid uid, EdgeDetectorComponent comp, ComponentInit args) @@ -23,25 +21,21 @@ public sealed partial class EdgeDetectorSystem : EntitySystem _deviceLink.EnsureSourcePorts(uid, comp.OutputHighPort, comp.OutputLowPort); } - private void OnSignalReceived(EntityUid uid, EdgeDetectorComponent comp, ref SignalReceivedEvent args) + [SubscribeLocalEvent] + private void OnSignalReceived(EntityUid uid, EdgeDetectorComponent comp, ref SignalReceivedEvent args) { - // only handle signals with edges - var state = SignalState.Momentary; - if (args.Data == null || - !args.Data.TryGetValue(DeviceNetworkConstants.LogicState, out state) || - state == SignalState.Momentary) - return; + var state = args.Data.State; if (args.Port != comp.InputPort) return; // make sure the level changed, multiple devices sending the same level are treated as one spamming - if (comp.State != state) - { - comp.State = state; + if (comp.State == state) + return; - var port = state == SignalState.High ? comp.OutputHighPort : comp.OutputLowPort; - _deviceLink.InvokePort(uid, port); - } + comp.State = state; + + var port = state == SignalState.High ? comp.OutputHighPort : comp.OutputLowPort; + _deviceLink.InvokePort(uid, port); } } diff --git a/Content.Server/DeviceLinking/Systems/LogicGateSystem.cs b/Content.Server/DeviceLinking/Systems/LogicGateSystem.cs index 4a09e3801a..8a555de291 100644 --- a/Content.Server/DeviceLinking/Systems/LogicGateSystem.cs +++ b/Content.Server/DeviceLinking/Systems/LogicGateSystem.cs @@ -1,8 +1,6 @@ using Content.Server.DeviceLinking.Components; -using Content.Server.DeviceNetwork; using Content.Shared.DeviceLinking; using Content.Shared.DeviceLinking.Events; -using Content.Shared.DeviceNetwork; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Popups; @@ -96,8 +94,26 @@ public sealed partial class LogicGateSystem : EntitySystem { // default to momentary for compatibility with non-logic signals. // currently only door status and logic gates have logic signal state. - var state = SignalState.Momentary; - args.Data?.TryGetValue(DeviceNetworkConstants.LogicState, out state); + + // update the state for the correct port + if (args.Port == comp.InputPortA) + { + comp.StateA = SignalState.Momentary; + _appearance.SetData(uid, LogicGateVisuals.InputA, false); //If A == High => Sets input A sprite to True + } + else if (args.Port == comp.InputPortB) + { + comp.StateB = SignalState.Momentary; + _appearance.SetData(uid, LogicGateVisuals.InputB, false); //If B == High => Sets input B sprite to True + } + + UpdateOutput(uid, comp); + } + + [SubscribeLocalEvent] + private void OnSignalReceived(EntityUid uid, LogicGateComponent comp, ref SignalReceivedEvent args) + { + var state = args.Data.State; // update the state for the correct port if (args.Port == comp.InputPortA) diff --git a/Content.Server/DeviceLinking/Systems/MemoryCellSystem.cs b/Content.Server/DeviceLinking/Systems/MemoryCellSystem.cs index 394ae0dddf..1faaffc895 100644 --- a/Content.Server/DeviceLinking/Systems/MemoryCellSystem.cs +++ b/Content.Server/DeviceLinking/Systems/MemoryCellSystem.cs @@ -1,7 +1,6 @@ using Content.Server.DeviceLinking.Components; using Content.Shared.DeviceLinking; using Content.Shared.DeviceLinking.Events; -using Content.Shared.DeviceNetwork; namespace Content.Server.DeviceLinking.Systems; @@ -46,7 +45,19 @@ public sealed partial class MemoryCellSystem : EntitySystem private void OnSignalReceived(Entity ent, ref SignalReceivedEvent args) { var state = SignalState.Momentary; - args.Data?.TryGetValue(DeviceNetworkConstants.LogicState, out state); + + if (args.Port == ent.Comp.InputPort) + ent.Comp.InputState = state; + else if (args.Port == ent.Comp.EnablePort) + ent.Comp.EnableState = state; + + UpdateOutput(ent); + } + + [SubscribeLocalEvent] + private void OnSignalReceived(Entity ent, ref SignalReceivedEvent args) + { + var state = args.Data.State; if (args.Port == ent.Comp.InputPort) ent.Comp.InputState = state; @@ -58,9 +69,6 @@ public sealed partial class MemoryCellSystem : EntitySystem private void UpdateOutput(Entity ent) { - if (!Resolve(ent, ref ent.Comp2)) - return; - if (ent.Comp1.EnableState == SignalState.Low) return; @@ -69,6 +77,6 @@ public sealed partial class MemoryCellSystem : EntitySystem return; ent.Comp1.LastOutput = value; - _deviceLink.SendSignal(ent, ent.Comp1.OutputPort, value, ent.Comp2); + _deviceLink.SendSignal((ent.Owner, ent.Comp2), ent.Comp1.OutputPort, value); } } diff --git a/Content.Server/DeviceNetwork/Systems/ApcNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/ApcNetworkSystem.cs index 34895e9bf8..a1c8d18cd6 100644 --- a/Content.Server/DeviceNetwork/Systems/ApcNetworkSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/ApcNetworkSystem.cs @@ -27,13 +27,14 @@ namespace Content.Server.DeviceNetwork.Systems /// /// Checks if both devices are connected to the same apc /// - private void OnBeforePacketSent(EntityUid uid, ApcNetworkComponent receiver, BeforePacketSentEvent args) + private void OnBeforePacketSent(Entity ent, ref BeforePacketSentEvent args) { - if (!TryComp(args.Sender, out ApcNetworkComponent? sender)) return; + if (!TryComp(args.Sender, out ApcNetworkComponent? sender)) + return; - if (sender.ConnectedNode?.NodeGroup == null || !sender.ConnectedNode.NodeGroup.Equals(receiver.ConnectedNode?.NodeGroup)) + if (sender.ConnectedNode?.NodeGroup == null || !sender.ConnectedNode.NodeGroup.Equals(ent.Comp.ConnectedNode?.NodeGroup)) { - args.Cancel(); + args.Cancelled = true; } } diff --git a/Content.Server/DeviceNetwork/Systems/DeviceListSystem.cs b/Content.Server/DeviceNetwork/Systems/DeviceListSystem.cs index f12ed6d245..b551350251 100644 --- a/Content.Server/DeviceNetwork/Systems/DeviceListSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/DeviceListSystem.cs @@ -1,4 +1,5 @@ using System.Linq; +using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared.DeviceNetwork.Systems; @@ -11,6 +12,7 @@ namespace Content.Server.DeviceNetwork.Systems; public sealed partial class DeviceListSystem : SharedDeviceListSystem { [Dependency] private NetworkConfiguratorSystem _configurator = default!; + [Dependency] private EntityQuery _deviceNetworkQuery = default!; public override void Initialize() @@ -82,17 +84,18 @@ public sealed partial class DeviceListSystem : SharedDeviceListSystem /// /// Filters the broadcasts recipient list against the device list as either an allow or deny list depending on the components IsAllowList field /// - private void OnBeforeBroadcast(EntityUid uid, DeviceListComponent component, BeforeBroadcastAttemptEvent args) + private void OnBeforeBroadcast(Entity ent, ref BeforeBroadcastAttemptEvent args) { + var component = ent.Comp; //Don't filter anything if the device list is empty if (component.Devices.Count == 0) { if (component.IsAllowList) - args.Cancel(); + args.Cancelled = true; return; } - HashSet filteredRecipients = new(args.Recipients.Count); + HashSet filteredRecipients = new(args.Recipients.Count); foreach (var recipient in args.Recipients) { @@ -106,10 +109,10 @@ public sealed partial class DeviceListSystem : SharedDeviceListSystem /// /// Filters incoming packets if that is enabled /// - private void OnBeforePacketSent(EntityUid uid, DeviceListComponent component, BeforePacketSentEvent args) + private void OnBeforePacketSent(Entity ent, ref BeforePacketSentEvent args) { - if (component.HandleIncomingPackets && component.Devices.Contains(args.Sender) != component.IsAllowList) - args.Cancel(); + if (ent.Comp.HandleIncomingPackets && ent.Comp.Devices.Contains(args.Sender) != ent.Comp.IsAllowList) + args.Cancelled = true; } public void OnDeviceShutdown(Entity list, Entity device) diff --git a/Content.Server/DeviceNetwork/Systems/DeviceNetworkJammerSystem.cs b/Content.Server/DeviceNetwork/Systems/DeviceNetworkJammerSystem.cs index e5b75ec831..d4edd463d4 100644 --- a/Content.Server/DeviceNetwork/Systems/DeviceNetworkJammerSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/DeviceNetworkJammerSystem.cs @@ -27,7 +27,7 @@ public sealed partial class DeviceNetworkJammerSystem : SharedDeviceNetworkJamme while (query.MoveNext(out var uid, out var jammerComp, out var jammerXform)) { - if (!_jammer.GetJammableNetworks((uid, jammerComp)).Contains(ev.NetworkId)) + if (!_jammer.GetJammableNetworks((uid, jammerComp)).Contains(ev.NetId)) continue; if (jammerComp.FrequenciesExcluded != null && @@ -37,10 +37,9 @@ public sealed partial class DeviceNetworkJammerSystem : SharedDeviceNetworkJamme if (_transform.InRange(jammerXform.Coordinates, ev.SenderTransform.Coordinates, jammerComp.Range) || _transform.InRange(jammerXform.Coordinates, xform.Comp.Coordinates, jammerComp.Range)) { - ev.Cancel(); + ev.Cancelled = true; return; } } } - } diff --git a/Content.Server/DeviceNetwork/Systems/DeviceNetworkRequiresPowerSystem.cs b/Content.Server/DeviceNetwork/Systems/DeviceNetworkRequiresPowerSystem.cs index 0dc1368809..98997189f7 100644 --- a/Content.Server/DeviceNetwork/Systems/DeviceNetworkRequiresPowerSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/DeviceNetworkRequiresPowerSystem.cs @@ -1,5 +1,4 @@ using Content.Server.DeviceNetwork.Components; -using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Shared.DeviceNetwork.Events; @@ -9,15 +8,15 @@ public sealed partial class DeviceNetworkRequiresPowerSystem : EntitySystem { public override void Initialize() { + base.Initialize(); SubscribeLocalEvent(OnBeforePacketSent); } - private void OnBeforePacketSent(EntityUid uid, DeviceNetworkRequiresPowerComponent component, - BeforePacketSentEvent args) + private void OnBeforePacketSent(Entity ent, ref BeforePacketSentEvent args) { - if (!this.IsPowered(uid, EntityManager)) + if (!this.IsPowered(ent, EntityManager)) { - args.Cancel(); + args.Cancelled = true; } } } diff --git a/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.API.cs b/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.API.cs new file mode 100644 index 0000000000..214987a6a0 --- /dev/null +++ b/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.API.cs @@ -0,0 +1,232 @@ +using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Events; +using JetBrains.Annotations; + +namespace Content.Server.DeviceNetwork.Systems; + +public sealed partial class DeviceNetworkSystem +{ + [PublicAPI] + public override bool SendPacket( + Entity ent, + string? address, + ref T data, + uint? frequency = null, + int? network = null) + { + if (!_deviceQuery.Resolve(ent.Owner, ref ent.Comp, false)) + return false; + + var device = ent.Comp; + if (device.Address == string.Empty) + return false; + + frequency ??= device.TransmitFrequency; + + if (frequency == null) + return false; + + network ??= device.DeviceNetId; + + var packet = new DeviceNetworkPacketEvent(network.Value, address, frequency.Value, device.Address, ent!, data); + SendPacket(ref packet); + return true; + } + + /// + /// Connect an entity with a DeviceNetworkComponent. Note that this will re-use an existing address if the + /// device already had one configured. If there is a clash, the device cannot join the network. + /// + [PublicAPI] + public bool ConnectDevice(Entity ent) + { + if (!_deviceQuery.Resolve(ent.Owner, ref ent.Comp, false)) + return false; + + if (!TryEnsureNetwork(ent.Comp.DeviceNetId, out var deviceNet)) + return false; + + var success = deviceNet.Add(ent!); + Dirty(ent); + return success; + } + + /// + /// Disconnect an entity with a DeviceNetworkComponent. + /// + /// The entity to disconnect from its network. + /// + /// If true, sets to false. + /// That way the device doesn't auto reconnect when a game state is loaded. + /// + /// True if the device was removed from the network successfully. + [PublicAPI] + public bool DisconnectDevice(Entity ent, bool preventAutoConnect = true) + { + if (!_deviceQuery.Resolve(ent.Owner, ref ent.Comp, false)) + return false; + + if (!TryGetNetwork(ent.Comp.DeviceNetId, out var deviceNet)) + return false; + + if (preventAutoConnect) + ent.Comp.AutoConnect = false; + + var result = deviceNet.Remove(ent!); + return result; + } + + /// + /// Checks if a device is already connected to its network. + /// + /// True if the device was found in the network with its corresponding network id. + [PublicAPI] + public bool IsDeviceConnected(Entity ent) + { + var (uid, deviceComp) = ent; + if (!_deviceQuery.Resolve(uid, ref deviceComp, false)) + return false; + + if (!_networks.TryGetValue(deviceComp.DeviceNetId, out var deviceNet)) + return false; + + var device = new Device(ent!); + return deviceNet.Devices.ContainsValue(device); + } + + /// + /// Checks if an address exists in the network with the given netId. + /// + [PublicAPI] + public bool IsAddressPresent(int netId, string? address) + { + if (address == null + || !_networks.TryGetValue(netId, out var network)) + return false; + + return network.Devices.ContainsKey(address); + } + + /// + /// Sets the receive frequency of an entity. + /// + /// The target device. + /// The new frequency. + [PublicAPI] + public void SetReceiveFrequency(Entity ent, uint? frequency) + { + if (!_deviceQuery.Resolve(ent.Owner, ref ent.Comp, false)) + return; + + if (ent.Comp.ReceiveFrequency == frequency) + return; + + if (!TryGetNetwork(ent.Comp.DeviceNetId, out var deviceNet)) + return; + + var oldFrequency = ent.Comp.ReceiveFrequency; + deviceNet.Remove(ent!); + ent.Comp.ReceiveFrequency = frequency; + deviceNet.Add(ent!); + + var ev = new DeviceReceiveFrequencyChangedEvent(oldFrequency, frequency); + RaiseLocalEvent(ent, ref ev); + + Dirty(ent); + } + + /// + /// Sets the transmit frequency of an entity. + /// + /// The target device. + /// The new frequency. + [PublicAPI] + public void SetTransmitFrequency(Entity ent, uint? frequency) + { + if (!_deviceQuery.Resolve(ent.Owner, ref ent.Comp, false)) + return; + + var oldFrequency = ent.Comp.TransmitFrequency; + ent.Comp.TransmitFrequency = frequency; + + var ev = new DeviceReceiveFrequencyChangedEvent(oldFrequency, frequency); + RaiseLocalEvent(ent, ref ev); + } + + /// + /// Sets the target device's ability to receive all network packets, regardless of the address. + /// + [PublicAPI] + public void SetReceiveAll(Entity ent, bool receiveAll) + { + if (!_deviceQuery.Resolve(ent.Owner, ref ent.Comp, false)) + return; + + if (ent.Comp.ReceiveAll == receiveAll) + return; + + if (!TryGetNetwork(ent.Comp.DeviceNetId, out var deviceNet)) + return; + + deviceNet.Remove(ent!); + ent.Comp.ReceiveAll = receiveAll; + deviceNet.Add(ent!); + + var ev = new DeviceReceiveAllChangedEvent(receiveAll); + RaiseLocalEvent(ent, ref ev); + + Dirty(ent); + } + + /// + /// Sets the address of the target device. + /// + [PublicAPI] + public void SetAddress(Entity ent, string address) + { + if (!_deviceQuery.Resolve(ent.Owner, ref ent.Comp, false)) + return; + + if (ent.Comp.Address == address && ent.Comp.CustomAddress) + return; + + if (!TryGetNetwork(ent.Comp.DeviceNetId, out var deviceNet)) + return; + + var oldAddress = ent.Comp.Address; + deviceNet.Remove(ent!); + ent.Comp.CustomAddress = true; + ent.Comp.Address = address; + deviceNet.Add(ent!); + + var ev = new DeviceAddressChangedEvent(oldAddress, address, ent.Comp.CustomAddress); + RaiseLocalEvent(ent, ref ev); + + Dirty(ent); + } + + /// + /// Randomizes the address of the target device. + /// + [PublicAPI] + public void RandomizeAddress(Entity ent) + { + if (!_deviceQuery.Resolve(ent.Owner, ref ent.Comp, false)) + return; + + if (!TryGetNetwork(ent.Comp.DeviceNetId, out var deviceNet)) + return; + + var oldAddress = ent.Comp.Address; + deviceNet.Remove(ent!); + ent.Comp.CustomAddress = false; + ent.Comp.Address = ""; + deviceNet.Add(ent!); + + var ev = new DeviceAddressChangedEvent(oldAddress, ent.Comp.Address, ent.Comp.CustomAddress); + RaiseLocalEvent(ent, ref ev); + + Dirty(ent); + } +} diff --git a/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.cs index aa58f568ff..83fa7bf50b 100644 --- a/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.cs @@ -4,357 +4,224 @@ using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared.DeviceNetwork.Systems; -using Content.Shared.Examine; -using JetBrains.Annotations; using Robust.Shared.Random; -namespace Content.Server.DeviceNetwork.Systems +namespace Content.Server.DeviceNetwork.Systems; + +/// +public sealed partial class DeviceNetworkSystem : SharedDeviceNetworkSystem { + [Dependency] private IRobustRandom _random = default!; + [Dependency] private SharedTransformSystem _transformSystem = default!; + [Dependency] private DeviceListSystem _deviceLists = default!; + [Dependency] private NetworkConfiguratorSystem _configurator = default!; + + [Dependency] private EntityQuery _deviceQuery = default!; + /// - /// Entity system that handles everything device network related. - /// Device networking allows machines and devices to communicate with each other while adhering to restrictions like range or being connected to the same powernet. + /// Basically a cache of devices to connect them together faster. /// - [UsedImplicitly] - public sealed partial class DeviceNetworkSystem : SharedDeviceNetworkSystem + private readonly Dictionary _networks = new(4); + + /// + /// Automatically attempt to connect some devices when a map starts. + /// + [SubscribeLocalEvent] + private void OnMapInit(Entity ent, ref MapInitEvent args) { - [Dependency] private IRobustRandom _random = default!; - [Dependency] private SharedTransformSystem _transformSystem = default!; - [Dependency] private DeviceListSystem _deviceLists = default!; - [Dependency] private NetworkConfiguratorSystem _configurator = default!; - - private readonly Dictionary _networks = new(4); - private readonly Queue _queueA = new(); - private readonly Queue _queueB = new(); - - /// - /// The queue being processed in the current tick - /// - private Queue _activeQueue = null!; - - /// - /// The queue that will be processed in the next tick - /// - private Queue _nextQueue = null!; - - - public override void Initialize() + var device = ent.Comp; + if (device.ReceiveFrequency == null + && device.ReceiveFrequencyId != null + && ProtoMan.TryIndex(device.ReceiveFrequencyId, out var receive)) { - SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnNetworkShutdown); - SubscribeLocalEvent(OnExamine); - - _activeQueue = _queueA; - _nextQueue = _queueB; + device.ReceiveFrequency = receive.Frequency; } - public override void Update(float frameTime) + if (device.TransmitFrequency == null + && device.TransmitFrequencyId != null + && ProtoMan.TryIndex(device.TransmitFrequencyId, out var xmit)) { - - while (_activeQueue.TryDequeue(out var packet)) - { - SendPacket(packet); - } - - SwapQueues(); + device.TransmitFrequency = xmit.Frequency; } - public override bool QueuePacket(EntityUid uid, string? address, NetworkPayload data, uint? frequency = null, int? network = null, DeviceNetworkComponent? device = null) + if (device.AutoConnect) + ConnectDevice(ent.AsNullable()); + } + + /// + /// Automatically disconnect when an entity with a DeviceNetworkComponent shuts down. + /// + [SubscribeLocalEvent] + private void OnNetworkShutdown(Entity ent, ref ComponentShutdown args) + { + var component = ent.Comp; + foreach (var list in component.DeviceLists) { - if (!Resolve(uid, ref device, false)) - return false; + if (Deleted(list)) + return; - if (device.Address == string.Empty) - return false; + _deviceLists.OnDeviceShutdown(list, ent); + } - frequency ??= device.TransmitFrequency; + foreach (var list in component.Configurators) + { + if (Deleted(list)) + return; - if (frequency == null) - return false; + _configurator.OnDeviceShutdown(list, ent); + } - network ??= device.DeviceNetId; + if (TryGetNetwork(component.DeviceNetId, out var network)) + network.Remove(ent); + } - _nextQueue.Enqueue(new DeviceNetworkPacketEvent(network.Value, address, frequency.Value, device.Address, uid, data)); + /// + /// Try to find a device on a network using its address. + /// + private bool TryGetDevice(int netId, string address, [NotNullWhen(true)] out Device? device) + { + device = null; + if (!TryGetNetwork(netId, out var network) + || !network.Devices.TryGetValue(address, out var foundDevice)) + return false; + + device = foundDevice; + return true; + } + + /// + /// Tries to get an already existing device network, and creates a new network if it doesn't exist. + /// + /// False if the manager is not initialized. + /// + private bool TryEnsureNetwork(int netId, [NotNullWhen(true)] out DeviceNet? network) + { + network = null; + + if (_networks.TryGetValue(netId, out var deviceNet)) + { + network = deviceNet; return true; } - /// - /// Swaps the active queue. - /// Queues are swapped so that packets being sent in the current tick get processed in the next tick. - /// - /// - /// This prevents infinite loops while sending packets - /// - private void SwapQueues() - { - _nextQueue = _activeQueue; - _activeQueue = _activeQueue == _queueA ? _queueB : _queueA; - } + var newDeviceNet = new DeviceNet(netId, _random); + _networks[netId] = newDeviceNet; + network = newDeviceNet; + return true; + } - private void OnExamine(EntityUid uid, DeviceNetworkComponent device, ExaminedEvent args) + /// + /// Tries to get an already existing network. + /// + /// False if the manager is not initialized, or the network wasn't found. + private bool TryGetNetwork(int netId, [NotNullWhen(true)] out DeviceNet? network) + { + network = null; + + if (!_networks.TryGetValue(netId, out var deviceNet)) + return false; + + network = deviceNet; + return true; + } + + private void SendPacket(ref DeviceNetworkPacketEvent packet) where T : INetworkPayload + { + if (!TryEnsureNetwork(packet.NetId, out var network)) + return; + + if (packet.Address == null) { - if (device.ExaminableAddress) + // Broadcast to all listening devices + if (network.ListeningDevices.TryGetValue(packet.Frequency, out var devices) && CheckRecipientsList(packet, ref devices)) { - args.PushText(Loc.GetString("device-address-examine-message", ("address", device.Address))); + var deviceCopy = ArrayPool.Shared.Rent(devices.Count); + devices.CopyTo(deviceCopy); + SendToConnections(deviceCopy.AsSpan(0, devices.Count), packet); + ArrayPool.Shared.Return(deviceCopy); } } - - /// - /// Automatically attempt to connect some devices when a map starts. - /// - private void OnMapInit(EntityUid uid, DeviceNetworkComponent device, MapInitEvent args) + else { - if (device.ReceiveFrequency == null - && device.ReceiveFrequencyId != null - && ProtoMan.TryIndex(device.ReceiveFrequencyId, out var receive)) + var totalDevices = 0; + var hasTargetedDevice = false; + if (network.ReceiveAllDevices.TryGetValue(packet.Frequency, out var devices)) { - device.ReceiveFrequency = receive.Frequency; + totalDevices += devices.Count; } - if (device.TransmitFrequency == null - && device.TransmitFrequencyId != null - && ProtoMan.TryIndex(device.TransmitFrequencyId, out var xmit)) - { - device.TransmitFrequency = xmit.Frequency; - } - - if (device.AutoConnect) - ConnectDevice(uid, device); - } - - private DeviceNet GetNetwork(int netId) - { - if (_networks.TryGetValue(netId, out var deviceNet)) - return deviceNet; - var newDeviceNet = new DeviceNet(netId, _random); - _networks[netId] = newDeviceNet; - return newDeviceNet; - } - - /// - /// Automatically disconnect when an entity with a DeviceNetworkComponent shuts down. - /// - private void OnNetworkShutdown(EntityUid uid, DeviceNetworkComponent component, ComponentShutdown args) - { - foreach (var list in component.DeviceLists) - { - _deviceLists.OnDeviceShutdown(list, (uid, component)); - } - - foreach (var list in component.Configurators) - { - _configurator.OnDeviceShutdown(list, (uid, component)); - } - - GetNetwork(component.DeviceNetId).Remove(component); - } - - /// - /// Connect an entity with a DeviceNetworkComponent. Note that this will re-use an existing address if the - /// device already had one configured. If there is a clash, the device cannot join the network. - /// - public bool ConnectDevice(EntityUid uid, DeviceNetworkComponent? device = null) - { - if (!Resolve(uid, ref device, false)) - return false; - - return GetNetwork(device.DeviceNetId).Add(device); - } - - /// - /// Disconnect an entity with a DeviceNetworkComponent. - /// - public bool DisconnectDevice(EntityUid uid, DeviceNetworkComponent? device, bool preventAutoConnect = true) - { - if (!Resolve(uid, ref device, false)) - return false; - - // If manually disconnected, don't auto reconnect when a game state is loaded. - if (preventAutoConnect) - device.AutoConnect = false; - - return GetNetwork(device.DeviceNetId).Remove(device); - } - - /// - /// Checks if a device is already connected to its network - /// - /// True if the device was found in the network with its corresponding network id - public bool IsDeviceConnected(EntityUid uid, DeviceNetworkComponent? device) - { - if (!Resolve(uid, ref device, false)) - return false; - - if (!_networks.TryGetValue(device.DeviceNetId, out var deviceNet)) - return false; - - return deviceNet.Devices.ContainsValue(device); - } - - /// - /// Checks if an address exists in the network with the given netId - /// - public bool IsAddressPresent(int netId, string? address) - { - if (address == null || !_networks.TryGetValue(netId, out var network)) - return false; - - return network.Devices.ContainsKey(address); - } - - public void SetReceiveFrequency(EntityUid uid, uint? frequency, DeviceNetworkComponent? device = null) - { - if (!Resolve(uid, ref device, false)) + if (!TryGetDevice(packet.NetId, packet.Address, out var device)) return; - if (device.ReceiveFrequency == frequency) return; - - var deviceNet = GetNetwork(device.DeviceNetId); - deviceNet.Remove(device); - device.ReceiveFrequency = frequency; - deviceNet.Add(device); - } - - public void SetTransmitFrequency(EntityUid uid, uint? frequency, DeviceNetworkComponent? device = null) - { - if (Resolve(uid, ref device, false)) - device.TransmitFrequency = frequency; - } - - public void SetReceiveAll(EntityUid uid, bool receiveAll, DeviceNetworkComponent? device = null) - { - if (!Resolve(uid, ref device, false)) - return; - - if (device.ReceiveAll == receiveAll) return; - - var deviceNet = GetNetwork(device.DeviceNetId); - deviceNet.Remove(device); - device.ReceiveAll = receiveAll; - deviceNet.Add(device); - } - - public void SetAddress(EntityUid uid, string address, DeviceNetworkComponent? device = null) - { - if (!Resolve(uid, ref device, false)) - return; - - if (device.Address == address && device.CustomAddress) return; - - var deviceNet = GetNetwork(device.DeviceNetId); - deviceNet.Remove(device); - device.CustomAddress = true; - device.Address = address; - deviceNet.Add(device); - } - - public void RandomizeAddress(EntityUid uid, DeviceNetworkComponent? device = null) - { - if (!Resolve(uid, ref device, false)) - return; - var deviceNet = GetNetwork(device.DeviceNetId); - deviceNet.Remove(device); - device.CustomAddress = false; - device.Address = ""; - deviceNet.Add(device); - } - - /// - /// Try to find a device on a network using its address. - /// - private bool TryGetDevice(int netId, string address, [NotNullWhen(true)] out DeviceNetworkComponent? device) => - GetNetwork(netId).Devices.TryGetValue(address, out device); - - private void SendPacket(DeviceNetworkPacketEvent packet) - { - var network = GetNetwork(packet.NetId); - if (packet.Address == null) + if (!device.Value.ReceiveAll && + device.Value.ReceiveFrequency == packet.Frequency) { - // Broadcast to all listening devices - if (network.ListeningDevices.TryGetValue(packet.Frequency, out var devices) && CheckRecipientsList(packet, ref devices)) - { - var deviceCopy = ArrayPool.Shared.Rent(devices.Count); - devices.CopyTo(deviceCopy); - SendToConnections(deviceCopy.AsSpan(0, devices.Count), packet); - ArrayPool.Shared.Return(deviceCopy); - } + totalDevices += 1; + hasTargetedDevice = true; } - else + var deviceCopy = ArrayPool.Shared.Rent(totalDevices); + if (devices != null) { - var totalDevices = 0; - var hasTargetedDevice = false; - if (network.ReceiveAllDevices.TryGetValue(packet.Frequency, out var devices)) - { - totalDevices += devices.Count; - } - if (TryGetDevice(packet.NetId, packet.Address, out var device) && - !device.ReceiveAll && - device.ReceiveFrequency == packet.Frequency) - { - totalDevices += 1; - hasTargetedDevice = true; - } - var deviceCopy = ArrayPool.Shared.Rent(totalDevices); - if (devices != null) - { - devices.CopyTo(deviceCopy); - } - if (hasTargetedDevice) - { - deviceCopy[totalDevices - 1] = device!; - } - SendToConnections(deviceCopy.AsSpan(0, totalDevices), packet); - ArrayPool.Shared.Return(deviceCopy); + devices.CopyTo(deviceCopy); } + if (hasTargetedDevice) + { + deviceCopy[totalDevices - 1] = device.Value; + } + SendToConnections(deviceCopy.AsSpan(0, totalDevices), packet); + ArrayPool.Shared.Return(deviceCopy); } + } - /// - /// Sends the to the sending entity if the packets SendBeforeBroadcastAttemptEvent field is set to true. - /// The recipients is set to the modified recipient list. - /// - /// false if the broadcast was canceled - private bool CheckRecipientsList(DeviceNetworkPacketEvent packet, ref HashSet recipients) - { - if (!_networks.ContainsKey(packet.NetId) || !_networks[packet.NetId].Devices.ContainsKey(packet.SenderAddress)) - return false; - - var sender = _networks[packet.NetId].Devices[packet.SenderAddress]; - if (!sender.SendBroadcastAttemptEvent) - return true; - - var beforeBroadcastAttemptEvent = new BeforeBroadcastAttemptEvent(recipients); - RaiseLocalEvent(packet.Sender, beforeBroadcastAttemptEvent, true); - - if (beforeBroadcastAttemptEvent.Cancelled || beforeBroadcastAttemptEvent.ModifiedRecipients == null) - return false; - - recipients = beforeBroadcastAttemptEvent.ModifiedRecipients; + /// + /// Sends the to the sending entity if the packets SendBeforeBroadcastAttemptEvent field is set to true. + /// The recipients is set to the modified recipient list. + /// + /// false if the broadcast was canceled + private bool CheckRecipientsList(DeviceNetworkPacketEvent packet, ref HashSet recipients) where T : INetworkPayload + { + if (!packet.Sender.Comp.SendBroadcastAttemptEvent) return true; + + var beforeBroadcastAttemptEvent = new BeforeBroadcastAttemptEvent(recipients); + RaiseLocalEvent(packet.Sender, ref beforeBroadcastAttemptEvent, true); + + if (beforeBroadcastAttemptEvent.Cancelled || beforeBroadcastAttemptEvent.ModifiedRecipients == null) + return false; + + recipients = beforeBroadcastAttemptEvent.ModifiedRecipients; + return true; + } + + private void SendToConnections(ReadOnlySpan connections, DeviceNetworkPacketEvent packet) where T : INetworkPayload + { + if (Deleted(packet.Sender)) + { + return; } - private void SendToConnections(ReadOnlySpan connections, DeviceNetworkPacketEvent packet) + var xform = Transform(packet.Sender); + + var senderPos = _transformSystem.GetWorldPosition(xform); + + foreach (var connection in connections) { - if (Deleted(packet.Sender)) - { - return; - } + if (connection.Owner == packet.Sender.Owner) + continue; - var xform = Transform(packet.Sender); + var beforeEv = new BeforePacketSentEvent(packet.NetId, + packet.Address, + packet.Frequency, + packet.SenderAddress, + packet.Sender, + xform, + senderPos); + RaiseLocalEvent(connection.Owner, ref beforeEv); - var senderPos = _transformSystem.GetWorldPosition(xform); + if (beforeEv.Cancelled) + continue; - foreach (var connection in connections) - { - if (connection.Owner == packet.Sender) - continue; - - BeforePacketSentEvent beforeEv = new(packet.Sender, xform, senderPos, connection.NetIdEnum.ToString(), packet.Frequency); - RaiseLocalEvent(connection.Owner, beforeEv, false); - - if (!beforeEv.Cancelled) - RaiseLocalEvent(connection.Owner, packet, false); - else - beforeEv.Uncancel(); - } + RaiseLocalEvent(connection.Owner, ref packet); } } } diff --git a/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs b/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs index a432c10291..27ab0c6139 100644 --- a/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs @@ -1,8 +1,8 @@ using Content.Server.DeviceNetwork.Components.Devices; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Interaction; using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Payloads; namespace Content.Server.DeviceNetwork.Systems.Devices { @@ -15,43 +15,38 @@ namespace Content.Server.DeviceNetwork.Systems.Devices base.Initialize(); SubscribeLocalEvent(OnInteracted); - SubscribeLocalEvent(OnPackedReceived); } - /// - /// Toggles the state of the switch and sents a command with the - /// value set to state. - /// - private void OnInteracted(EntityUid uid, ApcNetSwitchComponent component, InteractHandEvent args) + private void OnInteracted(Entity ent, ref InteractHandEvent args) { - if (!TryComp(uid, out DeviceNetworkComponent? networkComponent)) return; + var (uid, component) = ent; + if (!TryComp(uid, out DeviceNetworkComponent? networkComponent)) + return; component.State = !component.State; if (networkComponent.TransmitFrequency == null) return; - var payload = new NetworkPayload + var payload = new ApcNetTogglePayload { - [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdSetState, - [DeviceNetworkConstants.StateEnabled] = component.State, + Enabled = component.State, }; - _deviceNetworkSystem.QueuePacket(uid, null, payload, device: networkComponent); + _deviceNetworkSystem.SendPacket(uid, null, ref payload); args.Handled = true; } - /// - /// Listens to the command of other switches to sync state - /// - private void OnPackedReceived(EntityUid uid, ApcNetSwitchComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnPackedReceived(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!TryComp(uid, out DeviceNetworkComponent? networkComponent) || args.SenderAddress == networkComponent.Address) return; - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command) || command != DeviceNetworkConstants.CmdSetState) return; - if (!args.Data.TryGetValue(DeviceNetworkConstants.StateEnabled, out bool enabled)) return; + var (uid, component) = ent; + if (!TryComp(uid, out DeviceNetworkComponent? networkComponent) + || args.SenderAddress == networkComponent.Address) + return; - component.State = enabled; + component.State = args.Data.Enabled; } } } diff --git a/Content.Server/DeviceNetwork/Systems/SingletonDeviceNetServerSystem.cs b/Content.Server/DeviceNetwork/Systems/SingletonDeviceNetServerSystem.cs index b507284852..97098c75ad 100644 --- a/Content.Server/DeviceNetwork/Systems/SingletonDeviceNetServerSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/SingletonDeviceNetServerSystem.cs @@ -103,10 +103,10 @@ public sealed partial class SingletonDeviceNetServerSystem : EntitySystem var connectedEvent = new DeviceNetServerConnectedEvent(); RaiseLocalEvent(uid, ref connectedEvent); - if (_deviceNetworkSystem.IsDeviceConnected(uid, device)) + if (_deviceNetworkSystem.IsDeviceConnected((uid, device))) return; - _deviceNetworkSystem.ConnectDevice(uid, device); + _deviceNetworkSystem.ConnectDevice((uid, device)); } /// @@ -122,7 +122,7 @@ public sealed partial class SingletonDeviceNetServerSystem : EntitySystem var disconnectedEvent = new DeviceNetServerDisconnectedEvent(); RaiseLocalEvent(uid, ref disconnectedEvent); - _deviceNetworkSystem.DisconnectDevice(uid, device, false); + _deviceNetworkSystem.DisconnectDevice((uid, device), false); } } diff --git a/Content.Server/DeviceNetwork/Systems/StationLimitedNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/StationLimitedNetworkSystem.cs index fbb8b2e35a..7120e452f9 100644 --- a/Content.Server/DeviceNetwork/Systems/StationLimitedNetworkSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/StationLimitedNetworkSystem.cs @@ -2,7 +2,6 @@ using Content.Server.DeviceNetwork.Components; using Content.Server.Station.Systems; using Content.Shared.DeviceNetwork.Events; using JetBrains.Annotations; -using Robust.Shared.Map; namespace Content.Server.DeviceNetwork.Systems { @@ -54,14 +53,15 @@ namespace Content.Server.DeviceNetwork.Systems /// /// Checks if both devices are limited to the same station /// - private void OnBeforePacketSent(EntityUid uid, StationLimitedNetworkComponent component, BeforePacketSentEvent args) + private void OnBeforePacketSent(Entity ent, ref BeforePacketSentEvent args) { + var (uid, component) = ent; if (!component.StationId.HasValue) TrySetStationId(uid, component); if (!CheckStationId(args.Sender, component.AllowNonStationPackets, component.StationId)) { - args.Cancel(); + args.Cancelled = true; } } diff --git a/Content.Server/DeviceNetwork/Systems/WiredNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/WiredNetworkSystem.cs index f8258ecaf6..52700a175e 100644 --- a/Content.Server/DeviceNetwork/Systems/WiredNetworkSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/WiredNetworkSystem.cs @@ -16,11 +16,11 @@ namespace Content.Server.DeviceNetwork.Systems /// /// Checks if both devices are on the same grid /// - private void OnBeforePacketSent(EntityUid uid, WiredNetworkComponent component, BeforePacketSentEvent args) + private void OnBeforePacketSent(Entity ent, ref BeforePacketSentEvent args) { - if (Transform(uid).GridUid != args.SenderTransform.GridUid) + if (Transform(ent).GridUid != args.SenderTransform.GridUid) { - args.Cancel(); + args.Cancelled = true; } } diff --git a/Content.Server/DeviceNetwork/Systems/WirelessNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/WirelessNetworkSystem.cs index 0506f1cce6..3b72a97d35 100644 --- a/Content.Server/DeviceNetwork/Systems/WirelessNetworkSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/WirelessNetworkSystem.cs @@ -18,10 +18,10 @@ namespace Content.Server.DeviceNetwork.Systems /// /// Gets the position of both the sending and receiving entity and checks if the receiver is in range of the sender. /// - private void OnBeforePacketSent(EntityUid uid, WirelessNetworkComponent component, BeforePacketSentEvent args) + private void OnBeforePacketSent(Entity ent, ref BeforePacketSentEvent args) { var ownPosition = args.SenderPosition; - var xform = Transform(uid); + var xform = Transform(ent); // not a wireless to wireless connection, just let it happen if (!TryComp(args.Sender, out var sendingComponent)) @@ -30,7 +30,7 @@ namespace Content.Server.DeviceNetwork.Systems if (xform.MapID != args.SenderTransform.MapID || (ownPosition - _transformSystem.GetWorldPosition(xform)).Length() > sendingComponent.Range) { - args.Cancel(); + args.Cancelled = true; } } } diff --git a/Content.Server/Fax/AdminUI/AdminFaxEui.cs b/Content.Server/Fax/AdminUI/AdminFaxEui.cs index 21089befe0..9e5b5e0f17 100644 --- a/Content.Server/Fax/AdminUI/AdminFaxEui.cs +++ b/Content.Server/Fax/AdminUI/AdminFaxEui.cs @@ -1,5 +1,3 @@ -using Content.Server.Construction.Conditions; -using Content.Server.DeviceNetwork.Components; using Content.Server.EUI; using Content.Shared.Eui; using Content.Shared.Fax.Components; diff --git a/Content.Server/Fax/FaxConstants.cs b/Content.Server/Fax/FaxConstants.cs deleted file mode 100644 index 8578172381..0000000000 --- a/Content.Server/Fax/FaxConstants.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Content.Server.Fax; - -public static class FaxConstants -{ - // Commands - - /** - * Used to get other faxes connected to current network - */ - public const string FaxPingCommand = "fax_ping"; - - /** - * Used as response to ping command - */ - public const string FaxPongCommand = "fax_pong"; - - /** - * Used when fax sending data to destination fax - */ - public const string FaxPrintCommand = "fax_print"; - - // Data - - public const string FaxNameData = "fax_data_name"; - public const string FaxPaperNameData = "fax_data_title"; - public const string FaxPaperLabelData = "fax_data_label"; - public const string FaxPaperPrototypeData = "fax_data_prototype"; - public const string FaxPaperContentData = "fax_data_content"; - public const string FaxPaperStampStateData = "fax_data_stamp_state"; - public const string FaxPaperStampedByData = "fax_data_stamped_by"; - public const string FaxSyndicateData = "fax_data_i_am_syndicate"; - public const string FaxPaperLockedData = "fax_data_locked"; - public const string FaxPaperSenderFaxNameData = "fax_data_sender_fax_name"; -} diff --git a/Content.Server/Fax/FaxSystem.cs b/Content.Server/Fax/FaxSystem.cs index cddb9b4854..ecca1e91f0 100644 --- a/Content.Server/Fax/FaxSystem.cs +++ b/Content.Server/Fax/FaxSystem.cs @@ -8,8 +8,6 @@ using Content.Server.Tools; using Content.Shared.Administration.Logs; using Content.Shared.Containers.ItemSlots; using Content.Shared.Database; -using Content.Shared.DeviceNetwork; -using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Emag.Systems; using Content.Shared.Fax; @@ -31,7 +29,6 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Player; using Robust.Shared.Prototypes; -using Robust.Shared.Timing; namespace Content.Server.Fax; @@ -71,7 +68,6 @@ public sealed partial class FaxSystem : EntitySystem SubscribeLocalEvent(OnItemSlotChanged); SubscribeLocalEvent(OnItemSlotChanged); SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnPacketReceived); // Interaction SubscribeLocalEvent(OnInteractUsing); @@ -261,56 +257,32 @@ public sealed partial class FaxSystem : EntitySystem args.Handled = true; } - private void OnPacketReceived(EntityUid uid, FaxMachineComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnPingPayload(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!HasComp(uid) || string.IsNullOrEmpty(args.SenderAddress)) + var isForSyndie = _emag.CheckFlag(ent.Owner, EmagType.Interaction) && args.Data.IsSyndicate; + if (!isForSyndie && !ent.Comp.ResponsePings) return; - if (args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command)) + var pong = new FaxPongPayload { - switch (command) - { - case FaxConstants.FaxPingCommand: - var isForSyndie = _emag.CheckFlag(uid, EmagType.Interaction) && - args.Data.ContainsKey(FaxConstants.FaxSyndicateData); - if (!isForSyndie && !component.ResponsePings) - return; + FaxName = ent.Comp.FaxName, + }; - var payload = new NetworkPayload() - { - { DeviceNetworkConstants.Command, FaxConstants.FaxPongCommand }, - { FaxConstants.FaxNameData, component.FaxName } - }; - _deviceNetworkSystem.QueuePacket(uid, args.SenderAddress, payload); + _deviceNetworkSystem.SendPacket(ent.Owner, args.SenderAddress, ref pong); + } - break; - case FaxConstants.FaxPongCommand: - if (!args.Data.TryGetValue(FaxConstants.FaxNameData, out string? faxName)) - return; + [SubscribeLocalEvent] + private void OnPongPayload(Entity ent, ref DeviceNetworkPacketEvent args) + { + ent.Comp.KnownFaxes[args.SenderAddress] = args.Data.FaxName; + UpdateUserInterface(ent.Owner, ent.Comp); + } - component.KnownFaxes[args.SenderAddress] = faxName; - - UpdateUserInterface(uid, component); - - break; - case FaxConstants.FaxPrintCommand: - if (!args.Data.TryGetValue(FaxConstants.FaxPaperNameData, out string? name) || - !args.Data.TryGetValue(FaxConstants.FaxPaperContentData, out string? content)) - return; - - args.Data.TryGetValue(FaxConstants.FaxPaperLabelData, out string? label); - args.Data.TryGetValue(FaxConstants.FaxPaperStampStateData, out string? stampState); - args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List? stampedBy); - args.Data.TryGetValue(FaxConstants.FaxPaperPrototypeData, out string? prototypeId); - args.Data.TryGetValue(FaxConstants.FaxPaperLockedData, out bool? locked); - args.Data.TryGetValue(FaxConstants.FaxPaperSenderFaxNameData, out string? senderFaxName); - - var printout = new FaxPrintout(content, name, label, prototypeId, stampState, stampedBy, locked ?? false, senderFaxName); - Receive(uid, printout, args.SenderAddress); - - break; - } - } + [SubscribeLocalEvent] + private void OnPrintPayload(Entity ent, ref DeviceNetworkPacketEvent args) + { + Receive(ent, args.Data.Data, args.SenderAddress); } private void OnToggleInterface(EntityUid uid, FaxMachineComponent component, AfterActivatableUIOpenEvent args) @@ -413,15 +385,12 @@ public sealed partial class FaxSystem : EntitySystem component.DestinationFaxAddress = null; component.KnownFaxes.Clear(); - var payload = new NetworkPayload() + var payload = new FaxPingPayload { - { DeviceNetworkConstants.Command, FaxConstants.FaxPingCommand } + IsSyndicate = _emag.CheckFlag(uid, EmagType.Interaction), }; - if (_emag.CheckFlag(uid, EmagType.Interaction)) - payload.Add(FaxConstants.FaxSyndicateData, true); - - _deviceNetworkSystem.QueuePacket(uid, null, payload); + _deviceNetworkSystem.SendPacket(uid, null, ref payload); } /// @@ -522,57 +491,26 @@ public sealed partial class FaxSystem : EntitySystem !TryComp(sendEntity, out var paper)) return; + if (metadata.EntityPrototype == null) + return; + TryComp(sendEntity, out var nameMod); TryComp(sendEntity, out var labelComponent); - var content = paper.Content; - - if (component.AddSenderInfo) + var payload = new FaxPrintPayload { - var faxMachineAddress = TryComp(uid, out var deviceNetworkComponent) - ? deviceNetworkComponent.Address - : Loc.GetString("device-address-unknown"); - - var time = _gameTicker.RoundDuration(); - var timeString = TimeSpan.FromSeconds(Math.Truncate(time.TotalSeconds)).ToString(); - - content += "\n"; - content += Loc.GetString(component.SenderInfo, - ("sender_name", component.FaxName), - ("sender_addr", faxMachineAddress), - ("recipient_name", component.DestinationFaxName ?? Loc.GetString("fax-machine-popup-source-unknown")), - ("recipient_addr", component.DestinationFaxAddress), - ("time", timeString) - ); - } - - var payload = new NetworkPayload() - { - { DeviceNetworkConstants.Command, FaxConstants.FaxPrintCommand }, - { FaxConstants.FaxPaperNameData, nameMod?.BaseName ?? metadata.EntityName }, - { FaxConstants.FaxPaperLabelData, labelComponent?.CurrentLabel }, - { FaxConstants.FaxPaperContentData, content }, - { FaxConstants.FaxPaperLockedData, paper.EditingDisabled }, - { FaxConstants.FaxPaperSenderFaxNameData, component.FaxName ?? Loc.GetString("fax-machine-popup-source-unknown") } + Data = new FaxPrintout( + paper.Content, + nameMod?.BaseName ?? metadata.EntityName, + labelComponent?.CurrentLabel, + metadata.EntityPrototype.ID, + paper.StampState, + paper.StampedBy, + paper.EditingDisabled), }; - if (metadata.EntityPrototype != null) - { - // TODO: Ideally, we could just make a copy of the whole entity when it's - // faxed, in order to preserve visuals, etc.. This functionality isn't - // available yet, so we'll pass along the originating prototypeId and fall - // back to component.PrintPaperId in SpawnPaperFromQueue if we can't find one here. - payload[FaxConstants.FaxPaperPrototypeData] = metadata.EntityPrototype.ID; - } - - if (paper.StampState != null) - { - payload[FaxConstants.FaxPaperStampStateData] = paper.StampState; - payload[FaxConstants.FaxPaperStampedByData] = paper.StampedBy; - } - - _deviceNetworkSystem.QueuePacket(uid, component.DestinationFaxAddress, payload); + _deviceNetworkSystem.SendPacket(uid, component.DestinationFaxAddress, ref payload); _adminLogger.Add(LogType.Action, LogImpact.Low, diff --git a/Content.Server/GameTicking/Rules/ParadoxCloneRuleSystem.cs b/Content.Server/GameTicking/Rules/ParadoxCloneRuleSystem.cs index e9107e9851..447a25499f 100644 --- a/Content.Server/GameTicking/Rules/ParadoxCloneRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ParadoxCloneRuleSystem.cs @@ -5,7 +5,7 @@ using Content.Server.Medical.SuitSensors; using Content.Server.Objectives.Components; using Content.Shared.GameTicking.Components; using Content.Shared.Gibbing.Components; -using Content.Shared.Medical.SuitSensor; +using Content.Shared.Medical.SuitSensors; using Content.Shared.Mind; using Content.Shared.Objectives.Systems; using Robust.Shared.Random; diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleComponent.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleComponent.cs index c2d7124194..91bfb02d51 100644 --- a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleComponent.cs +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleComponent.cs @@ -1,4 +1,4 @@ -using Content.Shared.Medical.SuitSensor; +using Content.Shared.Medical.SuitSensors; namespace Content.Server.Medical.CrewMonitoring; diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs index 6399250475..d3e6fb77e0 100644 --- a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs @@ -1,12 +1,8 @@ using System.Linq; -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Systems; -using Content.Shared.PowerCell; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Medical.CrewMonitoring; -using Content.Shared.Medical.SuitSensor; using Content.Shared.Pinpointer; +using Content.Shared.PowerCell; using Robust.Server.GameObjects; namespace Content.Server.Medical.CrewMonitoring; @@ -20,7 +16,6 @@ public sealed partial class CrewMonitoringConsoleSystem : EntitySystem { base.Initialize(); SubscribeLocalEvent(OnRemove); - SubscribeLocalEvent(OnPacketReceived); SubscribeLocalEvent(OnUIOpened); } @@ -29,22 +24,11 @@ public sealed partial class CrewMonitoringConsoleSystem : EntitySystem component.ConnectedSensors.Clear(); } - private void OnPacketReceived(EntityUid uid, CrewMonitoringConsoleComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSuitSensorBroadcast(Entity ent, ref DeviceNetworkPacketEvent args) { - var payload = args.Data; - - // Check command - if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command)) - return; - - if (command != DeviceNetworkConstants.CmdUpdatedState) - return; - - if (!payload.TryGetValue(SuitSensorConstants.NET_STATUS_COLLECTION, out Dictionary? sensorStatus)) - return; - - component.ConnectedSensors = sensorStatus; - UpdateUserInterface(uid, component); + ent.Comp.ConnectedSensors = args.Data.SensorStatus; + UpdateUserInterface(ent, ent.Comp); } private void OnUIOpened(EntityUid uid, CrewMonitoringConsoleComponent component, BoundUIOpenedEvent args) diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerComponent.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerComponent.cs index 7eeafb49c6..26b5387412 100644 --- a/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerComponent.cs +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerComponent.cs @@ -1,5 +1,4 @@ -using Content.Shared.Medical.SuitSensor; -using Robust.Shared.Map; +using Content.Shared.Medical.SuitSensors; namespace Content.Server.Medical.CrewMonitoring; diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs index 87e9fb48d4..5b87771c4a 100644 --- a/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs @@ -1,16 +1,14 @@ using Content.Server.DeviceNetwork.Systems; -using Content.Server.Medical.SuitSensors; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; -using Content.Shared.Medical.SuitSensor; using Robust.Shared.Timing; using Content.Shared.DeviceNetwork.Components; +using Content.Shared.Medical.CrewMonitoring; +using Content.Shared.Medical.SuitSensors; namespace Content.Server.Medical.CrewMonitoring; public sealed partial class CrewMonitoringServerSystem : EntitySystem { - [Dependency] private SuitSensorSystem _sensors = default!; [Dependency] private IGameTiming _gameTiming = default!; [Dependency] private DeviceNetworkSystem _deviceNetworkSystem = default!; [Dependency] private SingletonDeviceNetServerSystem _singletonServerSystem = default!; @@ -22,7 +20,6 @@ public sealed partial class CrewMonitoringServerSystem : EntitySystem { base.Initialize(); SubscribeLocalEvent(OnRemove); - SubscribeLocalEvent(OnPacketReceived); SubscribeLocalEvent(OnDisconnected); } @@ -51,14 +48,12 @@ public sealed partial class CrewMonitoringServerSystem : EntitySystem /// /// Adds or updates a sensor status entry if the received package is a sensor status update /// - private void OnPacketReceived(EntityUid uid, CrewMonitoringServerComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSensorStatus(Entity ent, ref DeviceNetworkPacketEvent args) { - var sensorStatus = _sensors.PacketToSuitSensor(args.Data); - if (sensorStatus == null) - return; - - sensorStatus.Timestamp = _gameTiming.CurTime; - component.SensorStatus[args.SenderAddress] = sensorStatus; + var sensorData = args.Data.Data; + sensorData.Timestamp = _gameTiming.CurTime; + ent.Comp.SensorStatus[args.SenderAddress] = sensorData; } /// @@ -93,13 +88,12 @@ public sealed partial class CrewMonitoringServerSystem : EntitySystem if (!Resolve(uid, ref serverComponent, ref device)) return; - var payload = new NetworkPayload() + var payload = new BroadcastSuitSensorStatePayload { - [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdUpdatedState, - [SuitSensorConstants.NET_STATUS_COLLECTION] = serverComponent.SensorStatus + SensorStatus = serverComponent.SensorStatus, }; - _deviceNetworkSystem.QueuePacket(uid, null, payload, device: device); + _deviceNetworkSystem.SendPacket((uid, device), null, ref payload); } /// diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index 2ae1ce7cca..68f05b00dd 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -46,9 +46,6 @@ public sealed partial class SuitSensorSystem : SharedSuitSensorSystem sensor.ConnectedServer = address; } - // Send it to the connected server - var payload = SuitSensorToPacket(status); - // Clear the connected server if its address isn't on the network if (!_deviceNetworkSystem.IsAddressPresent(device.DeviceNetId, sensor.ConnectedServer)) { @@ -56,7 +53,11 @@ public sealed partial class SuitSensorSystem : SharedSuitSensorSystem continue; } - _deviceNetworkSystem.QueuePacket(uid, sensor.ConnectedServer, payload, device: device); + var payload = new SuitSensorStatusPayload + { + Data = status.Value, + }; + _deviceNetworkSystem.SendPacket((uid, device), sensor.ConnectedServer, ref payload); } } } diff --git a/Content.Server/PDA/PdaSystem.cs b/Content.Server/PDA/PdaSystem.cs index 23c3b1923f..cfe69e6b58 100644 --- a/Content.Server/PDA/PdaSystem.cs +++ b/Content.Server/PDA/PdaSystem.cs @@ -1,13 +1,11 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.Access.Systems; -using Content.Server.CartridgeLoader; using Content.Server.Chat.Managers; using Content.Server.Instruments; using Content.Server.PDA.Ringer; using Content.Server.Station.Systems; using Content.Server.Store.Systems; -using Content.Server.Traitor.Uplink; using Content.Shared.Access.Components; using Content.Shared.AlertLevel; using Content.Shared.CartridgeLoader; @@ -343,7 +341,7 @@ namespace Content.Server.PDA if (TryComp(uid, out DeviceNetworkComponent? deviceNetworkComponent)) { - address = deviceNetworkComponent?.Address; + address = deviceNetworkComponent.Address; } return address; diff --git a/Content.Server/Power/Generation/Teg/TegSensorData.cs b/Content.Server/Power/Generation/Teg/TegSensorData.cs deleted file mode 100644 index f994b5762c..0000000000 --- a/Content.Server/Power/Generation/Teg/TegSensorData.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Content.Server.Power.Components; - -namespace Content.Server.Power.Generation.Teg; - -/// -/// Sensor data reported by the when queried over the device network. -/// -/// -public sealed class TegSensorData -{ - /// - /// Information for the A-side circulator. - /// - public Circulator CirculatorA; - - /// - /// Information for the B-side circulator. - /// - public Circulator CirculatorB; - - /// - /// The amount of energy (Joules) generated by the TEG last atmos tick. - /// - /// - public float LastGeneration; - - /// - /// Ramping position for the TEG power generation. - /// - /// - public float RampPosition; - - /// - /// Power (Watts) actually being supplied by the TEG to connected power network. - /// - /// - public float PowerOutput; - - /// - /// Information for a single TEG circulator. - /// - /// Pressure measured at the circulator's input pipe - /// Pressure measured at the circulator's output pipe - /// Temperature measured at the circulator's input pipe - /// Temperature measured at the circulator's output pipe - public record struct Circulator( - float InletPressure, - float OutletPressure, - float InletTemperature, - float OutletTemperature); -} - diff --git a/Content.Server/Power/Generation/Teg/TegSystem.cs b/Content.Server/Power/Generation/Teg/TegSystem.cs index d1e18875bf..42feb1f991 100644 --- a/Content.Server/Power/Generation/Teg/TegSystem.cs +++ b/Content.Server/Power/Generation/Teg/TegSystem.cs @@ -5,7 +5,6 @@ using Content.Server.NodeContainer.Nodes; using Content.Server.Power.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Examine; using Content.Shared.NodeContainer; @@ -43,7 +42,7 @@ namespace Content.Server.Power.Generation.Teg; /// /// /// -/// +/// public sealed partial class TegSystem : EntitySystem { /// @@ -61,11 +60,6 @@ public sealed partial class TegSystem : EntitySystem /// private const string NodeNameOutlet = "outlet"; - /// - /// Device network command to have the TEG output a object for its last statistics. - /// - public const string DeviceNetworkCommandSyncData = "teg_sync_data"; - [Dependency] private AmbientSoundSystem _ambientSound = default!; [Dependency] private AppearanceSystem _appearance = default!; [Dependency] private AtmosphereSystem _atmosphere = default!; @@ -80,7 +74,6 @@ public sealed partial class TegSystem : EntitySystem SubscribeLocalEvent(GeneratorUpdate); SubscribeLocalEvent(GeneratorPowerChange); - SubscribeLocalEvent(DeviceNetworkPacketReceived); SubscribeLocalEvent(GeneratorExamined); } @@ -361,46 +354,32 @@ public sealed partial class TegSystem : EntitySystem return (inlet, outlet); } - private void DeviceNetworkPacketReceived( - EntityUid uid, - TegGeneratorComponent component, - DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSyncPayload(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd)) + var group = GetNodeGroup(ent.Owner); + if (group is not { IsFullyBuilt: true }) return; - switch (cmd) + var supplier = Comp(ent); + + var dataPayload = new TegSensorPayload { - case DeviceNetworkCommandSyncData: - var group = GetNodeGroup(uid); - if (group is not { IsFullyBuilt: true }) - return; + CirculatorA = GetCirculatorSensorData(group.CirculatorA!.Owner), + CirculatorB = GetCirculatorSensorData(group.CirculatorB!.Owner), + LastGeneration = ent.Comp.LastGeneration, + PowerOutput = supplier.CurrentSupply, + RampPosition = ent.Comp.RampPosition, + }; - var supplier = Comp(uid); - - var payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = DeviceNetworkCommandSyncData, - [DeviceNetworkCommandSyncData] = new TegSensorData - { - CirculatorA = GetCirculatorSensorData(group.CirculatorA!.Owner), - CirculatorB = GetCirculatorSensorData(group.CirculatorB!.Owner), - LastGeneration = component.LastGeneration, - PowerOutput = supplier.CurrentSupply, - RampPosition = component.RampPosition - } - }; - - _deviceNetwork.QueuePacket(uid, args.SenderAddress, payload); - break; - } + _deviceNetwork.SendPacket(ent.Owner, args.SenderAddress, ref dataPayload); } - private TegSensorData.Circulator GetCirculatorSensorData(EntityUid circulator) + private Circulator GetCirculatorSensorData(EntityUid circulator) { var (inlet, outlet) = GetPipes(circulator); - return new TegSensorData.Circulator( + return new Circulator( inlet.Air.Pressure, outlet.Air.Pressure, inlet.Air.Temperature, diff --git a/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs b/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs index 0a7b26ceac..16d26deec2 100644 --- a/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs +++ b/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs @@ -3,7 +3,6 @@ using Content.Server.DeviceNetwork.Systems; using Content.Server.Radio.EntitySystems; using Content.Shared.Lock; using Content.Shared.Database; -using Content.Shared.DeviceNetwork; using Content.Shared.Robotics; using Content.Shared.Robotics.Components; using Content.Shared.Robotics.Systems; @@ -33,7 +32,6 @@ public sealed partial class RoboticsConsoleSystem : SharedRoboticsConsoleSystem { base.Initialize(); - SubscribeLocalEvent(OnPacketReceived); Subs.BuiEvents(RoboticsConsoleUiKey.Key, subs => { subs.Event(OnOpened); @@ -70,20 +68,12 @@ public sealed partial class RoboticsConsoleSystem : SharedRoboticsConsoleSystem } } - private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) { - var payload = args.Data; - if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command)) - return; - if (command != DeviceNetworkConstants.CmdUpdatedState) - return; - - if (!payload.TryGetValue(RoboticsConsoleConstants.NET_CYBORG_DATA, out CyborgControlData? data)) - return; - - var real = data.Value; - real.Timeout = _timing.CurTime + ent.Comp.Timeout; - ent.Comp.Cyborgs[args.SenderAddress] = real; + var data = args.Data.Data; + data.Timeout = _timing.CurTime + ent.Comp.Timeout; + ent.Comp.Cyborgs[args.SenderAddress] = data; UpdateUserInterface(ent); } @@ -104,12 +94,9 @@ public sealed partial class RoboticsConsoleSystem : SharedRoboticsConsoleSystem if (!ent.Comp.Cyborgs.TryGetValue(args.Address, out var data)) return; - var payload = new NetworkPayload() - { - [DeviceNetworkConstants.Command] = RoboticsConsoleConstants.NET_DISABLE_COMMAND - }; + var payload = new RoboticsCyborgDisablePayload(); + _deviceNetwork.SendPacket(ent.Owner, args.Address, ref payload); - _deviceNetwork.QueuePacket(ent, args.Address, payload); _adminLogger.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):user} disabled borg {data.Name} with address {args.Address}"); } @@ -128,12 +115,8 @@ public sealed partial class RoboticsConsoleSystem : SharedRoboticsConsoleSystem if (!ent.Comp.Cyborgs.Remove(args.Address, out var data)) return; - var payload = new NetworkPayload() - { - [DeviceNetworkConstants.Command] = RoboticsConsoleConstants.NET_DESTROY_COMMAND - }; - - _deviceNetwork.QueuePacket(ent, args.Address, payload); + var payload = new RoboticsCyborgDestroyPayload(); + _deviceNetwork.SendPacket(ent.Owner, args.Address, ref payload); var message = Loc.GetString(ent.Comp.DestroyMessage, ("name", data.Name)); _radio.SendRadioMessage(ent, message, ent.Comp.RadioChannel, ent); diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index 69d355dc9f..590140b4ae 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -6,18 +6,17 @@ using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; using Content.Server.DeviceNetwork.Systems; using Content.Server.GameTicking; -using Content.Server.Screens.Components; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Systems; using Content.Server.Station.Systems; using Content.Shared.Database; -using Content.Shared.DeviceNetwork; using Content.Shared.GameTicking; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Player; using Robust.Shared.Timing; using Content.Shared.DeviceNetwork.Components; +using Content.Shared.RoundEnd; using Content.Shared.Station.Components; using Timer = Robust.Shared.Timing.Timer; @@ -223,16 +222,16 @@ namespace Content.Server.RoundEnd var shuttle = _shuttle.GetShuttle(); if (shuttle != null && TryComp(shuttle, out var net)) { - var payload = new NetworkPayload + var payload = new ScreenShuttlePayload { - [ShuttleTimerMasks.ShuttleMap] = shuttle, - [ShuttleTimerMasks.SourceMap] = GetCentcomm(), - [ShuttleTimerMasks.DestMap] = GetStation(), - [ShuttleTimerMasks.ShuttleTime] = countdownTime, - [ShuttleTimerMasks.SourceTime] = countdownTime + TimeSpan.FromSeconds(_shuttle.TransitTime + _cfg.GetCVar(CCVars.EmergencyShuttleDockTime)), - [ShuttleTimerMasks.DestTime] = countdownTime, + Shuttle = shuttle, + SourceMap = GetCentcomm(), + DestinationMap = GetStation(), + ShuttleTime = countdownTime, + SourceTime = countdownTime + TimeSpan.FromSeconds(_shuttle.TransitTime + _cfg.GetCVar(CCVars.EmergencyShuttleDockTime)), + DestinationTime = countdownTime, }; - _deviceNetworkSystem.QueuePacket(shuttle.Value, null, payload, net.TransmitFrequency); + _deviceNetworkSystem.SendPacket(shuttle.Value, null, ref payload, net.TransmitFrequency); } } @@ -271,16 +270,16 @@ namespace Content.Server.RoundEnd var shuttle = _shuttle.GetShuttle(); if (shuttle != null && TryComp(shuttle, out var net)) { - var payload = new NetworkPayload + var payload = new ScreenShuttlePayload { - [ShuttleTimerMasks.ShuttleMap] = shuttle, - [ShuttleTimerMasks.SourceMap] = GetCentcomm(), - [ShuttleTimerMasks.DestMap] = GetStation(), - [ShuttleTimerMasks.ShuttleTime] = zero, - [ShuttleTimerMasks.SourceTime] = zero, - [ShuttleTimerMasks.DestTime] = zero, + Shuttle = shuttle, + SourceMap = GetCentcomm(), + DestinationMap = GetStation(), + ShuttleTime = zero, + SourceTime = zero, + DestinationTime = zero, }; - _deviceNetworkSystem.QueuePacket(shuttle.Value, null, payload, net.TransmitFrequency); + _deviceNetworkSystem.SendPacket(shuttle.Value, null, ref payload, net.TransmitFrequency); } } diff --git a/Content.Server/Screens/Systems/ScreenSystem.cs b/Content.Server/Screens/Systems/ScreenSystem.cs index 2a30472543..c15d180edd 100644 --- a/Content.Server/Screens/Systems/ScreenSystem.cs +++ b/Content.Server/Screens/Systems/ScreenSystem.cs @@ -1,7 +1,8 @@ using Content.Shared.TextScreen; using Content.Server.Screens.Components; -using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; +using Content.Shared.RoundEnd; +using Content.Shared.Screens; using Robust.Shared.Timing; namespace Content.Server.Screens.Systems; @@ -14,24 +15,13 @@ public sealed partial class ScreenSystem : EntitySystem [Dependency] private IGameTiming _gameTiming = default!; [Dependency] private SharedAppearanceSystem _appearanceSystem = default!; - /// - /// Calls either a normal screen text update or shuttle timer update based on the presence of - /// in - /// - [SubscribeLocalEvent] - private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) - { - if (args.Data.TryGetValue(ShuttleTimerMasks.ShuttleMap, out _)) - ShuttleTimer(ent, args); - else - ScreenText(ent, args); - } - /// /// Send a text update to every screen on the same MapUid as the originating comms console. /// - private void ScreenText(Entity ent, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnScreenText(Entity ent, ref DeviceNetworkPacketEvent args) { + var text = args.Data.Text; // don't allow text updates if there's an active timer // (and just check here so the server doesn't have to track them) if (_appearanceSystem.TryGetData(ent, TextScreenVisuals.TargetTime, out TimeSpan target) @@ -41,17 +31,15 @@ public sealed partial class ScreenSystem : EntitySystem var screenMap = Transform(ent).MapUid; var argsMap = Transform(args.Sender).MapUid; - if (screenMap != null - && argsMap != null - && screenMap == argsMap - && args.Data.TryGetValue(ScreenMasks.Text, out string? text) - && text != null - ) - { - _appearanceSystem.SetData(ent, TextScreenVisuals.DefaultText, text); - _appearanceSystem.SetData(ent, TextScreenVisuals.ScreenText, text); - _appearanceSystem.SetData(ent, TextScreenVisuals.ScreenTextTime, _gameTiming.CurTime); - } + if (screenMap == null + || argsMap == null + || screenMap != argsMap + || text == null) + return; + + _appearanceSystem.SetData(ent, TextScreenVisuals.DefaultText, text); + _appearanceSystem.SetData(ent, TextScreenVisuals.ScreenText, text); + _appearanceSystem.SetData(ent, TextScreenVisuals.ScreenTextTime, _gameTiming.CurTime); } /// @@ -62,49 +50,46 @@ public sealed partial class ScreenSystem : EntitySystem /// Subnets are the shuttle, source, and dest. Source/dest change each jump. /// This is required to send different timers to the shuttle/terminal/station. /// - private void ShuttleTimer(Entity ent, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnShuttleTimer(Entity ent, ref DeviceNetworkPacketEvent args) { + var payload = args.Data; var timerXform = Transform(ent); // no false positives. if (timerXform.MapUid == null) return; - string key; - args.Data.TryGetValue(ShuttleTimerMasks.ShuttleMap, out EntityUid? shuttleMap); - args.Data.TryGetValue(ShuttleTimerMasks.SourceMap, out EntityUid? source); - args.Data.TryGetValue(ShuttleTimerMasks.DestMap, out EntityUid? dest); - args.Data.TryGetValue(ShuttleTimerMasks.Docked, out bool docked); - string text = docked ? ShuttleTimerMasks.ETD : ShuttleTimerMasks.ETA; + string? text = null; + TimeSpan time; switch (timerXform.MapUid) { - // sometimes the timer transforms on FTL shuttles have a hyperspace mapuid, so matching by grid works as a fallback. - case var local when local == shuttleMap || timerXform.GridUid == shuttleMap: - key = ShuttleTimerMasks.ShuttleTime; + // sometimes the timer transforms on FTL shuttles have a hyperspace mapent, so matching by grid works as a fallback. + case var local when local == payload.Shuttle || timerXform.GridUid == payload.Shuttle: + time = payload.ShuttleTime; break; - case var origin when origin == source: - key = ShuttleTimerMasks.SourceTime; + case var origin when origin == payload.SourceMap: + time = payload.SourceTime; break; - case var remote when remote == dest: - key = ShuttleTimerMasks.DestTime; + case var remote when remote == payload.DestinationMap: + time = payload.DestinationTime; text = ShuttleTimerMasks.ETA; break; default: return; } - if (!args.Data.TryGetValue(key, out TimeSpan duration)) - return; + if (payload.OverrideText != null) + text = payload.OverrideText; - if (args.Data.TryGetValue(ScreenMasks.Text, out string? label) && label != null) - text = label; - - _appearanceSystem.SetData(ent, TextScreenVisuals.ScreenText, text); - _appearanceSystem.SetData(ent, TextScreenVisuals.TargetTime, _gameTiming.CurTime + duration); + _appearanceSystem.SetData(ent, TextScreenVisuals.TargetTime, _gameTiming.CurTime + time); _appearanceSystem.SetData(ent, TextScreenVisuals.ScreenTextTime, _gameTiming.CurTime); - if (args.Data.TryGetValue(ScreenMasks.Color, out Color color)) - _appearanceSystem.SetData(ent, TextScreenVisuals.Color, color); + if (text != null) + _appearanceSystem.SetData(ent, TextScreenVisuals.ScreenText, text); + + if (payload.OverrideColor != null) + _appearanceSystem.SetData(ent, TextScreenVisuals.Color, payload.OverrideColor); } } diff --git a/Content.Server/SensorMonitoring/BatterySensorComponent.cs b/Content.Server/SensorMonitoring/BatterySensorComponent.cs index a5a48ddc91..41755f7a82 100644 --- a/Content.Server/SensorMonitoring/BatterySensorComponent.cs +++ b/Content.Server/SensorMonitoring/BatterySensorComponent.cs @@ -14,20 +14,3 @@ public sealed partial class BatterySensorComponent : Component { } -/// -/// Device network data sent by a . -/// -/// The current energy charge of the battery, in joules (J). -/// The maximum energy capacity of the battery, in joules (J). -/// The current amount of power being received by the battery, in watts (W). -/// The maximum amount of power that can be received by the battery, in watts (W). -/// The current amount of power being supplied by the battery, in watts (W). -/// The maximum amount of power that can be received by the battery, in watts (W). -public sealed record BatterySensorData( - float Charge, - float MaxCharge, - float Receiving, - float MaxReceiving, - float Supplying, - float MaxSupplying -); diff --git a/Content.Server/SensorMonitoring/BatterySensorSystem.cs b/Content.Server/SensorMonitoring/BatterySensorSystem.cs index 12db2764fa..feb943e0af 100644 --- a/Content.Server/SensorMonitoring/BatterySensorSystem.cs +++ b/Content.Server/SensorMonitoring/BatterySensorSystem.cs @@ -1,50 +1,35 @@ -using Content.Server.DeviceNetwork.Systems; +using Content.Server.DeviceNetwork.Systems; using Content.Server.Power.Components; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power.Components; using Content.Shared.Power.EntitySystems; +using Content.Shared.SensorMonitoring; namespace Content.Server.SensorMonitoring; public sealed partial class BatterySensorSystem : EntitySystem { - public const string DeviceNetworkCommandSyncData = "bat_sync_data"; - [Dependency] private DeviceNetworkSystem _deviceNetwork = default!; [Dependency] private SharedBatterySystem _battery = default!; - public override void Initialize() + [SubscribeLocalEvent] + private void OnSensorRequest(Entity ent, ref DeviceNetworkPacketEvent args) { - SubscribeLocalEvent(PacketReceived); - } + var battery = Comp(ent); + var currentCharge = _battery.GetCharge((ent.Owner, battery)); + var netBattery = Comp(ent); - private void PacketReceived(EntityUid uid, BatterySensorComponent component, DeviceNetworkPacketEvent args) - { - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd)) - return; - - switch (cmd) + var dataPayload = new BatterySensorDataPayload { - case DeviceNetworkCommandSyncData: - var battery = Comp(uid); - var currentCharge = _battery.GetCharge((uid, battery)); - var netBattery = Comp(uid); + Data = new BatterySensorData( + currentCharge, + battery.MaxCharge, + netBattery.CurrentReceiving, + netBattery.MaxChargeRate, + netBattery.CurrentSupply, + netBattery.MaxSupply), + }; - var payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = DeviceNetworkCommandSyncData, - [DeviceNetworkCommandSyncData] = new BatterySensorData( - currentCharge, - battery.MaxCharge, - netBattery.CurrentReceiving, - netBattery.MaxChargeRate, - netBattery.CurrentSupply, - netBattery.MaxSupply) - }; - - _deviceNetwork.QueuePacket(uid, args.SenderAddress, payload); - break; - } + _deviceNetwork.SendPacket(ent.Owner, args.SenderAddress, ref dataPayload); } } diff --git a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.cs b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.cs index de33473616..3f01f599f8 100644 --- a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.cs +++ b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.cs @@ -1,5 +1,5 @@ using Content.Server.Atmos.Monitor.Components; -using Content.Server.Atmos.Monitor.Systems; +using Content.Server.Atmos.Monitor.Payloads; using Content.Server.DeviceNetwork.Systems; using Content.Server.Power.Generation.Teg; using Content.Shared.Atmos.Components; @@ -10,6 +10,7 @@ using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared.DeviceNetwork.Systems; +using Content.Shared.Power.Generation.Teg; using Content.Shared.SensorMonitoring; using Robust.Server.GameObjects; using Robust.Shared.Timing; @@ -41,7 +42,6 @@ public sealed partial class SensorMonitoringConsoleSystem : EntitySystem SubscribeLocalEvent(DeviceListUpdated); SubscribeLocalEvent(ConsoleStartup); - SubscribeLocalEvent(DevicePacketReceived); SubscribeLocalEvent(AtmosUpdate); } @@ -143,99 +143,86 @@ public sealed partial class SensorMonitoringConsoleSystem : EntitySystem return SensorDeviceType.Unknown; } - private void DevicePacketReceived(EntityUid uid, SensorMonitoringConsoleComponent component, - DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnTegReceived(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!component.Sensors.TryGetValue(args.Sender, out var sensorData)) + var payload = args.Data; + if (!ent.Comp.Sensors.TryGetValue(args.Sender, out var sensorData)) return; - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command)) + // @formatter:off + WriteSample(ent, sensorData, "teg_last_generated", SensorUnit.EnergyJ, payload.LastGeneration); + WriteSample(ent, sensorData, "teg_power", SensorUnit.PowerW, payload.PowerOutput); + if (ent.Comp.DebugStreams) + WriteSample(ent, sensorData, "teg_ramp_pos", SensorUnit.PowerW, payload.RampPosition); + + WriteSample(ent, sensorData, "teg_circ_a_in_pressure", SensorUnit.PressureKpa, payload.CirculatorA.InletPressure); + WriteSample(ent, sensorData, "teg_circ_a_in_temperature", SensorUnit.TemperatureK, payload.CirculatorA.InletTemperature); + WriteSample(ent, sensorData, "teg_circ_a_out_pressure", SensorUnit.PressureKpa, payload.CirculatorA.OutletPressure); + WriteSample(ent, sensorData, "teg_circ_a_out_temperature", SensorUnit.TemperatureK, payload.CirculatorA.OutletTemperature); + + WriteSample(ent, sensorData, "teg_circ_b_in_pressure", SensorUnit.PressureKpa, payload.CirculatorB.InletPressure); + WriteSample(ent, sensorData, "teg_circ_b_in_temperature", SensorUnit.TemperatureK, payload.CirculatorB.InletTemperature); + WriteSample(ent, sensorData, "teg_circ_b_out_pressure", SensorUnit.PressureKpa, payload.CirculatorB.OutletPressure); + WriteSample(ent, sensorData, "teg_circ_b_out_temperature", SensorUnit.TemperatureK, payload.CirculatorB.OutletTemperature); + // @formatter:on + } + + [SubscribeLocalEvent] + private void OnAtmosSensorReceived(Entity ent, ref DeviceNetworkPacketEvent args) + { + var payload = args.Data.Data; + if (!ent.Comp.Sensors.TryGetValue(args.Sender, out var sensorData)) return; - switch (sensorData.DeviceType) - { - case SensorDeviceType.Teg: - if (command != TegSystem.DeviceNetworkCommandSyncData) - return; + // @formatter:off + WriteSample(ent, sensorData, "atmo_pressure", SensorUnit.PressureKpa, payload.Pressure); + WriteSample(ent, sensorData, "atmo_temperature", SensorUnit.TemperatureK, payload.Temperature); + // @formatter:on + } - if (!args.Data.TryGetValue(TegSystem.DeviceNetworkCommandSyncData, out TegSensorData? tegData)) - return; + [SubscribeLocalEvent] + private void OnThermoMachineReceived(Entity ent, ref DeviceNetworkPacketEvent args) + { + var payload = args.Data; + if (!ent.Comp.Sensors.TryGetValue(args.Sender, out var sensorData)) + return; - // @formatter:off - WriteSample(component, sensorData, "teg_last_generated", SensorUnit.EnergyJ, tegData.LastGeneration); - WriteSample(component, sensorData, "teg_power", SensorUnit.PowerW, tegData.PowerOutput); - if (component.DebugStreams) - WriteSample(component, sensorData, "teg_ramp_pos", SensorUnit.PowerW, tegData.RampPosition); + // @formatter:off + WriteSample(ent, sensorData, "abs_energy_delta", SensorUnit.EnergyJ, MathF.Abs(payload.EnergyDelta)); + // @formatter:on + } - WriteSample(component, sensorData, "teg_circ_a_in_pressure", SensorUnit.PressureKpa, tegData.CirculatorA.InletPressure); - WriteSample(component, sensorData, "teg_circ_a_in_temperature", SensorUnit.TemperatureK, tegData.CirculatorA.InletTemperature); - WriteSample(component, sensorData, "teg_circ_a_out_pressure", SensorUnit.PressureKpa, tegData.CirculatorA.OutletPressure); - WriteSample(component, sensorData, "teg_circ_a_out_temperature", SensorUnit.TemperatureK, tegData.CirculatorA.OutletTemperature); + [SubscribeLocalEvent] + private void OnVolumePipeReceived(Entity ent, ref DeviceNetworkPacketEvent args) + { + var payload = args.Data; + if (!ent.Comp.Sensors.TryGetValue(args.Sender, out var sensorData)) + return; - WriteSample(component, sensorData, "teg_circ_b_in_pressure", SensorUnit.PressureKpa, tegData.CirculatorB.InletPressure); - WriteSample(component, sensorData, "teg_circ_b_in_temperature", SensorUnit.TemperatureK, tegData.CirculatorB.InletTemperature); - WriteSample(component, sensorData, "teg_circ_b_out_pressure", SensorUnit.PressureKpa, tegData.CirculatorB.OutletPressure); - WriteSample(component, sensorData, "teg_circ_b_out_temperature", SensorUnit.TemperatureK, tegData.CirculatorB.OutletTemperature); - // @formatter:on - break; + // @formatter:off + WriteSample(ent, sensorData, "moles_transferred", SensorUnit.Moles, payload.LastMolesTransferred); + // @formatter:on + } - case SensorDeviceType.AtmosSensor: - if (command != AtmosDeviceNetworkSystem.SyncData) - return; + [SubscribeLocalEvent] + private void OnBatteryReceived(Entity ent, ref DeviceNetworkPacketEvent args) + { + if (!ent.Comp.Sensors.TryGetValue(args.Sender, out var sensorData)) + return; - if (!args.Data.TryGetValue(AtmosDeviceNetworkSystem.SyncData, out AtmosSensorData? atmosData)) - return; + var batteryData = args.Data.Data; - // @formatter:off - WriteSample(component, sensorData, "atmo_pressure", SensorUnit.PressureKpa, atmosData.Pressure); - WriteSample(component, sensorData, "atmo_temperature", SensorUnit.TemperatureK, atmosData.Temperature); - // @formatter:on - break; + // @formatter:off + WriteSample(ent, sensorData, "charge", SensorUnit.EnergyJ, batteryData.Charge); + WriteSample(ent, sensorData, "charge_max", SensorUnit.EnergyJ, batteryData.MaxCharge); - case SensorDeviceType.ThermoMachine: - if (command != AtmosDeviceNetworkSystem.SyncData) - return; + WriteSample(ent, sensorData, "receiving", SensorUnit.PowerW, batteryData.Receiving); + WriteSample(ent, sensorData, "receiving_max", SensorUnit.PowerW, batteryData.MaxReceiving); - if (!args.Data.TryGetValue(AtmosDeviceNetworkSystem.SyncData, out GasThermoMachineData? thermoData)) - return; - - // @formatter:off - WriteSample(component, sensorData, "abs_energy_delta", SensorUnit.EnergyJ, MathF.Abs(thermoData.EnergyDelta)); - // @formatter:on - break; - - case SensorDeviceType.VolumePump: - if (command != AtmosDeviceNetworkSystem.SyncData) - return; - - if (!args.Data.TryGetValue(AtmosDeviceNetworkSystem.SyncData, out GasVolumePumpData? volumePumpData)) - return; - - // @formatter:off - WriteSample(component, sensorData, "moles_transferred", SensorUnit.Moles, volumePumpData.LastMolesTransferred); - // @formatter:on - break; - - case SensorDeviceType.Battery: - if (command != BatterySensorSystem.DeviceNetworkCommandSyncData) - return; - - if (!args.Data.TryGetValue(BatterySensorSystem.DeviceNetworkCommandSyncData, out BatterySensorData? batteryData)) - return; - - // @formatter:off - WriteSample(component, sensorData, "charge", SensorUnit.EnergyJ, batteryData.Charge); - WriteSample(component, sensorData, "charge_max", SensorUnit.EnergyJ, batteryData.MaxCharge); - - WriteSample(component, sensorData, "receiving", SensorUnit.PowerW, batteryData.Receiving); - WriteSample(component, sensorData, "receiving_max", SensorUnit.PowerW, batteryData.MaxReceiving); - - WriteSample(component, sensorData, "supplying", SensorUnit.PowerW, batteryData.Supplying); - WriteSample(component, sensorData, "supplying_max", SensorUnit.PowerW, batteryData.MaxSupplying); - // @formatter:on - - break; - } + WriteSample(ent, sensorData, "supplying", SensorUnit.PowerW, batteryData.Supplying); + WriteSample(ent, sensorData, "supplying_max", SensorUnit.PowerW, batteryData.MaxSupplying); + // @formatter:on } private void WriteSample( @@ -267,32 +254,22 @@ public sealed partial class SensorMonitoringConsoleSystem : EntitySystem foreach (var (ent, data) in comp.Sensors) { // Send network requests for new data! - NetworkPayload payload; + INetworkPayload payload; switch (data.DeviceType) { case SensorDeviceType.Teg: - payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = TegSystem.DeviceNetworkCommandSyncData - }; - break; - case SensorDeviceType.AtmosSensor: case SensorDeviceType.ThermoMachine: case SensorDeviceType.VolumePump: - payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = AtmosDeviceNetworkSystem.SyncData - }; + payload = new AtmosSyncPayload(); break; - default: // Unknown device type, don't do anything. continue; } var address = _deviceNetworkQuery.GetComponent(ent); - _deviceNetwork.QueuePacket(uid, address.Address, payload); + _deviceNetwork.SendPacket(uid, address.Address, ref payload); } } @@ -301,23 +278,19 @@ public sealed partial class SensorMonitoringConsoleSystem : EntitySystem foreach (var (ent, data) in comp.Sensors) { // Send network requests for new data! - NetworkPayload payload; + INetworkPayload payload; switch (data.DeviceType) { case SensorDeviceType.Battery: - payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = BatterySensorSystem.DeviceNetworkCommandSyncData - }; + payload = new BatterySensorSyncPayload(); break; - default: // Unknown device type, don't do anything. continue; } var address = _deviceNetworkQuery.GetComponent(ent); - _deviceNetwork.QueuePacket(uid, address.Address, payload); + _deviceNetwork.SendPacket(uid, address.Address, ref payload); } } } diff --git a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs index 4820b0946f..e79a0d6b08 100644 --- a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs +++ b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs @@ -7,7 +7,6 @@ using Content.Server.DeviceNetwork.Systems; using Content.Server.GameTicking; using Content.Server.GameTicking.Events; using Content.Server.Parallax; -using Content.Server.Screens.Components; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; using Content.Server.Spawners.Components; @@ -17,12 +16,12 @@ using Content.Server.Station.Systems; using Content.Shared.Administration; using Content.Shared.CCVar; using Content.Shared.Damage.Components; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.GameTicking; using Content.Shared.Mobs.Components; using Content.Shared.Movement.Components; using Content.Shared.Parallax.Biomes; +using Content.Shared.RoundEnd; using Content.Shared.Salvage; using Content.Shared.Shuttles.Components; using Content.Shared.Tiles; @@ -208,10 +207,10 @@ public sealed partial class ArrivalsSystem : EntitySystem TryComp(shuttleUid, out var ftlComp); var ftlTime = TimeSpan.FromSeconds(ftlComp?.TravelTime ?? _shuttles.DefaultTravelTime); - var payload = new NetworkPayload + var payload = new ScreenShuttlePayload { - [ShuttleTimerMasks.ShuttleMap] = shuttleUid, - [ShuttleTimerMasks.ShuttleTime] = ftlTime + Shuttle = shuttleUid, + ShuttleTime = ftlTime, }; // unfortunate levels of spaghetti due to roundstart arrivals ftl behavior @@ -224,16 +223,16 @@ public sealed partial class ArrivalsSystem : EntitySystem sourceMap = station == null ? null : Transform(station.Value)?.MapUid; arrivalsDelay += RoundStartFTLDuration; component.FirstRun = false; - payload.Add(ShuttleTimerMasks.DestMap, Transform(args.TargetCoordinates.EntityId).MapUid); - payload.Add(ShuttleTimerMasks.DestTime, ftlTime); + payload.DestinationMap = Transform(args.TargetCoordinates.EntityId).MapUid; + payload.DestinationTime = ftlTime; } else sourceMap = args.FromMapUid; - payload.Add(ShuttleTimerMasks.SourceMap, sourceMap); - payload.Add(ShuttleTimerMasks.SourceTime, ftlTime + TimeSpan.FromSeconds(arrivalsDelay)); + payload.SourceMap = sourceMap; + payload.SourceTime = ftlTime + TimeSpan.FromSeconds(arrivalsDelay); - _deviceNetworkSystem.QueuePacket(shuttleUid, null, payload, netComp.TransmitFrequency); + _deviceNetworkSystem.SendPacket(shuttleUid, null, ref payload, netComp.TransmitFrequency); } // Don't do anything here when leaving arrivals. @@ -282,15 +281,15 @@ public sealed partial class ArrivalsSystem : EntitySystem if (TryComp(uid, out var netComp)) { - var payload = new NetworkPayload + var payload = new ScreenShuttlePayload { - [ShuttleTimerMasks.ShuttleMap] = uid, - [ShuttleTimerMasks.ShuttleTime] = dockTime, - [ShuttleTimerMasks.SourceMap] = args.MapUid, - [ShuttleTimerMasks.SourceTime] = dockTime, - [ShuttleTimerMasks.Docked] = true + Shuttle = uid, + ShuttleTime = dockTime, + SourceMap = args.MapUid, + SourceTime = dockTime, + Docked = true, }; - _deviceNetworkSystem.QueuePacket(uid, null, payload, netComp.TransmitFrequency); + _deviceNetworkSystem.SendPacket(uid, null, ref payload, netComp.TransmitFrequency); } } diff --git a/Content.Server/Shuttles/Systems/DockingSignalControlSystem.cs b/Content.Server/Shuttles/Systems/DockingSignalControlSystem.cs index 483778d201..e8fcaa1dbe 100644 --- a/Content.Server/Shuttles/Systems/DockingSignalControlSystem.cs +++ b/Content.Server/Shuttles/Systems/DockingSignalControlSystem.cs @@ -18,11 +18,11 @@ public sealed partial class DockingSignalControlSystem : EntitySystem private void OnDocked(Entity ent, ref DockEvent args) { - _deviceLinkSystem.SendSignal(ent, ent.Comp.DockStatusSignalPort, signal: true); + _deviceLinkSystem.SendSignal(ent.Owner, ent.Comp.DockStatusSignalPort, signal: true); } private void OnUndocked(Entity ent, ref UndockEvent args) { - _deviceLinkSystem.SendSignal(ent, ent.Comp.DockStatusSignalPort, signal: false); + _deviceLinkSystem.SendSignal(ent.Owner, ent.Comp.DockStatusSignalPort, signal: false); } } diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs index c177b37504..2d7e6feefc 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs @@ -1,13 +1,12 @@ using System.Threading; -using Content.Server.Screens.Components; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; using Content.Shared.Access; using Content.Shared.CCVar; using Content.Shared.Database; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.Popups; +using Content.Shared.RoundEnd; using Content.Shared.Shuttles.BUIStates; using Content.Shared.Shuttles.Components; using Content.Shared.Shuttles.Events; @@ -376,17 +375,17 @@ public sealed partial class EmergencyShuttleSystem var shuttle = GetShuttle(); if (shuttle != null && TryComp(shuttle, out var net)) { - var payload = new NetworkPayload + var payload = new ScreenShuttlePayload { - [ShuttleTimerMasks.ShuttleMap] = shuttle, - [ShuttleTimerMasks.SourceMap] = _roundEnd.GetStation(), - [ShuttleTimerMasks.DestMap] = _roundEnd.GetCentcomm(), - [ShuttleTimerMasks.ShuttleTime] = time, - [ShuttleTimerMasks.SourceTime] = time, - [ShuttleTimerMasks.DestTime] = time + TimeSpan.FromSeconds(TransitTime), - [ShuttleTimerMasks.Docked] = true + Shuttle = shuttle, + SourceMap = _roundEnd.GetStation(), + DestinationMap = _roundEnd.GetCentcomm(), + ShuttleTime = time, + SourceTime = time, + DestinationTime = time + TimeSpan.FromSeconds(TransitTime), + Docked = true, }; - _deviceNetworkSystem.QueuePacket(shuttle.Value, null, payload, net.TransmitFrequency); + _deviceNetworkSystem.SendPacket(shuttle.Value, null, ref payload, net.TransmitFrequency); } return true; diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index e0cd4a155f..a6105f3e58 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -19,10 +19,10 @@ using Content.Server.Station.Systems; using Content.Shared.Access.Systems; using Content.Shared.CCVar; using Content.Shared.Database; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.GameTicking; using Content.Shared.Localizations; +using Content.Shared.RoundEnd; using Content.Shared.Shuttles.Components; using Content.Shared.Shuttles.Events; using Content.Shared.Shuttles.Systems; @@ -210,16 +210,16 @@ public sealed partial class EmergencyShuttleSystem : SharedEmergencyShuttleSyste if (TryComp(uid, out var netComp)) { - var payload = new NetworkPayload + var payload = new ScreenShuttlePayload { - [ShuttleTimerMasks.ShuttleMap] = uid, - [ShuttleTimerMasks.SourceMap] = args.FromMapUid, - [ShuttleTimerMasks.DestMap] = _transformSystem.GetMap(args.TargetCoordinates), - [ShuttleTimerMasks.ShuttleTime] = ftlTime, - [ShuttleTimerMasks.SourceTime] = ftlTime, - [ShuttleTimerMasks.DestTime] = ftlTime + Shuttle = uid, + SourceMap = args.FromMapUid, + DestinationMap = _transformSystem.GetMap(args.TargetCoordinates), + ShuttleTime = ftlTime, + SourceTime = ftlTime, + DestinationTime = ftlTime, }; - _deviceNetworkSystem.QueuePacket(uid, null, payload, netComp.TransmitFrequency); + _deviceNetworkSystem.SendPacket(uid, null, ref payload, netComp.TransmitFrequency); } } @@ -232,27 +232,27 @@ public sealed partial class EmergencyShuttleSystem : SharedEmergencyShuttleSyste var shuttle = args.Entity; if (TryComp(shuttle, out var net)) { - var payload = new NetworkPayload + var payload = new ScreenShuttlePayload { - [ShuttleTimerMasks.ShuttleMap] = shuttle, - [ShuttleTimerMasks.SourceMap] = _roundEnd.GetCentcomm(), - [ShuttleTimerMasks.DestMap] = _roundEnd.GetStation(), - [ShuttleTimerMasks.ShuttleTime] = countdownTime, - [ShuttleTimerMasks.SourceTime] = countdownTime, - [ShuttleTimerMasks.DestTime] = countdownTime, + Shuttle = shuttle, + SourceMap = _roundEnd.GetCentcomm(), + DestinationMap = _roundEnd.GetStation(), + ShuttleTime = countdownTime, + SourceTime = countdownTime, + DestinationTime = countdownTime, }; // by popular request // https://discord.com/channels/310555209753690112/770682801607278632/1189989482234126356 if (_random.Next(1000) == 0) { - payload.Add(ScreenMasks.Text, ShuttleTimerMasks.Kill); - payload.Add(ScreenMasks.Color, Color.Red); + payload.OverrideText = ShuttleTimerMasks.Kill; + payload.OverrideColor = Color.Red; } else - payload.Add(ScreenMasks.Text, ShuttleTimerMasks.Bye); + payload.OverrideText = ShuttleTimerMasks.Bye; - _deviceNetworkSystem.QueuePacket(shuttle, null, payload, net.TransmitFrequency); + _deviceNetworkSystem.SendPacket(shuttle, null, ref payload, net.TransmitFrequency); } } @@ -377,17 +377,17 @@ public sealed partial class EmergencyShuttleSystem : SharedEmergencyShuttleSyste var time = TimeSpan.FromSeconds(_consoleAccumulator); if (TryComp(shuttle, out var netComp)) { - var payload = new NetworkPayload + var payload = new ScreenShuttlePayload { - [ShuttleTimerMasks.ShuttleMap] = shuttle, - [ShuttleTimerMasks.SourceMap] = targetXform.MapUid, - [ShuttleTimerMasks.DestMap] = _roundEnd.GetCentcomm(), - [ShuttleTimerMasks.ShuttleTime] = time, - [ShuttleTimerMasks.SourceTime] = time, - [ShuttleTimerMasks.DestTime] = time + TimeSpan.FromSeconds(TransitTime), - [ShuttleTimerMasks.Docked] = true, + Shuttle = shuttle, + SourceMap = targetXform.MapUid, + DestinationMap = _roundEnd.GetCentcomm(), + ShuttleTime = time, + SourceTime = time, + DestinationTime = time + TimeSpan.FromSeconds(TransitTime), + Docked = true, }; - _deviceNetworkSystem.QueuePacket(shuttle.Value, null, payload, netComp.TransmitFrequency); + _deviceNetworkSystem.SendPacket(shuttle.Value, null, ref payload, netComp.TransmitFrequency); } // Play announcement audio. diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs index d181c7e228..35a1a78caf 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs @@ -1,4 +1,3 @@ -using Content.Shared.DeviceNetwork; using Content.Shared.Damage.Components; using Content.Shared.FixedPoint; using Content.Shared.Mobs; @@ -16,11 +15,6 @@ namespace Content.Server.Silicons.Borgs; /// public sealed partial class BorgSystem { - private void InitializeTransponder() - { - SubscribeLocalEvent(OnPacketReceived); - } - public void UpdateTransponder(float frameTime) { var now = _timing.CurTime; @@ -52,12 +46,11 @@ public sealed partial class BorgSystem hasBrain, canDisable); - var payload = new NetworkPayload() + var payload = new RoboticsCyborgDataPayload { - [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdUpdatedState, - [RoboticsConsoleConstants.NET_CYBORG_DATA] = data + Data = data, }; - _deviceNetwork.QueuePacket(uid, null, payload, device: device); + _deviceNetwork.SendPacket((uid, device), null, ref payload); comp.NextBroadcast = now + comp.BroadcastDelay; } @@ -81,16 +74,16 @@ public sealed partial class BorgSystem _container.Remove(brain, ent.Comp2.BrainContainer); } - private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnDisable(Entity ent, ref DeviceNetworkPacketEvent args) { - var payload = args.Data; - if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command)) - return; + Disable(ent); + } - if (command == RoboticsConsoleConstants.NET_DISABLE_COMMAND) - Disable(ent); - else if (command == RoboticsConsoleConstants.NET_DESTROY_COMMAND) - Destroy(ent.Owner); + [SubscribeLocalEvent] + private void OnDestroy(Entity ent, ref DeviceNetworkPacketEvent args) + { + Destroy(ent.AsNullable()); } private void Disable(Entity ent) diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 16e5b3e281..c5af1f12a8 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -36,14 +36,6 @@ public sealed partial class BorgSystem : SharedBorgSystem public static readonly ProtoId BorgJobId = "Borg"; - /// - public override void Initialize() - { - base.Initialize(); - - InitializeTransponder(); - } - public override bool CanPlayerBeBorged(ICommonSession session) { if (_banManager.GetJobBans(session.UserId)?.Contains(BorgJobId) == true) diff --git a/Content.Server/SurveillanceCamera/Components/SurveillanceCameraRouterComponent.cs b/Content.Server/SurveillanceCamera/Components/SurveillanceCameraRouterComponent.cs index fc848881e7..bc1fb31c1a 100644 --- a/Content.Server/SurveillanceCamera/Components/SurveillanceCameraRouterComponent.cs +++ b/Content.Server/SurveillanceCamera/Components/SurveillanceCameraRouterComponent.cs @@ -8,22 +8,29 @@ public sealed partial class SurveillanceCameraRouterComponent : Component { [ViewVariables] public bool Active { get; set; } - // The name of the subnet connected to this router. - [DataField("subnetName")] - public string SubnetName { get; set; } = string.Empty; - + /// + /// The name of the subnet connected to this router. + /// + [ViewVariables] + public string SubnetName = string.Empty; + + /// + /// The monitors to route to. This raises an issue related to + /// camera monitors disappearing before sending a D/C packet, + /// this could probably be refreshed every time a new monitor + /// is added or removed from active routing. + /// [ViewVariables] - // The monitors to route to. This raises an issue related to - // camera monitors disappearing before sending a D/C packet, - // this could probably be refreshed every time a new monitor - // is added or removed from active routing. public HashSet MonitorRoutes { get; } = new(); + /// + /// The frequency that talks to this router's subnet. + /// [ViewVariables] - // The frequency that talks to this router's subnet. public uint SubnetFrequency; + [DataField("subnetFrequency")] - public ProtoId? SubnetFrequencyId { get; set; } + public ProtoId? SubnetFrequencyId { get; set; } [DataField("setupAvailableNetworks")] public List> AvailableNetworks { get; private set; } = new(); diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMapSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMapSystem.cs index a2417372a2..590a92e7e3 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMapSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMapSystem.cs @@ -76,6 +76,9 @@ public sealed partial class SurveillanceCameraMapSystem : EntitySystem if (gridUid is null) return; + if (deviceNet.ReceiveFrequencyId == null) + return; + var netEntity = GetNetEntity(uid); var mapComp = EnsureComp(gridUid.Value); @@ -84,7 +87,7 @@ public sealed partial class SurveillanceCameraMapSystem : EntitySystem var localPos = Vector2.Transform(worldPos, gridMatrix); var address = deviceNet.Address; - var subnet = deviceNet.ReceiveFrequencyId ?? string.Empty; + var subnet = deviceNet.ReceiveFrequencyId.Value; var powered = CompOrNull(uid)?.Powered ?? true; var active = comp.Active && powered; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs index 65a15e1a9e..b499b8ad35 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Server.DeviceNetwork.Systems; using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; +using Content.Shared.DeviceNetwork.Systems; using Content.Shared.Power; using Content.Shared.UserInterface; using Content.Shared.SurveillanceCamera; @@ -16,13 +17,14 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem [Dependency] private SurveillanceCameraSystem _surveillanceCameras = default!; [Dependency] private UserInterfaceSystem _userInterface = default!; [Dependency] private DeviceNetworkSystem _deviceNetworkSystem = default!; + [Dependency] private DeviceNetworkRouterSystem _deviceNetworkRouter = default!; public override void Initialize() { + base.Initialize(); SubscribeLocalEvent(OnSurveillanceCameraDeactivate); SubscribeLocalEvent(OnPowerChanged); SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPacketReceived); SubscribeLocalEvent(OnComponentStartup); SubscribeLocalEvent(OnToggleInterface); Subs.BuiEvents(SurveillanceCameraMonitorUiKey.Key, subs => @@ -93,72 +95,52 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem } } - private void OnPacketReceived(EntityUid uid, SurveillanceCameraMonitorComponent component, - DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnCameraConnect(Entity ent, ref DeviceNetworkPacketEvent args) { - if (string.IsNullOrEmpty(args.SenderAddress)) + var payload = args.Data; + if (ent.Comp.NextCameraAddress == payload.SenderAddress) { - return; + if (payload.SenderAddress != null) + ent.Comp.ActiveCameraAddress = payload.SenderAddress; + TrySwitchCameraByUid(ent, payload.Sender, ent.Comp); } - if (args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command)) + ent.Comp.NextCameraAddress = null; + } + + [SubscribeLocalEvent] + private void OnCameraHeartbeat(Entity ent, ref DeviceNetworkPacketEvent args) + { + if (args.Data.SenderAddress == ent.Comp.ActiveCameraAddress) { - switch (command) - { - case SurveillanceCameraSystem.CameraConnectMessage: - if (component.NextCameraAddress == args.SenderAddress) - { - component.ActiveCameraAddress = args.SenderAddress; - TrySwitchCameraByUid(uid, args.Sender, component); - } - - component.NextCameraAddress = null; - break; - case SurveillanceCameraSystem.CameraHeartbeatMessage: - if (args.SenderAddress == component.ActiveCameraAddress) - { - component.LastHeartbeat = 0; - } - - break; - case SurveillanceCameraSystem.CameraDataMessage: - { - if (!args.Data.TryGetValue(SurveillanceCameraSystem.CameraNameData, out string? name) - || !args.Data.TryGetValue(SurveillanceCameraSystem.CameraSubnetData, out ProtoId? subnetData) - || !args.Data.TryGetValue(SurveillanceCameraSystem.CameraAddressData, out string? address)) - { - return; - } - - if (component.ActiveSubnet != subnetData && subnetData is { } subnet) - { - DisconnectFromSubnet(uid, subnet); - } - - if (!component.KnownCameras.ContainsKey(address)) - { - component.KnownCameras.Add(address, name); - } - - UpdateUserInterface(uid, component); - break; - } - case SurveillanceCameraSystem.CameraSubnetData: - { - if (args.Data.TryGetValue(SurveillanceCameraSystem.CameraSubnetData, out ProtoId? subnetValue) - && subnetValue is { } subnet - && !component.KnownSubnets.ContainsKey(subnet)) - { - component.KnownSubnets.Add(subnet, args.SenderAddress); - } - - UpdateUserInterface(uid, component); - break; - } - } + ent.Comp.LastHeartbeat = 0; } } + [SubscribeLocalEvent] + private void OnCameraData(Entity ent, ref DeviceNetworkPacketEvent args) + { + var payload = args.Data; + var subnetData = payload.Subnet; + + if (ent.Comp.ActiveSubnet != subnetData) + { + DisconnectFromSubnet(ent, subnetData); + } + + if (payload.SenderAddress != null) + ent.Comp.KnownCameras.TryAdd(payload.SenderAddress, payload.Name); + UpdateUserInterface(ent, ent.Comp); + } + + [SubscribeLocalEvent] + private void OnSubnetData(Entity ent, ref DeviceNetworkPacketEvent args) + { + ent.Comp.KnownSubnets.TryAdd(args.Data.TransmitFrequency, args.SenderAddress); + UpdateUserInterface(ent, ent.Comp); + } + private void OnDisconnectMessage(EntityUid uid, SurveillanceCameraMonitorComponent component, SurveillanceCameraDisconnectMessage message) { @@ -169,7 +151,7 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem SurveillanceCameraRefreshCamerasMessage message) { component.KnownCameras.Clear(); - RequestActiveSubnetInfo(uid, component); + PingCameraNetwork(uid, component); } private void OnRefreshSubnetsMessage(EntityUid uid, SurveillanceCameraMonitorComponent component, @@ -231,13 +213,9 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem return; } - var payload = new NetworkPayload() - { - { DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraHeartbeatMessage }, - { SurveillanceCameraSystem.CameraAddressData, monitor.ActiveCameraAddress } - }; + var payload = new SurveillanceCameraHeartbeatPayload(); + _deviceNetworkRouter.SendPacketRouted(uid, ref payload, subnetAddress, monitor.ActiveCameraAddress, ProtoMan.Index(activeSubnet).Frequency); - _deviceNetworkSystem.QueuePacket(uid, subnetAddress, payload); monitor.LastHeartbeatSent = 0; } @@ -267,21 +245,18 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem } monitor.KnownSubnets.Clear(); - PingCameraNetwork(uid, monitor); + PingSubnets(uid, monitor); } private void PingCameraNetwork(EntityUid uid, SurveillanceCameraMonitorComponent? monitor = null) { - if (!Resolve(uid, ref monitor)) - { + if (!Resolve(uid, ref monitor) + || monitor.ActiveSubnet == null + || !monitor.KnownSubnets.TryGetValue(monitor.ActiveSubnet.Value, out var subnetData)) return; - } - var payload = new NetworkPayload() - { - { DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraPingMessage } - }; - _deviceNetworkSystem.QueuePacket(uid, null, payload); + var payload = new SurveillanceCameraPingPayload { Subnet = monitor.ActiveSubnet }; + _deviceNetworkRouter.SendPacketRouted(uid, ref payload, null, null, ProtoMan.Index(monitor.ActiveSubnet.Value).Frequency); } private void SetActiveSubnet(EntityUid uid, ProtoId subnet, @@ -303,20 +278,15 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem ConnectToSubnet(uid, subnet); } - private void RequestActiveSubnetInfo(EntityUid uid, SurveillanceCameraMonitorComponent? monitor = null) + private void PingSubnets(EntityUid uid, SurveillanceCameraMonitorComponent? monitor = null) { - if (!Resolve(uid, ref monitor) - || monitor.ActiveSubnet is not { } activeSubnet - || !monitor.KnownSubnets.TryGetValue(activeSubnet, out var address)) + if (!Resolve(uid, ref monitor)) { return; } - var payload = new NetworkPayload() - { - {DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraPingSubnetMessage}, - }; - _deviceNetworkSystem.QueuePacket(uid, address, payload); + var payload = new SurveillanceCameraPingSubnetPayload(); + _deviceNetworkSystem.SendPacket(uid, null, ref payload); } private void ConnectToSubnet(EntityUid uid, string subnet, SurveillanceCameraMonitorComponent? monitor = null) @@ -328,13 +298,10 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem return; } - var payload = new NetworkPayload() - { - {DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraSubnetConnectMessage}, - }; - _deviceNetworkSystem.QueuePacket(uid, address, payload); + var payload = new SurveillanceCameraSubnetConnectPayload(); + _deviceNetworkSystem.SendPacket(uid, address, ref payload); - RequestActiveSubnetInfo(uid); + PingSubnets(uid); } private void DisconnectFromSubnet(EntityUid uid, ProtoId subnet, SurveillanceCameraMonitorComponent? monitor = null) @@ -345,11 +312,8 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem return; } - var payload = new NetworkPayload() - { - {DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraSubnetDisconnectMessage}, - }; - _deviceNetworkSystem.QueuePacket(uid, address, payload); + var payload = new SurveillanceCameraSubnetDisconnectPayload(); + _deviceNetworkSystem.SendPacket(uid, address, ref payload); } // Adds a viewer to the camera and the monitor. @@ -436,14 +400,9 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem || !monitor.KnownSubnets.TryGetValue(activeSubnet, out var subnetAddress)) return; - var payload = new NetworkPayload() - { - {DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraConnectMessage}, - {SurveillanceCameraSystem.CameraAddressData, address} - }; - + var payload = new SurveillanceCameraConnectRequestPayload(); monitor.NextCameraAddress = address; - _deviceNetworkSystem.QueuePacket(uid, subnetAddress, payload); + _deviceNetworkRouter.SendPacketRouted(uid, ref payload, subnetAddress, address, ProtoMan.Index(activeSubnet).Frequency); } // Attempts to switch over the current viewed camera on this monitor @@ -498,7 +457,12 @@ public sealed partial class SurveillanceCameraMonitorSystem : EntitySystem return; } - var state = new SurveillanceCameraMonitorUiState(GetNetEntity(monitor.ActiveCamera), monitor.KnownSubnets.Keys.ToHashSet(), monitor.ActiveCameraAddress, monitor.ActiveSubnet, monitor.KnownCameras); + var state = new SurveillanceCameraMonitorUiState( + GetNetEntity(monitor.ActiveCamera), + monitor.KnownSubnets.Keys.ToHashSet(), + monitor.ActiveCameraAddress, + monitor.ActiveSubnet, + monitor.KnownCameras); _userInterface.SetUiState(uid, SurveillanceCameraMonitorUiKey.Key, state); } } diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs index ddfcd696db..d082374bc9 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs @@ -1,6 +1,5 @@ using Content.Server.DeviceNetwork.Systems; using Content.Shared.ActionBlocker; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; using Content.Shared.SurveillanceCamera; @@ -15,249 +14,163 @@ public sealed partial class SurveillanceCameraRouterSystem : EntitySystem [Dependency] private DeviceNetworkSystem _deviceNetworkSystem = default!; [Dependency] private ActionBlockerSystem _actionBlocker = default!; [Dependency] private UserInterfaceSystem _userInterface = default!; + + [Dependency] private EntityQuery _query = default!; + public override void Initialize() { - SubscribeLocalEvent(OnInitialize); - SubscribeLocalEvent(OnPacketReceive); + base.Initialize(); + SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnSetNetwork); SubscribeLocalEvent>(AddVerbs); SubscribeLocalEvent(OnPowerChanged); } - private void OnInitialize(EntityUid uid, SurveillanceCameraRouterComponent router, ComponentInit args) + private void OnMapInit(Entity ent, ref MapInitEvent args) { - if (router.SubnetFrequencyId == null || - !ProtoMan.TryIndex(router.SubnetFrequencyId, out DeviceFrequencyPrototype? subnetFrequency)) + if (ent.Comp.SubnetFrequencyId == null + || !ProtoMan.TryIndex(ent.Comp.SubnetFrequencyId, out var subnetFrequency)) + return; + + ent.Comp.SubnetFrequency = subnetFrequency.Frequency; + ent.Comp.Active = true; + + if (string.IsNullOrEmpty(ent.Comp.SubnetName) && subnetFrequency.Name != null) + ent.Comp.SubnetName = Loc.GetString(subnetFrequency.Name); + } + + [SubscribeLocalEvent] + private void OnSubnetConnect(Entity ent, ref DeviceNetworkPacketEvent args) + { + AddMonitorToRoute(ent.AsNullable(), args.SenderAddress); + PingSubnet(ent.AsNullable()); + } + + [SubscribeLocalEvent] + private void OnSubnetDisconnect(Entity ent, ref DeviceNetworkPacketEvent args) + { + RemoveMonitorFromRoute(ent.AsNullable(), args.SenderAddress); + } + + [SubscribeLocalEvent] + private void OnSubnetPing(Entity ent, ref DeviceNetworkPacketEvent args) + { + if (ent.Comp.SubnetFrequencyId == null) + return; + + var response = new SurveillanceCameraSubnetDataPayload + { + Subnet = ent.Comp.SubnetName, + TransmitFrequency = ent.Comp.SubnetFrequencyId.Value, + }; + _deviceNetworkSystem.SendPacket(ent.Owner, args.SenderAddress, ref response); + } + + private void OnPowerChanged(Entity ent, ref PowerChangedEvent args) + { + ent.Comp.MonitorRoutes.Clear(); + ent.Comp.Active = args.Powered; + } + + private void AddVerbs(Entity ent, ref GetVerbsEvent verbs) + { + if (!_actionBlocker.CanInteract(verbs.User, ent.Owner) || !_actionBlocker.CanComplexInteract(verbs.User)) { return; } - router.SubnetFrequency = subnetFrequency.Frequency; - router.Active = true; - } - - private void OnPacketReceive(EntityUid uid, SurveillanceCameraRouterComponent router, DeviceNetworkPacketEvent args) - { - if (!router.Active - || string.IsNullOrEmpty(args.SenderAddress) - || !args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command)) - { - return; - } - - switch (command) - { - case SurveillanceCameraSystem.CameraConnectMessage: - if (!args.Data.TryGetValue(SurveillanceCameraSystem.CameraAddressData, out string? address)) - { - return; - } - - ConnectCamera(uid, args.SenderAddress, address, router); - break; - case SurveillanceCameraSystem.CameraHeartbeatMessage: - if (!args.Data.TryGetValue(SurveillanceCameraSystem.CameraAddressData, out string? camera)) - { - return; - } - - SendHeartbeat(uid, args.SenderAddress, camera, router); - break; - case SurveillanceCameraSystem.CameraSubnetConnectMessage: - AddMonitorToRoute(uid, args.SenderAddress, router); - PingSubnet(uid, router); - break; - case SurveillanceCameraSystem.CameraSubnetDisconnectMessage: - RemoveMonitorFromRoute(uid, args.SenderAddress, router); - break; - case SurveillanceCameraSystem.CameraPingSubnetMessage: - PingSubnet(uid, router); - break; - case SurveillanceCameraSystem.CameraPingMessage: - SubnetPingResponse(uid, args.SenderAddress, router); - break; - case SurveillanceCameraSystem.CameraDataMessage: - SendCameraInfo(uid, args.Data, router); - break; - } - } - - private void OnPowerChanged(EntityUid uid, SurveillanceCameraRouterComponent component, ref PowerChangedEvent args) - { - component.MonitorRoutes.Clear(); - component.Active = args.Powered; - } - - private void AddVerbs(EntityUid uid, SurveillanceCameraRouterComponent component, GetVerbsEvent verbs) - { - if (!_actionBlocker.CanInteract(verbs.User, uid) || !_actionBlocker.CanComplexInteract(verbs.User)) - { - return; - } - - if (component.SubnetFrequencyId != null) + if (ent.Comp.SubnetFrequencyId != null) { return; } AlternativeVerb verb = new(); + var user = verbs.User; verb.Text = Loc.GetString("surveillance-camera-setup"); - verb.Act = () => OpenSetupInterface(uid, verbs.User, component); + verb.Act = () => OpenSetupInterface(ent.AsNullable(), user); verbs.Verbs.Add(verb); } - private void OnSetNetwork(EntityUid uid, SurveillanceCameraRouterComponent component, - SurveillanceCameraSetupSetNetwork args) + private void OnSetNetwork(Entity ent, ref SurveillanceCameraSetupSetNetwork args) { if (args.UiKey is not SurveillanceCameraSetupUiKey key || key != SurveillanceCameraSetupUiKey.Router) { return; } - if (args.Network < 0 || args.Network >= component.AvailableNetworks.Count) + if (args.Network < 0 || args.Network >= ent.Comp.AvailableNetworks.Count) { return; } - if (!ProtoMan.Resolve(component.AvailableNetworks[args.Network], - out var frequency)) + if (!ProtoMan.Resolve(ent.Comp.AvailableNetworks[args.Network], out var frequency)) { return; } - component.SubnetFrequencyId = component.AvailableNetworks[args.Network]; - component.SubnetFrequency = frequency.Frequency; - component.Active = true; - UpdateSetupInterface(uid, component); + ent.Comp.SubnetFrequencyId = ent.Comp.AvailableNetworks[args.Network]; + ent.Comp.SubnetFrequency = frequency.Frequency; + ent.Comp.Active = true; + UpdateSetupInterface(ent.AsNullable()); } - private void OpenSetupInterface(EntityUid uid, EntityUid player, SurveillanceCameraRouterComponent? camera = null) + private void OpenSetupInterface(Entity ent, EntityUid player) { - if (!Resolve(uid, ref camera)) + if (!_query.Resolve(ref ent)) return; - if (!_userInterface.TryOpenUi(uid, SurveillanceCameraSetupUiKey.Router, player)) + if (!_userInterface.TryOpenUi(ent.Owner, SurveillanceCameraSetupUiKey.Router, player)) return; - UpdateSetupInterface(uid, camera); + UpdateSetupInterface(ent.AsNullable()); } - private void UpdateSetupInterface(EntityUid uid, SurveillanceCameraRouterComponent? router = null, DeviceNetworkComponent? deviceNet = null) + private void UpdateSetupInterface(Entity ent) { - if (!Resolve(uid, ref router, ref deviceNet)) + if (!_query.Resolve(ent.Owner, ref ent.Comp1) || !Resolve(ent.Owner, ref ent.Comp2)) + return; + + if (ent.Comp1.AvailableNetworks.Count == 0 || ent.Comp1.SubnetFrequencyId != null) { + _userInterface.CloseUi(ent.Owner, SurveillanceCameraSetupUiKey.Router); return; } - if (router.AvailableNetworks.Count == 0 || router.SubnetFrequencyId != null) - { - _userInterface.CloseUi(uid, SurveillanceCameraSetupUiKey.Router); - return; - } - - var state = new SurveillanceCameraSetupBoundUiState(router.SubnetName, deviceNet.ReceiveFrequency ?? 0, - router.AvailableNetworks, true, router.SubnetFrequencyId != null); - _userInterface.SetUiState(uid, SurveillanceCameraSetupUiKey.Router, state); - } - - private void SendHeartbeat(EntityUid uid, string origin, string destination, - SurveillanceCameraRouterComponent? router = null) - { - if (!Resolve(uid, ref router)) - { - return; - } - - var payload = new NetworkPayload() - { - { DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraHeartbeatMessage }, - { SurveillanceCameraSystem.CameraAddressData, origin } - }; - - _deviceNetworkSystem.QueuePacket(uid, destination, payload, router.SubnetFrequency); - } - - private void SubnetPingResponse(EntityUid uid, string origin, SurveillanceCameraRouterComponent? router = null) - { - if (!Resolve(uid, ref router) || router.SubnetFrequencyId == null) - { - return; - } - - var payload = new NetworkPayload() - { - { DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraSubnetData }, - { SurveillanceCameraSystem.CameraSubnetData, router.SubnetFrequencyId } - }; - - _deviceNetworkSystem.QueuePacket(uid, origin, payload); - } - - private void ConnectCamera(EntityUid uid, string origin, string address, SurveillanceCameraRouterComponent? router = null) - { - if (!Resolve(uid, ref router)) - { - return; - } - - var payload = new NetworkPayload() - { - { DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraConnectMessage }, - { SurveillanceCameraSystem.CameraAddressData, origin } - }; - - _deviceNetworkSystem.QueuePacket(uid, address, payload, router.SubnetFrequency); + var state = new SurveillanceCameraSetupBoundUiState(ent.Comp1.SubnetName, + ent.Comp2.ReceiveFrequency ?? 0, + ent.Comp1.AvailableNetworks, + true, + ent.Comp1.SubnetFrequencyId != null); + _userInterface.SetUiState(ent.Owner, SurveillanceCameraSetupUiKey.Router, state); } // Adds a monitor to the set of routes. - private void AddMonitorToRoute(EntityUid uid, string address, SurveillanceCameraRouterComponent? router = null) + private void AddMonitorToRoute(Entity ent, string address) { - if (!Resolve(uid, ref router)) - { + if (!_query.Resolve(ref ent) || ent.Comp == null) return; - } - router.MonitorRoutes.Add(address); + ent.Comp.MonitorRoutes.Add(address); } - private void RemoveMonitorFromRoute(EntityUid uid, string address, SurveillanceCameraRouterComponent? router = null) + private void RemoveMonitorFromRoute(Entity ent, string address) { - if (!Resolve(uid, ref router)) - { + if (!_query.Resolve(ref ent) || ent.Comp == null) return; - } - router.MonitorRoutes.Remove(address); + ent.Comp.MonitorRoutes.Remove(address); } // Pings a subnet to get all camera information. - private void PingSubnet(EntityUid uid, SurveillanceCameraRouterComponent? router = null) + private void PingSubnet(Entity ent) { - if (!Resolve(uid, ref router)) - { + if (!_query.Resolve(ref ent) || ent.Comp == null) return; - } - var payload = new NetworkPayload() + var payload = new SurveillanceCameraPingPayload { - { DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraPingMessage }, - { SurveillanceCameraSystem.CameraSubnetData, router.SubnetFrequencyId } + Subnet = ent.Comp.SubnetName, }; - - _deviceNetworkSystem.QueuePacket(uid, null, payload, router.SubnetFrequency); - } - - // Sends camera information to all monitors currently interested. - private void SendCameraInfo(EntityUid uid, NetworkPayload payload, SurveillanceCameraRouterComponent? router = null) - { - if (!Resolve(uid, ref router)) - { - return; - } - - foreach (var address in router.MonitorRoutes) - { - _deviceNetworkSystem.QueuePacket(uid, address, payload); - } + _deviceNetworkSystem.SendPacket(ent.Owner, null, ref payload, ent.Comp.SubnetFrequency); } } diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.Collide.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.Collide.cs index b171bdab75..c7d8ce699e 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.Collide.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.Collide.cs @@ -6,7 +6,7 @@ using Robust.Shared.Physics.Systems; namespace Content.Server.SurveillanceCamera; -public partial class SurveillanceCameraSystem +public sealed partial class SurveillanceCameraSystem { [Dependency] private SharedPhysicsSystem _physics = default!; [Dependency] private SharedPowerReceiverSystem _power = default!; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs index f6118f8c4b..2b1dd89d5e 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs @@ -1,15 +1,14 @@ using Content.Server.Administration.Logs; using Content.Server.DeviceNetwork.Systems; using Content.Shared.Database; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; +using Content.Shared.DeviceNetwork.Systems; using Content.Shared.Power; using Content.Shared.SurveillanceCamera; using Content.Shared.SurveillanceCamera.Components; using Robust.Server.GameObjects; using Robust.Shared.Player; -using Robust.Shared.Prototypes; namespace Content.Server.SurveillanceCamera; @@ -17,37 +16,13 @@ public sealed partial class SurveillanceCameraSystem : SharedSurveillanceCameraS { [Dependency] private ViewSubscriberSystem _viewSubscriberSystem = default!; [Dependency] private DeviceNetworkSystem _deviceNetworkSystem = default!; + [Dependency] private DeviceNetworkRouterSystem _deviceNetworkRouter = default!; [Dependency] private UserInterfaceSystem _userInterface = default!; [Dependency] private IAdminLogManager _adminLogger = default!; [Dependency] private SurveillanceCameraMapSystem _cameraMapSystem = default!; [Dependency] private SharedAppearanceSystem _appearance = default!; - // Pings a surveillance camera subnet. All cameras will always respond - // with a data message if they are on the same subnet. - public const string CameraPingSubnetMessage = "surveillance_camera_ping_subnet"; - - // Pings a surveillance camera. Useful to ensure that the camera is still on - // before connecting fully. - public const string CameraPingMessage = "surveillance_camera_ping"; - - // Camera heartbeat. Monitors ping this to ensure that a camera is still able to - // be contacted. If this doesn't get sent after some time, the monitor will - // automatically disconnect. - public const string CameraHeartbeatMessage = "surveillance_camera_heartbeat"; - - // Surveillance camera data. This generally should contain nothing - // except for the subnet that this camera is on - - // this is because of the fact that the PacketEvent already - // contains the sender UID, and that this will always be targeted - // towards the sender that pinged the camera. - public const string CameraDataMessage = "surveillance_camera_data"; - public const string CameraConnectMessage = "surveillance_camera_connect"; - public const string CameraSubnetConnectMessage = "surveillance_camera_subnet_connect"; - public const string CameraSubnetDisconnectMessage = "surveillance_camera_subnet_disconnect"; - - public const string CameraAddressData = "surveillance_camera_data_origin"; - public const string CameraNameData = "surveillance_camera_data_name"; - public const string CameraSubnetData = "surveillance_camera_data_subnet"; + [Dependency] private EntityQuery _routerQuery = default!; public const int CameraNameLimit = 32; @@ -57,74 +32,53 @@ public sealed partial class SurveillanceCameraSystem : SharedSurveillanceCameraS SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnPacketReceived); SubscribeLocalEvent(OnSetName); SubscribeLocalEvent(OnSetNetwork); InitializeCollide(); } - private void OnPacketReceived(EntityUid uid, SurveillanceCameraComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnConnectRequest(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!component.Active) - { + var payload = args.Data; + if (!ent.Comp.Active) return; - } - if (!TryComp(uid, out DeviceNetworkComponent? deviceNet)) - { + var responsePayload = new SurveillanceCameraConnectPayload(); + _deviceNetworkRouter.SendPacketRouted(ent.Owner, ref responsePayload, args.SenderAddress, payload.SenderAddress); + } + + [SubscribeLocalEvent] + private void OnHeartbeatRequest(Entity ent, ref DeviceNetworkPacketEvent args) + { + var payload = args.Data; + if (!ent.Comp.Active) return; - } - if (args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command)) + var responsePayload = new SurveillanceCameraHeartbeatPayload(); + _deviceNetworkRouter.SendPacketRouted(ent.Owner, ref responsePayload, args.SenderAddress, payload.SenderAddress); + } + + [SubscribeLocalEvent] + private void OnPing(Entity ent, ref DeviceNetworkPacketEvent args) + { + var payload = args.Data; + if (!ent.Comp.Active) + return; + + if (!_routerQuery.TryComp(args.Sender, out var routerComp)) + return; + + if (routerComp.SubnetName != payload.Subnet) + return; + + var name = ent.Comp.UseEntityNameAsCameraId ? MetaData(ent).EntityName : ent.Comp.CameraId; + var responsePayload = new SurveillanceCameraDataPayload { - var payload = new NetworkPayload() - { - { DeviceNetworkConstants.Command, string.Empty }, - { CameraAddressData, deviceNet.Address }, - { CameraNameData, component.UseEntityNameAsCameraId ? MetaData(uid).EntityName : component.CameraId }, - { CameraSubnetData, null } - }; - - var dest = string.Empty; - - switch (command) - { - case CameraConnectMessage: - if (!args.Data.TryGetValue(CameraAddressData, out dest) - || string.IsNullOrEmpty(args.Address)) - { - return; - } - - payload[DeviceNetworkConstants.Command] = CameraConnectMessage; - break; - case CameraHeartbeatMessage: - if (!args.Data.TryGetValue(CameraAddressData, out dest) - || string.IsNullOrEmpty(args.Address)) - { - return; - } - - payload[DeviceNetworkConstants.Command] = CameraHeartbeatMessage; - break; - case CameraPingMessage: - if (!args.Data.TryGetValue(CameraSubnetData, out ProtoId? subnet)) - { - return; - } - - dest = args.SenderAddress; - payload[CameraSubnetData] = subnet; - payload[DeviceNetworkConstants.Command] = CameraDataMessage; - break; - } - - _deviceNetworkSystem.QueuePacket( - uid, - dest, - payload); - } + Name = name, + }; + _deviceNetworkRouter.SendPacketRouted(ent.Owner, ref responsePayload, args.SenderAddress, payload.SenderAddress); } private void OnPowerChanged(EntityUid camera, SurveillanceCameraComponent component, ref PowerChangedEvent args) @@ -154,9 +108,9 @@ public sealed partial class SurveillanceCameraSystem : SharedSurveillanceCameraS _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(args.Actor)} set the name of {ToPrettyString(uid)} to \"{args.Name}.\""); } - private void OnSetNetwork(EntityUid uid, SurveillanceCameraComponent component, - SurveillanceCameraSetupSetNetwork args) + private void OnSetNetwork(Entity ent, ref SurveillanceCameraSetupSetNetwork args) { + var (uid, component) = ent; if (args.UiKey is not SurveillanceCameraSetupUiKey key || key != SurveillanceCameraSetupUiKey.Camera) { @@ -167,8 +121,7 @@ public sealed partial class SurveillanceCameraSystem : SharedSurveillanceCameraS return; } - if (!ProtoMan.Resolve(component.AvailableNetworks[args.Network], - out var frequency)) + if (!ProtoMan.Resolve(component.AvailableNetworks[args.Network], out var frequency)) { return; } @@ -217,8 +170,11 @@ public sealed partial class SurveillanceCameraSystem : SharedSurveillanceCameraS } var name = camera.UseEntityNameAsCameraId ? MetaData(uid).EntityName : camera.CameraId; - var state = new SurveillanceCameraSetupBoundUiState(name, deviceNet.ReceiveFrequency ?? 0, - camera.AvailableNetworks, camera.NameSet, camera.NetworkSet); + var state = new SurveillanceCameraSetupBoundUiState(name, + deviceNet.ReceiveFrequency ?? 0, + camera.AvailableNetworks, + camera.NameSet, + camera.NetworkSet); _userInterface.SetUiState(uid, SurveillanceCameraSetupUiKey.Camera, state); } diff --git a/Content.Server/TurretController/DeployableTurretControllerSystem.cs b/Content.Server/TurretController/DeployableTurretControllerSystem.cs index c953baa7da..89f7545147 100644 --- a/Content.Server/TurretController/DeployableTurretControllerSystem.cs +++ b/Content.Server/TurretController/DeployableTurretControllerSystem.cs @@ -1,6 +1,5 @@ using Content.Server.DeviceNetwork.Systems; using Content.Shared.Access; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared.DeviceNetwork.Systems; @@ -19,26 +18,25 @@ public sealed partial class DeployableTurretControllerSystem : SharedDeployableT { [Dependency] private UserInterfaceSystem _userInterfaceSystem = default!; [Dependency] private DeviceNetworkSystem _deviceNetwork = default!; + [Dependency] private DeviceListSystem _deviceList = default!; [Dependency] private IAdminLogManager _adminLogger = default!; - /// Keys for the device network. See for further examples. - public const string CmdSetArmamemtState = "set_armament_state"; - public const string CmdSetAccessExemptions = "set_access_exemption"; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnBUIOpened); - SubscribeLocalEvent(OnDeviceListUpdate); - SubscribeLocalEvent(OnPacketReceived); - } - + [SubscribeLocalEvent] private void OnBUIOpened(Entity ent, ref BoundUIOpenedEvent args) { + if (!TryComp(ent, out var deviceNetwork)) + return; + + var payload = new TurretControllerRequestPayload(); + foreach (var (address, _) in _deviceList.GetDeviceList(ent.Owner)) + { + _deviceNetwork.SendPacket((ent.Owner, deviceNetwork), address, ref payload); + } + UpdateUIState(ent); } + [SubscribeLocalEvent] private void OnDeviceListUpdate(Entity ent, ref DeviceListUpdateEvent args) { if (!TryComp(ent, out var deviceNetwork)) @@ -48,10 +46,7 @@ public sealed partial class DeployableTurretControllerSystem : SharedDeployableT var turretsToAdd = args.Devices.Except(args.OldDevices); // Request data from newly linked devices - var payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdUpdatedState, - }; + var payload = new TurretControllerRequestPayload(); foreach (var turretUid in turretsToAdd) { @@ -61,7 +56,7 @@ public sealed partial class DeployableTurretControllerSystem : SharedDeployableT if (!TryComp(turretUid, out var turretDeviceNetwork)) continue; - _deviceNetwork.QueuePacket(ent, turretDeviceNetwork.Address, payload, device: deviceNetwork); + _deviceNetwork.SendPacket((ent.Owner, deviceNetwork), turretDeviceNetwork.Address, ref payload); } // Remove newly unlinked devices @@ -81,21 +76,16 @@ public sealed partial class DeployableTurretControllerSystem : SharedDeployableT UpdateUIState(ent); } - private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command)) - return; - if (!TryComp(ent, out var deviceNetwork) || deviceNetwork.ReceiveFrequency != args.Frequency) return; // If an update was received from a turret, connect to it and update the UI - if (command == DeviceNetworkConstants.CmdUpdatedState && - args.Data.TryGetValue(command, out DeployableTurretState updatedState)) - { - ent.Comp.LinkedTurrets[args.SenderAddress] = updatedState; - UpdateUIState(ent); - } + + ent.Comp.LinkedTurrets[args.SenderAddress] = args.Data.State; + UpdateUIState(ent); } protected override void ChangeArmamentSetting(Entity ent, int armamentState, EntityUid? user = null) @@ -106,15 +96,14 @@ public sealed partial class DeployableTurretControllerSystem : SharedDeployableT return; // Update linked turrets' armament statuses - var payload = new NetworkPayload + var payload = new TurretControllerSetArmamentPayload { - [DeviceNetworkConstants.Command] = CmdSetArmamemtState, - [CmdSetArmamemtState] = armamentState, + ArmamentState = armamentState, }; _adminLogger.Add(LogType.ItemConfigure, LogImpact.Medium, $"{ToPrettyString(user)} set {ToPrettyString(ent)} to {armamentState}"); - _deviceNetwork.QueuePacket(ent, null, payload, device: device); + _deviceNetwork.SendPacket((ent.Owner, device), null, ref payload); } protected override void ChangeExemptAccessLevels( @@ -131,10 +120,9 @@ public sealed partial class DeployableTurretControllerSystem : SharedDeployableT return; // Update linked turrets' target selection exemptions - var payload = new NetworkPayload + var payload = new TurretControllerSetAccessPayload { - [DeviceNetworkConstants.Command] = CmdSetAccessExemptions, - [CmdSetAccessExemptions] = turretTargetingSettings.ExemptAccessLevels, + AccessExemptions = turretTargetingSettings.ExemptAccessLevels, }; foreach (var exemption in exemptions) @@ -142,7 +130,7 @@ public sealed partial class DeployableTurretControllerSystem : SharedDeployableT _adminLogger.Add(LogType.ItemConfigure, LogImpact.Medium, $"{ToPrettyString(user)} set {ToPrettyString(ent)} authorization of {exemption} to {enabled}"); } - _deviceNetwork.QueuePacket(ent, null, payload, device: device); + _deviceNetwork.SendPacket((ent.Owner, device), null, ref payload); } private void UpdateUIState(Entity ent) diff --git a/Content.Server/Turrets/DeployableTurretSystem.cs b/Content.Server/Turrets/DeployableTurretSystem.cs index d0c5c1accc..f57dcca658 100644 --- a/Content.Server/Turrets/DeployableTurretSystem.cs +++ b/Content.Server/Turrets/DeployableTurretSystem.cs @@ -2,22 +2,19 @@ using Content.Server.Destructible; using Content.Server.DeviceNetwork.Systems; using Content.Server.NPC.HTN; using Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat.Ranged; -using Content.Server.Power.Components; -using Content.Server.TurretController; -using Content.Shared.Access; using Content.Shared.Destructible; using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; using Content.Shared.Repairable; +using Content.Shared.TurretController; using Content.Shared.Turrets; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Weapons.Ranged.Systems; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; -using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Server.Turrets; @@ -32,6 +29,8 @@ public sealed partial class DeployableTurretSystem : SharedDeployableTurretSyste [Dependency] private TurretTargetSettingsSystem _turretTargetingSettings = default!; [Dependency] private IGameTiming _timing = default!; + [Dependency] private EntityQuery _deviceQuery = default!; + public override void Initialize() { base.Initialize(); @@ -41,7 +40,6 @@ public sealed partial class DeployableTurretSystem : SharedDeployableTurretSyste SubscribeLocalEvent(OnPowerChanged); SubscribeLocalEvent(OnBroken); SubscribeLocalEvent(OnRepaired); - SubscribeLocalEvent(OnPacketReceived); SubscribeLocalEvent(OnBeforeBroadcast); } @@ -74,37 +72,28 @@ public sealed partial class DeployableTurretSystem : SharedDeployableTurretSyste _appearance.SetData(ent, DeployableTurretVisuals.Broken, false, appearance); } - private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnSetArmament(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command)) + if (TryComp(ent, out var batteryWeaponFireModes)) + _fireModes.TrySetFireMode((ent.Owner, batteryWeaponFireModes), args.Data.ArmamentState); + + TrySetState(ent, args.Data.ArmamentState >= 0); + } + + [SubscribeLocalEvent] + private void OnSetAccess(Entity ent, ref DeviceNetworkPacketEvent args) + { + if (!TryComp(ent, out var targetSettings)) return; - // Received a command to change armament state - if (command == DeployableTurretControllerSystem.CmdSetArmamemtState && - args.Data.TryGetValue(command, out int? armamentState)) - { - if (TryComp(ent, out var batteryWeaponFireModes)) - _fireModes.TrySetFireMode((ent, batteryWeaponFireModes), armamentState.Value); + _turretTargetingSettings.SyncAccessLevelExemptions((ent, targetSettings), args.Data.AccessExemptions); + } - TrySetState(ent, armamentState.Value >= 0); - return; - } - - // Received a command to change access exemptions - if (command == DeployableTurretControllerSystem.CmdSetAccessExemptions && - args.Data.TryGetValue(command, out HashSet>? accessExemptions) && - TryComp(ent, out var turretTargetSettings)) - { - _turretTargetingSettings.SyncAccessLevelExemptions((ent, turretTargetSettings), accessExemptions); - return; - } - - // Received a command to update the device network - if (command == DeviceNetworkConstants.CmdUpdatedState) - { - SendStateUpdateToDeviceNetwork(ent); - return; - } + [SubscribeLocalEvent] + private void OnRequest(Entity ent, ref DeviceNetworkPacketEvent args) + { + SendStateUpdateToDeviceNetwork(ent); } private void OnBeforeBroadcast(Entity ent, ref BeforeBroadcastAttemptEvent args) @@ -112,15 +101,15 @@ public sealed partial class DeployableTurretSystem : SharedDeployableTurretSyste if (!TryComp(ent, out var deviceNetwork)) return; - var recipientDeviceNetworks = new HashSet(); + var recipientDeviceNetworks = new HashSet(); // Only broadcast to connected devices foreach (var recipient in deviceNetwork.DeviceLists) { - if (!TryComp(recipient, out var recipientDeviceNetwork)) + if (!_deviceQuery.TryComp(recipient, out var recipientDeviceNetwork)) continue; - recipientDeviceNetworks.Add(recipientDeviceNetwork); + recipientDeviceNetworks.Add(new Device((recipient, recipientDeviceNetwork))); } if (recipientDeviceNetworks.Count > 0) @@ -132,13 +121,11 @@ public sealed partial class DeployableTurretSystem : SharedDeployableTurretSyste if (!TryComp(ent, out var device)) return; - var payload = new NetworkPayload + var payload = new TurretStatePayload { - [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdUpdatedState, - [DeviceNetworkConstants.CmdUpdatedState] = GetTurretState(ent) + State = GetTurretState(ent), }; - - _deviceNetwork.QueuePacket(ent, null, payload, device: device); + _deviceNetwork.SendPacket((ent.Owner, device), null, ref payload); } protected override void SetState(Entity ent, bool enabled, EntityUid? user = null) diff --git a/Content.Shared/Atmos/Monitor/AtmosSensorData.cs b/Content.Shared/Atmos/Monitor/AtmosSensorData.cs index 041c386b5f..1a2b291243 100644 --- a/Content.Shared/Atmos/Monitor/AtmosSensorData.cs +++ b/Content.Shared/Atmos/Monitor/AtmosSensorData.cs @@ -1,12 +1,28 @@ -using Content.Shared.Atmos.Monitor.Components; +using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Systems; using Robust.Shared.Serialization; namespace Content.Shared.Atmos.Monitor; -[Serializable, NetSerializable] -public sealed class AtmosSensorData : IAtmosDeviceData +/// +/// Contains . +/// +public partial record struct AtmosMonitorDataPayload : INetworkPayload { - public AtmosSensorData(float pressure, float temperature, float totalMoles, AtmosAlarmType alarmState, Dictionary gases, AtmosAlarmThreshold pressureThreshold, AtmosAlarmThreshold temperatureThreshold, Dictionary gasThresholds) + [DataField] + public AtmosMonitorData Data; +} + +[Serializable, NetSerializable] +public sealed partial class AtmosMonitorData : BaseAtmosDeviceData +{ + public override void RaisePayload(EntityUid uid, string address, SharedDeviceNetworkSystem deviceNetSys) + { + var payload = new AtmosMonitorDataPayload { Data = this }; + deviceNetSys.SendPacket(uid, address, ref payload); + } + + public AtmosMonitorData(float pressure, float temperature, float totalMoles, AtmosAlarmType alarmState, Dictionary gases, AtmosAlarmThreshold pressureThreshold, AtmosAlarmThreshold temperatureThreshold, Dictionary gasThresholds) { Pressure = pressure; Temperature = temperature; @@ -18,10 +34,6 @@ public sealed class AtmosSensorData : IAtmosDeviceData GasThresholds = gasThresholds; } - public bool Enabled { get; set; } - public bool Dirty { get; set; } - public bool IgnoreAlarms { get; set; } - /// Most fields are readonly, because it's data that's meant to be transmitted. /// diff --git a/Content.Shared/Atmos/Monitor/BaseAtmosDeviceData.cs b/Content.Shared/Atmos/Monitor/BaseAtmosDeviceData.cs new file mode 100644 index 0000000000..2b5ef56b86 --- /dev/null +++ b/Content.Shared/Atmos/Monitor/BaseAtmosDeviceData.cs @@ -0,0 +1,19 @@ +using Content.Shared.DeviceNetwork.Systems; +using Robust.Shared.Serialization; + +namespace Content.Shared.Atmos.Monitor; + +[Serializable, NetSerializable] +public abstract partial class BaseAtmosDeviceData : IAtmosDeviceData +{ + [DataField] + public bool Enabled { get; set; } + + [DataField] + public bool Dirty { get; set; } + + [DataField] + public bool IgnoreAlarms { get; set; } + + public abstract void RaisePayload(EntityUid uid, string address, SharedDeviceNetworkSystem deviceNetSys); +} diff --git a/Content.Shared/Atmos/Monitor/Components/SharedAirAlarmComponent.cs b/Content.Shared/Atmos/Monitor/Components/SharedAirAlarmComponent.cs index 3d67d18a0a..1b4675f711 100644 --- a/Content.Shared/Atmos/Monitor/Components/SharedAirAlarmComponent.cs +++ b/Content.Shared/Atmos/Monitor/Components/SharedAirAlarmComponent.cs @@ -27,13 +27,6 @@ public enum AirAlarmWireStatus DeviceSync } -public interface IAtmosDeviceData -{ - public bool Enabled { get; set; } - public bool Dirty { get; set; } - public bool IgnoreAlarms { get; set; } -} - [Serializable, NetSerializable] public sealed class AirAlarmUIState : BoundUserInterfaceState { @@ -69,8 +62,7 @@ public sealed class AirAlarmUIState : BoundUserInterfaceState } [Serializable, NetSerializable] -public sealed class AirAlarmResyncAllDevicesMessage : BoundUserInterfaceMessage -{} +public sealed class AirAlarmResyncAllDevicesMessage : BoundUserInterfaceMessage; [Serializable, NetSerializable] public sealed class AirAlarmUpdateAlarmModeMessage : BoundUserInterfaceMessage diff --git a/Content.Shared/Atmos/Monitor/IAtmosDeviceData.cs b/Content.Shared/Atmos/Monitor/IAtmosDeviceData.cs new file mode 100644 index 0000000000..d62288a736 --- /dev/null +++ b/Content.Shared/Atmos/Monitor/IAtmosDeviceData.cs @@ -0,0 +1,21 @@ +using Content.Shared.DeviceNetwork.Systems; + +namespace Content.Shared.Atmos.Monitor; + +[ImplicitDataDefinitionForInheritors] +public partial interface IAtmosDeviceData +{ + bool Enabled { get; set; } + + bool Dirty { get; set; } + + bool IgnoreAlarms { get; set; } + + /// + /// Creates a payload that contains this atmos device data and send it to the specified address. + /// + /// Owner of this atmos data. + /// The target address. + /// The device network system. + void RaisePayload(EntityUid uid, string address, SharedDeviceNetworkSystem deviceNetSys); +} diff --git a/Content.Shared/Atmos/Piping/Binary/Components/SharedGasVolumePumpComponent.cs b/Content.Shared/Atmos/Piping/Binary/Components/SharedGasVolumePumpComponent.cs index f3b6bb8caf..f34d22d9ad 100644 --- a/Content.Shared/Atmos/Piping/Binary/Components/SharedGasVolumePumpComponent.cs +++ b/Content.Shared/Atmos/Piping/Binary/Components/SharedGasVolumePumpComponent.cs @@ -1,34 +1,41 @@ -using Robust.Shared.Serialization; +using Content.Shared.DeviceNetwork; +using Robust.Shared.Serialization; -namespace Content.Shared.Atmos.Piping.Binary.Components +namespace Content.Shared.Atmos.Piping.Binary.Components; + +/// +/// Contains data about a . +/// +public partial record struct GasVolumePumpDataPayload : INetworkPayload { - public sealed record GasVolumePumpData(float LastMolesTransferred); + [DataField] + public float LastMolesTransferred; +} - [Serializable, NetSerializable] - public enum GasVolumePumpUiKey : byte +[Serializable, NetSerializable] +public enum GasVolumePumpUiKey : byte +{ + Key, +} + +[Serializable, NetSerializable] +public sealed class GasVolumePumpToggleStatusMessage : BoundUserInterfaceMessage +{ + public bool Enabled { get; } + + public GasVolumePumpToggleStatusMessage(bool enabled) { - Key, - } - - [Serializable, NetSerializable] - public sealed class GasVolumePumpToggleStatusMessage : BoundUserInterfaceMessage - { - public bool Enabled { get; } - - public GasVolumePumpToggleStatusMessage(bool enabled) - { - Enabled = enabled; - } - } - - [Serializable, NetSerializable] - public sealed class GasVolumePumpChangeTransferRateMessage : BoundUserInterfaceMessage - { - public float TransferRate { get; } - - public GasVolumePumpChangeTransferRateMessage(float transferRate) - { - TransferRate = transferRate; - } + Enabled = enabled; + } +} + +[Serializable, NetSerializable] +public sealed class GasVolumePumpChangeTransferRateMessage : BoundUserInterfaceMessage +{ + public float TransferRate { get; } + + public GasVolumePumpChangeTransferRateMessage(float transferRate) + { + TransferRate = transferRate; } } diff --git a/Content.Shared/Atmos/Piping/Unary/Components/SharedGasThermomachineComponent.cs b/Content.Shared/Atmos/Piping/Unary/Components/SharedGasThermomachineComponent.cs index 5d2beb9de5..9b4caa953d 100644 --- a/Content.Shared/Atmos/Piping/Unary/Components/SharedGasThermomachineComponent.cs +++ b/Content.Shared/Atmos/Piping/Unary/Components/SharedGasThermomachineComponent.cs @@ -1,9 +1,16 @@ -using Robust.Shared.Serialization; +using Content.Shared.DeviceNetwork; +using Robust.Shared.Serialization; namespace Content.Shared.Atmos.Piping.Unary.Components; -[Serializable, NetSerializable] -public sealed record GasThermoMachineData(float EnergyDelta); +/// +/// Contains data about . +/// +public partial record struct GasThermoMachineDataPayload : INetworkPayload +{ + [DataField] + public float EnergyDelta; +} [Serializable] [NetSerializable] diff --git a/Content.Shared/Atmos/Piping/Unary/Components/SharedVentPumpComponent.cs b/Content.Shared/Atmos/Piping/Unary/Components/SharedVentPumpComponent.cs index 15fece204d..1a06faba39 100644 --- a/Content.Shared/Atmos/Piping/Unary/Components/SharedVentPumpComponent.cs +++ b/Content.Shared/Atmos/Piping/Unary/Components/SharedVentPumpComponent.cs @@ -1,81 +1,94 @@ -using Content.Shared.Atmos.Monitor.Components; +using Content.Shared.Atmos.Monitor; +using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Systems; using Robust.Shared.Serialization; -namespace Content.Shared.Atmos.Piping.Unary.Components +namespace Content.Shared.Atmos.Piping.Unary.Components; + +[Serializable, NetSerializable] +public sealed partial class GasVentPumpData : BaseAtmosDeviceData { - [Serializable, NetSerializable] - public sealed class GasVentPumpData : IAtmosDeviceData + public override void RaisePayload(EntityUid uid, string address, SharedDeviceNetworkSystem deviceNetSys) { - public bool Enabled { get; set; } - public bool Dirty { get; set; } - public bool IgnoreAlarms { get; set; } = false; - public VentPumpDirection PumpDirection { get; set; } = VentPumpDirection.Releasing; - public VentPressureBound PressureChecks { get; set; } = VentPressureBound.ExternalBound; - public float ExternalPressureBound { get; set; } = Atmospherics.OneAtmosphere; - public float InternalPressureBound { get; set; } = 0f; - public bool PressureLockoutOverride { get; set; } = false; - - // Presets for 'dumb' air alarm modes - - public static GasVentPumpData FilterModePreset = new GasVentPumpData - { - Enabled = true, - PumpDirection = VentPumpDirection.Releasing, - PressureChecks = VentPressureBound.ExternalBound, - ExternalPressureBound = Atmospherics.OneAtmosphere, - InternalPressureBound = 0f, - PressureLockoutOverride = false - }; - - public static GasVentPumpData FillModePreset = new GasVentPumpData - { - Enabled = true, - Dirty = true, - PumpDirection = VentPumpDirection.Releasing, - PressureChecks = VentPressureBound.ExternalBound, - ExternalPressureBound = Atmospherics.OneAtmosphere * 50, - InternalPressureBound = 0f, - PressureLockoutOverride = true - }; - - public static GasVentPumpData PanicModePreset = new GasVentPumpData - { - Enabled = false, - Dirty = true, - PumpDirection = VentPumpDirection.Releasing, - PressureChecks = VentPressureBound.ExternalBound, - ExternalPressureBound = Atmospherics.OneAtmosphere, - InternalPressureBound = 0f, - PressureLockoutOverride = false - }; - - public static GasVentPumpData ReplaceModePreset = new GasVentPumpData - { - Enabled = false, - IgnoreAlarms = true, - Dirty = true, - PumpDirection = VentPumpDirection.Releasing, - PressureChecks = VentPressureBound.ExternalBound, - ExternalPressureBound = Atmospherics.OneAtmosphere, - InternalPressureBound = 0f, - PressureLockoutOverride = false - }; + var payload = new GasVentPumpSetDataPayload { Data = this }; + deviceNetSys.SendPacket(uid, address, ref payload); } - [Serializable, NetSerializable] - public enum VentPumpDirection : sbyte - { - Siphoning = 0, - Releasing = 1, - } + public VentPumpDirection PumpDirection { get; set; } = VentPumpDirection.Releasing; + public VentPressureBound PressureChecks { get; set; } = VentPressureBound.ExternalBound; + public float ExternalPressureBound { get; set; } = Atmospherics.OneAtmosphere; + public float InternalPressureBound { get; set; } = 0f; + public bool PressureLockoutOverride { get; set; } = false; - [Flags] - [Serializable, NetSerializable] - public enum VentPressureBound : sbyte + // Presets for 'dumb' air alarm modes + + public static GasVentPumpData FilterModePreset = new GasVentPumpData { - NoBound = 0, - InternalBound = 1, - ExternalBound = 2, - Both = 3, - } + Enabled = true, + PumpDirection = VentPumpDirection.Releasing, + PressureChecks = VentPressureBound.ExternalBound, + ExternalPressureBound = Atmospherics.OneAtmosphere, + InternalPressureBound = 0f, + PressureLockoutOverride = false + }; + + public static GasVentPumpData FillModePreset = new GasVentPumpData + { + Enabled = true, + Dirty = true, + PumpDirection = VentPumpDirection.Releasing, + PressureChecks = VentPressureBound.ExternalBound, + ExternalPressureBound = Atmospherics.OneAtmosphere * 50, + InternalPressureBound = 0f, + PressureLockoutOverride = true + }; + + public static GasVentPumpData PanicModePreset = new GasVentPumpData + { + Enabled = false, + Dirty = true, + PumpDirection = VentPumpDirection.Releasing, + PressureChecks = VentPressureBound.ExternalBound, + ExternalPressureBound = Atmospherics.OneAtmosphere, + InternalPressureBound = 0f, + PressureLockoutOverride = false + }; + + public static GasVentPumpData ReplaceModePreset = new GasVentPumpData + { + Enabled = false, + IgnoreAlarms = true, + Dirty = true, + PumpDirection = VentPumpDirection.Releasing, + PressureChecks = VentPressureBound.ExternalBound, + ExternalPressureBound = Atmospherics.OneAtmosphere, + InternalPressureBound = 0f, + PressureLockoutOverride = false + }; +} + +/// +/// Used to set . +/// +public partial record struct GasVentPumpSetDataPayload : INetworkPayload +{ + [DataField] + public GasVentPumpData Data; +} + +[Serializable, NetSerializable] +public enum VentPumpDirection : sbyte +{ + Siphoning = 0, + Releasing = 1, +} + +[Flags] +[Serializable, NetSerializable] +public enum VentPressureBound : sbyte +{ + NoBound = 0, + InternalBound = 1, + ExternalBound = 2, + Both = 3, } diff --git a/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs b/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs index 63d2e552a7..5f5ebe7dd9 100644 --- a/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs +++ b/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs @@ -1,87 +1,100 @@ -using Content.Shared.Atmos.Monitor.Components; +using Content.Shared.Atmos.Monitor; +using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Systems; using Robust.Shared.Serialization; -namespace Content.Shared.Atmos.Piping.Unary.Components +namespace Content.Shared.Atmos.Piping.Unary.Components; + +[Serializable, NetSerializable] +public sealed partial class GasVentScrubberData : BaseAtmosDeviceData { - [Serializable, NetSerializable] - public sealed class GasVentScrubberData : IAtmosDeviceData + public override void RaisePayload(EntityUid uid, string address, SharedDeviceNetworkSystem deviceNetSys) { - public bool Enabled { get; set; } - public bool Dirty { get; set; } - public bool IgnoreAlarms { get; set; } = false; - public HashSet FilterGases { get; set; } = new(DefaultFilterGases); - public ScrubberPumpDirection PumpDirection { get; set; } = ScrubberPumpDirection.Scrubbing; - public float VolumeRate { get; set; } = 200f; - public bool WideNet { get; set; } = false; - public bool AirAlarmPanicWireCut { get; set; } - - public static HashSet DefaultFilterGases = new() - { - Gas.CarbonDioxide, - Gas.Plasma, - Gas.Tritium, - Gas.WaterVapor, - Gas.Ammonia, - Gas.NitrousOxide, - Gas.Frezon - }; - - // Presets for 'dumb' air alarm modes - - public static GasVentScrubberData FilterModePreset = new GasVentScrubberData - { - Enabled = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), - PumpDirection = ScrubberPumpDirection.Scrubbing, - VolumeRate = 200f, - WideNet = false - }; - - public static GasVentScrubberData WideFilterModePreset = new GasVentScrubberData - { - Enabled = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), - PumpDirection = ScrubberPumpDirection.Scrubbing, - VolumeRate = 200f, - WideNet = true - }; - - public static GasVentScrubberData FillModePreset = new GasVentScrubberData - { - Enabled = false, - Dirty = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), - PumpDirection = ScrubberPumpDirection.Scrubbing, - VolumeRate = 200f, - WideNet = false - }; - - public static GasVentScrubberData PanicModePreset = new GasVentScrubberData - { - Enabled = true, - Dirty = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), - PumpDirection = ScrubberPumpDirection.Siphoning, - VolumeRate = 200f, - WideNet = true - }; - - public static GasVentScrubberData ReplaceModePreset = new GasVentScrubberData - { - Enabled = true, - IgnoreAlarms = true, - Dirty = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), - PumpDirection = ScrubberPumpDirection.Siphoning, - VolumeRate = 200f, - WideNet = false - }; + var payload = new GasVentScrubberSetDataPayload { Data = this }; + deviceNetSys.SendPacket(uid, address, ref payload); } - [Serializable, NetSerializable] - public enum ScrubberPumpDirection : sbyte + public HashSet FilterGases { get; set; } = new(DefaultFilterGases); + public ScrubberPumpDirection PumpDirection { get; set; } = ScrubberPumpDirection.Scrubbing; + public float VolumeRate { get; set; } = 200f; + public bool WideNet { get; set; } = false; + public bool AirAlarmPanicWireCut { get; set; } + + public static HashSet DefaultFilterGases = new() { - Siphoning = 0, - Scrubbing = 1, - } + Gas.CarbonDioxide, + Gas.Plasma, + Gas.Tritium, + Gas.WaterVapor, + Gas.Ammonia, + Gas.NitrousOxide, + Gas.Frezon + }; + + // Presets for 'dumb' air alarm modes + + public static GasVentScrubberData FilterModePreset = new GasVentScrubberData + { + Enabled = true, + FilterGases = new(GasVentScrubberData.DefaultFilterGases), + PumpDirection = ScrubberPumpDirection.Scrubbing, + VolumeRate = 200f, + WideNet = false + }; + + public static GasVentScrubberData WideFilterModePreset = new GasVentScrubberData + { + Enabled = true, + FilterGases = new(GasVentScrubberData.DefaultFilterGases), + PumpDirection = ScrubberPumpDirection.Scrubbing, + VolumeRate = 200f, + WideNet = true + }; + + public static GasVentScrubberData FillModePreset = new GasVentScrubberData + { + Enabled = false, + Dirty = true, + FilterGases = new(GasVentScrubberData.DefaultFilterGases), + PumpDirection = ScrubberPumpDirection.Scrubbing, + VolumeRate = 200f, + WideNet = false + }; + + public static GasVentScrubberData PanicModePreset = new GasVentScrubberData + { + Enabled = true, + Dirty = true, + FilterGases = new(GasVentScrubberData.DefaultFilterGases), + PumpDirection = ScrubberPumpDirection.Siphoning, + VolumeRate = 200f, + WideNet = true + }; + + public static GasVentScrubberData ReplaceModePreset = new GasVentScrubberData + { + Enabled = true, + IgnoreAlarms = true, + Dirty = true, + FilterGases = new(GasVentScrubberData.DefaultFilterGases), + PumpDirection = ScrubberPumpDirection.Siphoning, + VolumeRate = 200f, + WideNet = false + }; +} + +/// +/// Used to set . +/// +public partial record struct GasVentScrubberSetDataPayload : INetworkPayload +{ + [DataField] + public GasVentScrubberData Data; +} + +[Serializable, NetSerializable] +public enum ScrubberPumpDirection : sbyte +{ + Siphoning = 0, + Scrubbing = 1, } diff --git a/Content.Shared/CartridgeLoader/CartridgeLoaderSystem.Relay.cs b/Content.Shared/CartridgeLoader/CartridgeLoaderSystem.Relay.cs index db4e952a48..985093b792 100644 --- a/Content.Shared/CartridgeLoader/CartridgeLoaderSystem.Relay.cs +++ b/Content.Shared/CartridgeLoader/CartridgeLoaderSystem.Relay.cs @@ -1,4 +1,3 @@ -using Content.Shared.DeviceNetwork.Events; using Content.Shared.Interaction; namespace Content.Shared.CartridgeLoader; @@ -9,7 +8,6 @@ public sealed partial class CartridgeLoaderSystem { SubscribeLocalEvent(RelayEvent); SubscribeLocalEvent(RelayEvent); - SubscribeLocalEvent(RelayEvent); } private void RefRelayEvent(EntityUid uid, CartridgeLoaderComponent component, ref T args) where T : struct diff --git a/Content.Shared/CartridgeLoader/Cartridges/NetProbeCartridgeSystem.cs b/Content.Shared/CartridgeLoader/Cartridges/NetProbeCartridgeSystem.cs index 4d339134be..81e0bf0866 100644 --- a/Content.Shared/CartridgeLoader/Cartridges/NetProbeCartridgeSystem.cs +++ b/Content.Shared/CartridgeLoader/Cartridges/NetProbeCartridgeSystem.cs @@ -56,8 +56,8 @@ public sealed partial class NetProbeCartridgeSystem : EntitySystem var device = new ProbedNetworkDevice( Name(target), networkComponent.Address, - networkComponent.ReceiveFrequency?.FrequencyToString() ?? string.Empty, - networkComponent.DeviceNetId.DeviceNetIdToLocalizedName() + DeviceLocalizationHelpers.FrequencyToString(networkComponent.ReceiveFrequency), + DeviceLocalizationHelpers.DeviceNetIdToLocalizedName(networkComponent.DeviceNetId, Loc) ); component.ProbedDevices.Add(device); diff --git a/Content.Shared/DeviceLinking/Events/SignalReceivedEvent.cs b/Content.Shared/DeviceLinking/Events/SignalReceivedEvent.cs index 335a95cecc..534714f176 100644 --- a/Content.Shared/DeviceLinking/Events/SignalReceivedEvent.cs +++ b/Content.Shared/DeviceLinking/Events/SignalReceivedEvent.cs @@ -1,6 +1,7 @@ -using Content.Shared.DeviceNetwork; - namespace Content.Shared.DeviceLinking.Events; [ByRefEvent] -public readonly record struct SignalReceivedEvent(string Port, EntityUid? Trigger = null, NetworkPayload? Data = null); +public readonly record struct SignalReceivedEvent(string Port, EntityUid? Trigger = null); + +[ByRefEvent] +public readonly record struct SignalReceivedEvent(string Port, T Data, EntityUid? Trigger = null) where T : ISignalNetworkPayload; diff --git a/Content.Shared/DeviceLinking/LogicStatePayload.cs b/Content.Shared/DeviceLinking/LogicStatePayload.cs new file mode 100644 index 0000000000..5266b0f840 --- /dev/null +++ b/Content.Shared/DeviceLinking/LogicStatePayload.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.DeviceLinking; + +/// +/// Contains a logic state of a . +/// +public partial record struct LogicStatePayload : ISignalNetworkPayload +{ + [DataField] + public SignalState State; +} diff --git a/Content.Shared/DeviceLinking/SharedDeviceLinkSystem.cs b/Content.Shared/DeviceLinking/SharedDeviceLinkSystem.cs index a19f001fcb..d3beb43ef2 100644 --- a/Content.Shared/DeviceLinking/SharedDeviceLinkSystem.cs +++ b/Content.Shared/DeviceLinking/SharedDeviceLinkSystem.cs @@ -17,13 +17,13 @@ public abstract partial class SharedDeviceLinkSystem : EntitySystem [Dependency] private SharedTransformSystem _transform = default!; [Dependency] private IGameTiming _gameTiming = default!; - [Dependency] private EntityQuery _deviceLinkSinkQuery = default!; - - public const string InvokedPort = "link_port"; + [Dependency] protected EntityQuery DeviceLinkSinkQuery = default!; + [Dependency] protected EntityQuery DeviceLinkSourceQuery = default!; /// public override void Initialize() { + base.Initialize(); SubscribeLocalEvent(OnSourceStartup); SubscribeLocalEvent(OnSourceRemoved); SubscribeLocalEvent(OnSinkRemoved); @@ -85,7 +85,7 @@ public abstract partial class SharedDeviceLinkSystem : EntitySystem { foreach (var sinkUid in source.Comp.LinkedPorts.Keys) { - if (_deviceLinkSinkQuery.TryGetComponent(sinkUid, out var sink)) + if (DeviceLinkSinkQuery.TryGetComponent(sinkUid, out var sink)) RemoveSinkFromSourceInternal(source, sinkUid, source, sink); else Log.Error($"Device source {ToPrettyString(source)} links to invalid entity: {ToPrettyString(sinkUid)}"); @@ -539,12 +539,21 @@ public abstract partial class SharedDeviceLinkSystem : EntitySystem /// Sends a network payload directed at the sink entity. /// Just raises a without data if the source or the sink doesn't have a /// - /// The source uid that invokes the port + /// The source uid that invokes the port + /// The port to invoke + public virtual void InvokePort(Entity ent, string port) + { + // NOOP on client for the moment. + } + + /// + /// Sends a network payload directed at the sink entity. + /// Just raises a without data if the source or the sink doesn't have a + /// + /// The source entity that invokes the port /// The port to invoke /// Optional data to send along - /// - public virtual void InvokePort(EntityUid uid, string port, NetworkPayload? data = null, - DeviceLinkSourceComponent? sourceComponent = null) + public virtual void InvokePort(Entity ent, string port, ref T data) where T : ISignalNetworkPayload { // NOOP on client for the moment. } diff --git a/Content.Shared/DeviceLinking/SignalPayload.cs b/Content.Shared/DeviceLinking/SignalPayload.cs new file mode 100644 index 0000000000..bcd5f679b5 --- /dev/null +++ b/Content.Shared/DeviceLinking/SignalPayload.cs @@ -0,0 +1,41 @@ +using Content.Shared.DeviceLinking.Events; +using Content.Shared.DeviceNetwork; + +namespace Content.Shared.DeviceLinking; + +/// +/// A network payload that can be nested inside . +/// +public partial interface ISignalNetworkPayload : INetworkPayload; + +/// +/// A network payload that raises when successfully delivered. +/// Optionally contains a to provide additional data for the event. +/// +public partial record struct SignalPayload : INetworkPayload +{ + /// + /// A signal port that was invoked. + /// + [DataField] + public string InvokedPort; +} + +/// +/// A network payload that raises when successfully delivered. +/// Optionally contains a to provide additional data for the event. +/// +public partial record struct SignalPayload : INetworkPayload where T : ISignalNetworkPayload +{ + /// + /// A signal port that was invoked. + /// + [DataField] + public string InvokedPort; + + /// + /// Optional additional data about the signal. + /// + [DataField] + public T Payload; +} diff --git a/Content.Shared/DeviceNetwork/Components/DeviceNetworkComponent.cs b/Content.Shared/DeviceNetwork/Components/DeviceNetworkComponent.cs index 42c897d3b1..13abc3ebaa 100644 --- a/Content.Shared/DeviceNetwork/Components/DeviceNetworkComponent.cs +++ b/Content.Shared/DeviceNetwork/Components/DeviceNetworkComponent.cs @@ -1,120 +1,107 @@ using Content.Shared.DeviceNetwork.Systems; +using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -namespace Content.Shared.DeviceNetwork.Components +namespace Content.Shared.DeviceNetwork.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedDeviceNetworkSystem), typeof(DeviceNet))] +public sealed partial class DeviceNetworkComponent : Component { - [RegisterComponent] - [Access(typeof(SharedDeviceNetworkSystem), typeof(DeviceNet))] - public sealed partial class DeviceNetworkComponent : Component - { - public enum DeviceNetIdDefaults - { - Private, - Wired, - Wireless, - Apc, - AtmosDevices, - Reserved = 100, - // Ids outside this enum may exist - // This exists to let yml use nice names instead of numbers - } + /// + /// Default device network ID to connect to. + /// + [DataField("deviceNetId")] + public DeviceNetIdDefaults NetIdEnum { get; set; } - [DataField("deviceNetId")] - public DeviceNetIdDefaults NetIdEnum { get; set; } + public int DeviceNetId => (int) NetIdEnum; - public int DeviceNetId => (int) NetIdEnum; + /// + /// The frequency that this device is listening on. + /// + [DataField] + public uint? ReceiveFrequency; - /// - /// The frequency that this device is listening on. - /// - [DataField] - public uint? ReceiveFrequency; + /// + /// The address ID of the device, either on the network it is currently connected to or whatever address it + /// most recently used. + /// + [DataField] + public string Address = string.Empty; - /// - /// frequency prototype. Used to select a default frequency to listen to on. Used when the map is - /// initialized. - /// - [DataField] - public ProtoId? ReceiveFrequencyId; + /// + /// Whether the device should listen for all device messages, regardless of the intended recipient. + /// + [DataField] + public bool ReceiveAll; - /// - /// The frequency that this device going to try transmit on. - /// - [DataField] - public uint? TransmitFrequency; + /// + /// The frequency that this device going to try to transmit on. + /// + [DataField] + public uint? TransmitFrequency; - /// - /// frequency prototype. Used to select a default frequency to transmit on. Used when the map is - /// initialized. - /// - [DataField] - public ProtoId? TransmitFrequencyId; + /// + /// Frequency prototype, used to select a default frequency to listen to on. + /// + [DataField] + public ProtoId? ReceiveFrequencyId; - /// - /// The address of the device, either on the network it is currently connected to or whatever address it - /// most recently used. - /// - [DataField] - public string Address = string.Empty; + /// + /// Frequency prototype, used to select a default frequency to transmit on. + /// + [DataField] + public ProtoId? TransmitFrequencyId; - /// - /// If true, the address was customized and should be preserved across networks. If false, a randomly - /// generated address will be created whenever this device connects to a network. - /// - [DataField] - public bool CustomAddress = false; + /// + /// Whether to send the broadcast recipients list to the sender so it can be filtered. + /// + [DataField] + public bool SendBroadcastAttemptEvent; - /// - /// Prefix to prepend to any automatically generated addresses. Helps players to identify devices. This gets - /// localized. - /// - [DataField] - public string? Prefix; + /// + /// If the device should show its address upon an examine. + /// Useful for devices that do not have a visible UI. + /// + [DataField, AutoNetworkedField] + public bool ExaminableAddress; - /// - /// Whether the device should listen for all device messages, regardless of the intended recipient. - /// - [DataField] - public bool ReceiveAll; + /// + /// Prefix to prepend to any automatically generated addresses. Helps players to identify devices. + /// + [DataField] + public LocId? Prefix; - /// - /// If the device should show its address upon an examine. Useful for devices - /// that do not have a visible UI. - /// - [DataField] - public bool ExaminableAddress; + /// + /// Whether the device should attempt to join the network on map init. + /// + [DataField] + public bool AutoConnect = true; - /// - /// Whether the device should attempt to join the network on map init. - /// - [DataField] - public bool AutoConnect = true; + /// + /// Whether this device's address can be saved to device-lists + /// + [DataField] + public bool SavableAddress = true; - /// - /// Whether to send the broadcast recipients list to the sender so it can be filtered. - /// - /// - [DataField] - public bool SendBroadcastAttemptEvent = false; + /// + /// If true, the address was customized and should be preserved across networks. If false, a randomly + /// generated address will be created whenever this device connects to a network. + /// + [DataField] + public bool CustomAddress; - /// - /// Whether this device's address can be saved to device-lists - /// - [DataField] - public bool SavableAddress = true; + /// + /// A list of device-lists that this device is on. + /// + [DataField] + [Access(typeof(SharedDeviceListSystem))] + public HashSet DeviceLists = new(); - /// - /// A list of device-lists that this device is on. - /// - [DataField] - [Access(typeof(SharedDeviceListSystem))] - public HashSet DeviceLists = new(); - - /// - /// A list of configurators that this device is on. - /// - [DataField] - [Access(typeof(SharedNetworkConfiguratorSystem))] - public HashSet Configurators = new(); - } + /// + /// A list of configurators that this device is on. + /// + [DataField] + [Access(typeof(SharedNetworkConfiguratorSystem))] + public HashSet Configurators = new(); } diff --git a/Content.Shared/DeviceNetwork/Components/DeviceNetworkJammerComponent.cs b/Content.Shared/DeviceNetwork/Components/DeviceNetworkJammerComponent.cs index 5ee04de0d1..05edea42e7 100644 --- a/Content.Shared/DeviceNetwork/Components/DeviceNetworkJammerComponent.cs +++ b/Content.Shared/DeviceNetwork/Components/DeviceNetworkJammerComponent.cs @@ -21,7 +21,7 @@ public sealed partial class DeviceNetworkJammerComponent : Component /// Network ids are not guaranteed to be limited to DeviceNetIdDefaults. /// [DataField, AutoNetworkedField] - public HashSet JammableNetworks = []; + public HashSet JammableNetworks = []; /// /// Device networks frequencies that wont be jammed. diff --git a/Content.Shared/DeviceNetwork/Components/DeviceNetworkRouterComponent.cs b/Content.Shared/DeviceNetwork/Components/DeviceNetworkRouterComponent.cs new file mode 100644 index 0000000000..6ca7b0f644 --- /dev/null +++ b/Content.Shared/DeviceNetwork/Components/DeviceNetworkRouterComponent.cs @@ -0,0 +1,11 @@ +using Content.Shared.DeviceNetwork.Payloads; +using Robust.Shared.GameStates; + +namespace Content.Shared.DeviceNetwork.Components; + +/// +/// Re-routs s to some other devices. +/// Useful for server setups where there are lots of payloads that have to be relayed. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class DeviceNetworkRouterComponent : Component; diff --git a/Content.Shared/DeviceNetwork/Device.cs b/Content.Shared/DeviceNetwork/Device.cs new file mode 100644 index 0000000000..85bcaf309b --- /dev/null +++ b/Content.Shared/DeviceNetwork/Device.cs @@ -0,0 +1,25 @@ +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Systems; + +namespace Content.Shared.DeviceNetwork; + +/// +/// Represents a device in a . +/// +/// +/// This type is read-only. To change any parameters of the device, use 's API. +/// +[DataRecord] +public readonly partial record struct Device(EntityUid Owner, uint? ReceiveFrequency, string Address, bool ReceiveAll) +{ + public Device(Entity ent) : this( + ent.Owner, + ent.Comp.ReceiveFrequency, + ent.Comp.Address, + ent.Comp.ReceiveAll) + { + Owner = ent.Owner; + ReceiveFrequency = ent.Comp.ReceiveFrequency; + ReceiveAll = ent.Comp.ReceiveAll; + } +} diff --git a/Content.Shared/DeviceNetwork/DeviceFrequencyPrototype.cs b/Content.Shared/DeviceNetwork/DeviceFrequencyPrototype.cs index ac5b6eec18..7e486e5b1d 100644 --- a/Content.Shared/DeviceNetwork/DeviceFrequencyPrototype.cs +++ b/Content.Shared/DeviceNetwork/DeviceFrequencyPrototype.cs @@ -13,13 +13,12 @@ public sealed partial class DeviceFrequencyPrototype : IPrototype public string ID { get; private set; } = default!; // TODO Somehow Allow per-station or some other type of named but randomized frequencies? - [DataField("frequency", required: true)] + [DataField(required: true)] public uint Frequency; /// /// Optional name for this frequency, for displaying in game. /// - [DataField("name")] - public string? Name; - + [DataField] + public LocId? Name; } diff --git a/Content.Shared/DeviceNetwork/DeviceLocalizationHelpers.cs b/Content.Shared/DeviceNetwork/DeviceLocalizationHelpers.cs new file mode 100644 index 0000000000..1ccb3c0242 --- /dev/null +++ b/Content.Shared/DeviceNetwork/DeviceLocalizationHelpers.cs @@ -0,0 +1,42 @@ +using Robust.Shared.Utility; + +namespace Content.Shared.DeviceNetwork; + +/// +/// A helper class for localization of frequencies and device network IDs. +/// +public static class DeviceLocalizationHelpers +{ + /// + /// Converts the unsigned int to string and inserts a number before the last digit + /// + public static string FrequencyToString(uint? frequency) + { + if (frequency == null) + return string.Empty; + + var result = frequency.Value.ToString(); + if (result.Length <= 2) + return result + ".0"; + + return result.Insert(result.Length - 1, "."); + } + + /// + /// Either returns the localized name representation of the corresponding + /// or converts the id to string + /// + public static string DeviceNetIdToLocalizedName(int? id, ILocalizationManager localeMan) + { + if (id == null) + return string.Empty; + + if (!Enum.IsDefined(typeof(DeviceNetIdDefaults), id)) + return id.Value.ToString(); + + var result = ((DeviceNetIdDefaults) id).ToString(); + var resultKebab = "device-net-id-" + CaseConversion.PascalToKebab(result); + + return !localeMan.TryGetString(resultKebab, out var name) ? result : name; + } +} diff --git a/Content.Shared/DeviceNetwork/DeviceNet.cs b/Content.Shared/DeviceNetwork/DeviceNet.cs index 4234b30385..0a831796cd 100644 --- a/Content.Shared/DeviceNetwork/DeviceNet.cs +++ b/Content.Shared/DeviceNetwork/DeviceNet.cs @@ -17,17 +17,20 @@ public sealed class DeviceNet /// This dictionary contains all devices connected to this network, though they may not be listening to any /// specific frequency. /// - public readonly Dictionary Devices = new(); + [ViewVariables] + public readonly Dictionary Devices = new(); /// /// Devices listening on a given frequency. /// - public readonly Dictionary> ListeningDevices = new(); + [ViewVariables] + public readonly Dictionary> ListeningDevices = new(); /// /// Devices listening to all packets on a given frequency, regardless of the intended recipient. /// - public readonly Dictionary> ReceiveAllDevices = new(); + [ViewVariables] + public readonly Dictionary> ReceiveAllDevices = new(); private readonly IRobustRandom _random; public readonly int NetId; @@ -41,9 +44,11 @@ public sealed class DeviceNet /// /// Add a device to the network. /// - public bool Add(DeviceNetworkComponent device) + public bool Add(Entity ent) { - if (device.CustomAddress) + var deviceComp = ent.Comp; + var device = new Device(ent); + if (deviceComp.CustomAddress) { // Only add if the device's existing address is available. if (!Devices.TryAdd(device.Address, device)) @@ -53,12 +58,15 @@ public sealed class DeviceNet { // 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); + { + deviceComp.Address = GenerateValidAddress(deviceComp.Prefix); + device = new Device(ent); // Reallocate because the data had changed + } Devices[device.Address] = device; } - if (device.ReceiveFrequency is not uint freq) + if (device.ReceiveFrequency is not { } freq) return true; if (!ListeningDevices.TryGetValue(freq, out var devices)) @@ -79,12 +87,14 @@ public sealed class DeviceNet /// /// Remove a device from the network. /// - public bool Remove(DeviceNetworkComponent device) + public bool Remove(Entity ent) { - if (device.Address == null || !Devices.Remove(device.Address)) + var deviceComp = ent.Comp; + var device = new Device(ent); + if (!Devices.Remove(device.Address)) return false; - if (device.ReceiveFrequency is not uint freq) + if (device.ReceiveFrequency is not { } freq) return true; if (ListeningDevices.TryGetValue(freq, out var listening)) @@ -104,121 +114,6 @@ public sealed class DeviceNet 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. /// @@ -230,8 +125,7 @@ public sealed class DeviceNet { var num = _random.Next(); address = $"{prefix}{num >> 16:X4}-{num & 0xFFFF:X4}"; - } - while (Devices.ContainsKey(address)); + } while (Devices.ContainsKey(address)); return address; } diff --git a/Content.Shared/DeviceNetwork/DeviceNetIdDefaults.cs b/Content.Shared/DeviceNetwork/DeviceNetIdDefaults.cs new file mode 100644 index 0000000000..8446ee0e5d --- /dev/null +++ b/Content.Shared/DeviceNetwork/DeviceNetIdDefaults.cs @@ -0,0 +1,16 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.DeviceNetwork; + +[Serializable, NetSerializable] +public enum DeviceNetIdDefaults +{ + Private, + Wired, + Wireless, + Apc, + AtmosDevices, + Reserved = 100, + // Ids outside this enum may exist + // This exists to let yml use nice names instead of numbers +} diff --git a/Content.Shared/DeviceNetwork/DeviceNetworkConstants.cs b/Content.Shared/DeviceNetwork/DeviceNetworkConstants.cs deleted file mode 100644 index 7fec72bb69..0000000000 --- a/Content.Shared/DeviceNetwork/DeviceNetworkConstants.cs +++ /dev/null @@ -1,79 +0,0 @@ -using Robust.Shared.Utility; -using Content.Shared.DeviceNetwork.Components; - -namespace Content.Shared.DeviceNetwork -{ - /// - /// A collection of constants to help with using device networks - /// - public static class DeviceNetworkConstants - { - /// - /// Used by logic gates to transmit the state of their ports - /// - public const string LogicState = "logic_state"; - - #region Commands - - /// - /// The key for command names - /// E.g. [DeviceNetworkConstants.Command] = "ping" - /// - public const string Command = "command"; - - /// - /// The command for setting a devices state - /// E.g. to turn a light on or off - /// - public const string CmdSetState = "set_state"; - - /// - /// The command for a device that just updated its state - /// E.g. suit sensors broadcasting owners vitals state - /// - public const string CmdUpdatedState = "updated_state"; - - #endregion - - #region SetState - - /// - /// Used with the command to turn a device on or off - /// - public const string StateEnabled = "state_enabled"; - - #endregion - - #region DisplayHelpers - - /// - /// Converts the unsigned int to string and inserts a number before the last digit - /// - public static string FrequencyToString(this uint frequency) - { - var result = frequency.ToString(); - if (result.Length <= 2) - return result + ".0"; - - return result.Insert(result.Length - 1, "."); - } - - /// - /// Either returns the localized name representation of the corresponding - /// or converts the id to string - /// - public static string DeviceNetIdToLocalizedName(this int id) - { - - if (!Enum.IsDefined(typeof(DeviceNetworkComponent.DeviceNetIdDefaults), id)) - return id.ToString(); - - var result = ((DeviceNetworkComponent.DeviceNetIdDefaults) id).ToString(); - var resultKebab = "device-net-id-" + CaseConversion.PascalToKebab(result); - - return !Loc.TryGetString(resultKebab, out var name) ? result : name; - } - - #endregion - } -} diff --git a/Content.Shared/DeviceNetwork/Events/BeforeBroadcastAttemptEvent.cs b/Content.Shared/DeviceNetwork/Events/BeforeBroadcastAttemptEvent.cs index f495847482..0c9cd90f35 100644 --- a/Content.Shared/DeviceNetwork/Events/BeforeBroadcastAttemptEvent.cs +++ b/Content.Shared/DeviceNetwork/Events/BeforeBroadcastAttemptEvent.cs @@ -1,16 +1,18 @@ -using Content.Shared.DeviceNetwork.Components; - namespace Content.Shared.DeviceNetwork.Events; /// /// Sent to the sending entity before broadcasting network packets to recipients /// -public sealed class BeforeBroadcastAttemptEvent : CancellableEntityEventArgs +[ByRefEvent] +public record struct BeforeBroadcastAttemptEvent { - public readonly IReadOnlySet Recipients; - public HashSet? ModifiedRecipients; + public readonly IReadOnlySet Recipients; - public BeforeBroadcastAttemptEvent(IReadOnlySet recipients) + public HashSet? ModifiedRecipients; + + public bool Cancelled = false; + + public BeforeBroadcastAttemptEvent(IReadOnlySet recipients) { Recipients = recipients; } diff --git a/Content.Shared/DeviceNetwork/Events/BeforePacketSentEvent.cs b/Content.Shared/DeviceNetwork/Events/BeforePacketSentEvent.cs index b34995a285..2e7c49cbd8 100644 --- a/Content.Shared/DeviceNetwork/Events/BeforePacketSentEvent.cs +++ b/Content.Shared/DeviceNetwork/Events/BeforePacketSentEvent.cs @@ -3,39 +3,16 @@ using System.Numerics; namespace Content.Shared.DeviceNetwork.Events; /// -/// Event raised before a device network packet is send. +/// Event raised before a device network packet is sent. /// Subscribed to by other systems to prevent the packet from being sent. /// -public sealed class BeforePacketSentEvent : CancellableEntityEventArgs -{ - /// - /// The EntityUid of the entity the packet was sent from. - /// - public readonly EntityUid Sender; - - public readonly TransformComponent SenderTransform; - - /// - /// The senders current position in world coordinates. - /// - public readonly Vector2 SenderPosition; - - /// - /// The network the packet will be sent to. - /// - public readonly string NetworkId; - - /// - /// The frequency the packet is sent on. - /// - public readonly uint Frequency; - - public BeforePacketSentEvent(EntityUid sender, TransformComponent xform, Vector2 senderPosition, string networkId, uint frequency) - { - Sender = sender; - SenderTransform = xform; - SenderPosition = senderPosition; - NetworkId = networkId; - Frequency = frequency; - } -} +[ByRefEvent] +public record struct BeforePacketSentEvent( + int NetId, + string? Address, + uint Frequency, + string SenderAddress, + EntityUid Sender, + TransformComponent SenderTransform, + Vector2 SenderPosition, + bool Cancelled = false); diff --git a/Content.Shared/DeviceNetwork/Events/DeviceAddressChangedEvent.cs b/Content.Shared/DeviceNetwork/Events/DeviceAddressChangedEvent.cs new file mode 100644 index 0000000000..37ac5ea261 --- /dev/null +++ b/Content.Shared/DeviceNetwork/Events/DeviceAddressChangedEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.DeviceNetwork.Events; + +/// +/// Raised when the was changed. +/// +[ByRefEvent] +public record struct DeviceAddressChangedEvent(string OldAddress, string NewAddress, bool IsCustom); diff --git a/Content.Shared/DeviceNetwork/Events/DeviceNetworkPacketEvent.cs b/Content.Shared/DeviceNetwork/Events/DeviceNetworkPacketEvent.cs index 4ae6afeef7..05938483da 100644 --- a/Content.Shared/DeviceNetwork/Events/DeviceNetworkPacketEvent.cs +++ b/Content.Shared/DeviceNetwork/Events/DeviceNetworkPacketEvent.cs @@ -1,47 +1,38 @@ +using Content.Shared.DeviceNetwork.Components; + namespace Content.Shared.DeviceNetwork.Events; /// -/// Event raised when a device network packet gets sent. +/// Event raised when a device network packet is received by an entity. /// -public sealed class DeviceNetworkPacketEvent : EntityEventArgs -{ - /// - /// The id of the network that this packet is being sent on. - /// - public int NetId; - - /// - /// The frequency the packet is sent on. - /// - public readonly uint Frequency; - - /// - /// Address of the intended recipient. Null if the message was broadcast. - /// - public string? Address; - - /// - /// The device network address of the sending entity. - /// - public readonly string SenderAddress; - - /// - /// The entity that sent the packet. - /// - public EntityUid Sender; - - /// - /// The data that is being sent. - /// - public readonly NetworkPayload Data; - - public DeviceNetworkPacketEvent(int netId, string? address, uint frequency, string senderAddress, EntityUid sender, NetworkPayload data) - { - NetId = netId; - Address = address; - Frequency = frequency; - SenderAddress = senderAddress; - Sender = sender; - Data = data; - } -} \ No newline at end of file +/// +/// ID of the network that this packet is translated on. +/// Device networks are currently global and only represent the way of signal transmission. +/// +/// +/// Address of the target device in a target network. +/// If null, this packet gets broadcasted to all devices in the network. +/// Empty string means invalid address. +/// +/// +/// Transmit frequency of the sender and receive frequency of the targeted device. +/// +/// +/// The device address of the sender. Can be used to send responses to payloads. +/// +/// +/// The sender entity with its . +/// +/// +/// The of a specific type. +/// This is the main container for custom information. +/// +/// Type of the payload sent by this event. +[ByRefEvent] +public readonly record struct DeviceNetworkPacketEvent( + int NetId, + string? Address, + uint Frequency, + string SenderAddress, + Entity Sender, + T Data) where T : INetworkPayload; diff --git a/Content.Shared/DeviceNetwork/Events/DeviceReceiveAllChangedEvent.cs b/Content.Shared/DeviceNetwork/Events/DeviceReceiveAllChangedEvent.cs new file mode 100644 index 0000000000..de65523fec --- /dev/null +++ b/Content.Shared/DeviceNetwork/Events/DeviceReceiveAllChangedEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.DeviceNetwork.Events; + +/// +/// Raised when the was changed. +/// +[ByRefEvent] +public record struct DeviceReceiveAllChangedEvent(bool ReceiveAll); diff --git a/Content.Shared/DeviceNetwork/Events/DeviceReceiveFrequencyChangedEvent.cs b/Content.Shared/DeviceNetwork/Events/DeviceReceiveFrequencyChangedEvent.cs new file mode 100644 index 0000000000..42935ce34e --- /dev/null +++ b/Content.Shared/DeviceNetwork/Events/DeviceReceiveFrequencyChangedEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.DeviceNetwork.Events; + +/// +/// Raised when the was changed. +/// +[ByRefEvent] +public record struct DeviceReceiveFrequencyChangedEvent(uint? OldFrequency, uint? NewFrequency); diff --git a/Content.Shared/DeviceNetwork/Events/DeviceTransmitFrequencyChangedEvent.cs b/Content.Shared/DeviceNetwork/Events/DeviceTransmitFrequencyChangedEvent.cs new file mode 100644 index 0000000000..86c04f38a6 --- /dev/null +++ b/Content.Shared/DeviceNetwork/Events/DeviceTransmitFrequencyChangedEvent.cs @@ -0,0 +1,9 @@ +using Content.Shared.DeviceNetwork.Components; + +namespace Content.Shared.DeviceNetwork.Events; + +/// +/// Raised when the was changed. +/// +[ByRefEvent] +public record struct DeviceTransmitFrequencyChangedEvent(uint? OldFrequency, uint? NewFrequency); diff --git a/Content.Shared/DeviceNetwork/NetworkPayload.cs b/Content.Shared/DeviceNetwork/NetworkPayload.cs index 3239374021..624faf0bfe 100644 --- a/Content.Shared/DeviceNetwork/NetworkPayload.cs +++ b/Content.Shared/DeviceNetwork/NetworkPayload.cs @@ -1,24 +1,7 @@ -using System.Diagnostics.CodeAnalysis; -using Robust.Shared.Utility; - namespace Content.Shared.DeviceNetwork; -public sealed class NetworkPayload : Dictionary -{ - /// - /// Tries to get a value from the payload and checks if that value is of type T. - /// - /// The type that should be casted to - /// Whether the value was present in the payload and of the required type - public bool TryGetValue(string key, [NotNullWhen(true)] out T? value) - { - if (this.TryCastValue(key, out T? result)) - { - value = result; - return true; - } - - value = default; - return false; - } -} +/// +/// A data class for information passing through a Device Network. +/// +[ImplicitDataRecord] +public partial interface INetworkPayload; diff --git a/Content.Shared/DeviceNetwork/Payloads/ApcNetTogglePayload.cs b/Content.Shared/DeviceNetwork/Payloads/ApcNetTogglePayload.cs new file mode 100644 index 0000000000..5830610036 --- /dev/null +++ b/Content.Shared/DeviceNetwork/Payloads/ApcNetTogglePayload.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.DeviceNetwork.Payloads; + +/// +/// A payload for the Apc net switch. +/// +public partial record struct ApcNetTogglePayload : INetworkPayload +{ + [DataField] + public bool Enabled; +} diff --git a/Content.Shared/DeviceNetwork/Payloads/RoutedNetworkPayload.cs b/Content.Shared/DeviceNetwork/Payloads/RoutedNetworkPayload.cs new file mode 100644 index 0000000000..34f252af5e --- /dev/null +++ b/Content.Shared/DeviceNetwork/Payloads/RoutedNetworkPayload.cs @@ -0,0 +1,88 @@ +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Systems; + +namespace Content.Shared.DeviceNetwork.Payloads; + +/// +/// Represents a payload that can be re-routed by a . +/// +public partial interface IRoutableNetworkPayload : INetworkPayload +{ + /// + /// Original sender address of this payload. + /// + string? SenderAddress { get; set; } + + /// + /// Original sender entity of this payload. + /// + EntityUid Sender { get; set; } +} + +public partial interface IRoutedNetworkPayload : INetworkPayload +{ + /// + /// If specified, the device router will use this frequency for transmitting the . + /// + uint? OverrideFrequency { get; set; } + + /// + /// If specified, the device router will use this network ID for transmitting the . + /// + int? OverrideNetwork { get; set; } + + /// + /// Address to re-route to when the is being handled. + /// + string? TargetAddress { get; set; } + + /// + /// + /// + void Reroute(EntityUid sender, string? address, uint? frequency, int? network, SharedDeviceNetworkSystem system); +} + +/// +/// A wrapper around the , sent to an entity with . +/// +public partial record struct RoutedNetworkPayload : IRoutedNetworkPayload where T : IRoutableNetworkPayload +{ + /// + /// The wrapped payload that is going to be sent when received by . + /// + [DataField] + public T Payload; + + /// + /// If specified, the device router will use this frequency for transmitting the . + /// + [DataField] + public uint? OverrideFrequency { get; set; } + + /// + /// If specified, the device router will use this network ID for transmitting the . + /// + [DataField] + public int? OverrideNetwork { get; set; } + + /// + /// Address to re-route to when the is being handled. + /// + [DataField] + public string? TargetAddress { get; set; } + + public void Reroute(EntityUid sender, + string? address, + uint? frequency, + int? network, + SharedDeviceNetworkSystem system) + { + // Things sometimes take a **weird route** when it comes to type parameters. + system.SendPacket( + sender, + address, + ref Payload, + frequency, + network); + } +} diff --git a/Content.Shared/DeviceNetwork/Systems/DeviceNetworkRouterSystem.cs b/Content.Shared/DeviceNetwork/Systems/DeviceNetworkRouterSystem.cs new file mode 100644 index 0000000000..b89afa7efe --- /dev/null +++ b/Content.Shared/DeviceNetwork/Systems/DeviceNetworkRouterSystem.cs @@ -0,0 +1,97 @@ +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Events; +using Content.Shared.DeviceNetwork.Payloads; +using Content.Shared.SurveillanceCamera; + +namespace Content.Shared.DeviceNetwork.Systems; + +/// +/// A system for re-routing s +/// through an entity with . +/// +public sealed partial class DeviceNetworkRouterSystem : EntitySystem +{ + [Dependency] private SharedDeviceNetworkSystem _deviceNetworkSystem = default!; + + [Dependency] private EntityQuery _query = default!; + + // TODO: make an engine PR to allow for auto-generated relay subscriptions + // Should be doable by using reflection on marker interfaces and then adding them to the auto-generated subscriptions + // I know it looks absolutely hilarious and horrible, but uuuhhhh anything to not make boxing allocations!!!!!!!! :godo: + public override void Initialize() + { + base.Initialize(); + + // Surveillance cameras + SubscribeLocalEvent>>((ent, ref args) => OnRoutePayload(ent, ref args)); + SubscribeLocalEvent>>((ent, ref args) => OnRoutePayload(ent, ref args)); + SubscribeLocalEvent>>((ent, ref args) => OnRoutePayload(ent, ref args)); + SubscribeLocalEvent>>((ent, ref args) => OnRoutePayload(ent, ref args)); + SubscribeLocalEvent>>((ent, ref args) => OnRoutePayload(ent, ref args)); + SubscribeLocalEvent>>((ent, ref args) => OnRoutePayload(ent, ref args)); + } + + private void OnRoutePayload(Entity ent, ref DeviceNetworkPacketEvent args) where T : IRoutedNetworkPayload + { + var payload = args.Data; + if (!_query.TryComp(ent, out var deviceComp)) + return; + + args.Data.Reroute(ent.Owner, + payload.TargetAddress, + payload.OverrideFrequency ?? deviceComp.TransmitFrequency, + payload.OverrideNetwork ?? deviceComp.DeviceNetId, + _deviceNetworkSystem); + } + + /// + /// Sends the given as a device network packet to the Relay entity with the given address and frequency. + /// After the payload is received by an entity with , + /// it gets re-routed to . + /// + /// + /// This is useful for routing server setups where the packet must be sent in both directions through a server. + /// + /// The sending entity. + /// The data to be sent. + /// + /// The address of the entity with that the packet gets sent to. + /// If null, the message is broadcast to all devices on that frequency (except the sender). + /// This address must include the router entity, so the packet can be relayed. + /// + /// + /// The Actual address to which the payload will be relayed + /// to after it was received by a . + /// + /// The frequency to send on to the router. + /// If specified, will use this frequency when re-routing the packet. + /// The network to send on to the router. + /// If specified, will use this network when re-routing the packet. + /// Returns true when the packet was successfully enqueued. + public void SendPacketRouted( + Entity ent, + ref T data, + string? routerAddress, + string? targetAddress, + uint? overrideFrequency = null, + uint? frequency = null, + int? overrideNetwork = null, + int? network = null) + where T : IRoutableNetworkPayload + { + if (!_query.Resolve(ref ent) || ent.Comp == null) + return; + + data.SenderAddress = ent.Comp.Address; + data.Sender = ent.Owner; + var payload = new RoutedNetworkPayload + { + Payload = data, + OverrideFrequency = overrideFrequency, + OverrideNetwork = overrideNetwork, + TargetAddress = targetAddress, + }; + + _deviceNetworkSystem.SendPacket(ent.Owner, routerAddress, ref payload, frequency, network); + } +} diff --git a/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkJammerSystem.cs b/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkJammerSystem.cs index 6ed770ffbc..9b4227bb39 100644 --- a/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkJammerSystem.cs +++ b/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkJammerSystem.cs @@ -26,7 +26,7 @@ public abstract class SharedDeviceNetworkJammerSystem : EntitySystem /// /// Returns the set of networks that this entity can jam. - public IReadOnlySet GetJammableNetworks(Entity ent) + public IReadOnlySet GetJammableNetworks(Entity ent) { return ent.Comp.JammableNetworks; } @@ -34,7 +34,7 @@ public abstract class SharedDeviceNetworkJammerSystem : EntitySystem /// /// Enables this entity to jam packets on the specified network. /// - public void AddJammableNetwork(Entity ent, string networkId) + public void AddJammableNetwork(Entity ent, int networkId) { if (ent.Comp.JammableNetworks.Add(networkId)) Dirty(ent); @@ -43,7 +43,7 @@ public abstract class SharedDeviceNetworkJammerSystem : EntitySystem /// /// Stops this entity from jamming packets on the specified network. /// - public void RemoveJammableNetwork(Entity ent, string networkId) + public void RemoveJammableNetwork(Entity ent, int networkId) { if (ent.Comp.JammableNetworks.Remove(networkId)) Dirty(ent); diff --git a/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkSystem.cs b/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkSystem.cs index 5992c40413..5bede5cb11 100644 --- a/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkSystem.cs +++ b/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkSystem.cs @@ -1,24 +1,44 @@ using Content.Shared.DeviceNetwork.Components; +using Content.Shared.Examine; +using JetBrains.Annotations; namespace Content.Shared.DeviceNetwork.Systems; -public abstract class SharedDeviceNetworkSystem : EntitySystem +/// +/// Entity system that handles everything device network related. +/// Device networking allows machines and devices to communicate with each other +/// while adhering to restrictions like range or being connected to the same power network. +/// +public abstract partial class SharedDeviceNetworkSystem : EntitySystem { + [SubscribeLocalEvent] + private void OnExamine(Entity ent, ref ExaminedEvent args) + { + if (ent.Comp.ExaminableAddress) + args.PushText(Loc.GetString("device-address-examine-message", ("address", ent.Comp.Address))); + } + /// - /// Sends the given payload as a device network packet to the entity with the given address and frequency. - /// Addresses are given to the DeviceNetworkComponent of an entity when connecting. + /// Sends the given as a device network packet to the entity with the given address and frequency. + /// Addresses are given to the of an entity when connecting. /// - /// The EntityUid of the sending entity - /// The address of the entity that the packet gets sent to. If null, the message is broadcast to all devices on that frequency (except the sender) - /// The frequency to send on - /// The data to be sent + /// The sending entity. + /// + /// The address of the entity that the packet gets sent to. + /// If null, the message is broadcast to all devices on that frequency (except the sender) + /// + /// The frequency to send on. + /// The data to be sent. + /// The network to send on. /// Returns true when the packet was successfully enqueued. - public virtual bool QueuePacket(EntityUid uid, + [PublicAPI] + public virtual bool SendPacket( + Entity ent, string? address, - NetworkPayload data, + ref T data, uint? frequency = null, - int? network = null, - DeviceNetworkComponent? device = null) + int? network = null) + where T : INetworkPayload { return false; } diff --git a/Content.Shared/Disposal/Mailing/MailRequestTagPayload.cs b/Content.Shared/Disposal/Mailing/MailRequestTagPayload.cs new file mode 100644 index 0000000000..b48c3d8337 --- /dev/null +++ b/Content.Shared/Disposal/Mailing/MailRequestTagPayload.cs @@ -0,0 +1,26 @@ +using Content.Shared.DeviceNetwork; + +namespace Content.Shared.Disposal.Mailing; + +/// +/// Request to get all available target mailing units. +/// +public partial record struct MailRequestTagPayload : INetworkPayload; + +/// +/// Sent as response to , contains tag of the sender. +/// +public partial record struct MailTagPayload : INetworkPayload +{ + [DataField] + public string Tag; +} + +public partial record struct MailSendPayload : INetworkPayload +{ + [DataField] + public string Tag; + + [DataField] + public string Target; +} diff --git a/Content.Shared/Disposal/Mailing/SharedMailingUnitSystem.cs b/Content.Shared/Disposal/Mailing/SharedMailingUnitSystem.cs index c7e3631046..fe91115fe2 100644 --- a/Content.Shared/Disposal/Mailing/SharedMailingUnitSystem.cs +++ b/Content.Shared/Disposal/Mailing/SharedMailingUnitSystem.cs @@ -1,12 +1,10 @@ using Content.Shared.Configurable; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared.DeviceNetwork.Systems; using Content.Shared.Disposal.Components; using Content.Shared.Disposal.Unit; using Content.Shared.Interaction; -using Content.Shared.Power.EntitySystems; using Robust.Shared.Player; namespace Content.Shared.Disposal.Mailing; @@ -14,26 +12,16 @@ namespace Content.Shared.Disposal.Mailing; public abstract partial class SharedMailingUnitSystem : EntitySystem { [Dependency] private SharedDeviceNetworkSystem _deviceNetwork = default!; - [Dependency] private SharedPowerReceiverSystem _power = default!; [Dependency] private SharedUserInterfaceSystem _userInterface = default!; private const string MailTag = "mail"; - private const string TagConfigurationKey = "tag"; - private const string NetTag = "tag"; - private const string NetSrc = "src"; - private const string NetTarget = "target"; - private const string NetCmdSent = "mail_sent"; - private const string NetCmdRequest = "get_mailer_tag"; - private const string NetCmdResponse = "mailer_tag"; - public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnPacketReceived); SubscribeLocalEvent(OnBeforeFlush); SubscribeLocalEvent(OnConfigurationUpdated); SubscribeLocalEvent(HandleActivate, before: new[] { typeof(SharedDisposalUnitSystem) }); @@ -45,39 +33,25 @@ public abstract partial class SharedMailingUnitSystem : EntitySystem UpdateTargetList(ent); } - private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnRequestTag(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command) || !_power.IsPowered(ent.Owner)) + if (ent.Comp.Tag == null) return; - switch (command) + var tagPayload = new MailTagPayload { - case NetCmdRequest: - SendTagRequestResponse(ent, args, ent.Comp.Tag); - break; - case NetCmdResponse when args.Data.TryGetValue(NetTag, out string? tag): - //Add the received tag request response to the list of targets - ent.Comp.TargetList.Add(tag); - Dirty(ent); - break; - } - } - - /// - /// Sends the given tag as a response to a if it's not null - /// - private void SendTagRequestResponse(EntityUid uid, DeviceNetworkPacketEvent args, string? tag) - { - if (tag == null) - return; - - var payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = NetCmdResponse, - [NetTag] = tag + Tag = ent.Comp.Tag, }; - _deviceNetwork.QueuePacket(uid, args.SenderAddress, payload, args.Frequency); + _deviceNetwork.SendPacket(ent.Owner, args.SenderAddress, ref tagPayload, args.Frequency); + } + + [SubscribeLocalEvent] + private void OnTag(Entity ent, ref DeviceNetworkPacketEvent args) + { + ent.Comp.TargetList.Add(args.Data.Tag); + Dirty(ent); } /// @@ -106,32 +80,27 @@ public abstract partial class SharedMailingUnitSystem : EntitySystem if (string.IsNullOrEmpty(ent.Comp.Tag) || string.IsNullOrEmpty(ent.Comp.Target) || !Resolve(ent, ref device)) return; - var payload = new NetworkPayload + var payload = new MailSendPayload { - [DeviceNetworkConstants.Command] = NetCmdSent, - [NetSrc] = ent.Comp.Tag, - [NetTarget] = ent.Comp.Target + Tag = ent.Comp.Tag, + Target = ent.Comp.Target, }; - _deviceNetwork.QueuePacket(ent, null, payload, null, null, device); + _deviceNetwork.SendPacket((ent.Owner, device), null, ref payload); } /// - /// Clears the units target list and broadcasts a . - /// The target list will then get populated with responses from all active mailing units on the same grid + /// Clears the units target list and broadcasts a . + /// The target list will then get populated with responses from all active mailing units on the same grid /// private void UpdateTargetList(Entity ent, DeviceNetworkComponent? device = null) { if (!Resolve(ent, ref device, false)) return; - var payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = NetCmdRequest - }; - + var payload = new MailRequestTagPayload(); ent.Comp.TargetList.Clear(); - _deviceNetwork.QueuePacket(ent, null, payload, null, null, device); + _deviceNetwork.SendPacket((ent.Owner, device), null, ref payload); } /// diff --git a/Content.Shared/Disposal/SignalRouter/DisposalSignallerSystem.cs b/Content.Shared/Disposal/SignalRouter/DisposalSignallerSystem.cs index e6c373f3a6..468a75bbfd 100644 --- a/Content.Shared/Disposal/SignalRouter/DisposalSignallerSystem.cs +++ b/Content.Shared/Disposal/SignalRouter/DisposalSignallerSystem.cs @@ -21,11 +21,11 @@ public sealed partial class DisposalSignallerSystem : EntitySystem private void OnInit(Entity ent, ref ComponentInit args) { - _link.EnsureSourcePorts(ent, ent.Comp.Port); + _link.EnsureSourcePorts(ent.Owner, ent.Comp.Port); } private void OnGetNextDirection(Entity ent, ref GetDisposalsNextDirectionEvent args) { - _link.InvokePort(ent, ent.Comp.Port); + _link.InvokePort(ent.Owner, ent.Comp.Port); } } diff --git a/Content.Shared/Fax/Components/FaxMachineComponent.cs b/Content.Shared/Fax/Components/FaxMachineComponent.cs index 96e87de3ff..d8aed8d790 100644 --- a/Content.Shared/Fax/Components/FaxMachineComponent.cs +++ b/Content.Shared/Fax/Components/FaxMachineComponent.cs @@ -3,6 +3,7 @@ using Content.Shared.Paper; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; namespace Content.Shared.Fax.Components; @@ -149,6 +150,7 @@ public sealed partial class FaxMachineComponent : Component } [DataDefinition] +[Serializable, NetSerializable] public sealed partial class FaxPrintout { [DataField(required: true)] diff --git a/Content.Shared/Fax/FaxPayloads.cs b/Content.Shared/Fax/FaxPayloads.cs new file mode 100644 index 0000000000..177e158bfa --- /dev/null +++ b/Content.Shared/Fax/FaxPayloads.cs @@ -0,0 +1,32 @@ +using Content.Shared.DeviceNetwork; +using Content.Shared.Fax.Components; + +namespace Content.Shared.Fax; + +/// +/// Broadcasted from one fax to all other available faxes. +/// +public partial record struct FaxPingPayload : INetworkPayload +{ + // TODO this should probably be made a more general system in the future + [DataField] + public bool IsSyndicate; +} + +/// +/// Sent as a response to . +/// +public partial record struct FaxPongPayload : INetworkPayload +{ + [DataField] + public string FaxName; +} + +/// +/// Payload to print a paper on the receiver fax. +/// +public partial record struct FaxPrintPayload : INetworkPayload +{ + [DataField] + public FaxPrintout Data; +} diff --git a/Content.Shared/Light/EntitySystems/SharedPoweredLightSystem.cs b/Content.Shared/Light/EntitySystems/SharedPoweredLightSystem.cs index 86b0e628ce..651d34bbc0 100644 --- a/Content.Shared/Light/EntitySystems/SharedPoweredLightSystem.cs +++ b/Content.Shared/Light/EntitySystems/SharedPoweredLightSystem.cs @@ -3,8 +3,8 @@ using Content.Shared.Damage.Components; using Content.Shared.Damage.Systems; using Content.Shared.DeviceLinking; using Content.Shared.DeviceLinking.Events; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; +using Content.Shared.DeviceNetwork.Payloads; using Content.Shared.DoAfter; using Content.Shared.Emp; using Content.Shared.Hands.EntitySystems; @@ -51,7 +51,6 @@ public abstract partial class SharedPoweredLightSystem : EntitySystem SubscribeLocalEvent(OnInteractUsing); SubscribeLocalEvent(OnInteractHand); SubscribeLocalEvent(OnSignalReceived); - SubscribeLocalEvent(OnPacketReceived); SubscribeLocalEvent(OnPowerChanged); SubscribeLocalEvent(OnDoAfter); SubscribeLocalEvent(HandleLightDamaged); @@ -130,15 +129,12 @@ public abstract partial class SharedPoweredLightSystem : EntitySystem } /// - /// Turns the light on or of when receiving a command. - /// The light is turned on or of according to the value + /// Turns the light on or of when receiving a . /// - private void OnPacketReceived(EntityUid uid, PoweredLightComponent component, DeviceNetworkPacketEvent args) + [SubscribeLocalEvent] + private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) { - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command) || command != DeviceNetworkConstants.CmdSetState) return; - if (!args.Data.TryGetValue(DeviceNetworkConstants.StateEnabled, out bool enabled)) return; - - SetState(uid, enabled, component); + SetState(ent, args.Data.Enabled, ent.Comp); } /// diff --git a/Content.Shared/Medical/CrewMonitoring/BroadcastSuitSensorStatePayload.cs b/Content.Shared/Medical/CrewMonitoring/BroadcastSuitSensorStatePayload.cs new file mode 100644 index 0000000000..237abf0d29 --- /dev/null +++ b/Content.Shared/Medical/CrewMonitoring/BroadcastSuitSensorStatePayload.cs @@ -0,0 +1,13 @@ +using Content.Shared.DeviceNetwork; +using Content.Shared.Medical.SuitSensors; + +namespace Content.Shared.Medical.CrewMonitoring; + +/// +/// Broadcast payoad from the crew monitoring server to all crew monitors. +/// +public partial record struct BroadcastSuitSensorStatePayload : INetworkPayload +{ + [DataField] + public Dictionary SensorStatus = new(); +} diff --git a/Content.Shared/Medical/CrewMonitoring/CrewMonitoringShared.cs b/Content.Shared/Medical/CrewMonitoring/CrewMonitoringShared.cs index 5b78839678..9ce87f0f83 100644 --- a/Content.Shared/Medical/CrewMonitoring/CrewMonitoringShared.cs +++ b/Content.Shared/Medical/CrewMonitoring/CrewMonitoringShared.cs @@ -1,4 +1,4 @@ -using Content.Shared.Medical.SuitSensor; +using Content.Shared.Medical.SuitSensors; using Robust.Shared.Serialization; namespace Content.Shared.Medical.CrewMonitoring; diff --git a/Content.Shared/Medical/SuitSensors/SharedSuitSensor.cs b/Content.Shared/Medical/SuitSensors/SharedSuitSensor.cs index f0a552c7ec..a6e556dd9e 100644 --- a/Content.Shared/Medical/SuitSensors/SharedSuitSensor.cs +++ b/Content.Shared/Medical/SuitSensors/SharedSuitSensor.cs @@ -1,11 +1,21 @@ +using Content.Shared.DeviceNetwork; using Content.Shared.DoAfter; using Robust.Shared.Map; using Robust.Shared.Serialization; -namespace Content.Shared.Medical.SuitSensor; +namespace Content.Shared.Medical.SuitSensors; -[Serializable, NetSerializable] -public sealed class SuitSensorStatus +/// +/// A network payload that contains . +/// +public partial record struct SuitSensorStatusPayload : INetworkPayload +{ + [DataField] + public SuitSensorStatus Data; +} + +[DataDefinition, Serializable, NetSerializable] +public partial struct SuitSensorStatus : IEquatable { public SuitSensorStatus(NetEntity ownerUid, NetEntity suitSensorUid, string name, string job, string jobIcon, List jobDepartments) { @@ -29,6 +39,51 @@ public sealed class SuitSensorStatus public int? TotalDamageThreshold; public float? DamagePercentage => TotalDamageThreshold == null || TotalDamage == null ? null : TotalDamage / (float) TotalDamageThreshold; public NetCoordinates? Coordinates; + + public bool Equals(SuitSensorStatus other) + { + return Timestamp.Equals(other.Timestamp) + && SuitSensorUid.Equals(other.SuitSensorUid) + && OwnerUid.Equals(other.OwnerUid) + && Name == other.Name + && Job == other.Job + && JobIcon == other.JobIcon + && IsAlive == other.IsAlive + && TotalDamage == other.TotalDamage + && TotalDamageThreshold == other.TotalDamageThreshold + && Nullable.Equals(Coordinates, other.Coordinates); + } + + public override bool Equals(object? obj) + { + return obj is SuitSensorStatus other && Equals(other); + } + + public override int GetHashCode() + { + var hashCode = new HashCode(); + hashCode.Add(Timestamp); + hashCode.Add(SuitSensorUid); + hashCode.Add(OwnerUid); + hashCode.Add(Name); + hashCode.Add(Job); + hashCode.Add(JobIcon); + hashCode.Add(IsAlive); + hashCode.Add(TotalDamage); + hashCode.Add(TotalDamageThreshold); + hashCode.Add(Coordinates); + return hashCode.ToHashCode(); + } + + public static bool operator ==(SuitSensorStatus left, SuitSensorStatus right) + { + return left.Equals(right); + } + + public static bool operator !=(SuitSensorStatus left, SuitSensorStatus right) + { + return !left.Equals(right); + } } [Serializable, NetSerializable] @@ -55,23 +110,6 @@ public enum SuitSensorMode : byte SensorCords = 3 } -public static class SuitSensorConstants -{ - public const string NET_OWNER_UID = "ownerUid"; - public const string NET_NAME = "name"; - public const string NET_JOB = "job"; - public const string NET_JOB_ICON = "jobIcon"; - public const string NET_JOB_DEPARTMENTS = "jobDepartments"; - public const string NET_IS_ALIVE = "alive"; - public const string NET_TOTAL_DAMAGE = "vitals"; - public const string NET_TOTAL_DAMAGE_THRESHOLD = "vitalsThreshold"; - public const string NET_COORDINATES = "coords"; - public const string NET_SUIT_SENSOR_UID = "uid"; - - ///Used by the CrewMonitoringServerSystem to send the status of all connected suit sensors to each crew monitor - public const string NET_STATUS_COLLECTION = "suit-status-collection"; -} - [Serializable, NetSerializable] public sealed partial class SuitSensorChangeDoAfterEvent : DoAfterEvent { diff --git a/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs b/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs index 0bc91d25af..bfec5e0fdd 100644 --- a/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs +++ b/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs @@ -2,16 +2,13 @@ using System.Numerics; using Content.Shared.Access.Systems; using Content.Shared.ActionBlocker; using Content.Shared.Clothing; -using Content.Shared.Damage.Components; using Content.Shared.Damage.Systems; -using Content.Shared.DeviceNetwork; using Content.Shared.DoAfter; using Content.Shared.Emp; using Content.Shared.Examine; using Content.Shared.GameTicking; using Content.Shared.Interaction; using Content.Shared.Inventory; -using Content.Shared.Medical.SuitSensor; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; @@ -20,7 +17,6 @@ using Content.Shared.Station; using Content.Shared.Verbs; using Robust.Shared.Containers; using Robust.Shared.Map; -using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -441,66 +437,4 @@ public abstract partial class SharedSuitSensorSystem : EntitySystem return status; } - - /// - /// Create a device network package from the suit sensors status. - /// - public NetworkPayload SuitSensorToPacket(SuitSensorStatus status) - { - var payload = new NetworkPayload() - { - [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdUpdatedState, - [SuitSensorConstants.NET_NAME] = status.Name, - [SuitSensorConstants.NET_JOB] = status.Job, - [SuitSensorConstants.NET_JOB_ICON] = status.JobIcon, - [SuitSensorConstants.NET_JOB_DEPARTMENTS] = status.JobDepartments, - [SuitSensorConstants.NET_IS_ALIVE] = status.IsAlive, - [SuitSensorConstants.NET_SUIT_SENSOR_UID] = status.SuitSensorUid, - [SuitSensorConstants.NET_OWNER_UID] = status.OwnerUid, - }; - - if (status.TotalDamage != null) - payload.Add(SuitSensorConstants.NET_TOTAL_DAMAGE, status.TotalDamage); - if (status.TotalDamageThreshold != null) - payload.Add(SuitSensorConstants.NET_TOTAL_DAMAGE_THRESHOLD, status.TotalDamageThreshold); - if (status.Coordinates != null) - payload.Add(SuitSensorConstants.NET_COORDINATES, status.Coordinates); - - return payload; - } - - /// - /// Try to create the suit sensors status from the device network message. - /// - public SuitSensorStatus? PacketToSuitSensor(NetworkPayload payload) - { - // check command - if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command)) - return null; - if (command != DeviceNetworkConstants.CmdUpdatedState) - return null; - - // check name, job and alive - if (!payload.TryGetValue(SuitSensorConstants.NET_NAME, out string? name)) return null; - if (!payload.TryGetValue(SuitSensorConstants.NET_JOB, out string? job)) return null; - if (!payload.TryGetValue(SuitSensorConstants.NET_JOB_ICON, out string? jobIcon)) return null; - if (!payload.TryGetValue(SuitSensorConstants.NET_JOB_DEPARTMENTS, out List? jobDepartments)) return null; - if (!payload.TryGetValue(SuitSensorConstants.NET_IS_ALIVE, out bool? isAlive)) return null; - if (!payload.TryGetValue(SuitSensorConstants.NET_SUIT_SENSOR_UID, out NetEntity suitSensorUid)) return null; - if (!payload.TryGetValue(SuitSensorConstants.NET_OWNER_UID, out NetEntity ownerUid)) return null; - - // try get total damage and cords (optionals) - payload.TryGetValue(SuitSensorConstants.NET_TOTAL_DAMAGE, out int? totalDamage); - payload.TryGetValue(SuitSensorConstants.NET_TOTAL_DAMAGE_THRESHOLD, out int? totalDamageThreshold); - payload.TryGetValue(SuitSensorConstants.NET_COORDINATES, out NetCoordinates? coords); - - var status = new SuitSensorStatus(ownerUid, suitSensorUid, name, job, jobIcon, jobDepartments) - { - IsAlive = isAlive.Value, - TotalDamage = totalDamage, - TotalDamageThreshold = totalDamageThreshold, - Coordinates = coords, - }; - return status; - } } diff --git a/Content.Shared/Medical/SuitSensors/SuitSensorComponent.cs b/Content.Shared/Medical/SuitSensors/SuitSensorComponent.cs index 19bee1b017..dfdaa1f18a 100644 --- a/Content.Shared/Medical/SuitSensors/SuitSensorComponent.cs +++ b/Content.Shared/Medical/SuitSensors/SuitSensorComponent.cs @@ -1,4 +1,3 @@ -using Content.Shared.Medical.SuitSensor; using Robust.Shared.GameStates; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; diff --git a/Content.Shared/Power/Generation/Teg/TegSensorPayload.cs b/Content.Shared/Power/Generation/Teg/TegSensorPayload.cs new file mode 100644 index 0000000000..afa432f9e2 --- /dev/null +++ b/Content.Shared/Power/Generation/Teg/TegSensorPayload.cs @@ -0,0 +1,63 @@ +using Content.Shared.DeviceNetwork; +using Robust.Shared.Serialization; + +namespace Content.Shared.Power.Generation.Teg; + +/// +/// Information for a single TEG circulator. +/// +/// Pressure measured at the circulator's input pipe +/// Pressure measured at the circulator's output pipe +/// Temperature measured at the circulator's input pipe +/// Temperature measured at the circulator's output pipe +[DataRecord] +[Serializable, NetSerializable] +public partial record struct Circulator( + float InletPressure, + float OutletPressure, + float InletTemperature, + float OutletTemperature); + +/// +/// Sensor data reported by the when queried over the device network. +/// +public partial record struct TegSensorPayload : INetworkPayload +{ + /// + /// Information for the A-side circulator. + /// + [DataField] + public Circulator CirculatorA; + + /// + /// Information for the B-side circulator. + /// + [DataField] + public Circulator CirculatorB; + + /// + /// The amount of energy (Joules) generated by the TEG last atmos tick. + /// + /// + [DataField] + public float LastGeneration; + + /// + /// Ramping position for the TEG power generation. + /// + /// + [DataField] + public float RampPosition; + + /// + /// Power (Watts) actually being supplied by the TEG to connected power network. + /// + /// + [DataField] + public float PowerOutput; +} + +/// +/// Request to get . +/// +public partial record struct TegSensorSyncPayload : INetworkPayload; diff --git a/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs b/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs index 5b928edc08..0322d9a3d5 100644 --- a/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs +++ b/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.Popups; using Content.Shared.Verbs; @@ -33,7 +34,7 @@ public abstract partial class SharedJammerSystem : EntitySystem EnsureComp(entity); EnsureComp(entity, out var jammingComp); _jammer.SetRange((entity, jammingComp), GetCurrentRange(entity)); - _jammer.AddJammableNetwork((entity, jammingComp), DeviceNetworkComponent.DeviceNetIdDefaults.Wireless.ToString()); + _jammer.AddJammableNetwork((entity, jammingComp), (int) DeviceNetIdDefaults.Wireless); // Add excluded frequencies using the system method foreach (var freq in entity.Comp.FrequenciesExcluded) diff --git a/Content.Shared/Robotics/RoboticsConsoleUi.cs b/Content.Shared/Robotics/RoboticsConsoleUi.cs index 01ecb3f598..ecf273c646 100644 --- a/Content.Shared/Robotics/RoboticsConsoleUi.cs +++ b/Content.Shared/Robotics/RoboticsConsoleUi.cs @@ -1,4 +1,4 @@ -using Robust.Shared.Prototypes; +using Content.Shared.DeviceNetwork; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Utility; @@ -136,12 +136,21 @@ public partial record struct CyborgControlData } } -public static class RoboticsConsoleConstants -{ - // broadcast by cyborgs on Robotics Console frequency - public const string NET_CYBORG_DATA = "cyborg-data"; +/// +/// Disables a borg when received. +/// +public partial record struct RoboticsCyborgDisablePayload : INetworkPayload; - // sent by robotics console to cyborgs on Cyborg Control frequency - public const string NET_DISABLE_COMMAND = "cyborg-disable"; - public const string NET_DESTROY_COMMAND = "cyborg-destroy"; +/// +/// Destroys a borg when received. +/// +public partial record struct RoboticsCyborgDestroyPayload : INetworkPayload; + +/// +/// A wrapper for +/// +public partial record struct RoboticsCyborgDataPayload : INetworkPayload +{ + [DataField] + public CyborgControlData Data; } diff --git a/Content.Shared/Robotics/Systems/SharedRoboticsConsoleSystem.cs b/Content.Shared/Robotics/Systems/SharedRoboticsConsoleSystem.cs index 25b3c5d07a..554dad46e9 100644 --- a/Content.Shared/Robotics/Systems/SharedRoboticsConsoleSystem.cs +++ b/Content.Shared/Robotics/Systems/SharedRoboticsConsoleSystem.cs @@ -3,6 +3,4 @@ namespace Content.Shared.Robotics.Systems; /// /// Does nothing, only exists for access right now. /// -public abstract class SharedRoboticsConsoleSystem : EntitySystem -{ -} +public abstract class SharedRoboticsConsoleSystem : EntitySystem; diff --git a/Content.Shared/RoundEnd/ScreenShuttlePayload.cs b/Content.Shared/RoundEnd/ScreenShuttlePayload.cs new file mode 100644 index 0000000000..2dcfd3809a --- /dev/null +++ b/Content.Shared/RoundEnd/ScreenShuttlePayload.cs @@ -0,0 +1,36 @@ +using Content.Shared.DeviceNetwork; + +namespace Content.Shared.RoundEnd; + +/// +/// A network payload to broadcast data to shuttle screens. +/// +public partial record struct ScreenShuttlePayload : INetworkPayload +{ + [DataField] + public EntityUid? Shuttle; + + [DataField] + public EntityUid? SourceMap; + + [DataField] + public EntityUid? DestinationMap; + + [DataField] + public TimeSpan ShuttleTime; + + [DataField] + public TimeSpan SourceTime; + + [DataField] + public TimeSpan DestinationTime; + + [DataField] + public bool Docked; + + [DataField] + public string? OverrideText; + + [DataField] + public Color? OverrideColor; +} diff --git a/Content.Shared/Screens/ScreenTextPayload.cs b/Content.Shared/Screens/ScreenTextPayload.cs new file mode 100644 index 0000000000..25371e8ca5 --- /dev/null +++ b/Content.Shared/Screens/ScreenTextPayload.cs @@ -0,0 +1,12 @@ +using Content.Shared.DeviceNetwork; + +namespace Content.Shared.Screens; + +/// +/// Broadcasts text to screens. +/// +public partial record struct ScreenTextPayload : INetworkPayload +{ + [DataField] + public string? Text; +} diff --git a/Content.Shared/SensorMonitoring/BatterySensorPayloads.cs b/Content.Shared/SensorMonitoring/BatterySensorPayloads.cs new file mode 100644 index 0000000000..3b2e422468 --- /dev/null +++ b/Content.Shared/SensorMonitoring/BatterySensorPayloads.cs @@ -0,0 +1,36 @@ +using Content.Shared.DeviceNetwork; + +namespace Content.Shared.SensorMonitoring; + +/// +/// Data about a battery sent to the power monitoring console. +/// +public partial record struct BatterySensorDataPayload : INetworkPayload +{ + [DataField] + public BatterySensorData Data; +} + +/// +/// A request for . +/// +public partial record struct BatterySensorSyncPayload : INetworkPayload; + +/// +/// Device network data sent by a . +/// +/// The current energy charge of the battery, in joules (J). +/// The maximum energy capacity of the battery, in joules (J). +/// The current amount of power being received by the battery, in watts (W). +/// The maximum amount of power that can be received by the battery, in watts (W). +/// The current amount of power being supplied by the battery, in watts (W). +/// The maximum amount of power that can be received by the battery, in watts (W). +[DataRecord] +public partial record struct BatterySensorData( + float Charge, + float MaxCharge, + float Receiving, + float MaxReceiving, + float Supplying, + float MaxSupplying +); diff --git a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs index d0e4f2fd91..223b0645c7 100644 --- a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs +++ b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Administration.Logs; using Content.Shared.Body.Events; using Content.Shared.Containers.ItemSlots; using Content.Shared.Database; +using Content.Shared.DeviceNetwork.Systems; using Content.Shared.Gibbing; using Content.Shared.Hands.EntitySystems; using Content.Shared.IdentityManagement; diff --git a/Content.Shared/SurveillanceCamera/Components/SurveillanceCameraMapComponent.cs b/Content.Shared/SurveillanceCamera/Components/SurveillanceCameraMapComponent.cs index 754240f604..3613456bcd 100644 --- a/Content.Shared/SurveillanceCamera/Components/SurveillanceCameraMapComponent.cs +++ b/Content.Shared/SurveillanceCamera/Components/SurveillanceCameraMapComponent.cs @@ -1,5 +1,7 @@ using System.Numerics; +using Content.Shared.DeviceNetwork; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.SurveillanceCamera.Components; @@ -46,7 +48,7 @@ public partial struct CameraMarker /// Subnet the camera is connected to. /// [DataField] - public string Subnet; + public ProtoId Subnet; /// /// Should the camera be displayed on the camera map. diff --git a/Content.Shared/SurveillanceCamera/SharedSurveillanceCameraSystem.cs b/Content.Shared/SurveillanceCamera/SharedSurveillanceCameraSystem.cs index 1be49f8fc8..dfe4365b1a 100644 --- a/Content.Shared/SurveillanceCamera/SharedSurveillanceCameraSystem.cs +++ b/Content.Shared/SurveillanceCamera/SharedSurveillanceCameraSystem.cs @@ -9,6 +9,7 @@ public abstract partial class SharedSurveillanceCameraSystem : EntitySystem { public override void Initialize() { + base.Initialize(); SubscribeLocalEvent>(AddVerbs); SubscribeLocalEvent(OnEmpPulse); SubscribeLocalEvent(OnEmpDisabledRemoved); diff --git a/Content.Shared/SurveillanceCamera/SurveillanceCameraPayloads.cs b/Content.Shared/SurveillanceCamera/SurveillanceCameraPayloads.cs new file mode 100644 index 0000000000..a8b27dfa2d --- /dev/null +++ b/Content.Shared/SurveillanceCamera/SurveillanceCameraPayloads.cs @@ -0,0 +1,114 @@ +using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Payloads; +using Robust.Shared.Prototypes; + +namespace Content.Shared.SurveillanceCamera; + +/// +/// Response to +/// from the camera in order to establish the connection. +/// +public partial record struct SurveillanceCameraConnectPayload : IRoutableNetworkPayload +{ + [DataField] + public string? SenderAddress { get; set; } + + [DataField] + public EntityUid Sender { get; set; } +} + +/// +/// Request to connect to a camera from the camera monitor. +/// +public partial record struct SurveillanceCameraConnectRequestPayload : IRoutableNetworkPayload +{ + [DataField] + public string? SenderAddress { get; set; } + + [DataField] + public EntityUid Sender { get; set; } +} + +/// +/// Message sent periodically by an active camera monitor towards the active camera. +/// +public partial record struct SurveillanceCameraHeartbeatRequestPayload : IRoutableNetworkPayload +{ + [DataField] + public string? SenderAddress { get; set; } + + [DataField] + public EntityUid Sender { get; set; } +} + +/// +/// Response from the camera to the . +/// +public partial record struct SurveillanceCameraHeartbeatPayload : IRoutableNetworkPayload +{ + [DataField] + public string? SenderAddress { get; set; } + + [DataField] + public EntityUid Sender { get; set; } +} + +/// +/// Request to get from all cameras on a certain subnet. +/// +public partial record struct SurveillanceCameraPingPayload : IRoutableNetworkPayload +{ + [DataField] + public string Subnet; + + [DataField] + public string? SenderAddress { get; set; } + + [DataField] + public EntityUid Sender { get; set; } +} + +/// +/// Response to the request, contains info about a camera on a subnet. +/// +public partial record struct SurveillanceCameraDataPayload : IRoutableNetworkPayload +{ + [DataField] + public string Name; + + [DataField] + public string Subnet; + + [DataField] + public string? SenderAddress { get; set; } + + [DataField] + public EntityUid Sender { get; set; } +} + +/// +/// Request to connect to a camera subnet. +/// +public partial record struct SurveillanceCameraSubnetConnectPayload : INetworkPayload; + +/// +/// Request to disconnect from a camera subnet. +/// +public partial record struct SurveillanceCameraSubnetDisconnectPayload : INetworkPayload; + +/// +/// Request to get all available subnets. +/// +public partial record struct SurveillanceCameraPingSubnetPayload : INetworkPayload; + +/// +/// Response to the , contains the name of the available subnet. +/// +public partial record struct SurveillanceCameraSubnetDataPayload : INetworkPayload +{ + [DataField] + public string Subnet; + + [DataField] + public ProtoId TransmitFrequency; +} diff --git a/Content.Shared/TurretController/TurretControllerPayloads.cs b/Content.Shared/TurretController/TurretControllerPayloads.cs new file mode 100644 index 0000000000..733bd42fa0 --- /dev/null +++ b/Content.Shared/TurretController/TurretControllerPayloads.cs @@ -0,0 +1,28 @@ +using Content.Shared.Access; +using Content.Shared.DeviceNetwork; +using Robust.Shared.Prototypes; + +namespace Content.Shared.TurretController; + +/// +/// A network payload that sets fire mode for a turret. +/// +public partial record struct TurretControllerSetArmamentPayload : INetworkPayload +{ + [DataField] + public int ArmamentState; +} + +/// +/// A network payload that sets access exemptions for a turret. +/// +public partial record struct TurretControllerSetAccessPayload : INetworkPayload +{ + [DataField] + public HashSet> AccessExemptions = new(); +} + +/// +/// A network payload request to get the state of all available turrets. +/// +public readonly partial record struct TurretControllerRequestPayload : INetworkPayload; diff --git a/Content.Shared/Turrets/TurretPayloads.cs b/Content.Shared/Turrets/TurretPayloads.cs new file mode 100644 index 0000000000..5271742221 --- /dev/null +++ b/Content.Shared/Turrets/TurretPayloads.cs @@ -0,0 +1,12 @@ +using Content.Shared.DeviceNetwork; + +namespace Content.Shared.Turrets; + +/// +/// A wrapper for . +/// +public partial record struct TurretStatePayload : INetworkPayload +{ + [DataField] + public DeployableTurretState State; +} diff --git a/Resources/Locale/en-US/devices/device-network.ftl b/Resources/Locale/en-US/devices/device-network.ftl index 7151e218f3..c198215867 100644 --- a/Resources/Locale/en-US/devices/device-network.ftl +++ b/Resources/Locale/en-US/devices/device-network.ftl @@ -1,4 +1,4 @@ -# named frequencies +# Named frequencies device-frequency-prototype-name-atmos = Atmospheric Devices device-frequency-prototype-name-suit-sensors = Suit Sensors device-frequency-prototype-name-crew-monitor = Crew Monitor @@ -13,8 +13,11 @@ device-frequency-prototype-name-turret = Sentry Turret device-frequency-prototype-name-turret-control = Sentry Turret Control device-frequency-prototype-name-xenoborg = Xenoborg device-frequency-prototype-name-mothership = Mothership +device-frequency-prototype-name-arrivals-shuttle-timer = Arrivals Timer +device-frequency-prototype-name-shuttle-timer = Evac Shuttle Timer -## camera frequencies +## Camera frequencies +device-frequency-prototype-name-surveillance-camera = Cameras device-frequency-prototype-name-surveillance-camera-test = Subnet Test device-frequency-prototype-name-surveillance-camera-engineering = Engineering Cameras device-frequency-prototype-name-surveillance-camera-security = Security Cameras @@ -26,7 +29,7 @@ device-frequency-prototype-name-surveillance-camera-medical = Medical Cameras device-frequency-prototype-name-surveillance-camera-general = General Cameras device-frequency-prototype-name-surveillance-camera-entertainment = Entertainment Cameras -# prefixes for randomly generated device addresses +# Prefixes for randomly generated device addresses device-address-prefix-vent = VNT- device-address-prefix-scrubber = SCR- device-address-prefix-sensor = SNS- @@ -43,7 +46,16 @@ device-address-prefix-console = CLS- device-address-prefix-fire-alarm = FIR- device-address-prefix-air-alarm = AIR- -device-address-prefix-sensor-monitor = MON- +# Consoles +device-address-prefix-sensor-monitor = SEM- +device-address-prefix-camera-monitor = SCM- +device-address-prefix-crew-monitor = MCM- + +# Servers and routers +device-address-prefix-camera-router = CMR- +device-address-prefix-camera-router-wireless = CMW- +device-address-prefix-camera = CAM- +device-address-prefix-crew-monitoring-server = CMS- device-address-examine-message = The device's address is {$address}. diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml index 3593ce1df1..4a0d4c6425 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml @@ -21,6 +21,7 @@ - type: DeviceNetwork deviceNetId: Wireless receiveFrequencyId: CrewMonitor + prefix: device-address-prefix-crew-monitor - type: WirelessNetworkConnection range: 500 - type: StationLimitedNetwork diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index 9c43f60324..6164240896 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -457,6 +457,7 @@ - type: DeviceNetwork deviceNetId: Wireless receiveFrequencyId: CrewMonitor + prefix: device-address-prefix-crew-monitor - type: WirelessNetworkConnection range: 1200 - type: AmbientMusicMarkerMedical @@ -1405,6 +1406,7 @@ deviceNetId: Wired receiveFrequencyId: SurveillanceCamera transmitFrequencyId: SurveillanceCamera + prefix: device-address-prefix-camera-monitor - type: WiredNetworkConnection - type: DeviceNetworkRequiresPower - type: SurveillanceCameraMonitor @@ -1444,6 +1446,7 @@ deviceNetId: Wireless receiveFrequencyId: SurveillanceCamera transmitFrequencyId: SurveillanceCamera + prefix: device-address-prefix-camera-monitor - type: WirelessNetworkConnection range: 200 - type: DeviceNetworkRequiresPower diff --git a/Resources/Prototypes/Entities/Structures/Machines/crew_monitor_server.yml b/Resources/Prototypes/Entities/Structures/Machines/crew_monitor_server.yml index 1b35e4baec..e069fa3879 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/crew_monitor_server.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/crew_monitor_server.yml @@ -33,6 +33,7 @@ deviceNetId: Wireless transmitFrequencyId: CrewMonitor receiveFrequencyId: SuitSensor + prefix: device-address-prefix-crew-monitoring-server autoConnect: false - type: WirelessNetworkConnection range: 500 diff --git a/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml b/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml index f345fa3988..5ace676f3b 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml @@ -1,72 +1,75 @@ - type: entity abstract: true - parent: [ BaseMachinePowered, ConstructibleMachine, BaseConstructibleMachineDestructible ] + parent: [ BaseMachinePowered, ConstructibleMachine ] id: SurveillanceCameraRouterBase name: camera router description: A surveillance camera router. It routes. Perhaps. components: - - type: DeviceNetwork - deviceNetId: Wired - receiveFrequencyId: SurveillanceCamera - transmitFrequencyId: SurveillanceCamera - - type: WiredNetworkConnection - - type: DeviceNetworkRequiresPower - - type: UserInterface - interfaces: - enum.SurveillanceCameraSetupUiKey.Router: - type: SurveillanceCameraSetupBoundUi - - type: Machine - board: SurveillanceCameraRouterCircuitboard - - type: Sprite - sprite: Structures/Machines/server.rsi - snapCardinals: true - layers: - - state: server-off - - state: server-on - visible: false - map: ["enum.PowerDeviceVisualLayers.Powered"] - - state: server_o - map: ["enum.WiresVisualLayers.MaintenancePanel"] - - type: GenericVisualizer - visuals: - enum.PowerDeviceVisuals.Powered: - enum.PowerDeviceVisualLayers.Powered: - True: { visible: true } - False: { visible: false } - - type: Destructible - thresholds: - - trigger: !type:DamageTrigger - damage: 175 - behaviors: - - !type:PlaySoundBehavior - sound: - collection: MetalBreak - - type: Appearance - - type: AmbientOnPowered - - type: AmbientSound - volume: -9 - range: 5 - enabled: false - sound: - collection: ServerFans - - type: WiresVisuals - - type: WiresPanel + - type: Sprite + sprite: Structures/Machines/server.rsi + snapCardinals: true + layers: + - state: server-off + - state: server-on + visible: false + map: ["enum.PowerDeviceVisualLayers.Powered"] + - state: server_o + map: ["enum.WiresVisualLayers.MaintenancePanel"] + - type: GenericVisualizer + visuals: + enum.PowerDeviceVisuals.Powered: + enum.PowerDeviceVisualLayers.Powered: + True: { visible: true } + False: { visible: false } + - type: Appearance + - type: AmbientOnPowered + - type: AmbientSound + volume: -9 + range: 5 + enabled: false + sound: + collection: ServerFans + - type: WiresVisuals + - type: WiresPanel + - type: Machine + board: SurveillanceCameraRouterCircuitboard + - type: Destructible + thresholds: + - trigger: !type:DamageTrigger + damage: 175 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: MetalBreak + - type: DeviceNetwork + deviceNetId: Wired + receiveFrequencyId: SurveillanceCamera + transmitFrequencyId: SurveillanceCamera + prefix: device-address-prefix-camera-router + - type: WiredNetworkConnection + - type: DeviceNetworkRequiresPower + - type: DeviceNetworkRouter + - type: SurveillanceCameraRouter + - type: UserInterface + interfaces: + enum.SurveillanceCameraSetupUiKey.Router: + type: SurveillanceCameraSetupBoundUi - type: entity parent: SurveillanceCameraRouterBase id: SurveillanceCameraRouterConstructed suffix: Constructed components: - - type: SurveillanceCameraRouter - setupAvailableNetworks: - - SurveillanceCameraEngineering - - SurveillanceCameraSecurity - - SurveillanceCameraService - - SurveillanceCameraSupply - - SurveillanceCameraScience - - SurveillanceCameraGeneral - - SurveillanceCameraMedical - - SurveillanceCameraCommand + - type: SurveillanceCameraRouter + setupAvailableNetworks: + - SurveillanceCameraEngineering + - SurveillanceCameraSecurity + - SurveillanceCameraService + - SurveillanceCameraSupply + - SurveillanceCameraScience + - SurveillanceCameraGeneral + - SurveillanceCameraMedical + - SurveillanceCameraCommand - type: entity parent: SurveillanceCameraRouterBase @@ -74,8 +77,8 @@ name: engineering camera router suffix: Engineering components: - - type: SurveillanceCameraRouter - subnetFrequency: SurveillanceCameraEngineering + - type: SurveillanceCameraRouter + subnetFrequency: SurveillanceCameraEngineering - type: entity parent: SurveillanceCameraRouterBase @@ -83,8 +86,8 @@ name: security camera router suffix: Security components: - - type: SurveillanceCameraRouter - subnetFrequency: SurveillanceCameraSecurity + - type: SurveillanceCameraRouter + subnetFrequency: SurveillanceCameraSecurity - type: entity parent: SurveillanceCameraRouterBase @@ -92,8 +95,8 @@ name: science camera router suffix: Science components: - - type: SurveillanceCameraRouter - subnetFrequency: SurveillanceCameraScience + - type: SurveillanceCameraRouter + subnetFrequency: SurveillanceCameraScience - type: entity parent: SurveillanceCameraRouterBase @@ -101,8 +104,8 @@ name: supply camera router suffix: Supply components: - - type: SurveillanceCameraRouter - subnetFrequency: SurveillanceCameraSupply + - type: SurveillanceCameraRouter + subnetFrequency: SurveillanceCameraSupply - type: entity parent: SurveillanceCameraRouterBase @@ -110,8 +113,8 @@ name: command camera router suffix: Command components: - - type: SurveillanceCameraRouter - subnetFrequency: SurveillanceCameraCommand + - type: SurveillanceCameraRouter + subnetFrequency: SurveillanceCameraCommand - type: entity parent: SurveillanceCameraRouterBase @@ -119,8 +122,8 @@ name: service camera router suffix: Service components: - - type: SurveillanceCameraRouter - subnetFrequency: SurveillanceCameraService + - type: SurveillanceCameraRouter + subnetFrequency: SurveillanceCameraService - type: entity parent: SurveillanceCameraRouterBase @@ -128,8 +131,8 @@ name: medical camera router suffix: Medical components: - - type: SurveillanceCameraRouter - subnetFrequency: SurveillanceCameraMedical + - type: SurveillanceCameraRouter + subnetFrequency: SurveillanceCameraMedical - type: entity parent: SurveillanceCameraRouterBase @@ -137,8 +140,8 @@ name: general camera router suffix: General components: - - type: SurveillanceCameraRouter - subnetFrequency: SurveillanceCameraGeneral + - type: SurveillanceCameraRouter + subnetFrequency: SurveillanceCameraGeneral - type: entity abstract: true @@ -147,61 +150,62 @@ name: wireless camera router description: A wireless surveillance camera router. It routes. Perhaps. components: - - type: DeviceNetwork - deviceNetId: Wireless - receiveFrequencyId: SurveillanceCamera - transmitFrequencyId: SurveillanceCamera - - type: WirelessNetworkConnection - range: 200 - - type: DeviceNetworkRequiresPower - - type: UserInterface - interfaces: - enum.SurveillanceCameraSetupUiKey.Router: - type: SurveillanceCameraSetupBoundUi - - type: Machine - board: SurveillanceCameraWirelessRouterCircuitboard - - type: Sprite - sprite: Structures/Machines/server.rsi - layers: - - state: server-off - - state: server-on - visible: false - map: ["enum.PowerDeviceVisualLayers.Powered"] - - state: server_o - map: ["enum.WiresVisualLayers.MaintenancePanel"] - - type: GenericVisualizer - visuals: - enum.PowerDeviceVisuals.Powered: - enum.PowerDeviceVisualLayers.Powered: - True: { visible: true } - False: { visible: false } - - type: Destructible - thresholds: - - trigger: !type:DamageTrigger - damage: 175 - behaviors: - - !type:PlaySoundBehavior - sound: - collection: MetalBreak - - type: Appearance - - type: AmbientOnPowered - - type: AmbientSound - volume: -9 - range: 5 - enabled: false - sound: - collection: ServerFans - - type: WiresVisuals - - type: WiresPanel + - type: Sprite + sprite: Structures/Machines/server.rsi + layers: + - state: server-off + - state: server-on + visible: false + map: ["enum.PowerDeviceVisualLayers.Powered"] + - state: server_o + map: ["enum.WiresVisualLayers.MaintenancePanel"] + - type: GenericVisualizer + visuals: + enum.PowerDeviceVisuals.Powered: + enum.PowerDeviceVisualLayers.Powered: + True: { visible: true } + False: { visible: false } + - type: Appearance + - type: AmbientOnPowered + - type: AmbientSound + volume: -9 + range: 5 + enabled: false + sound: + collection: ServerFans + - type: WiresVisuals + - type: WiresPanel + - type: Machine + board: SurveillanceCameraWirelessRouterCircuitboard + - type: Destructible + thresholds: + - trigger: !type:DamageTrigger + damage: 175 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: MetalBreak + - type: DeviceNetwork + deviceNetId: Wireless + receiveFrequencyId: SurveillanceCamera + transmitFrequencyId: SurveillanceCamera + prefix: device-address-prefix-camera-router-wireless + - type: WirelessNetworkConnection + range: 200 + - type: DeviceNetworkRequiresPower + - type: UserInterface + interfaces: + enum.SurveillanceCameraSetupUiKey.Router: + type: SurveillanceCameraSetupBoundUi - type: entity parent: SurveillanceCameraWirelessRouterBase id: SurveillanceCameraWirelessRouterConstructed suffix: Constructed components: - - type: SurveillanceCameraRouter - setupAvailableNetworks: - - SurveillanceCameraEntertainment + - type: SurveillanceCameraRouter + setupAvailableNetworks: + - SurveillanceCameraEntertainment - type: entity parent: SurveillanceCameraWirelessRouterBase @@ -209,8 +213,8 @@ name: entertainment camera router suffix: Entertainment components: - - type: SurveillanceCameraRouter - subnetFrequency: SurveillanceCameraEntertainment + - type: SurveillanceCameraRouter + subnetFrequency: SurveillanceCameraEntertainment - type: entity parent: SurveillanceCameraWirelessRouterBase diff --git a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml index 2dc2baa5f4..ecee7ae7d8 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml @@ -226,6 +226,7 @@ deviceNetId: Wired receiveFrequencyId: MailingUnit transmitFrequencyId: MailingUnit + - type: DeviceNetworkRequiresPower - type: WiredNetworkConnection - type: Configuration config: diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/Monitors/telescreens.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/Monitors/telescreens.yml index 8689dc698b..1f29d6b846 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/Monitors/telescreens.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/Monitors/telescreens.yml @@ -44,6 +44,7 @@ deviceNetId: Wired receiveFrequencyId: SurveillanceCamera transmitFrequencyId: SurveillanceCamera + prefix: device-address-prefix-camera-monitor - type: WiredNetworkConnection - type: DeviceNetworkRequiresPower - type: SurveillanceCameraMonitor diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/air_alarm.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/air_alarm.yml index 3fc723257e..7d435f2d22 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/air_alarm.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/air_alarm.yml @@ -51,12 +51,15 @@ group: AirAlarm - type: Clickable - type: InteractionOutline + - type: ActivatableUI + key: enum.SharedAirAlarmInterfaceKey.Key - type: UserInterface interfaces: enum.SharedAirAlarmInterfaceKey.Key: type: AirAlarmBoundUserInterface enum.WiresUiKey.Key: type: WiresBoundUserInterface + - type: ActivatableUIRequiresPower - type: WiresPanel - type: Wires boardName: wires-board-name-airalarm diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/surveillance_camera.yml index 44bf6537c6..c9d0250cb8 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/surveillance_camera.yml @@ -9,8 +9,20 @@ snap: - Wallmount components: + - type: Transform + anchored: true + - type: Sprite + drawdepth: WallMountedItems + sprite: Structures/Wallmounts/camera.rsi + offset: 0, -0.5 + layers: + - map: [ "enum.SurveillanceCameraVisualsKey.Layer" ] + state: camera + - type: Appearance - type: Physics bodyType: Static + - type: Clickable + - type: InteractionOutline - type: Fixtures fixtures: light: @@ -29,57 +41,14 @@ - None layer: - TabletopMachineLayer - - type: CameraActiveOnCollide - requiresPower: false # TODO: Change this when AI can no longer see via unpowered cameras + - type: Eye - type: PointLight enabled: false radius: 5 - - type: SlimPoweredLight - enabled: false - - type: StationAiVision - - type: Clickable - - type: InteractionOutline - - type: Construction - graph: SurveillanceCamera - node: camera - - type: Electrified - enabled: false - usesApcPower: true - - type: WallMount - - type: ApcPowerReceiver - - type: ExtensionCableReceiver - - type: Eye - - type: WiredNetworkConnection - - type: DeviceNetworkRequiresPower - - type: Transform - anchored: true - - type: WiresPanel - - type: Wires - alwaysRandomize: true - layoutId: SurveillanceCamera - - type: Sprite - drawdepth: WallMountedItems - sprite: Structures/Wallmounts/camera.rsi - offset: 0, -0.5 - layers: - - map: [ "enum.SurveillanceCameraVisualsKey.Layer" ] - state: camera - - type: Appearance - - type: SurveillanceCameraVisuals - sprites: - Active: camera - Disabled: camera_off - InUse: camera_in_use - - type: UserInterface - interfaces: - enum.SurveillanceCameraSetupUiKey.Camera: - type: SurveillanceCameraSetupBoundUi - enum.WiresUiKey.Key: - type: WiresBoundUserInterface - - type: StaticPrice - price: 200 - type: Damageable damageModifierSet: SteelMod + - type: Injurable + damageContainer: StructuralInorganic - type: Destructible thresholds: &ThresholdsSurveilCamera - trigger: @@ -96,6 +65,43 @@ SheetSteel1: min: 0 max: 1 + - type: SlimPoweredLight + enabled: false + - type: Electrified + enabled: false + usesApcPower: true + - type: WallMount + - type: ApcPowerReceiver + - type: ExtensionCableReceiver + - type: WiresPanel + - type: Wires + alwaysRandomize: true + layoutId: SurveillanceCamera + - type: DeviceNetwork + deviceNetId: Wired + transmitFrequencyId: SurveillanceCamera + prefix: device-address-prefix-camera + - type: DeviceNetworkRequiresPower + - type: WiredNetworkConnection + - type: StationAiVision + - type: CameraActiveOnCollide + requiresPower: false # TODO: Change this when AI can no longer see via unpowered cameras + - type: Construction + graph: SurveillanceCamera + node: camera + - type: StaticPrice + price: 200 + - type: SurveillanceCameraVisuals + sprites: + Active: camera + Disabled: camera_off + InUse: camera_in_use + - type: UserInterface + interfaces: + enum.SurveillanceCameraSetupUiKey.Camera: + type: SurveillanceCameraSetupBoundUi + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: entity parent: SurveillanceCameraBase @@ -103,19 +109,16 @@ name: camera suffix: Constructed components: - - type: DeviceNetwork - deviceNetId: Wired - transmitFrequencyId: SurveillanceCamera - - type: SurveillanceCamera - setupAvailableNetworks: - - SurveillanceCameraEngineering - - SurveillanceCameraSecurity - - SurveillanceCameraService - - SurveillanceCameraSupply - - SurveillanceCameraScience - - SurveillanceCameraGeneral - - SurveillanceCameraMedical - - SurveillanceCameraCommand + - type: SurveillanceCamera + setupAvailableNetworks: + - SurveillanceCameraEngineering + - SurveillanceCameraSecurity + - SurveillanceCameraService + - SurveillanceCameraSupply + - SurveillanceCameraScience + - SurveillanceCameraGeneral + - SurveillanceCameraMedical + - SurveillanceCameraCommand - type: entity parent: SurveillanceCameraBase @@ -124,9 +127,8 @@ suffix: Engineering components: - type: DeviceNetwork - deviceNetId: Wired receiveFrequencyId: SurveillanceCameraEngineering - transmitFrequencyId: SurveillanceCamera + prefix: device-address-prefix-camera - type: SurveillanceCamera networkSet: true @@ -137,9 +139,7 @@ suffix: Security components: - type: DeviceNetwork - deviceNetId: Wired receiveFrequencyId: SurveillanceCameraSecurity - transmitFrequencyId: SurveillanceCamera - type: SurveillanceCamera networkSet: true @@ -150,9 +150,7 @@ suffix: Science components: - type: DeviceNetwork - deviceNetId: Wired receiveFrequencyId: SurveillanceCameraScience - transmitFrequencyId: SurveillanceCamera - type: SurveillanceCamera networkSet: true @@ -163,9 +161,7 @@ suffix: Supply components: - type: DeviceNetwork - deviceNetId: Wired receiveFrequencyId: SurveillanceCameraSupply - transmitFrequencyId: SurveillanceCamera - type: SurveillanceCamera networkSet: true @@ -176,9 +172,7 @@ suffix: Command components: - type: DeviceNetwork - deviceNetId: Wired receiveFrequencyId: SurveillanceCameraCommand - transmitFrequencyId: SurveillanceCamera - type: SurveillanceCamera networkSet: true @@ -189,9 +183,7 @@ suffix: Service components: - type: DeviceNetwork - deviceNetId: Wired receiveFrequencyId: SurveillanceCameraService - transmitFrequencyId: SurveillanceCamera - type: SurveillanceCamera networkSet: true @@ -202,9 +194,7 @@ suffix: Medical components: - type: DeviceNetwork - deviceNetId: Wired receiveFrequencyId: SurveillanceCameraMedical - transmitFrequencyId: SurveillanceCamera - type: SurveillanceCamera networkSet: true @@ -215,9 +205,7 @@ suffix: General components: - type: DeviceNetwork - deviceNetId: Wired receiveFrequencyId: SurveillanceCameraGeneral - transmitFrequencyId: SurveillanceCamera - type: SurveillanceCamera networkSet: true @@ -231,20 +219,20 @@ snap: - Wallmount components: - - type: Clickable - - type: InteractionOutline - - type: Construction - graph: SurveillanceCamera - node: assembly - - type: WallMount - - type: Transform - anchored: true - - type: Damageable - damageModifierSet: SteelMod - - type: Destructible - thresholds: *ThresholdsSurveilCamera - - type: Sprite - drawdepth: WallMountedItems - sprite: Structures/Wallmounts/camera.rsi - layers: - - state: camera_off + - type: Transform + anchored: true + - type: Sprite + drawdepth: WallMountedItems + sprite: Structures/Wallmounts/camera.rsi + layers: + - state: camera_off + - type: Clickable + - type: InteractionOutline + - type: Damageable + damageModifierSet: SteelMod + - type: Destructible + thresholds: *ThresholdsSurveilCamera + - type: Construction + graph: SurveillanceCamera + node: assembly + - type: WallMount diff --git a/Resources/Prototypes/Entities/Structures/gates.yml b/Resources/Prototypes/Entities/Structures/gates.yml index 46faf923e0..c86c869500 100644 --- a/Resources/Prototypes/Entities/Structures/gates.yml +++ b/Resources/Prototypes/Entities/Structures/gates.yml @@ -24,6 +24,8 @@ receiveFrequencyId: BasicDevice - type: WirelessNetworkConnection range: 200 + - type: SoundOnOverload + - type: SpawnOnOverload - type: entity parent: BaseLogicItem