Add a system for modifying entity names without causing conflicts (#27863)
This commit is contained in:
@@ -14,14 +14,6 @@ namespace Content.Server.Chemistry.Components;
|
||||
[RegisterComponent, Access(typeof(TransformableContainerSystem))]
|
||||
public sealed partial class TransformableContainerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the initial metadata name for the container.
|
||||
/// It will revert to this when emptied.
|
||||
/// It defaults to the name of the parent entity unless overwritten.
|
||||
/// </summary>
|
||||
[DataField("initialName")]
|
||||
public string? InitialName;
|
||||
|
||||
/// <summary>
|
||||
/// This is the initial metadata description for the container.
|
||||
/// It will revert to this when emptied.
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Server.Chemistry.Components;
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.EntitySystems;
|
||||
@@ -11,6 +12,7 @@ public sealed class TransformableContainerSystem : EntitySystem
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadataSystem = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -18,15 +20,12 @@ public sealed class TransformableContainerSystem : EntitySystem
|
||||
|
||||
SubscribeLocalEvent<TransformableContainerComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<TransformableContainerComponent, SolutionContainerChangedEvent>(OnSolutionChange);
|
||||
SubscribeLocalEvent<TransformableContainerComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<TransformableContainerComponent> entity, ref MapInitEvent args)
|
||||
private void OnMapInit(Entity<TransformableContainerComponent> entity, ref MapInitEvent args)
|
||||
{
|
||||
var meta = MetaData(entity.Owner);
|
||||
if (string.IsNullOrEmpty(entity.Comp.InitialName))
|
||||
{
|
||||
entity.Comp.InitialName = meta.EntityName;
|
||||
}
|
||||
if (string.IsNullOrEmpty(entity.Comp.InitialDescription))
|
||||
{
|
||||
entity.Comp.InitialDescription = meta.EntityDescription;
|
||||
@@ -58,12 +57,20 @@ public sealed class TransformableContainerSystem : EntitySystem
|
||||
&& _prototypeManager.TryIndex(reagentId.Value.Prototype, out ReagentPrototype? proto))
|
||||
{
|
||||
var metadata = MetaData(entity.Owner);
|
||||
var val = Loc.GetString("transformable-container-component-glass", ("name", proto.LocalizedName));
|
||||
_metadataSystem.SetEntityName(entity.Owner, val, metadata);
|
||||
_metadataSystem.SetEntityDescription(entity.Owner, proto.LocalizedDescription, metadata);
|
||||
entity.Comp.CurrentReagent = proto;
|
||||
entity.Comp.Transformed = true;
|
||||
}
|
||||
|
||||
_nameMod.RefreshNameModifiers(entity.Owner);
|
||||
}
|
||||
|
||||
private void OnRefreshNameModifiers(Entity<TransformableContainerComponent> entity, ref RefreshNameModifiersEvent args)
|
||||
{
|
||||
if (entity.Comp.CurrentReagent is { } currentReagent)
|
||||
{
|
||||
args.AddModifier("transformable-container-component-glass", priority: -1, ("reagent", currentReagent.LocalizedName));
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelTransformation(Entity<TransformableContainerComponent> entity)
|
||||
@@ -73,10 +80,8 @@ public sealed class TransformableContainerSystem : EntitySystem
|
||||
|
||||
var metadata = MetaData(entity);
|
||||
|
||||
if (!string.IsNullOrEmpty(entity.Comp.InitialName))
|
||||
{
|
||||
_metadataSystem.SetEntityName(entity.Owner, entity.Comp.InitialName, metadata);
|
||||
}
|
||||
_nameMod.RefreshNameModifiers(entity.Owner);
|
||||
|
||||
if (!string.IsNullOrEmpty(entity.Comp.InitialDescription))
|
||||
{
|
||||
_metadataSystem.SetEntityDescription(entity.Owner, entity.Comp.InitialDescription, metadata);
|
||||
|
||||
@@ -14,8 +14,8 @@ using Content.Server.Emoting.Systems;
|
||||
using Content.Server.Speech.EntitySystems;
|
||||
using Content.Shared.Cluwne;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
|
||||
namespace Content.Server.Cluwne;
|
||||
|
||||
@@ -30,6 +30,7 @@ public sealed class CluwneSystem : EntitySystem
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly AutoEmoteSystem _autoEmote = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -39,6 +40,7 @@ public sealed class CluwneSystem : EntitySystem
|
||||
SubscribeLocalEvent<CluwneComponent, MobStateChangedEvent>(OnMobState);
|
||||
SubscribeLocalEvent<CluwneComponent, EmoteEvent>(OnEmote, before:
|
||||
new[] { typeof(VocalSystem), typeof(BodyEmotesSystem) });
|
||||
SubscribeLocalEvent<CluwneComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,19 +49,19 @@ public sealed class CluwneSystem : EntitySystem
|
||||
private void OnMobState(EntityUid uid, CluwneComponent component, MobStateChangedEvent args)
|
||||
{
|
||||
if (args.NewMobState == MobState.Dead)
|
||||
{
|
||||
{
|
||||
RemComp<CluwneComponent>(uid);
|
||||
RemComp<ClumsyComponent>(uid);
|
||||
RemComp<AutoEmoteComponent>(uid);
|
||||
var damageSpec = new DamageSpecifier(_prototypeManager.Index<DamageGroupPrototype>("Genetic"), 300);
|
||||
_damageableSystem.TryChangeDamage(uid, damageSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EmoteSoundsPrototype? EmoteSounds;
|
||||
|
||||
/// <summary>
|
||||
/// OnStartup gives the cluwne outfit, ensures clumsy, gives name prefix and makes sure emote sounds are laugh.
|
||||
/// OnStartup gives the cluwne outfit, ensures clumsy, and makes sure emote sounds are laugh.
|
||||
/// </summary>
|
||||
private void OnComponentStartup(EntityUid uid, CluwneComponent component, ComponentStartup args)
|
||||
{
|
||||
@@ -67,9 +69,6 @@ public sealed class CluwneSystem : EntitySystem
|
||||
return;
|
||||
_prototypeManager.TryIndex(component.EmoteSoundsId, out EmoteSounds);
|
||||
|
||||
var meta = MetaData(uid);
|
||||
var name = meta.EntityName;
|
||||
|
||||
EnsureComp<AutoEmoteComponent>(uid);
|
||||
_autoEmote.AddEmote(uid, "CluwneGiggle");
|
||||
EnsureComp<ClumsyComponent>(uid);
|
||||
@@ -77,7 +76,7 @@ public sealed class CluwneSystem : EntitySystem
|
||||
_popupSystem.PopupEntity(Loc.GetString("cluwne-transform", ("target", uid)), uid, PopupType.LargeCaution);
|
||||
_audio.PlayPvs(component.SpawnSound, uid);
|
||||
|
||||
_metaData.SetEntityName(uid, Loc.GetString("cluwne-name-prefix", ("target", name)), meta);
|
||||
_nameMod.RefreshNameModifiers(uid);
|
||||
|
||||
SetOutfitCommand.SetOutfit(uid, "CluwneGear", EntityManager);
|
||||
}
|
||||
@@ -104,4 +103,12 @@ public sealed class CluwneSystem : EntitySystem
|
||||
_chat.TrySendInGameICMessage(uid, "spasms", InGameICChatType.Emote, ChatTransmitRange.Normal);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies "Cluwnified" prefix
|
||||
/// </summary>
|
||||
private void OnRefreshNameModifiers(Entity<CluwneComponent> entity, ref RefreshNameModifiersEvent args)
|
||||
{
|
||||
args.AddModifier("cluwne-name-prefix");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.NameModifier.Components;
|
||||
|
||||
namespace Content.Server.Fax;
|
||||
|
||||
@@ -464,10 +465,11 @@ public sealed class FaxSystem : EntitySystem
|
||||
return;
|
||||
|
||||
TryComp<LabelComponent>(sendEntity, out var labelComponent);
|
||||
TryComp<NameModifierComponent>(sendEntity, out var nameMod);
|
||||
|
||||
// TODO: See comment in 'Send()' about not being able to copy whole entities
|
||||
var printout = new FaxPrintout(paper.Content,
|
||||
labelComponent?.OriginalName ?? metadata.EntityName,
|
||||
nameMod?.BaseName ?? metadata.EntityName,
|
||||
labelComponent?.CurrentLabel,
|
||||
metadata.EntityPrototype?.ID ?? DefaultPaperPrototypeId,
|
||||
paper.StampState,
|
||||
@@ -510,12 +512,14 @@ public sealed class FaxSystem : EntitySystem
|
||||
!TryComp<PaperComponent>(sendEntity, out var paper))
|
||||
return;
|
||||
|
||||
TryComp<NameModifierComponent>(sendEntity, out var nameMod);
|
||||
|
||||
TryComp<LabelComponent>(sendEntity, out var labelComponent);
|
||||
|
||||
var payload = new NetworkPayload()
|
||||
{
|
||||
{ DeviceNetworkConstants.Command, FaxConstants.FaxPrintCommand },
|
||||
{ FaxConstants.FaxPaperNameData, labelComponent?.OriginalName ?? metadata.EntityName },
|
||||
{ FaxConstants.FaxPaperNameData, nameMod?.BaseName ?? metadata.EntityName },
|
||||
{ FaxConstants.FaxPaperLabelData, labelComponent?.CurrentLabel },
|
||||
{ FaxConstants.FaxPaperContentData, paper.Content },
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Shared.Hands;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
@@ -20,9 +21,9 @@ public sealed class GlueSystem : SharedGlueSystem
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly OpenableSystem _openable = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -32,6 +33,7 @@ public sealed class GlueSystem : SharedGlueSystem
|
||||
SubscribeLocalEvent<GluedComponent, ComponentInit>(OnGluedInit);
|
||||
SubscribeLocalEvent<GlueComponent, GetVerbsEvent<UtilityVerb>>(OnUtilityVerb);
|
||||
SubscribeLocalEvent<GluedComponent, GotEquippedHandEvent>(OnHandPickUp);
|
||||
SubscribeLocalEvent<GluedComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
|
||||
}
|
||||
|
||||
// When glue bottle is used on item it will apply the glued and unremoveable components.
|
||||
@@ -95,27 +97,22 @@ public sealed class GlueSystem : SharedGlueSystem
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<GluedComponent, UnremoveableComponent, MetaDataComponent>();
|
||||
while (query.MoveNext(out var uid, out var glue, out var _, out var meta))
|
||||
var query = EntityQueryEnumerator<GluedComponent, UnremoveableComponent>();
|
||||
while (query.MoveNext(out var uid, out var glue, out var _))
|
||||
{
|
||||
if (_timing.CurTime < glue.Until)
|
||||
continue;
|
||||
|
||||
// Instead of string matching, just reconstruct the expected name and compare
|
||||
if (meta.EntityName == Loc.GetString("glued-name-prefix", ("target", glue.BeforeGluedEntityName)))
|
||||
_metaData.SetEntityName(uid, glue.BeforeGluedEntityName);
|
||||
|
||||
RemComp<UnremoveableComponent>(uid);
|
||||
RemComp<GluedComponent>(uid);
|
||||
|
||||
_nameMod.RefreshNameModifiers(uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGluedInit(Entity<GluedComponent> entity, ref ComponentInit args)
|
||||
{
|
||||
var meta = MetaData(entity);
|
||||
var name = meta.EntityName;
|
||||
entity.Comp.BeforeGluedEntityName = meta.EntityName;
|
||||
_metaData.SetEntityName(entity.Owner, Loc.GetString("glued-name-prefix", ("target", name)));
|
||||
_nameMod.RefreshNameModifiers(entity.Owner);
|
||||
}
|
||||
|
||||
private void OnHandPickUp(Entity<GluedComponent> entity, ref GotEquippedHandEvent args)
|
||||
@@ -124,4 +121,9 @@ public sealed class GlueSystem : SharedGlueSystem
|
||||
comp.DeleteOnDrop = false;
|
||||
entity.Comp.Until = _timing.CurTime + entity.Comp.Duration;
|
||||
}
|
||||
|
||||
private void OnRefreshNameModifiers(Entity<GluedComponent> entity, ref RefreshNameModifiersEvent args)
|
||||
{
|
||||
args.AddModifier("glued-name-prefix");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.Examine;
|
||||
using Content.Shared.Labels;
|
||||
using Content.Shared.Labels.Components;
|
||||
using Content.Shared.Labels.EntitySystems;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
@@ -18,7 +19,7 @@ namespace Content.Server.Labels
|
||||
{
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
|
||||
public const string ContainerName = "paper_label";
|
||||
|
||||
@@ -41,6 +42,8 @@ namespace Content.Server.Labels
|
||||
component.CurrentLabel = Loc.GetString(component.CurrentLabel);
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
_nameMod.RefreshNameModifiers(uid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,30 +55,11 @@ namespace Content.Server.Labels
|
||||
/// <param name="metadata">metadata component for resolve</param>
|
||||
public override void Label(EntityUid uid, string? text, MetaDataComponent? metadata = null, LabelComponent? label = null)
|
||||
{
|
||||
if (!Resolve(uid, ref metadata))
|
||||
return;
|
||||
if (!Resolve(uid, ref label, false))
|
||||
label = EnsureComp<LabelComponent>(uid);
|
||||
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
if (label.OriginalName is null)
|
||||
return;
|
||||
|
||||
// Remove label
|
||||
_metaData.SetEntityName(uid, label.OriginalName, metadata);
|
||||
label.CurrentLabel = null;
|
||||
label.OriginalName = null;
|
||||
|
||||
Dirty(uid, label);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Update label
|
||||
label.OriginalName ??= metadata.EntityName;
|
||||
label.CurrentLabel = text;
|
||||
_metaData.SetEntityName(uid, $"{label.OriginalName} ({text})", metadata);
|
||||
_nameMod.RefreshNameModifiers(uid);
|
||||
|
||||
Dirty(uid, label);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Lube;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Throwing;
|
||||
using Robust.Shared.Containers;
|
||||
@@ -9,11 +10,11 @@ namespace Content.Server.Lube;
|
||||
|
||||
public sealed class LubedSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -21,14 +22,12 @@ public sealed class LubedSystem : EntitySystem
|
||||
|
||||
SubscribeLocalEvent<LubedComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<LubedComponent, ContainerGettingInsertedAttemptEvent>(OnHandPickUp);
|
||||
SubscribeLocalEvent<LubedComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, LubedComponent component, ComponentInit args)
|
||||
{
|
||||
var meta = MetaData(uid);
|
||||
var name = meta.EntityName;
|
||||
component.BeforeLubedEntityName = meta.EntityName;
|
||||
_metaData.SetEntityName(uid, Loc.GetString("lubed-name-prefix", ("target", name)));
|
||||
_nameMod.RefreshNameModifiers(uid);
|
||||
}
|
||||
|
||||
private void OnHandPickUp(EntityUid uid, LubedComponent component, ContainerGettingInsertedAttemptEvent args)
|
||||
@@ -36,7 +35,7 @@ public sealed class LubedSystem : EntitySystem
|
||||
if (component.SlipsLeft <= 0)
|
||||
{
|
||||
RemComp<LubedComponent>(uid);
|
||||
_metaData.SetEntityName(uid, component.BeforeLubedEntityName);
|
||||
_nameMod.RefreshNameModifiers(uid);
|
||||
return;
|
||||
}
|
||||
component.SlipsLeft--;
|
||||
@@ -47,4 +46,9 @@ public sealed class LubedSystem : EntitySystem
|
||||
_throwing.TryThrow(uid, _random.NextVector2(), strength: component.SlipStrength);
|
||||
_popup.PopupEntity(Loc.GetString("lube-slip", ("target", Identity.Entity(uid, EntityManager))), user, user, PopupType.MediumCaution);
|
||||
}
|
||||
|
||||
private void OnRefreshNameModifiers(Entity<LubedComponent> entity, ref RefreshNameModifiersEvent args)
|
||||
{
|
||||
args.AddModifier("lubed-name-prefix");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,12 @@ using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.Nutrition.AnimalHusbandry;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Content.Shared.Storage;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
@@ -29,12 +28,12 @@ public sealed class AnimalHusbandrySystem : EntitySystem
|
||||
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
|
||||
private readonly HashSet<EntityUid> _failedAttempts = new();
|
||||
private readonly HashSet<EntityUid> _birthQueue = new();
|
||||
@@ -43,8 +42,7 @@ public sealed class AnimalHusbandrySystem : EntitySystem
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<ReproductiveComponent, MindAddedMessage>(OnMindAdded);
|
||||
SubscribeLocalEvent<InfantComponent, ComponentStartup>(OnInfantStartup);
|
||||
SubscribeLocalEvent<InfantComponent, ComponentShutdown>(OnInfantShutdown);
|
||||
SubscribeLocalEvent<InfantComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
|
||||
}
|
||||
|
||||
// we express EZ-pass terminate the pregnancy if a player takes the role
|
||||
@@ -54,16 +52,11 @@ public sealed class AnimalHusbandrySystem : EntitySystem
|
||||
component.GestationEndTime = null;
|
||||
}
|
||||
|
||||
private void OnInfantStartup(EntityUid uid, InfantComponent component, ComponentStartup args)
|
||||
private void OnRefreshNameModifiers(Entity<InfantComponent> entity, ref RefreshNameModifiersEvent args)
|
||||
{
|
||||
var meta = MetaData(uid);
|
||||
component.OriginalName = meta.EntityName;
|
||||
_metaData.SetEntityName(uid, Loc.GetString("infant-name-prefix", ("name", meta.EntityName)), meta);
|
||||
}
|
||||
|
||||
private void OnInfantShutdown(EntityUid uid, InfantComponent component, ComponentShutdown args)
|
||||
{
|
||||
_metaData.SetEntityName(uid, component.OriginalName);
|
||||
// This check may seem redundant, but it makes sure that the prefix is removed before the component is removed
|
||||
if (_timing.CurTime < entity.Comp.InfantEndTime)
|
||||
args.AddModifier("infant-name-prefix");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -202,6 +195,8 @@ public sealed class AnimalHusbandrySystem : EntitySystem
|
||||
{
|
||||
var infant = AddComp<InfantComponent>(offspring);
|
||||
infant.InfantEndTime = _timing.CurTime + infant.InfantDuration;
|
||||
// Make sure the name prefix is applied
|
||||
_nameMod.RefreshNameModifiers(offspring);
|
||||
}
|
||||
_adminLog.Add(LogType.Action, $"{ToPrettyString(uid)} gave birth to {ToPrettyString(offspring)}.");
|
||||
}
|
||||
@@ -249,6 +244,8 @@ public sealed class AnimalHusbandrySystem : EntitySystem
|
||||
if (_timing.CurTime < infant.InfantEndTime)
|
||||
continue;
|
||||
RemCompDeferred(uid, infant);
|
||||
// Make sure the name prefix gets removed
|
||||
_nameMod.RefreshNameModifiers(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,9 +222,7 @@ namespace Content.Server.Zombies
|
||||
_faction.AddFaction(target, "Zombie");
|
||||
|
||||
//gives it the funny "Zombie ___" name.
|
||||
var meta = MetaData(target);
|
||||
zombiecomp.BeforeZombifiedEntityName = meta.EntityName;
|
||||
_metaData.SetEntityName(target, Loc.GetString("zombie-name-prefix", ("target", meta.EntityName)), meta);
|
||||
_nameMod.RefreshNameModifiers(target);
|
||||
|
||||
_identity.QueueIdentityUpdate(target);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ using Content.Shared.Mind;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
using Content.Shared.Zombies;
|
||||
@@ -34,9 +35,9 @@ namespace Content.Server.Zombies
|
||||
[Dependency] private readonly ActionsSystem _actions = default!;
|
||||
[Dependency] private readonly AutoEmoteSystem _autoEmote = default!;
|
||||
[Dependency] private readonly EmoteOnDamageSystem _emoteOnDamage = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
|
||||
public const SlotFlags ProtectiveSlots =
|
||||
SlotFlags.FEET |
|
||||
@@ -281,7 +282,7 @@ namespace Content.Server.Zombies
|
||||
_humanoidAppearance.SetSkinColor(target, zombiecomp.BeforeZombifiedSkinColor, false);
|
||||
_bloodstream.ChangeBloodReagent(target, zombiecomp.BeforeZombifiedBloodReagent);
|
||||
|
||||
_metaData.SetEntityName(target, zombiecomp.BeforeZombifiedEntityName);
|
||||
_nameMod.RefreshNameModifiers(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,6 @@ namespace Content.Shared.Glue;
|
||||
[Access(typeof(SharedGlueSystem))]
|
||||
public sealed partial class GluedComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Reverts name to before prefix event (essentially removes prefix).
|
||||
/// </summary>
|
||||
[DataField("beforeGluedEntityName"), ViewVariables(VVAccess.ReadOnly)]
|
||||
public string BeforeGluedEntityName = string.Empty;
|
||||
|
||||
[DataField("until", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan Until;
|
||||
|
||||
@@ -7,6 +7,7 @@ using Content.Shared.Gravity;
|
||||
using Content.Shared.IdentityManagement.Components;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.Overlays;
|
||||
using Content.Shared.Radio;
|
||||
using Content.Shared.Slippery;
|
||||
@@ -28,6 +29,7 @@ public partial class InventorySystem
|
||||
SubscribeLocalEvent<InventoryComponent, SeeIdentityAttemptEvent>(RelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, ModifyChangedTemperatureEvent>(RelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, GetDefaultRadioChannelEvent>(RelayInventoryEvent);
|
||||
SubscribeLocalEvent<InventoryComponent, RefreshNameModifiersEvent>(RelayInventoryEvent);
|
||||
|
||||
// by-ref events
|
||||
SubscribeLocalEvent<InventoryComponent, GetExplosionResistanceEvent>(RefRelayInventoryEvent);
|
||||
|
||||
@@ -14,11 +14,4 @@ public sealed partial class LabelComponent : Component
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public string? CurrentLabel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The original name of the entity
|
||||
/// Used for reverting the modified entity name when the label is removed
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public string? OriginalName { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Labels.Components;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Labels.EntitySystems;
|
||||
@@ -11,6 +12,7 @@ public abstract partial class SharedLabelSystem : EntitySystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<LabelComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<LabelComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
|
||||
}
|
||||
|
||||
public virtual void Label(EntityUid uid, string? text, MetaDataComponent? metadata = null, LabelComponent? label = null){}
|
||||
@@ -27,4 +29,10 @@ public abstract partial class SharedLabelSystem : EntitySystem
|
||||
message.AddText(Loc.GetString("hand-labeler-has-label", ("label", label.CurrentLabel)));
|
||||
args.PushMessage(message);
|
||||
}
|
||||
|
||||
private void OnRefreshNameModifiers(Entity<LabelComponent> entity, ref RefreshNameModifiersEvent args)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(entity.Comp.CurrentLabel))
|
||||
args.AddModifier("comp-label-format", extraArgs: ("label", entity.Comp.CurrentLabel));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,6 @@ namespace Content.Shared.Lube;
|
||||
[RegisterComponent]
|
||||
public sealed partial class LubedComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Reverts name to before prefix event (essentially removes prefix).
|
||||
/// </summary>
|
||||
[DataField("beforeLubedEntityName")]
|
||||
public string BeforeLubedEntityName = string.Empty;
|
||||
|
||||
[DataField("slipsLeft"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public int SlipsLeft;
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.NameModifier.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a modifier to the wearer's name when this item is equipped,
|
||||
/// and removes it when it is unequipped.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[AutoGenerateComponentState]
|
||||
public sealed partial class ModifyWearerNameComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The localization ID of the text to be used as the modifier.
|
||||
/// The base name will be passed in as <c>$baseName</c>
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public LocId LocId = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Priority of the modifier. See <see cref="EntitySystems.RefreshNameModifiersEvent"/> for more information.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public int Priority;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.NameModifier.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Used to manage modifiers on an entity's name and handle renaming in a way
|
||||
/// that survives being renamed by multiple systems.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(NameModifierSystem))]
|
||||
public sealed partial class NameModifierComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity's name without any modifiers applied.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public string BaseName = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Content.Shared.Clothing;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.NameModifier.Components;
|
||||
|
||||
namespace Content.Shared.NameModifier.EntitySystems;
|
||||
|
||||
public sealed partial class ModifyWearerNameSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ModifyWearerNameComponent, InventoryRelayedEvent<RefreshNameModifiersEvent>>(OnRefreshNameModifiers);
|
||||
SubscribeLocalEvent<ModifyWearerNameComponent, ClothingGotEquippedEvent>(OnGotEquipped);
|
||||
SubscribeLocalEvent<ModifyWearerNameComponent, ClothingGotUnequippedEvent>(OnGotUnequipped);
|
||||
}
|
||||
|
||||
private void OnGotEquipped(Entity<ModifyWearerNameComponent> entity, ref ClothingGotEquippedEvent args)
|
||||
{
|
||||
_nameMod.RefreshNameModifiers(args.Wearer);
|
||||
}
|
||||
|
||||
private void OnGotUnequipped(Entity<ModifyWearerNameComponent> entity, ref ClothingGotUnequippedEvent args)
|
||||
{
|
||||
_nameMod.RefreshNameModifiers(args.Wearer);
|
||||
}
|
||||
|
||||
private void OnRefreshNameModifiers(Entity<ModifyWearerNameComponent> entity, ref InventoryRelayedEvent<RefreshNameModifiersEvent> args)
|
||||
{
|
||||
args.Args.AddModifier(entity.Comp.LocId, entity.Comp.Priority);
|
||||
}
|
||||
}
|
||||
143
Content.Shared/NameModifier/EntitySystems/NameModifierSystem.cs
Normal file
143
Content.Shared/NameModifier/EntitySystems/NameModifierSystem.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.NameModifier.Components;
|
||||
|
||||
namespace Content.Shared.NameModifier.EntitySystems;
|
||||
|
||||
/// <inheritdoc cref="NameModifierComponent"/>
|
||||
public sealed partial class NameModifierSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<NameModifierComponent, EntityRenamedEvent>(OnEntityRenamed);
|
||||
}
|
||||
|
||||
private void OnEntityRenamed(Entity<NameModifierComponent> entity, ref EntityRenamedEvent args)
|
||||
{
|
||||
SetBaseName((entity, entity.Comp), args.NewName);
|
||||
RefreshNameModifiers((entity, entity.Comp));
|
||||
}
|
||||
|
||||
private void SetBaseName(Entity<NameModifierComponent> entity, string name)
|
||||
{
|
||||
if (name == entity.Comp.BaseName)
|
||||
return;
|
||||
|
||||
// Set the base name to the new name
|
||||
entity.Comp.BaseName = name;
|
||||
Dirty(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises a <see cref="RefreshNameModifiersEvent"/> to gather modifiers and
|
||||
/// updates the entity's name to its base name with modifiers applied.
|
||||
/// This will add a <see cref="NameModifierComponent"/> if any modifiers are added.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Call this to update the entity's name when adding or removing a modifier.
|
||||
/// </remarks>
|
||||
public void RefreshNameModifiers(Entity<NameModifierComponent?> entity)
|
||||
{
|
||||
var meta = MetaData(entity);
|
||||
var baseName = meta.EntityName;
|
||||
if (Resolve(entity, ref entity.Comp, logMissing: false))
|
||||
baseName = entity.Comp.BaseName;
|
||||
|
||||
// Raise an event to get any modifiers
|
||||
// If the entity already has the component, use its BaseName, otherwise use the entity's name from metadata
|
||||
var modifierEvent = new RefreshNameModifiersEvent(baseName);
|
||||
RaiseLocalEvent(entity, ref modifierEvent);
|
||||
|
||||
// Nothing added a modifier, so we can just use the base name
|
||||
if (modifierEvent.ModifierCount == 0)
|
||||
{
|
||||
// If the entity doesn't have the component, we're done
|
||||
if (entity.Comp == null)
|
||||
return;
|
||||
|
||||
// Restore the base name
|
||||
_metaData.SetEntityName(entity, entity.Comp.BaseName, meta, raiseEvents: false);
|
||||
// The component isn't doing anything anymore, so remove it
|
||||
RemComp<NameModifierComponent>(entity);
|
||||
return;
|
||||
}
|
||||
// We have at least one modifier, so we need to apply it to the entity.
|
||||
|
||||
// Get the final name with modifiers applied
|
||||
var modifiedName = modifierEvent.GetModifiedName();
|
||||
|
||||
// Add the component if needed, and initialize it with the base name
|
||||
if (!EnsureComp<NameModifierComponent>(entity, out var comp))
|
||||
SetBaseName((entity, comp), meta.EntityName);
|
||||
|
||||
// Set the entity's name with modifiers applied
|
||||
_metaData.SetEntityName(entity, modifiedName, meta, raiseEvents: false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity when <see cref="NameModifierSystem.RefreshNameModifiers"/> is called.
|
||||
/// Subscribe to this event and use its methods to add modifiers to the entity's name.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class RefreshNameModifiersEvent : IInventoryRelayEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity's name without any modifiers applied.
|
||||
/// If you want to base a modifier on the entity's name, use
|
||||
/// this so you don't include other modifiers.
|
||||
/// </summary>
|
||||
public readonly string BaseName;
|
||||
|
||||
private readonly List<(LocId LocId, int Priority, (string, object)[] ExtraArgs)> _modifiers = [];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SlotFlags TargetSlots => ~SlotFlags.POCKET;
|
||||
|
||||
/// <summary>
|
||||
/// How many modifiers have been added to this event.
|
||||
/// </summary>
|
||||
public int ModifierCount => _modifiers.Count;
|
||||
|
||||
public RefreshNameModifiersEvent(string baseName)
|
||||
{
|
||||
BaseName = baseName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a modifier to the entity's name.
|
||||
/// The original name will be passed to Fluent as <c>$baseName</c> along with any <paramref name="extraArgs"/>.
|
||||
/// Modifiers with a higher <paramref name="priority"/> will be applied later.
|
||||
/// </summary>
|
||||
public void AddModifier(LocId locId, int priority = 0, params (string, object)[] extraArgs)
|
||||
{
|
||||
_modifiers.Add((locId, priority, extraArgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the final name with all modifiers applied.
|
||||
/// </summary>
|
||||
public string GetModifiedName()
|
||||
{
|
||||
// Start out with the entity's name name
|
||||
var name = BaseName;
|
||||
|
||||
// Iterate through all the modifiers in priority order
|
||||
foreach (var modifier in _modifiers.OrderBy(n => n.Priority))
|
||||
{
|
||||
// Grab any extra args needed by the Loc string
|
||||
var args = modifier.ExtraArgs;
|
||||
// Add the current version of the entity name as an arg
|
||||
Array.Resize(ref args, args.Length + 1);
|
||||
args[^1] = ("baseName", name);
|
||||
// Resolve the Loc string and use the result as the base in the next iteration.
|
||||
name = Loc.GetString(modifier.LocId, args);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -35,10 +35,4 @@ public sealed partial class InfantComponent : Component
|
||||
[DataField("infantEndTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
[AutoPausedField]
|
||||
public TimeSpan InfantEndTime;
|
||||
|
||||
/// <summary>
|
||||
/// The entity's name before the "baby" prefix is added.
|
||||
/// </summary>
|
||||
[DataField("originalName")]
|
||||
public string OriginalName = string.Empty;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
|
||||
namespace Content.Shared.Zombies;
|
||||
|
||||
@@ -10,6 +11,7 @@ public abstract class SharedZombieSystem : EntitySystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ZombieComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshSpeed);
|
||||
SubscribeLocalEvent<ZombieComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
|
||||
}
|
||||
|
||||
private void OnRefreshSpeed(EntityUid uid, ZombieComponent component, RefreshMovementSpeedModifiersEvent args)
|
||||
@@ -17,4 +19,9 @@ public abstract class SharedZombieSystem : EntitySystem
|
||||
var mod = component.ZombieMovementSpeedDebuff;
|
||||
args.ModifySpeed(mod, mod);
|
||||
}
|
||||
|
||||
private void OnRefreshNameModifiers(Entity<ZombieComponent> entity, ref RefreshNameModifiersEvent args)
|
||||
{
|
||||
args.AddModifier("zombie-name-prefix");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,12 +62,6 @@ public sealed partial class ZombieComponent : Component
|
||||
[DataField("zombieRoleId", customTypeSerializer: typeof(PrototypeIdSerializer<AntagPrototype>))]
|
||||
public string ZombieRoleId = "Zombie";
|
||||
|
||||
/// <summary>
|
||||
/// The EntityName of the humanoid to restore in case of cloning
|
||||
/// </summary>
|
||||
[DataField("beforeZombifiedEntityName"), ViewVariables(VVAccess.ReadOnly)]
|
||||
public string BeforeZombifiedEntityName = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The CustomBaseLayers of the humanoid to restore in case of cloning
|
||||
/// </summary>
|
||||
|
||||
@@ -1 +1 @@
|
||||
transformable-container-component-glass = {$name} glass
|
||||
transformable-container-component-glass = {$reagent} glass
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
cluwne-transform = {CAPITALIZE(THE($target))} turned into a cluwne!
|
||||
cluwne-name-prefix = Cluwnified {$target}
|
||||
cluwne-name-prefix = cluwnified {$baseName}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
glue-success = {THE($target)} has been covered in glue!
|
||||
glued-name-prefix = Glued {$target}
|
||||
glued-name-prefix = glued {$baseName}
|
||||
glue-failure = Can't cover {THE($target)} in glue!
|
||||
glue-verb-text = Apply Glue
|
||||
glue-verb-message = Glue an object
|
||||
|
||||
1
Resources/Locale/en-US/label/label-component.ftl
Normal file
1
Resources/Locale/en-US/label/label-component.ftl
Normal file
@@ -0,0 +1 @@
|
||||
comp-label-format = {$baseName} ({$label})
|
||||
@@ -1,5 +1,5 @@
|
||||
lube-success = {THE($target)} has been covered in lube!
|
||||
lubed-name-prefix = Lubed {$target}
|
||||
lubed-name-prefix = lubed {$baseName}
|
||||
lube-failure = Can't cover {THE($target)} in lube!
|
||||
lube-slip = {THE($target)} slips out of your hands!
|
||||
lube-verb-text = Apply Lube
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
infant-name-prefix = baby {$name}
|
||||
infant-name-prefix = baby {$baseName}
|
||||
reproductive-birth-popup = {CAPITALIZE(THE($parent))} gave birth!
|
||||
reproductive-laid-egg-popup = {CAPITALIZE(THE($parent))} lays an egg!
|
||||
|
||||
@@ -2,7 +2,7 @@ zombie-transform = {CAPITALIZE(THE($target))} turned into a zombie!
|
||||
zombie-infection-greeting = You have become a zombie. Your goal is to seek out the living and to try to infect them. Work together with the other zombies to overtake the station.
|
||||
|
||||
zombie-generic = zombie
|
||||
zombie-name-prefix = Zombified {$target}
|
||||
zombie-name-prefix = zombified {$baseName}
|
||||
zombie-role-desc = A malevolent creature of the dead.
|
||||
zombie-role-rules = You are an antagonist. Search out the living and bite them in order to infect them and turn them into zombies. Work together with the other zombies to overtake the station.
|
||||
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- type: Label
|
||||
originalName: jug
|
||||
- type: Tag
|
||||
tags:
|
||||
- ChemDispensable
|
||||
|
||||
Reference in New Issue
Block a user