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

View File

@@ -53,11 +53,13 @@ namespace Content.IntegrationTests.Tests.Tag
EntityUid sTagDummy = default;
TagComponent sTagComponent = null!;
Entity<TagComponent> sTagEntity = default;
await server.WaitPost(() =>
{
sTagDummy = sEntityManager.SpawnEntity(TagEntityId, MapCoordinates.Nullspace);
sTagComponent = sEntityManager.GetComponent<TagComponent>(sTagDummy);
sTagEntity = new Entity<TagComponent>(sTagDummy, sTagComponent);
});
await server.WaitAssertion(() =>
@@ -130,49 +132,64 @@ namespace Content.IntegrationTests.Tests.Tag
Assert.Multiple(() =>
{
// Cannot add the starting tag again
Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, 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.AddTag(sTagEntity, 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
Assert.That(tagSystem.HasTag(sTagComponent, 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, 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
Assert.That(tagSystem.HasTag(sTagComponent, 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, 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
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
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
Assert.That(tagSystem.RemoveTag(sTagDummy, sTagComponent, 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.RemoveTag(sTagEntity, 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
Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, AddedTag), Is.True);
Assert.That(tagSystem.AddTag(sTagEntity, AddedTag), Is.True);
Assert.Multiple(() =>
{
// 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
Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, StartingTag, AddedTag), Is.False);
Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, new List<string> { StartingTag, AddedTag }), Is.False);
Assert.That(tagSystem.AddTags(sTagEntity, 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
Assert.That(sTagComponent.Tags, Has.Count.EqualTo(2));
@@ -180,65 +197,103 @@ namespace Content.IntegrationTests.Tests.Tag
// Has both tags
Assert.That(tagSystem.HasTag(sTagComponent, StartingTag), Is.True);
Assert.That(tagSystem.HasTag(sTagComponent, AddedTag), 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, new List<string> { 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>> { StartingTag, AddedTag }), 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, 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(() =>
{
// 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
Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, AddedTag, AddedTag), Is.True);
Assert.That(tagSystem.RemoveTags(sTagEntity, AddedTag, AddedTag), Is.True);
});
Assert.Multiple(() =>
{
// 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
Assert.That(sTagComponent.Tags, Is.Empty);
});
#if !DEBUG
return;
// It is run only in DEBUG build,
// 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
// 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();
}

View File

@@ -1,6 +1,7 @@
using System.Linq;
using Content.Shared.Administration;
using Content.Shared.Tag;
using Robust.Shared.Prototypes;
using Robust.Shared.Toolshed;
using Robust.Shared.Toolshed.Syntax;
using Robust.Shared.Toolshed.TypeParsers;
@@ -13,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>>();
});
}
@@ -72,7 +73,7 @@ public sealed class TagCommand : ToolshedCommand
)
{
_tag ??= GetSys<TagSystem>();
_tag.AddTags(input, @ref.Evaluate(ctx)!);
_tag.AddTags(input, (IEnumerable<ProtoId<TagPrototype>>)@ref.Evaluate(ctx)!);
return input;
}
@@ -92,7 +93,7 @@ public sealed class TagCommand : ToolshedCommand
)
{
_tag ??= GetSys<TagSystem>();
_tag.RemoveTags(input, @ref.Evaluate(ctx)!);
_tag.RemoveTags(input, (IEnumerable<ProtoId<TagPrototype>>)@ref.Evaluate(ctx)!);
return input;
}

View File

@@ -14,6 +14,7 @@ namespace Content.Server.Mech.Systems;
public sealed class MechAssemblySystem : EntitySystem
{
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly TagSystem _tag = default!;
/// <inheritdoc/>
public override void Initialize()
@@ -44,7 +45,7 @@ public sealed class MechAssemblySystem : EntitySystem
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);

View File

@@ -13,6 +13,7 @@ using Robust.Shared.Collections;
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;
@@ -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;
}

View File

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

View File

@@ -10,6 +10,7 @@ using Content.Shared.GameTicking;
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;
@@ -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!;
@@ -199,6 +201,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
_decals,
this,
_lookup,
_tag,
_tile,
_transform,
gen,
@@ -231,6 +234,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
_decals,
this,
_lookup,
_tag,
_tile,
_transform,
gen,

View File

@@ -246,7 +246,7 @@ public sealed partial class RevenantSystem
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();

View File

@@ -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.
@@ -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()
@@ -189,7 +189,6 @@ public sealed class SpreaderSystem : EntitySystem
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.
@@ -212,7 +211,7 @@ public sealed class SpreaderSystem : EntitySystem
// 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;
}
@@ -250,8 +249,7 @@ public sealed class SpreaderSystem : EntitySystem
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;
}

View File

@@ -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()
{
@@ -81,7 +82,7 @@ public abstract class SharedChameleonClothingSystem : EntitySystem
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

View File

@@ -12,13 +12,12 @@ namespace Content.Shared.Construction.Conditions
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;
}

View File

@@ -15,6 +15,7 @@ using Robust.Shared.Map;
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;
@@ -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) });
@@ -312,7 +311,7 @@ public sealed partial class AnchorableSystem : EntitySystem
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)
@@ -327,10 +326,8 @@ public sealed partial class AnchorableSystem : EntitySystem
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;

View File

@@ -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)
{
@@ -21,16 +22,12 @@ namespace Content.Shared.Construction.Steps
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!

View File

@@ -3,6 +3,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using Content.Shared.Tag;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -24,7 +25,7 @@ public abstract class SharedNavMapSystem : EntitySystem
[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;
public override void Initialize()
@@ -58,7 +59,7 @@ public abstract class SharedNavMapSystem : EntitySystem
if (_doorQuery.HasComp(uid))
return NavMapChunkType.Airlock;
if (_tagSystem.HasAnyTag(uid, _wallTags))
if (_tagSystem.HasAnyTag(uid, WallTags))
return NavMapChunkType.Wall;
return NavMapChunkType.Invalid;

View File

@@ -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();
}

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;
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;
}

File diff suppressed because it is too large Load Diff