1
0

NameModifierSystem.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. using System.Linq;
  2. using Content.Shared.Inventory;
  3. using Content.Shared.NameModifier.Components;
  4. namespace Content.Shared.NameModifier.EntitySystems;
  5. /// <inheritdoc cref="NameModifierComponent"/>
  6. public sealed class NameModifierSystem : EntitySystem
  7. {
  8. [Dependency] private readonly MetaDataSystem _metaData = default!;
  9. public override void Initialize()
  10. {
  11. base.Initialize();
  12. SubscribeLocalEvent<NameModifierComponent, EntityRenamedEvent>(OnEntityRenamed);
  13. }
  14. private void OnEntityRenamed(Entity<NameModifierComponent> ent, ref EntityRenamedEvent args)
  15. {
  16. SetBaseName(ent, args.NewName);
  17. RefreshNameModifiers((ent.Owner, ent.Comp));
  18. }
  19. private void SetBaseName(Entity<NameModifierComponent> entity, string name)
  20. {
  21. if (name == entity.Comp.BaseName)
  22. return;
  23. // Set the base name to the new name
  24. entity.Comp.BaseName = name;
  25. Dirty(entity);
  26. }
  27. /// <summary>
  28. /// Returns the base name of the entity, without any modifiers applied.
  29. /// If the entity doesn't have a <see cref="NameModifierComponent"/>,
  30. /// this returns the entity's metadata name.
  31. /// </summary>
  32. public string GetBaseName(Entity<NameModifierComponent?> entity)
  33. {
  34. if (Resolve(entity, ref entity.Comp, logMissing: false))
  35. return entity.Comp.BaseName;
  36. return Name(entity);
  37. }
  38. /// <summary>
  39. /// Raises a <see cref="RefreshNameModifiersEvent"/> to gather modifiers and
  40. /// updates the entity's name to its base name with modifiers applied.
  41. /// This will add a <see cref="NameModifierComponent"/> if any modifiers are added.
  42. /// </summary>
  43. /// <remarks>
  44. /// Call this to update the entity's name when adding or removing a modifier.
  45. /// </remarks>
  46. public void RefreshNameModifiers(Entity<NameModifierComponent?> entity)
  47. {
  48. var meta = MetaData(entity);
  49. var baseName = meta.EntityName;
  50. if (Resolve(entity, ref entity.Comp, logMissing: false))
  51. baseName = entity.Comp.BaseName;
  52. // Raise an event to get any modifiers
  53. // If the entity already has the component, use its BaseName, otherwise use the entity's name from metadata
  54. var modifierEvent = new RefreshNameModifiersEvent(baseName);
  55. RaiseLocalEvent(entity, ref modifierEvent);
  56. // Nothing added a modifier, so we can just use the base name
  57. if (modifierEvent.ModifierCount == 0)
  58. {
  59. // If the entity doesn't have the component, we're done
  60. if (entity.Comp == null)
  61. return;
  62. // Restore the base name
  63. _metaData.SetEntityName(entity, entity.Comp.BaseName, meta, raiseEvents: false);
  64. // The component isn't doing anything anymore, so remove it
  65. RemComp<NameModifierComponent>(entity);
  66. return;
  67. }
  68. // We have at least one modifier, so we need to apply it to the entity.
  69. // Get the final name with modifiers applied
  70. var modifiedName = modifierEvent.GetModifiedName();
  71. // Add the component if needed, and initialize it with the base name
  72. if (!EnsureComp<NameModifierComponent>(entity, out var comp))
  73. SetBaseName((entity, comp), meta.EntityName);
  74. // Set the entity's name with modifiers applied
  75. _metaData.SetEntityName(entity, modifiedName, meta, raiseEvents: false);
  76. }
  77. }
  78. /// <summary>
  79. /// Raised on an entity when <see cref="NameModifierSystem.RefreshNameModifiers"/> is called.
  80. /// Subscribe to this event and use its methods to add modifiers to the entity's name.
  81. /// </summary>
  82. [ByRefEvent]
  83. public sealed class RefreshNameModifiersEvent : IInventoryRelayEvent
  84. {
  85. /// <summary>
  86. /// The entity's name without any modifiers applied.
  87. /// If you want to base a modifier on the entity's name, use
  88. /// this so you don't include other modifiers.
  89. /// </summary>
  90. public readonly string BaseName;
  91. private readonly List<(LocId LocId, int Priority, (string, object)[] ExtraArgs)> _modifiers = [];
  92. /// <inheritdoc/>
  93. public SlotFlags TargetSlots => ~SlotFlags.POCKET;
  94. /// <summary>
  95. /// How many modifiers have been added to this event.
  96. /// </summary>
  97. public int ModifierCount => _modifiers.Count;
  98. public RefreshNameModifiersEvent(string baseName)
  99. {
  100. BaseName = baseName;
  101. }
  102. /// <summary>
  103. /// Adds a modifier to the entity's name.
  104. /// The original name will be passed to Fluent as <c>$baseName</c> along with any <paramref name="extraArgs"/>.
  105. /// Modifiers with a higher <paramref name="priority"/> will be applied later.
  106. /// </summary>
  107. public void AddModifier(LocId locId, int priority = 0, params (string, object)[] extraArgs)
  108. {
  109. _modifiers.Add((locId, priority, extraArgs));
  110. }
  111. /// <summary>
  112. /// Returns the final name with all modifiers applied.
  113. /// </summary>
  114. public string GetModifiedName()
  115. {
  116. // Start out with the entity's name name
  117. var name = BaseName;
  118. // Iterate through all the modifiers in priority order
  119. foreach (var modifier in _modifiers.OrderBy(n => n.Priority))
  120. {
  121. // Grab any extra args needed by the Loc string
  122. var args = modifier.ExtraArgs;
  123. // Add the current version of the entity name as an arg
  124. Array.Resize(ref args, args.Length + 1);
  125. args[^1] = ("baseName", name);
  126. // Resolve the Loc string and use the result as the base in the next iteration.
  127. name = Loc.GetString(modifier.LocId, args);
  128. }
  129. return name;
  130. }
  131. }