Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleans up tag system #28272

Merged
merged 8 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

11 changes: 6 additions & 5 deletions Content.Server/Administration/Toolshed/TagCommand.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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>>();
});
}

Expand Down Expand Up @@ -72,7 +73,7 @@ [CommandArgument] ValueRef<IEnumerable<string>, IEnumerable<string>> @ref
)
{
_tag ??= GetSys<TagSystem>();
_tag.AddTags(input, @ref.Evaluate(ctx)!);
_tag.AddTags(input, (IEnumerable<ProtoId<TagPrototype>>)@ref.Evaluate(ctx)!);
return input;
}

Expand All @@ -92,7 +93,7 @@ [CommandArgument] ValueRef<IEnumerable<string>, IEnumerable<string>> @ref
)
{
_tag ??= GetSys<TagSystem>();
_tag.RemoveTags(input, @ref.Evaluate(ctx)!);
_tag.RemoveTags(input, (IEnumerable<ProtoId<TagPrototype>>)@ref.Evaluate(ctx)!);
return input;
}

Expand Down
3 changes: 2 additions & 1 deletion Content.Server/Mech/Systems/MechAssemblySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -44,7 +45,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 @@ -241,7 +241,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";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for these will ProtoId have a compile time / initialization stage error if you do this or will it just silently have an invalid id

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, electro made a linter pass for static protoid variables

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/// <summary>
/// This attribute should be used on static string or string collection fields to validate that they correspond to
/// valid YAML prototype ids. This attribute is not required for static <see cref="ProtoId{T}"/> and
/// <see cref="EntProtoId"/> fields, as they automatically get validated.
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public sealed class ValidatePrototypeIdAttribute<T> : Attribute where T : IPrototype
{
}


/// <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
5 changes: 3 additions & 2 deletions Content.Shared/Pinpointer/SharedNavMapSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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;
Expand All @@ -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()
Expand Down Expand Up @@ -58,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();
}
Loading
Loading