BUI bugfixes / improvements (#23881)

* Fix ActivatableUIRequiresPowerCellComponent stopping power draw when one of two people closes the UI.

Also fixes it to check UiKey properly.

* Remove unnecessary CrewManifestViewer on PDAs

This is for a pop-up crew manifest UI, which the PDA doesn't use.

* Fix BoundUIClosedEvents that didn't check UI key/not correctly at least.

Uses the new helper method in engine.

* Fix drone (cargo shuttle) pilot console UI breaking if two people open it and one person closes it.

* Fixes for disposal router/tagger UI.

Code was badly copy pasted without changing identifiers, never worked.

Also cleaned up some of the logic (text trimming, sounds).

Also removed the "refuse to work if you have something in your active hand" check like why.

* Avoid running most ActivatableUIComponent logic when closing a UI via toggle

Activating the UI while it's already open closes it via toggle. Except it still ran 99% of the "attempting to open" logic which makes no sense.

This probably fixes a bug or some other dumb behavior somewhere.

* Bitch
This commit is contained in:
Pieter-Jan Briers
2024-01-14 08:18:39 +01:00
committed by GitHub
parent b51d69184e
commit 123a4147de
22 changed files with 174 additions and 125 deletions

View File

@@ -31,14 +31,18 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<AccessOverriderComponent, WriteToTargetAccessReaderIdMessage>(OnWriteToTargetAccessReaderIdMessage);
SubscribeLocalEvent<AccessOverriderComponent, ComponentStartup>(UpdateUserInterface); SubscribeLocalEvent<AccessOverriderComponent, ComponentStartup>(UpdateUserInterface);
SubscribeLocalEvent<AccessOverriderComponent, EntInsertedIntoContainerMessage>(UpdateUserInterface); SubscribeLocalEvent<AccessOverriderComponent, EntInsertedIntoContainerMessage>(UpdateUserInterface);
SubscribeLocalEvent<AccessOverriderComponent, EntRemovedFromContainerMessage>(UpdateUserInterface); SubscribeLocalEvent<AccessOverriderComponent, EntRemovedFromContainerMessage>(UpdateUserInterface);
SubscribeLocalEvent<AccessOverriderComponent, AfterInteractEvent>(AfterInteractOn); SubscribeLocalEvent<AccessOverriderComponent, AfterInteractEvent>(AfterInteractOn);
SubscribeLocalEvent<AccessOverriderComponent, AccessOverriderDoAfterEvent>(OnDoAfter); SubscribeLocalEvent<AccessOverriderComponent, AccessOverriderDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<AccessOverriderComponent, BoundUIOpenedEvent>(UpdateUserInterface);
SubscribeLocalEvent<AccessOverriderComponent, BoundUIClosedEvent>(OnClose); Subs.BuiEvents<AccessOverriderComponent>(AccessOverriderUiKey.Key, subs =>
{
subs.Event<BoundUIOpenedEvent>(UpdateUserInterface);
subs.Event<BoundUIClosedEvent>(OnClose);
subs.Event<WriteToTargetAccessReaderIdMessage>(OnWriteToTargetAccessReaderIdMessage);
});
} }
private void AfterInteractOn(EntityUid uid, AccessOverriderComponent component, AfterInteractEvent args) private void AfterInteractOn(EntityUid uid, AccessOverriderComponent component, AfterInteractEvent args)

View File

@@ -16,9 +16,13 @@ public sealed class BlockGameArcadeSystem : EntitySystem
SubscribeLocalEvent<BlockGameArcadeComponent, ComponentInit>(OnComponentInit); SubscribeLocalEvent<BlockGameArcadeComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<BlockGameArcadeComponent, AfterActivatableUIOpenEvent>(OnAfterUIOpen); SubscribeLocalEvent<BlockGameArcadeComponent, AfterActivatableUIOpenEvent>(OnAfterUIOpen);
SubscribeLocalEvent<BlockGameArcadeComponent, BoundUIClosedEvent>(OnAfterUiClose);
SubscribeLocalEvent<BlockGameArcadeComponent, PowerChangedEvent>(OnBlockPowerChanged); SubscribeLocalEvent<BlockGameArcadeComponent, PowerChangedEvent>(OnBlockPowerChanged);
SubscribeLocalEvent<BlockGameArcadeComponent, BlockGameMessages.BlockGamePlayerActionMessage>(OnPlayerAction);
Subs.BuiEvents<BlockGameArcadeComponent>(BlockGameUiKey.Key, subs =>
{
subs.Event<BoundUIClosedEvent>(OnAfterUiClose);
subs.Event<BlockGameMessages.BlockGamePlayerActionMessage>(OnPlayerAction);
});
} }
public override void Update(float frameTime) public override void Update(float frameTime)

View File

@@ -157,19 +157,23 @@ public sealed class AirAlarmSystem : EntitySystem
SubscribeLocalEvent<AirAlarmComponent, AtmosDeviceUpdateEvent>(OnAtmosUpdate); SubscribeLocalEvent<AirAlarmComponent, AtmosDeviceUpdateEvent>(OnAtmosUpdate);
SubscribeLocalEvent<AirAlarmComponent, AtmosAlarmEvent>(OnAtmosAlarm); SubscribeLocalEvent<AirAlarmComponent, AtmosAlarmEvent>(OnAtmosAlarm);
SubscribeLocalEvent<AirAlarmComponent, PowerChangedEvent>(OnPowerChanged); SubscribeLocalEvent<AirAlarmComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<AirAlarmComponent, AirAlarmResyncAllDevicesMessage>(OnResyncAll);
SubscribeLocalEvent<AirAlarmComponent, AirAlarmUpdateAlarmModeMessage>(OnUpdateAlarmMode);
SubscribeLocalEvent<AirAlarmComponent, AirAlarmUpdateAutoModeMessage>(OnUpdateAutoMode);
SubscribeLocalEvent<AirAlarmComponent, AirAlarmUpdateAlarmThresholdMessage>(OnUpdateThreshold);
SubscribeLocalEvent<AirAlarmComponent, AirAlarmUpdateDeviceDataMessage>(OnUpdateDeviceData);
SubscribeLocalEvent<AirAlarmComponent, AirAlarmCopyDeviceDataMessage>(OnCopyDeviceData);
SubscribeLocalEvent<AirAlarmComponent, AirAlarmTabSetMessage>(OnTabChange);
SubscribeLocalEvent<AirAlarmComponent, DeviceListUpdateEvent>(OnDeviceListUpdate); SubscribeLocalEvent<AirAlarmComponent, DeviceListUpdateEvent>(OnDeviceListUpdate);
SubscribeLocalEvent<AirAlarmComponent, BoundUIClosedEvent>(OnClose);
SubscribeLocalEvent<AirAlarmComponent, ComponentInit>(OnInit); SubscribeLocalEvent<AirAlarmComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<AirAlarmComponent, MapInitEvent>(OnMapInit); SubscribeLocalEvent<AirAlarmComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<AirAlarmComponent, ComponentShutdown>(OnShutdown); SubscribeLocalEvent<AirAlarmComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<AirAlarmComponent, ActivateInWorldEvent>(OnActivate); SubscribeLocalEvent<AirAlarmComponent, ActivateInWorldEvent>(OnActivate);
Subs.BuiEvents<AirAlarmComponent>(SharedAirAlarmInterfaceKey.Key, subs =>
{
subs.Event<BoundUIClosedEvent>(OnClose);
subs.Event<AirAlarmResyncAllDevicesMessage>(OnResyncAll);
subs.Event<AirAlarmUpdateAlarmModeMessage>(OnUpdateAlarmMode);
subs.Event<AirAlarmUpdateAutoModeMessage>(OnUpdateAutoMode);
subs.Event<AirAlarmUpdateAlarmThresholdMessage>(OnUpdateThreshold);
subs.Event<AirAlarmUpdateDeviceDataMessage>(OnUpdateDeviceData);
subs.Event<AirAlarmCopyDeviceDataMessage>(OnCopyDeviceData);
subs.Event<AirAlarmTabSetMessage>(OnTabChange);
});
} }
private void OnDeviceListUpdate(EntityUid uid, AirAlarmComponent component, DeviceListUpdateEvent args) private void OnDeviceListUpdate(EntityUid uid, AirAlarmComponent component, DeviceListUpdateEvent args)

View File

@@ -13,6 +13,7 @@ using Content.Shared.StationRecords;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Console; using Robust.Shared.Console;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Server.CrewManifest; namespace Content.Server.CrewManifest;
@@ -37,10 +38,11 @@ public sealed class CrewManifestSystem : EntitySystem
SubscribeLocalEvent<AfterGeneralRecordCreatedEvent>(AfterGeneralRecordCreated); SubscribeLocalEvent<AfterGeneralRecordCreatedEvent>(AfterGeneralRecordCreated);
SubscribeLocalEvent<RecordModifiedEvent>(OnRecordModified); SubscribeLocalEvent<RecordModifiedEvent>(OnRecordModified);
SubscribeLocalEvent<RecordRemovedEvent>(OnRecordRemoved); SubscribeLocalEvent<RecordRemovedEvent>(OnRecordRemoved);
SubscribeLocalEvent<CrewManifestViewerComponent, BoundUIClosedEvent>(OnBoundUiClose);
SubscribeLocalEvent<CrewManifestViewerComponent, CrewManifestOpenUiMessage>(OpenEuiFromBui);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart); SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
SubscribeNetworkEvent<RequestCrewManifestMessage>(OnRequestCrewManifest); SubscribeNetworkEvent<RequestCrewManifestMessage>(OnRequestCrewManifest);
SubscribeLocalEvent<CrewManifestViewerComponent, BoundUIClosedEvent>(OnBoundUiClose);
SubscribeLocalEvent<CrewManifestViewerComponent, CrewManifestOpenUiMessage>(OpenEuiFromBui);
} }
private void OnRoundRestart(RoundRestartCleanupEvent ev) private void OnRoundRestart(RoundRestartCleanupEvent ev)
@@ -91,6 +93,9 @@ public sealed class CrewManifestSystem : EntitySystem
private void OnBoundUiClose(EntityUid uid, CrewManifestViewerComponent component, BoundUIClosedEvent ev) private void OnBoundUiClose(EntityUid uid, CrewManifestViewerComponent component, BoundUIClosedEvent ev)
{ {
if (!Equals(ev.UiKey, component.OwnerKey))
return;
var owningStation = _stationSystem.GetOwningStation(uid); var owningStation = _stationSystem.GetOwningStation(uid);
if (owningStation == null || ev.Session is not { } session) if (owningStation == null || ev.Session is not { } session)
{ {
@@ -124,6 +129,14 @@ public sealed class CrewManifestSystem : EntitySystem
private void OpenEuiFromBui(EntityUid uid, CrewManifestViewerComponent component, CrewManifestOpenUiMessage msg) private void OpenEuiFromBui(EntityUid uid, CrewManifestViewerComponent component, CrewManifestOpenUiMessage msg)
{ {
if (!msg.UiKey.Equals(component.OwnerKey))
{
Log.Error(
"{User} tried to open crew manifest from wrong UI: {Key}. Correct owned is {ExpectedKey}",
msg.Session, msg.UiKey, component.OwnerKey);
return;
}
var owningStation = _stationSystem.GetOwningStation(uid); var owningStation = _stationSystem.GetOwningStation(uid);
if (owningStation == null || msg.Session is not { } session) if (owningStation == null || msg.Session is not { } session)
{ {

View File

@@ -1,3 +1,5 @@
using Content.Shared.CCVar;
namespace Content.Server.CrewManifest; namespace Content.Server.CrewManifest;
[RegisterComponent] [RegisterComponent]
@@ -5,8 +7,14 @@ public sealed partial class CrewManifestViewerComponent : Component
{ {
/// <summary> /// <summary>
/// If this manifest viewer is unsecure or not. If it is, /// If this manifest viewer is unsecure or not. If it is,
/// CCVars.CrewManifestUnsecure being false will /// <see cref="CCVars.CrewManifestUnsecure"/> being false will
/// not allow this entity to be processed by CrewManifestSystem. /// not allow this entity to be processed by CrewManifestSystem.
/// </summary> /// </summary>
[DataField("unsecure")] public bool Unsecure; [DataField("unsecure")] public bool Unsecure;
/// <summary>
/// The owner interface of this crew manifest viewer. When it closes, so too will an opened crew manifest.
/// </summary>
[DataField(required: true)]
public Enum OwnerKey { get; private set; } = default!;
} }

View File

@@ -532,6 +532,13 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
/// </summary> /// </summary>
private void OnUiClosed(EntityUid uid, NetworkConfiguratorComponent component, BoundUIClosedEvent args) private void OnUiClosed(EntityUid uid, NetworkConfiguratorComponent component, BoundUIClosedEvent args)
{ {
if (!args.UiKey.Equals(NetworkConfiguratorUiKey.Configure)
&& !args.UiKey.Equals(NetworkConfiguratorUiKey.Link)
&& !args.UiKey.Equals(NetworkConfiguratorUiKey.List))
{
return;
}
if (TryComp(component.ActiveDeviceList, out DeviceListComponent? list)) if (TryComp(component.ActiveDeviceList, out DeviceListComponent? list))
{ {
list.Configurators.Remove(uid); list.Configurators.Remove(uid);

View File

@@ -58,22 +58,26 @@ namespace Content.Server.Disposal.Tube
SubscribeLocalEvent<DisposalJunctionComponent, GetDisposalsConnectableDirectionsEvent>(OnGetJunctionConnectableDirections); SubscribeLocalEvent<DisposalJunctionComponent, GetDisposalsConnectableDirectionsEvent>(OnGetJunctionConnectableDirections);
SubscribeLocalEvent<DisposalJunctionComponent, GetDisposalsNextDirectionEvent>(OnGetJunctionNextDirection); SubscribeLocalEvent<DisposalJunctionComponent, GetDisposalsNextDirectionEvent>(OnGetJunctionNextDirection);
SubscribeLocalEvent<DisposalRouterComponent, ComponentRemove>(OnComponentRemove);
SubscribeLocalEvent<DisposalRouterComponent, GetDisposalsConnectableDirectionsEvent>(OnGetRouterConnectableDirections); SubscribeLocalEvent<DisposalRouterComponent, GetDisposalsConnectableDirectionsEvent>(OnGetRouterConnectableDirections);
SubscribeLocalEvent<DisposalRouterComponent, GetDisposalsNextDirectionEvent>(OnGetRouterNextDirection); SubscribeLocalEvent<DisposalRouterComponent, GetDisposalsNextDirectionEvent>(OnGetRouterNextDirection);
SubscribeLocalEvent<DisposalTransitComponent, GetDisposalsConnectableDirectionsEvent>(OnGetTransitConnectableDirections); SubscribeLocalEvent<DisposalTransitComponent, GetDisposalsConnectableDirectionsEvent>(OnGetTransitConnectableDirections);
SubscribeLocalEvent<DisposalTransitComponent, GetDisposalsNextDirectionEvent>(OnGetTransitNextDirection); SubscribeLocalEvent<DisposalTransitComponent, GetDisposalsNextDirectionEvent>(OnGetTransitNextDirection);
SubscribeLocalEvent<DisposalTaggerComponent, ComponentRemove>(OnComponentRemove);
SubscribeLocalEvent<DisposalTaggerComponent, GetDisposalsConnectableDirectionsEvent>(OnGetTaggerConnectableDirections); SubscribeLocalEvent<DisposalTaggerComponent, GetDisposalsConnectableDirectionsEvent>(OnGetTaggerConnectableDirections);
SubscribeLocalEvent<DisposalTaggerComponent, GetDisposalsNextDirectionEvent>(OnGetTaggerNextDirection); SubscribeLocalEvent<DisposalTaggerComponent, GetDisposalsNextDirectionEvent>(OnGetTaggerNextDirection);
SubscribeLocalEvent<DisposalRouterComponent, ActivatableUIOpenAttemptEvent>(OnOpenRouterUIAttempt); Subs.BuiEvents<DisposalRouterComponent>(DisposalRouterUiKey.Key, subs =>
SubscribeLocalEvent<DisposalTaggerComponent, ActivatableUIOpenAttemptEvent>(OnOpenTaggerUIAttempt); {
subs.Event<BoundUIOpenedEvent>(OnOpenRouterUI);
subs.Event<SharedDisposalRouterComponent.UiActionMessage>(OnUiAction);
});
SubscribeLocalEvent<DisposalRouterComponent, SharedDisposalRouterComponent.UiActionMessage>(OnUiAction); Subs.BuiEvents<DisposalTaggerComponent>(DisposalTaggerUiKey.Key, subs =>
SubscribeLocalEvent<DisposalTaggerComponent, SharedDisposalTaggerComponent.UiActionMessage>(OnUiAction); {
subs.Event<BoundUIOpenedEvent>(OnOpenTaggerUI);
subs.Event<SharedDisposalTaggerComponent.UiActionMessage>(OnUiAction);
});
} }
@@ -84,15 +88,13 @@ namespace Content.Server.Disposal.Tube
/// <param name="msg">A user interface message from the client.</param> /// <param name="msg">A user interface message from the client.</param>
private void OnUiAction(EntityUid uid, DisposalTaggerComponent tagger, SharedDisposalTaggerComponent.UiActionMessage msg) private void OnUiAction(EntityUid uid, DisposalTaggerComponent tagger, SharedDisposalTaggerComponent.UiActionMessage msg)
{ {
if (!DisposalTaggerUiKey.Key.Equals(msg.UiKey))
return;
if (TryComp<PhysicsComponent>(uid, out var physBody) && physBody.BodyType != BodyType.Static) if (TryComp<PhysicsComponent>(uid, out var physBody) && physBody.BodyType != BodyType.Static)
return; return;
//Check for correct message and ignore maleformed strings //Check for correct message and ignore maleformed strings
if (msg.Action == SharedDisposalTaggerComponent.UiAction.Ok && SharedDisposalTaggerComponent.TagRegex.IsMatch(msg.Tag)) if (msg.Action == SharedDisposalTaggerComponent.UiAction.Ok && SharedDisposalTaggerComponent.TagRegex.IsMatch(msg.Tag))
{ {
tagger.Tag = msg.Tag; tagger.Tag = msg.Tag.Trim();
_audioSystem.PlayPvs(tagger.ClickSound, uid, AudioParams.Default.WithVolume(-2f)); _audioSystem.PlayPvs(tagger.ClickSound, uid, AudioParams.Default.WithVolume(-2f));
} }
} }
@@ -105,8 +107,6 @@ namespace Content.Server.Disposal.Tube
/// <param name="msg">A user interface message from the client.</param> /// <param name="msg">A user interface message from the client.</param>
private void OnUiAction(EntityUid uid, DisposalRouterComponent router, SharedDisposalRouterComponent.UiActionMessage msg) private void OnUiAction(EntityUid uid, DisposalRouterComponent router, SharedDisposalRouterComponent.UiActionMessage msg)
{ {
if (!DisposalRouterUiKey.Key.Equals(msg.UiKey))
return;
if (!EntityManager.EntityExists(msg.Session.AttachedEntity)) if (!EntityManager.EntityExists(msg.Session.AttachedEntity))
return; return;
if (TryComp<PhysicsComponent>(uid, out var physBody) && physBody.BodyType != BodyType.Static) if (TryComp<PhysicsComponent>(uid, out var physBody) && physBody.BodyType != BodyType.Static)
@@ -118,9 +118,14 @@ namespace Content.Server.Disposal.Tube
router.Tags.Clear(); router.Tags.Clear();
foreach (var tag in msg.Tags.Split(',', StringSplitOptions.RemoveEmptyEntries)) foreach (var tag in msg.Tags.Split(',', StringSplitOptions.RemoveEmptyEntries))
{ {
var trimmed = tag.Trim();
if (trimmed == "")
continue;
router.Tags.Add(tag.Trim()); router.Tags.Add(tag.Trim());
_audioSystem.PlayPvs(router.ClickSound, uid, AudioParams.Default.WithVolume(-2f));
} }
_audioSystem.PlayPvs(router.ClickSound, uid, AudioParams.Default.WithVolume(-2f));
} }
} }
@@ -134,16 +139,6 @@ namespace Content.Server.Disposal.Tube
DisconnectTube(uid, tube); DisconnectTube(uid, tube);
} }
private void OnComponentRemove(EntityUid uid, DisposalTaggerComponent tagger, ComponentRemove args)
{
_uiSystem.TryCloseAll(uid, DisposalTaggerUiKey.Key);
}
private void OnComponentRemove(EntityUid uid, DisposalRouterComponent tagger, ComponentRemove args)
{
_uiSystem.TryCloseAll(uid, DisposalRouterUiKey.Key);
}
private void OnGetBendConnectableDirections(EntityUid uid, DisposalBendComponent component, ref GetDisposalsConnectableDirectionsEvent args) private void OnGetBendConnectableDirections(EntityUid uid, DisposalBendComponent component, ref GetDisposalsConnectableDirectionsEvent args)
{ {
var direction = Transform(uid).LocalRotation; var direction = Transform(uid).LocalRotation;
@@ -283,40 +278,18 @@ namespace Content.Server.Disposal.Tube
DisconnectTube(uid, component); DisconnectTube(uid, component);
} }
private void OnOpenRouterUIAttempt(EntityUid uid, DisposalRouterComponent router, ActivatableUIOpenAttemptEvent args) private void OnOpenRouterUI(EntityUid uid, DisposalRouterComponent router, BoundUIOpenedEvent args)
{ {
if (!TryComp<HandsComponent>(args.User, out var hands))
{
_popups.PopupClient(Loc.GetString("disposal-router-window-tag-input-activate-no-hands"), uid, args.User);
return;
}
var activeHandEntity = hands.ActiveHandEntity;
if (activeHandEntity != null)
{
args.Cancel();
}
UpdateRouterUserInterface(uid, router); UpdateRouterUserInterface(uid, router);
} }
private void OnOpenTaggerUIAttempt(EntityUid uid, DisposalTaggerComponent tagger, ActivatableUIOpenAttemptEvent args) private void OnOpenTaggerUI(EntityUid uid, DisposalTaggerComponent tagger, BoundUIOpenedEvent args)
{ {
if (!TryComp<HandsComponent>(args.User, out var hands))
{
_popups.PopupClient(Loc.GetString("disposal-tagger-window-activate-no-hands"), uid, args.User);
return;
}
var activeHandEntity = hands.ActiveHandEntity;
if (activeHandEntity != null)
{
args.Cancel();
}
if (_uiSystem.TryGetUi(uid, DisposalTaggerUiKey.Key, out var bui)) if (_uiSystem.TryGetUi(uid, DisposalTaggerUiKey.Key, out var bui))
{
_uiSystem.SetUiState(bui, _uiSystem.SetUiState(bui,
new DisposalTaggerUserInterfaceState(tagger.Tag)); new DisposalTaggerUserInterfaceState(tagger.Tag));
}
} }
/// <summary> /// <summary>
@@ -325,11 +298,13 @@ namespace Content.Server.Disposal.Tube
/// <returns>Returns a <see cref="SharedDisposalRouterComponent.DisposalRouterUserInterfaceState"/></returns> /// <returns>Returns a <see cref="SharedDisposalRouterComponent.DisposalRouterUserInterfaceState"/></returns>
private void UpdateRouterUserInterface(EntityUid uid, DisposalRouterComponent router) private void UpdateRouterUserInterface(EntityUid uid, DisposalRouterComponent router)
{ {
var bui = _uiSystem.GetUiOrNull(uid, DisposalTaggerUiKey.Key); var bui = _uiSystem.GetUiOrNull(uid, DisposalRouterUiKey.Key);
if (bui == null)
return;
if (router.Tags.Count <= 0) if (router.Tags.Count <= 0)
{ {
if (bui is not null) _uiSystem.SetUiState(bui, new DisposalRouterUserInterfaceState(""));
_uiSystem.SetUiState(bui, new DisposalTaggerUserInterfaceState(""));
return; return;
} }
@@ -343,8 +318,7 @@ namespace Content.Server.Disposal.Tube
taglist.Remove(taglist.Length - 2, 2); taglist.Remove(taglist.Length - 2, 2);
if (bui is not null) _uiSystem.SetUiState(bui, new DisposalRouterUserInterfaceState(taglist.ToString()));
_uiSystem.SetUiState(bui, new DisposalTaggerUserInterfaceState(taglist.ToString()));
} }
private void OnAnchorChange(EntityUid uid, DisposalTubeComponent component, ref AnchorStateChangedEvent args) private void OnAnchorChange(EntityUid uid, DisposalTubeComponent component, ref AnchorStateChangedEvent args)

View File

@@ -50,9 +50,12 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
SubscribeNetworkEvent<InstrumentSetMasterEvent>(OnMidiSetMaster); SubscribeNetworkEvent<InstrumentSetMasterEvent>(OnMidiSetMaster);
SubscribeNetworkEvent<InstrumentSetFilteredChannelEvent>(OnMidiSetFilteredChannel); SubscribeNetworkEvent<InstrumentSetFilteredChannelEvent>(OnMidiSetFilteredChannel);
SubscribeLocalEvent<InstrumentComponent, BoundUIClosedEvent>(OnBoundUIClosed); Subs.BuiEvents<InstrumentComponent>(InstrumentUiKey.Key, subs =>
SubscribeLocalEvent<InstrumentComponent, BoundUIOpenedEvent>(OnBoundUIOpened); {
SubscribeLocalEvent<InstrumentComponent, InstrumentBandRequestBuiMessage>(OnBoundUIRequestBands); subs.Event<BoundUIClosedEvent>(OnBoundUIClosed);
subs.Event<BoundUIOpenedEvent>(OnBoundUIOpened);
subs.Event<InstrumentBandRequestBuiMessage>(OnBoundUIRequestBands);
});
SubscribeLocalEvent<InstrumentComponent, ComponentGetState>(OnStrumentGetState); SubscribeLocalEvent<InstrumentComponent, ComponentGetState>(OnStrumentGetState);
@@ -197,9 +200,6 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
private void OnBoundUIClosed(EntityUid uid, InstrumentComponent component, BoundUIClosedEvent args) private void OnBoundUIClosed(EntityUid uid, InstrumentComponent component, BoundUIClosedEvent args)
{ {
if (args.UiKey is not InstrumentUiKey)
return;
if (HasComp<ActiveInstrumentComponent>(uid) if (HasComp<ActiveInstrumentComponent>(uid)
&& _bui.TryGetUi(uid, args.UiKey, out var bui) && _bui.TryGetUi(uid, args.UiKey, out var bui)
&& bui.SubscribedSessions.Count == 0) && bui.SubscribedSessions.Count == 0)
@@ -212,9 +212,6 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
private void OnBoundUIOpened(EntityUid uid, InstrumentComponent component, BoundUIOpenedEvent args) private void OnBoundUIOpened(EntityUid uid, InstrumentComponent component, BoundUIOpenedEvent args)
{ {
if (args.UiKey is not InstrumentUiKey)
return;
EnsureComp<ActiveInstrumentComponent>(uid); EnsureComp<ActiveInstrumentComponent>(uid);
Clean(uid, component); Clean(uid, component);
} }

View File

@@ -29,11 +29,15 @@ public sealed class MagicMirrorSystem : EntitySystem
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<MagicMirrorComponent, ActivatableUIOpenAttemptEvent>(OnOpenUIAttempt); SubscribeLocalEvent<MagicMirrorComponent, ActivatableUIOpenAttemptEvent>(OnOpenUIAttempt);
SubscribeLocalEvent<MagicMirrorComponent, BoundUIClosedEvent>(OnUIClosed);
SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorSelectMessage>(OnMagicMirrorSelect); Subs.BuiEvents<MagicMirrorComponent>(MagicMirrorUiKey.Key, subs =>
SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorChangeColorMessage>(OnTryMagicMirrorChangeColor); {
SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorAddSlotMessage>(OnTryMagicMirrorAddSlot); subs.Event<BoundUIClosedEvent>(OnUIClosed);
SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorRemoveSlotMessage>(OnTryMagicMirrorRemoveSlot); subs.Event<MagicMirrorSelectMessage>(OnMagicMirrorSelect);
subs.Event<MagicMirrorChangeColorMessage>(OnTryMagicMirrorChangeColor);
subs.Event<MagicMirrorAddSlotMessage>(OnTryMagicMirrorAddSlot);
subs.Event<MagicMirrorRemoveSlotMessage>(OnTryMagicMirrorRemoveSlot);
});
SubscribeLocalEvent<MagicMirrorComponent, AfterInteractEvent>(OnMagicMirrorInteract); SubscribeLocalEvent<MagicMirrorComponent, AfterInteractEvent>(OnMagicMirrorInteract);

View File

@@ -14,8 +14,12 @@ public sealed class StationMapSystem : EntitySystem
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<StationMapUserComponent, EntParentChangedMessage>(OnUserParentChanged); SubscribeLocalEvent<StationMapUserComponent, EntParentChangedMessage>(OnUserParentChanged);
SubscribeLocalEvent<StationMapComponent, BoundUIOpenedEvent>(OnStationMapOpened);
SubscribeLocalEvent<StationMapComponent, BoundUIClosedEvent>(OnStationMapClosed); Subs.BuiEvents<StationMapComponent>(StationMapUiKey.Key, subs =>
{
subs.Event<BoundUIOpenedEvent>(OnStationMapOpened);
subs.Event<BoundUIClosedEvent>(OnStationMapClosed);
});
} }
private void OnStationMapClosed(EntityUid uid, StationMapComponent component, BoundUIClosedEvent args) private void OnStationMapClosed(EntityUid uid, StationMapComponent component, BoundUIClosedEvent args)

View File

@@ -10,7 +10,10 @@ public sealed partial class SensorMonitoringConsoleSystem
{ {
private void InitUI() private void InitUI()
{ {
SubscribeLocalEvent<SensorMonitoringConsoleComponent, BoundUIClosedEvent>(ConsoleUIClosed); Subs.BuiEvents<SensorMonitoringConsoleComponent>(SensorMonitoringConsoleUiKey.Key, subs =>
{
subs.Event<BoundUIClosedEvent>(ConsoleUIClosed);
});
} }
private void UpdateConsoleUI(EntityUid uid, SensorMonitoringConsoleComponent comp) private void UpdateConsoleUI(EntityUid uid, SensorMonitoringConsoleComponent comp)

View File

@@ -27,7 +27,9 @@ public sealed partial class ShuttleConsoleSystem
private void OnDronePilotConsoleClose(EntityUid uid, DroneConsoleComponent component, BoundUIClosedEvent args) private void OnDronePilotConsoleClose(EntityUid uid, DroneConsoleComponent component, BoundUIClosedEvent args)
{ {
component.Entity = null; // Only if last person closed UI.
if (!_ui.IsUiOpen(uid, args.UiKey))
component.Entity = null;
} }
private void OnCargoGetConsole(EntityUid uid, DroneConsoleComponent component, ref ConsoleShuttleEvent args) private void OnCargoGetConsole(EntityUid uid, DroneConsoleComponent component, ref ConsoleShuttleEvent args)

View File

@@ -43,12 +43,18 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
SubscribeLocalEvent<ShuttleConsoleComponent, PowerChangedEvent>(OnConsolePowerChange); SubscribeLocalEvent<ShuttleConsoleComponent, PowerChangedEvent>(OnConsolePowerChange);
SubscribeLocalEvent<ShuttleConsoleComponent, AnchorStateChangedEvent>(OnConsoleAnchorChange); SubscribeLocalEvent<ShuttleConsoleComponent, AnchorStateChangedEvent>(OnConsoleAnchorChange);
SubscribeLocalEvent<ShuttleConsoleComponent, ActivatableUIOpenAttemptEvent>(OnConsoleUIOpenAttempt); SubscribeLocalEvent<ShuttleConsoleComponent, ActivatableUIOpenAttemptEvent>(OnConsoleUIOpenAttempt);
SubscribeLocalEvent<ShuttleConsoleComponent, ShuttleConsoleFTLRequestMessage>(OnDestinationMessage); Subs.BuiEvents<ShuttleConsoleComponent>(ShuttleConsoleUiKey.Key, subs =>
SubscribeLocalEvent<ShuttleConsoleComponent, BoundUIClosedEvent>(OnConsoleUIClose); {
subs.Event<ShuttleConsoleFTLRequestMessage>(OnDestinationMessage);
subs.Event<BoundUIClosedEvent>(OnConsoleUIClose);
});
SubscribeLocalEvent<DroneConsoleComponent, ConsoleShuttleEvent>(OnCargoGetConsole); SubscribeLocalEvent<DroneConsoleComponent, ConsoleShuttleEvent>(OnCargoGetConsole);
SubscribeLocalEvent<DroneConsoleComponent, AfterActivatableUIOpenEvent>(OnDronePilotConsoleOpen); SubscribeLocalEvent<DroneConsoleComponent, AfterActivatableUIOpenEvent>(OnDronePilotConsoleOpen);
SubscribeLocalEvent<DroneConsoleComponent, BoundUIClosedEvent>(OnDronePilotConsoleClose); Subs.BuiEvents<DroneConsoleComponent>(ShuttleConsoleUiKey.Key, subs =>
{
subs.Event<BoundUIClosedEvent>(OnDronePilotConsoleClose);
});
SubscribeLocalEvent<DockEvent>(OnDock); SubscribeLocalEvent<DockEvent>(OnDock);
SubscribeLocalEvent<UndockEvent>(OnUndock); SubscribeLocalEvent<UndockEvent>(OnUndock);

View File

@@ -34,7 +34,10 @@ public sealed partial class StorageSystem : SharedStorageSystem
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<StorageComponent, GetVerbsEvent<ActivationVerb>>(AddUiVerb); SubscribeLocalEvent<StorageComponent, GetVerbsEvent<ActivationVerb>>(AddUiVerb);
SubscribeLocalEvent<StorageComponent, BoundUIClosedEvent>(OnBoundUIClosed); Subs.BuiEvents<StorageComponent>(StorageComponent.StorageUiKey.Key, subs =>
{
subs.Event<BoundUIClosedEvent>(OnBoundUIClosed);
});
SubscribeLocalEvent<StorageComponent, BeforeExplodeEvent>(OnExploded); SubscribeLocalEvent<StorageComponent, BeforeExplodeEvent>(OnExploded);
SubscribeLocalEvent<StorageFillComponent, MapInitEvent>(OnStorageFillMapInit); SubscribeLocalEvent<StorageFillComponent, MapInitEvent>(OnStorageFillMapInit);

View File

@@ -18,16 +18,19 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, SurveillanceCameraDeactivateEvent>(OnSurveillanceCameraDeactivate); SubscribeLocalEvent<SurveillanceCameraMonitorComponent, SurveillanceCameraDeactivateEvent>(OnSurveillanceCameraDeactivate);
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, BoundUIClosedEvent>(OnBoundUiClose);
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, PowerChangedEvent>(OnPowerChanged); SubscribeLocalEvent<SurveillanceCameraMonitorComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, SurveillanceCameraMonitorSwitchMessage>(OnSwitchMessage);
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, DeviceNetworkPacketEvent>(OnPacketReceived); SubscribeLocalEvent<SurveillanceCameraMonitorComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, SurveillanceCameraMonitorSubnetRequestMessage>(OnSubnetRequest);
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, ComponentStartup>(OnComponentStartup); SubscribeLocalEvent<SurveillanceCameraMonitorComponent, ComponentStartup>(OnComponentStartup);
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, AfterActivatableUIOpenEvent>(OnToggleInterface); SubscribeLocalEvent<SurveillanceCameraMonitorComponent, AfterActivatableUIOpenEvent>(OnToggleInterface);
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, SurveillanceCameraRefreshCamerasMessage>(OnRefreshCamerasMessage); Subs.BuiEvents<SurveillanceCameraMonitorComponent>(SurveillanceCameraMonitorUiKey.Key, subs =>
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, SurveillanceCameraRefreshSubnetsMessage>(OnRefreshSubnetsMessage); {
SubscribeLocalEvent<SurveillanceCameraMonitorComponent, SurveillanceCameraDisconnectMessage>(OnDisconnectMessage); subs.Event<SurveillanceCameraRefreshCamerasMessage>(OnRefreshCamerasMessage);
subs.Event<SurveillanceCameraRefreshSubnetsMessage>(OnRefreshSubnetsMessage);
subs.Event<SurveillanceCameraDisconnectMessage>(OnDisconnectMessage);
subs.Event<SurveillanceCameraMonitorSubnetRequestMessage>(OnSubnetRequest);
subs.Event<SurveillanceCameraMonitorSwitchMessage>(OnSwitchMessage);
subs.Event<BoundUIClosedEvent>(OnBoundUiClose);
});
} }
private const float _maxHeartbeatTime = 300f; private const float _maxHeartbeatTime = 300f;

View File

@@ -31,12 +31,24 @@ public sealed partial class ActivatableUISystem
private void OnBatteryOpened(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIOpenedEvent args) private void OnBatteryOpened(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIOpenedEvent args)
{ {
var activatable = Comp<ActivatableUIComponent>(uid);
if (!args.UiKey.Equals(activatable.Key))
return;
_cell.SetPowerCellDrawEnabled(uid, true); _cell.SetPowerCellDrawEnabled(uid, true);
} }
private void OnBatteryClosed(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIClosedEvent args) private void OnBatteryClosed(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIClosedEvent args)
{ {
_cell.SetPowerCellDrawEnabled(uid, false); var activatable = Comp<ActivatableUIComponent>(uid);
if (!args.UiKey.Equals(activatable.Key))
return;
// Stop drawing power if this was the last person with the UI open.
if (!_uiSystem.IsUiOpen(uid, activatable.Key))
_cell.SetPowerCellDrawEnabled(uid, false);
} }
/// <summary> /// <summary>

View File

@@ -124,16 +124,7 @@ public sealed partial class ActivatableUISystem : EntitySystem
private bool InteractUI(EntityUid user, EntityUid uiEntity, ActivatableUIComponent aui) private bool InteractUI(EntityUid user, EntityUid uiEntity, ActivatableUIComponent aui)
{ {
if (!_blockerSystem.CanInteract(user, uiEntity) && (!aui.AllowSpectator || !HasComp<GhostComponent>(user))) if (!TryComp(user, out ActorComponent? actor))
return false;
if (aui.RequireHands && !HasComp<HandsComponent>(user))
return false;
if (!EntityManager.TryGetComponent(user, out ActorComponent? actor))
return false;
if (aui.AdminOnly && !_adminManager.IsAdmin(actor.PlayerSession))
return false; return false;
if (aui.Key == null) if (aui.Key == null)
@@ -142,6 +133,21 @@ public sealed partial class ActivatableUISystem : EntitySystem
if (!_uiSystem.TryGetUi(uiEntity, aui.Key, out var ui)) if (!_uiSystem.TryGetUi(uiEntity, aui.Key, out var ui))
return false; return false;
if (ui.SubscribedSessions.Contains(actor.PlayerSession))
{
_uiSystem.CloseUi(ui, actor.PlayerSession);
return true;
}
if (!_blockerSystem.CanInteract(user, uiEntity) && (!aui.AllowSpectator || !HasComp<GhostComponent>(user)))
return false;
if (aui.RequireHands && !HasComp<HandsComponent>(user))
return false;
if (aui.AdminOnly && !_adminManager.IsAdmin(actor.PlayerSession))
return false;
if (aui.SingleUser && (aui.CurrentSingleUser != null) && (actor.PlayerSession != aui.CurrentSingleUser)) if (aui.SingleUser && (aui.CurrentSingleUser != null) && (actor.PlayerSession != aui.CurrentSingleUser))
{ {
string message = Loc.GetString("machine-already-in-use", ("machine", uiEntity)); string message = Loc.GetString("machine-already-in-use", ("machine", uiEntity));
@@ -169,7 +175,7 @@ public sealed partial class ActivatableUISystem : EntitySystem
RaiseLocalEvent(uiEntity, bae); RaiseLocalEvent(uiEntity, bae);
SetCurrentSingleUser(uiEntity, actor.PlayerSession, aui); SetCurrentSingleUser(uiEntity, actor.PlayerSession, aui);
_uiSystem.ToggleUi(ui, actor.PlayerSession); _uiSystem.OpenUi(ui, actor.PlayerSession);
//Let the component know a user opened it so it can do whatever it needs to do //Let the component know a user opened it so it can do whatever it needs to do
var aae = new AfterActivatableUIOpenEvent(user, actor.PlayerSession); var aae = new AfterActivatableUIOpenEvent(user, actor.PlayerSession);

View File

@@ -56,9 +56,13 @@ namespace Content.Server.VendingMachines
SubscribeLocalEvent<VendingMachineComponent, EmpPulseEvent>(OnEmpPulse); SubscribeLocalEvent<VendingMachineComponent, EmpPulseEvent>(OnEmpPulse);
SubscribeLocalEvent<VendingMachineComponent, ActivatableUIOpenAttemptEvent>(OnActivatableUIOpenAttempt); SubscribeLocalEvent<VendingMachineComponent, ActivatableUIOpenAttemptEvent>(OnActivatableUIOpenAttempt);
SubscribeLocalEvent<VendingMachineComponent, BoundUIOpenedEvent>(OnBoundUIOpened);
SubscribeLocalEvent<VendingMachineComponent, BoundUIClosedEvent>(OnBoundUIClosed); Subs.BuiEvents<VendingMachineComponent>(VendingMachineUiKey.Key, subs =>
SubscribeLocalEvent<VendingMachineComponent, VendingMachineEjectMessage>(OnInventoryEjectMessage); {
subs.Event<BoundUIOpenedEvent>(OnBoundUIOpened);
subs.Event<BoundUIClosedEvent>(OnBoundUIClosed);
subs.Event<VendingMachineEjectMessage>(OnInventoryEjectMessage);
});
SubscribeLocalEvent<VendingMachineComponent, VendingMachineSelfDispenseEvent>(OnSelfDispense); SubscribeLocalEvent<VendingMachineComponent, VendingMachineSelfDispenseEvent>(OnSelfDispense);
@@ -114,12 +118,6 @@ namespace Content.Server.VendingMachines
private void OnBoundUIClosed(EntityUid uid, VendingMachineComponent component, BoundUIClosedEvent args) private void OnBoundUIClosed(EntityUid uid, VendingMachineComponent component, BoundUIClosedEvent args)
{ {
if (args.UiKey is not VendingMachineUiKey)
return;
if ((VendingMachineUiKey) args.UiKey != VendingMachineUiKey.Key)
return;
// Only vendors that advertise will send message after dispensing // Only vendors that advertise will send message after dispensing
if (component.ShouldSayThankYou && TryComp<AdvertiseComponent>(uid, out var advertise)) if (component.ShouldSayThankYou && TryComp<AdvertiseComponent>(uid, out var advertise))
{ {

View File

@@ -4,7 +4,6 @@ disposal-router-window-title = Disposal Router
disposal-router-window-tags-label = Tags: disposal-router-window-tags-label = Tags:
disposal-router-window-tag-input-tooltip = A comma separated list of tags disposal-router-window-tag-input-tooltip = A comma separated list of tags
disposal-router-window-tag-input-confirm-button = Confirm disposal-router-window-tag-input-confirm-button = Confirm
disposal-router-window-tag-input-activate-no-hands = You have no hands
## ConfigureVerb ## ConfigureVerb

View File

@@ -1,7 +1,6 @@
disposal-tagger-window-title = Disposal Tagger disposal-tagger-window-title = Disposal Tagger
disposal-tagger-window-tag-input-label = Tag: disposal-tagger-window-tag-input-label = Tag:
disposal-tagger-window-tag-confirm-button = Confirm disposal-tagger-window-tag-confirm-button = Confirm
disposal-tagger-window-activate-no-hands = You have no hands.
## ConfigureVerb ## ConfigureVerb
configure-verb-get-data-text = Open Configuration configure-verb-get-data-text = Open Configuration

View File

@@ -99,8 +99,6 @@
type: InstrumentBoundUserInterface type: InstrumentBoundUserInterface
- key: enum.HealthAnalyzerUiKey.Key - key: enum.HealthAnalyzerUiKey.Key
type: HealthAnalyzerBoundUserInterface type: HealthAnalyzerBoundUserInterface
- type: CrewManifestViewer
unsecure: true
- type: Tag - type: Tag
tags: tags:
- DoorBumpOpener - DoorBumpOpener

View File

@@ -486,6 +486,7 @@
- key: enum.IdCardConsoleUiKey.Key - key: enum.IdCardConsoleUiKey.Key
type: IdCardConsoleBoundUserInterface type: IdCardConsoleBoundUserInterface
- type: CrewManifestViewer - type: CrewManifestViewer
ownerKey: enum.IdCardConsoleUiKey.Key
- type: Sprite - type: Sprite
layers: layers:
- map: ["computerLayerBody"] - map: ["computerLayerBody"]