diff --git a/Content.Client/Chat/ChatBox.cs b/Content.Client/Chat/ChatBox.cs new file mode 100644 index 0000000000..228ccea90b --- /dev/null +++ b/Content.Client/Chat/ChatBox.cs @@ -0,0 +1,157 @@ +using System.Collections.Generic; +using Content.Shared.Chat; +using SS14.Client.Console; +using SS14.Client.Graphics.Drawing; +using SS14.Client.Input; +using SS14.Client.UserInterface; +using SS14.Client.UserInterface.Controls; +using SS14.Shared.Maths; +using SS14.Shared.Utility; + +namespace Content.Client.Chat +{ + public class ChatBox : PanelContainer + { + protected override ResourcePath ScenePath => new ResourcePath("/Scenes/ChatBox/ChatBox.tscn"); + + public delegate void TextSubmitHandler(ChatBox chatBox, string text); + + private const int MaxLinePixelLength = 500; + + private readonly IList _inputHistory = new List(); + + public LineEdit Input { get; private set; } + private OutputPanel contents; + + /// + /// Index while cycling through the input history. -1 means not going through history. + /// + private int _inputIndex = -1; + + /// + /// Message that WAS being input before going through history began. + /// + private string _inputTemp; + + /// + /// Default formatting string for the ClientChatConsole. + /// + public string DefaultChatFormat { get; set; } + + protected override void Initialize() + { + base.Initialize(); + + Input = GetChild("VBoxContainer/Input"); + Input.OnKeyDown += InputKeyDown; + Input.OnTextEntered += Input_OnTextEntered; + GetChild("VBoxContainer/Contents").Dispose(); + + contents = new OutputPanel + { + SizeFlagsVertical = SizeFlags.FillExpand, + }; + GetChild("VBoxContainer").AddChild(contents); + contents.SetPositionInParent(0); + + PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Gray.WithAlpha(0.5f)}; + } + + protected override void MouseDown(GUIMouseButtonEventArgs e) + { + base.MouseDown(e); + + Input.GrabKeyboardFocus(); + } + + private void InputKeyDown(GUIKeyEventArgs e) + { + if (e.Key == Keyboard.Key.Escape) + { + Input.ReleaseKeyboardFocus(); + e.Handle(); + return; + } + + if (e.Key == Keyboard.Key.Up) + { + if (_inputIndex == -1 && _inputHistory.Count != 0) + { + _inputTemp = Input.Text; + _inputIndex++; + } + else if (_inputIndex + 1 < _inputHistory.Count) + { + _inputIndex++; + } + + if (_inputIndex != -1) + { + Input.Text = _inputHistory[_inputIndex]; + } + + e.Handle(); + return; + } + + if (e.Key == Keyboard.Key.Down) + { + if (_inputIndex == 0) + { + Input.Text = _inputTemp; + _inputTemp = ""; + _inputIndex--; + } + else if (_inputIndex != -1) + { + _inputIndex--; + Input.Text = _inputHistory[_inputIndex]; + } + + e.Handle(); + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + TextSubmitted = null; + Input = null; + contents = null; + } + } + + public event TextSubmitHandler TextSubmitted; + + public void AddLine(string message, ChatChannel channel, Color color) + { + if (Disposed) + { + return; + } + + var formatted = new FormattedMessage(3); + formatted.PushColor(color); + formatted.AddText(message); + formatted.Pop(); + contents.AddMessage(formatted); + } + + private void Input_OnTextEntered(LineEdit.LineEditEventArgs args) + { + if (!string.IsNullOrWhiteSpace(args.Text)) + { + TextSubmitted?.Invoke(this, args.Text); + _inputHistory.Insert(0, args.Text); + } + + _inputIndex = -1; + + Input.Clear(); + Input.ReleaseKeyboardFocus(); + } + } +} diff --git a/Content.Client/Chat/ChatManager.cs b/Content.Client/Chat/ChatManager.cs new file mode 100644 index 0000000000..13e42b52e1 --- /dev/null +++ b/Content.Client/Chat/ChatManager.cs @@ -0,0 +1,110 @@ +using System; +using Content.Client.Interfaces.Chat; +using Content.Shared.Chat; +using SS14.Client.Console; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.Interfaces.Network; +using SS14.Shared.IoC; +using SS14.Shared.Log; +using SS14.Shared.Maths; +using SS14.Shared.Utility; + +namespace Content.Client.Chat +{ + internal sealed class ChatManager : IChatManager + { + private const char ConCmdSlash = '/'; + private const char OOCAlias = '['; + private const char MeAlias = '@'; + +#pragma warning disable 649 + [Dependency] private readonly IClientNetManager _netManager; + [Dependency] private readonly IClientConsole _console; + [Dependency] private readonly IEntityManager _entityManager; +#pragma warning restore 649 + + private ChatBox _currentChatBox; + + public void Initialize() + { + _netManager.RegisterNetMessage(MsgChatMessage.NAME, _onChatMessage); + } + + public void SetChatBox(ChatBox chatBox) + { + if (_currentChatBox != null) + { + _currentChatBox.TextSubmitted -= _onChatBoxTextSubmitted; + } + + _currentChatBox = chatBox; + if (_currentChatBox != null) + { + _currentChatBox.TextSubmitted += _onChatBoxTextSubmitted; + } + } + + private void _onChatMessage(MsgChatMessage message) + { + Logger.Debug($"{message.Channel}: {message.Message}"); + + var color = Color.DarkGray; + var messageText = message.Message; + if (!string.IsNullOrEmpty(message.MessageWrap)) + { + messageText = string.Format(message.MessageWrap, messageText); + } + + switch (message.Channel) + { + case ChatChannel.Server: + color = Color.Orange; + break; + case ChatChannel.OOC: + color = Color.LightSkyBlue; + break; + } + + _currentChatBox?.AddLine(messageText, message.Channel, color); + } + + private void _onChatBoxTextSubmitted(ChatBox chatBox, string text) + { + DebugTools.Assert(chatBox == _currentChatBox); + + if (string.IsNullOrWhiteSpace(text)) + return; + + switch (text[0]) + { + case ConCmdSlash: + { + // run locally + var conInput = text.Substring(1); + _console.ProcessCommand(conInput); + break; + } + case OOCAlias: + { + var conInput = text.Substring(1); + _console.ProcessCommand($"ooc \"{conInput}\""); + break; + } + case MeAlias: + { + var conInput = text.Substring(1); + _console.ProcessCommand($"me \"{conInput}\""); + break; + } + default: + { + var conInput = _currentChatBox.DefaultChatFormat != null + ? string.Format(_currentChatBox.DefaultChatFormat, text) + : text; + _console.ProcessCommand(conInput); + break; + } + } + } + } +} diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj index b21bff8ec5..dbf6b9a7fe 100644 --- a/Content.Client/Content.Client.csproj +++ b/Content.Client/Content.Client.csproj @@ -71,6 +71,8 @@ + + @@ -101,6 +103,7 @@ + diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 65bb0164d0..999f4b7915 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -25,9 +25,11 @@ using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.IoC; using SS14.Shared.Prototypes; using System; +using Content.Client.Chat; using Content.Client.GameObjects.Components; using Content.Client.GameObjects.Components.Mobs; using Content.Client.GameObjects.Components.Sound; +using Content.Client.Interfaces.Chat; using Content.Client.UserInterface; using Content.Shared.GameObjects.Components.Markers; using Content.Shared.GameObjects.Components.Mobs; @@ -124,6 +126,7 @@ namespace Content.Client IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); IoCManager.BuildGraph(); IoCManager.Resolve().LoadParallax(); @@ -181,6 +184,7 @@ namespace Content.Client IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().AddOverlay(new ParallaxOverlay()); + IoCManager.Resolve().Initialize(); } public override void Update(AssemblyLoader.UpdateLevel level, float frameTime) diff --git a/Content.Client/GameTicking/ClientGameTicker.cs b/Content.Client/GameTicking/ClientGameTicker.cs index 2bd512374e..63f973dbd3 100644 --- a/Content.Client/GameTicking/ClientGameTicker.cs +++ b/Content.Client/GameTicking/ClientGameTicker.cs @@ -1,13 +1,15 @@ using System; +using Content.Client.Chat; using Content.Client.Interfaces; +using Content.Client.Interfaces.Chat; using Content.Client.UserInterface; using Content.Shared; +using Content.Shared.Input; using SS14.Client; using SS14.Client.Console; using SS14.Client.Interfaces; using SS14.Client.Interfaces.Input; using SS14.Client.Interfaces.UserInterface; -using SS14.Client.UserInterface.CustomControls; using SS14.Shared.Input; using SS14.Shared.Interfaces.Network; using SS14.Shared.IoC; @@ -21,15 +23,16 @@ namespace Content.Client.GameTicking #pragma warning disable 649 [Dependency] private IClientNetManager _netManager; [Dependency] private IUserInterfaceManager _userInterfaceManager; - [Dependency] private IClientChatConsole _chatConsole; [Dependency] private IInputManager _inputManager; [Dependency] private IBaseClient _baseClient; + [Dependency] private IChatManager _chatManager; + [Dependency] private IClientConsole _console; #pragma warning restore 649 [ViewVariables] private bool _areWeReady; [ViewVariables] private bool _initialized; [ViewVariables] private TickerState _tickerState; - [ViewVariables] private Chatbox _gameChat; + [ViewVariables] private ChatBox _gameChat; [ViewVariables] private LobbyGui _lobby; [ViewVariables] private bool _gameStarted; [ViewVariables] private DateTime _startTime; @@ -135,8 +138,6 @@ namespace Content.Client.GameTicking if (_gameChat != null) { - _gameChat.TextSubmitted -= _chatConsole.ParseChatMessage; - _chatConsole.AddString -= _gameChat.AddLine; _gameChat.Dispose(); _gameChat = null; } @@ -146,19 +147,21 @@ namespace Content.Client.GameTicking _lobby = new LobbyGui(); _userInterfaceManager.StateRoot.AddChild(_lobby); - _lobby.Chat.TextSubmitted += _chatConsole.ParseChatMessage; - _chatConsole.AddString += _lobby.Chat.AddLine; + _chatManager.SetChatBox(_lobby.Chat); _lobby.Chat.DefaultChatFormat = "ooc \"{0}\""; _lobby.ServerName.Text = _baseClient.GameInfo.ServerName; - _inputManager.SetInputCommand(EngineKeyFunctions.FocusChat, - InputCmdHandler.FromDelegate(session => { _lobby.Chat.Input.GrabKeyboardFocus(); })); + _inputManager.SetInputCommand(ContentKeyFunctions.FocusChat, + InputCmdHandler.FromDelegate(session => + { + _lobby.Chat.Input.IgnoreNext = true; + _lobby.Chat.Input.GrabKeyboardFocus(); + })); _updateLobbyUi(); - _lobby.ObserveButton.OnPressed += args => { _chatConsole.ProcessCommand("observe"); }; - + _lobby.ObserveButton.OnPressed += args => _console.ProcessCommand("observe"); _lobby.ReadyButton.OnPressed += args => { if (!_gameStarted) @@ -166,7 +169,7 @@ namespace Content.Client.GameTicking return; } - _chatConsole.ProcessCommand("joingame"); + _console.ProcessCommand("joingame"); }; _lobby.ReadyButton.OnToggled += args => @@ -176,10 +179,10 @@ namespace Content.Client.GameTicking return; } - _chatConsole.ProcessCommand($"toggleready {args.Pressed}"); + _console.ProcessCommand($"toggleready {args.Pressed}"); }; - _lobby.LeaveButton.OnPressed += args => _chatConsole.ProcessCommand("disconnect"); + _lobby.LeaveButton.OnPressed += args => _console.ProcessCommand("disconnect"); } private void _joinGame(MsgTickerJoinGame message) @@ -193,19 +196,20 @@ namespace Content.Client.GameTicking if (_lobby != null) { - _lobby.Chat.TextSubmitted -= _chatConsole.ParseChatMessage; - _chatConsole.AddString -= _lobby.Chat.AddLine; _lobby.Dispose(); _lobby = null; } - _inputManager.SetInputCommand(EngineKeyFunctions.FocusChat, - InputCmdHandler.FromDelegate(session => { _gameChat.Input.GrabKeyboardFocus(); })); + _inputManager.SetInputCommand(ContentKeyFunctions.FocusChat, + InputCmdHandler.FromDelegate(session => + { + _lobby.Chat.Input.IgnoreNext = true; + _gameChat.Input.GrabKeyboardFocus(); + })); - _gameChat = new Chatbox(); + _gameChat = new ChatBox(); _userInterfaceManager.StateRoot.AddChild(_gameChat); - _gameChat.TextSubmitted += _chatConsole.ParseChatMessage; - _chatConsole.AddString += _gameChat.AddLine; + _chatManager.SetChatBox(_gameChat); _gameChat.DefaultChatFormat = "say \"{0}\""; } diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 96eb3cb979..1f1afa5d93 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -11,6 +11,9 @@ namespace Content.Client.Input { public static void SetupContexts(IInputContextContainer contexts) { + var common = contexts.GetContext("common"); + common.AddFunction(ContentKeyFunctions.FocusChat); + var human = contexts.GetContext("human"); human.AddFunction(ContentKeyFunctions.SwapHands); human.AddFunction(ContentKeyFunctions.Drop); diff --git a/Content.Client/Interfaces/Chat/IChatManager.cs b/Content.Client/Interfaces/Chat/IChatManager.cs new file mode 100644 index 0000000000..41123d318a --- /dev/null +++ b/Content.Client/Interfaces/Chat/IChatManager.cs @@ -0,0 +1,11 @@ +using Content.Client.Chat; + +namespace Content.Client.Interfaces.Chat +{ + public interface IChatManager + { + void Initialize(); + + void SetChatBox(ChatBox chatBox); + } +} diff --git a/Content.Client/UserInterface/LobbyGui.cs b/Content.Client/UserInterface/LobbyGui.cs index 9fe5413409..2607743321 100644 --- a/Content.Client/UserInterface/LobbyGui.cs +++ b/Content.Client/UserInterface/LobbyGui.cs @@ -1,3 +1,4 @@ +using Content.Client.Chat; using SS14.Client.UserInterface; using SS14.Client.UserInterface.Controls; using SS14.Client.UserInterface.CustomControls; @@ -20,14 +21,14 @@ namespace Content.Client.UserInterface public Button LeaveButton => GetChild