diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.CornerClutter.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.CornerClutter.cs index 918e5efa0d..3fc20147f9 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.CornerClutter.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.CornerClutter.cs @@ -42,7 +42,7 @@ public sealed partial class DungeonJob if (random.Prob(gen.Chance)) { var coords = _maps.GridTileToLocal(_gridUid, _grid, tile); - var protos = contentsTable.Table.GetSpawns(random, _entManager, _prototype); + var protos = _entTable.GetSpawns(contentsTable, random); _entManager.SpawnEntitiesAttachedTo(coords, protos); } diff --git a/Content.Shared/EntityTable/Conditions/EntityTableCondition.cs b/Content.Shared/EntityTable/Conditions/EntityTableCondition.cs index 9505b6502c..05c421e510 100644 --- a/Content.Shared/EntityTable/Conditions/EntityTableCondition.cs +++ b/Content.Shared/EntityTable/Conditions/EntityTableCondition.cs @@ -16,13 +16,13 @@ public abstract partial class EntityTableCondition [DataField] public bool Invert; - public bool Evaluate(IEntityManager entMan, IPrototypeManager proto) + public bool Evaluate(EntityTableSelector root, IEntityManager entMan, IPrototypeManager proto, EntityTableContext ctx) { - var res = EvaluateImplementation(entMan, proto); + var res = EvaluateImplementation(root, entMan, proto, ctx); // XOR eval to invert the result. return res ^ Invert; } - public abstract bool EvaluateImplementation(IEntityManager entMan, IPrototypeManager proto); + protected abstract bool EvaluateImplementation(EntityTableSelector root, IEntityManager entMan, IPrototypeManager proto, EntityTableContext ctx); } diff --git a/Content.Shared/EntityTable/Conditions/PlayerCountCondition.cs b/Content.Shared/EntityTable/Conditions/PlayerCountCondition.cs index 72ac75ca3f..55f0c61c3b 100644 --- a/Content.Shared/EntityTable/Conditions/PlayerCountCondition.cs +++ b/Content.Shared/EntityTable/Conditions/PlayerCountCondition.cs @@ -1,3 +1,4 @@ +using Content.Shared.EntityTable.EntitySelectors; using Robust.Shared.Player; using Robust.Shared.Prototypes; @@ -22,7 +23,7 @@ public sealed partial class PlayerCountCondition : EntityTableCondition private static ISharedPlayerManager? _playerManager; - public override bool EvaluateImplementation(IEntityManager entMan, IPrototypeManager proto) + protected override bool EvaluateImplementation(EntityTableSelector root, IEntityManager entMan, IPrototypeManager proto, EntityTableContext ctx) { // Don't resolve this repeatedly _playerManager ??= IoCManager.Resolve(); diff --git a/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs b/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs index 8fb8b5e546..0fb477ca07 100644 --- a/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs +++ b/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs @@ -12,11 +12,12 @@ public sealed partial class AllSelector : EntityTableSelector protected override IEnumerable GetSpawnsImplementation(System.Random rand, IEntityManager entMan, - IPrototypeManager proto) + IPrototypeManager proto, + EntityTableContext ctx) { foreach (var child in Children) { - foreach (var spawn in child.GetSpawns(rand, entMan, proto)) + foreach (var spawn in child.GetSpawns(rand, entMan, proto, ctx)) { yield return spawn; } diff --git a/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs b/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs index 8443ec2c06..9834603136 100644 --- a/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs +++ b/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs @@ -18,7 +18,8 @@ public sealed partial class EntSelector : EntityTableSelector protected override IEnumerable GetSpawnsImplementation(System.Random rand, IEntityManager entMan, - IPrototypeManager proto) + IPrototypeManager proto, + EntityTableContext ctx) { var num = Amount.Get(rand); for (var i = 0; i < num; i++) diff --git a/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs b/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs index 6ad80c4a2a..e25993bd1d 100644 --- a/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs +++ b/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs @@ -42,9 +42,10 @@ public abstract partial class EntityTableSelector public IEnumerable GetSpawns(System.Random rand, IEntityManager entMan, - IPrototypeManager proto) + IPrototypeManager proto, + EntityTableContext ctx) { - if (!CheckConditions(entMan, proto)) + if (!CheckConditions(entMan, proto, ctx)) yield break; var rolls = Rolls.Get(rand); @@ -53,14 +54,14 @@ public abstract partial class EntityTableSelector if (!rand.Prob(Prob)) continue; - foreach (var spawn in GetSpawnsImplementation(rand, entMan, proto)) + foreach (var spawn in GetSpawnsImplementation(rand, entMan, proto, ctx)) { yield return spawn; } } } - public bool CheckConditions(IEntityManager entMan, IPrototypeManager proto) + public bool CheckConditions(IEntityManager entMan, IPrototypeManager proto, EntityTableContext ctx) { if (Conditions.Count == 0) return true; @@ -68,7 +69,7 @@ public abstract partial class EntityTableSelector var success = false; foreach (var condition in Conditions) { - var res = condition.Evaluate(entMan, proto); + var res = condition.Evaluate(this, entMan, proto, ctx); if (RequireAll && !res) return false; // intentional break out of loop and function @@ -84,5 +85,6 @@ public abstract partial class EntityTableSelector protected abstract IEnumerable GetSpawnsImplementation(System.Random rand, IEntityManager entMan, - IPrototypeManager proto); + IPrototypeManager proto, + EntityTableContext ctx); } diff --git a/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs b/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs index 8012eeae68..25c81a4565 100644 --- a/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs +++ b/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs @@ -13,13 +13,14 @@ public sealed partial class GroupSelector : EntityTableSelector protected override IEnumerable GetSpawnsImplementation(System.Random rand, IEntityManager entMan, - IPrototypeManager proto) + IPrototypeManager proto, + EntityTableContext ctx) { var children = new Dictionary(Children.Count); foreach (var child in Children) { // Don't include invalid groups - if (!child.CheckConditions(entMan, proto)) + if (!child.CheckConditions(entMan, proto, ctx)) continue; children.Add(child, child.Weight); @@ -27,6 +28,6 @@ public sealed partial class GroupSelector : EntityTableSelector var pick = SharedRandomExtensions.Pick(children, rand); - return pick.GetSpawns(rand, entMan, proto); + return pick.GetSpawns(rand, entMan, proto, ctx); } } diff --git a/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs b/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs index fc8d8f08d3..4a96c89ccb 100644 --- a/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs +++ b/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs @@ -13,8 +13,9 @@ public sealed partial class NestedSelector : EntityTableSelector protected override IEnumerable GetSpawnsImplementation(System.Random rand, IEntityManager entMan, - IPrototypeManager proto) + IPrototypeManager proto, + EntityTableContext ctx) { - return proto.Index(TableId).Table.GetSpawns(rand, entMan, proto); + return proto.Index(TableId).Table.GetSpawns(rand, entMan, proto, ctx); } } diff --git a/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs b/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs index 21fcb6d279..f41c542420 100644 --- a/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs +++ b/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs @@ -9,7 +9,8 @@ public sealed partial class NoneSelector : EntityTableSelector { protected override IEnumerable GetSpawnsImplementation(System.Random rand, IEntityManager entMan, - IPrototypeManager proto) + IPrototypeManager proto, + EntityTableContext ctx) { yield break; } diff --git a/Content.Shared/EntityTable/EntityTableSystem.cs b/Content.Shared/EntityTable/EntityTableSystem.cs index eab8b87ad7..37c9a9411b 100644 --- a/Content.Shared/EntityTable/EntityTableSystem.cs +++ b/Content.Shared/EntityTable/EntityTableSystem.cs @@ -1,4 +1,6 @@ +using System.Diagnostics.CodeAnalysis; using Content.Shared.EntityTable.EntitySelectors; +using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -9,18 +11,55 @@ public sealed class EntityTableSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; - public IEnumerable GetSpawns(EntityTablePrototype entTableProto, System.Random? rand = null) + public IEnumerable GetSpawns(EntityTablePrototype entTableProto, System.Random? rand = null, EntityTableContext? ctx = null) { // convenient - return GetSpawns(entTableProto.Table, rand); + return GetSpawns(entTableProto.Table, rand, ctx); } - public IEnumerable GetSpawns(EntityTableSelector? table, System.Random? rand = null) + public IEnumerable GetSpawns(EntityTableSelector? table, System.Random? rand = null, EntityTableContext? ctx = null) { if (table == null) return new List(); rand ??= _random.GetRandom(); - return table.GetSpawns(rand, EntityManager, _prototypeManager); + ctx ??= new EntityTableContext(); + return table.GetSpawns(rand, EntityManager, _prototypeManager, ctx); + } +} + +/// +/// Context used by selectors and conditions to evaluate in generic gamestate information. +/// +public sealed class EntityTableContext +{ + private readonly Dictionary _data = new(); + + public EntityTableContext() + { + + } + + public EntityTableContext(Dictionary data) + { + _data = data; + } + + /// + /// Retrieves an arbitrary piece of data from the context based on a provided key. + /// + /// A string key that corresponds to the value we are searching for. + /// The value we are trying to extract from the context object + /// The type of that we are trying to retrieve + /// If has a corresponding value of type + [PublicAPI] + public bool TryGetData([ForbidLiteral] string key, [NotNullWhen(true)] out T? value) + { + value = default; + if (!_data.TryGetValue(key, out var valueData) || valueData is not T castValueData) + return false; + + value = castValueData; + return true; } }