From c3a0ba9dd890a617236082674730cb12669a688b Mon Sep 17 00:00:00 2001
From: Errant <35878406+Errant-4@users.noreply.github.com>
Date: Tue, 30 Apr 2024 17:06:56 +0200
Subject: [PATCH] Size-based entity whitelist (#26798)
* Size based whitelisting
* namespace and misc refactor
* modern datafields, what will they think of next
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
* the future is now
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
* Update TagSystem to work with ProtoId lists
* I guess someone might run into these too, one day
* copypaste moment
* update to sawmill
* Okay, but what if it just worked
---------
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
---
Content.Shared/Tag/TagSystem.cs | 75 ++++++++-
Content.Shared/Whitelist/EntityWhitelist.cs | 172 +++++++++++---------
2 files changed, 167 insertions(+), 80 deletions(-)
diff --git a/Content.Shared/Tag/TagSystem.cs b/Content.Shared/Tag/TagSystem.cs
index 62197dc319..c2ea28d4c3 100644
--- a/Content.Shared/Tag/TagSystem.cs
+++ b/Content.Shared/Tag/TagSystem.cs
@@ -234,6 +234,21 @@ public sealed class TagSystem : EntitySystem
///
/// The entity to check.
/// The tags to check for.
+ /// true if they all exist, false otherwise.
+ ///
+ /// Thrown if one of the ids represents an unregistered .
+ ///
+ public bool HasAllTags(EntityUid entity, List> ids)
+ {
+ return TryComp(entity, out var component) &&
+ HasAllTags(component, ids);
+ }
+
+ ///
+ /// Checks if any of the given tags have been added to an entity.
+ ///
+ /// The entity to check.
+ /// The tags to check for.
/// true if any of them exist, false otherwise.
///
/// Thrown if one of the ids represents an unregistered .
@@ -245,7 +260,7 @@ public sealed class TagSystem : EntitySystem
}
///
- /// Checks if all of the given tags have been added to an entity.
+ /// Checks if any of the given tags have been added to an entity.
///
/// The entity to check.
/// The tag to check for.
@@ -256,7 +271,7 @@ public sealed class TagSystem : EntitySystem
public bool HasAnyTag(EntityUid entity, string id) => HasTag(entity, id);
///
- /// Checks if all of the given tags have been added to an entity.
+ /// Checks if any of the given tags have been added to an entity.
///
/// The entity to check.
/// The tags to check for.
@@ -271,7 +286,22 @@ public sealed class TagSystem : EntitySystem
}
///
- /// Checks if all of the given tags have been added to an entity.
+ /// Checks if any of the given tags have been added to an entity.
+ ///
+ /// The entity to check.
+ /// The tags to check for.
+ /// true if any of them exist, false otherwise.
+ ///
+ /// Thrown if one of the ids represents an unregistered .
+ ///
+ public bool HasAnyTag(EntityUid entity, List> ids)
+ {
+ return TryComp(entity, out var component) &&
+ HasAnyTag(component, ids);
+ }
+
+ ///
+ /// Checks if any of the given tags have been added to an entity.
///
/// The entity to check.
/// The tags to check for.
@@ -478,6 +508,26 @@ public sealed class TagSystem : EntitySystem
return true;
}
+ ///
+ /// Checks if all of the given tags have been added.
+ ///
+ /// The tags to check for.
+ /// true if they all exist, false otherwise.
+ ///
+ /// Thrown if one of the ids represents an unregistered .
+ ///
+ public bool HasAllTags(TagComponent component, List> ids)
+ {
+ var stringIds = new List();
+ foreach (var tag in ids)
+ {
+ stringIds.Add(tag.Id);
+ }
+
+ return HasAllTags(component, stringIds);
+ }
+
+
///
/// Checks if any of the given tags have been added.
///
@@ -548,6 +598,25 @@ public sealed class TagSystem : EntitySystem
return false;
}
+ ///
+ /// Checks if any of the given tags have been added.
+ ///
+ /// The tags to check for.
+ /// true if any of them exist, false otherwise.
+ ///
+ /// Thrown if one of the ids represents an unregistered .
+ ///
+ public bool HasAnyTag(TagComponent comp, List> ids)
+ {
+ var stringIds = new List();
+ foreach (var tag in ids)
+ {
+ stringIds.Add(tag.Id);
+ }
+
+ return HasAnyTag(comp, stringIds);
+ }
+
///
/// Tries to remove a tag if it exists.
///
diff --git a/Content.Shared/Whitelist/EntityWhitelist.cs b/Content.Shared/Whitelist/EntityWhitelist.cs
index b412a09b98..7fa6ce7f82 100644
--- a/Content.Shared/Whitelist/EntityWhitelist.cs
+++ b/Content.Shared/Whitelist/EntityWhitelist.cs
@@ -1,103 +1,121 @@
+using Content.Shared.Item;
using Content.Shared.Tag;
+using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
-namespace Content.Shared.Whitelist
+namespace Content.Shared.Whitelist;
+
+///
+/// Used to determine whether an entity fits a certain whitelist.
+/// Does not whitelist by prototypes, since that is undesirable; you're better off just adding a tag to all
+/// entity prototypes that need to be whitelisted, and checking for that.
+///
+///
+/// whitelist:
+/// tags:
+/// - Cigarette
+/// - FirelockElectronics
+/// components:
+/// - Buckle
+/// - AsteroidRock
+/// sizes:
+/// - Tiny
+/// - Large
+///
+[DataDefinition]
+[Serializable, NetSerializable]
+public sealed partial class EntityWhitelist
{
///
- /// Used to determine whether an entity fits a certain whitelist.
- /// Does not whitelist by prototypes, since that is undesirable; you're better off just adding a tag to all
- /// entity prototypes that need to be whitelisted, and checking for that.
+ /// Component names that are allowed in the whitelist.
///
- ///
- /// whitelist:
- /// tags:
- /// - Cigarette
- /// - FirelockElectronics
- /// components:
- /// - Buckle
- /// - AsteroidRock
- ///
- [DataDefinition]
- [Serializable, NetSerializable]
- public sealed partial class EntityWhitelist
- {
- ///
- /// Component names that are allowed in the whitelist.
- ///
- [DataField("components")] public string[]? Components = null;
- // TODO yaml validation
+ [DataField] public string[]? Components;
+ // TODO yaml validation
- [NonSerialized]
- private List? _registrations = null;
+ ///
+ /// Item sizes that are allowed in the whitelist.
+ ///
+ [DataField]
+ public List>? Sizes;
- ///
- /// Tags that are allowed in the whitelist.
- ///
- [DataField("tags", customTypeSerializer:typeof(PrototypeIdListSerializer))]
- public List? Tags = null;
+ [NonSerialized]
+ private List? _registrations;
- ///
- /// If false, an entity only requires one of these components or tags to pass the whitelist. If true, an
- /// entity requires to have ALL of these components and tags to pass.
- ///
- [DataField("requireAll")]
- public bool RequireAll = false;
+ ///
+ /// Tags that are allowed in the whitelist.
+ ///
+ [DataField]
+ public List>? Tags;
- public void UpdateRegistrations()
- {
- if (Components == null) return;
+ ///
+ /// If false, an entity only requires one of these components or tags to pass the whitelist. If true, an
+ /// entity requires to have ALL of these components and tags to pass.
+ /// The "Sizes" criteria will ignores this, since an item can only have one size.
+ ///
+ [DataField]
+ public bool RequireAll;
- var compfact = IoCManager.Resolve();
- _registrations = new List();
- foreach (var name in Components)
+ public void UpdateRegistrations()
+ {
+
+ if (Components == null)
+ return;
+
+ var compFact = IoCManager.Resolve();
+ _registrations = new List();
+ foreach (var name in Components)
+ {
+ var availability = compFact.GetComponentAvailability(name);
+ if (compFact.TryGetRegistration(name, out var registration)
+ && availability == ComponentAvailability.Available)
{
- var availability = compfact.GetComponentAvailability(name);
- if (compfact.TryGetRegistration(name, out var registration)
- && availability == ComponentAvailability.Available)
- {
- _registrations.Add(registration);
- }
- else if (availability == ComponentAvailability.Unknown)
- {
- Logger.Warning($"Unknown component name {name} passed to EntityWhitelist!");
- }
+ _registrations.Add(registration);
+ }
+ else if (availability == ComponentAvailability.Unknown)
+ {
+ Logger.Warning($"Unknown component name {name} passed to EntityWhitelist!");
}
}
+ }
- ///
- /// Returns whether a given entity fits the whitelist.
- ///
- public bool IsValid(EntityUid uid, IEntityManager? entityManager = null)
- {
- if (Components != null && _registrations == null)
- UpdateRegistrations();
+ ///
+ /// Returns whether a given entity fits the whitelist.
+ ///
+ public bool IsValid(EntityUid uid, IEntityManager? entityManager = null)
+ {
+ if (Components != null && _registrations == null)
+ UpdateRegistrations();
- IoCManager.Resolve(ref entityManager);
- if (_registrations != null)
+ IoCManager.Resolve(ref entityManager);
+ if (_registrations != null)
+ {
+ foreach (var reg in _registrations)
{
- foreach (var reg in _registrations)
+ if (entityManager.HasComponent(uid, reg.Type))
{
- if (entityManager.HasComponent(uid, reg.Type))
- {
- if (!RequireAll)
- return true;
- }
- else if (RequireAll)
- return false;
+ if (!RequireAll)
+ return true;
}
+ else if (RequireAll)
+ return false;
}
+ }
- if (Tags != null && entityManager.TryGetComponent(uid, out TagComponent? tags))
- {
- var tagSystem = entityManager.System();
- return RequireAll ? tagSystem.HasAllTags(tags, Tags) : tagSystem.HasAnyTag(tags, Tags);
- }
-
- if (RequireAll)
+ if (Sizes != null && entityManager.TryGetComponent(uid, out ItemComponent? itemComp))
+ {
+ if (Sizes.Contains(itemComp.Size))
return true;
+ }
- return false;
+ if (Tags != null && entityManager.TryGetComponent(uid, out TagComponent? tags))
+ {
+ var tagSystem = entityManager.System();
+ return RequireAll ? tagSystem.HasAllTags(tags, Tags) : tagSystem.HasAnyTag(tags, Tags);
}
+
+ if (RequireAll)
+ return true;
+
+ return false;
}
}
--
2.52.0