Files
tbd-station-14/Content.Server/NameIdentifier/NameIdentifierSystem.cs
Nemanja 98fa00a21f Borgs (#18136)
* Laws

* positronic brain and PAI rewrite

* MMI

* MMI pt. 2

* borg brain transfer

* Roleban support, Borg job (WIP), the end of mind shenaniganry

* battery drain, item slot cleanup, alerts

* visuals

* fix this pt1

* fix this pt2

* Modules, Lingering Stacks, Better borg flashlight

* Start on UI, fix battery alerts, expand activation/deactivation, low movement speed on no power.

* sprotes

* no zombie borgs

* oh fuck yeah i love a good relay

* charger

* fix the tiniest of sprite issues

* adjustable names

* a functional UI????

* foobar

* more modules

* this shit for some reason

* upstream

* genericize selectable borg modules

* upstream again

* holy fucking shit

* i love christ

* proper construction

* da job

* AA borgs

* and boom more shit

* admin logs

* laws redux

* ok just do this rq

* oh boy that looks like modules

* oh shit research

* testos passo

* so much shit holy fuck

* fuckit we SHIP

* last minute snags

* should've gotten me on a better day
2023-08-12 16:39:58 -05:00

176 lines
5.3 KiB
C#

using Content.Shared.GameTicking;
using Content.Shared.NameIdentifier;
using Robust.Shared.Collections;
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!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
/// <summary>
/// Free IDs available per <see cref="NameIdentifierGroupPrototype"/>.
/// </summary>
[ViewVariables]
public readonly Dictionary<string, List<int>> CurrentIds = new();
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<NameIdentifierComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<NameIdentifierComponent, ComponentShutdown>(OnComponentShutdown);
SubscribeLocalEvent<RoundRestartCleanupEvent>(CleanupIds);
InitialSetupPrototypes();
_prototypeManager.PrototypesReloaded += OnReloadPrototypes;
}
private void OnComponentShutdown(EntityUid uid, NameIdentifierComponent component, ComponentShutdown args)
{
if (CurrentIds.TryGetValue(component.Group, out var ids))
{
// Avoid inserting the value right back at the end or shuffling in place:
// just pick a random spot to put it and then move that one to the end.
var randomIndex = _robustRandom.Next(ids.Count);
var random = ids[randomIndex];
ids[randomIndex] = component.Identifier;
ids.Add(random);
}
}
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, out int randomVal)
{
randomVal = 0;
var entityName = Name(uid);
if (!CurrentIds.TryGetValue(proto.ID, out var set))
return entityName;
if (set.Count == 0)
{
// Oh jeez. We're outta numbers.
return entityName;
}
randomVal = set[^1];
set.RemoveAt(set.Count - 1);
return proto.Prefix is not null
? $"{proto.Prefix}-{randomVal}"
: $"{randomVal}";
}
private void OnMapInit(EntityUid uid, NameIdentifierComponent component, MapInitEvent args)
{
if (!_prototypeManager.TryIndex<NameIdentifierGroupPrototype>(component.Group, out var group))
return;
int id;
string uniqueName;
// If it has an existing valid identifier then use that, otherwise generate a new one.
if (component.Identifier != -1 &&
CurrentIds.TryGetValue(component.Group, out var ids) &&
ids.Remove(component.Identifier))
{
id = component.Identifier;
uniqueName = group.Prefix is not null
? $"{group.Prefix}-{id}"
: $"{id}";
}
else
{
uniqueName = GenerateUniqueName(uid, group, out id);
component.Identifier = id;
}
component.FullIdentifier = group.FullName
? uniqueName
: $"({uniqueName})";
var meta = MetaData(uid);
// "DR-1234" as opposed to "drone (DR-1234)"
_metaData.SetEntityName(uid, group.FullName
? uniqueName
: $"{meta.EntityName} ({uniqueName})", meta);
Dirty(component);
}
private void InitialSetupPrototypes()
{
foreach (var proto in _prototypeManager.EnumeratePrototypes<NameIdentifierGroupPrototype>())
{
AddGroup(proto);
}
}
private void AddGroup(NameIdentifierGroupPrototype proto)
{
var values = new List<int>(proto.MaxValue - proto.MinValue);
for (var i = proto.MinValue; i < proto.MaxValue; i++)
{
values.Add(i);
}
_robustRandom.Shuffle(values);
CurrentIds.Add(proto.ID, values);
}
private void OnReloadPrototypes(PrototypesReloadedEventArgs ev)
{
if (!ev.ByType.TryGetValue(typeof(NameIdentifierGroupPrototype), out var set))
return;
var toRemove = new ValueList<string>();
foreach (var proto in CurrentIds.Keys)
{
if (!_prototypeManager.HasIndex<NameIdentifierGroupPrototype>(proto))
{
toRemove.Add(proto);
}
}
foreach (var proto in toRemove)
{
CurrentIds.Remove(proto);
}
foreach (var proto in set.Modified.Values)
{
// Only bother adding new ones.
if (CurrentIds.ContainsKey(proto.ID))
continue;
AddGroup((NameIdentifierGroupPrototype) proto);
}
}
private void CleanupIds(RoundRestartCleanupEvent ev)
{
foreach (var values in CurrentIds.Values)
{
_robustRandom.Shuffle(values);
}
}
}