Re-organize all projects (#4166)
This commit is contained in:
@@ -1,159 +0,0 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Administration;
|
||||
using Content.Client.Chat;
|
||||
using Content.Client.Construction;
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Voting;
|
||||
using Content.Shared;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.State
|
||||
{
|
||||
public class GameScreen : GameScreenBase, IMainViewportState
|
||||
{
|
||||
public static readonly Vector2i ViewportSize = (EyeManager.PixelsPerMeter * 21, EyeManager.PixelsPerMeter * 15);
|
||||
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IGameHud _gameHud = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
[Dependency] private readonly IVoteManager _voteManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
[Dependency] private readonly IClientAdminManager _adminManager = default!;
|
||||
[Dependency] private readonly IClyde _clyde = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
|
||||
[ViewVariables] private ChatBox? _gameChat;
|
||||
private ConstructionMenuPresenter? _constructionMenu;
|
||||
|
||||
public MainViewport Viewport { get; private set; } = default!;
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
_gameChat = new ChatBox();
|
||||
Viewport = new MainViewport
|
||||
{
|
||||
Viewport =
|
||||
{
|
||||
ViewportSize = ViewportSize
|
||||
}
|
||||
};
|
||||
|
||||
_userInterfaceManager.StateRoot.AddChild(Viewport);
|
||||
LayoutContainer.SetAnchorPreset(Viewport, LayoutContainer.LayoutPreset.Wide);
|
||||
Viewport.SetPositionFirst();
|
||||
|
||||
_userInterfaceManager.StateRoot.AddChild(_gameHud.RootControl);
|
||||
_chatManager.SetChatBox(_gameChat);
|
||||
_voteManager.SetPopupContainer(_gameHud.VoteContainer);
|
||||
_gameChat.DefaultChatFormat = "say \"{0}\"";
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusChat,
|
||||
InputCmdHandler.FromDelegate(_ => FocusChat(_gameChat)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusOOC,
|
||||
InputCmdHandler.FromDelegate(_ => FocusChannel(_gameChat, ChatChannel.OOC)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusLocalChat,
|
||||
InputCmdHandler.FromDelegate(_ => FocusChannel(_gameChat, ChatChannel.Local)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusRadio,
|
||||
InputCmdHandler.FromDelegate(_ => FocusChannel(_gameChat, ChatChannel.Radio)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusAdminChat,
|
||||
InputCmdHandler.FromDelegate(_ => FocusChannel(_gameChat, ChatChannel.AdminChat)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.CycleChatChannelForward,
|
||||
InputCmdHandler.FromDelegate(_ => _gameChat.CycleChatChannel(true)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.CycleChatChannelBackward,
|
||||
InputCmdHandler.FromDelegate(_ => _gameChat.CycleChatChannel(false)));
|
||||
|
||||
SetupPresenters();
|
||||
|
||||
_eyeManager.MainViewport = Viewport.Viewport;
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
DisposePresenters();
|
||||
|
||||
base.Shutdown();
|
||||
|
||||
_gameChat?.Dispose();
|
||||
Viewport.Dispose();
|
||||
_gameHud.RootControl.Orphan();
|
||||
// Clear viewport to some fallback, whatever.
|
||||
_eyeManager.MainViewport = _userInterfaceManager.MainViewport;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All UI Presenters should be constructed in here.
|
||||
/// </summary>
|
||||
private void SetupPresenters()
|
||||
{
|
||||
_constructionMenu = new ConstructionMenuPresenter(_gameHud);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All UI Presenters should be disposed in here.
|
||||
/// </summary>
|
||||
private void DisposePresenters()
|
||||
{
|
||||
_constructionMenu?.Dispose();
|
||||
}
|
||||
|
||||
internal static void FocusChat(ChatBox chat)
|
||||
{
|
||||
if (chat.UserInterfaceManager.KeyboardFocused != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
chat.Input.IgnoreNext = true;
|
||||
chat.Input.GrabKeyboardFocus();
|
||||
}
|
||||
internal static void FocusChannel(ChatBox chat, ChatChannel channel)
|
||||
{
|
||||
if (chat.UserInterfaceManager.KeyboardFocused != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
chat.SelectChannel(channel);
|
||||
chat.Input.IgnoreNext = true;
|
||||
chat.Input.GrabKeyboardFocus();
|
||||
}
|
||||
|
||||
public override void FrameUpdate(FrameEventArgs e)
|
||||
{
|
||||
base.FrameUpdate(e);
|
||||
|
||||
Viewport.Viewport.Eye = _eyeManager.CurrentEye;
|
||||
}
|
||||
|
||||
protected override void OnKeyBindStateChanged(ViewportBoundKeyEventArgs args)
|
||||
{
|
||||
if (args.Viewport == null)
|
||||
base.OnKeyBindStateChanged(new ViewportBoundKeyEventArgs(args.KeyEventArgs, Viewport.Viewport));
|
||||
else
|
||||
base.OnKeyBindStateChanged(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.State;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.State
|
||||
{
|
||||
// OH GOD.
|
||||
// Ok actually it's fine.
|
||||
// Instantiated dynamically through the StateManager, Dependencies will be resolved.
|
||||
public partial class GameScreenBase : Robust.Client.State.State, IEntityEventSubscriber
|
||||
{
|
||||
[Dependency] protected readonly IClientEntityManager EntityManager = default!;
|
||||
[Dependency] protected readonly IInputManager InputManager = default!;
|
||||
[Dependency] protected readonly IPlayerManager PlayerManager = default!;
|
||||
[Dependency] protected readonly IEntitySystemManager EntitySystemManager = default!;
|
||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||
[Dependency] protected readonly IUserInterfaceManager UserInterfaceManager = default!;
|
||||
[Dependency] protected readonly IConfigurationManager ConfigurationManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private IEventBus _eventBus => _entityManager.EventBus;
|
||||
|
||||
private IEntity? _lastHoveredEntity;
|
||||
|
||||
private bool _outlineEnabled = true;
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
InputManager.KeyBindStateChanged += OnKeyBindStateChanged;
|
||||
_eventBus.SubscribeEvent<OutlineToggleMessage>(EventSource.Local, this, HandleOutlineToggle);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
InputManager.KeyBindStateChanged -= OnKeyBindStateChanged;
|
||||
_eventBus.UnsubscribeEvent<OutlineToggleMessage>(EventSource.Local, this);
|
||||
}
|
||||
|
||||
private void HandleOutlineToggle(OutlineToggleMessage message)
|
||||
{
|
||||
_outlineEnabled = message.Enabled;
|
||||
}
|
||||
|
||||
public override void FrameUpdate(FrameEventArgs e)
|
||||
{
|
||||
base.FrameUpdate(e);
|
||||
|
||||
// If there is no local player, there is no session, and therefore nothing to do here.
|
||||
var localPlayer = PlayerManager.LocalPlayer;
|
||||
if (localPlayer == null)
|
||||
return;
|
||||
|
||||
IEntity? entityToClick = null;
|
||||
var renderScale = 1;
|
||||
if (UserInterfaceManager.CurrentlyHovered is IViewportControl vp)
|
||||
{
|
||||
var mousePosWorld = vp.ScreenToMap(InputManager.MouseScreenPosition.Position);
|
||||
entityToClick = GetEntityUnderPosition(mousePosWorld);
|
||||
|
||||
if (vp is ScalingViewport svp)
|
||||
{
|
||||
renderScale = svp.CurrentRenderScale;
|
||||
}
|
||||
}
|
||||
|
||||
var inRange = false;
|
||||
if (localPlayer.ControlledEntity != null && entityToClick != null)
|
||||
{
|
||||
inRange = localPlayer.InRangeUnobstructed(entityToClick, ignoreInsideBlocker: true);
|
||||
}
|
||||
|
||||
InteractionOutlineComponent? outline;
|
||||
if(!_outlineEnabled || !ConfigurationManager.GetCVar(CCVars.OutlineEnabled))
|
||||
{
|
||||
if(entityToClick != null && entityToClick.TryGetComponent(out outline))
|
||||
{
|
||||
outline.OnMouseLeave(); //Prevent outline remains from persisting post command.
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (entityToClick == _lastHoveredEntity)
|
||||
{
|
||||
if (entityToClick != null && entityToClick.TryGetComponent(out outline))
|
||||
{
|
||||
outline.UpdateInRange(inRange, renderScale);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (_lastHoveredEntity != null && !_lastHoveredEntity.Deleted &&
|
||||
_lastHoveredEntity.TryGetComponent(out outline))
|
||||
{
|
||||
outline.OnMouseLeave();
|
||||
}
|
||||
|
||||
_lastHoveredEntity = entityToClick;
|
||||
|
||||
if (_lastHoveredEntity != null && _lastHoveredEntity.TryGetComponent(out outline))
|
||||
{
|
||||
outline.OnMouseEnter(inRange, renderScale);
|
||||
}
|
||||
}
|
||||
|
||||
public IEntity? GetEntityUnderPosition(MapCoordinates coordinates)
|
||||
{
|
||||
var entitiesUnderPosition = GetEntitiesUnderPosition(coordinates);
|
||||
return entitiesUnderPosition.Count > 0 ? entitiesUnderPosition[0] : null;
|
||||
}
|
||||
|
||||
public IList<IEntity> GetEntitiesUnderPosition(EntityCoordinates coordinates)
|
||||
{
|
||||
return GetEntitiesUnderPosition(coordinates.ToMap(EntityManager));
|
||||
}
|
||||
|
||||
public IList<IEntity> GetEntitiesUnderPosition(MapCoordinates coordinates)
|
||||
{
|
||||
// Find all the entities intersecting our click
|
||||
var entities = IoCManager.Resolve<IEntityLookup>().GetEntitiesIntersecting(coordinates.MapId,
|
||||
Box2.CenteredAround(coordinates.Position, (1, 1)));
|
||||
|
||||
// Check the entities against whether or not we can click them
|
||||
var foundEntities = new List<(IEntity clicked, int drawDepth, uint renderOrder)>();
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
if (entity.TryGetComponent<ClickableComponent>(out var component)
|
||||
&& entity.Transform.IsMapTransform
|
||||
&& component.CheckClick(coordinates.Position, out var drawDepthClicked, out var renderOrder))
|
||||
{
|
||||
foundEntities.Add((entity, drawDepthClicked, renderOrder));
|
||||
}
|
||||
}
|
||||
|
||||
if (foundEntities.Count == 0)
|
||||
return new List<IEntity>();
|
||||
|
||||
foundEntities.Sort(new ClickableEntityComparer());
|
||||
// 0 is the top element.
|
||||
foundEntities.Reverse();
|
||||
return foundEntities.Select(a => a.clicked).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all entities intersecting the given position.
|
||||
///
|
||||
/// Static alternative to GetEntitiesUnderPosition to cut out
|
||||
/// some of the boilerplate needed to get state manager and check the current state.
|
||||
/// </summary>
|
||||
/// <param name="stateManager">state manager to use to get the current game screen</param>
|
||||
/// <param name="coordinates">coordinates to check</param>
|
||||
/// <returns>the entities under the position, empty list if none found</returns>
|
||||
public static IList<IEntity> GetEntitiesUnderPosition(IStateManager stateManager, EntityCoordinates coordinates)
|
||||
{
|
||||
if (stateManager.CurrentState is GameScreenBase gameScreenBase)
|
||||
{
|
||||
return gameScreenBase.GetEntitiesUnderPosition(coordinates);
|
||||
}
|
||||
|
||||
return ImmutableList<IEntity>.Empty;
|
||||
}
|
||||
|
||||
internal class ClickableEntityComparer : IComparer<(IEntity clicked, int depth, uint renderOrder)>
|
||||
{
|
||||
public int Compare((IEntity clicked, int depth, uint renderOrder) x,
|
||||
(IEntity clicked, int depth, uint renderOrder) y)
|
||||
{
|
||||
var val = x.depth.CompareTo(y.depth);
|
||||
if (val != 0)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
// Turning this off it can make picking stuff out of lockers and such up a bit annoying.
|
||||
/*
|
||||
val = x.renderOrder.CompareTo(y.renderOrder);
|
||||
if (val != 0)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
*/
|
||||
|
||||
var transX = x.clicked.Transform;
|
||||
var transY = y.clicked.Transform;
|
||||
val = transX.Coordinates.Y.CompareTo(transY.Coordinates.Y);
|
||||
if (val != 0)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
return x.clicked.Uid.CompareTo(y.clicked.Uid);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a state change event from outside the simulation to inside the simulation.
|
||||
/// </summary>
|
||||
/// <param name="args">Event data values for a bound key state change.</param>
|
||||
protected virtual void OnKeyBindStateChanged(ViewportBoundKeyEventArgs args)
|
||||
{
|
||||
// If there is no InputSystem, then there is nothing to forward to, and nothing to do here.
|
||||
if(!EntitySystemManager.TryGetEntitySystem(out InputSystem? inputSys))
|
||||
return;
|
||||
|
||||
var kArgs = args.KeyEventArgs;
|
||||
var func = kArgs.Function;
|
||||
var funcId = InputManager.NetworkBindMap.KeyFunctionID(func);
|
||||
|
||||
EntityCoordinates coordinates = default;
|
||||
EntityUid entityToClick = default;
|
||||
if (args.Viewport is IViewportControl vp)
|
||||
{
|
||||
var mousePosWorld = vp.ScreenToMap(kArgs.PointerLocation.Position);
|
||||
entityToClick = GetEntityUnderPosition(mousePosWorld)?.Uid ?? EntityUid.Invalid;
|
||||
|
||||
coordinates = MapManager.TryFindGridAt(mousePosWorld, out var grid) ? grid.MapToGrid(mousePosWorld) :
|
||||
EntityCoordinates.FromMap(EntityManager, MapManager, mousePosWorld);
|
||||
}
|
||||
|
||||
var message = new FullInputCmdMessage(Timing.CurTick, Timing.TickFraction, funcId, kArgs.State,
|
||||
coordinates , kArgs.PointerLocation,
|
||||
entityToClick);
|
||||
|
||||
// client side command handlers will always be sent the local player session.
|
||||
var session = PlayerManager.LocalPlayer?.Session;
|
||||
if (inputSys.HandleInputCommand(session, func, message))
|
||||
{
|
||||
kArgs.Handle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using Content.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.State
|
||||
{
|
||||
/// <summary>
|
||||
/// Client state that has a main viewport.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used for taking no-UI screenshots (including things like flash overlay).
|
||||
/// </remarks>
|
||||
public interface IMainViewportState
|
||||
{
|
||||
public MainViewport Viewport { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
using System;
|
||||
using Content.Client.UserInterface;
|
||||
using Robust.Client;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Client.State
|
||||
{
|
||||
public class LauncherConnecting : Robust.Client.State.State
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IClientNetManager _clientNetManager = default!;
|
||||
[Dependency] private readonly IGameController _gameController = default!;
|
||||
[Dependency] private readonly IBaseClient _baseClient = default!;
|
||||
|
||||
private LauncherConnectingGui? _control;
|
||||
|
||||
private Page _currentPage;
|
||||
private string? _connectFailReason;
|
||||
|
||||
public string? Address => _gameController.LaunchState.Ss14Address ?? _gameController.LaunchState.ConnectAddress;
|
||||
|
||||
public string? ConnectFailReason
|
||||
{
|
||||
get => _connectFailReason;
|
||||
private set
|
||||
{
|
||||
_connectFailReason = value;
|
||||
ConnectFailReasonChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
public Page CurrentPage
|
||||
{
|
||||
get => _currentPage;
|
||||
private set
|
||||
{
|
||||
_currentPage = value;
|
||||
PageChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
public ClientConnectionState ConnectionState => _clientNetManager.ClientConnectState;
|
||||
|
||||
public event Action<Page>? PageChanged;
|
||||
public event Action<string?>? ConnectFailReasonChanged;
|
||||
public event Action<ClientConnectionState>? ConnectionStateChanged;
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
_control = new LauncherConnectingGui(this);
|
||||
|
||||
_userInterfaceManager.StateRoot.AddChild(_control);
|
||||
|
||||
_clientNetManager.ConnectFailed += (_, args) =>
|
||||
{
|
||||
ConnectFailReason = args.Reason;
|
||||
CurrentPage = Page.ConnectFailed;
|
||||
};
|
||||
|
||||
_clientNetManager.ClientConnectStateChanged += state => ConnectionStateChanged?.Invoke(state);
|
||||
|
||||
CurrentPage = Page.Connecting;
|
||||
}
|
||||
|
||||
public void RetryConnect()
|
||||
{
|
||||
if (_gameController.LaunchState.ConnectEndpoint != null)
|
||||
{
|
||||
_baseClient.ConnectToServer(_gameController.LaunchState.ConnectEndpoint);
|
||||
CurrentPage = Page.Connecting;
|
||||
}
|
||||
}
|
||||
|
||||
public void Exit()
|
||||
{
|
||||
_gameController.Shutdown("Exit button pressed");
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
_control?.Dispose();
|
||||
}
|
||||
|
||||
public void SetDisconnected()
|
||||
{
|
||||
CurrentPage = Page.Disconnected;
|
||||
}
|
||||
|
||||
public enum Page : byte
|
||||
{
|
||||
Connecting,
|
||||
ConnectFailed,
|
||||
Disconnected,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Client.Interfaces;
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Voting;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Content.Shared.GameTicking.SharedGameTicker;
|
||||
|
||||
namespace Content.Client.State
|
||||
{
|
||||
public class LobbyState : Robust.Client.State.State
|
||||
{
|
||||
[Dependency] private readonly IBaseClient _baseClient = default!;
|
||||
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IClientGameTicker _clientGameTicker = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IVoteManager _voteManager = default!;
|
||||
|
||||
[ViewVariables] private CharacterSetupGui _characterSetup = default!;
|
||||
[ViewVariables] private LobbyGui _lobby = default!;
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
_characterSetup = new CharacterSetupGui(_entityManager, _resourceCache, _preferencesManager,
|
||||
_prototypeManager);
|
||||
LayoutContainer.SetAnchorPreset(_characterSetup, LayoutContainer.LayoutPreset.Wide);
|
||||
|
||||
_characterSetup.CloseButton.OnPressed += _ =>
|
||||
{
|
||||
_userInterfaceManager.StateRoot.AddChild(_lobby);
|
||||
_userInterfaceManager.StateRoot.RemoveChild(_characterSetup);
|
||||
};
|
||||
|
||||
_characterSetup.SaveButton.OnPressed += _ =>
|
||||
{
|
||||
_characterSetup.Save();
|
||||
_lobby?.CharacterPreview.UpdateUI();
|
||||
};
|
||||
|
||||
_lobby = new LobbyGui(_entityManager, _preferencesManager);
|
||||
_userInterfaceManager.StateRoot.AddChild(_lobby);
|
||||
|
||||
LayoutContainer.SetAnchorPreset(_lobby, LayoutContainer.LayoutPreset.Wide);
|
||||
|
||||
_chatManager.SetChatBox(_lobby.Chat);
|
||||
_voteManager.SetPopupContainer(_lobby.VoteContainer);
|
||||
|
||||
_lobby.Chat.DefaultChatFormat = "ooc \"{0}\"";
|
||||
|
||||
_lobby.ServerName.Text = _baseClient.GameInfo?.ServerName;
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusChat,
|
||||
InputCmdHandler.FromDelegate(_ => GameScreen.FocusChat(_lobby.Chat)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusOOC,
|
||||
InputCmdHandler.FromDelegate(_ => GameScreen.FocusChannel(_lobby.Chat, ChatChannel.OOC)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusAdminChat,
|
||||
InputCmdHandler.FromDelegate(_ => GameScreen.FocusChannel(_lobby.Chat, ChatChannel.AdminChat)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.CycleChatChannelForward,
|
||||
InputCmdHandler.FromDelegate(_ => _lobby.Chat.CycleChatChannel(true)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.CycleChatChannelBackward,
|
||||
InputCmdHandler.FromDelegate(_ => _lobby.Chat.CycleChatChannel(false)));
|
||||
|
||||
UpdateLobbyUi();
|
||||
|
||||
_lobby.CharacterPreview.CharacterSetupButton.OnPressed += _ =>
|
||||
{
|
||||
SetReady(false);
|
||||
_userInterfaceManager.StateRoot.RemoveChild(_lobby);
|
||||
_userInterfaceManager.StateRoot.AddChild(_characterSetup);
|
||||
};
|
||||
|
||||
_lobby.ObserveButton.OnPressed += _ => _consoleHost.ExecuteCommand("observe");
|
||||
_lobby.ReadyButton.OnPressed += _ =>
|
||||
{
|
||||
if (!_clientGameTicker.IsGameStarted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
new LateJoinGui().OpenCentered();
|
||||
};
|
||||
|
||||
_lobby.ReadyButton.OnToggled += args =>
|
||||
{
|
||||
SetReady(args.Pressed);
|
||||
};
|
||||
|
||||
_lobby.LeaveButton.OnPressed += _ => _consoleHost.ExecuteCommand("disconnect");
|
||||
_lobby.OptionsButton.OnPressed += _ => new OptionsMenu().Open();
|
||||
|
||||
UpdatePlayerList();
|
||||
|
||||
_playerManager.PlayerListUpdated += PlayerManagerOnPlayerListUpdated;
|
||||
_clientGameTicker.InfoBlobUpdated += UpdateLobbyUi;
|
||||
_clientGameTicker.LobbyStatusUpdated += LobbyStatusUpdated;
|
||||
_clientGameTicker.LobbyReadyUpdated += LobbyReadyUpdated;
|
||||
_clientGameTicker.LobbyLateJoinStatusUpdated += LobbyLateJoinStatusUpdated;
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
_playerManager.PlayerListUpdated -= PlayerManagerOnPlayerListUpdated;
|
||||
_clientGameTicker.InfoBlobUpdated -= UpdateLobbyUi;
|
||||
_clientGameTicker.LobbyStatusUpdated -= LobbyStatusUpdated;
|
||||
_clientGameTicker.LobbyReadyUpdated -= LobbyReadyUpdated;
|
||||
_clientGameTicker.LobbyLateJoinStatusUpdated -= LobbyLateJoinStatusUpdated;
|
||||
|
||||
_clientGameTicker.Status.Clear();
|
||||
|
||||
_lobby.Dispose();
|
||||
_characterSetup.Dispose();
|
||||
}
|
||||
|
||||
public override void FrameUpdate(FrameEventArgs e)
|
||||
{
|
||||
if (_clientGameTicker.IsGameStarted)
|
||||
{
|
||||
_lobby.StartTime.Text = "";
|
||||
return;
|
||||
}
|
||||
|
||||
string text;
|
||||
|
||||
if (_clientGameTicker.Paused)
|
||||
{
|
||||
text = Loc.GetString("Paused");
|
||||
}
|
||||
else
|
||||
{
|
||||
var difference = _clientGameTicker.StartTime - _gameTiming.CurTime;
|
||||
var seconds = difference.TotalSeconds;
|
||||
if (seconds < 0)
|
||||
{
|
||||
text = Loc.GetString(seconds < -5 ? "Right Now?" : "Right Now");
|
||||
}
|
||||
else
|
||||
{
|
||||
text = $"{(int) Math.Floor(difference.TotalMinutes / 60)}:{difference.Seconds:D2}";
|
||||
}
|
||||
}
|
||||
|
||||
_lobby.StartTime.Text = Loc.GetString("Round Starts In: {0}", text);
|
||||
}
|
||||
|
||||
private void PlayerManagerOnPlayerListUpdated(object? sender, EventArgs e)
|
||||
{
|
||||
// Remove disconnected sessions from the Ready Dict
|
||||
foreach (var p in _clientGameTicker.Status)
|
||||
{
|
||||
if (!_playerManager.SessionsDict.TryGetValue(p.Key, out _))
|
||||
{
|
||||
// This is a shitty fix. Observers can rejoin because they are already in the game.
|
||||
// So we don't delete them, but keep them if they decide to rejoin
|
||||
if (p.Value != PlayerStatus.Observer)
|
||||
_clientGameTicker.Status.Remove(p.Key);
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePlayerList();
|
||||
}
|
||||
|
||||
private void LobbyReadyUpdated() => UpdatePlayerList();
|
||||
|
||||
private void LobbyStatusUpdated()
|
||||
{
|
||||
UpdatePlayerList();
|
||||
UpdateLobbyUi();
|
||||
}
|
||||
|
||||
private void LobbyLateJoinStatusUpdated()
|
||||
{
|
||||
_lobby.ReadyButton.Disabled = _clientGameTicker.DisallowedLateJoin;
|
||||
}
|
||||
|
||||
private void UpdateLobbyUi()
|
||||
{
|
||||
if (_lobby == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_clientGameTicker.IsGameStarted)
|
||||
{
|
||||
_lobby.ReadyButton.Text = Loc.GetString("Join");
|
||||
_lobby.ReadyButton.ToggleMode = false;
|
||||
_lobby.ReadyButton.Pressed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lobby.StartTime.Text = "";
|
||||
_lobby.ReadyButton.Text = Loc.GetString("Ready Up");
|
||||
_lobby.ReadyButton.ToggleMode = true;
|
||||
_lobby.ReadyButton.Disabled = false;
|
||||
_lobby.ReadyButton.Pressed = _clientGameTicker.AreWeReady;
|
||||
}
|
||||
|
||||
if (_clientGameTicker.ServerInfoBlob != null)
|
||||
{
|
||||
_lobby.ServerInfo.SetInfoBlob(_clientGameTicker.ServerInfoBlob);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayerList()
|
||||
{
|
||||
_lobby.OnlinePlayerList.Clear();
|
||||
|
||||
foreach (var session in _playerManager.Sessions.OrderBy(s => s.Name))
|
||||
{
|
||||
var readyState = "";
|
||||
// Don't show ready state if we're ingame
|
||||
if (!_clientGameTicker.IsGameStarted)
|
||||
{
|
||||
PlayerStatus status;
|
||||
if (session.UserId == _playerManager.LocalPlayer?.UserId)
|
||||
status = _clientGameTicker.AreWeReady ? PlayerStatus.Ready : PlayerStatus.NotReady;
|
||||
else
|
||||
_clientGameTicker.Status.TryGetValue(session.UserId, out status);
|
||||
|
||||
readyState = status switch
|
||||
{
|
||||
PlayerStatus.NotReady => Loc.GetString("Not Ready"),
|
||||
PlayerStatus.Ready => Loc.GetString("Ready"),
|
||||
PlayerStatus.Observer => Loc.GetString("Observer"),
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
_lobby.OnlinePlayerList.AddItem(session.Name, readyState);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetReady(bool newReady)
|
||||
{
|
||||
if (_clientGameTicker.IsGameStarted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_consoleHost.ExecuteCommand($"toggleready {newReady}");
|
||||
UpdatePlayerList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using Content.Client.Changelog;
|
||||
using Content.Client.UserInterface;
|
||||
using Robust.Client;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Utility;
|
||||
using UsernameHelpers = Robust.Shared.AuthLib.UsernameHelpers;
|
||||
|
||||
namespace Content.Client.State
|
||||
{
|
||||
/// <summary>
|
||||
/// Main menu screen that is the first screen to be displayed when the game starts.
|
||||
/// </summary>
|
||||
// Instantiated dynamically through the StateManager, Dependencies will be resolved.
|
||||
public class MainScreen : Robust.Client.State.State
|
||||
{
|
||||
private const string PublicServerAddress = "server.spacestation14.io";
|
||||
|
||||
[Dependency] private readonly IBaseClient _client = default!;
|
||||
[Dependency] private readonly IClientNetManager _netManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
[Dependency] private readonly IGameController _controllerProxy = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
|
||||
private MainMenuControl _mainMenuControl = default!;
|
||||
private OptionsMenu _optionsMenu = default!;
|
||||
private bool _isConnecting;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static readonly Regex IPv6Regex = new(@"\[(.*:.*:.*)](?::(\d+))?");
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Startup()
|
||||
{
|
||||
_mainMenuControl = new MainMenuControl(_resourceCache, _configurationManager);
|
||||
_userInterfaceManager.StateRoot.AddChild(_mainMenuControl);
|
||||
|
||||
_mainMenuControl.QuitButton.OnPressed += QuitButtonPressed;
|
||||
_mainMenuControl.OptionsButton.OnPressed += OptionsButtonPressed;
|
||||
_mainMenuControl.DirectConnectButton.OnPressed += DirectConnectButtonPressed;
|
||||
_mainMenuControl.JoinPublicServerButton.OnPressed += JoinPublicServerButtonPressed;
|
||||
_mainMenuControl.AddressBox.OnTextEntered += AddressBoxEntered;
|
||||
|
||||
_client.RunLevelChanged += RunLevelChanged;
|
||||
|
||||
_optionsMenu = new OptionsMenu();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Shutdown()
|
||||
{
|
||||
_client.RunLevelChanged -= RunLevelChanged;
|
||||
_netManager.ConnectFailed -= _onConnectFailed;
|
||||
|
||||
_mainMenuControl.Dispose();
|
||||
_optionsMenu.Dispose();
|
||||
}
|
||||
|
||||
private void QuitButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
_controllerProxy.Shutdown();
|
||||
}
|
||||
|
||||
private void OptionsButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
_optionsMenu.OpenCentered();
|
||||
}
|
||||
|
||||
private void DirectConnectButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
var input = _mainMenuControl.AddressBox;
|
||||
TryConnect(input.Text);
|
||||
}
|
||||
|
||||
private void JoinPublicServerButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
TryConnect(PublicServerAddress);
|
||||
}
|
||||
|
||||
private void AddressBoxEntered(LineEdit.LineEditEventArgs args)
|
||||
{
|
||||
if (_isConnecting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TryConnect(args.Text);
|
||||
}
|
||||
|
||||
private void TryConnect(string address)
|
||||
{
|
||||
var inputName = _mainMenuControl.UserNameBox.Text.Trim();
|
||||
if (!UsernameHelpers.IsNameValid(inputName, out var reason))
|
||||
{
|
||||
var invalidReason = Loc.GetString(reason.ToText());
|
||||
_userInterfaceManager.Popup(
|
||||
Loc.GetString("Invalid username:\n{0}", invalidReason),
|
||||
Loc.GetString("Invalid Username"));
|
||||
return;
|
||||
}
|
||||
|
||||
var configName = _configurationManager.GetCVar(CVars.PlayerName);
|
||||
if (_mainMenuControl.UserNameBox.Text != configName)
|
||||
{
|
||||
_configurationManager.SetCVar(CVars.PlayerName, inputName);
|
||||
_configurationManager.SaveToFile();
|
||||
}
|
||||
|
||||
_setConnectingState(true);
|
||||
_netManager.ConnectFailed += _onConnectFailed;
|
||||
try
|
||||
{
|
||||
ParseAddress(address, out var ip, out var port);
|
||||
_client.ConnectToServer(ip, port);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
_userInterfaceManager.Popup($"Unable to connect: {e.Message}", "Connection error.");
|
||||
Logger.Warning(e.ToString());
|
||||
_netManager.ConnectFailed -= _onConnectFailed;
|
||||
_setConnectingState(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void RunLevelChanged(object? obj, RunLevelChangedEventArgs args)
|
||||
{
|
||||
if (args.NewLevel == ClientRunLevel.Initialize)
|
||||
{
|
||||
_setConnectingState(false);
|
||||
_netManager.ConnectFailed -= _onConnectFailed;
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseAddress(string address, out string ip, out ushort port)
|
||||
{
|
||||
var match6 = IPv6Regex.Match(address);
|
||||
if (match6 != Match.Empty)
|
||||
{
|
||||
ip = match6.Groups[1].Value;
|
||||
if (!match6.Groups[2].Success)
|
||||
{
|
||||
port = _client.DefaultPort;
|
||||
}
|
||||
else if (!ushort.TryParse(match6.Groups[2].Value, out port))
|
||||
{
|
||||
throw new ArgumentException("Not a valid port.");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// See if the IP includes a port.
|
||||
var split = address.Split(':');
|
||||
ip = address;
|
||||
port = _client.DefaultPort;
|
||||
if (split.Length > 2)
|
||||
{
|
||||
throw new ArgumentException("Not a valid Address.");
|
||||
}
|
||||
|
||||
// IP:port format.
|
||||
if (split.Length == 2)
|
||||
{
|
||||
ip = split[0];
|
||||
if (!ushort.TryParse(split[1], out port))
|
||||
{
|
||||
throw new ArgumentException("Not a valid port.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _onConnectFailed(object? _, NetConnectFailArgs args)
|
||||
{
|
||||
_userInterfaceManager.Popup($"Failed to connect:\n{args.Reason}");
|
||||
_netManager.ConnectFailed -= _onConnectFailed;
|
||||
_setConnectingState(false);
|
||||
}
|
||||
|
||||
private void _setConnectingState(bool state)
|
||||
{
|
||||
_isConnecting = state;
|
||||
_mainMenuControl.DirectConnectButton.Disabled = state;
|
||||
#if FULL_RELEASE
|
||||
_mainMenuControl.JoinPublicServerButton.Disabled = state;
|
||||
#endif
|
||||
}
|
||||
|
||||
private sealed class MainMenuControl : Control
|
||||
{
|
||||
private readonly IResourceCache _resourceCache;
|
||||
private readonly IConfigurationManager _configurationManager;
|
||||
|
||||
public LineEdit UserNameBox { get; }
|
||||
public Button JoinPublicServerButton { get; }
|
||||
public LineEdit AddressBox { get; }
|
||||
public Button DirectConnectButton { get; }
|
||||
public Button OptionsButton { get; }
|
||||
public Button QuitButton { get; }
|
||||
public Label VersionLabel { get; }
|
||||
|
||||
public MainMenuControl(IResourceCache resCache, IConfigurationManager configMan)
|
||||
{
|
||||
_resourceCache = resCache;
|
||||
_configurationManager = configMan;
|
||||
|
||||
LayoutContainer.SetAnchorPreset(this, LayoutContainer.LayoutPreset.Wide);
|
||||
|
||||
AddChild(new ParallaxControl());
|
||||
|
||||
var layout = new LayoutContainer();
|
||||
AddChild(layout);
|
||||
|
||||
var vBox = new VBoxContainer
|
||||
{
|
||||
StyleIdentifier = "mainMenuVBox"
|
||||
};
|
||||
|
||||
layout.AddChild(vBox);
|
||||
LayoutContainer.SetAnchorPreset(vBox, LayoutContainer.LayoutPreset.TopRight);
|
||||
LayoutContainer.SetMarginRight(vBox, -25);
|
||||
LayoutContainer.SetMarginTop(vBox, 30);
|
||||
LayoutContainer.SetGrowHorizontal(vBox, LayoutContainer.GrowDirection.Begin);
|
||||
|
||||
var logoTexture = _resourceCache.GetResource<TextureResource>("/Textures/Logo/logo.png");
|
||||
var logo = new TextureRect
|
||||
{
|
||||
Texture = logoTexture,
|
||||
Stretch = TextureRect.StretchMode.KeepCentered,
|
||||
};
|
||||
vBox.AddChild(logo);
|
||||
|
||||
var userNameHBox = new HBoxContainer {SeparationOverride = 4};
|
||||
vBox.AddChild(userNameHBox);
|
||||
userNameHBox.AddChild(new Label {Text = "Username:"});
|
||||
|
||||
var currentUserName = _configurationManager.GetCVar(CVars.PlayerName);
|
||||
UserNameBox = new LineEdit
|
||||
{
|
||||
Text = currentUserName, PlaceHolder = "Username",
|
||||
HorizontalExpand = true
|
||||
};
|
||||
|
||||
userNameHBox.AddChild(UserNameBox);
|
||||
|
||||
JoinPublicServerButton = new Button
|
||||
{
|
||||
Text = "Join Public Server",
|
||||
StyleIdentifier = "mainMenu",
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
#if !FULL_RELEASE
|
||||
Disabled = true,
|
||||
ToolTip = "Cannot connect to public server with a debug build."
|
||||
#endif
|
||||
};
|
||||
|
||||
vBox.AddChild(JoinPublicServerButton);
|
||||
|
||||
// Separator.
|
||||
vBox.AddChild(new Control {MinSize = (0, 2)});
|
||||
|
||||
AddressBox = new LineEdit
|
||||
{
|
||||
Text = "localhost",
|
||||
PlaceHolder = "server address:port",
|
||||
HorizontalExpand = true
|
||||
};
|
||||
|
||||
vBox.AddChild(AddressBox);
|
||||
|
||||
DirectConnectButton = new Button
|
||||
{
|
||||
Text = "Direct Connect",
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
StyleIdentifier = "mainMenu",
|
||||
};
|
||||
|
||||
vBox.AddChild(DirectConnectButton);
|
||||
|
||||
// Separator.
|
||||
vBox.AddChild(new Control {MinSize = (0, 2)});
|
||||
|
||||
OptionsButton = new Button
|
||||
{
|
||||
Text = "Options",
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
StyleIdentifier = "mainMenu",
|
||||
};
|
||||
|
||||
vBox.AddChild(OptionsButton);
|
||||
|
||||
QuitButton = new Button
|
||||
{
|
||||
Text = "Quit",
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
StyleIdentifier = "mainMenu",
|
||||
};
|
||||
|
||||
vBox.AddChild(QuitButton);
|
||||
|
||||
vBox.AddChild(new ChangelogButton());
|
||||
|
||||
VersionLabel = new Label
|
||||
{
|
||||
Text = "v0.1"
|
||||
};
|
||||
|
||||
LayoutContainer.SetAnchorPreset(VersionLabel, LayoutContainer.LayoutPreset.BottomRight);
|
||||
LayoutContainer.SetGrowHorizontal(VersionLabel, LayoutContainer.GrowDirection.Begin);
|
||||
LayoutContainer.SetGrowVertical(VersionLabel, LayoutContainer.GrowDirection.Begin);
|
||||
layout.AddChild(VersionLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user