Skip to content

Commit

Permalink
Merge pull request Simple-Station#7 from FoxxoTrystan/Languages
Browse files Browse the repository at this point in the history
Languages
  • Loading branch information
Eagle-0 authored May 7, 2024
2 parents dbacec0 + 146c32f commit 6e4fe04
Show file tree
Hide file tree
Showing 86 changed files with 3,270 additions and 136 deletions.
1 change: 1 addition & 0 deletions Content.Client/Input/ContentContexts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public static void SetupContexts(IInputContextContainer contexts)
human.AddFunction(ContentKeyFunctions.UseItemInHand);
human.AddFunction(ContentKeyFunctions.AltUseItemInHand);
human.AddFunction(ContentKeyFunctions.OpenCharacterMenu);
human.AddFunction(ContentKeyFunctions.OpenLanguageMenu);
human.AddFunction(ContentKeyFunctions.ActivateItemInWorld);
human.AddFunction(ContentKeyFunctions.ThrowItemInHand);
human.AddFunction(ContentKeyFunctions.AltActivateItemInWorld);
Expand Down
18 changes: 18 additions & 0 deletions Content.Client/Language/LanguageMenuWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc language-menu-window-title}"
SetSize="300 300">
<BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="150">
<PanelContainer Name="CurrentLanguageContainer" Access="Public" StyleClasses="PdaBorderRect">
<Label Name="CurrentLanguageLabel" Access="Public" Text="Current Language:" HorizontalExpand="True"></Label>
</PanelContainer>

<ui:HLine></ui:HLine>

<ScrollContainer HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="False" VScrollEnabled="True" MinHeight="50">
<BoxContainer Name="OptionsList" Access="Public" HorizontalExpand="True" SeparationOverride="2" Orientation="Vertical">
<!-- The rest here is generated programmatically -->
</BoxContainer>
</ScrollContainer>
</BoxContainer>
</DefaultWindow>
121 changes: 121 additions & 0 deletions Content.Client/Language/LanguageMenuWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using Content.Client.Language.Systems;
using Content.Shared.Language;
using Content.Shared.Language.Systems;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Console;
using Robust.Shared.Utility;
using static Content.Shared.Language.Systems.SharedLanguageSystem;

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>();
}

public void UpdateState(string currentLanguage, List<string> 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(string language)
{
var proto = _clientLanguageSystem.GetLanguage(language);
var state = new EntryState { language = language };

var container = new BoxContainer();
container.Orientation = BoxContainer.LayoutOrientation.Vertical;

// Create and add a header with the name and the button to select the language
{
var header = new BoxContainer();
header.Orientation = BoxContainer.LayoutOrientation.Horizontal;

header.Orientation = BoxContainer.LayoutOrientation.Horizontal;
header.HorizontalExpand = true;
header.SeparationOverride = 2;

var name = new Label();
name.Text = proto?.Name ?? "<error>";
name.MinWidth = 50;
name.HorizontalExpand = true;

var button = new Button();
button.Text = "Choose";
button.OnPressed += _ => OnLanguageChosen(language);
state.button = button;

header.AddChild(name);
header.AddChild(button);

container.AddChild(header);
}

// Create and add a collapsible description
{
var body = new CollapsibleBody();
body.HorizontalExpand = true;
body.Margin = new Thickness(4f, 4f);

var description = new RichTextLabel();
description.SetMessage(proto?.Description ?? "<error>");
description.HorizontalExpand = true;

body.AddChild(description);

var collapser = new Collapsible(Loc.GetString("language-menu-description-header"), body);
collapser.Orientation = BoxContainer.LayoutOrientation.Vertical;
collapser.HorizontalExpand = true;

container.AddChild(collapser);
}

// 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(string id)
{
var proto = _clientLanguageSystem.GetLanguage(id);
if (proto != null)
_clientLanguageSystem.RequestSetLanguage(proto);
}

private struct EntryState
{
public string language;
public Button? button;
}
}
67 changes: 67 additions & 0 deletions Content.Client/Language/Systems/LanguageSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Content.Shared.Language;
using Content.Shared.Language.Events;
using Content.Shared.Language.Systems;
using Robust.Shared.Console;

namespace Content.Client.Language.Systems;

/// <summary>
/// Client-side language system.
/// </summary>
/// <remarks>
/// Unlike the server, the client is not aware of other entities' languages; it's only notified about the entity that it posesses.
/// Due to that, this system stores such information in a static manner.
/// </remarks>
public sealed class LanguageSystem : SharedLanguageSystem
{
/// <summary>
/// The current language of the entity currently possessed by the player.
/// </summary>
public string CurrentLanguage { get; private set; } = default!;
/// <summary>
/// The list of languages the currently possessed entity can speak.
/// </summary>
public List<string> SpokenLanguages { get; private set; } = new();
/// <summary>
/// The list of languages the currently possessed entity can understand.
/// </summary>
public List<string> UnderstoodLanguages { get; private set; } = new();

[Dependency] private readonly IConsoleHost _consoleHost = default!;

public override void Initialize()
{
SubscribeNetworkEvent<LanguagesUpdatedMessage>(OnLanguagesUpdated);
}

/// <summary>
/// Sends a network request to the server to update this system's state.
/// The server may ignore the said request if the player is not possessing an entity.
/// </summary>
public void RequestStateUpdate()
{
RaiseNetworkEvent(new RequestLanguagesMessage());
}

public void RequestSetLanguage(LanguagePrototype language)
{
// May cause some minor desync...
if (language.ID == CurrentLanguage)
return;

// (This is dumb. This is very dumb. It should be a message instead.)
// TODO Change this, soonish
_consoleHost.ExecuteCommand("languageselect " + language.ID);

// So to reduce the probability of desync, we replicate the change locally too
if (SpokenLanguages.Contains(language.ID))
CurrentLanguage = language.ID;
}

private void OnLanguagesUpdated(LanguagesUpdatedMessage message)
{
CurrentLanguage = message.CurrentLanguage;
SpokenLanguages = message.Spoken;
UnderstoodLanguages = message.Understood;
}
}
8 changes: 8 additions & 0 deletions Content.Client/Language/Systems/TranslatorImplanterSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Content.Shared.Language.Systems;

namespace Content.Client.Language.Systems;

public sealed class TranslatorImplanterSystem : SharedTranslatorImplanterSystem
{

}
1 change: 1 addition & 0 deletions Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ void AddCheckBox(string checkBoxName, bool currentState, Action<BaseButton.Butto
AddButton(ContentKeyFunctions.OpenCraftingMenu);
AddButton(ContentKeyFunctions.OpenGuidebook);
AddButton(ContentKeyFunctions.OpenInventoryMenu);
AddButton(ContentKeyFunctions.OpenLanguageMenu);
AddButton(ContentKeyFunctions.OpenAHelp);
AddButton(ContentKeyFunctions.OpenActionsMenu);
AddButton(ContentKeyFunctions.OpenEntitySpawnWindow);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Content.Shared.Chat;
using Content.Shared.Input;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;

namespace Content.Client.UserInterface.Systems.Chat.Controls;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using Content.Client.Language;
using Content.Client.Gameplay;
using Content.Client.UserInterface.Controls;
using Content.Shared.Input;
using Content.Shared.Language.Events;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input.Binding;
using Robust.Shared.Utility;
using static Robust.Client.UserInterface.Controls.BaseButton;
using JetBrains.Annotations;

namespace Content.Client.UserInterface.Systems.Language;

[UsedImplicitly]
public sealed class LanguageMenuUIController : UIController, IOnStateEntered<GameplayState>, IOnStateExited<GameplayState>
{
public LanguageMenuWindow? _languageWindow;
private MenuButton? LanguageButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.LanguageButton;

public override void Initialize()
{
SubscribeNetworkEvent((LanguagesUpdatedMessage message, EntitySessionEventArgs args) => _languageWindow?.UpdateState(message.CurrentLanguage, message.Spoken));
}

public void OnStateEntered(GameplayState state)
{
DebugTools.Assert(_languageWindow == null);

_languageWindow = UIManager.CreateWindow<LanguageMenuWindow>();
LayoutContainer.SetAnchorPreset(_languageWindow, LayoutContainer.LayoutPreset.CenterTop);

CommandBinds.Builder.Bind(ContentKeyFunctions.OpenLanguageMenu, InputCmdHandler.FromDelegate(_ => ToggleWindow())).Register<LanguageMenuUIController>();
}

public void OnStateExited(GameplayState state)
{
if (_languageWindow != null)
{
_languageWindow.Dispose();
_languageWindow = null;
}

CommandBinds.Unregister<LanguageMenuUIController>();
}

public void UnloadButton()
{
if (LanguageButton == null)
{
return;
}

LanguageButton.OnPressed -= LanguageButtonPressed;
}

public void LoadButton()
{
if (LanguageButton == null)
{
return;
}

LanguageButton.OnPressed += LanguageButtonPressed;

if (_languageWindow == null)
{
return;
}

_languageWindow.OnClose += DeactivateButton;
_languageWindow.OnOpen += ActivateButton;
}

private void DeactivateButton() => LanguageButton!.Pressed = false;
private void ActivateButton() => LanguageButton!.Pressed = true;

private void LanguageButtonPressed(ButtonEventArgs args)
{
ToggleWindow();
}

private void CloseWindow()
{
_languageWindow?.Close();
}

private void ToggleWindow()
{
if (_languageWindow == null)
return;

if (LanguageButton != null)
{
LanguageButton.SetClickPressed(!_languageWindow.IsOpen);
}

if (_languageWindow.IsOpen)
{
CloseWindow();
}
else
{
_languageWindow.Open();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Content.Client.UserInterface.Systems.MenuBar.Widgets;
using Content.Client.UserInterface.Systems.Sandbox;
using Robust.Client.UserInterface.Controllers;
using Content.Client.UserInterface.Systems.Language;

namespace Content.Client.UserInterface.Systems.MenuBar;

Expand All @@ -22,6 +23,7 @@ public sealed class GameTopMenuBarUIController : UIController
[Dependency] private readonly ActionUIController _action = default!;
[Dependency] private readonly SandboxUIController _sandbox = default!;
[Dependency] private readonly GuidebookUIController _guidebook = default!;
[Dependency] private readonly LanguageMenuUIController _language = default!;

private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull<GameTopMenuBar>();

Expand All @@ -44,6 +46,7 @@ public void UnloadButtons()
_ahelp.UnloadButton();
_action.UnloadButton();
_sandbox.UnloadButton();
_language.UnloadButton();
}

public void LoadButtons()
Expand All @@ -56,5 +59,6 @@ public void LoadButtons()
_ahelp.LoadButton();
_action.LoadButton();
_sandbox.LoadButton();
_language.LoadButton();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@
HorizontalExpand="True"
AppendStyleClass="{x:Static style:StyleBase.ButtonSquare}"
/>
<ui:MenuButton
Name="LanguageButton"
Access="Internal"
Icon="{xe:Tex '/Textures/Interface/language.png'}"
BoundKey = "{x:Static is:ContentKeyFunctions.OpenLanguageMenu}"
ToolTip="Open the Language Menu"
MinSize="42 64"
HorizontalExpand="True"
AppendStyleClass="{x:Static style:StyleBase.ButtonSquare}"
/>
<ui:MenuButton
Name="AdminButton"
Access="Internal"
Expand Down
Loading

0 comments on commit 6e4fe04

Please sign in to comment.