using Content.Shared.EntityTable.Conditions;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
namespace Content.Shared.EntityTable.EntitySelectors;
///
/// Base type for entity table selector that can have child selectors and properly apply entity table conditions for them.
///
[ImplicitDataDefinitionForInheritors, UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public abstract partial class EntityTableSelectorWithChildrenBase : EntityTableSelectorWithNestedBase
{
///
/// The child entries of this selector.
///
[DataField(required: true)]
public List Children = new();
///
public override bool CheckConditions(IEntityManager entMan, IPrototypeManager proto, EntityTableContext ctx)
{
if (!base.CheckConditions(entMan, proto, ctx))
return false;
using var scoped = ScopedConditions(ctx);
foreach (var selector in Children)
{
// If any child succeeds this is a valid node
if (selector.CheckConditions(entMan, proto, ctx))
return true;
}
return false;
}
}
///
/// Base type for entity table selector that can apply list of additional entity table conditions upon
/// nested entity table selectors.
/// When making type, derived from this one, please remember to use in your implementation of
/// , and inside
/// (if you override it).
///
[ImplicitDataDefinitionForInheritors, UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public abstract partial class EntityTableSelectorWithNestedBase : EntityTableSelector
{
///
/// A list of conditions that must evaluate to 'true' for the selector to apply.
///
[DataField]
public List ConditionsForChildren = new();
///
/// Temporarily injects (merged with any conditions already
/// scoped in ) into the context so they are evaluated for every selector
/// below this one. The context is restored when the returned handle is disposed.
///
protected IDisposable ScopedConditions(EntityTableContext ctx)
{
if (ConditionsForChildren.Count == 0)
return default(ScopedConditionsRestore);
if (!ctx.TryGetData>(AdditionalConditionsKey, out var existingConditions))
{
// Nothing was scoped before: our own list can be used directly, no copy.
ctx.SetData(AdditionalConditionsKey, ConditionsForChildren);
return new ScopedConditionsRestore(ctx, null);
}
// Merge our conditions with whatever is already scoped in the context.
var combined = new List(ConditionsForChildren);
combined.AddRange(existingConditions);
ctx.SetData(AdditionalConditionsKey, combined);
return new ScopedConditionsRestore(ctx, existingConditions);
}
///
/// Restores the after a scoped-conditions block.
///
protected readonly struct ScopedConditionsRestore(
EntityTableContext? ctx,
List? existingConditions
) : IDisposable
{
public void Dispose()
{
if(ctx == null)
return;
if (existingConditions is null)
ctx.RemoveData(AdditionalConditionsKey);
else
ctx.SetData(AdditionalConditionsKey, existingConditions);
}
}
}