Use ECS prototype-reload events (#22613)

* Use ECS prototype-reload events

* better constructors

* Maybe this fixes tests?
This commit is contained in:
Leon Friedrich
2023-12-22 09:13:45 -05:00
committed by GitHub
parent 053c1e877f
commit b6bd82caa6
23 changed files with 135 additions and 242 deletions

View 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.");
}
}