Files
wwdpublic/Content.Client/Language/LanguageMenuWindow.xaml.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

146 lines
4.4 KiB
C#

using Content.Client.Language.Systems;
using Content.Shared.Language;
using Content.Shared.Language.Components;
using Content.Shared.Language.Events;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Language;
[GenerateTypedNameReferences]
public sealed partial class LanguageMenuWindow : DefaultWindow
{
private readonly LanguageSystem _clientLanguageSystem;
private readonly List<EntryState> _entries = new();
public LanguageMenuWindow()
{
RobustXamlLoader.Load(this);
_clientLanguageSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<LanguageSystem>();
_clientLanguageSystem.OnLanguagesChanged += UpdateState;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_clientLanguageSystem.OnLanguagesChanged -= UpdateState;
}
protected override void Opened()
{
UpdateState();
}
private void UpdateState()
{
var languageSpeaker = _clientLanguageSystem.GetLocalSpeaker();
if (languageSpeaker == null)
return;
UpdateState(languageSpeaker.CurrentLanguage, languageSpeaker.SpokenLanguages);
}
public void UpdateState(ProtoId<LanguagePrototype> currentLanguage, List<ProtoId<LanguagePrototype>> spokenLanguages)
{
var langName = Loc.GetString($"language-{currentLanguage}-name");
CurrentLanguageLabel.Text = Loc.GetString("language-menu-current-language", ("language", langName));
OptionsList.RemoveAllChildren();
_entries.Clear();
foreach (var language in spokenLanguages)
{
AddLanguageEntry(language);
}
// Disable the button for the currently chosen language
foreach (var entry in _entries)
{
if (entry.Button != null)
entry.Button.Disabled = entry.Language == currentLanguage;
}
}
private void AddLanguageEntry(ProtoId<LanguagePrototype> language)
{
var proto = _clientLanguageSystem.GetLanguagePrototype(language);
var state = new EntryState { Language = language };
var container = new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Vertical };
#region Header
var header = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
SeparationOverride = 2
};
var name = new Label
{
Text = proto?.Name ?? Loc.GetString("generic-error"),
MinWidth = 50,
HorizontalExpand = true
};
var button = new Button { Text = "Choose" };
button.OnPressed += _ => OnLanguageChosen(language);
state.Button = button;
header.AddChild(name);
header.AddChild(button);
container.AddChild(header);
#endregion
#region Collapsible description
var body = new CollapsibleBody
{
HorizontalExpand = true,
Margin = new Thickness(4f, 4f)
};
var description = new RichTextLabel { HorizontalExpand = true };
description.SetMessage(proto?.Description ?? Loc.GetString("generic-error"));
body.AddChild(description);
var collapser = new Collapsible(Loc.GetString("language-menu-description-header"), body)
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
HorizontalExpand = true
};
container.AddChild(collapser);
#endregion
// Before adding, wrap the new container in a PanelContainer to give it a distinct look
var wrapper = new PanelContainer();
wrapper.StyleClasses.Add("PdaBorderRect");
wrapper.AddChild(container);
OptionsList.AddChild(wrapper);
_entries.Add(state);
}
private void OnLanguageChosen(ProtoId<LanguagePrototype> id)
{
_clientLanguageSystem.RequestSetLanguage(id);
// Predict the change
if (_clientLanguageSystem.GetLocalSpeaker()?.SpokenLanguages is {} languages)
UpdateState(id, languages);
}
private struct EntryState
{
public ProtoId<LanguagePrototype> Language;
public Button? Button;
}
}