mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 10:21:18 +03:00
Device Network refactor part 1: API improvements (#44346)
* Refactor DeviceNetwork * Singleton * NetworkPayloads refactor * Reorganize DeviceNetworkSystem * Surveillance cameras * Fix code * Fix build * Fix test fail by rewriting entire singleton logic * Properly predict examine * Update DeviceNetworkSystem.API.cs * Update EntityTest.cs * Update DeviceNetworkSystem.cs * Alright I'll do this expensive check fine * Fix disposals debug assert * Implement device network static events support * Use frozen dictionaries for performance * Update SharedDeviceNetworkSystem.Payloads.cs * Parallel payload handling support * Fix some spagetti-code * Optimize NetworkPayload cancellation * Parallel payloads are now cancellable * Fix screens * Fix robotics console * Allow new methods for shared * Mail fix * Turret fix * Fix network system method usage + signal and borg fix * finally fix atmos devices OH MY GOOOD * Remove stupid parallelism from fax * Fix surveiollance cameras * Working on a single thing for 2 days straight award * Fix the test? * Update units.yml * Add IDevice interface because why not * Add more device network suffixes * Fix camera router failing test * yaml linter peak * Improve docs for DeviceNetworkHandlers * fix build * Update CartridgeLoaderSystem.Relay.cs * Remove parallel system and EntitySystem post init * Add more docs and also events * Remove unnecessary caching * Update DevicePayloadComponentSystem.cs * Back to entity events * Implement DeviceData * Remove serializable from payloads * Update DeviceData.cs * Add a prototype for a singleton * Fix tests * Fix air alarms * Update DeviceNetworkSystem.cs * Fix cameras * Make camera router event-less * Fix atmos sync payloads, add more docs * Remove singleton + instant packets * oops remove public access * Fix tests? * Why the hell overload effect makes puddle sparks * Apparently it was redundant * Update gates.yml * Finish documentation * Review * Mark relay properties as obsolete * Struct payloads support (#blazinglyfastmemorysafe) * Update DeviceNetworkTest.cs * Make device structs stuff better * Move address prefix to DeviceNetworkComponent * Locale fixes * Fix tests * Doesn't know boolean logic award * Update AtmosAlarmableSystem.cs * Fix address predicted examine * Partial fix to air alarmables * Fix deployable turrets UI * Fix firelocks, maybe * Apparently Activatable UI was enough lol * Fix surveillance cameras * Rename `QueuePacket` into `SendPacket` * Simplify DeviceData as much as possible * Update DeviceData.cs * Update FaxMachineComponent.cs * Remove DeviceData because its stupid * Update ScreenSystem.cs * Fix build (camera map broken still) * Fix map * fix usings * Review changes * Build fix
This commit is contained in:
parent
0b2245ff2c
commit
cc2c14f8e4
149 changed files with 3573 additions and 3260 deletions
|
|
@ -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<EntityUid> _targetEntities = new();
|
||||
private readonly List<EntityUid> _targetWirelessEntities = new();
|
||||
|
||||
|
||||
private NetworkPayload _payload = default!;
|
||||
|
||||
[TestPrototypes]
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
|
|
@ -54,7 +50,7 @@ public class DeviceNetworkingBenchmark
|
|||
//public static IEnumerable<int> 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<DeviceNetworkSystem>();
|
||||
_deviceNetTestSystem = entityManager.EntitySysManager.GetEntitySystem<DeviceNetworkTestSystem>();
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Content.Client.Atmos.Monitor.UI;
|
|||
public sealed partial class AirAlarmWindow : FancyWindow
|
||||
{
|
||||
public event Action<string, IAtmosDeviceData>? AtmosDeviceDataChanged;
|
||||
public event Action<IAtmosDeviceData>? AtmosDeviceDataCopied;
|
||||
public event Action<IAtmosDeviceData>? AtmosDeviceDataCopied;
|
||||
public event Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? AtmosAlarmThresholdChanged;
|
||||
public event Action<AirAlarmMode>? AirAlarmModeChanged;
|
||||
public event Action<bool>? 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);
|
||||
|
|
|
|||
|
|
@ -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<string, IAtmosDeviceData>? 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<VentPressureBound>())
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string, IAtmosDeviceData>? ScrubberDataChanged;
|
||||
|
|
@ -34,7 +34,7 @@ public sealed partial class ScrubberControl : BoxContainer
|
|||
private GridContainer _gases => CGasContainer;
|
||||
private Dictionary<Gas, Button> _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<Gas>();
|
||||
_selectAll.OnPressed += _ =>
|
||||
{
|
||||
_data.FilterGases = new HashSet<Gas>(allGases);
|
||||
ScrubberDataChanged?.Invoke(_address, _data);
|
||||
_dataPayload.FilterGases = new HashSet<Gas>(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<Gas>())
|
||||
{
|
||||
_gasControls[value].Pressed = data.FilterGases.Contains(value);
|
||||
_gasControls[value].Pressed = dataPayload.FilterGases.Contains(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public sealed partial class SensorInfo : BoxContainer
|
|||
[Dependency] private IEntityManager _entMan = default!;
|
||||
|
||||
public Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? OnThresholdUpdate;
|
||||
public event Action<AtmosSensorData>? SensorDataCopied;
|
||||
public event Action<AtmosMonitorData>? SensorDataCopied;
|
||||
private string _address;
|
||||
|
||||
private ThresholdControl _pressureThreshold;
|
||||
|
|
@ -27,7 +27,7 @@ public sealed partial class SensorInfo : BoxContainer
|
|||
private Dictionary<Gas, RichTextLabel> _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<SharedAtmosphereSystem>();
|
||||
|
|
@ -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<GasPrototype> 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<SharedAtmosphereSystem>();
|
||||
|
||||
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<GasPrototype> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<SuitSensorStatus>();
|
||||
// TODO too much evil LINQ going on here
|
||||
var orderedSensors = uniqueSensors.OrderBy(n => n.Name).ThenBy(j => j.Job);
|
||||
var assignedSensors = new List<SuitSensorStatus>();
|
||||
var departments = uniqueSensors.SelectMany(d => d.JobDepartments).Distinct().OrderBy(n => n);
|
||||
|
||||
// Create department labels and populate lists
|
||||
|
|
|
|||
|
|
@ -180,9 +180,10 @@ public sealed partial class SurveillanceCameraMonitorWindow : DefaultWindow
|
|||
private int AddSubnet(ProtoId<DeviceFrequencyPrototype> 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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkSystem>();
|
||||
var deviceNetTestSystem = entityManager.EntitySysManager.GetEntitySystem<DeviceNetworkTestSystem>();
|
||||
|
||||
|
||||
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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
SubscribeLocalEvent<DeviceNetworkComponent, DeviceNetworkPacketData>(OnBaselinePacketReceived);
|
||||
SubscribeLocalEvent<DeviceNetworkComponent, DeviceNetworkPacketEvent<TestPayload>>(OnTypedPacketReceived);
|
||||
SubscribeLocalEvent<DeviceNetworkComponent, DeviceNetworkPacketEvent<SecondTestPayload>>(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<DeviceNetworkComponent> ent, ref DeviceNetworkPacketData args)
|
||||
{
|
||||
LastPayloadClass = (TestPayloadClass) args.Data;
|
||||
}
|
||||
|
||||
private void OnTypedPacketReceived(Entity<DeviceNetworkComponent> ent, ref DeviceNetworkPacketEvent<TestPayload> args)
|
||||
{
|
||||
LastPayload = args.Data;
|
||||
}
|
||||
|
||||
private void OnTypedPacketReceived(Entity<DeviceNetworkComponent> ent, ref DeviceNetworkPacketEvent<SecondTestPayload> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,6 @@ public sealed partial class TechAnomalySystem : EntitySystem
|
|||
|
||||
private void OnPulse(Entity<TechAnomalyComponent> tech, ref AnomalyPulseEvent args)
|
||||
{
|
||||
_signal.InvokePort(tech, tech.Comp.PulsePort);
|
||||
_signal.InvokePort(tech.Owner, tech.Comp.PulsePort);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed partial class AirAlarmComponent : Component
|
|||
public readonly HashSet<string> KnownDevices = new();
|
||||
public readonly Dictionary<string, GasVentPumpData> VentData = new();
|
||||
public readonly Dictionary<string, GasVentScrubberData> ScrubberData = new();
|
||||
public readonly Dictionary<string, AtmosSensorData> SensorData = new();
|
||||
public readonly Dictionary<string, AtmosMonitorData> SensorData = new();
|
||||
|
||||
public bool CanSync = true;
|
||||
|
||||
|
|
|
|||
23
Content.Server/Atmos/Monitor/Payloads/AirAlarmPayloads.cs
Normal file
23
Content.Server/Atmos/Monitor/Payloads/AirAlarmPayloads.cs
Normal file
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// A network payload sent to an air alarm to set its mode.
|
||||
/// </summary>
|
||||
public partial record struct AirAlarmSetModePayload : INetworkPayload
|
||||
{
|
||||
[DataField]
|
||||
public AirAlarmMode Mode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A network payload sent from an atmos device to an air alarm to update its UI.
|
||||
/// </summary>
|
||||
public partial record struct AirAlarmSetDataPayload : INetworkPayload
|
||||
{
|
||||
[DataField]
|
||||
public IAtmosDeviceData Payload;
|
||||
}
|
||||
|
|
@ -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<ProtoId<TagPrototype>> Source { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Broadcasts an atmos alarm.
|
||||
/// </summary>
|
||||
public partial record struct AtmosAlarmPayload : IAtmosAlarmableSourcePayload
|
||||
{
|
||||
[DataField]
|
||||
public AtmosAlarmType Type;
|
||||
|
||||
[DataField]
|
||||
public AtmosMonitorThresholdTypeFlags? TrippedThresholds;
|
||||
|
||||
[DataField]
|
||||
public HashSet<ProtoId<TagPrototype>> Source { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Synchronizes the data of an atmos alarmable to all other alarmable devices.
|
||||
/// </summary>
|
||||
public partial record struct AtmosAlarmableSyncAlertsPayload : IAtmosAlarmableSourcePayload
|
||||
{
|
||||
[DataField]
|
||||
public Dictionary<string, AtmosAlarmType> AlarmStates = new();
|
||||
|
||||
[DataField]
|
||||
public HashSet<ProtoId<TagPrototype>> Source { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the state of an atmos alarmable to Normal.
|
||||
/// </summary>
|
||||
public partial record struct AtmosAlarmableResetAllPayload : IAtmosAlarmableSourcePayload
|
||||
{
|
||||
[DataField]
|
||||
public HashSet<ProtoId<TagPrototype>> Source { get; set; } = new();
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Used for synchronizing the sender device and adding its address to all listeners.
|
||||
/// </summary>
|
||||
public partial record struct AtmosMonitorRegisterDevicePayload : INetworkPayload;
|
||||
|
||||
/// <summary>
|
||||
/// Removes the sender device from all listeners of this payload.
|
||||
/// </summary>
|
||||
public partial record struct AtmosMonitorDeregisterDevicePayload : INetworkPayload;
|
||||
|
||||
/// <summary>
|
||||
/// Sets specific threshold on the target atmos device.
|
||||
/// </summary>
|
||||
public partial record struct AtmosMonitorSetThresholdPayload : INetworkPayload
|
||||
{
|
||||
[DataField]
|
||||
public AtmosMonitorThresholdType Type;
|
||||
|
||||
[DataField]
|
||||
public AtmosAlarmThreshold Threshold;
|
||||
|
||||
[DataField]
|
||||
public Gas? Gas;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets thresholds on all connected devices.
|
||||
/// </summary>
|
||||
public partial record struct AtmosMonitorSetAllThresholdsPayload : INetworkPayload
|
||||
{
|
||||
[DataField]
|
||||
public AtmosMonitorData Data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the alarm state of a <see cref="AtmosMonitorComponent"/> to Normal
|
||||
/// and broadcasts it to all listening <see cref="AtmosAlarmableComponent"/>.
|
||||
/// </summary>
|
||||
public partial record struct AtmosMonitorResetPayload : INetworkPayload;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
using Content.Shared.DeviceNetwork;
|
||||
|
||||
namespace Content.Server.Atmos.Monitor.Payloads;
|
||||
|
||||
/// <summary>
|
||||
/// A general payload that when sent to an atmos device forces it to respond with its data payload.
|
||||
/// </summary>
|
||||
public partial record struct AtmosSyncPayload : INetworkPayload;
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkComponent> _deviceNetworkQuery = default!;
|
||||
|
||||
#region Device Network API
|
||||
|
||||
/// <summary>
|
||||
/// Command to set an air alarm's mode.
|
||||
/// </summary>
|
||||
public const string AirAlarmSetMode = "air_alarm_set_mode";
|
||||
|
||||
// -- API --
|
||||
|
||||
/// <summary>
|
||||
/// Set the data for an air alarm managed device.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of the device.</param>
|
||||
/// <param name="data">The data to send to the device.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -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<AtmosMonitorComponent>(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<AirAlarmComponent, DeviceNetworkPacketEvent>(OnPacketRecv);
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<AirAlarmComponent, AtmosDeviceUpdateEvent>(OnAtmosUpdate);
|
||||
SubscribeLocalEvent<AirAlarmComponent, AtmosAlarmEvent>(OnAtmosAlarm);
|
||||
SubscribeLocalEvent<AirAlarmComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
|
|
@ -178,7 +170,7 @@ public sealed partial class AirAlarmSystem : EntitySystem
|
|||
SubscribeLocalEvent<AirAlarmComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<AirAlarmComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<AirAlarmComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<AirAlarmComponent, ActivateInWorldEvent>(OnActivate);
|
||||
SubscribeLocalEvent<AirAlarmComponent, AfterActivatableUIOpenEvent>(OnActivate);
|
||||
|
||||
Subs.BuiEvents<AirAlarmComponent>(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<WiresPanelComponent>(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<DeviceLinkSourceComponent>(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
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets device data. Practically a wrapper around the packet sending function, SetData.
|
||||
/// Sets device data.
|
||||
/// </summary>
|
||||
/// <param name="address">The address to send the new data to.</param>
|
||||
/// <param name="devData">The device data to be sent.</param>
|
||||
|
|
@ -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<AirAlarmComponent> ent, ref DeviceNetworkPacketEvent<AirAlarmSetDataPayload> 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<AirAlarmComponent> ent, ref DeviceNetworkPacketEvent<AirAlarmSetModePayload> args)
|
||||
{
|
||||
SetMode(ent, args.SenderAddress, args.Data.Mode, uiOnly: false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -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!;
|
||||
|
||||
/// <summary>
|
||||
/// An alarm. Has three valid states: Normal, Warning, Danger.
|
||||
/// Will attempt to fetch the tags from the alarming entity
|
||||
/// to send over.
|
||||
/// </summary>
|
||||
public const string AlertCmd = "atmos_alarm";
|
||||
|
||||
public const string AlertSource = "atmos_alarm_source";
|
||||
|
||||
public const string AlertTypes = "atmos_alarm_types";
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public const string SyncAlerts = "atmos_alarmable_sync_alerts";
|
||||
|
||||
public const string ResetAll = "atmos_alarmable_reset_all";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<AtmosAlarmableComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<AtmosAlarmableComponent, DeviceNetworkPacketEvent>(OnPacketRecv);
|
||||
SubscribeLocalEvent<AtmosAlarmableComponent, PowerChangedEvent>(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<AtmosAlarmableComponent> ent, ref DeviceNetworkPacketEvent<AtmosAlarmPayload> 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<ProtoId<TagPrototype>>? 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<AtmosAlarmableComponent> ent, ref DeviceNetworkPacketEvent<AtmosAlarmableResetAllPayload> 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<AtmosAlarmableComponent> ent, ref DeviceNetworkPacketEvent<AtmosAlarmableSyncAlertsPayload> 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<string, AtmosAlarmType>? 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<T>(Entity<AtmosAlarmableComponent> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the state of this alarmable to normal.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="alarmable"></param>
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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;
|
|||
/// </summary>
|
||||
public sealed partial class AtmosDeviceNetworkSystem : EntitySystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Register a device's address on this device.
|
||||
/// </summary>
|
||||
public const string RegisterDevice = "atmos_register_device";
|
||||
|
||||
/// <summary>
|
||||
/// Deregister a device's address on this device.
|
||||
/// </summary>
|
||||
public const string DeregisterDevice = "atmos_deregister_device";
|
||||
|
||||
/// <summary>
|
||||
/// Synchronize the data this device has with the sender.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<AtmosMonitorComponent, ComponentStartup>(OnAtmosMonitorStartup);
|
||||
SubscribeLocalEvent<AtmosMonitorComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<AtmosMonitorComponent, AtmosDeviceUpdateEvent>(OnAtmosUpdate);
|
||||
SubscribeLocalEvent<AtmosMonitorComponent, TileFireEvent>(OnFireEvent);
|
||||
SubscribeLocalEvent<AtmosMonitorComponent, PowerChangedEvent>(OnPowerChangedEvent);
|
||||
SubscribeLocalEvent<AtmosMonitorComponent, BeforePacketSentEvent>(BeforePacketRecv);
|
||||
SubscribeLocalEvent<AtmosMonitorComponent, DeviceNetworkPacketEvent>(OnPacketRecv);
|
||||
SubscribeLocalEvent<AtmosMonitorComponent, AtmosDeviceDisabledEvent>(OnAtmosDeviceLeaveAtmosphere);
|
||||
SubscribeLocalEvent<AtmosMonitorComponent, AtmosDeviceEnabledEvent>(OnAtmosDeviceEnterAtmosphere);
|
||||
SubscribeLocalEvent<AtmosMonitorComponent, AtmosDeviceTileChangedEvent>(OnAtmosDeviceTileChangedEvent);
|
||||
|
|
@ -112,74 +101,73 @@ public sealed partial class AtmosMonitorSystem : EntitySystem
|
|||
}
|
||||
}
|
||||
|
||||
private void BeforePacketRecv(EntityUid uid, AtmosMonitorComponent component, BeforePacketSentEvent args)
|
||||
private void BeforePacketRecv(Entity<AtmosMonitorComponent> 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<AtmosMonitorComponent> ent, ref DeviceNetworkPacketEvent<AtmosMonitorRegisterDevicePayload> 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<AtmosMonitorComponent> ent, ref DeviceNetworkPacketEvent<AtmosMonitorDeregisterDevicePayload> args)
|
||||
{
|
||||
ent.Comp.RegisteredDevices.Remove(args.SenderAddress);
|
||||
}
|
||||
|
||||
[SubscribeLocalEvent]
|
||||
private void OnReset(Entity<AtmosMonitorComponent> ent, ref DeviceNetworkPacketEvent<AtmosMonitorResetPayload> args)
|
||||
{
|
||||
Reset(ent);
|
||||
}
|
||||
|
||||
[SubscribeLocalEvent]
|
||||
private void OnSetThreshold(Entity<AtmosMonitorComponent> ent, ref DeviceNetworkPacketEvent<AtmosMonitorSetThresholdPayload> args)
|
||||
{
|
||||
SetThreshold(ent, args.Data.Type, args.Data.Threshold, args.Data.Gas);
|
||||
}
|
||||
|
||||
[SubscribeLocalEvent]
|
||||
private void OnSetAllThresholds(Entity<AtmosMonitorComponent> ent, ref DeviceNetworkPacketEvent<AtmosMonitorSetAllThresholdsPayload> args)
|
||||
{
|
||||
SetAllThresholds(ent, args.Data.Data);
|
||||
}
|
||||
|
||||
[SubscribeLocalEvent]
|
||||
private void OnSyncPayload(Entity<AtmosMonitorComponent> ent, ref DeviceNetworkPacketEvent<AtmosSyncPayload> args)
|
||||
{
|
||||
var dataPayload = new AtmosMonitorData();
|
||||
if (ent.Comp.TileGas != null)
|
||||
{
|
||||
return;
|
||||
var gases = new Dictionary<Gas, float>();
|
||||
foreach (var gas in Enum.GetValues<Gas>())
|
||||
{
|
||||
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<Gas, float>();
|
||||
foreach (var gas in Enum.GetValues<Gas>())
|
||||
{
|
||||
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<AtmosMonitorComponent> 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.
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity's uid</param>
|
||||
/// <param name="allThresholdData">An AtmosSensorData object from which the thresholds will be loaded.</param>
|
||||
public void SetAllThresholds(EntityUid uid, AtmosSensorData allThresholdData)
|
||||
/// <param name="allThresholdDataPayload">An AtmosSensorData object from which the thresholds will be loaded.</param>
|
||||
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<Gas>())
|
||||
{
|
||||
SetThreshold(uid, AtmosMonitorThresholdType.Gas, allThresholdData.GasThresholds[gas], gas);
|
||||
SetThreshold(uid, AtmosMonitorThresholdType.Gas, allThresholdDataPayload.GasThresholds[gas], gas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<GasVolumePumpComponent, AtmosDeviceUpdateEvent>(OnVolumePumpUpdated);
|
||||
SubscribeLocalEvent<GasVolumePumpComponent, AtmosDeviceDisabledEvent>(OnVolumePumpLeaveAtmosphere);
|
||||
|
||||
SubscribeLocalEvent<GasVolumePumpComponent, DeviceNetworkPacketEvent>(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<GasVolumePumpComponent> ent, ref DeviceNetworkPacketEvent<AtmosSyncPayload> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<GasThermoMachineComponent, AtmosDeviceUpdateEvent>(OnThermoMachineUpdated);
|
||||
|
||||
// Device network
|
||||
SubscribeLocalEvent<GasThermoMachineComponent, DeviceNetworkPacketEvent>(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<GasThermoMachineComponent> ent, ref DeviceNetworkPacketEvent<AtmosSyncPayload> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<GasVentPumpComponent, AtmosDeviceEnabledEvent>(OnGasVentPumpEnterAtmosphere);
|
||||
SubscribeLocalEvent<GasVentPumpComponent, AtmosAlarmEvent>(OnAtmosAlarm);
|
||||
SubscribeLocalEvent<GasVentPumpComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
SubscribeLocalEvent<GasVentPumpComponent, DeviceNetworkPacketEvent>(OnPacketRecv);
|
||||
SubscribeLocalEvent<GasVentPumpComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<GasVentPumpComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<GasVentPumpComponent, SignalReceivedEvent>(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<GasVentPumpComponent> ent, ref DeviceNetworkPacketEvent<AtmosSyncPayload> 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<GasVentPumpComponent> ent, ref DeviceNetworkPacketEvent<GasVentPumpSetDataPayload> 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)
|
||||
|
|
|
|||
|
|
@ -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<GasVentScrubberComponent, AtmosDeviceDisabledEvent>(OnVentScrubberLeaveAtmosphere);
|
||||
SubscribeLocalEvent<GasVentScrubberComponent, AtmosAlarmEvent>(OnAtmosAlarm);
|
||||
SubscribeLocalEvent<GasVentScrubberComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
SubscribeLocalEvent<GasVentScrubberComponent, DeviceNetworkPacketEvent>(OnPacketRecv);
|
||||
SubscribeLocalEvent<GasVentScrubberComponent, WeldableChangedEvent>(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<GasVentScrubberComponent> ent, ref DeviceNetworkPacketEvent<AtmosSyncPayload> 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<GasVentScrubberComponent> ent, ref DeviceNetworkPacketEvent<GasVentScrubberSetDataPayload> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkComponent>(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}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,5 +16,5 @@ public sealed partial class SpawnOnOverloadComponent : Component
|
|||
/// The entity prototype to spawn when the device overloads
|
||||
/// </summary>
|
||||
[DataField("spawnedPrototype")]
|
||||
public EntProtoId Prototype = "PuddleSparkle";
|
||||
public EntProtoId Prototype = "EffectSparks";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DeviceLinkSinkComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
SubscribeLocalEvent<DeviceLinkSourceComponent, NewLinkEvent>(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<DeviceLinkSinkComponent, DeviceNetworkPacketEvent<SignalPayload<LogicStatePayload>>>(OnSignalReceived);
|
||||
}
|
||||
|
||||
private void OnSignalReceived<T>(Entity<DeviceLinkSinkComponent> ent,
|
||||
ref DeviceNetworkPacketEvent<SignalPayload<T>> args) where T : ISignalNetworkPayload
|
||||
{
|
||||
var (uid, component) = ent;
|
||||
if (!component.Ports.Contains(args.Data.InvokedPort))
|
||||
return;
|
||||
|
||||
var eventArgs = new SignalReceivedEvent<T>(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<DeviceLinkSourceComponent?> 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<DeviceLinkSinkComponent>(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<T>(Entity<DeviceLinkSourceComponent?> 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
|
|||
/// <summary>
|
||||
/// Raises an event on or sends a network packet directly to a sink from a source.
|
||||
/// </summary>
|
||||
private void InvokeDirect(Entity<DeviceLinkSourceComponent> source, Entity<DeviceLinkSinkComponent?> sink, string sourcePort, string sinkPort, NetworkPayload? data)
|
||||
private void InvokeDirect(Entity<DeviceLinkSourceComponent> source,
|
||||
Entity<DeviceLinkSinkComponent?> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises an event on or sends a network packet directly to a sink from a source.
|
||||
/// </summary>
|
||||
private void InvokeDirect<T>(Entity<DeviceLinkSourceComponent> source,
|
||||
Entity<DeviceLinkSinkComponent?> 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<DeviceNetworkComponent>(source) || !TryComp<DeviceNetworkComponent>(sink, out var sinkNetwork))
|
||||
{
|
||||
var eventArgs = new SignalReceivedEvent(sinkPort, source);
|
||||
RaiseLocalEvent(sink, ref eventArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
var payload = new SignalPayload<T>
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function that invokes a port with a high/low binary logic signal.
|
||||
/// </summary>
|
||||
public void SendSignal(EntityUid uid, string port, bool signal, DeviceLinkSourceComponent? comp = null)
|
||||
public void SendSignal(Entity<DeviceLinkSourceComponent?> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -116,7 +190,7 @@ public sealed partial class DeviceLinkSystem : SharedDeviceLinkSystem
|
|||
/// </summary>
|
||||
public void ClearSignal(Entity<DeviceLinkSourceComponent?> 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 <see cref="SignalReceivedEvent"/> containing the payload when the check passes
|
||||
/// </summary>
|
||||
private void OnPacketReceived(EntityUid uid, DeviceLinkSinkComponent component, DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnSignalReceived(Entity<DeviceLinkSinkComponent> ent, ref DeviceNetworkPacketEvent<SignalPayload> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When linking from a port that currently has a signal being sent, invoke the new link with that signal.
|
||||
/// </summary>
|
||||
[SubscribeLocalEvent]
|
||||
private void OnNewLink(Entity<DeviceLinkSourceComponent> 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DoorBoltComponent>(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<LogicStatePayload> 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)
|
||||
|
|
|
|||
|
|
@ -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<EdgeDetectorComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<EdgeDetectorComponent, SignalReceivedEvent>(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<LogicStatePayload> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<LogicStatePayload> args)
|
||||
{
|
||||
var state = args.Data.State;
|
||||
|
||||
// update the state for the correct port
|
||||
if (args.Port == comp.InputPortA)
|
||||
|
|
|
|||
|
|
@ -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<MemoryCellComponent> 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<MemoryCellComponent> ent, ref SignalReceivedEvent<LogicStatePayload> 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<MemoryCellComponent, DeviceLinkSourceComponent?> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ namespace Content.Server.DeviceNetwork.Systems
|
|||
/// <summary>
|
||||
/// Checks if both devices are connected to the same apc
|
||||
/// </summary>
|
||||
private void OnBeforePacketSent(EntityUid uid, ApcNetworkComponent receiver, BeforePacketSentEvent args)
|
||||
private void OnBeforePacketSent(Entity<ApcNetworkComponent> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkComponent> _deviceNetworkQuery = default!;
|
||||
|
||||
public override void Initialize()
|
||||
|
|
@ -82,17 +84,18 @@ public sealed partial class DeviceListSystem : SharedDeviceListSystem
|
|||
/// <summary>
|
||||
/// Filters the broadcasts recipient list against the device list as either an allow or deny list depending on the components IsAllowList field
|
||||
/// </summary>
|
||||
private void OnBeforeBroadcast(EntityUid uid, DeviceListComponent component, BeforeBroadcastAttemptEvent args)
|
||||
private void OnBeforeBroadcast(Entity<DeviceListComponent> 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<DeviceNetworkComponent> filteredRecipients = new(args.Recipients.Count);
|
||||
HashSet<Device> filteredRecipients = new(args.Recipients.Count);
|
||||
|
||||
foreach (var recipient in args.Recipients)
|
||||
{
|
||||
|
|
@ -106,10 +109,10 @@ public sealed partial class DeviceListSystem : SharedDeviceListSystem
|
|||
/// <summary>
|
||||
/// Filters incoming packets if that is enabled <see cref="OnBeforeBroadcast"/>
|
||||
/// </summary>
|
||||
private void OnBeforePacketSent(EntityUid uid, DeviceListComponent component, BeforePacketSentEvent args)
|
||||
private void OnBeforePacketSent(Entity<DeviceListComponent> 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<DeviceListComponent?> list, Entity<DeviceNetworkComponent> device)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkRequiresPowerComponent, BeforePacketSentEvent>(OnBeforePacketSent);
|
||||
}
|
||||
|
||||
private void OnBeforePacketSent(EntityUid uid, DeviceNetworkRequiresPowerComponent component,
|
||||
BeforePacketSentEvent args)
|
||||
private void OnBeforePacketSent(Entity<DeviceNetworkRequiresPowerComponent> ent, ref BeforePacketSentEvent args)
|
||||
{
|
||||
if (!this.IsPowered(uid, EntityManager))
|
||||
if (!this.IsPowered(ent, EntityManager))
|
||||
{
|
||||
args.Cancel();
|
||||
args.Cancelled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
232
Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.API.cs
Normal file
232
Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.API.cs
Normal file
|
|
@ -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<T>(
|
||||
Entity<DeviceNetworkComponent?> 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<T>(network.Value, address, frequency.Value, device.Address, ent!, data);
|
||||
SendPacket(ref packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool ConnectDevice(Entity<DeviceNetworkComponent?> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect an entity with a DeviceNetworkComponent.
|
||||
/// </summary>
|
||||
/// <param name="ent">The entity to disconnect from its network.</param>
|
||||
/// <param name="preventAutoConnect">
|
||||
/// If true, sets <see cref="DeviceNetworkComponent.AutoConnect"/> to false.
|
||||
/// That way the device doesn't auto reconnect when a game state is loaded.
|
||||
/// </param>
|
||||
/// <returns>True if the device was removed from the network successfully.</returns>
|
||||
[PublicAPI]
|
||||
public bool DisconnectDevice(Entity<DeviceNetworkComponent?> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a device is already connected to its network.
|
||||
/// </summary>
|
||||
/// <returns>True if the device was found in the network with its corresponding network id.</returns>
|
||||
[PublicAPI]
|
||||
public bool IsDeviceConnected(Entity<DeviceNetworkComponent?> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if an address exists in the network with the given netId.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool IsAddressPresent(int netId, string? address)
|
||||
{
|
||||
if (address == null
|
||||
|| !_networks.TryGetValue(netId, out var network))
|
||||
return false;
|
||||
|
||||
return network.Devices.ContainsKey(address);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the receive frequency of an entity.
|
||||
/// </summary>
|
||||
/// <param name="ent">The target device.</param>
|
||||
/// <param name="frequency">The new frequency.</param>
|
||||
[PublicAPI]
|
||||
public void SetReceiveFrequency(Entity<DeviceNetworkComponent?> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the transmit frequency of an entity.
|
||||
/// </summary>
|
||||
/// <param name="ent">The target device.</param>
|
||||
/// <param name="frequency">The new frequency.</param>
|
||||
[PublicAPI]
|
||||
public void SetTransmitFrequency(Entity<DeviceNetworkComponent?> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the target device's ability to receive all network packets, regardless of the address.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void SetReceiveAll(Entity<DeviceNetworkComponent?> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the address of the target device.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void SetAddress(Entity<DeviceNetworkComponent?> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Randomizes the address of the target device.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void RandomizeAddress(Entity<DeviceNetworkComponent?> 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
/// <inheritdoc/>
|
||||
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<DeviceNetworkComponent> _deviceQuery = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class DeviceNetworkSystem : SharedDeviceNetworkSystem
|
||||
private readonly Dictionary<int, DeviceNet> _networks = new(4);
|
||||
|
||||
/// <summary>
|
||||
/// Automatically attempt to connect some devices when a map starts.
|
||||
/// </summary>
|
||||
[SubscribeLocalEvent]
|
||||
private void OnMapInit(Entity<DeviceNetworkComponent> 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<int, DeviceNet> _networks = new(4);
|
||||
private readonly Queue<DeviceNetworkPacketEvent> _queueA = new();
|
||||
private readonly Queue<DeviceNetworkPacketEvent> _queueB = new();
|
||||
|
||||
/// <summary>
|
||||
/// The queue being processed in the current tick
|
||||
/// </summary>
|
||||
private Queue<DeviceNetworkPacketEvent> _activeQueue = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The queue that will be processed in the next tick
|
||||
/// </summary>
|
||||
private Queue<DeviceNetworkPacketEvent> _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<DeviceNetworkComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<DeviceNetworkComponent, ComponentShutdown>(OnNetworkShutdown);
|
||||
SubscribeLocalEvent<DeviceNetworkComponent, ExaminedEvent>(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());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Automatically disconnect when an entity with a DeviceNetworkComponent shuts down.
|
||||
/// </summary>
|
||||
[SubscribeLocalEvent]
|
||||
private void OnNetworkShutdown(Entity<DeviceNetworkComponent> 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));
|
||||
/// <summary>
|
||||
/// Try to find a device on a network using its address.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get an already existing device network, and creates a new network if it doesn't exist.
|
||||
/// </summary>
|
||||
/// <returns>False if the manager is not initialized.</returns>
|
||||
/// <returns></returns>
|
||||
private bool TryEnsureNetwork(int netId, [NotNullWhen(true)] out DeviceNet? network)
|
||||
{
|
||||
network = null;
|
||||
|
||||
if (_networks.TryGetValue(netId, out var deviceNet))
|
||||
{
|
||||
network = deviceNet;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swaps the active queue.
|
||||
/// Queues are swapped so that packets being sent in the current tick get processed in the next tick.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This prevents infinite loops while sending packets
|
||||
/// </remarks>
|
||||
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)
|
||||
/// <summary>
|
||||
/// Tries to get an already existing network.
|
||||
/// </summary>
|
||||
/// <returns>False if the manager is not initialized, or the network wasn't found.</returns>
|
||||
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<T>(ref DeviceNetworkPacketEvent<T> 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<Device>.Shared.Rent(devices.Count);
|
||||
devices.CopyTo(deviceCopy);
|
||||
SendToConnections(deviceCopy.AsSpan(0, devices.Count), packet);
|
||||
ArrayPool<Device>.Shared.Return(deviceCopy);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Automatically attempt to connect some devices when a map starts.
|
||||
/// </summary>
|
||||
private void OnMapInit(EntityUid uid, DeviceNetworkComponent device, MapInitEvent args)
|
||||
else
|
||||
{
|
||||
if (device.ReceiveFrequency == null
|
||||
&& device.ReceiveFrequencyId != null
|
||||
&& ProtoMan.TryIndex<DeviceFrequencyPrototype>(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<DeviceFrequencyPrototype>(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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Automatically disconnect when an entity with a DeviceNetworkComponent shuts down.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public bool ConnectDevice(EntityUid uid, DeviceNetworkComponent? device = null)
|
||||
{
|
||||
if (!Resolve(uid, ref device, false))
|
||||
return false;
|
||||
|
||||
return GetNetwork(device.DeviceNetId).Add(device);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect an entity with a DeviceNetworkComponent.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a device is already connected to its network
|
||||
/// </summary>
|
||||
/// <returns>True if the device was found in the network with its corresponding network id</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if an address exists in the network with the given netId
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find a device on a network using its address.
|
||||
/// </summary>
|
||||
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<DeviceNetworkComponent>.Shared.Rent(devices.Count);
|
||||
devices.CopyTo(deviceCopy);
|
||||
SendToConnections(deviceCopy.AsSpan(0, devices.Count), packet);
|
||||
ArrayPool<DeviceNetworkComponent>.Shared.Return(deviceCopy);
|
||||
}
|
||||
totalDevices += 1;
|
||||
hasTargetedDevice = true;
|
||||
}
|
||||
else
|
||||
var deviceCopy = ArrayPool<Device>.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<DeviceNetworkComponent>.Shared.Rent(totalDevices);
|
||||
if (devices != null)
|
||||
{
|
||||
devices.CopyTo(deviceCopy);
|
||||
}
|
||||
if (hasTargetedDevice)
|
||||
{
|
||||
deviceCopy[totalDevices - 1] = device!;
|
||||
}
|
||||
SendToConnections(deviceCopy.AsSpan(0, totalDevices), packet);
|
||||
ArrayPool<DeviceNetworkComponent>.Shared.Return(deviceCopy);
|
||||
devices.CopyTo(deviceCopy);
|
||||
}
|
||||
if (hasTargetedDevice)
|
||||
{
|
||||
deviceCopy[totalDevices - 1] = device.Value;
|
||||
}
|
||||
SendToConnections(deviceCopy.AsSpan(0, totalDevices), packet);
|
||||
ArrayPool<Device>.Shared.Return(deviceCopy);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the <see cref="BeforeBroadcastAttemptEvent"/> to the sending entity if the packets SendBeforeBroadcastAttemptEvent field is set to true.
|
||||
/// The recipients is set to the modified recipient list.
|
||||
/// </summary>
|
||||
/// <returns>false if the broadcast was canceled</returns>
|
||||
private bool CheckRecipientsList(DeviceNetworkPacketEvent packet, ref HashSet<DeviceNetworkComponent> 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;
|
||||
/// <summary>
|
||||
/// Sends the <see cref="BeforeBroadcastAttemptEvent"/> to the sending entity if the packets SendBeforeBroadcastAttemptEvent field is set to true.
|
||||
/// The recipients is set to the modified recipient list.
|
||||
/// </summary>
|
||||
/// <returns>false if the broadcast was canceled</returns>
|
||||
private bool CheckRecipientsList<T>(DeviceNetworkPacketEvent<T> packet, ref HashSet<Device> 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<T>(ReadOnlySpan<Device> connections, DeviceNetworkPacketEvent<T> packet) where T : INetworkPayload
|
||||
{
|
||||
if (Deleted(packet.Sender))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private void SendToConnections(ReadOnlySpan<DeviceNetworkComponent> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ApcNetSwitchComponent, InteractHandEvent>(OnInteracted);
|
||||
SubscribeLocalEvent<ApcNetSwitchComponent, DeviceNetworkPacketEvent>(OnPackedReceived);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the state of the switch and sents a <see cref="DeviceNetworkConstants.CmdSetState"/> command with the
|
||||
/// <see cref="DeviceNetworkConstants.StateEnabled"/> value set to state.
|
||||
/// </summary>
|
||||
private void OnInteracted(EntityUid uid, ApcNetSwitchComponent component, InteractHandEvent args)
|
||||
private void OnInteracted(Entity<ApcNetSwitchComponent> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Listens to the <see cref="DeviceNetworkConstants.CmdSetState"/> command of other switches to sync state
|
||||
/// </summary>
|
||||
private void OnPackedReceived(EntityUid uid, ApcNetSwitchComponent component, DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnPackedReceived(Entity<ApcNetSwitchComponent> ent, ref DeviceNetworkPacketEvent<ApcNetTogglePayload> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|||
/// <summary>
|
||||
/// Checks if both devices are limited to the same station
|
||||
/// </summary>
|
||||
private void OnBeforePacketSent(EntityUid uid, StationLimitedNetworkComponent component, BeforePacketSentEvent args)
|
||||
private void OnBeforePacketSent(Entity<StationLimitedNetworkComponent> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ namespace Content.Server.DeviceNetwork.Systems
|
|||
/// <summary>
|
||||
/// Checks if both devices are on the same grid
|
||||
/// </summary>
|
||||
private void OnBeforePacketSent(EntityUid uid, WiredNetworkComponent component, BeforePacketSentEvent args)
|
||||
private void OnBeforePacketSent(Entity<WiredNetworkComponent> ent, ref BeforePacketSentEvent args)
|
||||
{
|
||||
if (Transform(uid).GridUid != args.SenderTransform.GridUid)
|
||||
if (Transform(ent).GridUid != args.SenderTransform.GridUid)
|
||||
{
|
||||
args.Cancel();
|
||||
args.Cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ namespace Content.Server.DeviceNetwork.Systems
|
|||
/// <summary>
|
||||
/// Gets the position of both the sending and receiving entity and checks if the receiver is in range of the sender.
|
||||
/// </summary>
|
||||
private void OnBeforePacketSent(EntityUid uid, WirelessNetworkComponent component, BeforePacketSentEvent args)
|
||||
private void OnBeforePacketSent(Entity<WirelessNetworkComponent> 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<WirelessNetworkComponent>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
|
@ -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<FaxMachineComponent, EntInsertedIntoContainerMessage>(OnItemSlotChanged);
|
||||
SubscribeLocalEvent<FaxMachineComponent, EntRemovedFromContainerMessage>(OnItemSlotChanged);
|
||||
SubscribeLocalEvent<FaxMachineComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
SubscribeLocalEvent<FaxMachineComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
|
||||
// Interaction
|
||||
SubscribeLocalEvent<FaxMachineComponent, InteractUsingEvent>(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<FaxMachineComponent> ent, ref DeviceNetworkPacketEvent<FaxPingPayload> args)
|
||||
{
|
||||
if (!HasComp<DeviceNetworkComponent>(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<FaxMachineComponent> ent, ref DeviceNetworkPacketEvent<FaxPongPayload> 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<StampDisplayInfo>? 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<FaxMachineComponent> ent, ref DeviceNetworkPacketEvent<FaxPrintPayload> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -522,57 +491,26 @@ public sealed partial class FaxSystem : EntitySystem
|
|||
!TryComp<PaperComponent>(sendEntity, out var paper))
|
||||
return;
|
||||
|
||||
if (metadata.EntityPrototype == null)
|
||||
return;
|
||||
|
||||
TryComp<NameModifierComponent>(sendEntity, out var nameMod);
|
||||
|
||||
TryComp<LabelComponent>(sendEntity, out var labelComponent);
|
||||
|
||||
var content = paper.Content;
|
||||
|
||||
if (component.AddSenderInfo)
|
||||
var payload = new FaxPrintPayload
|
||||
{
|
||||
var faxMachineAddress = TryComp<DeviceNetworkComponent>(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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Content.Shared.Medical.SuitSensor;
|
||||
using Content.Shared.Medical.SuitSensors;
|
||||
|
||||
namespace Content.Server.Medical.CrewMonitoring;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<CrewMonitoringConsoleComponent, ComponentRemove>(OnRemove);
|
||||
SubscribeLocalEvent<CrewMonitoringConsoleComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
SubscribeLocalEvent<CrewMonitoringConsoleComponent, BoundUIOpenedEvent>(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<CrewMonitoringConsoleComponent> ent, ref DeviceNetworkPacketEvent<BroadcastSuitSensorStatePayload> 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<string, SuitSensorStatus>? 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)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Content.Shared.Medical.SuitSensor;
|
||||
using Robust.Shared.Map;
|
||||
using Content.Shared.Medical.SuitSensors;
|
||||
|
||||
namespace Content.Server.Medical.CrewMonitoring;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<CrewMonitoringServerComponent, ComponentRemove>(OnRemove);
|
||||
SubscribeLocalEvent<CrewMonitoringServerComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
SubscribeLocalEvent<CrewMonitoringServerComponent, DeviceNetServerDisconnectedEvent>(OnDisconnected);
|
||||
}
|
||||
|
||||
|
|
@ -51,14 +48,12 @@ public sealed partial class CrewMonitoringServerSystem : EntitySystem
|
|||
/// <summary>
|
||||
/// Adds or updates a sensor status entry if the received package is a sensor status update
|
||||
/// </summary>
|
||||
private void OnPacketReceived(EntityUid uid, CrewMonitoringServerComponent component, DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnSensorStatus(Entity<CrewMonitoringServerComponent> ent, ref DeviceNetworkPacketEvent<SuitSensorStatusPayload> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
using Content.Server.Power.Components;
|
||||
|
||||
namespace Content.Server.Power.Generation.Teg;
|
||||
|
||||
/// <summary>
|
||||
/// Sensor data reported by the <see cref="TegGeneratorComponent"/> when queried over the device network.
|
||||
/// </summary>
|
||||
/// <seealso cref="TegSystem"/>
|
||||
public sealed class TegSensorData
|
||||
{
|
||||
/// <summary>
|
||||
/// Information for the A-side circulator.
|
||||
/// </summary>
|
||||
public Circulator CirculatorA;
|
||||
|
||||
/// <summary>
|
||||
/// Information for the B-side circulator.
|
||||
/// </summary>
|
||||
public Circulator CirculatorB;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of energy (Joules) generated by the TEG last atmos tick.
|
||||
/// </summary>
|
||||
/// <seealso cref="TegGeneratorComponent.LastGeneration"/>
|
||||
public float LastGeneration;
|
||||
|
||||
/// <summary>
|
||||
/// Ramping position for the TEG power generation.
|
||||
/// </summary>
|
||||
/// <seealso cref="TegGeneratorComponent.RampPosition"/>
|
||||
public float RampPosition;
|
||||
|
||||
/// <summary>
|
||||
/// Power (Watts) actually being supplied by the TEG to connected power network.
|
||||
/// </summary>
|
||||
/// <seealso cref="PowerSupplierComponent.CurrentSupply"/>
|
||||
public float PowerOutput;
|
||||
|
||||
/// <summary>
|
||||
/// Information for a single TEG circulator.
|
||||
/// </summary>
|
||||
/// <param name="InletPressure">Pressure measured at the circulator's input pipe</param>
|
||||
/// <param name="OutletPressure">Pressure measured at the circulator's output pipe</param>
|
||||
/// <param name="InletTemperature">Temperature measured at the circulator's input pipe</param>
|
||||
/// <param name="OutletTemperature">Temperature measured at the circulator's output pipe</param>
|
||||
public record struct Circulator(
|
||||
float InletPressure,
|
||||
float OutletPressure,
|
||||
float InletTemperature,
|
||||
float OutletTemperature);
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
|||
/// <seealso cref="TegGeneratorComponent"/>
|
||||
/// <seealso cref="TegCirculatorComponent"/>
|
||||
/// <seealso cref="TegNodeGroup"/>
|
||||
/// <seealso cref="TegSensorData"/>
|
||||
/// <seealso cref="TegSensorPayload"/>
|
||||
public sealed partial class TegSystem : EntitySystem
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -61,11 +60,6 @@ public sealed partial class TegSystem : EntitySystem
|
|||
/// </summary>
|
||||
private const string NodeNameOutlet = "outlet";
|
||||
|
||||
/// <summary>
|
||||
/// Device network command to have the TEG output a <see cref="TegSensorData"/> object for its last statistics.
|
||||
/// </summary>
|
||||
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<TegGeneratorComponent, AtmosDeviceUpdateEvent>(GeneratorUpdate);
|
||||
SubscribeLocalEvent<TegGeneratorComponent, PowerChangedEvent>(GeneratorPowerChange);
|
||||
SubscribeLocalEvent<TegGeneratorComponent, DeviceNetworkPacketEvent>(DeviceNetworkPacketReceived);
|
||||
|
||||
SubscribeLocalEvent<TegGeneratorComponent, ExaminedEvent>(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<TegGeneratorComponent> ent, ref DeviceNetworkPacketEvent<TegSensorSyncPayload> 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<PowerSupplierComponent>(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<PowerSupplierComponent>(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,
|
||||
|
|
|
|||
|
|
@ -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<RoboticsConsoleComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
Subs.BuiEvents<RoboticsConsoleComponent>(RoboticsConsoleUiKey.Key, subs =>
|
||||
{
|
||||
subs.Event<BoundUIOpenedEvent>(OnOpened);
|
||||
|
|
@ -70,20 +68,12 @@ public sealed partial class RoboticsConsoleSystem : SharedRoboticsConsoleSystem
|
|||
}
|
||||
}
|
||||
|
||||
private void OnPacketReceived(Entity<RoboticsConsoleComponent> ent, ref DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnPacketReceived(Entity<RoboticsConsoleComponent> ent, ref DeviceNetworkPacketEvent<RoboticsCyborgDataPayload> 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);
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkComponent>(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<DeviceNetworkComponent>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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!;
|
||||
|
||||
/// <summary>
|
||||
/// Calls either a normal screen text update or shuttle timer update based on the presence of
|
||||
/// <see cref="ShuttleTimerMasks.ShuttleMap"/> in <see cref="args.Data"/>
|
||||
/// </summary>
|
||||
[SubscribeLocalEvent]
|
||||
private void OnPacketReceived(Entity<ScreenComponent> ent, ref DeviceNetworkPacketEvent args)
|
||||
{
|
||||
if (args.Data.TryGetValue(ShuttleTimerMasks.ShuttleMap, out _))
|
||||
ShuttleTimer(ent, args);
|
||||
else
|
||||
ScreenText(ent, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a text update to every screen on the same MapUid as the originating comms console.
|
||||
/// </summary>
|
||||
private void ScreenText(Entity<ScreenComponent> ent, DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnScreenText(Entity<ScreenComponent> ent, ref DeviceNetworkPacketEvent<ScreenTextPayload> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -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.
|
||||
/// </summary>
|
||||
private void ShuttleTimer(Entity<ScreenComponent> ent, DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnShuttleTimer(Entity<ScreenComponent> ent, ref DeviceNetworkPacketEvent<ScreenShuttlePayload> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,20 +14,3 @@ public sealed partial class BatterySensorComponent : Component
|
|||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Device network data sent by a <see cref="BatterySensorComponent"/>.
|
||||
/// </summary>
|
||||
/// <param name="Charge">The current energy charge of the battery, in joules (J).</param>
|
||||
/// <param name="MaxCharge">The maximum energy capacity of the battery, in joules (J).</param>
|
||||
/// <param name="Receiving">The current amount of power being received by the battery, in watts (W).</param>
|
||||
/// <param name="MaxReceiving">The maximum amount of power that can be received by the battery, in watts (W).</param>
|
||||
/// <param name="Supplying">The current amount of power being supplied by the battery, in watts (W).</param>
|
||||
/// <param name="MaxSupplying">The maximum amount of power that can be received by the battery, in watts (W).</param>
|
||||
public sealed record BatterySensorData(
|
||||
float Charge,
|
||||
float MaxCharge,
|
||||
float Receiving,
|
||||
float MaxReceiving,
|
||||
float Supplying,
|
||||
float MaxSupplying
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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<BatterySensorComponent> ent, ref DeviceNetworkPacketEvent<BatterySensorSyncPayload> args)
|
||||
{
|
||||
SubscribeLocalEvent<BatterySensorComponent, DeviceNetworkPacketEvent>(PacketReceived);
|
||||
}
|
||||
var battery = Comp<BatteryComponent>(ent);
|
||||
var currentCharge = _battery.GetCharge((ent.Owner, battery));
|
||||
var netBattery = Comp<PowerNetworkBatteryComponent>(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<BatteryComponent>(uid);
|
||||
var currentCharge = _battery.GetCharge((uid, battery));
|
||||
var netBattery = Comp<PowerNetworkBatteryComponent>(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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<SensorMonitoringConsoleComponent, DeviceListUpdateEvent>(DeviceListUpdated);
|
||||
SubscribeLocalEvent<SensorMonitoringConsoleComponent, ComponentStartup>(ConsoleStartup);
|
||||
SubscribeLocalEvent<SensorMonitoringConsoleComponent, DeviceNetworkPacketEvent>(DevicePacketReceived);
|
||||
SubscribeLocalEvent<SensorMonitoringConsoleComponent, AtmosDeviceUpdateEvent>(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<SensorMonitoringConsoleComponent> ent, ref DeviceNetworkPacketEvent<TegSensorPayload> 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<SensorMonitoringConsoleComponent> ent, ref DeviceNetworkPacketEvent<AtmosMonitorDataPayload> 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<SensorMonitoringConsoleComponent> ent, ref DeviceNetworkPacketEvent<GasThermoMachineDataPayload> 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<SensorMonitoringConsoleComponent> ent, ref DeviceNetworkPacketEvent<GasVolumePumpDataPayload> 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<SensorMonitoringConsoleComponent> ent, ref DeviceNetworkPacketEvent<BatterySensorDataPayload> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<FTLComponent>(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<DeviceNetworkComponent>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ public sealed partial class DockingSignalControlSystem : EntitySystem
|
|||
|
||||
private void OnDocked(Entity<DockingSignalControlComponent> 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<DockingSignalControlComponent> ent, ref UndockEvent args)
|
||||
{
|
||||
_deviceLinkSystem.SendSignal(ent, ent.Comp.DockStatusSignalPort, signal: false);
|
||||
_deviceLinkSystem.SendSignal(ent.Owner, ent.Comp.DockStatusSignalPort, signal: false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkComponent>(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;
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkComponent>(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<DeviceNetworkComponent>(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<DeviceNetworkComponent>(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.
|
||||
|
|
|
|||
|
|
@ -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;
|
|||
/// <inheritdoc/>
|
||||
public sealed partial class BorgSystem
|
||||
{
|
||||
private void InitializeTransponder()
|
||||
{
|
||||
SubscribeLocalEvent<BorgTransponderComponent, DeviceNetworkPacketEvent>(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<BorgTransponderComponent> ent, ref DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnDisable(Entity<BorgTransponderComponent> ent, ref DeviceNetworkPacketEvent<RoboticsCyborgDisablePayload> 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<BorgTransponderComponent> ent, ref DeviceNetworkPacketEvent<RoboticsCyborgDestroyPayload> args)
|
||||
{
|
||||
Destroy(ent.AsNullable());
|
||||
}
|
||||
|
||||
private void Disable(Entity<BorgTransponderComponent, BorgChassisComponent?> ent)
|
||||
|
|
|
|||
|
|
@ -36,14 +36,6 @@ public sealed partial class BorgSystem : SharedBorgSystem
|
|||
|
||||
public static readonly ProtoId<JobPrototype> BorgJobId = "Borg";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
InitializeTransponder();
|
||||
}
|
||||
|
||||
public override bool CanPlayerBeBorged(ICommonSession session)
|
||||
{
|
||||
if (_banManager.GetJobBans(session.UserId)?.Contains(BorgJobId) == true)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the subnet connected to this router.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public string SubnetName = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[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<string> MonitorRoutes { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The frequency that talks to this router's subnet.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
// The frequency that talks to this router's subnet.
|
||||
public uint SubnetFrequency;
|
||||
|
||||
[DataField("subnetFrequency")]
|
||||
public ProtoId<DeviceFrequencyPrototype>? SubnetFrequencyId { get; set; }
|
||||
public ProtoId<DeviceFrequencyPrototype>? SubnetFrequencyId { get; set; }
|
||||
|
||||
[DataField("setupAvailableNetworks")]
|
||||
public List<ProtoId<DeviceFrequencyPrototype>> AvailableNetworks { get; private set; } = new();
|
||||
|
|
|
|||
|
|
@ -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<SurveillanceCameraMapComponent>(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<ApcPowerReceiverComponent>(uid)?.Powered ?? true;
|
||||
var active = comp.Active && powered;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<SurveillanceCameraMonitorComponent, SurveillanceCameraDeactivateEvent>(OnSurveillanceCameraDeactivate);
|
||||
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, AfterActivatableUIOpenEvent>(OnToggleInterface);
|
||||
Subs.BuiEvents<SurveillanceCameraMonitorComponent>(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<SurveillanceCameraMonitorComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraConnectPayload> 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<SurveillanceCameraMonitorComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraHeartbeatPayload> 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<DeviceFrequencyPrototype>? 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<DeviceFrequencyPrototype>? 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<SurveillanceCameraMonitorComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraDataPayload> 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<SurveillanceCameraMonitorComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraSubnetDataPayload> 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<DeviceFrequencyPrototype> 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<DeviceFrequencyPrototype> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<SurveillanceCameraRouterComponent> _query = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<SurveillanceCameraRouterComponent, ComponentInit>(OnInitialize);
|
||||
SubscribeLocalEvent<SurveillanceCameraRouterComponent, DeviceNetworkPacketEvent>(OnPacketReceive);
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<SurveillanceCameraRouterComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<SurveillanceCameraRouterComponent, SurveillanceCameraSetupSetNetwork>(OnSetNetwork);
|
||||
SubscribeLocalEvent<SurveillanceCameraRouterComponent, GetVerbsEvent<AlternativeVerb>>(AddVerbs);
|
||||
SubscribeLocalEvent<SurveillanceCameraRouterComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
}
|
||||
|
||||
private void OnInitialize(EntityUid uid, SurveillanceCameraRouterComponent router, ComponentInit args)
|
||||
private void OnMapInit(Entity<SurveillanceCameraRouterComponent> 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<SurveillanceCameraRouterComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraSubnetConnectPayload> args)
|
||||
{
|
||||
AddMonitorToRoute(ent.AsNullable(), args.SenderAddress);
|
||||
PingSubnet(ent.AsNullable());
|
||||
}
|
||||
|
||||
[SubscribeLocalEvent]
|
||||
private void OnSubnetDisconnect(Entity<SurveillanceCameraRouterComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraSubnetDisconnectPayload> args)
|
||||
{
|
||||
RemoveMonitorFromRoute(ent.AsNullable(), args.SenderAddress);
|
||||
}
|
||||
|
||||
[SubscribeLocalEvent]
|
||||
private void OnSubnetPing(Entity<SurveillanceCameraRouterComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraPingSubnetPayload> 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<SurveillanceCameraRouterComponent> ent, ref PowerChangedEvent args)
|
||||
{
|
||||
ent.Comp.MonitorRoutes.Clear();
|
||||
ent.Comp.Active = args.Powered;
|
||||
}
|
||||
|
||||
private void AddVerbs(Entity<SurveillanceCameraRouterComponent> ent, ref GetVerbsEvent<AlternativeVerb> 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<AlternativeVerb> 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<SurveillanceCameraRouterComponent> 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<DeviceFrequencyPrototype>(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<SurveillanceCameraRouterComponent?> 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<SurveillanceCameraRouterComponent?, DeviceNetworkComponent?> 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<SurveillanceCameraRouterComponent?> 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<SurveillanceCameraRouterComponent?> 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<SurveillanceCameraRouterComponent?> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!;
|
||||
|
|
|
|||
|
|
@ -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<SurveillanceCameraRouterComponent> _routerQuery = default!;
|
||||
|
||||
public const int CameraNameLimit = 32;
|
||||
|
||||
|
|
@ -57,74 +32,53 @@ public sealed partial class SurveillanceCameraSystem : SharedSurveillanceCameraS
|
|||
|
||||
SubscribeLocalEvent<SurveillanceCameraComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<SurveillanceCameraComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
SubscribeLocalEvent<SurveillanceCameraComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
SubscribeLocalEvent<SurveillanceCameraComponent, SurveillanceCameraSetupSetName>(OnSetName);
|
||||
SubscribeLocalEvent<SurveillanceCameraComponent, SurveillanceCameraSetupSetNetwork>(OnSetNetwork);
|
||||
|
||||
InitializeCollide();
|
||||
}
|
||||
|
||||
private void OnPacketReceived(EntityUid uid, SurveillanceCameraComponent component, DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnConnectRequest(Entity<SurveillanceCameraComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraConnectRequestPayload> 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<SurveillanceCameraComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraHeartbeatRequestPayload> 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<SurveillanceCameraComponent> ent, ref DeviceNetworkPacketEvent<SurveillanceCameraPingPayload> 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<DeviceFrequencyPrototype>? 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<SurveillanceCameraComponent> 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<DeviceFrequencyPrototype>(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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <see cref="DeviceNetworkConstants"/> for further examples.
|
||||
public const string CmdSetArmamemtState = "set_armament_state";
|
||||
public const string CmdSetAccessExemptions = "set_access_exemption";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DeployableTurretControllerComponent, BoundUIOpenedEvent>(OnBUIOpened);
|
||||
SubscribeLocalEvent<DeployableTurretControllerComponent, DeviceListUpdateEvent>(OnDeviceListUpdate);
|
||||
SubscribeLocalEvent<DeployableTurretControllerComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
}
|
||||
|
||||
[SubscribeLocalEvent]
|
||||
private void OnBUIOpened(Entity<DeployableTurretControllerComponent> ent, ref BoundUIOpenedEvent args)
|
||||
{
|
||||
if (!TryComp<DeviceNetworkComponent>(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<DeployableTurretControllerComponent> ent, ref DeviceListUpdateEvent args)
|
||||
{
|
||||
if (!TryComp<DeviceNetworkComponent>(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<DeviceNetworkComponent>(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<DeployableTurretControllerComponent> ent, ref DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnPacketReceived(Entity<DeployableTurretControllerComponent> ent, ref DeviceNetworkPacketEvent<TurretStatePayload> args)
|
||||
{
|
||||
if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command))
|
||||
return;
|
||||
|
||||
if (!TryComp<DeviceNetworkComponent>(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<DeployableTurretControllerComponent> 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<DeployableTurretControllerComponent> ent)
|
||||
|
|
|
|||
|
|
@ -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<DeviceNetworkComponent> _deviceQuery = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
|
@ -41,7 +40,6 @@ public sealed partial class DeployableTurretSystem : SharedDeployableTurretSyste
|
|||
SubscribeLocalEvent<DeployableTurretComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
SubscribeLocalEvent<DeployableTurretComponent, BreakageEventArgs>(OnBroken);
|
||||
SubscribeLocalEvent<DeployableTurretComponent, RepairedEvent>(OnRepaired);
|
||||
SubscribeLocalEvent<DeployableTurretComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
SubscribeLocalEvent<DeployableTurretComponent, BeforeBroadcastAttemptEvent>(OnBeforeBroadcast);
|
||||
}
|
||||
|
||||
|
|
@ -74,37 +72,28 @@ public sealed partial class DeployableTurretSystem : SharedDeployableTurretSyste
|
|||
_appearance.SetData(ent, DeployableTurretVisuals.Broken, false, appearance);
|
||||
}
|
||||
|
||||
private void OnPacketReceived(Entity<DeployableTurretComponent> ent, ref DeviceNetworkPacketEvent args)
|
||||
[SubscribeLocalEvent]
|
||||
private void OnSetArmament(Entity<DeployableTurretComponent> ent, ref DeviceNetworkPacketEvent<TurretControllerSetArmamentPayload> args)
|
||||
{
|
||||
if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command))
|
||||
if (TryComp<BatteryWeaponFireModesComponent>(ent, out var batteryWeaponFireModes))
|
||||
_fireModes.TrySetFireMode((ent.Owner, batteryWeaponFireModes), args.Data.ArmamentState);
|
||||
|
||||
TrySetState(ent, args.Data.ArmamentState >= 0);
|
||||
}
|
||||
|
||||
[SubscribeLocalEvent]
|
||||
private void OnSetAccess(Entity<DeployableTurretComponent> ent, ref DeviceNetworkPacketEvent<TurretControllerSetAccessPayload> args)
|
||||
{
|
||||
if (!TryComp<TurretTargetSettingsComponent>(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<BatteryWeaponFireModesComponent>(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<ProtoId<AccessLevelPrototype>>? accessExemptions) &&
|
||||
TryComp<TurretTargetSettingsComponent>(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<DeployableTurretComponent> ent, ref DeviceNetworkPacketEvent<TurretControllerRequestPayload> args)
|
||||
{
|
||||
SendStateUpdateToDeviceNetwork(ent);
|
||||
}
|
||||
|
||||
private void OnBeforeBroadcast(Entity<DeployableTurretComponent> ent, ref BeforeBroadcastAttemptEvent args)
|
||||
|
|
@ -112,15 +101,15 @@ public sealed partial class DeployableTurretSystem : SharedDeployableTurretSyste
|
|||
if (!TryComp<DeviceNetworkComponent>(ent, out var deviceNetwork))
|
||||
return;
|
||||
|
||||
var recipientDeviceNetworks = new HashSet<DeviceNetworkComponent>();
|
||||
var recipientDeviceNetworks = new HashSet<Device>();
|
||||
|
||||
// Only broadcast to connected devices
|
||||
foreach (var recipient in deviceNetwork.DeviceLists)
|
||||
{
|
||||
if (!TryComp<DeviceNetworkComponent>(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<DeviceNetworkComponent>(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<DeployableTurretComponent> ent, bool enabled, EntityUid? user = null)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
/// <summary>
|
||||
/// Contains <see cref="AtmosMonitorData"/>.
|
||||
/// </summary>
|
||||
public partial record struct AtmosMonitorDataPayload : INetworkPayload
|
||||
{
|
||||
public AtmosSensorData(float pressure, float temperature, float totalMoles, AtmosAlarmType alarmState, Dictionary<Gas, float> gases, AtmosAlarmThreshold pressureThreshold, AtmosAlarmThreshold temperatureThreshold, Dictionary<Gas, AtmosAlarmThreshold> 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<Gas, float> gases, AtmosAlarmThreshold pressureThreshold, AtmosAlarmThreshold temperatureThreshold, Dictionary<Gas, AtmosAlarmThreshold> 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.
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
19
Content.Shared/Atmos/Monitor/BaseAtmosDeviceData.cs
Normal file
19
Content.Shared/Atmos/Monitor/BaseAtmosDeviceData.cs
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
21
Content.Shared/Atmos/Monitor/IAtmosDeviceData.cs
Normal file
21
Content.Shared/Atmos/Monitor/IAtmosDeviceData.cs
Normal file
|
|
@ -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; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a payload that contains this atmos device data and send it to the specified address.
|
||||
/// </summary>
|
||||
/// <param name="uid">Owner of this atmos data.</param>
|
||||
/// <param name="address">The target address.</param>
|
||||
/// <param name="deviceNetSys">The device network system.</param>
|
||||
void RaisePayload(EntityUid uid, string address, SharedDeviceNetworkSystem deviceNetSys);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Contains data about a <see cref="GasVolumePumpComponent"/>.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
/// <summary>
|
||||
/// Contains data about <see cref="GasThermoMachineComponent"/>.
|
||||
/// </summary>
|
||||
public partial record struct GasThermoMachineDataPayload : INetworkPayload
|
||||
{
|
||||
[DataField]
|
||||
public float EnergyDelta;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[NetSerializable]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to set <see cref="GasVentPumpData"/>.
|
||||
/// </summary>
|
||||
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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Gas> 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<Gas> 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<Gas> 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<Gas> 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
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to set <see cref="GasVentScrubberData"/>.
|
||||
/// </summary>
|
||||
public partial record struct GasVentScrubberSetDataPayload : INetworkPayload
|
||||
{
|
||||
[DataField]
|
||||
public GasVentScrubberData Data;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum ScrubberPumpDirection : sbyte
|
||||
{
|
||||
Siphoning = 0,
|
||||
Scrubbing = 1,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<CartridgeLoaderComponent, AfterInteractEvent>(RelayEvent);
|
||||
SubscribeLocalEvent<CartridgeLoaderComponent, InteractUsingEvent>(RelayEvent);
|
||||
SubscribeLocalEvent<CartridgeLoaderComponent, DeviceNetworkPacketEvent>(RelayEvent);
|
||||
}
|
||||
|
||||
private void RefRelayEvent<T>(EntityUid uid, CartridgeLoaderComponent component, ref T args) where T : struct
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<T>(string Port, T Data, EntityUid? Trigger = null) where T : ISignalNetworkPayload;
|
||||
|
|
|
|||
10
Content.Shared/DeviceLinking/LogicStatePayload.cs
Normal file
10
Content.Shared/DeviceLinking/LogicStatePayload.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
namespace Content.Shared.DeviceLinking;
|
||||
|
||||
/// <summary>
|
||||
/// Contains a logic state of a <see cref="SignalPayload"/>.
|
||||
/// </summary>
|
||||
public partial record struct LogicStatePayload : ISignalNetworkPayload
|
||||
{
|
||||
[DataField]
|
||||
public SignalState State;
|
||||
}
|
||||
|
|
@ -17,13 +17,13 @@ public abstract partial class SharedDeviceLinkSystem : EntitySystem
|
|||
[Dependency] private SharedTransformSystem _transform = default!;
|
||||
[Dependency] private IGameTiming _gameTiming = default!;
|
||||
|
||||
[Dependency] private EntityQuery<DeviceLinkSinkComponent> _deviceLinkSinkQuery = default!;
|
||||
|
||||
public const string InvokedPort = "link_port";
|
||||
[Dependency] protected EntityQuery<DeviceLinkSinkComponent> DeviceLinkSinkQuery = default!;
|
||||
[Dependency] protected EntityQuery<DeviceLinkSourceComponent> DeviceLinkSourceQuery = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<DeviceLinkSourceComponent, ComponentStartup>(OnSourceStartup);
|
||||
SubscribeLocalEvent<DeviceLinkSourceComponent, ComponentRemove>(OnSourceRemoved);
|
||||
SubscribeLocalEvent<DeviceLinkSinkComponent, ComponentRemove>(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 <see cref="SignalReceivedEvent"/> without data if the source or the sink doesn't have a <see cref="DeviceNetworkComponent"/>
|
||||
/// </summary>
|
||||
/// <param name="uid">The source uid that invokes the port</param>
|
||||
/// <param name="ent">The source uid that invokes the port</param>
|
||||
/// <param name="port">The port to invoke</param>
|
||||
public virtual void InvokePort(Entity<DeviceLinkSourceComponent?> ent, string port)
|
||||
{
|
||||
// NOOP on client for the moment.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a network payload directed at the sink entity.
|
||||
/// Just raises a <see cref="SignalReceivedEvent"/> without data if the source or the sink doesn't have a <see cref="DeviceNetworkComponent"/>
|
||||
/// </summary>
|
||||
/// <param name="ent">The source entity that invokes the port</param>
|
||||
/// <param name="port">The port to invoke</param>
|
||||
/// <param name="data">Optional data to send along</param>
|
||||
/// <param name="sourceComponent"></param>
|
||||
public virtual void InvokePort(EntityUid uid, string port, NetworkPayload? data = null,
|
||||
DeviceLinkSourceComponent? sourceComponent = null)
|
||||
public virtual void InvokePort<T>(Entity<DeviceLinkSourceComponent?> ent, string port, ref T data) where T : ISignalNetworkPayload
|
||||
{
|
||||
// NOOP on client for the moment.
|
||||
}
|
||||
|
|
|
|||
41
Content.Shared/DeviceLinking/SignalPayload.cs
Normal file
41
Content.Shared/DeviceLinking/SignalPayload.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using Content.Shared.DeviceLinking.Events;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
|
||||
namespace Content.Shared.DeviceLinking;
|
||||
|
||||
/// <summary>
|
||||
/// A network payload that can be nested inside <see cref="SignalPayload{T}"/>.
|
||||
/// </summary>
|
||||
public partial interface ISignalNetworkPayload : INetworkPayload;
|
||||
|
||||
/// <summary>
|
||||
/// A network payload that raises <see cref="SignalReceivedEvent"/> when successfully delivered.
|
||||
/// Optionally contains a <see cref="INetworkPayload"/> to provide additional data for the event.
|
||||
/// </summary>
|
||||
public partial record struct SignalPayload : INetworkPayload
|
||||
{
|
||||
/// <summary>
|
||||
/// A signal port that was invoked.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string InvokedPort;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A network payload that raises <see cref="SignalReceivedEvent"/> when successfully delivered.
|
||||
/// Optionally contains a <see cref="INetworkPayload"/> to provide additional data for the event.
|
||||
/// </summary>
|
||||
public partial record struct SignalPayload<T> : INetworkPayload where T : ISignalNetworkPayload
|
||||
{
|
||||
/// <summary>
|
||||
/// A signal port that was invoked.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string InvokedPort;
|
||||
|
||||
/// <summary>
|
||||
/// Optional additional data about the signal.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public T Payload;
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
/// <summary>
|
||||
/// Default device network ID to connect to.
|
||||
/// </summary>
|
||||
[DataField("deviceNetId")]
|
||||
public DeviceNetIdDefaults NetIdEnum { get; set; }
|
||||
|
||||
[DataField("deviceNetId")]
|
||||
public DeviceNetIdDefaults NetIdEnum { get; set; }
|
||||
public int DeviceNetId => (int) NetIdEnum;
|
||||
|
||||
public int DeviceNetId => (int) NetIdEnum;
|
||||
/// <summary>
|
||||
/// The frequency that this device is listening on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public uint? ReceiveFrequency;
|
||||
|
||||
/// <summary>
|
||||
/// The frequency that this device is listening on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public uint? ReceiveFrequency;
|
||||
/// <summary>
|
||||
/// The address ID of the device, either on the network it is currently connected to or whatever address it
|
||||
/// most recently used.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string Address = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// frequency prototype. Used to select a default frequency to listen to on. Used when the map is
|
||||
/// initialized.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<DeviceFrequencyPrototype>? ReceiveFrequencyId;
|
||||
/// <summary>
|
||||
/// Whether the device should listen for all device messages, regardless of the intended recipient.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool ReceiveAll;
|
||||
|
||||
/// <summary>
|
||||
/// The frequency that this device going to try transmit on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public uint? TransmitFrequency;
|
||||
/// <summary>
|
||||
/// The frequency that this device going to try to transmit on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public uint? TransmitFrequency;
|
||||
|
||||
/// <summary>
|
||||
/// frequency prototype. Used to select a default frequency to transmit on. Used when the map is
|
||||
/// initialized.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<DeviceFrequencyPrototype>? TransmitFrequencyId;
|
||||
/// <summary>
|
||||
/// Frequency prototype, used to select a default frequency to listen to on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<DeviceFrequencyPrototype>? ReceiveFrequencyId;
|
||||
|
||||
/// <summary>
|
||||
/// The address of the device, either on the network it is currently connected to or whatever address it
|
||||
/// most recently used.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string Address = string.Empty;
|
||||
/// <summary>
|
||||
/// Frequency prototype, used to select a default frequency to transmit on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<DeviceFrequencyPrototype>? TransmitFrequencyId;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool CustomAddress = false;
|
||||
/// <summary>
|
||||
/// Whether to send the broadcast recipients list to the sender so it can be filtered.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool SendBroadcastAttemptEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Prefix to prepend to any automatically generated addresses. Helps players to identify devices. This gets
|
||||
/// localized.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string? Prefix;
|
||||
/// <summary>
|
||||
/// If the device should show its address upon an examine.
|
||||
/// Useful for devices that do not have a visible UI.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool ExaminableAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the device should listen for all device messages, regardless of the intended recipient.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool ReceiveAll;
|
||||
/// <summary>
|
||||
/// Prefix to prepend to any automatically generated addresses. Helps players to identify devices.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId? Prefix;
|
||||
|
||||
/// <summary>
|
||||
/// If the device should show its address upon an examine. Useful for devices
|
||||
/// that do not have a visible UI.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool ExaminableAddress;
|
||||
/// <summary>
|
||||
/// Whether the device should attempt to join the network on map init.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool AutoConnect = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the device should attempt to join the network on map init.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool AutoConnect = true;
|
||||
/// <summary>
|
||||
/// Whether this device's address can be saved to device-lists
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool SavableAddress = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to send the broadcast recipients list to the sender so it can be filtered.
|
||||
/// <see cref="DeviceListSystem"/>
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool SendBroadcastAttemptEvent = false;
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool CustomAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this device's address can be saved to device-lists
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool SavableAddress = true;
|
||||
/// <summary>
|
||||
/// A list of device-lists that this device is on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[Access(typeof(SharedDeviceListSystem))]
|
||||
public HashSet<EntityUid> DeviceLists = new();
|
||||
|
||||
/// <summary>
|
||||
/// A list of device-lists that this device is on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[Access(typeof(SharedDeviceListSystem))]
|
||||
public HashSet<EntityUid> DeviceLists = new();
|
||||
|
||||
/// <summary>
|
||||
/// A list of configurators that this device is on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[Access(typeof(SharedNetworkConfiguratorSystem))]
|
||||
public HashSet<EntityUid> Configurators = new();
|
||||
}
|
||||
/// <summary>
|
||||
/// A list of configurators that this device is on.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[Access(typeof(SharedNetworkConfiguratorSystem))]
|
||||
public HashSet<EntityUid> Configurators = new();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public sealed partial class DeviceNetworkJammerComponent : Component
|
|||
/// Network ids are not guaranteed to be limited to DeviceNetIdDefaults.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public HashSet<string> JammableNetworks = [];
|
||||
public HashSet<int> JammableNetworks = [];
|
||||
|
||||
/// <summary>
|
||||
/// Device networks frequencies that wont be jammed.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
using Content.Shared.DeviceNetwork.Payloads;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.DeviceNetwork.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Re-routs <see cref="RoutedNetworkPayload"/>s to some other devices.
|
||||
/// Useful for server setups where there are lots of payloads that have to be relayed.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DeviceNetworkRouterComponent : Component;
|
||||
25
Content.Shared/DeviceNetwork/Device.cs
Normal file
25
Content.Shared/DeviceNetwork/Device.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using Content.Shared.DeviceNetwork.Components;
|
||||
using Content.Shared.DeviceNetwork.Systems;
|
||||
|
||||
namespace Content.Shared.DeviceNetwork;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a device in a <see cref="DeviceNet"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This type is read-only. To change any parameters of the device, use <see cref="SharedDeviceNetworkSystem"/>'s API.
|
||||
/// </remarks>
|
||||
[DataRecord]
|
||||
public readonly partial record struct Device(EntityUid Owner, uint? ReceiveFrequency, string Address, bool ReceiveAll)
|
||||
{
|
||||
public Device(Entity<DeviceNetworkComponent> ent) : this(
|
||||
ent.Owner,
|
||||
ent.Comp.ReceiveFrequency,
|
||||
ent.Comp.Address,
|
||||
ent.Comp.ReceiveAll)
|
||||
{
|
||||
Owner = ent.Owner;
|
||||
ReceiveFrequency = ent.Comp.ReceiveFrequency;
|
||||
ReceiveAll = ent.Comp.ReceiveAll;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Optional name for this frequency, for displaying in game.
|
||||
/// </summary>
|
||||
[DataField("name")]
|
||||
public string? Name;
|
||||
|
||||
[DataField]
|
||||
public LocId? Name;
|
||||
}
|
||||
|
|
|
|||
42
Content.Shared/DeviceNetwork/DeviceLocalizationHelpers.cs
Normal file
42
Content.Shared/DeviceNetwork/DeviceLocalizationHelpers.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.DeviceNetwork;
|
||||
|
||||
/// <summary>
|
||||
/// A helper class for localization of frequencies and device network IDs.
|
||||
/// </summary>
|
||||
public static class DeviceLocalizationHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the unsigned int to string and inserts a number before the last digit
|
||||
/// </summary>
|
||||
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, ".");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Either returns the localized name representation of the corresponding <see cref="DeviceNetIdDefaults"/>
|
||||
/// or converts the id to string
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
/// </summary>
|
||||
public readonly Dictionary<string, DeviceNetworkComponent> Devices = new();
|
||||
[ViewVariables]
|
||||
public readonly Dictionary<string, Device> Devices = new();
|
||||
|
||||
/// <summary>
|
||||
/// Devices listening on a given frequency.
|
||||
/// </summary>
|
||||
public readonly Dictionary<uint, HashSet<DeviceNetworkComponent>> ListeningDevices = new();
|
||||
[ViewVariables]
|
||||
public readonly Dictionary<uint, HashSet<Device>> ListeningDevices = new();
|
||||
|
||||
/// <summary>
|
||||
/// Devices listening to all packets on a given frequency, regardless of the intended recipient.
|
||||
/// </summary>
|
||||
public readonly Dictionary<uint, HashSet<DeviceNetworkComponent>> ReceiveAllDevices = new();
|
||||
[ViewVariables]
|
||||
public readonly Dictionary<uint, HashSet<Device>> ReceiveAllDevices = new();
|
||||
|
||||
private readonly IRobustRandom _random;
|
||||
public readonly int NetId;
|
||||
|
|
@ -41,9 +44,11 @@ public sealed class DeviceNet
|
|||
/// <summary>
|
||||
/// Add a device to the network.
|
||||
/// </summary>
|
||||
public bool Add(DeviceNetworkComponent device)
|
||||
public bool Add(Entity<DeviceNetworkComponent> 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
|
|||
/// <summary>
|
||||
/// Remove a device from the network.
|
||||
/// </summary>
|
||||
public bool Remove(DeviceNetworkComponent device)
|
||||
public bool Remove(Entity<DeviceNetworkComponent> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the address of an existing device.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make an existing network device listen to a new frequency.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make an existing network device listen to a new frequency.
|
||||
/// </summary>
|
||||
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<DeviceNetworkComponent>? 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a valid address by randomly generating one and checking if it already exists on the network.
|
||||
/// </summary>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue