MainMenu.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using System.Text.RegularExpressions;
  2. using Content.Client.MainMenu.UI;
  3. using Content.Client.UserInterface.Systems.EscapeMenu;
  4. using Robust.Client;
  5. using Robust.Client.ResourceManagement;
  6. using Robust.Client.UserInterface;
  7. using Robust.Client.UserInterface.Controls;
  8. using Robust.Shared;
  9. using Robust.Shared.Configuration;
  10. using Robust.Shared.Network;
  11. using Robust.Shared.Utility;
  12. using UsernameHelpers = Robust.Shared.AuthLib.UsernameHelpers;
  13. namespace Content.Client.MainMenu
  14. {
  15. /// <summary>
  16. /// Main menu screen that is the first screen to be displayed when the game starts.
  17. /// </summary>
  18. // Instantiated dynamically through the StateManager, Dependencies will be resolved.
  19. public sealed class MainScreen : Robust.Client.State.State
  20. {
  21. [Dependency] private readonly IBaseClient _client = default!;
  22. [Dependency] private readonly IClientNetManager _netManager = default!;
  23. [Dependency] private readonly IConfigurationManager _configurationManager = default!;
  24. [Dependency] private readonly IGameController _controllerProxy = default!;
  25. [Dependency] private readonly IResourceCache _resourceCache = default!;
  26. [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
  27. [Dependency] private readonly ILogManager _logManager = default!;
  28. private ISawmill _sawmill = default!;
  29. private MainMenuControl _mainMenuControl = default!;
  30. private bool _isConnecting;
  31. // ReSharper disable once InconsistentNaming
  32. private static readonly Regex IPv6Regex = new(@"\[(.*:.*:.*)](?::(\d+))?");
  33. /// <inheritdoc />
  34. protected override void Startup()
  35. {
  36. _sawmill = _logManager.GetSawmill("mainmenu");
  37. _mainMenuControl = new MainMenuControl(_resourceCache, _configurationManager);
  38. _userInterfaceManager.StateRoot.AddChild(_mainMenuControl);
  39. _mainMenuControl.QuitButton.OnPressed += QuitButtonPressed;
  40. _mainMenuControl.OptionsButton.OnPressed += OptionsButtonPressed;
  41. _mainMenuControl.DirectConnectButton.OnPressed += DirectConnectButtonPressed;
  42. _mainMenuControl.AddressBox.OnTextEntered += AddressBoxEntered;
  43. _mainMenuControl.ChangelogButton.OnPressed += ChangelogButtonPressed;
  44. _client.RunLevelChanged += RunLevelChanged;
  45. }
  46. /// <inheritdoc />
  47. protected override void Shutdown()
  48. {
  49. _client.RunLevelChanged -= RunLevelChanged;
  50. _netManager.ConnectFailed -= _onConnectFailed;
  51. _mainMenuControl.Dispose();
  52. }
  53. private void ChangelogButtonPressed(BaseButton.ButtonEventArgs args)
  54. {
  55. _userInterfaceManager.GetUIController<ChangelogUIController>().ToggleWindow();
  56. }
  57. private void OptionsButtonPressed(BaseButton.ButtonEventArgs args)
  58. {
  59. _userInterfaceManager.GetUIController<OptionsUIController>().ToggleWindow();
  60. }
  61. private void QuitButtonPressed(BaseButton.ButtonEventArgs args)
  62. {
  63. _controllerProxy.Shutdown();
  64. }
  65. private void DirectConnectButtonPressed(BaseButton.ButtonEventArgs args)
  66. {
  67. var input = _mainMenuControl.AddressBox;
  68. TryConnect(input.Text);
  69. }
  70. private void AddressBoxEntered(LineEdit.LineEditEventArgs args)
  71. {
  72. if (_isConnecting)
  73. {
  74. return;
  75. }
  76. TryConnect(args.Text);
  77. }
  78. private void TryConnect(string address)
  79. {
  80. var inputName = _mainMenuControl.UsernameBox.Text.Trim();
  81. if (!UsernameHelpers.IsNameValid(inputName, out var reason))
  82. {
  83. var invalidReason = Loc.GetString(reason.ToText());
  84. _userInterfaceManager.Popup(
  85. Loc.GetString("main-menu-invalid-username-with-reason", ("invalidReason", invalidReason)),
  86. Loc.GetString("main-menu-invalid-username"));
  87. return;
  88. }
  89. var configName = _configurationManager.GetCVar(CVars.PlayerName);
  90. if (_mainMenuControl.UsernameBox.Text != configName)
  91. {
  92. _configurationManager.SetCVar(CVars.PlayerName, inputName);
  93. _configurationManager.SaveToFile();
  94. }
  95. _setConnectingState(true);
  96. _netManager.ConnectFailed += _onConnectFailed;
  97. try
  98. {
  99. ParseAddress(address, out var ip, out var port);
  100. _client.ConnectToServer(ip, port);
  101. }
  102. catch (ArgumentException e)
  103. {
  104. _userInterfaceManager.Popup($"Unable to connect: {e.Message}", "Connection error.");
  105. _sawmill.Warning(e.ToString());
  106. _netManager.ConnectFailed -= _onConnectFailed;
  107. _setConnectingState(false);
  108. }
  109. }
  110. private void RunLevelChanged(object? obj, RunLevelChangedEventArgs args)
  111. {
  112. switch (args.NewLevel)
  113. {
  114. case ClientRunLevel.Connecting:
  115. _setConnectingState(true);
  116. break;
  117. case ClientRunLevel.Initialize:
  118. _setConnectingState(false);
  119. _netManager.ConnectFailed -= _onConnectFailed;
  120. break;
  121. }
  122. }
  123. private void ParseAddress(string address, out string ip, out ushort port)
  124. {
  125. var match6 = IPv6Regex.Match(address);
  126. if (match6 != Match.Empty)
  127. {
  128. ip = match6.Groups[1].Value;
  129. if (!match6.Groups[2].Success)
  130. {
  131. port = _client.DefaultPort;
  132. }
  133. else if (!ushort.TryParse(match6.Groups[2].Value, out port))
  134. {
  135. throw new ArgumentException("Not a valid port.");
  136. }
  137. return;
  138. }
  139. // See if the IP includes a port.
  140. var split = address.Split(':');
  141. ip = address;
  142. port = _client.DefaultPort;
  143. if (split.Length > 2)
  144. {
  145. throw new ArgumentException("Not a valid Address.");
  146. }
  147. // IP:port format.
  148. if (split.Length == 2)
  149. {
  150. ip = split[0];
  151. if (!ushort.TryParse(split[1], out port))
  152. {
  153. throw new ArgumentException("Not a valid port.");
  154. }
  155. }
  156. }
  157. private void _onConnectFailed(object? _, NetConnectFailArgs args)
  158. {
  159. _userInterfaceManager.Popup(Loc.GetString("main-menu-failed-to-connect",("reason", args.Reason)));
  160. _netManager.ConnectFailed -= _onConnectFailed;
  161. _setConnectingState(false);
  162. }
  163. private void _setConnectingState(bool state)
  164. {
  165. _isConnecting = state;
  166. _mainMenuControl.DirectConnectButton.Disabled = state;
  167. }
  168. }
  169. }