Use ECS prototype-reload events (#22613)
* Use ECS prototype-reload events * better constructors * Maybe this fixes tests?
This commit is contained in:
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user