uplink locking/unlocking, minor pda refactor (#15842)

Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
deltanedas
2023-05-01 06:30:08 +00:00
committed by GitHub
parent 904d61baee
commit 44f9c098ec
13 changed files with 134 additions and 49 deletions

View File

@@ -53,11 +53,14 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
_menu.UpdateBalance(msg.Balance);
_menu.PopulateStoreCategoryButtons(msg.Listings);
_menu.UpdateListing(msg.Listings.ToList());
_menu.SetFooterVisibility(msg.ShowFooter);
break;
case StoreInitializeState msg:
_windowName = msg.Name;
if (_menu != null && _menu.Window != null)
{
_menu.Window.Title = msg.Name;
}
break;
}
}

View File

@@ -50,5 +50,15 @@
</BoxContainer>
</PanelContainer>
</BoxContainer>
<!-- Footer -->
<BoxContainer Orientation="Vertical" Name="TraitorFooter">
<PanelContainer StyleClasses="LowDivider" />
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
<Label Text="{Loc 'store-ui-traitor-flavor'}" StyleClasses="WindowFooterText" />
<Label Text="{Loc 'store-ui-traitor-warning'}" StyleClasses="WindowFooterText"
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
</BoxContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -77,6 +77,11 @@ public sealed partial class StoreMenu : DefaultWindow
}
}
public void SetFooterVisibility(bool visible)
{
TraitorFooter.Visible = visible;
}
private void OnWithdrawButtonDown(BaseButton.ButtonEventArgs args)
{
// check if window is already open

View File

@@ -82,11 +82,13 @@ public sealed class RenameCommand : IConsoleCommand
// PDAs
if (entSysMan.TryGetEntitySystem<PDASystem>(out var pdaSystem))
{
foreach (var pdaComponent in entMan.EntityQuery<PDAComponent>())
var query = entMan.EntityQueryEnumerator<PDAComponent>();
while (query.MoveNext(out var uid, out var pda))
{
if (pdaComponent.OwnerName != oldName)
continue;
pdaSystem.SetOwner(pdaComponent, name);
if (pda.OwnerName == oldName)
{
pdaSystem.SetOwner(uid, pda, name);
}
}
}

View File

@@ -6,6 +6,8 @@ using Content.Server.Light.EntitySystems;
using Content.Server.Light.Events;
using Content.Server.PDA.Ringer;
using Content.Server.Station.Systems;
using Content.Server.Store.Components;
using Content.Server.Store.Systems;
using Content.Server.UserInterface;
using Content.Shared.PDA;
using Robust.Server.GameObjects;
@@ -18,12 +20,13 @@ namespace Content.Server.PDA
{
public sealed class PDASystem : SharedPDASystem
{
[Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!;
[Dependency] private readonly InstrumentSystem _instrument = default!;
[Dependency] private readonly RingerSystem _ringer = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly StoreSystem _store = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly UnpoweredFlashlightSystem _unpoweredFlashlight = default!;
[Dependency] private readonly RingerSystem _ringerSystem = default!;
[Dependency] private readonly InstrumentSystem _instrumentSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly StationSystem _stationSystem = default!;
[Dependency] private readonly CartridgeLoaderSystem _cartridgeLoaderSystem = default!;
public override void Initialize()
{
@@ -40,43 +43,46 @@ namespace Content.Server.PDA
if (!TryComp(uid, out ServerUserInterfaceComponent? uiComponent))
return;
UpdateStationName(pda);
UpdateStationName(uid, pda);
if (_uiSystem.TryGetUi(uid, PDAUiKey.Key, out var ui, uiComponent))
if (_ui.TryGetUi(uid, PDAUiKey.Key, out var ui, uiComponent))
ui.OnReceiveMessage += (msg) => OnUIMessage(pda, msg);
}
protected override void OnItemInserted(EntityUid uid, PDAComponent pda, EntInsertedIntoContainerMessage args)
{
base.OnItemInserted(uid, pda, args);
UpdatePDAUserInterface(pda);
UpdatePdaUi(uid, pda);
}
protected override void OnItemRemoved(EntityUid uid, PDAComponent pda, EntRemovedFromContainerMessage args)
{
base.OnItemRemoved(uid, pda, args);
UpdatePDAUserInterface(pda);
UpdatePdaUi(uid, pda);
}
private void OnLightToggle(EntityUid uid, PDAComponent pda, LightToggleEvent args)
{
pda.FlashlightOn = args.IsOn;
UpdatePDAUserInterface(pda);
UpdatePdaUi(uid, pda);
}
public void SetOwner(PDAComponent pda, string ownerName)
public void SetOwner(EntityUid uid, PDAComponent pda, string ownerName)
{
pda.OwnerName = ownerName;
UpdatePDAUserInterface(pda);
UpdatePdaUi(uid, pda);
}
private void OnGridChanged(EntityUid uid, PDAComponent pda, GridModifiedEvent args)
{
UpdateStationName(pda);
UpdatePDAUserInterface(pda);
UpdateStationName(uid, pda);
UpdatePdaUi(uid, pda);
}
private void UpdatePDAUserInterface(PDAComponent pda)
/// <summary>
/// Send new UI state to clients, call if you modify something like uplink.
/// </summary>
public void UpdatePdaUi(EntityUid uid, PDAComponent pda)
{
var ownerInfo = new PDAIdInfoText
{
@@ -85,49 +91,62 @@ namespace Content.Server.PDA
JobTitle = pda.ContainedID?.JobTitle
};
if (!_uiSystem.TryGetUi(pda.Owner, PDAUiKey.Key, out var ui))
if (!_ui.TryGetUi(uid, PDAUiKey.Key, out var ui))
return;
var address = GetDeviceNetAddress(pda.Owner);
var hasInstrument = HasComp<InstrumentComponent>(pda.Owner);
var state = new PDAUpdateState(pda.FlashlightOn, pda.PenSlot.HasItem, ownerInfo, pda.StationName, false, hasInstrument, address);
var address = GetDeviceNetAddress(uid);
var hasInstrument = HasComp<InstrumentComponent>(uid);
var showUplink = HasComp<StoreComponent>(uid) && IsUnlocked(uid);
_cartridgeLoaderSystem?.UpdateUiState(pda.Owner, state);
var state = new PDAUpdateState(pda.FlashlightOn, pda.PenSlot.HasItem, ownerInfo, pda.StationName, showUplink, hasInstrument, address);
_cartridgeLoader?.UpdateUiState(uid, state);
}
private void OnUIMessage(PDAComponent pda, ServerBoundUserInterfaceMessage msg)
{
var pdaEnt = pda.Owner;
var uid = pda.Owner;
// todo: move this to entity events
switch (msg.Message)
{
case PDARequestUpdateInterfaceMessage _:
UpdatePDAUserInterface(pda);
UpdatePdaUi(uid, pda);
break;
case PDAToggleFlashlightMessage _:
{
if (EntityManager.TryGetComponent(pdaEnt, out UnpoweredFlashlightComponent? flashlight))
_unpoweredFlashlight.ToggleLight(pdaEnt, flashlight);
if (TryComp<UnpoweredFlashlightComponent>(uid, out var flashlight))
_unpoweredFlashlight.ToggleLight(uid, flashlight);
break;
}
case PDAShowRingtoneMessage _:
{
if (EntityManager.TryGetComponent(pdaEnt, out RingerComponent? ringer))
_ringerSystem.ToggleRingerUI(ringer, msg.Session);
if (TryComp<RingerComponent>(uid, out var ringer))
_ringer.ToggleRingerUI(ringer, msg.Session);
break;
}
case PDAShowMusicMessage _:
{
if (TryComp(pdaEnt, out InstrumentComponent? instrument))
_instrumentSystem.ToggleInstrumentUi(pdaEnt, msg.Session, instrument);
if (TryComp<InstrumentComponent>(uid, out var instrument))
_instrument.ToggleInstrumentUi(uid, msg.Session, instrument);
break;
}
case PDAShowUplinkMessage _:
{
// check if its locked again to prevent malicious clients opening locked uplinks
if (TryComp<StoreComponent>(uid, out var store) && IsUnlocked(uid))
_store.ToggleUi(msg.Session.AttachedEntity!.Value, uid, store);
break;
}
}
}
private void UpdateStationName(PDAComponent pda)
private bool IsUnlocked(EntityUid uid)
{
var station = _stationSystem.GetOwningStation(pda.Owner);
return TryComp<RingerUplinkComponent>(uid, out var uplink) ? uplink.Unlocked : true;
}
private void UpdateStationName(EntityUid uid, PDAComponent pda)
{
var station = _station.GetOwningStation(uid);
pda.StationName = station is null ? null : Name(station.Value);
}

View File

@@ -3,6 +3,8 @@ using Content.Server.Store.Systems;
using Content.Server.UserInterface;
using Content.Shared.PDA;
using Content.Shared.PDA.Ringer;
using Content.Shared.Store;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Player;
@@ -14,8 +16,10 @@ namespace Content.Server.PDA.Ringer
{
public sealed class RingerSystem : SharedRingerSystem
{
[Dependency] private readonly PDASystem _pda = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly StoreSystem _store = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
public override void Initialize()
{
@@ -26,7 +30,7 @@ namespace Content.Server.PDA.Ringer
SubscribeLocalEvent<RingerUplinkComponent, ComponentInit>(RandomizeUplinkCode);
// RingerBoundUserInterface Subscriptions
SubscribeLocalEvent<RingerComponent, RingerSetRingtoneMessage>(OnSetRingtone);
SubscribeLocalEvent<RingerUplinkComponent, RingerSetRingtoneMessage>(OnSetUplinkRingtone);
SubscribeLocalEvent<RingerUplinkComponent, BeforeRingtoneSetEvent>(OnSetUplinkRingtone);
SubscribeLocalEvent<RingerComponent, RingerPlayRingtoneMessage>(RingerPlayRingtone);
SubscribeLocalEvent<RingerComponent, RingerRequestUpdateInterfaceMessage>(UpdateRingerUserInterfaceDriver);
@@ -50,17 +54,28 @@ namespace Content.Server.PDA.Ringer
// Client sent us an updated ringtone so set it to that.
if (args.Ringtone.Length != RingtoneLength) return;
var ev = new BeforeRingtoneSetEvent(args.Ringtone);
RaiseLocalEvent(uid, ref ev);
if (ev.Handled)
return;
UpdateRingerRingtone(ringer, args.Ringtone);
}
private void OnSetUplinkRingtone(EntityUid uid, RingerUplinkComponent uplink, RingerSetRingtoneMessage args)
private void OnSetUplinkRingtone(EntityUid uid, RingerUplinkComponent uplink, ref BeforeRingtoneSetEvent args)
{
if (uplink.Code.SequenceEqual(args.Ringtone) &&
args.Session.AttachedEntity != null &&
TryComp<StoreComponent>(uid, out var store))
if (uplink.Code.SequenceEqual(args.Ringtone) && TryComp<StoreComponent>(uid, out var store))
{
var user = args.Session.AttachedEntity.Value;
_store.ToggleUi(args.Session.AttachedEntity.Value, uid, store);
uplink.Unlocked = !uplink.Unlocked;
if (TryComp<PDAComponent>(uid, out var pda))
_pda.UpdatePdaUi(uid, pda);
// can't keep store open after locking it
if (!uplink.Unlocked)
_ui.TryCloseAll(uid, StoreUiKey.Key);
// no saving the code to prevent meta click set on sus guys pda -> wewlad
args.Handled = true;
}
}
@@ -161,3 +176,6 @@ namespace Content.Server.PDA.Ringer
}
}
}
[ByRefEvent]
public record struct BeforeRingtoneSetEvent(Note[] Ringtone, bool Handled = false);

View File

@@ -10,9 +10,15 @@ namespace Content.Server.PDA.Ringer;
public sealed class RingerUplinkComponent : Component
{
/// <summary>
/// Notes to set ringtone to in order to open the uplink.
/// Notes to set ringtone to in order to lock or unlock the uplink.
/// Automatically initialized to random notes.
/// </summary>
[DataField("code")]
public Note[] Code = new Note[RingerSystem.RingtoneLength];
/// <summary>
/// Whether to show the toggle uplink button in pda settings.
/// </summary>
[DataField("unlocked"), ViewVariables(VVAccess.ReadWrite)]
public bool Unlocked;
}

View File

@@ -231,7 +231,7 @@ public sealed class StationSpawningSystem : EntitySystem
_accessSystem.SetAccessToJob(cardId, jobPrototype, extendedAccess);
_pdaSystem.SetOwner(pdaComponent, characterName);
_pdaSystem.SetOwner(idUid.Value, pdaComponent, characterName);
}

View File

@@ -1,5 +1,6 @@
using Content.Server.Actions;
using Content.Server.Administration.Logs;
using Content.Server.PDA.Ringer;
using Content.Server.Stack;
using Content.Server.Store.Components;
using Content.Server.UserInterface;
@@ -49,6 +50,17 @@ public sealed partial class StoreSystem
UpdateUserInterface(user, storeEnt, component);
}
/// <summary>
/// Closes the store UI for everyone, if it's open
/// </summary>
public void CloseUi(EntityUid uid, StoreComponent? component = null)
{
if (!Resolve(uid, ref component))
return;
_ui.TryCloseAll(uid, StoreUiKey.Key);
}
/// <summary>
/// Updates the user interface for a store and refreshes the listings
/// </summary>
@@ -83,7 +95,9 @@ public sealed partial class StoreSystem
// TODO: if multiple users are supposed to be able to interact with a single BUI & see different
// stores/listings, this needs to use session specific BUI states.
var state = new StoreUpdateState(component.LastAvailableListings, allCurrency);
// only tell operatives to lock their uplink if it can be locked
var showFooter = HasComp<RingerUplinkComponent>(store);
var state = new StoreUpdateState(component.LastAvailableListings, allCurrency, showFooter);
_ui.SetUiState(ui, state);
}

View File

@@ -1,4 +1,5 @@
using Content.Server.Mind.Components;
using Content.Server.PDA.Ringer;
using Content.Server.Store.Components;
using Content.Server.UserInterface;
using Content.Shared.FixedPoint;
@@ -72,9 +73,9 @@ public sealed partial class StoreSystem : EntitySystem
if (args.Target == null || !TryComp<StoreComponent>(args.Target, out var store))
return;
// require the store to be open before inserting currency
// if the store can be locked, it must be unlocked first before inserting currency
var user = args.User;
if (!TryComp<ActorComponent>(user, out var actor) || !_ui.SessionHasOpenUi(uid, StoreUiKey.Key, actor.PlayerSession))
if (TryComp<RingerUplinkComponent>(args.Target, out var uplink) && !uplink.Unlocked)
return;
args.Handled = TryAddCurrency(GetCurrencyValue(uid, component), args.Target.Value, store);
@@ -183,6 +184,8 @@ public sealed partial class StoreSystem : EntitySystem
var ui = _ui.GetUiOrNull(uid, StoreUiKey.Key);
if (ui != null)
{
_ui.SetUiState(ui, new StoreInitializeState(preset.StoreName));
}
}
}

View File

@@ -16,10 +16,13 @@ public sealed class StoreUpdateState : BoundUserInterfaceState
public readonly Dictionary<string, FixedPoint2> Balance;
public StoreUpdateState(HashSet<ListingData> listings, Dictionary<string, FixedPoint2> balance)
public readonly bool ShowFooter;
public StoreUpdateState(HashSet<ListingData> listings, Dictionary<string, FixedPoint2> balance, bool showFooter)
{
Listings = listings;
Balance = balance;
ShowFooter = showFooter;
}
}

View File

@@ -53,7 +53,7 @@ traitor-role-codewords =
Listen for them, and keep them secret.
traitor-role-uplink-code =
Set your ringtone to the notes {$code} to lock or unlock your uplink.
Remember to lock it and change it, or the stations crew will easily open it too!
Remember to lock it after, or the stations crew will easily open it too!
# don't need all the flavour text for character menu
traitor-role-codewords-short =

View File

@@ -2,5 +2,7 @@ store-ui-default-title = Store
store-ui-default-withdraw-text = Withdraw
store-ui-balance-display = {$currency}: {$amount}
store-ui-price-display = {$amount} {$currency}
store-ui-traitor-flavor = Copyright (C) NT -30643
store-ui-traitor-warning = Operatives must lock their uplinks after use to avoid detection.
store-withdraw-button-ui = Withdraw {$currency}