Files
wwdpublic/Content.Server/Language/Commands/AdminTranslatorCommand.cs
Mnemotechnican 82cbea2aef Language Refactor 3 (#937)
# Description
This significantly improves the quality of the language system by fixing
the mistakes I've made almost a year ago while developing it.

Mainly, this throws away the old half-broken way of networking in favor
of the component state system provided by RT. Language speaker comp is
now shared with SendOnlyToOwner = true, and its state is handled
manually.

In addition to that, this brings the following changes:
- UniversalLanguageSpeaker and LanguageKnowledge are now server-side
- DetermineLanguagesEvent and LanguagesUpdateEvent are now shared (so
that future systems can be built in shared, if needed)
- Everything now uses the ProtoId<LanguagePrototype> type instead of raw
strings (god, I hated those so much)
- The server-side language system now accepts Entity<T?> arguments
instead of EntityUid + T
- UniversalLanguageSpeaker is now based on DetermineEntityLanguagesEvent
and gets an Enabled field, which allows to turn it off. This may have
some use in the future.
- Some minor cleanup

<!--
TODO MEDIA

<details><summary><h1>Media</h1></summary>
<p>

![Example Media Embed](https://example.com/thisimageisntreal.png)

</p>
</details>

-->

# Changelog
No cl

---------

Co-authored-by: VMSolidus <evilexecutive@gmail.com>
2024-10-19 13:41:35 +07:00

157 lines
5.8 KiB
C#

using System.Diagnostics.CodeAnalysis;
using Content.Server.Administration;
using Content.Shared.Administration;
using Content.Shared.Language;
using Content.Shared.Language.Components;
using Content.Shared.Language.Components.Translators;
using Content.Shared.Language.Systems;
using Robust.Server.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Toolshed;
using Robust.Shared.Toolshed.Syntax;
using Robust.Shared.Toolshed.TypeParsers;
namespace Content.Server.Language.Commands;
[ToolshedCommand(Name = "translator"), AdminCommand(AdminFlags.Admin)]
public sealed class AdminTranslatorCommand : ToolshedCommand
{
private LanguageSystem? _languagesField;
private ContainerSystem? _containersField;
private ContainerSystem Containers => _containersField ??= GetSys<ContainerSystem>();
private LanguageSystem Languages => _languagesField ??= GetSys<LanguageSystem>();
[CommandImplementation("addlang")]
public EntityUid AddLanguage(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<string, Prototype<LanguagePrototype>> @ref,
[CommandArgument] bool addSpeak = true,
[CommandArgument] bool addUnderstand = true
)
{
var language = @ref.Evaluate(ctx)!;
// noob trap - needs a universallanguagespeakercomponent
if (language == SharedLanguageSystem.UniversalPrototype)
throw new ArgumentException(Loc.GetString("command-language-error-this-will-not-work"));
if (!TryGetTranslatorComp(input, out var translator))
throw new ArgumentException(Loc.GetString("command-language-error-not-a-translator", ("entity", input)));
if (addSpeak && !translator.SpokenLanguages.Contains(language))
translator.SpokenLanguages.Add(language);
if (addUnderstand && !translator.UnderstoodLanguages.Contains(language))
translator.UnderstoodLanguages.Add(language);
UpdateTranslatorHolder(input);
return input;
}
[CommandImplementation("rmlang")]
public EntityUid RemoveLanguage(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<string, Prototype<LanguagePrototype>> @ref,
[CommandArgument] bool removeSpeak = true,
[CommandArgument] bool removeUnderstand = true
)
{
var language = @ref.Evaluate(ctx)!;
if (!TryGetTranslatorComp(input, out var translator))
throw new ArgumentException(Loc.GetString("command-language-error-not-a-translator", ("entity", input)));
if (removeSpeak)
translator.SpokenLanguages.Remove(language);
if (removeUnderstand)
translator.UnderstoodLanguages.Remove(language);
UpdateTranslatorHolder(input);
return input;
}
[CommandImplementation("addrequired")]
public EntityUid AddRequiredLanguage(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<string, Prototype<LanguagePrototype>> @ref)
{
var language = @ref.Evaluate(ctx)!;
if (!TryGetTranslatorComp(input, out var translator))
throw new ArgumentException(Loc.GetString("command-language-error-not-a-translator", ("entity", input)));
if (!translator.RequiredLanguages.Contains(language))
{
translator.RequiredLanguages.Add(language);
UpdateTranslatorHolder(input);
}
return input;
}
[CommandImplementation("rmrequired")]
public EntityUid RemoveRequiredLanguage(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<string, Prototype<LanguagePrototype>> @ref)
{
var language = @ref.Evaluate(ctx)!;
if (!TryGetTranslatorComp(input, out var translator))
throw new ArgumentException(Loc.GetString("command-language-error-not-a-translator", ("entity", input)));
if (translator.RequiredLanguages.Remove(language))
UpdateTranslatorHolder(input);
return input;
}
[CommandImplementation("lsspoken")]
public IEnumerable<ProtoId<LanguagePrototype>> ListSpoken([PipedArgument] EntityUid input)
{
if (!TryGetTranslatorComp(input, out var translator))
return [];
return translator.SpokenLanguages;
}
[CommandImplementation("lsunderstood")]
public IEnumerable<ProtoId<LanguagePrototype>> ListUnderstood([PipedArgument] EntityUid input)
{
if (!TryGetTranslatorComp(input, out var translator))
return [];
return translator.UnderstoodLanguages;
}
[CommandImplementation("lsrequired")]
public IEnumerable<ProtoId<LanguagePrototype>> ListRequired([PipedArgument] EntityUid input)
{
if (!TryGetTranslatorComp(input, out var translator))
return [];
return translator.RequiredLanguages;
}
private bool TryGetTranslatorComp(EntityUid uid, [NotNullWhen(true)] out BaseTranslatorComponent? translator)
{
if (TryComp<HandheldTranslatorComponent>(uid, out var handheld))
translator = handheld;
else if (TryComp<TranslatorImplantComponent>(uid, out var implant))
translator = implant;
else if (TryComp<IntrinsicTranslatorComponent>(uid, out var intrinsic))
translator = intrinsic;
else
translator = null;
return translator != null;
}
private void UpdateTranslatorHolder(EntityUid translator)
{
if (!Containers.TryGetContainingContainer(translator, out var cont)
|| cont.Owner is not { Valid: true } holder)
return;
Languages.UpdateEntityLanguages(holder);
}
}