From 351c53e774dd6cf60bcee3b47c4eb839baba582e Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sun, 12 Feb 2023 07:39:14 -0500 Subject: [PATCH] Clean up StoreSystem (#14027) --- Content.Server/PDA/PDASystem.cs | 19 ++--- .../EntitySystems/RevenantSystem.Abilities.cs | 11 +-- .../Revenant/EntitySystems/RevenantSystem.cs | 7 +- .../Store/Components/StoreComponent.cs | 11 +-- .../Store/Systems/StoreSystem.Listings.cs | 10 +-- .../Store/Systems/StoreSystem.Ui.cs | 66 +++++++++-------- Content.Server/Store/Systems/StoreSystem.cs | 73 ++++++++++++------- Content.Server/Traitor/Uplink/UplinkSystem.cs | 7 +- .../TraitorDeathMatchRedemptionSystem.cs | 5 +- 9 files changed, 108 insertions(+), 101 deletions(-) diff --git a/Content.Server/PDA/PDASystem.cs b/Content.Server/PDA/PDASystem.cs index 1792e7e142..fd8626cf74 100644 --- a/Content.Server/PDA/PDASystem.cs +++ b/Content.Server/PDA/PDASystem.cs @@ -76,12 +76,12 @@ namespace Content.Server.PDA UpdatePDAUserInterface(pda); } - private void OnUplinkInit(EntityUid uid, PDAComponent pda, StoreAddedEvent args) + private void OnUplinkInit(EntityUid uid, PDAComponent pda, ref StoreAddedEvent args) { UpdatePDAUserInterface(pda); } - private void OnUplinkRemoved(EntityUid uid, PDAComponent pda, StoreRemovedEvent args) + private void OnUplinkRemoved(EntityUid uid, PDAComponent pda, ref StoreRemovedEvent args) { UpdatePDAUserInterface(pda); } @@ -132,6 +132,7 @@ namespace Content.Server.PDA private void OnUIMessage(PDAComponent pda, ServerBoundUserInterfaceMessage msg) { + var pdaEnt = pda.Owner; // todo: move this to entity events switch (msg.Message) { @@ -140,28 +141,28 @@ namespace Content.Server.PDA break; case PDAToggleFlashlightMessage _: { - if (EntityManager.TryGetComponent(pda.Owner, out UnpoweredFlashlightComponent? flashlight)) - _unpoweredFlashlight.ToggleLight(flashlight.Owner, flashlight); + if (EntityManager.TryGetComponent(pdaEnt, out UnpoweredFlashlightComponent? flashlight)) + _unpoweredFlashlight.ToggleLight(pdaEnt, flashlight); break; } case PDAShowUplinkMessage _: { if (msg.Session.AttachedEntity != null && - TryComp(pda.Owner, out var store)) - _storeSystem.ToggleUi(msg.Session.AttachedEntity.Value, store); + TryComp(pdaEnt, out var store)) + _storeSystem.ToggleUi(msg.Session.AttachedEntity.Value, pdaEnt, store); break; } case PDAShowRingtoneMessage _: { - if (EntityManager.TryGetComponent(pda.Owner, out RingerComponent? ringer)) + if (EntityManager.TryGetComponent(pdaEnt, out RingerComponent? ringer)) _ringerSystem.ToggleRingerUI(ringer, msg.Session); break; } case PDAShowMusicMessage _: { - if (TryComp(pda.Owner, out InstrumentComponent? instrument)) - _instrumentSystem.ToggleInstrumentUi(pda.Owner, msg.Session, instrument); + if (TryComp(pdaEnt, out InstrumentComponent? instrument)) + _instrumentSystem.ToggleInstrumentUi(pdaEnt, msg.Session, instrument); break; } } diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index b26692144d..ee5d603edd 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -19,7 +19,6 @@ using Content.Shared.Bed.Sleep; using System.Linq; using Content.Server.Maps; using Content.Server.Revenant.Components; -using Content.Server.Store.Components; using Content.Shared.Emag.Systems; using Content.Shared.FixedPoint; using Content.Shared.Humanoid; @@ -29,7 +28,6 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Revenant.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Utility; -using Content.Shared.Humanoid; namespace Content.Server.Revenant.EntitySystems; @@ -180,13 +178,10 @@ public sealed partial class RevenantSystem essence.Harvested = true; ChangeEssenceAmount(uid, essence.EssenceAmount, component); - if (TryComp(uid, out var store)) - { - _store.TryAddCurrency(new Dictionary() - { {component.StolenEssenceCurrencyPrototype, essence.EssenceAmount} }, store); - } + _store.TryAddCurrency(new Dictionary + { {component.StolenEssenceCurrencyPrototype, essence.EssenceAmount} }, uid); - if (!TryComp(args.Target, out var mobstate)) + if (!HasComp(args.Target)) return; if (_mobState.IsAlive(args.Target) || _mobState.IsCritical(args.Target)) diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.cs index 8b1529ea42..b8d78f5803 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.cs @@ -18,7 +18,6 @@ using Content.Shared.Tag; using Content.Server.Store.Components; using Content.Server.Store.Systems; using Content.Shared.FixedPoint; -using Robust.Shared.Player; using Content.Shared.Maps; using Content.Shared.Mobs.Systems; using Content.Shared.Physics; @@ -80,7 +79,7 @@ public sealed partial class RevenantSystem : EntitySystem } //ghost vision - if (TryComp(component.Owner, out EyeComponent? eye)) + if (TryComp(uid, out EyeComponent? eye)) eye.VisibilityMask |= (uint) (VisibilityFlags.Ghost); var shopaction = new InstantAction(_proto.Index("RevenantShop")); @@ -131,7 +130,7 @@ public sealed partial class RevenantSystem : EntitySystem FixedPoint2.Min(component.Essence, component.EssenceRegenCap); if (TryComp(uid, out var store)) - _store.UpdateUserInterface(uid, store); + _store.UpdateUserInterface(uid, uid, store); _alerts.ShowAlert(uid, AlertType.Essence, (short) Math.Clamp(Math.Round(component.Essence.Float() / 10f), 0, 16)); @@ -172,7 +171,7 @@ public sealed partial class RevenantSystem : EntitySystem { if (!TryComp(uid, out var store)) return; - _store.ToggleUi(uid, store); + _store.ToggleUi(uid, uid, store); } public void MakeVisible(bool visible) diff --git a/Content.Server/Store/Components/StoreComponent.cs b/Content.Server/Store/Components/StoreComponent.cs index 16b89c754b..43f038effa 100644 --- a/Content.Server/Store/Components/StoreComponent.cs +++ b/Content.Server/Store/Components/StoreComponent.cs @@ -59,11 +59,6 @@ public sealed class StoreComponent : Component [ViewVariables] public HashSet LastAvailableListings = new(); - /// - /// checks whether or not the store has been opened yet. - /// - public bool Opened = false; - #region audio /// /// The sound played to the buyer when a purchase is succesfully made. @@ -76,8 +71,10 @@ public sealed class StoreComponent : Component /// /// Event that is broadcast when a store is added to an entity /// -public sealed class StoreAddedEvent : EntityEventArgs { }; +[ByRefEvent] +public readonly record struct StoreAddedEvent; /// /// Event that is broadcast when a store is removed from an entity /// -public sealed class StoreRemovedEvent : EntityEventArgs { }; +[ByRefEvent] +public readonly record struct StoreRemovedEvent; diff --git a/Content.Server/Store/Systems/StoreSystem.Listings.cs b/Content.Server/Store/Systems/StoreSystem.Listings.cs index 55bd2ccfa3..b5d1ae79be 100644 --- a/Content.Server/Store/Systems/StoreSystem.Listings.cs +++ b/Content.Server/Store/Systems/StoreSystem.Listings.cs @@ -3,7 +3,7 @@ using Content.Shared.Store; namespace Content.Server.Store.Systems; -public sealed partial class StoreSystem : EntitySystem +public sealed partial class StoreSystem { /// /// Refreshes all listings on a store. @@ -64,11 +64,12 @@ public sealed partial class StoreSystem : EntitySystem /// Gets the available listings for a store /// /// Either the account owner, user, or an inanimate object (e.g., surplus bundle) + /// /// The store the listings are coming from. /// The available listings. - public IEnumerable GetAvailableListings(EntityUid buyer, StoreComponent component) + public IEnumerable GetAvailableListings(EntityUid buyer, EntityUid store, StoreComponent component) { - return GetAvailableListings(buyer, component.Listings, component.Categories, component.Owner); + return GetAvailableListings(buyer, component.Listings, component.Categories, store); } /// @@ -81,8 +82,7 @@ public sealed partial class StoreSystem : EntitySystem /// The available listings. public IEnumerable GetAvailableListings(EntityUid buyer, HashSet? listings, HashSet categories, EntityUid? storeEntity = null) { - if (listings == null) - listings = GetAllListings(); + listings ??= GetAllListings(); foreach (var listing in listings) { diff --git a/Content.Server/Store/Systems/StoreSystem.Ui.cs b/Content.Server/Store/Systems/StoreSystem.Ui.cs index 228af4120c..6136a69ec4 100644 --- a/Content.Server/Store/Systems/StoreSystem.Ui.cs +++ b/Content.Server/Store/Systems/StoreSystem.Ui.cs @@ -1,6 +1,5 @@ using Content.Server.Actions; using Content.Server.Administration.Logs; -using Content.Server.Mind.Components; using Content.Server.Store.Components; using Content.Shared.Actions.ActionTypes; using Content.Shared.FixedPoint; @@ -10,11 +9,11 @@ using Content.Shared.Database; using Robust.Server.GameObjects; using System.Linq; using Content.Server.Stack; -using Robust.Shared.Player; +using Content.Server.UserInterface; namespace Content.Server.Store.Systems; -public sealed partial class StoreSystem : EntitySystem +public sealed partial class StoreSystem { [Dependency] private readonly IAdminLogManager _admin = default!; [Dependency] private readonly SharedHandsSystem _hands = default!; @@ -25,7 +24,7 @@ public sealed partial class StoreSystem : EntitySystem private void InitializeUi() { - SubscribeLocalEvent((_,c,r) => UpdateUserInterface(r.Session.AttachedEntity, c)); + SubscribeLocalEvent(OnRequestUpdate); SubscribeLocalEvent(OnBuyRequest); SubscribeLocalEvent(OnRequestWithdraw); } @@ -34,45 +33,41 @@ public sealed partial class StoreSystem : EntitySystem /// Toggles the store Ui open and closed /// /// the person doing the toggling - /// the store being toggled - public void ToggleUi(EntityUid user, StoreComponent component) + /// the store being toggled + /// + public void ToggleUi(EntityUid user, EntityUid storeEnt, StoreComponent? component = null) { + if (!Resolve(storeEnt, ref component)) + return; + if (!TryComp(user, out var actor)) return; - if (!_ui.TryToggleUi(component.Owner, StoreUiKey.Key, actor.PlayerSession)) + if (!_ui.TryToggleUi(storeEnt, StoreUiKey.Key, actor.PlayerSession)) return; - UpdateUserInterface(user, component); + UpdateUserInterface(user, storeEnt, component); } /// /// Updates the user interface for a store and refreshes the listings /// /// The person who if opening the store ui. Listings are filtered based on this. + /// The store entity itself /// The store component being refreshed. /// - public void UpdateUserInterface(EntityUid? user, StoreComponent component, BoundUserInterface? ui = null) + public void UpdateUserInterface(EntityUid? user, EntityUid store, StoreComponent? component = null, BoundUserInterface? ui = null) { - if (ui == null) - { - ui = _ui.GetUiOrNull(component.Owner, StoreUiKey.Key); - if (ui == null) - return; - } + if (!Resolve(store, ref component)) + return; - //if we haven't opened it before, initialize the shit - if (!component.Opened) - { - RefreshAllListings(component); - InitializeFromPreset(component.Preset, component); - component.Opened = true; - } + if (ui == null && !_ui.TryGetUi(store, StoreUiKey.Key, out ui)) + return; //this is the person who will be passed into logic for all listing filtering. if (user != null) //if we have no "buyer" for this update, then don't update the listings { - component.LastAvailableListings = GetAvailableListings(component.AccountOwner ?? user.Value, component).ToHashSet(); + component.LastAvailableListings = GetAvailableListings(component.AccountOwner ?? user.Value, store, component).ToHashSet(); } //dictionary for all currencies, including 0 values for currencies on the whitelist @@ -92,12 +87,22 @@ public sealed partial class StoreSystem : EntitySystem _ui.SetUiState(ui, state); } + private void OnRequestUpdate(EntityUid uid, StoreComponent component, StoreRequestUpdateInterfaceMessage args) + { + UpdateUserInterface(args.Session.AttachedEntity, args.Entity, component); + } + + private void BeforeActivatableUiOpen(EntityUid uid, StoreComponent component, BeforeActivatableUIOpenEvent args) + { + UpdateUserInterface(args.User, uid, component); + } + /// /// Handles whenever a purchase was made. /// private void OnBuyRequest(EntityUid uid, StoreComponent component, StoreBuyListingMessage msg) { - ListingData? listing = component.Listings.FirstOrDefault(x => x.Equals(msg.Listing)); + var listing = component.Listings.FirstOrDefault(x => x.Equals(msg.Listing)); if (listing == null) //make sure this listing actually exists { Logger.Debug("listing does not exist"); @@ -114,7 +119,7 @@ public sealed partial class StoreSystem : EntitySystem //condition checking because why not if (listing.Conditions != null) { - var args = new ListingConditionArgs(component.AccountOwner ?? buyer, component.Owner, listing, EntityManager); + var args = new ListingConditionArgs(component.AccountOwner ?? buyer, uid, listing, EntityManager); var conditionsMet = listing.Conditions.All(condition => condition.Condition(args)); if (!conditionsMet) @@ -156,16 +161,13 @@ public sealed partial class StoreSystem : EntitySystem } //log dat shit. - if (TryComp(buyer, out var mind)) - { - _admin.Add(LogType.StorePurchase, LogImpact.Low, - $"{ToPrettyString(mind.Owner):player} purchased listing \"{Loc.GetString(listing.Name)}\" from {ToPrettyString(uid)}"); - } + _admin.Add(LogType.StorePurchase, LogImpact.Low, + $"{ToPrettyString(buyer):player} purchased listing \"{Loc.GetString(listing.Name)}\" from {ToPrettyString(uid)}"); listing.PurchaseAmount++; //track how many times something has been purchased _audio.PlayEntity(component.BuySuccessSound, msg.Session, uid); //cha-ching! - UpdateUserInterface(buyer, component); + UpdateUserInterface(buyer, uid, component); } /// @@ -206,6 +208,6 @@ public sealed partial class StoreSystem : EntitySystem } component.Balance[msg.Currency] -= msg.Amount; - UpdateUserInterface(buyer, component); + UpdateUserInterface(buyer, uid, component); } } diff --git a/Content.Server/Store/Systems/StoreSystem.cs b/Content.Server/Store/Systems/StoreSystem.cs index c5cdbb3f04..9330538e2c 100644 --- a/Content.Server/Store/Systems/StoreSystem.cs +++ b/Content.Server/Store/Systems/StoreSystem.cs @@ -1,14 +1,13 @@ -using Content.Server.Stack; using Content.Server.Store.Components; using Content.Shared.FixedPoint; using Content.Shared.Interaction; using Content.Shared.Popups; using Content.Shared.Store; -using Robust.Shared.Player; using Robust.Shared.Prototypes; using System.Linq; using Content.Server.UserInterface; using Content.Shared.Stacks; +using JetBrains.Annotations; namespace Content.Server.Store.Systems; @@ -26,22 +25,38 @@ public sealed partial class StoreSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnAfterInteract); - SubscribeLocalEvent((_,c,a) => UpdateUserInterface(a.User, c)); + SubscribeLocalEvent(BeforeActivatableUiOpen); + SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnShutdown); InitializeUi(); } + private void OnMapInit(EntityUid uid, StoreComponent component, MapInitEvent args) + { + RefreshAllListings(component); + InitializeFromPreset(component.Preset, uid, component); + } + private void OnStartup(EntityUid uid, StoreComponent component, ComponentStartup args) { - RaiseLocalEvent(uid, new StoreAddedEvent(), true); + // for traitors, because the StoreComponent for the PDA can be added at any time. + if (MetaData(uid).EntityLifeStage == EntityLifeStage.MapInitialized) + { + RefreshAllListings(component); + InitializeFromPreset(component.Preset, uid, component); + } + + var ev = new StoreAddedEvent(); + RaiseLocalEvent(uid, ref ev, true); } private void OnShutdown(EntityUid uid, StoreComponent component, ComponentShutdown args) { - RaiseLocalEvent(uid, new StoreRemovedEvent(), true); + var ev = new StoreRemovedEvent(); + RaiseLocalEvent(uid, ref ev, true); } private void OnAfterInteract(EntityUid uid, CurrencyComponent component, AfterInteractEvent args) @@ -52,15 +67,7 @@ public sealed partial class StoreSystem : EntitySystem if (args.Target == null || !TryComp(args.Target, out var store)) return; - //if you somehow are inserting cash before the store initializes. - if (!store.Opened) - { - RefreshAllListings(store); - InitializeFromPreset(store.Preset, store); - store.Opened = true; - } - - args.Handled = TryAddCurrency(GetCurrencyValue(component), store); + args.Handled = TryAddCurrency(GetCurrencyValue(uid, component), args.Target.Value, store); if (args.Handled) { @@ -74,35 +81,43 @@ public sealed partial class StoreSystem : EntitySystem /// Gets the value from an entity's currency component. /// Scales with stacks. /// + /// /// /// The value of the currency - public Dictionary GetCurrencyValue(CurrencyComponent component) + public Dictionary GetCurrencyValue(EntityUid uid, CurrencyComponent component) { - TryComp(component.Owner, out var stack); - var amount = stack?.Count ?? 1; - + var amount = EntityManager.GetComponentOrNull(uid)?.Count ?? 1; return component.Price.ToDictionary(v => v.Key, p => p.Value * amount); } /// /// Tries to add a currency to a store's balance. /// - /// The currency to add + /// + /// + /// The currency to add /// The store to add it to /// Whether or not the currency was succesfully added - public bool TryAddCurrency(CurrencyComponent component, StoreComponent store) + [PublicAPI] + public bool TryAddCurrency(EntityUid currencyEnt, EntityUid storeEnt, StoreComponent? store = null, CurrencyComponent? currency = null) { - return TryAddCurrency(GetCurrencyValue(component), store); + if (!Resolve(currencyEnt, ref currency) || !Resolve(storeEnt, ref store)) + return false; + return TryAddCurrency(GetCurrencyValue(currencyEnt, currency), storeEnt, store); } /// /// Tries to add a currency to a store's balance /// /// The value to add to the store + /// /// The store to add it to /// Whether or not the currency was succesfully added - public bool TryAddCurrency(Dictionary currency, StoreComponent store) + public bool TryAddCurrency(Dictionary currency, EntityUid uid, StoreComponent? store = null) { + if (!Resolve(uid, ref store)) + return false; + //verify these before values are modified foreach (var type in currency) { @@ -116,7 +131,7 @@ public sealed partial class StoreSystem : EntitySystem store.Balance[type.Key] += type.Value; } - UpdateUserInterface(null, store); + UpdateUserInterface(null, uid, store); return true; } @@ -124,8 +139,9 @@ public sealed partial class StoreSystem : EntitySystem /// Initializes a store based on a preset ID /// /// The ID of a store preset prototype + /// /// The store being initialized - public void InitializeFromPreset(string? preset, StoreComponent component) + public void InitializeFromPreset(string? preset, EntityUid uid, StoreComponent component) { if (preset == null) return; @@ -133,23 +149,24 @@ public sealed partial class StoreSystem : EntitySystem if (!_proto.TryIndex(preset, out var proto)) return; - InitializeFromPreset(proto, component); + InitializeFromPreset(proto, uid, component); } /// /// Initializes a store based on a given preset /// /// The StorePresetPrototype + /// /// The store being initialized - public void InitializeFromPreset(StorePresetPrototype preset, StoreComponent component) + public void InitializeFromPreset(StorePresetPrototype preset, EntityUid uid, StoreComponent component) { component.Preset = preset.ID; component.CurrencyWhitelist.UnionWith(preset.CurrencyWhitelist); component.Categories.UnionWith(preset.Categories); if (component.Balance == new Dictionary() && preset.InitialBalance != null) //if we don't have a value stored, use the preset - TryAddCurrency(preset.InitialBalance, component); + TryAddCurrency(preset.InitialBalance, uid, component); - var ui = _ui.GetUiOrNull(component.Owner, StoreUiKey.Key); + var ui = _ui.GetUiOrNull(uid, StoreUiKey.Key); if (ui != null) _ui.SetUiState(ui, new StoreInitializeState(preset.StoreName)); } diff --git a/Content.Server/Traitor/Uplink/UplinkSystem.cs b/Content.Server/Traitor/Uplink/UplinkSystem.cs index 0a5968aa7a..956db85fcf 100644 --- a/Content.Server/Traitor/Uplink/UplinkSystem.cs +++ b/Content.Server/Traitor/Uplink/UplinkSystem.cs @@ -24,7 +24,7 @@ namespace Content.Server.Traitor.Uplink public int GetTCBalance(StoreComponent component) { FixedPoint2? tcBalance = component.Balance.GetValueOrDefault(TelecrystalCurrencyPrototype); - return tcBalance != null ? tcBalance.Value.Int() : 0; + return tcBalance?.Int() ?? 0; } /// @@ -46,15 +46,14 @@ namespace Content.Server.Traitor.Uplink } var store = EnsureComp(uplinkEntity.Value); - _store.InitializeFromPreset(uplinkPresetId, store); + _store.InitializeFromPreset(uplinkPresetId, uplinkEntity.Value, store); store.AccountOwner = user; store.Balance.Clear(); if (balance != null) { store.Balance.Clear(); - _store.TryAddCurrency( - new Dictionary() { { TelecrystalCurrencyPrototype, balance.Value } }, store); + _store.TryAddCurrency(new Dictionary { { TelecrystalCurrencyPrototype, balance.Value } }, uplinkEntity.Value, store); } // TODO add BUI. Currently can't be done outside of yaml -_- diff --git a/Content.Server/TraitorDeathMatch/TraitorDeathMatchRedemptionSystem.cs b/Content.Server/TraitorDeathMatch/TraitorDeathMatchRedemptionSystem.cs index c40ce777ae..9def8fc316 100644 --- a/Content.Server/TraitorDeathMatch/TraitorDeathMatchRedemptionSystem.cs +++ b/Content.Server/TraitorDeathMatch/TraitorDeathMatchRedemptionSystem.cs @@ -7,7 +7,6 @@ using Content.Shared.FixedPoint; using Content.Shared.Interaction; using Content.Shared.Inventory; using Content.Shared.Popups; -using Robust.Shared.Player; namespace Content.Server.TraitorDeathMatch; @@ -18,8 +17,6 @@ public sealed class TraitorDeathMatchRedemptionSystem : EntitySystem [Dependency] private readonly UplinkSystem _uplink = default!; [Dependency] private readonly StoreSystem _store = default!; - private const string TcCurrencyPrototype = "Telecrystal"; - public override void Initialize() { base.Initialize(); @@ -99,7 +96,7 @@ public sealed class TraitorDeathMatchRedemptionSystem : EntitySystem // 4 is the per-PDA bonus amount var transferAmount = _uplink.GetTCBalance(victimUplink) + 4; victimUplink.Balance.Clear(); - _store.TryAddCurrency(new Dictionary() { {"Telecrystal", FixedPoint2.New(transferAmount)}}, userUplink); + _store.TryAddCurrency(new Dictionary() { {"Telecrystal", FixedPoint2.New(transferAmount)}}, userUplink.Owner, userUplink); EntityManager.DeleteEntity(victimUplink.Owner);