mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 21:48:58 +03:00
# 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>  </p> </details> --> # Changelog No cl --------- Co-authored-by: VMSolidus <evilexecutive@gmail.com>
157 lines
5.8 KiB
C#
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);
|
|
}
|
|
}
|