Make RandomMetadata properly support localization (#36343)

* Make _outputSegments readonly

* Remove mystery character

* Use Fluent instead of string concatenation

* Adjust format

* Convert existing content

* Don't need these anymore

* Docs
This commit is contained in:
Tayrtahn
2025-04-06 14:12:39 -04:00
committed by GitHub
parent e88371b23b
commit 8d8c1e4dae
17 changed files with 83 additions and 54 deletions

View File

@@ -1,7 +1,7 @@
using Content.Shared.Dataset; using Content.Shared.Dataset;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Server.RandomMetadata; namespace Content.Server.RandomMetadata;
/// <summary> /// <summary>
/// Randomizes the description and/or the name for an entity by creating it from list of dataset prototypes or strings. /// Randomizes the description and/or the name for an entity by creating it from list of dataset prototypes or strings.
@@ -15,9 +15,17 @@ public sealed partial class RandomMetadataComponent : Component
[DataField] [DataField]
public List<ProtoId<LocalizedDatasetPrototype>>? NameSegments; public List<ProtoId<LocalizedDatasetPrototype>>? NameSegments;
/// <summary>
/// LocId of the formatting string to use to assemble the <see cref="NameSegments"/> into the entity's name.
/// Segments will be passed to the localization system with this string as variables named $part0, $part1, $part2, etc.
/// </summary>
[DataField] [DataField]
public string NameSeparator = " "; public LocId NameFormat = "random-metadata-name-format-default";
/// <summary>
/// LocId of the formatting string to use to assemble the <see cref="DescriptionSegments"/> into the entity's description.
/// Segments will be passed to the localization system with this string as variables named $part0, $part1, $part2, etc.
/// </summary>
[DataField] [DataField]
public string DescriptionSeparator = " "; public LocId DescriptionFormat = "random-metadata-description-format-default";
} }

View File

@@ -12,7 +12,7 @@ public sealed class RandomMetadataSystem : EntitySystem
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly MetaDataSystem _metaData = default!;
private List<string> _outputSegments = new(); private readonly List<(string, object)> _outputSegments = new();
public override void Initialize() public override void Initialize()
{ {
@@ -28,13 +28,13 @@ public sealed class RandomMetadataSystem : EntitySystem
if (component.NameSegments != null) if (component.NameSegments != null)
{ {
_metaData.SetEntityName(uid, GetRandomFromSegments(component.NameSegments, component.NameSeparator), meta); _metaData.SetEntityName(uid, GetRandomFromSegments(component.NameSegments, component.NameFormat), meta);
} }
if (component.DescriptionSegments != null) if (component.DescriptionSegments != null)
{ {
_metaData.SetEntityDescription(uid, _metaData.SetEntityDescription(uid,
GetRandomFromSegments(component.DescriptionSegments, component.DescriptionSeparator), meta); GetRandomFromSegments(component.DescriptionSegments, component.DescriptionFormat), meta);
} }
} }
@@ -42,17 +42,18 @@ public sealed class RandomMetadataSystem : EntitySystem
/// Generates a random string from segments and a separator. /// Generates a random string from segments and a separator.
/// </summary> /// </summary>
/// <param name="segments">The segments that it will be generated from</param> /// <param name="segments">The segments that it will be generated from</param>
/// <param name="separator">The separator that will be inbetween each segment</param> /// <param name="format">The format string used to combine the segments.</param>
/// <returns>The newly generated string</returns> /// <returns>The newly generated string</returns>
[PublicAPI] [PublicAPI]
public string GetRandomFromSegments(List<ProtoId<LocalizedDatasetPrototype>> segments, string? separator) public string GetRandomFromSegments(List<ProtoId<LocalizedDatasetPrototype>> segments, LocId format)
{ {
_outputSegments.Clear(); _outputSegments.Clear();
foreach (var segment in segments) for (var i = 0; i < segments.Count; ++i)
{ {
var localizedProto = _prototype.Index(segment); var localizedProto = _prototype.Index(segments[i]);
_outputSegments.Add(_random.Pick(localizedProto)); _outputSegments.Add(($"part{i}", _random.Pick(localizedProto)));
} }
return string.Join(separator, _outputSegments);
return Loc.GetString(format, _outputSegments.ToArray());
} }
} }

View File

@@ -1,2 +0,0 @@
names-word-the-1 = The
names-word-of-1 = of

View File

@@ -1,3 +0,0 @@
names-nukie-commander-1 = Commander
names-nukie-agent-1 = Agent
names-nukie-operator-1 = Operator

View File

@@ -0,0 +1,23 @@
random-metadata-name-format-default = {$part0}
random-metadata-description-format-default = {$part0}
# Used for standard humanoid names - "<firstName> <lastName>"
name-format-standard = {$part0} {$part1}
name-format-regal-rat = {$part0} {$part1}
name-format-revenant = The {$part0} of {$part1} {$part2}
name-format-ninja = {$part0} {$part1}
name-format-wizard = {$part0} {$part1}
# "<title> <name>"
name-format-nukie-generic = {$part0} {$part1}
name-format-nukie-agent = Agent {$part0}
name-format-nukie-commander = Commander {$part0}
name-format-nukie-operator = Operator {$part0}
# "<title> <name>"
name-format-ert = {$part0} {$part1}
# "<appearance> <type>"
name-format-book = {$part0} {$part1}
name-format-nuclear-operation = {$part0} {$part1}

View File

@@ -1,14 +0,0 @@
# These can be inserted inbetween name datasets
# Ideally it would be localized since just swapping words doesnt help much for a lot of languages
- type: localizedDataset
id: WordThe
values:
prefix: names-word-the-
count: 1
- type: localizedDataset
id: WordOf
values:
prefix: names-word-of-
count: 1

View File

@@ -1,17 +0,0 @@
- type: localizedDataset
id: NamesNukieFirstCommander
values:
prefix: names-nukie-commander-
count: 1
- type: localizedDataset
id: NamesNukieFirstAgent
values:
prefix: names-nukie-agent-
count: 1
- type: localizedDataset
id: NamesNukieFirstOperator
values:
prefix: names-nukie-operator-
count: 1

View File

@@ -117,6 +117,7 @@
nameSegments: nameSegments:
- NamesRegalratKingdom - NamesRegalratKingdom
- NamesRegalratTitle - NamesRegalratTitle
nameFormat: name-format-regal-rat
- type: GuideHelp - type: GuideHelp
guides: guides:
- MinorAntagonists - MinorAntagonists

View File

@@ -72,11 +72,10 @@
- StolenEssence - StolenEssence
- type: RandomMetadata - type: RandomMetadata
nameSegments: nameSegments:
- WordThe
- NamesRevenantType - NamesRevenantType
- WordOf
- NamesRevenantAdjective - NamesRevenantAdjective
- NamesRevenantTheme - NamesRevenantTheme
nameFormat: name-format-revenant
- type: Speech - type: Speech
speechVerb: Ghost speechVerb: Ghost
- type: Reactive - type: Reactive

View File

@@ -577,6 +577,7 @@
nameSegments: nameSegments:
- NamesFirst - NamesFirst
- NamesLast - NamesLast
nameFormat: name-format-standard
- type: randomHumanoidSettings - type: randomHumanoidSettings
id: ChallengeVictimChiefEngineer id: ChallengeVictimChiefEngineer
@@ -596,6 +597,7 @@
nameSegments: nameSegments:
- NamesFirst - NamesFirst
- NamesLast - NamesLast
nameFormat: name-format-standard
- type: randomHumanoidSettings - type: randomHumanoidSettings
id: ChallengeVictimCMO id: ChallengeVictimCMO
@@ -615,6 +617,7 @@
nameSegments: nameSegments:
- NamesFirst - NamesFirst
- NamesLast - NamesLast
nameFormat: name-format-standard
- type: randomHumanoidSettings - type: randomHumanoidSettings
id: ChallengeVictimHeadOfPersonnel id: ChallengeVictimHeadOfPersonnel
@@ -634,6 +637,7 @@
nameSegments: nameSegments:
- NamesFirst - NamesFirst
- NamesLast - NamesLast
nameFormat: name-format-standard
- type: randomHumanoidSettings - type: randomHumanoidSettings
id: ChallengeVictimHeadOfSecurity id: ChallengeVictimHeadOfSecurity
@@ -653,6 +657,7 @@
nameSegments: nameSegments:
- NamesFirst - NamesFirst
- NamesLast - NamesLast
nameFormat: name-format-standard
- type: randomHumanoidSettings - type: randomHumanoidSettings
id: ChallengeVictimResearchDirector id: ChallengeVictimResearchDirector
@@ -672,6 +677,7 @@
nameSegments: nameSegments:
- NamesFirst - NamesFirst
- NamesLast - NamesLast
nameFormat: name-format-standard
- type: randomHumanoidSettings - type: randomHumanoidSettings
id: ChallengeVictimQuartermaster id: ChallengeVictimQuartermaster
@@ -691,6 +697,7 @@
nameSegments: nameSegments:
- NamesFirst - NamesFirst
- NamesLast - NamesLast
nameFormat: name-format-standard
# Security # Security
# Following use EventHumanoidMindShielded since they are heads and probably should have mindshields # Following use EventHumanoidMindShielded since they are heads and probably should have mindshields
@@ -715,6 +722,7 @@
nameSegments: nameSegments:
- NamesFirst - NamesFirst
- NamesLast - NamesLast
nameFormat: name-format-standard
# Engineering # Engineering

View File

@@ -68,8 +68,8 @@
- type: NukeOperative - type: NukeOperative
- type: RandomMetadata - type: RandomMetadata
nameSegments: nameSegments:
- NamesNukieFirstOperator
- NamesSyndicateNormal - NamesSyndicateNormal
nameFormat: name-format-nukie-operator
- type: Loadout - type: Loadout
prototypes: [SyndicateOperativeGearFullNoUplink] prototypes: [SyndicateOperativeGearFullNoUplink]
@@ -99,6 +99,7 @@
nameSegments: nameSegments:
- NamesSyndicatePrefix - NamesSyndicatePrefix
- NamesSyndicateNormal - NamesSyndicateNormal
nameFormat: name-format-nukie-generic
- type: NpcFactionMember - type: NpcFactionMember
factions: factions:
- Syndicate - Syndicate

View File

@@ -36,6 +36,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirstLeader - NamesMilitaryFirstLeader
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: RandomHumanoidSpawner - type: RandomHumanoidSpawner
settings: DeathSquad settings: DeathSquad
@@ -59,6 +60,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirstLeader - NamesMilitaryFirstLeader
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
## ERT Leader ## ERT Leader
@@ -75,6 +77,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirstLeader - NamesMilitaryFirstLeader
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: RandomHumanoidSpawner - type: RandomHumanoidSpawner
settings: ERTLeader settings: ERTLeader
@@ -97,6 +100,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirstLeader - NamesMilitaryFirstLeader
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: entity - type: entity
id: RandomHumanoidSpawnerERTLeaderEVA id: RandomHumanoidSpawnerERTLeaderEVA
@@ -163,6 +167,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: RandomHumanoidSpawner - type: RandomHumanoidSpawner
settings: ERTChaplain settings: ERTChaplain
@@ -182,6 +187,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: Loadout - type: Loadout
prototypes: [ ERTChaplainGear ] prototypes: [ ERTChaplainGear ]
roleLoadout: [ RoleSurvivalExtended ] roleLoadout: [ RoleSurvivalExtended ]
@@ -229,6 +235,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: RandomHumanoidSpawner - type: RandomHumanoidSpawner
settings: ERTJanitor settings: ERTJanitor
@@ -247,6 +254,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: Loadout - type: Loadout
prototypes: [ ERTJanitorGear ] prototypes: [ ERTJanitorGear ]
roleLoadout: [ RoleSurvivalExtended ] roleLoadout: [ RoleSurvivalExtended ]
@@ -293,6 +301,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: RandomHumanoidSpawner - type: RandomHumanoidSpawner
settings: ERTEngineer settings: ERTEngineer
@@ -311,6 +320,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: Loadout - type: Loadout
prototypes: [ ERTEngineerGear ] prototypes: [ ERTEngineerGear ]
roleLoadout: [ RoleSurvivalExtended ] roleLoadout: [ RoleSurvivalExtended ]
@@ -357,6 +367,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: RandomHumanoidSpawner - type: RandomHumanoidSpawner
settings: ERTSecurity settings: ERTSecurity
@@ -375,6 +386,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: Loadout - type: Loadout
prototypes: [ ERTSecurityGear ] prototypes: [ ERTSecurityGear ]
roleLoadout: [ RoleSurvivalExtended ] roleLoadout: [ RoleSurvivalExtended ]
@@ -444,6 +456,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: RandomHumanoidSpawner - type: RandomHumanoidSpawner
settings: ERTMedical settings: ERTMedical
@@ -462,6 +475,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
- type: Loadout - type: Loadout
prototypes: [ ERTMedicalGear ] prototypes: [ ERTMedicalGear ]
roleLoadout: [ RoleSurvivalExtended ] roleLoadout: [ RoleSurvivalExtended ]
@@ -523,6 +537,7 @@
nameSegments: nameSegments:
- NamesMilitaryFirst - NamesMilitaryFirst
- NamesMilitaryLast - NamesMilitaryLast
nameFormat: name-format-ert
## Central Command ## Central Command
@@ -604,6 +619,7 @@
nameSegments: nameSegments:
- NamesFirst - NamesFirst
- NamesLast - NamesLast
nameFormat: name-format-standard
- type: randomHumanoidSettings - type: randomHumanoidSettings
id: Cluwne id: Cluwne

View File

@@ -356,6 +356,7 @@
nameSegments: nameSegments:
- BookHintAppearances - BookHintAppearances
- BookTypes - BookTypes
nameFormat: name-format-book
- type: RandomSprite - type: RandomSprite
available: available:
- cover: - cover:

View File

@@ -33,6 +33,7 @@
nameSegments: nameSegments:
- NamesSyndicatePrefix - NamesSyndicatePrefix
- NamesSyndicateNormal - NamesSyndicateNormal
nameFormat: name-format-nukie-generic
- type: Damageable - type: Damageable
damageContainer: Inorganic damageContainer: Inorganic
- type: ToggleableLightVisuals - type: ToggleableLightVisuals

View File

@@ -230,6 +230,7 @@
nameSegments: nameSegments:
- NamesNinjaTitle - NamesNinjaTitle
- NamesNinja - NamesNinja
nameFormat: name-format-ninja
mindRoles: mindRoles:
- MindRoleNinja - MindRoleNinja
@@ -316,6 +317,7 @@
nameSegments: nameSegments:
- NamesWizardFirst - NamesWizardFirst
- NamesWizardLast - NamesWizardLast
nameFormat: name-format-wizard
mindRoles: mindRoles:
- MindRoleWizard - MindRoleWizard
@@ -548,6 +550,7 @@
nameSegments: nameSegments:
- NamesSyndicatePrefix - NamesSyndicatePrefix
- NamesSyndicateNormal - NamesSyndicateNormal
nameFormat: name-format-nukie-generic
- type: NpcFactionMember - type: NpcFactionMember
factions: factions:
- Syndicate - Syndicate

View File

@@ -97,6 +97,7 @@
nameSegments: nameSegments:
- NamesOperationPrefix - NamesOperationPrefix
- NamesOperationSuffix - NamesOperationSuffix
nameFormat: name-format-nuclear-operation
- type: NukeopsRule - type: NukeopsRule
- type: RuleGrids - type: RuleGrids
- type: AntagSelection - type: AntagSelection
@@ -129,8 +130,8 @@
- type: NukeOperative - type: NukeOperative
- type: RandomMetadata - type: RandomMetadata
nameSegments: nameSegments:
- NamesNukieFirstCommander
- NamesSyndicateElite - NamesSyndicateElite
nameFormat: name-format-nukie-commander
- type: NpcFactionMember - type: NpcFactionMember
factions: factions:
- Syndicate - Syndicate
@@ -146,8 +147,8 @@
- type: NukeOperative - type: NukeOperative
- type: RandomMetadata - type: RandomMetadata
nameSegments: nameSegments:
- NamesNukieFirstAgent
- NamesSyndicateNormal - NamesSyndicateNormal
nameFormat: name-format-nukie-agent
- type: NpcFactionMember - type: NpcFactionMember
factions: factions:
- Syndicate - Syndicate
@@ -165,8 +166,8 @@
- type: NukeOperative - type: NukeOperative
- type: RandomMetadata - type: RandomMetadata
nameSegments: nameSegments:
- NamesNukieFirstOperator
- NamesSyndicateNormal - NamesSyndicateNormal
nameFormat: name-format-nukie-operator
- type: NpcFactionMember - type: NpcFactionMember
factions: factions:
- Syndicate - Syndicate
@@ -307,6 +308,7 @@
nameSegments: nameSegments:
- NamesWizardFirst - NamesWizardFirst
- NamesWizardLast - NamesWizardLast
nameFormat: name-format-wizard
mindRoles: mindRoles:
- MindRoleWizard - MindRoleWizard

View File

@@ -62,5 +62,6 @@
nameSegments: nameSegments:
- NamesWizardFirst - NamesWizardFirst
- NamesWizardLast - NamesWizardLast
nameFormat: name-format-wizard
mindRoles: mindRoles:
- MindRoleWizard - MindRoleWizard