Cleans up tag system (#28272)

* 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
This commit is contained in:
Tornado Tech
2024-06-02 11:11:19 +10:00
committed by GitHub
parent da6a1bbdd4
commit 21bc3bfa22
18 changed files with 834 additions and 780 deletions

View File

@@ -123,7 +123,6 @@ namespace Content.Client.Verbs
if ((visibility & MenuVisibility.Invisible) == 0) if ((visibility & MenuVisibility.Invisible) == 0)
{ {
var spriteQuery = GetEntityQuery<SpriteComponent>(); var spriteQuery = GetEntityQuery<SpriteComponent>();
var tagQuery = GetEntityQuery<TagComponent>();
for (var i = entities.Count - 1; i >= 0; i--) for (var i = entities.Count - 1; i >= 0; i--)
{ {
@@ -131,7 +130,7 @@ namespace Content.Client.Verbs
if (!spriteQuery.TryGetComponent(entity, out var spriteComponent) || if (!spriteQuery.TryGetComponent(entity, out var spriteComponent) ||
!spriteComponent.Visible || !spriteComponent.Visible ||
_tagSystem.HasTag(entity, "HideContextMenu", tagQuery)) _tagSystem.HasTag(entity, "HideContextMenu"))
{ {
entities.RemoveSwap(i); entities.RemoveSwap(i);
} }

View File

@@ -53,11 +53,13 @@ namespace Content.IntegrationTests.Tests.Tag
EntityUid sTagDummy = default; EntityUid sTagDummy = default;
TagComponent sTagComponent = null!; TagComponent sTagComponent = null!;
Entity<TagComponent> sTagEntity = default;
await server.WaitPost(() => await server.WaitPost(() =>
{ {
sTagDummy = sEntityManager.SpawnEntity(TagEntityId, MapCoordinates.Nullspace); sTagDummy = sEntityManager.SpawnEntity(TagEntityId, MapCoordinates.Nullspace);
sTagComponent = sEntityManager.GetComponent<TagComponent>(sTagDummy); sTagComponent = sEntityManager.GetComponent<TagComponent>(sTagDummy);
sTagEntity = new Entity<TagComponent>(sTagDummy, sTagComponent);
}); });
await server.WaitAssertion(() => await server.WaitAssertion(() =>
@@ -130,49 +132,64 @@ namespace Content.IntegrationTests.Tests.Tag
Assert.Multiple(() => Assert.Multiple(() =>
{ {
// Cannot add the starting tag again // Cannot add the starting tag again
Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, StartingTag), Is.False); Assert.That(tagSystem.AddTag(sTagEntity, StartingTag), Is.False);
Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, StartingTag, StartingTag), Is.False);
Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, new List<string> { StartingTag, StartingTag }), Is.False); Assert.That(tagSystem.AddTags(sTagEntity, StartingTag, StartingTag), Is.False);
Assert.That(tagSystem.AddTags(sTagEntity, new List<ProtoId<TagPrototype>> { StartingTag, StartingTag }), Is.False);
Assert.That(tagSystem.AddTags(sTagEntity, new HashSet<ProtoId<TagPrototype>> { StartingTag, StartingTag }), Is.False);
// Has the starting tag // Has the starting tag
Assert.That(tagSystem.HasTag(sTagComponent, StartingTag), Is.True); Assert.That(tagSystem.HasTag(sTagComponent, StartingTag), Is.True);
Assert.That(tagSystem.HasAllTags(sTagComponent, StartingTag, StartingTag), Is.True); Assert.That(tagSystem.HasAllTags(sTagComponent, StartingTag, StartingTag), Is.True);
Assert.That(tagSystem.HasAllTags(sTagComponent, new List<string> { StartingTag, StartingTag }), Is.True); Assert.That(tagSystem.HasAllTags(sTagComponent, new List<ProtoId<TagPrototype>> { StartingTag, StartingTag }), Is.True);
Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet<ProtoId<TagPrototype>> { StartingTag, StartingTag }), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, StartingTag, StartingTag), Is.True); Assert.That(tagSystem.HasAnyTag(sTagComponent, StartingTag, StartingTag), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new List<string> { StartingTag, StartingTag }), Is.True); Assert.That(tagSystem.HasAnyTag(sTagComponent, new List<ProtoId<TagPrototype>> { StartingTag, StartingTag }), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet<ProtoId<TagPrototype>> { StartingTag, StartingTag }), Is.True);
// Does not have the added tag yet // Does not have the added tag yet
Assert.That(tagSystem.HasTag(sTagComponent, AddedTag), Is.False); Assert.That(tagSystem.HasTag(sTagComponent, AddedTag), Is.False);
Assert.That(tagSystem.HasAllTags(sTagComponent, AddedTag, AddedTag), Is.False); Assert.That(tagSystem.HasAllTags(sTagComponent, AddedTag, AddedTag), Is.False);
Assert.That(tagSystem.HasAllTags(sTagComponent, new List<string> { AddedTag, AddedTag }), Is.False); Assert.That(tagSystem.HasAllTags(sTagComponent, new List<ProtoId<TagPrototype>> { AddedTag, AddedTag }), Is.False);
Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet<ProtoId<TagPrototype>> { AddedTag, AddedTag }), Is.False);
Assert.That(tagSystem.HasAnyTag(sTagComponent, AddedTag, AddedTag), Is.False); Assert.That(tagSystem.HasAnyTag(sTagComponent, AddedTag, AddedTag), Is.False);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new List<string> { AddedTag, AddedTag }), Is.False); Assert.That(tagSystem.HasAnyTag(sTagComponent, new List<ProtoId<TagPrototype>> { AddedTag, AddedTag }), Is.False);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet<ProtoId<TagPrototype>> { AddedTag, AddedTag }), Is.False);
// Has a combination of the two tags // Has a combination of the two tags
Assert.That(tagSystem.HasAnyTag(sTagComponent, StartingTag, AddedTag), Is.True); Assert.That(tagSystem.HasAnyTag(sTagComponent, StartingTag, AddedTag), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new List<string> { StartingTag, AddedTag }), Is.True); Assert.That(tagSystem.HasAnyTag(sTagComponent, new List<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.True);
// Does not have both tags // Does not have both tags
Assert.That(tagSystem.HasAllTags(sTagComponent, StartingTag, AddedTag), Is.False); Assert.That(tagSystem.HasAllTags(sTagComponent, StartingTag, AddedTag), Is.False);
Assert.That(tagSystem.HasAllTags(sTagComponent, new List<string> { StartingTag, AddedTag }), Is.False); Assert.That(tagSystem.HasAllTags(sTagComponent, new List<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.False);
Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.False);
// Cannot remove a tag that does not exist // Cannot remove a tag that does not exist
Assert.That(tagSystem.RemoveTag(sTagDummy, sTagComponent, AddedTag), Is.False); Assert.That(tagSystem.RemoveTag(sTagEntity, AddedTag), Is.False);
Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, AddedTag, AddedTag), Is.False);
Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, new List<string> { AddedTag, AddedTag }), Is.False); Assert.That(tagSystem.RemoveTags(sTagEntity, AddedTag, AddedTag), Is.False);
Assert.That(tagSystem.RemoveTags(sTagEntity, new List<ProtoId<TagPrototype>> { AddedTag, AddedTag }), Is.False);
Assert.That(tagSystem.RemoveTags(sTagEntity, new HashSet<ProtoId<TagPrototype>> { AddedTag, AddedTag }), Is.False);
}); });
// Can add the new tag // Can add the new tag
Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, AddedTag), Is.True); Assert.That(tagSystem.AddTag(sTagEntity, AddedTag), Is.True);
Assert.Multiple(() => Assert.Multiple(() =>
{ {
// Cannot add it twice // Cannot add it twice
Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, AddedTag), Is.False); Assert.That(tagSystem.AddTag(sTagEntity, AddedTag), Is.False);
// Cannot add existing tags // Cannot add existing tags
Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, StartingTag, AddedTag), Is.False); Assert.That(tagSystem.AddTags(sTagEntity, StartingTag, AddedTag), Is.False);
Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, new List<string> { StartingTag, AddedTag }), Is.False); Assert.That(tagSystem.AddTags(sTagEntity, new List<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.False);
Assert.That(tagSystem.AddTags(sTagEntity, new HashSet<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.False);
// Now has two tags // Now has two tags
Assert.That(sTagComponent.Tags, Has.Count.EqualTo(2)); Assert.That(sTagComponent.Tags, Has.Count.EqualTo(2));
@@ -180,65 +197,103 @@ namespace Content.IntegrationTests.Tests.Tag
// Has both tags // Has both tags
Assert.That(tagSystem.HasTag(sTagComponent, StartingTag), Is.True); Assert.That(tagSystem.HasTag(sTagComponent, StartingTag), Is.True);
Assert.That(tagSystem.HasTag(sTagComponent, AddedTag), Is.True); Assert.That(tagSystem.HasTag(sTagComponent, AddedTag), Is.True);
Assert.That(tagSystem.HasAllTags(sTagComponent, StartingTag, StartingTag), Is.True); Assert.That(tagSystem.HasAllTags(sTagComponent, StartingTag, StartingTag), Is.True);
Assert.That(tagSystem.HasAllTags(sTagComponent, AddedTag, StartingTag), Is.True); Assert.That(tagSystem.HasAllTags(sTagComponent, AddedTag, StartingTag), Is.True);
Assert.That(tagSystem.HasAllTags(sTagComponent, new List<string> { StartingTag, AddedTag }), Is.True); Assert.That(tagSystem.HasAllTags(sTagComponent, new List<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.True);
Assert.That(tagSystem.HasAllTags(sTagComponent, new List<string> { AddedTag, StartingTag }), Is.True); Assert.That(tagSystem.HasAllTags(sTagComponent, new List<ProtoId<TagPrototype>> { AddedTag, StartingTag }), Is.True);
Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.True);
Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet<ProtoId<TagPrototype>> { AddedTag, StartingTag }), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, StartingTag, AddedTag), Is.True); Assert.That(tagSystem.HasAnyTag(sTagComponent, StartingTag, AddedTag), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, AddedTag, StartingTag), Is.True); Assert.That(tagSystem.HasAnyTag(sTagComponent, AddedTag, StartingTag), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new List<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new List<ProtoId<TagPrototype>> { AddedTag, StartingTag }), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.True);
Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet<ProtoId<TagPrototype>> { AddedTag, StartingTag }), Is.True);
}); });
Assert.Multiple(() => Assert.Multiple(() =>
{ {
// Remove the existing starting tag // Remove the existing starting tag
Assert.That(tagSystem.RemoveTag(sTagDummy, sTagComponent, StartingTag), Is.True); Assert.That(tagSystem.RemoveTag(sTagEntity, StartingTag), Is.True);
// Remove the existing added tag // Remove the existing added tag
Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, AddedTag, AddedTag), Is.True); Assert.That(tagSystem.RemoveTags(sTagEntity, AddedTag, AddedTag), Is.True);
}); });
Assert.Multiple(() => Assert.Multiple(() =>
{ {
// No tags left to remove // No tags left to remove
Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, new List<string> { StartingTag, AddedTag }), Is.False); Assert.That(tagSystem.RemoveTags(sTagEntity, new List<ProtoId<TagPrototype>> { StartingTag, AddedTag }), Is.False);
// No tags left in the component // No tags left in the component
Assert.That(sTagComponent.Tags, Is.Empty); Assert.That(sTagComponent.Tags, Is.Empty);
}); });
#if !DEBUG // It is run only in DEBUG build,
return; // as the checks are performed only in DEBUG build.
#if DEBUG
// Has single
Assert.Throws<DebugAssertException>(() => { tagSystem.HasTag(sTagDummy, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasTag(sTagComponent, UnregisteredTag); });
// HasAny entityUid methods
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAnyTag(sTagDummy, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAnyTag(sTagDummy, UnregisteredTag, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAnyTag(sTagDummy, new List<ProtoId<TagPrototype>> { UnregisteredTag }); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAnyTag(sTagDummy, new HashSet<ProtoId<TagPrototype>> { UnregisteredTag }); });
// HasAny component methods
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAnyTag(sTagComponent, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAnyTag(sTagComponent, UnregisteredTag, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAnyTag(sTagComponent, new List<ProtoId<TagPrototype>> { UnregisteredTag }); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAnyTag(sTagComponent, new HashSet<ProtoId<TagPrototype>> { UnregisteredTag }); });
// HasAll entityUid methods
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAllTags(sTagDummy, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAllTags(sTagDummy, UnregisteredTag, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAllTags(sTagDummy, new List<ProtoId<TagPrototype>> { UnregisteredTag }); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAllTags(sTagDummy, new HashSet<ProtoId<TagPrototype>> { UnregisteredTag }); });
// HasAll component methods
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAllTags(sTagComponent, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAllTags(sTagComponent, UnregisteredTag, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAllTags(sTagComponent, new List<ProtoId<TagPrototype>> { UnregisteredTag }); });
Assert.Throws<DebugAssertException>(() => { tagSystem.HasAllTags(sTagComponent, new HashSet<ProtoId<TagPrototype>> { UnregisteredTag }); });
// RemoveTag single
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTag(sTagDummy, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTag(sTagEntity, UnregisteredTag); });
// RemoveTags entityUid methods
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTags(sTagDummy, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTags(sTagDummy, UnregisteredTag, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTags(sTagDummy, new List<ProtoId<TagPrototype>> { UnregisteredTag }); });
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTags(sTagDummy, new HashSet<ProtoId<TagPrototype>> { UnregisteredTag }); });
// RemoveTags entity methods
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTags(sTagEntity, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTags(sTagEntity, UnregisteredTag, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTags(sTagEntity, new List<ProtoId<TagPrototype>> { UnregisteredTag }); });
Assert.Throws<DebugAssertException>(() => { tagSystem.RemoveTags(sTagEntity, new HashSet<ProtoId<TagPrototype>> { UnregisteredTag }); });
// AddTag single
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTag(sTagDummy, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTag(sTagEntity, UnregisteredTag); });
// AddTags entityUid methods
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTags(sTagDummy, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTags(sTagDummy, UnregisteredTag, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTags(sTagDummy, new List<ProtoId<TagPrototype>> { UnregisteredTag }); });
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTags(sTagDummy, new HashSet<ProtoId<TagPrototype>> { UnregisteredTag }); });
// AddTags entity methods
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTags(sTagEntity, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTags(sTagEntity, UnregisteredTag, UnregisteredTag); });
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTags(sTagEntity, new List<ProtoId<TagPrototype>> { UnregisteredTag }); });
Assert.Throws<DebugAssertException>(() => { tagSystem.AddTags(sTagEntity, new HashSet<ProtoId<TagPrototype>> { UnregisteredTag }); });
#endif #endif
// Single
Assert.Throws<DebugAssertException>(() =>
{
tagSystem.HasTag(sTagDummy, UnregisteredTag);
});
Assert.Throws<DebugAssertException>(() =>
{
tagSystem.HasTag(sTagComponent, UnregisteredTag);
});
// Any
Assert.Throws<DebugAssertException>(() =>
{
tagSystem.HasAnyTag(sTagDummy, UnregisteredTag);
});
Assert.Throws<DebugAssertException>(() =>
{
tagSystem.HasAnyTag(sTagComponent, UnregisteredTag);
});
// All
Assert.Throws<DebugAssertException>(() =>
{
tagSystem.HasAllTags(sTagDummy, UnregisteredTag);
});
Assert.Throws<DebugAssertException>(() =>
{
tagSystem.HasAllTags(sTagComponent, UnregisteredTag);
});
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
} }

View File

@@ -1,6 +1,7 @@
using System.Linq; using System.Linq;
using Content.Shared.Administration; using Content.Shared.Administration;
using Content.Shared.Tag; using Content.Shared.Tag;
using Robust.Shared.Prototypes;
using Robust.Shared.Toolshed; using Robust.Shared.Toolshed;
using Robust.Shared.Toolshed.Syntax; using Robust.Shared.Toolshed.Syntax;
using Robust.Shared.Toolshed.TypeParsers; using Robust.Shared.Toolshed.TypeParsers;
@@ -13,14 +14,14 @@ public sealed class TagCommand : ToolshedCommand
private TagSystem? _tag; private TagSystem? _tag;
[CommandImplementation("list")] [CommandImplementation("list")]
public IEnumerable<string> List([PipedArgument] IEnumerable<EntityUid> ent) public IEnumerable<ProtoId<TagPrototype>> List([PipedArgument] IEnumerable<EntityUid> ent)
{ {
return ent.SelectMany(x => return ent.SelectMany(x =>
{ {
if (TryComp<TagComponent>(x, out var tags)) if (TryComp<TagComponent>(x, out var tags))
// Note: Cast is required for C# to figure out the type signature. // Note: Cast is required for C# to figure out the type signature.
return (IEnumerable<string>)tags.Tags; return (IEnumerable<ProtoId<TagPrototype>>)tags.Tags;
return Array.Empty<string>(); return Array.Empty<ProtoId<TagPrototype>>();
}); });
} }
@@ -72,7 +73,7 @@ public sealed class TagCommand : ToolshedCommand
) )
{ {
_tag ??= GetSys<TagSystem>(); _tag ??= GetSys<TagSystem>();
_tag.AddTags(input, @ref.Evaluate(ctx)!); _tag.AddTags(input, (IEnumerable<ProtoId<TagPrototype>>)@ref.Evaluate(ctx)!);
return input; return input;
} }
@@ -92,7 +93,7 @@ public sealed class TagCommand : ToolshedCommand
) )
{ {
_tag ??= GetSys<TagSystem>(); _tag ??= GetSys<TagSystem>();
_tag.RemoveTags(input, @ref.Evaluate(ctx)!); _tag.RemoveTags(input, (IEnumerable<ProtoId<TagPrototype>>)@ref.Evaluate(ctx)!);
return input; return input;
} }

View File

@@ -14,6 +14,7 @@ namespace Content.Server.Mech.Systems;
public sealed class MechAssemblySystem : EntitySystem public sealed class MechAssemblySystem : EntitySystem
{ {
[Dependency] private readonly ContainerSystem _container = default!; [Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly TagSystem _tag = default!;
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
@@ -44,7 +45,7 @@ public sealed class MechAssemblySystem : EntitySystem
foreach (var (tag, val) in component.RequiredParts) foreach (var (tag, val) in component.RequiredParts)
{ {
if (!val && tagComp.Tags.Contains(tag)) if (!val && _tag.HasTag(tagComp, tag))
{ {
component.RequiredParts[tag] = true; component.RequiredParts[tag] = true;
_container.Insert(args.Used, component.PartsContainer); _container.Insert(args.Used, component.PartsContainer);

View File

@@ -13,6 +13,7 @@ using Robust.Shared.Collections;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -24,13 +25,15 @@ public sealed partial class DungeonJob
* Run after the main dungeon generation * Run after the main dungeon generation
*/ */
private static readonly ProtoId<TagPrototype> WallTag = "Wall";
private bool HasWall(MapGridComponent grid, Vector2i tile) private bool HasWall(MapGridComponent grid, Vector2i tile)
{ {
var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile); var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile);
while (anchored.MoveNext(out var uid)) 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; return true;
} }

View File

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

View File

@@ -10,6 +10,7 @@ using Content.Shared.GameTicking;
using Content.Shared.Maps; using Content.Shared.Maps;
using Content.Shared.Physics; using Content.Shared.Physics;
using Content.Shared.Procedural; using Content.Shared.Procedural;
using Content.Shared.Tag;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Console; using Robust.Shared.Console;
@@ -31,6 +32,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
[Dependency] private readonly AnchorableSystem _anchorable = default!; [Dependency] private readonly AnchorableSystem _anchorable = default!;
[Dependency] private readonly DecalSystem _decals = default!; [Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly TileSystem _tile = default!; [Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly SharedMapSystem _maps = default!; [Dependency] private readonly SharedMapSystem _maps = default!;
@@ -199,6 +201,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
_decals, _decals,
this, this,
_lookup, _lookup,
_tag,
_tile, _tile,
_transform, _transform,
gen, gen,
@@ -231,6 +234,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
_decals, _decals,
this, this,
_lookup, _lookup,
_tag,
_tile, _tile,
_transform, _transform,
gen, gen,

View File

@@ -246,7 +246,7 @@ public sealed partial class RevenantSystem
foreach (var ent in lookup) foreach (var ent in lookup)
{ {
//break windows //break windows
if (tags.HasComponent(ent) && _tag.HasAnyTag(ent, "Window")) if (tags.HasComponent(ent) && _tag.HasTag(ent, "Window"))
{ {
//hardcoded damage specifiers til i die. //hardcoded damage specifiers til i die.
var dspec = new DamageSpecifier(); var dspec = new DamageSpecifier();

View File

@@ -21,6 +21,7 @@ public sealed class SpreaderSystem : EntitySystem
[Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly SharedMapSystem _map = default!; [Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly TagSystem _tag = default!;
/// <summary> /// <summary>
/// Cached maximum number of updates per spreader prototype. This is applied per-grid. /// Cached maximum number of updates per spreader prototype. This is applied per-grid.
@@ -37,8 +38,7 @@ public sealed class SpreaderSystem : EntitySystem
public const float SpreadCooldownSeconds = 1; public const float SpreadCooldownSeconds = 1;
[ValidatePrototypeId<TagPrototype>] private static readonly ProtoId<TagPrototype> IgnoredTag = "SpreaderIgnore";
private const string IgnoredTag = "SpreaderIgnore";
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
@@ -189,7 +189,6 @@ public sealed class SpreaderSystem : EntitySystem
var airtightQuery = GetEntityQuery<AirtightComponent>(); var airtightQuery = GetEntityQuery<AirtightComponent>();
var dockQuery = GetEntityQuery<DockingComponent>(); var dockQuery = GetEntityQuery<DockingComponent>();
var xformQuery = GetEntityQuery<TransformComponent>(); var xformQuery = GetEntityQuery<TransformComponent>();
var tagQuery = GetEntityQuery<TagComponent>();
var blockedAtmosDirs = AtmosDirection.Invalid; var blockedAtmosDirs = AtmosDirection.Invalid;
// Due to docking ports they may not necessarily be opposite directions. // Due to docking ports they may not necessarily be opposite directions.
@@ -212,7 +211,7 @@ public sealed class SpreaderSystem : EntitySystem
// If we're on a blocked tile work out which directions we can go. // If we're on a blocked tile work out which directions we can go.
if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked || 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; continue;
} }
@@ -250,8 +249,7 @@ public sealed class SpreaderSystem : EntitySystem
while (directionEnumerator.MoveNext(out var ent)) while (directionEnumerator.MoveNext(out var ent))
{ {
if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked || if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked || _tag.HasTag(ent.Value, IgnoredTag))
tagQuery.TryGetComponent(ent, out var tags) && tags.Tags.Contains(IgnoredTag))
{ {
continue; continue;
} }

View File

@@ -12,9 +12,10 @@ public abstract class SharedChameleonClothingSystem : EntitySystem
{ {
[Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
[Dependency] private readonly ClothingSystem _clothingSystem = default!; [Dependency] private readonly ClothingSystem _clothingSystem = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
[Dependency] private readonly TagSystem _tag = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -81,7 +82,7 @@ public abstract class SharedChameleonClothingSystem : EntitySystem
return false; return false;
// check if it is marked as valid chameleon target // 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; return false;
// check if it's valid clothing // check if it's valid clothing

View File

@@ -12,13 +12,12 @@ namespace Content.Shared.Construction.Conditions
public bool Condition(EntityUid user, EntityCoordinates location, Direction direction) public bool Condition(EntityUid user, EntityCoordinates location, Direction direction)
{ {
var entManager = IoCManager.Resolve<IEntityManager>(); var entManager = IoCManager.Resolve<IEntityManager>();
var tagQuery = entManager.GetEntityQuery<TagComponent>();
var sysMan = entManager.EntitySysManager; var sysMan = entManager.EntitySysManager;
var tagSystem = sysMan.GetEntitySystem<TagSystem>(); var tagSystem = sysMan.GetEntitySystem<TagSystem>();
foreach (var entity in location.GetEntitiesInTile(LookupFlags.Static)) foreach (var entity in location.GetEntitiesInTile(LookupFlags.Static))
{ {
if (tagSystem.HasTag(entity, "Window", tagQuery)) if (tagSystem.HasTag(entity, "Window"))
return false; return false;
} }

View File

@@ -15,6 +15,7 @@ using Robust.Shared.Map;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Components;
using Content.Shared.Tag; using Content.Shared.Tag;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem;
@@ -32,16 +33,14 @@ public sealed partial class AnchorableSystem : EntitySystem
[Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!;
private EntityQuery<PhysicsComponent> _physicsQuery; private EntityQuery<PhysicsComponent> _physicsQuery;
private EntityQuery<TagComponent> _tagQuery;
public const string Unstackable = "Unstackable"; public readonly ProtoId<TagPrototype> Unstackable = "Unstackable";
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_physicsQuery = GetEntityQuery<PhysicsComponent>(); _physicsQuery = GetEntityQuery<PhysicsComponent>();
_tagQuery = GetEntityQuery<TagComponent>();
SubscribeLocalEvent<AnchorableComponent, InteractUsingEvent>(OnInteractUsing, SubscribeLocalEvent<AnchorableComponent, InteractUsingEvent>(OnInteractUsing,
before: new[] { typeof(ItemSlotsSystem) }, after: new[] { typeof(SharedConstructionSystem) }); before: new[] { typeof(ItemSlotsSystem) }, after: new[] { typeof(SharedConstructionSystem) });
@@ -312,7 +311,7 @@ public sealed partial class AnchorableSystem : EntitySystem
DebugTools.Assert(!Transform(uid).Anchored); DebugTools.Assert(!Transform(uid).Anchored);
// If we are unstackable, iterate through any other entities anchored on the current square // 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) public bool AnyUnstackablesAnchoredAt(EntityCoordinates location)
@@ -327,11 +326,9 @@ public sealed partial class AnchorableSystem : EntitySystem
while (enumerator.MoveNext(out var entity)) while (enumerator.MoveNext(out var entity))
{ {
// If we find another unstackable here, return true. // If we find another unstackable here, return true.
if (_tagSystem.HasTag(entity.Value, Unstackable, _tagQuery)) if (_tagSystem.HasTag(entity.Value, Unstackable))
{
return true; return true;
} }
}
return false; return false;
} }

View File

@@ -1,14 +1,15 @@
using Content.Shared.Tag; using Content.Shared.Tag;
using Robust.Shared.Prototypes;
namespace Content.Shared.Construction.Steps namespace Content.Shared.Construction.Steps
{ {
public sealed partial class MultipleTagsConstructionGraphStep : ArbitraryInsertConstructionGraphStep public sealed partial class MultipleTagsConstructionGraphStep : ArbitraryInsertConstructionGraphStep
{ {
[DataField("allTags")] [DataField("allTags")]
private List<string>? _allTags; private List<ProtoId<TagPrototype>>? _allTags;
[DataField("anyTags")] [DataField("anyTags")]
private List<string>? _anyTags; private List<ProtoId<TagPrototype>>? _anyTags;
private static bool IsNullOrEmpty<T>(ICollection<T>? list) private static bool IsNullOrEmpty<T>(ICollection<T>? list)
{ {
@@ -21,16 +22,12 @@ namespace Content.Shared.Construction.Steps
if (IsNullOrEmpty(_allTags) && IsNullOrEmpty(_anyTags)) if (IsNullOrEmpty(_allTags) && IsNullOrEmpty(_anyTags))
return false; // Step is somehow invalid, we return. 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>(); 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. 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. return false; // We don't have any of the tags needed.
// This entity is valid! // This entity is valid!

View File

@@ -3,6 +3,7 @@ using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Content.Shared.Tag; using Content.Shared.Tag;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -24,7 +25,7 @@ public abstract class SharedNavMapSystem : EntitySystem
[Robust.Shared.IoC.Dependency] private readonly TagSystem _tagSystem = default!; [Robust.Shared.IoC.Dependency] private readonly TagSystem _tagSystem = default!;
private readonly string[] _wallTags = ["Wall", "Window"]; private static readonly ProtoId<TagPrototype>[] WallTags = {"Wall", "Window"};
private EntityQuery<NavMapDoorComponent> _doorQuery; private EntityQuery<NavMapDoorComponent> _doorQuery;
public override void Initialize() public override void Initialize()
@@ -58,7 +59,7 @@ public abstract class SharedNavMapSystem : EntitySystem
if (_doorQuery.HasComp(uid)) if (_doorQuery.HasComp(uid))
return NavMapChunkType.Airlock; return NavMapChunkType.Airlock;
if (_tagSystem.HasAnyTag(uid, _wallTags)) if (_tagSystem.HasAnyTag(uid, WallTags))
return NavMapChunkType.Wall; return NavMapChunkType.Wall;
return NavMapChunkType.Invalid; return NavMapChunkType.Invalid;

View File

@@ -1,13 +1,11 @@
using Robust.Shared.GameStates; 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))] [DataField, ViewVariables, AutoNetworkedField]
public sealed partial class TagComponent : Component public HashSet<ProtoId<TagPrototype>> Tags = new();
{
[DataField("tags", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<TagPrototype>))]
[Access(typeof(TagSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
public HashSet<string> Tags = new();
}
} }

View File

@@ -1,15 +0,0 @@
using Robust.Shared.Serialization;
namespace Content.Shared.Tag
{
[Serializable, NetSerializable]
public sealed class TagComponentState : ComponentState
{
public TagComponentState(string[] tags)
{
Tags = tags;
}
public string[] Tags { get; }
}
}

View File

@@ -1,17 +1,15 @@
using Robust.Shared.Prototypes; 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> [IdDataField, ViewVariables]
/// Prototype representing a tag in YAML. public string ID { get; } = string.Empty;
/// 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!;
}
} }

File diff suppressed because it is too large Load Diff