Unique name identifiers (#6697)

This commit is contained in:
mirrorcult
2022-02-14 19:41:08 -07:00
committed by GitHub
parent 26e0abb460
commit 6bb32ce725
7 changed files with 170 additions and 0 deletions

View File

@@ -19,6 +19,7 @@ namespace Content.Client.Entry
"WarpPoint", "WarpPoint",
"EmitSoundOnUse", "EmitSoundOnUse",
"EmitSoundOnLand", "EmitSoundOnLand",
"NameIdentifier",
"EmitSoundOnActivate", "EmitSoundOnActivate",
"FootstepModifier", "FootstepModifier",
"HeatResistance", "HeatResistance",

View File

@@ -0,0 +1,11 @@
using Content.Shared.NameIdentifier;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.NameIdentifier;
[RegisterComponent]
public sealed class NameIdentifierComponent : Component
{
[DataField("group", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<NameIdentifierGroupPrototype>))]
public string Group = string.Empty;
}

View File

@@ -0,0 +1,118 @@
using System.Linq;
using Content.Shared.GameTicking;
using Content.Shared.NameIdentifier;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.NameIdentifier;
/// <summary>
/// Handles unique name identifiers for entities e.g. `monkey (MK-912)`
/// </summary>
public sealed class NameIdentifierSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[ViewVariables]
public Dictionary<NameIdentifierGroupPrototype, HashSet<int>> CurrentIds = new();
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<NameIdentifierComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<RoundRestartCleanupEvent>(CleanupIds);
InitialSetupPrototypes();
_prototypeManager.PrototypesReloaded += OnReloadPrototypes;
}
public override void Shutdown()
{
base.Shutdown();
_prototypeManager.PrototypesReloaded -= OnReloadPrototypes;
}
/// <summary>
/// Generates a new unique name/suffix for a given entity and adds it to <see cref="CurrentIds"/>
/// but does not set the entity's name.
/// </summary>
public string GenerateUniqueName(EntityUid uid, NameIdentifierGroupPrototype proto)
{
var entityName = Name(uid);
if (!CurrentIds.TryGetValue(proto, out var set))
return entityName;
if (set.Count == (proto.MaxValue - proto.MinValue) + 1)
{
// Oh jeez. We're outta numbers.
return entityName;
}
// This is kind of inefficient with very large amounts of entities but its better than any other method
// I could come up with.
var randomVal = _robustRandom.Next(proto.MinValue, proto.MaxValue);
while (set.Contains(randomVal))
{
randomVal = _robustRandom.Next(proto.MinValue, proto.MaxValue);
}
set.Add(randomVal);
return proto.Prefix is not null
? $"{proto.Prefix}-{randomVal}"
: $"{randomVal}";
}
private void OnComponentInit(EntityUid uid, NameIdentifierComponent component, ComponentInit args)
{
if (!_prototypeManager.TryIndex<NameIdentifierGroupPrototype>(component.Group, out var group))
return;
// Generate a new name.
var meta = MetaData(uid);
var uniqueName = GenerateUniqueName(uid, group);
// "DR-1234" as opposed to "drone (DR-1234)"
meta.EntityName = group.FullName
? uniqueName
: $"{meta.EntityName} ({uniqueName})";
}
private void InitialSetupPrototypes()
{
foreach (var proto in _prototypeManager.EnumeratePrototypes<NameIdentifierGroupPrototype>())
{
CurrentIds.Add(proto, new());
}
}
private void OnReloadPrototypes(PrototypesReloadedEventArgs ev)
{
if (!ev.ByType.TryGetValue(typeof(NameIdentifierGroupPrototype), out var set))
return;
foreach (var (_, proto) in set.Modified)
{
if (proto is not NameIdentifierGroupPrototype group)
continue;
// Only bother adding new ones.
if (CurrentIds.ContainsKey(group))
continue;
CurrentIds.Add(group, new());
}
}
private void CleanupIds(RoundRestartCleanupEvent ev)
{
foreach (var (_, set) in CurrentIds)
{
set.Clear();
}
}
}

View File

@@ -0,0 +1,25 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.NameIdentifier;
[Prototype("nameIdentifierGroup")]
public sealed class NameIdentifierGroupPrototype : IPrototype
{
[DataField("id", required: true)]
public string ID { get; } = default!;
/// <summary>
/// Should the identifier become the full name, or just append?
/// </summary>
[DataField("fullName")]
public bool FullName = false;
[DataField("prefix")]
public string? Prefix;
[DataField("maxValue")]
public int MaxValue = 999;
[DataField("minValue")]
public int MinValue = 0;
}

View File

@@ -551,6 +551,8 @@
parent: SimpleMobBase parent: SimpleMobBase
description: New church of neo-darwinists actually believe that EVERY animal evolved from a monkey. Tastes like pork, and killing them is both fun and relaxing. description: New church of neo-darwinists actually believe that EVERY animal evolved from a monkey. Tastes like pork, and killing them is both fun and relaxing.
components: components:
- type: NameIdentifier
group: Monkey
- type: GhostTakeoverAvailable - type: GhostTakeoverAvailable
makeSentient: true makeSentient: true
name: monkey name: monkey

View File

@@ -63,6 +63,8 @@
- id: PowerDrill - id: PowerDrill
- id: JawsOfLife - id: JawsOfLife
- id: WelderExperimental - id: WelderExperimental
- type: NameIdentifier
group: Drone
- type: GhostTakeoverAvailable - type: GhostTakeoverAvailable
makeSentient: true makeSentient: true
name: Maintenance Drone name: Maintenance Drone

View File

@@ -0,0 +1,11 @@
# Non-fungible apes, anyone?
- type: nameIdentifierGroup
id: Monkey
prefix: MK
- type: nameIdentifierGroup
id: Drone
prefix: DR
fullName: true
minValue: 10000
maxValue: 99999