We have a lobby! (#127)

It's shoddy as hell but it works for our purposes.
This commit is contained in:
Pieter-Jan Briers
2018-11-25 19:04:49 +01:00
committed by GitHub
parent f887d22a16
commit 845d0f9182
13 changed files with 1054 additions and 89 deletions

View File

@@ -76,7 +76,9 @@
<Compile Include="GameObjects\Components\Storage\ClientStorageComponent.cs" /> <Compile Include="GameObjects\Components\Storage\ClientStorageComponent.cs" />
<Compile Include="GameObjects\EntitySystems\ClientNotifySystem.cs" /> <Compile Include="GameObjects\EntitySystems\ClientNotifySystem.cs" />
<Compile Include="GameObjects\EntitySystems\VerbSystem.cs" /> <Compile Include="GameObjects\EntitySystems\VerbSystem.cs" />
<Compile Include="GameTicking\ClientGameTicker.cs" />
<Compile Include="Input\ContentContexts.cs" /> <Compile Include="Input\ContentContexts.cs" />
<Compile Include="Interfaces\IClientGameTicker.cs" />
<Compile Include="Interfaces\IClientNotifyManager.cs" /> <Compile Include="Interfaces\IClientNotifyManager.cs" />
<Compile Include="ClientNotifyManager.cs" /> <Compile Include="ClientNotifyManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@@ -84,6 +86,7 @@
<Compile Include="Interfaces\GameObjects\Components\Items\IHandsComponent.cs" /> <Compile Include="Interfaces\GameObjects\Components\Items\IHandsComponent.cs" />
<Compile Include="UserInterface\HandsGui.cs" /> <Compile Include="UserInterface\HandsGui.cs" />
<Compile Include="GameObjects\Components\Power\PowerDebugTool.cs" /> <Compile Include="GameObjects\Components\Power\PowerDebugTool.cs" />
<Compile Include="UserInterface\LobbyGui.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Content.Shared\Content.Shared.csproj"> <ProjectReference Include="..\Content.Shared\Content.Shared.csproj">

View File

@@ -4,6 +4,7 @@ using Content.Client.GameObjects.Components.Construction;
using Content.Client.GameObjects.Components.Power; using Content.Client.GameObjects.Components.Power;
using Content.Client.GameObjects.Components.SmoothWalling; using Content.Client.GameObjects.Components.SmoothWalling;
using Content.Client.GameObjects.Components.Storage; using Content.Client.GameObjects.Components.Storage;
using Content.Client.GameTicking;
using Content.Client.Input; using Content.Client.Input;
using Content.Client.Interfaces; using Content.Client.Interfaces;
using Content.Client.Interfaces.GameObjects; using Content.Client.Interfaces.GameObjects;
@@ -77,6 +78,7 @@ namespace Content.Client
IoCManager.Register<IClientNotifyManager, ClientNotifyManager>(); IoCManager.Register<IClientNotifyManager, ClientNotifyManager>();
IoCManager.Register<ISharedNotifyManager, ClientNotifyManager>(); IoCManager.Register<ISharedNotifyManager, ClientNotifyManager>();
IoCManager.Register<IClientGameTicker, ClientGameTicker>();
IoCManager.BuildGraph(); IoCManager.BuildGraph();
} }
@@ -89,6 +91,7 @@ namespace Content.Client
ContentContexts.SetupContexts(inputMan.Contexts); ContentContexts.SetupContexts(inputMan.Contexts);
IoCManager.Resolve<IClientNotifyManager>().Initialize(); IoCManager.Resolve<IClientNotifyManager>().Initialize();
IoCManager.Resolve<IClientGameTicker>().Initialize();
} }
public override void Update(AssemblyLoader.UpdateLevel level, float frameTime) public override void Update(AssemblyLoader.UpdateLevel level, float frameTime)
@@ -98,7 +101,9 @@ namespace Content.Client
switch (level) switch (level)
{ {
case AssemblyLoader.UpdateLevel.FramePreEngine: case AssemblyLoader.UpdateLevel.FramePreEngine:
IoCManager.Resolve<IClientNotifyManager>().FrameUpdate(new RenderFrameEventArgs(frameTime)); var renderFrameEventArgs = new RenderFrameEventArgs(frameTime);
IoCManager.Resolve<IClientNotifyManager>().FrameUpdate(renderFrameEventArgs);
IoCManager.Resolve<IClientGameTicker>().FrameUpdate(renderFrameEventArgs);
break; break;
} }
} }

View File

@@ -0,0 +1,228 @@
using System;
using Content.Client.Interfaces;
using Content.Client.UserInterface;
using Content.Shared;
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;
using SS14.Shared.Utility;
using SS14.Shared.ViewVariables;
namespace Content.Client.GameTicking
{
public class ClientGameTicker : SharedGameTicker, IClientGameTicker
{
#pragma warning disable 649
[Dependency] private IClientNetManager _netManager;
[Dependency] private IUserInterfaceManager _userInterfaceManager;
[Dependency] private IClientChatConsole _chatConsole;
[Dependency] private IInputManager _inputManager;
[Dependency] private IBaseClient _baseClient;
#pragma warning restore 649
[ViewVariables] private bool _areWeReady;
[ViewVariables] private bool _initialized;
[ViewVariables] private TickerState _tickerState;
[ViewVariables] private Chatbox _gameChat;
[ViewVariables] private LobbyGui _lobby;
[ViewVariables] private bool _gameStarted;
[ViewVariables] private DateTime _startTime;
public void Initialize()
{
DebugTools.Assert(!_initialized);
_netManager.RegisterNetMessage<MsgTickerJoinLobby>(nameof(MsgTickerJoinLobby), _joinLobby);
_netManager.RegisterNetMessage<MsgTickerJoinGame>(nameof(MsgTickerJoinGame), _joinGame);
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus), _lobbyStatus);
_baseClient.RunLevelChanged += BaseClientOnRunLevelChanged;
_initialized = true;
}
private void BaseClientOnRunLevelChanged(object sender, RunLevelChangedEventArgs e)
{
if (e.NewLevel != ClientRunLevel.Initialize)
{
return;
}
_tickerState = TickerState.Unset;
_lobby?.Dispose();
_lobby = null;
_gameChat?.Dispose();
_gameChat = null;
}
public void FrameUpdate(RenderFrameEventArgs renderFrameEventArgs)
{
if (_lobby == null)
{
return;
}
if (_gameStarted)
{
_lobby.StartTime.Text = "";
return;
}
string text;
var difference = _startTime - DateTime.UtcNow;
if (difference.Ticks < 0)
{
if (difference.TotalSeconds < -5)
{
text = "Right Now?";
}
else
{
text = "Right Now";
}
}
else
{
text = $"{(int) Math.Floor(difference.TotalMinutes)}:{difference.Seconds:D2}";
}
_lobby.StartTime.Text = "Round Starts In: " + text;
}
private void _lobbyStatus(MsgTickerLobbyStatus message)
{
_startTime = message.StartTime;
_gameStarted = message.IsRoundStarted;
_areWeReady = message.YouAreReady;
_updateLobbyUi();
}
private void _updateLobbyUi()
{
if (_lobby == null)
{
return;
}
if (_gameStarted)
{
_lobby.ReadyButton.Text = "Join";
_lobby.ReadyButton.ToggleMode = false;
_lobby.ReadyButton.Pressed = false;
}
else
{
_lobby.StartTime.Text = "";
_lobby.ReadyButton.Text = "Ready Up";
_lobby.ReadyButton.ToggleMode = true;
_lobby.ReadyButton.Pressed = _areWeReady;
}
}
private void _joinLobby(MsgTickerJoinLobby message)
{
if (_tickerState == TickerState.InLobby)
{
return;
}
if (_gameChat != null)
{
_gameChat.TextSubmitted -= _chatConsole.ParseChatMessage;
_chatConsole.AddString -= _gameChat.AddLine;
_gameChat.Dispose();
_gameChat = null;
}
_tickerState = TickerState.InLobby;
_lobby = new LobbyGui();
_userInterfaceManager.StateRoot.AddChild(_lobby);
_lobby.Chat.TextSubmitted += _chatConsole.ParseChatMessage;
_chatConsole.AddString += _lobby.Chat.AddLine;
_lobby.Chat.DefaultChatFormat = "ooc \"{0}\"";
_lobby.ServerName.Text = _baseClient.GameInfo.ServerName;
_inputManager.SetInputCommand(EngineKeyFunctions.FocusChat,
InputCmdHandler.FromDelegate(session => { _lobby.Chat.Input.GrabFocus(); }));
_updateLobbyUi();
_lobby.ObserveButton.OnPressed += args => { _chatConsole.ProcessCommand("observe"); };
_lobby.ReadyButton.OnPressed += args =>
{
if (!_gameStarted)
{
return;
}
_chatConsole.ProcessCommand("joingame");
};
_lobby.ReadyButton.OnToggled += args =>
{
if (_gameStarted)
{
return;
}
_chatConsole.ProcessCommand($"toggleready {args.Pressed}");
};
_lobby.LeaveButton.OnPressed += args => _chatConsole.ProcessCommand("disconnect");
}
private void _joinGame(MsgTickerJoinGame message)
{
if (_tickerState == TickerState.InGame)
{
return;
}
_tickerState = TickerState.InGame;
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.GrabFocus(); }));
_gameChat = new Chatbox();
_userInterfaceManager.StateRoot.AddChild(_gameChat);
_gameChat.TextSubmitted += _chatConsole.ParseChatMessage;
_chatConsole.AddString += _gameChat.AddLine;
_gameChat.DefaultChatFormat = "say \"{0}\"";
}
private enum TickerState
{
Unset = 0,
/// <summary>
/// The client is in the lobby.
/// </summary>
InLobby = 1,
/// <summary>
/// The client is NOT in the lobby.
/// Do not confuse this with the client session status.
/// </summary>
InGame = 2
}
}
}

View File

@@ -0,0 +1,10 @@
using SS14.Client;
namespace Content.Client.Interfaces
{
public interface IClientGameTicker
{
void Initialize();
void FrameUpdate(RenderFrameEventArgs renderFrameEventArgs);
}
}

View File

@@ -0,0 +1,35 @@
using SS14.Client.UserInterface;
using SS14.Client.UserInterface.Controls;
using SS14.Client.UserInterface.CustomControls;
using SS14.Shared.Utility;
namespace Content.Client.UserInterface
{
public class LobbyGui : Control
{
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Lobby/Lobby.tscn");
public Label ServerName => GetChild<Label>("Panel/VBoxContainer/TitleContainer/ServerName");
public Label StartTime => GetChild<Label>("Panel/VBoxContainer/HBoxContainer/LeftVBox/ReadyButtons/RoundStartText");
public Button ReadyButton =>
GetChild<Button>("Panel/VBoxContainer/HBoxContainer/LeftVBox/ReadyButtons/ReadyButton");
public Button ObserveButton =>
GetChild<Button>("Panel/VBoxContainer/HBoxContainer/LeftVBox/ReadyButtons/ObserveButton");
public Button LeaveButton => GetChild<Button>("Panel/VBoxContainer/TitleContainer/LeaveButton");
public Chatbox Chat { get; private set; }
protected override void Initialize()
{
base.Initialize();
var chatContainer = GetChild("Panel/VBoxContainer/HBoxContainer/LeftVBox");
Chat = new Chatbox();
chatContainer.AddChild(Chat);
Chat.SizeFlagsVertical = SizeFlags.FillExpand;
}
}
}

View File

@@ -45,9 +45,6 @@ namespace Content.Server
{ {
public class EntryPoint : GameServer public class EntryPoint : GameServer
{ {
private IBaseServer _server;
private IPlayerManager _players;
private IChatManager chatManager;
private IGameTicker _gameTicker; private IGameTicker _gameTicker;
/// <inheritdoc /> /// <inheritdoc />
@@ -55,12 +52,6 @@ namespace Content.Server
{ {
base.Init(); base.Init();
_server = IoCManager.Resolve<IBaseServer>();
_players = IoCManager.Resolve<IPlayerManager>();
chatManager = IoCManager.Resolve<IChatManager>();
_players.PlayerStatusChanged += HandlePlayerStatusChanged;
var factory = IoCManager.Resolve<IComponentFactory>(); var factory = IoCManager.Resolve<IComponentFactory>();
factory.Register<HandsComponent>(); factory.Register<HandsComponent>();
@@ -140,76 +131,11 @@ namespace Content.Server
_gameTicker.Initialize(); _gameTicker.Initialize();
} }
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
if (disposing)
{
_players.PlayerStatusChanged -= HandlePlayerStatusChanged;
}
base.Dispose(disposing);
}
public override void Update(AssemblyLoader.UpdateLevel level, float frameTime) public override void Update(AssemblyLoader.UpdateLevel level, float frameTime)
{ {
base.Update(level, frameTime); base.Update(level, frameTime);
_gameTicker.Update(new FrameEventArgs(frameTime)); _gameTicker.Update(new FrameEventArgs(frameTime));
} }
private void HandlePlayerStatusChanged(object sender, SessionStatusEventArgs args)
{
var session = args.Session;
switch (args.NewStatus)
{
case SessionStatus.Connected:
{
if (session.Data.ContentDataUncast == null)
{
session.Data.ContentDataUncast = new PlayerData(session.SessionId);
}
// timer time must be > tick length
Timer.Spawn(0, args.Session.JoinGame);
chatManager.DispatchMessage(ChatChannel.Server, "Gamemode: Player joined server!", args.Session.SessionId);
}
break;
case SessionStatus.InGame:
{
//TODO: Check for existing mob and re-attach
var data = session.ContentData();
if (data.Mind == null)
{
// No mind yet (new session), make a new one.
data.Mind = new Mind(session.SessionId);
var mob = _gameTicker.SpawnPlayerMob();
data.Mind.TransferTo(mob);
}
else
{
if (data.Mind.CurrentEntity == null)
{
var mob = _gameTicker.SpawnPlayerMob();
data.Mind.TransferTo(mob);
}
session.AttachToEntity(data.Mind.CurrentEntity);
}
chatManager.DispatchMessage(ChatChannel.Server, "Gamemode: Player joined Game!",
args.Session.SessionId);
}
break;
case SessionStatus.Disconnected:
{
chatManager.DispatchMessage(ChatChannel.Server, "Gamemode: Player left!", args.Session.SessionId);
}
break;
}
}
} }
} }

View File

@@ -1,30 +1,39 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Server.GameObjects; using Content.Server.GameObjects;
using Content.Server.GameTicking.GamePresets; using Content.Server.GameTicking.GamePresets;
using Content.Server.Interfaces.GameTicking; using Content.Server.Interfaces.GameTicking;
using Content.Server.Mobs;
using Content.Server.Players;
using Content.Shared;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using JetBrains.Annotations; using SS14.Server.Interfaces.Chat;
using SS14.Server.Interfaces;
using SS14.Server.Interfaces.Console; using SS14.Server.Interfaces.Console;
using SS14.Server.Interfaces.Maps; using SS14.Server.Interfaces.Maps;
using SS14.Server.Interfaces.Player; using SS14.Server.Interfaces.Player;
using SS14.Server.Player;
using SS14.Shared.Configuration; using SS14.Shared.Configuration;
using SS14.Shared.Console;
using SS14.Shared.Enums;
using SS14.Shared.Interfaces.Configuration; using SS14.Shared.Interfaces.Configuration;
using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Map; using SS14.Shared.Interfaces.Map;
using SS14.Shared.Interfaces.Network;
using SS14.Shared.Interfaces.Timing; using SS14.Shared.Interfaces.Timing;
using SS14.Shared.IoC; using SS14.Shared.IoC;
using SS14.Shared.Log; using SS14.Shared.Log;
using SS14.Shared.Map; using SS14.Shared.Map;
using SS14.Shared.Maths; using SS14.Shared.Maths;
using SS14.Shared.Network;
using SS14.Shared.Timers;
using SS14.Shared.Timing; using SS14.Shared.Timing;
using SS14.Shared.Utility; using SS14.Shared.Utility;
using SS14.Shared.ViewVariables; using SS14.Shared.ViewVariables;
namespace Content.Server.GameTicking namespace Content.Server.GameTicking
{ {
public class GameTicker : IGameTicker public class GameTicker : SharedGameTicker, IGameTicker
{ {
[ViewVariables] [ViewVariables]
public GameRunLevel RunLevel public GameRunLevel RunLevel
@@ -44,11 +53,27 @@ namespace Content.Server.GameTicking
} }
} }
public Action<GameRunLevelChangedEventArgs> OnRunLevelChanged;
private const string PlayerPrototypeName = "HumanMob_Content"; private const string PlayerPrototypeName = "HumanMob_Content";
private const string ObserverPrototypeName = "MobObserver";
private const string MapFile = "Maps/stationstation.yml"; private const string MapFile = "Maps/stationstation.yml";
private bool _initialized; // Seconds.
private const float LobbyDuration = 20;
[ViewVariables] private bool _initialized;
[ViewVariables(VVAccess.ReadWrite)] private GridLocalCoordinates _spawnPoint; [ViewVariables(VVAccess.ReadWrite)] private GridLocalCoordinates _spawnPoint;
[ViewVariables] private GameRunLevel _runLevel;
[ViewVariables] private bool LobbyEnabled => _configurationManager.GetCVar<bool>("game.lobbyenabled");
// Value is whether they're ready.
[ViewVariables]
private readonly Dictionary<IPlayerSession, bool> _playersInLobby = new Dictionary<IPlayerSession, bool>();
[ViewVariables] private bool _roundStartCountdownHasNotStartedYetDueToNoPlayers;
private DateTime _roundStartTimeUtc;
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private IEntityManager _entityManager; [Dependency] private IEntityManager _entityManager;
@@ -56,16 +81,21 @@ namespace Content.Server.GameTicking
[Dependency] private IMapLoader _mapLoader; [Dependency] private IMapLoader _mapLoader;
[Dependency] private IGameTiming _gameTiming; [Dependency] private IGameTiming _gameTiming;
[Dependency] private IConfigurationManager _configurationManager; [Dependency] private IConfigurationManager _configurationManager;
[Dependency] private IPlayerManager _playerManager;
[Dependency] private IChatManager _chatManager;
[Dependency] private IServerNetManager _netManager;
#pragma warning restore 649 #pragma warning restore 649
public Action<GameRunLevelChangedEventArgs> OnRunLevelChanged;
private GameRunLevel _runLevel;
public void Initialize() public void Initialize()
{ {
DebugTools.Assert(!_initialized); DebugTools.Assert(!_initialized);
_configurationManager.RegisterCVar("game.lobbyenabled", false, CVar.ARCHIVE); _configurationManager.RegisterCVar("game.lobbyenabled", false, CVar.ARCHIVE);
_playerManager.PlayerStatusChanged += _handlePlayerStatusChanged;
_netManager.RegisterNetMessage<MsgTickerJoinLobby>(nameof(MsgTickerJoinLobby));
_netManager.RegisterNetMessage<MsgTickerJoinGame>(nameof(MsgTickerJoinGame));
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus));
RestartRound(); RestartRound();
@@ -74,6 +104,13 @@ namespace Content.Server.GameTicking
public void Update(FrameEventArgs frameEventArgs) public void Update(FrameEventArgs frameEventArgs)
{ {
if (RunLevel != GameRunLevel.PreRoundLobby || _roundStartTimeUtc > DateTime.UtcNow ||
_roundStartCountdownHasNotStartedYetDueToNoPlayers)
{
return;
}
StartRound();
} }
public void RestartRound() public void RestartRound()
@@ -84,13 +121,22 @@ namespace Content.Server.GameTicking
_resettingCleanup(); _resettingCleanup();
_preRoundSetup(); _preRoundSetup();
if (_configurationManager.GetCVar<bool>("game.lobbyenabled")) if (!LobbyEnabled)
{ {
throw new NotImplementedException();
}
StartRound(); StartRound();
} }
else
{
if (_playerManager.PlayerCount == 0)
{
_roundStartCountdownHasNotStartedYetDueToNoPlayers = true;
}
else
{
_roundStartTimeUtc = DateTime.UtcNow + TimeSpan.FromSeconds(LobbyDuration);
}
}
}
public void StartRound() public void StartRound()
{ {
@@ -102,6 +148,18 @@ namespace Content.Server.GameTicking
// TODO: Allow other presets to be selected. // TODO: Allow other presets to be selected.
var preset = new PresetTraitor(); var preset = new PresetTraitor();
preset.Start(); preset.Start();
foreach (var (playerSession, ready) in _playersInLobby.ToList())
{
if (!ready)
{
continue;
}
_spawnPlayer(playerSession);
}
_sendStatusToAll();
} }
public void EndRound() public void EndRound()
@@ -112,7 +170,52 @@ namespace Content.Server.GameTicking
RunLevel = GameRunLevel.PostRound; RunLevel = GameRunLevel.PostRound;
} }
public IEntity SpawnPlayerMob() public void Respawn(IPlayerSession targetPlayer)
{
targetPlayer.ContentData().WipeMind();
if (LobbyEnabled)
{
_playerJoinLobby(targetPlayer);
}
else
{
_spawnPlayer(targetPlayer);
}
}
public void MakeObserve(IPlayerSession player)
{
if (!_playersInLobby.ContainsKey(player))
{
return;
}
_spawnObserver(player);
}
public void MakeJoinGame(IPlayerSession player)
{
if (!_playersInLobby.ContainsKey(player))
{
return;
}
_spawnPlayer(player);
}
public void ToggleReady(IPlayerSession player, bool ready)
{
if (!_playersInLobby.ContainsKey(player))
{
return;
}
_playersInLobby[player] = ready;
_netManager.ServerSendMessage(_getStatusMsg(player), player.ConnectedClient);
}
private IEntity _spawnPlayerMob()
{ {
var entity = _entityManager.ForceSpawnEntityAt(PlayerPrototypeName, _spawnPoint); var entity = _entityManager.ForceSpawnEntityAt(PlayerPrototypeName, _spawnPoint);
var shoes = _entityManager.SpawnEntity("ShoesItem"); var shoes = _entityManager.SpawnEntity("ShoesItem");
@@ -126,6 +229,11 @@ namespace Content.Server.GameTicking
return entity; return entity;
} }
private IEntity _spawnObserverMob()
{
return _entityManager.ForceSpawnEntityAt(ObserverPrototypeName, _spawnPoint);
}
/// <summary> /// <summary>
/// Cleanup that has to run to clear up anything from the previous round. /// Cleanup that has to run to clear up anything from the previous round.
/// Stuff like wiping the previous map clean. /// Stuff like wiping the previous map clean.
@@ -149,6 +257,13 @@ namespace Content.Server.GameTicking
_mapManager.DeleteMap(map.Index); _mapManager.DeleteMap(map.Index);
} }
} }
// Delete the minds of everybody.
// TODO: Maybe move this into a separate manager?
foreach (var unCastData in _playerManager.GetAllPlayerData())
{
unCastData.ContentData().WipeMind();
}
} }
private void _preRoundSetup() private void _preRoundSetup()
@@ -162,6 +277,138 @@ namespace Content.Server.GameTicking
var timeSpan = _gameTiming.RealTime - startTime; var timeSpan = _gameTiming.RealTime - startTime;
Logger.InfoS("ticker", $"Loaded map in {timeSpan.TotalMilliseconds:N2}ms."); Logger.InfoS("ticker", $"Loaded map in {timeSpan.TotalMilliseconds:N2}ms.");
} }
private void _handlePlayerStatusChanged(object sender, SessionStatusEventArgs args)
{
var session = args.Session;
switch (args.NewStatus)
{
case SessionStatus.Connected:
{
// Always make sure the client has player data. Mind gets assigned on spawn.
if (session.Data.ContentDataUncast == null)
{
session.Data.ContentDataUncast = new PlayerData(session.SessionId);
}
// timer time must be > tick length
Timer.Spawn(0, args.Session.JoinGame);
_chatManager.DispatchMessage(ChatChannel.Server, "Game: Player joined server!",
args.Session.SessionId);
if (LobbyEnabled && _roundStartCountdownHasNotStartedYetDueToNoPlayers)
{
_roundStartCountdownHasNotStartedYetDueToNoPlayers = false;
_roundStartTimeUtc = DateTime.UtcNow + TimeSpan.FromSeconds(LobbyDuration);
}
break;
}
case SessionStatus.InGame:
{
//TODO: Check for existing mob and re-attach
var data = session.ContentData();
if (data.Mind == null)
{
if (LobbyEnabled)
{
_playerJoinLobby(session);
return;
}
_spawnPlayer(session);
}
else
{
if (data.Mind.CurrentEntity == null)
{
_spawnPlayer(session);
}
else
{
session.AttachToEntity(data.Mind.CurrentEntity);
_playerJoinGame(session);
}
}
_chatManager.DispatchMessage(ChatChannel.Server, "Game: Player joined Game!",
args.Session.SessionId);
break;
}
case SessionStatus.Disconnected:
{
if (_playersInLobby.ContainsKey(session))
{
_playersInLobby.Remove(session);
}
_chatManager.DispatchMessage(ChatChannel.Server, "Game: Player left!", args.Session.SessionId);
break;
}
}
}
private void _spawnPlayer(IPlayerSession session)
{
_playerJoinGame(session);
var data = session.ContentData();
data.WipeMind();
data.Mind = new Mind(session.SessionId);
var mob = _spawnPlayerMob();
data.Mind.TransferTo(mob);
}
private void _spawnObserver(IPlayerSession session)
{
_playerJoinGame(session);
var data = session.ContentData();
data.WipeMind();
data.Mind = new Mind(session.SessionId);
var mob = _spawnObserverMob();
data.Mind.TransferTo(mob);
}
private void _playerJoinLobby(IPlayerSession session)
{
_playersInLobby.Add(session, false);
_netManager.ServerSendMessage(_netManager.CreateNetMessage<MsgTickerJoinLobby>(), session.ConnectedClient);
_netManager.ServerSendMessage(_getStatusMsg(session), session.ConnectedClient);
}
private void _playerJoinGame(IPlayerSession session)
{
if (_playersInLobby.ContainsKey(session))
{
_playersInLobby.Remove(session);
}
_netManager.ServerSendMessage(_netManager.CreateNetMessage<MsgTickerJoinGame>(), session.ConnectedClient);
}
private MsgTickerLobbyStatus _getStatusMsg(IPlayerSession session)
{
_playersInLobby.TryGetValue(session, out var ready);
var msg = _netManager.CreateNetMessage<MsgTickerLobbyStatus>();
msg.IsRoundStarted = RunLevel != GameRunLevel.PreRoundLobby;
msg.StartTime = _roundStartTimeUtc;
msg.YouAreReady = ready;
return msg;
}
private void _sendStatusToAll()
{
foreach (var player in _playersInLobby.Keys)
{
_netManager.ServerSendMessage(_getStatusMsg(player), player.ConnectedClient);
}
}
} }
public enum GameRunLevel public enum GameRunLevel
@@ -235,4 +482,94 @@ namespace Content.Server.GameTicking
ticker.RestartRound(); ticker.RestartRound();
} }
} }
class RespawnCommand : IClientCommand
{
public string Command => "respawn";
public string Description => "Respawns a player, kicking them back to the lobby.";
public string Help => "respawn <player>";
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
{
if (args.Length != 1)
{
shell.SendText(player, "Must provide exactly one argument.");
return;
}
var playerMgr = IoCManager.Resolve<IPlayerManager>();
var ticker = IoCManager.Resolve<IGameTicker>();
var arg = new NetSessionId(args[0]);
if (!playerMgr.TryGetSessionById(arg, out var targetPlayer))
{
if (!playerMgr.TryGetPlayerData(arg, out var data))
{
shell.SendText(player, "Unknown player");
return;
}
data.ContentData().WipeMind();
shell.SendText(player,
"Player is not currently online, but they will respawn if they come back online");
return;
}
ticker.Respawn(targetPlayer);
}
}
class ObserveCommand : IClientCommand
{
public string Command => "observe";
public string Description => "";
public string Help => "";
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
{
if (player == null)
{
return;
}
var ticker = IoCManager.Resolve<IGameTicker>();
ticker.MakeObserve(player);
}
}
class JoinGameCommand : IClientCommand
{
public string Command => "joingame";
public string Description => "";
public string Help => "";
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
{
if (player == null)
{
return;
}
var ticker = IoCManager.Resolve<IGameTicker>();
ticker.MakeJoinGame(player);
}
}
class ToggleReadyCommand : IClientCommand
{
public string Command => "toggleready";
public string Description => "";
public string Help => "";
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
{
if (player == null)
{
return;
}
var ticker = IoCManager.Resolve<IGameTicker>();
ticker.ToggleReady(player, bool.Parse(args[0]));
}
}
} }

View File

@@ -1,4 +1,6 @@
using Content.Server.GameTicking; using Content.Server.GameTicking;
using SS14.Server.Interfaces.Player;
using SS14.Server.Player;
using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Timing; using SS14.Shared.Timing;
@@ -18,6 +20,9 @@ namespace Content.Server.Interfaces.GameTicking
void StartRound(); void StartRound();
void EndRound(); void EndRound();
IEntity SpawnPlayerMob(); void Respawn(IPlayerSession targetPlayer);
void MakeObserve(IPlayerSession player);
void MakeJoinGame(IPlayerSession player);
void ToggleReady(IPlayerSession player, bool ready);
} }
} }

View File

@@ -108,6 +108,7 @@
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />
<Compile Include="Input\ContentKeyFunctions.cs" /> <Compile Include="Input\ContentKeyFunctions.cs" />
<Compile Include="SharedGameTicker.cs" />
<Compile Include="SharedNotifyManager.cs" /> <Compile Include="SharedNotifyManager.cs" />
<Compile Include="Utility\ContentHelpers.cs" /> <Compile Include="Utility\ContentHelpers.cs" />
<Compile Include="GameObjects\Components\Power\SharedSmesComponent.cs" /> <Compile Include="GameObjects\Components\Power\SharedSmesComponent.cs" />

View File

@@ -0,0 +1,94 @@
using System;
using System.IO;
using Lidgren.Network;
using SS14.Shared.Interfaces.Network;
using SS14.Shared.Interfaces.Serialization;
using SS14.Shared.IoC;
using SS14.Shared.Map;
using SS14.Shared.Network;
namespace Content.Shared
{
public abstract class SharedGameTicker
{
protected class MsgTickerJoinLobby : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgTickerJoinLobby);
public MsgTickerJoinLobby(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override void ReadFromBuffer(NetIncomingMessage buffer)
{
}
public override void WriteToBuffer(NetOutgoingMessage buffer)
{
}
}
protected class MsgTickerJoinGame : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgTickerJoinGame);
public MsgTickerJoinGame(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override void ReadFromBuffer(NetIncomingMessage buffer)
{
}
public override void WriteToBuffer(NetOutgoingMessage buffer)
{
}
}
protected class MsgTickerLobbyStatus : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgTickerLobbyStatus);
public MsgTickerLobbyStatus(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public bool IsRoundStarted { get; set; }
public bool YouAreReady { get; set; }
// UTC.
public DateTime StartTime { get; set; }
public override void ReadFromBuffer(NetIncomingMessage buffer)
{
IsRoundStarted = buffer.ReadBoolean();
if (IsRoundStarted)
{
return;
}
YouAreReady = buffer.ReadBoolean();
StartTime = new DateTime(buffer.ReadInt64(), DateTimeKind.Utc);
}
public override void WriteToBuffer(NetOutgoingMessage buffer)
{
buffer.Write(IsRoundStarted);
if (IsRoundStarted)
{
return;
}
buffer.Write(YouAreReady);
buffer.Write(StartTime.Ticks);
}
}
}
}

View File

@@ -9,6 +9,8 @@
- whisper - whisper
- me - me
- ooc - ooc
- observe
- toggleready
- Index: 50 - Index: 50
Name: Moderator Name: Moderator
@@ -22,6 +24,8 @@
- me - me
- ooc - ooc
- showtime - showtime
- observe
- toggleready
- Index: 100 - Index: 100
Name: Administrator Name: Administrator
@@ -35,4 +39,6 @@
- ooc - ooc
- showtime - showtime
- aghost - aghost
- observe
- toggleready
CanViewVar: true CanViewVar: true

View File

@@ -0,0 +1,315 @@
[gd_scene format=2]
[node name="Control" type="Control" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
[node name="Panel" type="Panel" parent="." index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 20.0
margin_top = 20.0
margin_right = -20.0
margin_bottom = -20.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
[node name="VBoxContainer" type="VBoxContainer" parent="Panel" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 3.0
margin_top = 3.0
margin_right = -3.0
margin_bottom = -3.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
alignment = 0
[node name="TitleContainer" type="MarginContainer" parent="Panel/VBoxContainer" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 978.0
margin_bottom = 20.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
custom_constants/margin_right = 0
custom_constants/margin_top = 0
custom_constants/margin_left = 0
custom_constants/margin_bottom = 0
_sections_unfolded = [ "custom_constants", "custom_styles" ]
[node name="LobbyLabel" type="Label" parent="Panel/VBoxContainer/TitleContainer" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 3.0
margin_right = 43.0
margin_bottom = 17.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 0
size_flags_vertical = 4
text = "LOBBY"
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
_sections_unfolded = [ "Size Flags" ]
[node name="ServerName" type="Label" parent="Panel/VBoxContainer/TitleContainer" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 3.0
margin_right = 978.0
margin_bottom = 17.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 4
text = "Space Station 14"
align = 1
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
[node name="LeaveButton" type="Button" parent="Panel/VBoxContainer/TitleContainer" index="2"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 929.0
margin_right = 978.0
margin_bottom = 20.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 8
size_flags_vertical = 1
toggle_mode = false
enabled_focus_mode = 2
shortcut = null
group = null
text = "Leave"
flat = false
align = 1
_sections_unfolded = [ "Size Flags" ]
[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 24.0
margin_right = 978.0
margin_bottom = 554.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 3
alignment = 0
[node name="LeftVBox" type="VBoxContainer" parent="Panel/VBoxContainer/HBoxContainer" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 487.0
margin_bottom = 530.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 1
alignment = 0
[node name="LeftPanel" type="Container" parent="Panel/VBoxContainer/HBoxContainer/LeftVBox" index="0"]
editor/display_folded = true
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 487.0
margin_bottom = 506.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 3
[node name="RichTextLabel" type="RichTextLabel" parent="Panel/VBoxContainer/HBoxContainer/LeftVBox/LeftPanel" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = true
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
bbcode_enabled = false
bbcode_text = ""
visible_characters = -1
percent_visible = 1.0
meta_underlined = true
tab_size = 4
text = "Welcome to the server!
Player count: 0"
scroll_active = true
scroll_following = false
selection_enabled = false
override_selected_font_color = false
[node name="ReadyButtons" type="HBoxContainer" parent="Panel/VBoxContainer/HBoxContainer/LeftVBox" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 510.0
margin_right = 487.0
margin_bottom = 530.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 1
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
alignment = 0
[node name="ObserveButton" type="Button" parent="Panel/VBoxContainer/HBoxContainer/LeftVBox/ReadyButtons" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 66.0
margin_bottom = 20.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
toggle_mode = false
enabled_focus_mode = 2
shortcut = null
group = null
text = "Observe"
flat = false
align = 1
[node name="RoundStartText" type="Label" parent="Panel/VBoxContainer/HBoxContainer/LeftVBox/ReadyButtons" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 70.0
margin_top = 3.0
margin_right = 411.0
margin_bottom = 17.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 4
text = "Round Starts In:"
align = 2
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
[node name="ReadyButton" type="Button" parent="Panel/VBoxContainer/HBoxContainer/LeftVBox/ReadyButtons" index="2"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 415.0
margin_right = 487.0
margin_bottom = 20.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
toggle_mode = true
enabled_focus_mode = 2
shortcut = null
group = null
text = "Ready Up"
flat = false
align = 1
[node name="RightPanel" type="Container" parent="Panel/VBoxContainer/HBoxContainer" index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 491.0
margin_right = 978.0
margin_bottom = 530.0
rect_pivot_offset = Vector2( 0, 0 )
rect_clip_content = false
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 3
size_flags_vertical = 1

2
engine

Submodule engine updated: e3449e454b...861aabbe9b