]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Use ECS prototype-reload events (#22613)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Fri, 22 Dec 2023 14:13:45 +0000 (09:13 -0500)
committerGitHub <noreply@github.com>
Fri, 22 Dec 2023 14:13:45 +0000 (01:13 +1100)
* Use ECS prototype-reload events

* better constructors

* Maybe this fixes tests?

23 files changed:
Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs
Content.Client/Clothing/Systems/ChameleonClothingSystem.cs
Content.Client/CrewManifest/CrewManifestSystem.cs
Content.Client/Parallax/ParallaxSystem.cs
Content.Client/UserInterface/Systems/DecalPlacer/DecalPlacerUIController.cs
Content.Server/AlertLevel/AlertLevelSystem.cs
Content.Server/Audio/ContentAudioSystem.cs
Content.Server/Chat/Systems/ChatSystem.Emote.cs
Content.Server/Chat/Systems/ChatSystem.cs
Content.Server/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs
Content.Server/Holiday/Christmas/RandomGiftSystem.cs
Content.Server/NPC/HTN/HTNSystem.cs
Content.Server/NPC/Systems/NpcFactionSystem.cs
Content.Server/NameIdentifier/NameIdentifierSystem.cs
Content.Server/Parallax/BiomeSystem.cs
Content.Server/Procedural/DungeonSystem.cs
Content.Server/Spreader/SpreaderSystem.cs
Content.Shared/Alert/AlertsSystem.cs
Content.Shared/Chat/SharedChatSystem.cs
Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs
Content.Shared/Entry/EntryPoint.cs
Content.Shared/Humanoid/Markings/MarkingManager.cs
Content.Shared/Roles/Jobs/SharedJobSystem.cs

index 0fc0c18b62bcbc76b48317bc2238aa701853b05b..aafd0ea63073be1be7265cbaa27241fe02b77c66 100644 (file)
@@ -67,7 +67,7 @@ public sealed partial class ContentAudioSystem
         _nextAudio = TimeSpan.MaxValue;
 
         SetupAmbientSounds();
-        _proto.PrototypesReloaded += OnProtoReload;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnProtoReload);
         _state.OnStateChanged += OnStateChange;
         // On round end summary OR lobby cut audio.
         SubscribeNetworkEvent<RoundEndMessageEvent>(OnRoundEndMessage);
@@ -86,21 +86,14 @@ public sealed partial class ContentAudioSystem
     private void ShutdownAmbientMusic()
     {
         _configManager.UnsubValueChanged(CCVars.AmbientMusicVolume, AmbienceCVarChanged);
-        _proto.PrototypesReloaded -= OnProtoReload;
         _state.OnStateChanged -= OnStateChange;
         _ambientMusicStream = _audio.Stop(_ambientMusicStream);
     }
 
     private void OnProtoReload(PrototypesReloadedEventArgs obj)
     {
-        if (!obj.ByType.ContainsKey(typeof(AmbientMusicPrototype)) &&
-            !obj.ByType.ContainsKey(typeof(RulesPrototype)))
-        {
-            return;
-        }
-
-        _ambientSounds.Clear();
-        SetupAmbientSounds();
+        if (obj.WasModified<AmbientMusicPrototype>() || obj.WasModified<RulesPrototype>())
+            SetupAmbientSounds();
     }
 
     private void OnStateChange(StateChangedEventArgs obj)
@@ -114,6 +107,7 @@ public sealed partial class ContentAudioSystem
 
     private void SetupAmbientSounds()
     {
+        _ambientSounds.Clear();
         foreach (var ambience in _proto.EnumeratePrototypes<AmbientMusicPrototype>())
         {
             var tracks = _ambientSounds.GetOrNew(ambience.ID);
index f067d91051562843fe054b033ca8847e6911da76..0ea9bbac09187ee2046dcff5d81bd2a3e5c4e8f3 100644 (file)
@@ -29,18 +29,13 @@ public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem
         SubscribeLocalEvent<ChameleonClothingComponent, AfterAutoHandleStateEvent>(HandleState);
 
         PrepareAllVariants();
-        _proto.PrototypesReloaded += OnProtoReloaded;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnProtoReloaded);
     }
 
-    public override void Shutdown()
+    private void OnProtoReloaded(PrototypesReloadedEventArgs args)
     {
-        base.Shutdown();
-        _proto.PrototypesReloaded -= OnProtoReloaded;
-    }
-
-    private void OnProtoReloaded(PrototypesReloadedEventArgs _)
-    {
-        PrepareAllVariants();
+        if (args.WasModified<EntityPrototype>())
+            PrepareAllVariants();
     }
 
     private void HandleState(EntityUid uid, ChameleonClothingComponent component, ref AfterAutoHandleStateEvent args)
index 05f27620c41de62f52b895c66860049700a88597..d05acb56802a7fb5e9236d02adb7861d99e2a760 100644 (file)
@@ -1,4 +1,3 @@
-using Content.Client.GameTicking.Managers;
 using Content.Shared.CrewManifest;
 using Content.Shared.Roles;
 using Robust.Shared.Prototypes;
@@ -19,12 +18,7 @@ public sealed class CrewManifestSystem : EntitySystem
         base.Initialize();
 
         BuildDepartmentLookup();
-        _prototypeManager.PrototypesReloaded += OnPrototypesReload;
-    }
-
-    public override void Shutdown()
-    {
-        _prototypeManager.PrototypesReloaded -= OnPrototypesReload;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReload);
     }
 
     /// <summary>
@@ -36,16 +30,16 @@ public sealed class CrewManifestSystem : EntitySystem
         RaiseNetworkEvent(new RequestCrewManifestMessage(netEntity));
     }
 
-    private void OnPrototypesReload(PrototypesReloadedEventArgs _)
+    private void OnPrototypesReload(PrototypesReloadedEventArgs args)
     {
-        _jobDepartmentLookup.Clear();
-        _departments.Clear();
-
-        BuildDepartmentLookup();
+        if (args.WasModified<DepartmentPrototype>())
+            BuildDepartmentLookup();
     }
 
     private void BuildDepartmentLookup()
     {
+        _jobDepartmentLookup.Clear();
+        _departments.Clear();
         foreach (var department in _prototypeManager.EnumeratePrototypes<DepartmentPrototype>())
         {
             _departments.Add(department.ID);
index 721dc3a8c291783954f2ee6c6fb409bdecb30417..720da72e80edace3c2c05dece9896fc8a2cc41e3 100644 (file)
@@ -24,14 +24,13 @@ public sealed class ParallaxSystem : SharedParallaxSystem
     {
         base.Initialize();
         _overlay.AddOverlay(new ParallaxOverlay());
-        _protoManager.PrototypesReloaded += OnReload;
-
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnReload);
         SubscribeLocalEvent<ParallaxComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
     }
 
     private void OnReload(PrototypesReloadedEventArgs obj)
     {
-        if (!obj.ByType.ContainsKey(typeof(ParallaxPrototype)))
+        if (!obj.WasModified<ParallaxPrototype>())
             return;
 
         _parallax.UnloadParallax(Fallback);
@@ -48,7 +47,6 @@ public sealed class ParallaxSystem : SharedParallaxSystem
     {
         base.Shutdown();
         _overlay.RemoveOverlay<ParallaxOverlay>();
-        _protoManager.PrototypesReloaded -= OnReload;
     }
 
     private void OnAfterAutoHandleState(EntityUid uid, ParallaxComponent component, ref AfterAutoHandleStateEvent args)
index 5f1914a462170545839e151e5603ec2454d26005..f1b611ac5a915e679569341ec8039f5c6d567980 100644 (file)
@@ -53,7 +53,8 @@ public sealed class DecalPlacerUIController : UIController, IOnStateExited<Gamep
 
     private void OnPrototypesReloaded(PrototypesReloadedEventArgs obj)
     {
-        ReloadPrototypes();
+        if (obj.WasModified<DecalPrototype>())
+            ReloadPrototypes();
     }
 
     private void ReloadPrototypes()
index b2b63e618e61e9b6aae2799b6ddb0776c5cc44de..04e274ceeb5cf3e51ed319e9b605e33ac4241c68 100644 (file)
@@ -23,15 +23,7 @@ public sealed class AlertLevelSystem : EntitySystem
     public override void Initialize()
     {
         SubscribeLocalEvent<StationInitializedEvent>(OnStationInitialize);
-
-        _prototypeManager.PrototypesReloaded += OnPrototypeReload;
-    }
-
-    public override void Shutdown()
-    {
-        base.Shutdown();
-
-        _prototypeManager.PrototypesReloaded -= OnPrototypeReload;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeReload);
     }
 
     public override void Update(float time)
index 51bd3183b632e814211a55c9d619a6a224259692..b1db01141befdf3ce4ab9e2f59f28bf27ae2747b 100644 (file)
@@ -3,7 +3,6 @@ using Content.Shared.Audio;
 using Content.Shared.GameTicking;
 using Robust.Server.Audio;
 using Robust.Shared.Audio;
-using Robust.Shared.Audio.Components;
 using Robust.Shared.Prototypes;
 
 namespace Content.Server.Audio;
@@ -11,14 +10,13 @@ namespace Content.Server.Audio;
 public sealed class ContentAudioSystem : SharedContentAudioSystem
 {
     [Dependency] private readonly AudioSystem _serverAudio = default!;
-    [Dependency] private readonly IPrototypeManager _protoManager = default!;
 
     public override void Initialize()
     {
         base.Initialize();
         SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundCleanup);
         SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
-        _protoManager.PrototypesReloaded += OnProtoReload;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnProtoReload);
     }
 
     private void OnRoundCleanup(RoundRestartCleanupEvent ev)
@@ -28,16 +26,8 @@ public sealed class ContentAudioSystem : SharedContentAudioSystem
 
     private void OnProtoReload(PrototypesReloadedEventArgs obj)
     {
-        if (!obj.ByType.ContainsKey(typeof(AudioPresetPrototype)))
-            return;
-
-        _serverAudio.ReloadPresets();
-    }
-
-    public override void Shutdown()
-    {
-        base.Shutdown();
-        _protoManager.PrototypesReloaded -= OnProtoReload;
+        if (obj.WasModified<AudioPresetPrototype>())
+            _serverAudio.ReloadPresets();
     }
 
     private void OnRoundStart(RoundStartingEvent ev)
index 7ab86aa108134918ecd4ae05600ca99fdc0501bc..8bba76dadda9c2b3b92e4d0808fa5d49618a9b2c 100644 (file)
@@ -1,3 +1,4 @@
+using System.Collections.Frozen;
 using Content.Shared.Chat.Prototypes;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
@@ -7,44 +8,36 @@ namespace Content.Server.Chat.Systems;
 // emotes using emote prototype
 public partial class ChatSystem
 {
-    private readonly Dictionary<string, EmotePrototype> _wordEmoteDict = new();
+    private FrozenDictionary<string, EmotePrototype> _wordEmoteDict = FrozenDictionary<string, EmotePrototype>.Empty;
 
-    private void InitializeEmotes()
+    protected override void OnPrototypeReload(PrototypesReloadedEventArgs obj)
     {
-        _prototypeManager.PrototypesReloaded += OnPrototypeReloadEmotes;
-        CacheEmotes();
-    }
-
-    private void ShutdownEmotes()
-    {
-        _prototypeManager.PrototypesReloaded -= OnPrototypeReloadEmotes;
-    }
-
-    private void OnPrototypeReloadEmotes(PrototypesReloadedEventArgs obj)
-    {
-        CacheEmotes();
+        base.OnPrototypeReload(obj);
+        if (obj.WasModified<EmotePrototype>())
+            CacheEmotes();
     }
 
     private void CacheEmotes()
     {
-        _wordEmoteDict.Clear();
+        var dict = new Dictionary<string, EmotePrototype>();
         var emotes = _prototypeManager.EnumeratePrototypes<EmotePrototype>();
         foreach (var emote in emotes)
         {
             foreach (var word in emote.ChatTriggers)
             {
                 var lowerWord = word.ToLower();
-                if (_wordEmoteDict.ContainsKey(lowerWord))
+                if (dict.TryGetValue(lowerWord, out var value))
                 {
-                    var existingId = _wordEmoteDict[lowerWord].ID;
-                    var errMsg = $"Duplicate of emote word {lowerWord} in emotes {emote.ID} and {existingId}";
-                    Logger.Error(errMsg);
+                    var errMsg = $"Duplicate of emote word {lowerWord} in emotes {emote.ID} and {value.ID}";
+                    Log.Error(errMsg);
                     continue;
                 }
 
-                _wordEmoteDict.Add(lowerWord, emote);
+                dict.Add(lowerWord, emote);
             }
         }
+
+        _wordEmoteDict = dict.ToFrozenDictionary();
     }
 
     /// <summary>
index 390faab756b780ba82a6ba3cde688f5496afff6b..c8a43bb3a656b945b5d1c1117208f4c937ae7b64 100644 (file)
@@ -69,7 +69,7 @@ public sealed partial class ChatSystem : SharedChatSystem
     public override void Initialize()
     {
         base.Initialize();
-        InitializeEmotes();
+        CacheEmotes();
         _configurationManager.OnValueChanged(CCVars.LoocEnabled, OnLoocEnabledChanged, true);
         _configurationManager.OnValueChanged(CCVars.DeadLoocEnabled, OnDeadLoocEnabledChanged, true);
         _configurationManager.OnValueChanged(CCVars.CritLoocEnabled, OnCritLoocEnabledChanged, true);
@@ -80,7 +80,6 @@ public sealed partial class ChatSystem : SharedChatSystem
     public override void Shutdown()
     {
         base.Shutdown();
-        ShutdownEmotes();
         _configurationManager.UnsubValueChanged(CCVars.LoocEnabled, OnLoocEnabledChanged);
         _configurationManager.UnsubValueChanged(CCVars.DeadLoocEnabled, OnDeadLoocEnabledChanged);
         _configurationManager.UnsubValueChanged(CCVars.CritLoocEnabled, OnCritLoocEnabledChanged);
@@ -736,7 +735,7 @@ public sealed partial class ChatSystem : SharedChatSystem
 
         return ev.Message;
     }
+
     public bool CheckIgnoreSpeechBlocker(EntityUid sender, bool ignoreBlocker)
     {
         if (ignoreBlocker)
index 7485c0e9016338d825627bdbe7ec8dc704ebf6e4..e2cd72030de7cc5cb56b8bf0752702b74f8e9aa5 100644 (file)
@@ -17,8 +17,7 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
     {
         base.Initialize();
 
-        PrototypeManager.PrototypesReloaded += PrototypeManagerReload;
-
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(PrototypeManagerReload);
         _player.PlayerStatusChanged += OnPlayerStatusChanged;
 
         InitializeServerRegistry();
index 40b365105d14e47fccd83d449d618c5e9eb00746..33d5d0d234c396aa03de0f34978ca4f974aeb8bc 100644 (file)
@@ -31,7 +31,7 @@ public sealed class RandomGiftSystem : EntitySystem
     /// <inheritdoc/>
     public override void Initialize()
     {
-        _prototype.PrototypesReloaded += OnPrototypesReloaded;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReloaded);
         SubscribeLocalEvent<RandomGiftComponent, MapInitEvent>(OnGiftMapInit);
         SubscribeLocalEvent<RandomGiftComponent, UseInHandEvent>(OnUseInHand);
         SubscribeLocalEvent<RandomGiftComponent, ExaminedEvent>(OnExamined);
@@ -80,7 +80,8 @@ public sealed class RandomGiftSystem : EntitySystem
 
     private void OnPrototypesReloaded(PrototypesReloadedEventArgs obj)
     {
-        BuildIndex();
+        if (obj.WasModified<EntityPrototype>())
+            BuildIndex();
     }
 
     private void BuildIndex()
index a7689fbabed07c36ab57d283005ec79ba011992e..2ba91d5be6992ec09b9d17d3aa62be07edbcd001 100644 (file)
@@ -10,7 +10,6 @@ using Content.Shared.Administration;
 using Content.Shared.Mobs;
 using Content.Shared.NPC;
 using JetBrains.Annotations;
-using Robust.Server.GameObjects;
 using Robust.Shared.Player;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Utility;
@@ -38,8 +37,7 @@ public sealed class HTNSystem : EntitySystem
         SubscribeLocalEvent<HTNComponent, PlayerDetachedEvent>(_npc.OnPlayerNPCDetach);
         SubscribeLocalEvent<HTNComponent, ComponentShutdown>(OnHTNShutdown);
         SubscribeNetworkEvent<RequestHTNMessage>(OnHTNMessage);
-
-        _prototypeManager.PrototypesReloaded += OnPrototypeLoad;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeLoad);
         OnLoad();
     }
 
@@ -57,12 +55,6 @@ public sealed class HTNSystem : EntitySystem
         _subscribers.Remove(args.SenderSession);
     }
 
-    public override void Shutdown()
-    {
-        base.Shutdown();
-        _prototypeManager.PrototypesReloaded -= OnPrototypeLoad;
-    }
-
     private void OnLoad()
     {
         // Clear all NPCs in case they're hanging onto stale tasks
index 08c9353411d046bd5449cb188e17c7856a7ed2ba..0657ab4af917a7d9fb3425057207967bf601609a 100644 (file)
@@ -1,3 +1,4 @@
+using System.Collections.Frozen;
 using System.Linq;
 using Content.Server.NPC.Components;
 using JetBrains.Annotations;
@@ -18,31 +19,23 @@ public sealed partial class NpcFactionSystem : EntitySystem
     /// <summary>
     /// To avoid prototype mutability we store an intermediary data class that gets used instead.
     /// </summary>
-    private Dictionary<string, FactionData> _factions = new();
+    private FrozenDictionary<string, FactionData> _factions = FrozenDictionary<string, FactionData>.Empty;
 
     public override void Initialize()
     {
         base.Initialize();
         _sawmill = Logger.GetSawmill("faction");
         SubscribeLocalEvent<NpcFactionMemberComponent, ComponentStartup>(OnFactionStartup);
-        _protoManager.PrototypesReloaded += OnProtoReload;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnProtoReload);
 
         InitializeException();
         RefreshFactions();
     }
 
-    public override void Shutdown()
-    {
-        base.Shutdown();
-        _protoManager.PrototypesReloaded -= OnProtoReload;
-    }
-
     private void OnProtoReload(PrototypesReloadedEventArgs obj)
     {
-        if (!obj.ByType.ContainsKey(typeof(NpcFactionPrototype)))
-            return;
-
-        RefreshFactions();
+        if (obj.WasModified<NpcFactionPrototype>())
+            RefreshFactions();
     }
 
     private void OnFactionStartup(EntityUid uid, NpcFactionMemberComponent memberComponent, ComponentStartup args)
@@ -237,16 +230,15 @@ public sealed partial class NpcFactionSystem : EntitySystem
 
     private void RefreshFactions()
     {
-        _factions.Clear();
 
-        foreach (var faction in _protoManager.EnumeratePrototypes<NpcFactionPrototype>())
-        {
-            _factions[faction.ID] = new FactionData()
+        _factions = _protoManager.EnumeratePrototypes<NpcFactionPrototype>().ToFrozenDictionary(
+            faction => faction.ID,
+            faction =>  new FactionData
             {
                 Friendly = faction.Friendly.ToHashSet(),
-                Hostile = faction.Hostile.ToHashSet(),
-            };
-        }
+                Hostile = faction.Hostile.ToHashSet()
+
+            });
 
         foreach (var comp in EntityQuery<NpcFactionMemberComponent>(true))
         {
index bde8466d0680b1535efaed8f62e3141757b13a74..6d6e9e6c697d5cf37102e3c4e0ecb447a278f3ae 100644 (file)
@@ -28,9 +28,9 @@ public sealed class NameIdentifierSystem : EntitySystem
         SubscribeLocalEvent<NameIdentifierComponent, MapInitEvent>(OnMapInit);
         SubscribeLocalEvent<NameIdentifierComponent, ComponentShutdown>(OnComponentShutdown);
         SubscribeLocalEvent<RoundRestartCleanupEvent>(CleanupIds);
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnReloadPrototypes);
 
         InitialSetupPrototypes();
-        _prototypeManager.PrototypesReloaded += OnReloadPrototypes;
     }
 
     private void OnComponentShutdown(EntityUid uid, NameIdentifierComponent component, ComponentShutdown args)
@@ -46,13 +46,6 @@ public sealed class NameIdentifierSystem : EntitySystem
         }
     }
 
-    public override void Shutdown()
-    {
-        base.Shutdown();
-
-        _prototypeManager.PrototypesReloaded -= OnReloadPrototypes;
-    }
-
     /// <summary>
     ///     Generates a new unique name/suffix for a given entity and adds it to <see cref="CurrentIds"/>
     ///     but does not set the entity's name.
index daf21d77ddf6e0275ca983f8c1cf9d167994a915..881663db56be22f47eaa2ae235e1fecf469ca77f 100644 (file)
@@ -85,14 +85,13 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
         SubscribeLocalEvent<ShuttleFlattenEvent>(OnShuttleFlatten);
         _configManager.OnValueChanged(CVars.NetMaxUpdateRange, SetLoadRange, true);
         InitializeCommands();
-        ProtoManager.PrototypesReloaded += ProtoReload;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(ProtoReload);
     }
 
     public override void Shutdown()
     {
         base.Shutdown();
         _configManager.UnsubValueChanged(CVars.NetMaxUpdateRange, SetLoadRange);
-        ProtoManager.PrototypesReloaded -= ProtoReload;
     }
 
     private void ProtoReload(PrototypesReloadedEventArgs obj)
index 9e85d86bf1739e996562595edfd16324ec00480d..ba69f1ea5f8146d7b1bd2b150a7022bc28968a27 100644 (file)
@@ -48,7 +48,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
         _console.RegisterCommand("dungen", Loc.GetString("cmd-dungen-desc"), Loc.GetString("cmd-dungen-help"), GenerateDungeon, CompletionCallback);
         _console.RegisterCommand("dungen_preset_vis", Loc.GetString("cmd-dungen_preset_vis-desc"), Loc.GetString("cmd-dungen_preset_vis-help"), DungeonPresetVis, PresetCallback);
         _console.RegisterCommand("dungen_pack_vis", Loc.GetString("cmd-dungen_pack_vis-desc"), Loc.GetString("cmd-dungen_pack_vis-help"), DungeonPackVis, PackCallback);
-        _prototype.PrototypesReloaded += PrototypeReload;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(PrototypeReload);
         SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundCleanup);
         SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
     }
@@ -91,8 +91,6 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
     public override void Shutdown()
     {
         base.Shutdown();
-        _prototype.PrototypesReloaded -= PrototypeReload;
-
         foreach (var token in _dungeonJobs.Values)
         {
             token.Cancel();
index d61cf303d6bde692c14c7987738b4fda8520caba..8afc7e6bd543a94003aa1168c5d4fb8e29fa793b 100644 (file)
@@ -30,6 +30,7 @@ public sealed class SpreaderSystem : EntitySystem
     /// <summary>
     /// Remaining number of updates per grid & prototype.
     /// </summary>
+    // TODO PERFORMANCE Assign each prototype to an index and convert dictionary to array
     private Dictionary<EntityUid, Dictionary<string, int>> _gridUpdates = new();
 
     public const float SpreadCooldownSeconds = 1;
@@ -42,24 +43,16 @@ public sealed class SpreaderSystem : EntitySystem
     {
         SubscribeLocalEvent<AirtightChanged>(OnAirtightChanged);
         SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeReload);
 
         SubscribeLocalEvent<EdgeSpreaderComponent, EntityTerminatingEvent>(OnTerminating);
         SetupPrototypes();
-        _prototype.PrototypesReloaded += OnPrototypeReload;
-    }
-
-    public override void Shutdown()
-    {
-        base.Shutdown();
-        _prototype.PrototypesReloaded -= OnPrototypeReload;
     }
 
     private void OnPrototypeReload(PrototypesReloadedEventArgs obj)
     {
-        if (!obj.ByType.ContainsKey(typeof(EdgeSpreaderPrototype)))
-            return;
-
-        SetupPrototypes();
+        if (obj.WasModified<EdgeSpreaderPrototype>())
+            SetupPrototypes();
     }
 
     private void SetupPrototypes()
index 83dc9382a33aff580f6001a06da2a710d9694c27..424a4670ba9eb3a46bd923cd190cde989262cf5a 100644 (file)
@@ -1,3 +1,4 @@
+using System.Collections.Frozen;
 using System.Diagnostics.CodeAnalysis;
 using Robust.Shared.Player;
 using Robust.Shared.Prototypes;
@@ -7,7 +8,8 @@ namespace Content.Shared.Alert;
 public abstract class AlertsSystem : EntitySystem
 {
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
-    private readonly Dictionary<AlertType, AlertPrototype> _typeToAlert = new();
+
+    private FrozenDictionary<AlertType, AlertPrototype> _typeToAlert = default!;
 
     public IReadOnlyDictionary<AlertKey, AlertState>? GetActiveAlerts(EntityUid euid)
     {
@@ -170,9 +172,8 @@ public abstract class AlertsSystem : EntitySystem
         SubscribeLocalEvent<AlertsComponent, PlayerAttachedEvent>(OnPlayerAttached);
 
         SubscribeNetworkEvent<ClickAlertEvent>(HandleClickAlert);
-
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(HandlePrototypesReloaded);
         LoadPrototypes();
-        _prototypeManager.PrototypesReloaded += HandlePrototypesReloaded;
     }
 
     protected virtual void HandleComponentShutdown(EntityUid uid, AlertsComponent component, ComponentShutdown args)
@@ -185,29 +186,25 @@ public abstract class AlertsSystem : EntitySystem
         RaiseLocalEvent(uid, new AlertSyncEvent(uid), true);
     }
 
-    public override void Shutdown()
-    {
-        _prototypeManager.PrototypesReloaded -= HandlePrototypesReloaded;
-
-        base.Shutdown();
-    }
-
     private void HandlePrototypesReloaded(PrototypesReloadedEventArgs obj)
     {
-        LoadPrototypes();
+        if (obj.WasModified<AlertPrototype>())
+            LoadPrototypes();
     }
 
     protected virtual void LoadPrototypes()
     {
-        _typeToAlert.Clear();
+        var dict = new Dictionary<AlertType, AlertPrototype>();
         foreach (var alert in _prototypeManager.EnumeratePrototypes<AlertPrototype>())
         {
-            if (!_typeToAlert.TryAdd(alert.AlertType, alert))
+            if (!dict.TryAdd(alert.AlertType, alert))
             {
                 Log.Error("Found alert with duplicate alertType {0} - all alerts must have" +
                           " a unique alerttype, this one will be skipped", alert.AlertType);
             }
         }
+
+        _typeToAlert = dict.ToFrozenDictionary();
     }
 
     /// <summary>
index f749214f1b801b89716afe8408d3d647fda4cc81..69918f8098b4e9da007c280cae10a65ac1282ecd 100644 (file)
@@ -1,3 +1,4 @@
+using System.Collections.Frozen;
 using Content.Shared.Popups;
 using Content.Shared.Radio;
 using Content.Shared.Speech;
@@ -36,35 +37,26 @@ public abstract class SharedChatSystem : EntitySystem
     /// <summary>
     /// Cache of the keycodes for faster lookup.
     /// </summary>
-    private Dictionary<char, RadioChannelPrototype> _keyCodes = new();
+    private FrozenDictionary<char, RadioChannelPrototype> _keyCodes = default!;
 
     public override void Initialize()
     {
         base.Initialize();
         DebugTools.Assert(_prototypeManager.HasIndex<RadioChannelPrototype>(CommonChannel));
-        _prototypeManager.PrototypesReloaded += OnPrototypeReload;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeReload);
         CacheRadios();
     }
 
-    private void OnPrototypeReload(PrototypesReloadedEventArgs obj)
+    protected virtual void OnPrototypeReload(PrototypesReloadedEventArgs obj)
     {
-        if (obj.ByType.ContainsKey(typeof(RadioChannelPrototype)))
+        if (obj.WasModified<RadioChannelPrototype>())
             CacheRadios();
     }
 
     private void CacheRadios()
     {
-        _keyCodes.Clear();
-
-        foreach (var proto in _prototypeManager.EnumeratePrototypes<RadioChannelPrototype>())
-        {
-            _keyCodes.Add(proto.KeyCode, proto);
-        }
-    }
-
-    public override void Shutdown()
-    {
-        _prototypeManager.PrototypesReloaded -= OnPrototypeReload;
+        _keyCodes = _prototypeManager.EnumeratePrototypes<RadioChannelPrototype>()
+            .ToFrozenDictionary(x => x.KeyCode);
     }
 
     /// <summary>
index 1bf7e7888b848c8c82543ec7560c65749f34344d..05e176da5b82e327aea4825340ed83ffc0e6e5b6 100644 (file)
@@ -1,3 +1,4 @@
+using System.Collections.Frozen;
 using System.Linq;
 using Content.Shared.Administration.Logs;
 using Content.Shared.Chemistry.Components;
@@ -7,6 +8,7 @@ using Content.Shared.FixedPoint;
 using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
 
 namespace Content.Shared.Chemistry.Reaction
 {
@@ -22,23 +24,22 @@ namespace Content.Shared.Chemistry.Reaction
         [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
 
         /// <summary>
-        ///     A cache of all existant chemical reactions indexed by one of their
-        ///     required reactants.
+        /// A cache of all reactions indexed by at most ONE of their required reactants.
+        /// I.e., even if a reaction has more than one reagent, it will only ever appear once in this dictionary.
         /// </summary>
-        private IDictionary<string, List<ReactionPrototype>> _reactions = default!;
+        private FrozenDictionary<string, List<ReactionPrototype>> _reactionsSingle = default!;
+
+        /// <summary>
+        ///     A cache of all reactions indexed by one of their required reactants.
+        /// </summary>
+        private FrozenDictionary<string, List<ReactionPrototype>> _reactions = default!;
 
         public override void Initialize()
         {
             base.Initialize();
 
             InitializeReactionCache();
-            _prototypeManager.PrototypesReloaded += OnPrototypesReloaded;
-        }
-
-        public override void Shutdown()
-        {
-            base.Shutdown();
-            _prototypeManager.PrototypesReloaded -= OnPrototypesReloaded;
+            SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReloaded);
         }
 
         /// <summary>
@@ -46,34 +47,27 @@ namespace Content.Shared.Chemistry.Reaction
         /// </summary>
         private void InitializeReactionCache()
         {
-            _reactions = new Dictionary<string, List<ReactionPrototype>>();
-
-            var reactions = _prototypeManager.EnumeratePrototypes<ReactionPrototype>();
-            foreach(var reaction in reactions)
+            // Construct single-reaction dictionary.
+            var dict = new Dictionary<string, List<ReactionPrototype>>();
+            foreach(var reaction in _prototypeManager.EnumeratePrototypes<ReactionPrototype>())
             {
-                CacheReaction(reaction);
+                // For this dictionary we only need to cache based on the first reagent.
+                var reagent = reaction.Reactants.Keys.First();
+                var list = dict.GetOrNew(reagent);
+                list.Add(reaction);
             }
-        }
+            _reactionsSingle = dict.ToFrozenDictionary();
 
-        /// <summary>
-        ///     Caches a reaction by its first required reagent.
-        ///     Used to build the reaction cache.
-        /// </summary>
-        /// <param name="reaction">A reaction prototype to cache.</param>
-        private void CacheReaction(ReactionPrototype reaction)
-        {
-            var reagents = reaction.Reactants.Keys;
-            foreach(var reagent in reagents)
+            dict.Clear();
+            foreach(var reaction in _prototypeManager.EnumeratePrototypes<ReactionPrototype>())
             {
-                if(!_reactions.TryGetValue(reagent, out var cache))
+                foreach (var reagent in reaction.Reactants.Keys)
                 {
-                    cache = new List<ReactionPrototype>();
-                    _reactions.Add(reagent, cache);
+                    var list = dict.GetOrNew(reagent);
+                    list.Add(reaction);
                 }
-
-                cache.Add(reaction);
-                return; // Only need to cache based on the first reagent.
             }
+            _reactions = dict.ToFrozenDictionary();
         }
 
         /// <summary>
@@ -82,20 +76,8 @@ namespace Content.Shared.Chemistry.Reaction
         /// <param name="eventArgs">The set of modified prototypes.</param>
         private void OnPrototypesReloaded(PrototypesReloadedEventArgs eventArgs)
         {
-            if (!eventArgs.ByType.TryGetValue(typeof(ReactionPrototype), out var set))
-                return;
-
-            foreach (var (reactant, cache) in _reactions)
-            {
-                cache.RemoveAll((reaction) => set.Modified.ContainsKey(reaction.ID));
-                if (cache.Count == 0)
-                    _reactions.Remove(reactant);
-            }
-
-            foreach (var prototype in set.Modified.Values)
-            {
-                CacheReaction((ReactionPrototype) prototype);
-            }
+            if (eventArgs.WasModified<ReactionPrototype>())
+                InitializeReactionCache();
         }
 
         /// <summary>
@@ -285,7 +267,7 @@ namespace Content.Shared.Chemistry.Reaction
             SortedSet<ReactionPrototype> reactions = new();
             foreach (var reactant in solution.Contents)
             {
-                if (_reactions.TryGetValue(reactant.Reagent.Prototype, out var reactantReactions))
+                if (_reactionsSingle.TryGetValue(reactant.Reagent.Prototype, out var reactantReactions))
                     reactions.UnionWith(reactantReactions);
             }
 
@@ -297,7 +279,7 @@ namespace Content.Shared.Chemistry.Reaction
                     return;
             }
 
-            Logger.Error($"{nameof(Solution)} {owner} could not finish reacting in under {MaxReactionIterations} loops.");
+            Log.Error($"{nameof(Solution)} {owner} could not finish reacting in under {MaxReactionIterations} loops.");
         }
     }
 
index 225687aabdd8ecf41b145d918d96dd922e8e8fb2..baae144ac58df4c64aa24bb3dcb3e2baaa611042 100644 (file)
@@ -83,6 +83,9 @@ namespace Content.Shared.Entry
 
         private void PrototypeReload(PrototypesReloadedEventArgs obj)
         {
+            if (!obj.WasModified<ContentTileDefinition>())
+                return;
+
             // Need to re-allocate tiledefs due to how prototype reloads work
             foreach (var def in _prototypeManager.EnumeratePrototypes<ContentTileDefinition>())
             {
index 68f7cfe362d548464377ef8843fe16f85256c81e..7bf0be998b696894bbcda7f81695caa697cc6638 100644 (file)
@@ -1,4 +1,6 @@
+using System.Collections.Frozen;
 using System.Diagnostics.CodeAnalysis;
+using System.Linq;
 using Content.Shared.Humanoid.Prototypes;
 using Robust.Shared.Prototypes;
 
@@ -9,33 +11,41 @@ namespace Content.Shared.Humanoid.Markings
         [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
 
         private readonly List<MarkingPrototype> _index = new();
-        private readonly Dictionary<MarkingCategories, Dictionary<string, MarkingPrototype>> _markingDict = new();
-        private readonly Dictionary<string, MarkingPrototype> _markings = new();
+        public FrozenDictionary<MarkingCategories, FrozenDictionary<string, MarkingPrototype>> CategorizedMarkings = default!;
+        public FrozenDictionary<string, MarkingPrototype> Markings = default!;
 
         public void Initialize()
         {
             _prototypeManager.PrototypesReloaded += OnPrototypeReload;
+            CachePrototypes();
+        }
+
+        private void CachePrototypes()
+        {
+            _index.Clear();
+            var markingDict = new Dictionary<MarkingCategories, Dictionary<string, MarkingPrototype>>();
 
             foreach (var category in Enum.GetValues<MarkingCategories>())
             {
-                _markingDict.Add(category, new Dictionary<string, MarkingPrototype>());
+                markingDict.Add(category, new());
             }
 
             foreach (var prototype in _prototypeManager.EnumeratePrototypes<MarkingPrototype>())
             {
                 _index.Add(prototype);
-                _markingDict[prototype.MarkingCategory].Add(prototype.ID, prototype);
-                _markings.Add(prototype.ID, prototype);
+                markingDict[prototype.MarkingCategory].Add(prototype.ID, prototype);
             }
-        }
 
-        public IReadOnlyDictionary<string, MarkingPrototype> Markings => _markings;
-        public IReadOnlyDictionary<MarkingCategories, Dictionary<string, MarkingPrototype>> CategorizedMarkings => _markingDict;
+            Markings = _prototypeManager.EnumeratePrototypes<MarkingPrototype>().ToFrozenDictionary(x => x.ID);
+            CategorizedMarkings = markingDict.ToFrozenDictionary(
+                x => x.Key,
+                x => x.Value.ToFrozenDictionary());
+        }
 
-        public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategory(MarkingCategories category)
+        public FrozenDictionary<string, MarkingPrototype> MarkingsByCategory(MarkingCategories category)
         {
             // all marking categories are guaranteed to have a dict entry
-            return _markingDict[category];
+            return CategorizedMarkings[category];
         }
 
         /// <summary>
@@ -143,7 +153,7 @@ namespace Content.Shared.Humanoid.Markings
 
         public bool TryGetMarking(Marking marking, [NotNullWhen(true)] out MarkingPrototype? markingResult)
         {
-            return _markings.TryGetValue(marking.MarkingId, out markingResult);
+            return Markings.TryGetValue(marking.MarkingId, out markingResult);
         }
 
         /// <summary>
@@ -178,17 +188,8 @@ namespace Content.Shared.Humanoid.Markings
 
         private void OnPrototypeReload(PrototypesReloadedEventArgs args)
         {
-            if(!args.ByType.TryGetValue(typeof(MarkingPrototype), out var set))
-                return;
-
-
-            _index.RemoveAll(i => set.Modified.ContainsKey(i.ID));
-
-            foreach (var prototype in set.Modified.Values)
-            {
-                var markingPrototype = (MarkingPrototype) prototype;
-                _index.Add(markingPrototype);
-            }
+            if (args.WasModified<MarkingPrototype>())
+                CachePrototypes();
         }
 
         public bool CanBeApplied(string species, Sex sex, Marking marking, IPrototypeManager? prototypeManager = null)
index 0acda7425fe8840218775297af20a4ea96535e2a..fe0f9d115bf9e2406595e64ca2d40be25d75f216 100644 (file)
@@ -22,19 +22,14 @@ public abstract class SharedJobSystem : EntitySystem
     public override void Initialize()
     {
         base.Initialize();
-        _protoManager.PrototypesReloaded += OnProtoReload;
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnProtoReload);
         SetupTrackerLookup();
     }
 
-    public override void Shutdown()
-    {
-        base.Shutdown();
-        _protoManager.PrototypesReloaded -= OnProtoReload;
-    }
-
     private void OnProtoReload(PrototypesReloadedEventArgs obj)
     {
-        SetupTrackerLookup();
+        if (obj.WasModified<JobPrototype>())
+            SetupTrackerLookup();
     }
 
     private void SetupTrackerLookup()