Skip to content

Commit

Permalink
Cleans up tag system (space-wizards#28272)
Browse files Browse the repository at this point in the history
* Updated tag system

* Added params methods

* Fixed tag integration tests

* Fixed params methods recursion

* Revert has All/Any tag one argument realisation

* Updated tag integration tests

* Shit happens

* Added individual List/HashSet methods, docs, tests
  • Loading branch information
Tornado-Technology authored and sleepyyapril committed Dec 21, 2024
1 parent ebd00f5 commit cfb1fdf
Show file tree
Hide file tree
Showing 17 changed files with 162 additions and 127 deletions.
3 changes: 1 addition & 2 deletions Content.Client/Verbs/VerbSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,14 @@ public bool TryGetEntityMenuEntities(MapCoordinates targetPos, [NotNullWhen(true
if ((visibility & MenuVisibility.Invisible) == 0)
{
var spriteQuery = GetEntityQuery<SpriteComponent>();
var tagQuery = GetEntityQuery<TagComponent>();

for (var i = entities.Count - 1; i >= 0; i--)
{
var entity = entities[i];

if (!spriteQuery.TryGetComponent(entity, out var spriteComponent) ||
!spriteComponent.Visible ||
_tagSystem.HasTag(entity, "HideContextMenu", tagQuery))
_tagSystem.HasTag(entity, "HideContextMenu"))
{
entities.RemoveSwap(i);
}
Expand Down
161 changes: 108 additions & 53 deletions Content.IntegrationTests/Tests/Tag/TagTest.cs

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions Content.Server/Administration/Toolshed/TagCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ public sealed class TagCommand : ToolshedCommand
private TagSystem? _tag;

[CommandImplementation("list")]
public IEnumerable<string> List([PipedArgument] IEnumerable<EntityUid> ent)
public IEnumerable<ProtoId<TagPrototype>> List([PipedArgument] IEnumerable<EntityUid> ent)
{
return ent.SelectMany(x =>
{
if (TryComp<TagComponent>(x, out var tags))
// Note: Cast is required for C# to figure out the type signature.
return (IEnumerable<string>)tags.Tags;
return Array.Empty<string>();
return (IEnumerable<ProtoId<TagPrototype>>)tags.Tags;
return Array.Empty<ProtoId<TagPrototype>>();
});
}

Expand Down
2 changes: 1 addition & 1 deletion Content.Server/Mech/Systems/MechAssemblySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private void OnInteractUsing(EntityUid uid, MechAssemblyComponent component, Int

foreach (var (tag, val) in component.RequiredParts)
{
if (!val && tagComp.Tags.Contains(tag))
if (!val && _tag.HasTag(tagComp, tag))
{
component.RequiredParts[tag] = true;
_container.Insert(args.Used, component.PartsContainer);
Expand Down
5 changes: 4 additions & 1 deletion Content.Server/Procedural/DungeonJob.PostGen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;

Expand All @@ -24,13 +25,15 @@ public sealed partial class DungeonJob
* Run after the main dungeon generation
*/

private static readonly ProtoId<TagPrototype> WallTag = "Wall";

private bool HasWall(MapGridComponent grid, Vector2i tile)
{
var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile);

while (anchored.MoveNext(out var uid))
{
if (_tagQuery.TryGetComponent(uid, out var tagComp) && tagComp.Tags.Contains("Wall"))
if (_tag.HasTag(uid.Value, WallTag))
return true;
}

Expand Down
5 changes: 3 additions & 2 deletions Content.Server/Procedural/DungeonJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ public sealed partial class DungeonJob : Job<Dungeon>
private readonly DecalSystem _decals;
private readonly DungeonSystem _dungeon;
private readonly EntityLookupSystem _lookup;
private readonly TagSystem _tag;
private readonly TileSystem _tile;
private readonly SharedMapSystem _maps;
private readonly SharedTransformSystem _transform;
private EntityQuery<TagComponent> _tagQuery;

private readonly DungeonConfigPrototype _gen;
private readonly int _seed;
Expand All @@ -53,6 +53,7 @@ public DungeonJob(
DecalSystem decals,
DungeonSystem dungeon,
EntityLookupSystem lookup,
TagSystem tag,
TileSystem tile,
SharedTransformSystem transform,
DungeonConfigPrototype gen,
Expand All @@ -72,10 +73,10 @@ public DungeonJob(
_decals = decals;
_dungeon = dungeon;
_lookup = lookup;
_tag = tag;
_tile = tile;
_maps = _entManager.System<SharedMapSystem>();
_transform = transform;
_tagQuery = _entManager.GetEntityQuery<TagComponent>();

_gen = gen;
_grid = grid;
Expand Down
4 changes: 4 additions & 0 deletions Content.Server/Procedural/DungeonSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Content.Shared.Maps;
using Content.Shared.Physics;
using Content.Shared.Procedural;
using Content.Shared.Tag;
using Robust.Server.GameObjects;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
Expand All @@ -31,6 +32,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
[Dependency] private readonly AnchorableSystem _anchorable = default!;
[Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
Expand Down Expand Up @@ -199,6 +201,7 @@ public void GenerateDungeon(DungeonConfigPrototype gen,
_decals,
this,
_lookup,
_tag,
_tile,
_transform,
gen,
Expand Down Expand Up @@ -231,6 +234,7 @@ public async Task<Dungeon> GenerateDungeonAsync(
_decals,
this,
_lookup,
_tag,
_tile,
_transform,
gen,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ private void OnDefileAction(EntityUid uid, RevenantComponent component, Revenant
foreach (var ent in lookup)
{
//break windows
if (tags.HasComponent(ent) && _tag.HasAnyTag(ent, "Window"))
if (tags.HasComponent(ent) && _tag.HasTag(ent, "Window"))
{
//hardcoded damage specifiers til i die.
var dspec = new DamageSpecifier();
Expand Down
10 changes: 4 additions & 6 deletions Content.Server/Spreader/SpreaderSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public sealed class SpreaderSystem : EntitySystem
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly TagSystem _tag = default!;

/// <summary>
/// Cached maximum number of updates per spreader prototype. This is applied per-grid.
Expand All @@ -37,8 +38,7 @@ public sealed class SpreaderSystem : EntitySystem

public const float SpreadCooldownSeconds = 1;

[ValidatePrototypeId<TagPrototype>]
private const string IgnoredTag = "SpreaderIgnore";
private static readonly ProtoId<TagPrototype> IgnoredTag = "SpreaderIgnore";

/// <inheritdoc/>
public override void Initialize()
Expand Down Expand Up @@ -189,7 +189,6 @@ public void GetNeighbors(EntityUid uid, TransformComponent comp, ProtoId<EdgeSpr
var airtightQuery = GetEntityQuery<AirtightComponent>();
var dockQuery = GetEntityQuery<DockingComponent>();
var xformQuery = GetEntityQuery<TransformComponent>();
var tagQuery = GetEntityQuery<TagComponent>();
var blockedAtmosDirs = AtmosDirection.Invalid;

// Due to docking ports they may not necessarily be opposite directions.
Expand All @@ -212,7 +211,7 @@ public void GetNeighbors(EntityUid uid, TransformComponent comp, ProtoId<EdgeSpr

// If we're on a blocked tile work out which directions we can go.
if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked ||
tagQuery.TryGetComponent(ent, out var tags) && tags.Tags.Contains(IgnoredTag))
_tag.HasTag(ent.Value, IgnoredTag))
{
continue;
}
Expand Down Expand Up @@ -250,8 +249,7 @@ public void GetNeighbors(EntityUid uid, TransformComponent comp, ProtoId<EdgeSpr

while (directionEnumerator.MoveNext(out var ent))
{
if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked ||
tagQuery.TryGetComponent(ent, out var tags) && tags.Tags.Contains(IgnoredTag))
if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked || _tag.HasTag(ent.Value, IgnoredTag))
{
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ public abstract class SharedChameleonClothingSystem : EntitySystem
{
[Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
[Dependency] private readonly ClothingSystem _clothingSystem = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
[Dependency] private readonly TagSystem _tag = default!;

public override void Initialize()
{
Expand Down Expand Up @@ -81,7 +82,7 @@ public bool IsValidTarget(EntityPrototype proto, SlotFlags chameleonSlot = SlotF
return false;

// check if it is marked as valid chameleon target
if (!proto.TryGetComponent(out TagComponent? tags, _factory) || !tags.Tags.Contains("WhitelistChameleon"))
if (!proto.TryGetComponent(out TagComponent? tag, _factory) || !_tag.HasTag(tag, "WhitelistChameleon"))
return false;

// check if it's valid clothing
Expand Down
3 changes: 1 addition & 2 deletions Content.Shared/Construction/Conditions/NoWindowsInTile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ public sealed partial class NoWindowsInTile : IConstructionCondition
public bool Condition(EntityUid user, EntityCoordinates location, Direction direction)
{
var entManager = IoCManager.Resolve<IEntityManager>();
var tagQuery = entManager.GetEntityQuery<TagComponent>();
var sysMan = entManager.EntitySysManager;
var tagSystem = sysMan.GetEntitySystem<TagSystem>();

foreach (var entity in location.GetEntitiesInTile(LookupFlags.Static))
{
if (tagSystem.HasTag(entity, "Window", tagQuery))
if (tagSystem.HasTag(entity, "Window"))
return false;
}

Expand Down
11 changes: 4 additions & 7 deletions Content.Shared/Construction/EntitySystems/AnchorableSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Content.Shared.Tag;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem;
Expand All @@ -32,16 +33,14 @@ public sealed partial class AnchorableSystem : EntitySystem
[Dependency] private readonly TagSystem _tagSystem = default!;

private EntityQuery<PhysicsComponent> _physicsQuery;
private EntityQuery<TagComponent> _tagQuery;

public const string Unstackable = "Unstackable";
public readonly ProtoId<TagPrototype> Unstackable = "Unstackable";

public override void Initialize()
{
base.Initialize();

_physicsQuery = GetEntityQuery<PhysicsComponent>();
_tagQuery = GetEntityQuery<TagComponent>();

SubscribeLocalEvent<AnchorableComponent, InteractUsingEvent>(OnInteractUsing,
before: new[] { typeof(ItemSlotsSystem) }, after: new[] { typeof(SharedConstructionSystem) });
Expand Down Expand Up @@ -312,7 +311,7 @@ public bool AnyUnstackable(EntityUid uid, EntityCoordinates location)
DebugTools.Assert(!Transform(uid).Anchored);

// If we are unstackable, iterate through any other entities anchored on the current square
return _tagSystem.HasTag(uid, Unstackable, _tagQuery) && AnyUnstackablesAnchoredAt(location);
return _tagSystem.HasTag(uid, Unstackable) && AnyUnstackablesAnchoredAt(location);
}

public bool AnyUnstackablesAnchoredAt(EntityCoordinates location)
Expand All @@ -327,10 +326,8 @@ public bool AnyUnstackablesAnchoredAt(EntityCoordinates location)
while (enumerator.MoveNext(out var entity))
{
// If we find another unstackable here, return true.
if (_tagSystem.HasTag(entity.Value, Unstackable, _tagQuery))
{
if (_tagSystem.HasTag(entity.Value, Unstackable))
return true;
}
}

return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using Content.Shared.Tag;
using Robust.Shared.Prototypes;

namespace Content.Shared.Construction.Steps
{
public sealed partial class MultipleTagsConstructionGraphStep : ArbitraryInsertConstructionGraphStep
{
[DataField("allTags")]
private List<string>? _allTags;
private List<ProtoId<TagPrototype>>? _allTags;

[DataField("anyTags")]
private List<string>? _anyTags;
private List<ProtoId<TagPrototype>>? _anyTags;

private static bool IsNullOrEmpty<T>(ICollection<T>? list)
{
Expand All @@ -21,16 +22,12 @@ public override bool EntityValid(EntityUid uid, IEntityManager entityManager, IC
if (IsNullOrEmpty(_allTags) && IsNullOrEmpty(_anyTags))
return false; // Step is somehow invalid, we return.

// No tags at all.
if (!entityManager.TryGetComponent(uid, out TagComponent? tags))
return false;

var tagSystem = entityManager.EntitySysManager.GetEntitySystem<TagSystem>();

if (_allTags != null && !tagSystem.HasAllTags(tags, _allTags))
if (_allTags != null && !tagSystem.HasAllTags(uid, _allTags))
return false; // We don't have all the tags needed.

if (_anyTags != null && !tagSystem.HasAnyTag(tags, _anyTags))
if (_anyTags != null && !tagSystem.HasAnyTag(uid, _anyTags))
return false; // We don't have any of the tags needed.

// This entity is valid!
Expand Down
4 changes: 2 additions & 2 deletions Content.Shared/Pinpointer/SharedNavMapSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public abstract class SharedNavMapSystem : EntitySystem
[Robust.Shared.IoC.Dependency] private readonly TagSystem _tagSystem = default!;
[Robust.Shared.IoC.Dependency] private readonly INetManager _net = default!;

private readonly string[] _wallTags = ["Wall", "Window"];
private static readonly ProtoId<TagPrototype>[] WallTags = {"Wall", "Window"};
private EntityQuery<NavMapDoorComponent> _doorQuery;

public override void Initialize()
Expand Down Expand Up @@ -59,7 +59,7 @@ public NavMapChunkType GetEntityType(EntityUid uid)
if (_doorQuery.HasComp(uid))
return NavMapChunkType.Airlock;

if (_tagSystem.HasAnyTag(uid, _wallTags))
if (_tagSystem.HasAnyTag(uid, WallTags))
return NavMapChunkType.Wall;

return NavMapChunkType.Invalid;
Expand Down
16 changes: 7 additions & 9 deletions Content.Shared/Tag/TagComponent.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
using Robust.Shared.Prototypes;

namespace Content.Shared.Tag
namespace Content.Shared.Tag;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(TagSystem))]
public sealed partial class TagComponent : Component
{
[RegisterComponent, NetworkedComponent, Access(typeof(TagSystem))]
public sealed partial class TagComponent : Component
{
[DataField("tags", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<TagPrototype>))]
[Access(typeof(TagSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
public HashSet<string> Tags = new();
}
[DataField, ViewVariables, AutoNetworkedField]
public HashSet<ProtoId<TagPrototype>> Tags = new();
}
15 changes: 0 additions & 15 deletions Content.Shared/Tag/TagComponentState.cs

This file was deleted.

24 changes: 11 additions & 13 deletions Content.Shared/Tag/TagPrototype.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
using Robust.Shared.Prototypes;

namespace Content.Shared.Tag
namespace Content.Shared.Tag;

/// <summary>
/// Prototype representing a tag in YAML.
/// Meant to only have an ID property, as that is the only thing that
/// gets saved in TagComponent.
/// </summary>
[Prototype("Tag")]
public sealed partial class TagPrototype : IPrototype
{
/// <summary>
/// Prototype representing a tag in YAML.
/// Meant to only have an ID property, as that is the only thing that
/// gets saved in TagComponent.
/// </summary>
[Prototype("Tag")]
public sealed partial class TagPrototype : IPrototype
{
[ViewVariables]
[IdDataField]
public string ID { get; private set; } = default!;
}
[IdDataField, ViewVariables]
public string ID { get; } = string.Empty;
}

0 comments on commit cfb1fdf

Please sign in to comment.