]> git.deb.at Git - rhonda/impostor.git/commitdiff
Add more events and missing SnapTo check
authorAeonLucid <aeonlucid@outlook.com>
Sat, 24 Oct 2020 23:07:36 +0000 (01:07 +0200)
committerAeonLucid <aeonlucid@outlook.com>
Sat, 24 Oct 2020 23:07:36 +0000 (01:07 +0200)
23 files changed:
src/Impostor.Api/Events/Game/GameEndedEvent.cs [new file with mode: 0644]
src/Impostor.Api/Events/Game/GameStartedEvent.cs [new file with mode: 0644]
src/Impostor.Api/Events/Game/GameStartingEvent.cs [new file with mode: 0644]
src/Impostor.Api/Events/Game/Net/PlayerChatEvent.cs [deleted file]
src/Impostor.Api/Events/Game/Net/PlayerDestroyedEvent.cs [deleted file]
src/Impostor.Api/Events/Game/Net/PlayerSpawnedEvent.cs [deleted file]
src/Impostor.Api/Events/Game/PlayerChatEvent.cs [new file with mode: 0644]
src/Impostor.Api/Events/Game/PlayerDestroyedEvent.cs [new file with mode: 0644]
src/Impostor.Api/Events/Game/PlayerMovementEvent.cs [new file with mode: 0644]
src/Impostor.Api/Events/Game/PlayerSpawnedEvent.cs [new file with mode: 0644]
src/Impostor.Api/Innersloth/GameStates.cs
src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs
src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs
src/Impostor.Plugins.Example/Handlers/GameEventListener.cs
src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs
src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs
src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs
src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs
src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs
src/Impostor.Server/Net/State/Game.Incoming.cs
src/Impostor.Server/Net/State/Game.Outgoing.cs
src/Impostor.Server/Net/State/Game.State.cs
src/Impostor.Server/Net/State/Game.cs

diff --git a/src/Impostor.Api/Events/Game/GameEndedEvent.cs b/src/Impostor.Api/Events/Game/GameEndedEvent.cs
new file mode 100644 (file)
index 0000000..0628fcf
--- /dev/null
@@ -0,0 +1,14 @@
+using Impostor.Api.Games;
+
+namespace Impostor.Api.Events
+{
+    public class GameEndedEvent : IGameEvent
+    {
+        public GameEndedEvent(IGame game)
+        {
+            Game = game;
+        }
+        
+        public IGame Game { get; }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Events/Game/GameStartedEvent.cs b/src/Impostor.Api/Events/Game/GameStartedEvent.cs
new file mode 100644 (file)
index 0000000..12311a3
--- /dev/null
@@ -0,0 +1,17 @@
+using Impostor.Api.Games;
+
+namespace Impostor.Api.Events
+{
+    /// <summary>
+    ///     The game is started here and players have been initialized.
+    /// </summary>
+    public class GameStartedEvent : IGameEvent
+    {
+        public GameStartedEvent(IGame game)
+        {
+            Game = game;
+        }
+
+        public IGame Game { get; }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Events/Game/GameStartingEvent.cs b/src/Impostor.Api/Events/Game/GameStartingEvent.cs
new file mode 100644 (file)
index 0000000..b60d007
--- /dev/null
@@ -0,0 +1,19 @@
+using Impostor.Api.Games;
+
+namespace Impostor.Api.Events
+{
+    /// <summary>
+    ///     Called when the game is going to start.
+    ///     When this is called, not all players are initialized properly yet.
+    ///     If you want to get correct player states, use <see cref="GameStartedEvent"/>.
+    /// </summary>
+    public class GameStartingEvent : IGameEvent
+    {
+        public GameStartingEvent(IGame game)
+        {
+            Game = game;
+        }
+
+        public IGame Game { get; }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Events/Game/Net/PlayerChatEvent.cs b/src/Impostor.Api/Events/Game/Net/PlayerChatEvent.cs
deleted file mode 100644 (file)
index cac481c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-using Impostor.Api.Games;
-using Impostor.Api.Net.Inner.Objects;
-
-namespace Impostor.Api.Events.Net
-{
-    public class PlayerChatEvent : IGameEvent
-    {
-        public PlayerChatEvent(IGame game, IInnerPlayerControl playerControl, string message)
-        {
-            Game = game;
-            PlayerControl = playerControl;
-            Message = message;
-        }
-
-        public IGame Game { get; }
-
-        public IInnerPlayerControl PlayerControl { get; }
-
-        public string Message { get; }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Api/Events/Game/Net/PlayerDestroyedEvent.cs b/src/Impostor.Api/Events/Game/Net/PlayerDestroyedEvent.cs
deleted file mode 100644 (file)
index 6d5d8c4..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-using Impostor.Api.Games;
-using Impostor.Api.Net.Inner.Objects;
-
-namespace Impostor.Api.Events.Net
-{
-    public class PlayerDestroyedEvent : IGameEvent
-    {
-        public PlayerDestroyedEvent(IGame game, IInnerPlayerControl playerControl)
-        {
-            Game = game;
-            PlayerControl = playerControl;
-        }
-
-        public IGame Game { get; }
-
-        public IInnerPlayerControl PlayerControl { get; }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Api/Events/Game/Net/PlayerSpawnedEvent.cs b/src/Impostor.Api/Events/Game/Net/PlayerSpawnedEvent.cs
deleted file mode 100644 (file)
index 9b1664a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-using Impostor.Api.Games;
-using Impostor.Api.Net.Inner.Objects;
-
-namespace Impostor.Api.Events.Net
-{
-    public class PlayerSpawnedEvent : IGameEvent
-    {
-        public PlayerSpawnedEvent(IGame game, IInnerPlayerControl playerControl)
-        {
-            Game = game;
-            PlayerControl = playerControl;
-        }
-
-        public IGame Game { get; }
-
-        public IInnerPlayerControl PlayerControl { get; }
-    }
-}
\ No newline at end of file
diff --git a/src/Impostor.Api/Events/Game/PlayerChatEvent.cs b/src/Impostor.Api/Events/Game/PlayerChatEvent.cs
new file mode 100644 (file)
index 0000000..1d70536
--- /dev/null
@@ -0,0 +1,21 @@
+using Impostor.Api.Games;
+using Impostor.Api.Net.Inner.Objects;
+
+namespace Impostor.Api.Events
+{
+    public class PlayerChatEvent : IGameEvent
+    {
+        public PlayerChatEvent(IGame game, IInnerPlayerControl playerControl, string message)
+        {
+            Game = game;
+            PlayerControl = playerControl;
+            Message = message;
+        }
+
+        public IGame Game { get; }
+
+        public IInnerPlayerControl PlayerControl { get; }
+
+        public string Message { get; }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Events/Game/PlayerDestroyedEvent.cs b/src/Impostor.Api/Events/Game/PlayerDestroyedEvent.cs
new file mode 100644 (file)
index 0000000..6d5d8c4
--- /dev/null
@@ -0,0 +1,18 @@
+using Impostor.Api.Games;
+using Impostor.Api.Net.Inner.Objects;
+
+namespace Impostor.Api.Events.Net
+{
+    public class PlayerDestroyedEvent : IGameEvent
+    {
+        public PlayerDestroyedEvent(IGame game, IInnerPlayerControl playerControl)
+        {
+            Game = game;
+            PlayerControl = playerControl;
+        }
+
+        public IGame Game { get; }
+
+        public IInnerPlayerControl PlayerControl { get; }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Events/Game/PlayerMovementEvent.cs b/src/Impostor.Api/Events/Game/PlayerMovementEvent.cs
new file mode 100644 (file)
index 0000000..fd9238a
--- /dev/null
@@ -0,0 +1,14 @@
+using Impostor.Api.Games;
+
+namespace Impostor.Api.Events
+{
+    public class PlayerMovementEvent : IGameEvent
+    {
+        public PlayerMovementEvent(IGame game)
+        {
+            Game = game;
+        }
+
+        public IGame Game { get; }
+    }
+}
\ No newline at end of file
diff --git a/src/Impostor.Api/Events/Game/PlayerSpawnedEvent.cs b/src/Impostor.Api/Events/Game/PlayerSpawnedEvent.cs
new file mode 100644 (file)
index 0000000..9b1664a
--- /dev/null
@@ -0,0 +1,18 @@
+using Impostor.Api.Games;
+using Impostor.Api.Net.Inner.Objects;
+
+namespace Impostor.Api.Events.Net
+{
+    public class PlayerSpawnedEvent : IGameEvent
+    {
+        public PlayerSpawnedEvent(IGame game, IInnerPlayerControl playerControl)
+        {
+            Game = game;
+            PlayerControl = playerControl;
+        }
+
+        public IGame Game { get; }
+
+        public IInnerPlayerControl PlayerControl { get; }
+    }
+}
\ No newline at end of file
index 8abc8c7a482f403a8a9785941f36828da99e07a1..f5aaa9cc502feffcb02b7b5bae73b9450093a1fb 100644 (file)
@@ -3,8 +3,9 @@
     public enum GameStates : byte
     {
         NotStarted = 0,
-        Started = 1,
-        Ended = 2,
-        Destroyed = 3
+        Starting = 1,
+        Started = 2,
+        Ended = 3,
+        Destroyed = 4,
     }
 }
\ No newline at end of file
index 45b949a7bc59de994598107d23395afe42643dfe..4d53d2c52c2a8d49efd0494afa12b7e7152763a0 100644 (file)
@@ -1,7 +1,13 @@
-namespace Impostor.Api.Net.Inner.Objects
+using System.Threading.Tasks;
+
+namespace Impostor.Api.Net.Inner.Objects
 {
     public interface IInnerPlayerControl
     {
         IInnerPlayerInfo PlayerInfo { get; }
+
+        ValueTask SetNameAsync(string name);
+
+        ValueTask SendChatAsync(string text);
     }
 }
\ No newline at end of file
index e1de18b6e69f07ca61ff8b47d7504dbd9f48e658..2715d2de18980d049dc5e9c20a8778ef0dc86b17 100644 (file)
@@ -1,10 +1,47 @@
-namespace Impostor.Api.Net.Inner.Objects
+using Impostor.Api.Innersloth;
+
+namespace Impostor.Api.Net.Inner.Objects
 {
     public interface IInnerPlayerInfo
     {
         /// <summary>
         ///     Gets the name of the player as decided by the host.
         /// </summary>
-        public string PlayerName { get; }
+        string PlayerName { get; }
+
+        /// <summary>
+        ///     Gets the color of the player.
+        /// </summary>
+        byte ColorId { get; }
+
+        /// <summary>
+        ///     Gets the hat of the player.
+        /// </summary>
+        uint HatId { get; }
+
+        /// <summary>
+        ///     Gets the pet of the player.
+        /// </summary>
+        uint PetId { get; }
+
+        /// <summary>
+        ///     Gets the skin of the player.
+        /// </summary>
+        uint SkinId { get; }
+
+        /// <summary>
+        ///     Gets a value indicating whether the player is an impostor.
+        /// </summary>
+        bool IsImpostor { get; }
+
+        /// <summary>
+        ///     Gets a value indicating whether the player is a dead in the current game.
+        /// </summary>
+        bool IsDead { get; }
+
+        /// <summary>
+        ///     Gets the reason why the player is dead in the current game.
+        /// </summary>
+        DeathReason LastDeathReason { get; }
     }
 }
\ No newline at end of file
index 29c3c98ace479512ba96225e694922ef523673ae..19d9bc4b164e1e6f3d879576394053d75a91731a 100644 (file)
@@ -8,13 +8,38 @@ namespace Impostor.Plugins.Example.Handlers
         [EventListener]
         public void OnGameCreated(GameCreatedEvent e)
         {
-            Console.WriteLine("Game was created.");
+            Console.WriteLine("Game > created");
+        }
+
+        [EventListener]
+        public void OnGameStarting(GameStartingEvent e)
+        {
+            Console.WriteLine("Game > starting");
+        }
+
+        [EventListener]
+        public void OnGameStarted(GameStartedEvent e)
+        {
+            Console.WriteLine("Game > started");
+
+            foreach (var player in e.Game.Players)
+            {
+                var info = player.Character.PlayerInfo;
+
+                Console.WriteLine($"- {info.PlayerName} {info.IsImpostor}");
+            }
+        }
+
+        [EventListener]
+        public void OnGameEnded(GameEndedEvent e)
+        {
+            Console.WriteLine("Game > ended");
         }
 
         [EventListener]
         public void OnGameDestroyed(GameDestroyedEvent e)
         {
-            Console.WriteLine("Game was destroyed.");
+            Console.WriteLine("Game > destroyed");
         }
 
         [EventListener]
index 590ad711603140527cd3883ff4147b6d5a2249a9..9d162299dcd9564ef370a00dbae23a2649a5e008 100644 (file)
@@ -1,4 +1,5 @@
 using System;
+using System.Threading.Tasks;
 using Impostor.Api.Events;
 using Impostor.Api.Events.Net;
 
@@ -19,9 +20,12 @@ namespace Impostor.Plugins.Example.Handlers
         }
 
         [EventListener]
-        public void OnPlayerChat(PlayerChatEvent e)
+        public async ValueTask OnPlayerChat(PlayerChatEvent e)
         {
             Console.WriteLine(e.PlayerControl.PlayerInfo.PlayerName + " said " + e.Message);
+
+            await e.PlayerControl.SetNameAsync(e.Message);
+            await e.PlayerControl.SendChatAsync(e.Message);
         }
     }
 }
\ No newline at end of file
index 75e331e6f3fc68b2deedb78ca4a6a3ea00df9c06..c621add3ef2c84646865d482b67945c9546cfc7d 100644 (file)
@@ -1,4 +1,5 @@
-using System.Numerics;
+using System;
+using System.Numerics;
 using System.Threading.Tasks;
 using Impostor.Api;
 using Impostor.Api.Innersloth;
@@ -15,14 +16,18 @@ namespace Impostor.Server.Net.Inner.Objects.Components
         private static readonly FloatRange YRange = new FloatRange(-40f, 40f);
 
         private readonly ILogger<InnerCustomNetworkTransform> _logger;
+        private readonly InnerPlayerControl _playerControl;
+        private readonly Game _game;
 
         private ushort _lastSequenceId;
         private Vector2 _targetSyncPosition;
         private Vector2 _targetSyncVelocity;
 
-        public InnerCustomNetworkTransform(ILogger<InnerCustomNetworkTransform> logger)
+        public InnerCustomNetworkTransform(ILogger<InnerCustomNetworkTransform> logger, InnerPlayerControl playerControl, Game game)
         {
             _logger = logger;
+            _playerControl = playerControl;
+            _game = game;
         }
 
         private static bool SidGreaterThan(ushort newSid, ushort prevSid)
@@ -48,18 +53,31 @@ namespace Impostor.Server.Net.Inner.Objects.Components
             return new Vector2(XRange.Lerp(v1), YRange.Lerp(v2));
         }
 
-        public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
+        public override async ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
         {
             if (call == RpcCalls.SnapTo)
             {
+                if (!sender.IsOwner(this))
+                {
+                    throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SnapTo)} to an unowned {nameof(InnerPlayerControl)}");
+                }
+
+                if (target != null)
+                {
+                    throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SnapTo)} to a specific player instead of broadcast");
+                }
+
+                if (!sender.Character.PlayerInfo.IsImpostor)
+                {
+                    throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SnapTo)} as crewmate");
+                }
+
                 SnapTo(ReadVector2(reader), reader.ReadUInt16());
             }
             else
             {
                 _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerCustomNetworkTransform), call);
             }
-
-            return default;
         }
 
         public override bool Serialize(IMessageWriter writer, bool initialState)
index 08738f77d339fcdc0d91db1ff693502bb1cbef2e..50c3a0621481f3c096303bed9f39713756e21555 100644 (file)
@@ -11,10 +11,12 @@ namespace Impostor.Server.Net.Inner.Objects.Components
     internal class InnerPlayerPhysics : InnerNetObject
     {
         private readonly ILogger<InnerPlayerPhysics> _logger;
+        private readonly InnerPlayerControl _playerControl;
 
-        public InnerPlayerPhysics(ILogger<InnerPlayerPhysics> logger)
+        public InnerPlayerPhysics(ILogger<InnerPlayerPhysics> logger, InnerPlayerControl playerControl)
         {
             _logger = logger;
+            _playerControl = playerControl;
         }
 
         public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
index 225d78f42ca4702e837c0eb9a0cb8862cd447c5a..6a9fa45fa093c21909a083362b719da5f482ede8 100644 (file)
@@ -1,9 +1,28 @@
-using Impostor.Api.Net.Inner.Objects;
+using System.Threading.Tasks;
+using Impostor.Api.Net.Inner.Objects;
 
 namespace Impostor.Server.Net.Inner.Objects
 {
     internal partial class InnerPlayerControl : IInnerPlayerControl
     {
         IInnerPlayerInfo IInnerPlayerControl.PlayerInfo => PlayerInfo;
+
+        public async ValueTask SetNameAsync(string name)
+        {
+            using (var writer = _game.StartRpc(NetId, RpcCalls.SetName))
+            {
+                writer.Write(name);
+                await _game.FinishRpcAsync(writer);
+            }
+        }
+
+        public async ValueTask SendChatAsync(string text)
+        {
+            using (var writer = _game.StartRpc(NetId, RpcCalls.SendChat))
+            {
+                writer.Write(text);
+                await _game.FinishRpcAsync(writer);
+            }
+        }
     }
 }
\ No newline at end of file
index 4d3576cf4bb7cb81590defa66823a12981c131d2..0d6f39b25681dd603c5818d1f6341d7ac0705bc7 100644 (file)
@@ -1,6 +1,7 @@
 using System;
 using System.Threading.Tasks;
 using Impostor.Api;
+using Impostor.Api.Events;
 using Impostor.Api.Events.Managers;
 using Impostor.Api.Events.Net;
 using Impostor.Api.Innersloth;
@@ -26,9 +27,12 @@ namespace Impostor.Server.Net.Inner.Objects
             _eventManager = eventManager;
             _game = game;
 
+            Physics = ActivatorUtilities.CreateInstance<InnerPlayerPhysics>(serviceProvider, this);
+            NetworkTransform = ActivatorUtilities.CreateInstance<InnerCustomNetworkTransform>(serviceProvider, this, _game);
+
             Components.Add(this);
-            Components.Add(ActivatorUtilities.CreateInstance<InnerPlayerPhysics>(serviceProvider));
-            Components.Add(ActivatorUtilities.CreateInstance<InnerCustomNetworkTransform>(serviceProvider));
+            Components.Add(Physics);
+            Components.Add(NetworkTransform);
 
             PlayerId = byte.MaxValue;
         }
@@ -37,6 +41,10 @@ namespace Impostor.Server.Net.Inner.Objects
 
         public byte PlayerId { get; private set; }
 
+        public InnerPlayerPhysics Physics { get; }
+
+        public InnerCustomNetworkTransform NetworkTransform { get; }
+
         public InnerPlayerInfo PlayerInfo { get; internal set; }
 
         public override async ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
@@ -103,8 +111,15 @@ namespace Impostor.Server.Net.Inner.Objects
                     {
                         var playerId = reader.ReadByte();
                         var player = _game.GameNet.GameData.GetPlayerById(playerId);
+                        if (player != null)
+                        {
+                            player.IsImpostor = true;
+                        }
+                    }
 
-                        player.IsImpostor = true;
+                    if (_game.GameState == GameStates.Starting)
+                    {
+                        await _game.StartedAsync();
                     }
 
                     break;
index 4d1342b92c9a9f22c3339ccc793fee0621c315ce..7d81b360e8b28bd1b1dd959f11190b38cb1286f3 100644 (file)
@@ -1,6 +1,7 @@
 using System;
 using System.Threading;
 using System.Threading.Tasks;
+using Impostor.Api.Events;
 using Impostor.Api.Games;
 using Impostor.Api.Innersloth;
 using Impostor.Api.Net;
@@ -17,11 +18,13 @@ namespace Impostor.Server.Net.State
 
         public async ValueTask HandleStartGame(IMessageReader message)
         {
-            GameState = GameStates.Started;
+            GameState = GameStates.Starting;
 
             using var packet = MessageWriter.Get(MessageType.Reliable);
             message.CopyTo(packet);
             await SendToAllAsync(packet);
+
+            await _eventManager.CallAsync(new GameStartingEvent(this));
         }
 
         public async ValueTask<GameJoinResult> AddClientAsync(ClientBase client)
@@ -66,7 +69,7 @@ namespace Impostor.Server.Net.State
                 return GameJoinResult.FromError(GameJoinError.GameFull);
             }
 
-            if (GameState == GameStates.Started)
+            if (GameState == GameStates.Starting || GameState == GameStates.Started)
             {
                 return GameJoinResult.FromError(GameJoinError.GameStarted);
             }
@@ -124,6 +127,8 @@ namespace Impostor.Server.Net.State
             {
                 player.Value.Limbo = LimboStates.PreSpawn;
             }
+
+            await _eventManager.CallAsync(new GameEndedEvent(this));
         }
 
         public async ValueTask HandleAlterGame(IMessageReader message, IClientPlayer sender, bool isPublic)
index 3f2ef680da0c7415ddf201ca22e9ecc38a0d601a..555216af7f9fca46c904221b2dc1490b3bec1d0b 100644 (file)
@@ -4,6 +4,9 @@ using Impostor.Api.Innersloth;
 using Impostor.Api.Net;
 using Impostor.Api.Net.Messages;
 using Impostor.Api.Net.Messages.S2C;
+using Impostor.Hazel;
+using Impostor.Hazel.Udp;
+using Impostor.Server.Net.Inner;
 
 namespace Impostor.Server.Net.State
 {
@@ -35,6 +38,37 @@ namespace Impostor.Server.Net.State
             }
         }
 
+        internal IMessageWriter StartRpc(uint targetNetId, RpcCalls callId, int targetClientId = -1, MessageType type = MessageType.Reliable)
+        {
+            var writer = MessageWriter.Get(type);
+
+            if (targetClientId < 0)
+            {
+                writer.StartMessage(MessageFlags.GameData);
+                writer.Write(Code);
+            }
+            else
+            {
+                writer.StartMessage(MessageFlags.GameDataTo);
+                writer.Write(Code);
+                writer.WritePacked(targetClientId);
+            }
+
+            writer.StartMessage(GameDataTag.RpcFlag);
+            writer.WritePacked(targetNetId);
+            writer.Write((byte) callId);
+
+            return writer;
+        }
+
+        internal ValueTask FinishRpcAsync(IMessageWriter writer)
+        {
+            writer.EndMessage();
+            writer.EndMessage();
+
+            return SendToAllAsync(writer);
+        }
+
         private void WriteRemovePlayerMessage(IMessageWriter message, bool clear, int playerId, DisconnectReason reason)
         {
             Message04RemovePlayerS2C.Serialize(message, clear, Code, playerId, HostId, reason);
index 27b65a850526dd8f1a6fac4c374e29fbfc2ade7c..8b22030d573cc7243070b8ed0f71b6aa288fc6f3 100644 (file)
@@ -40,7 +40,7 @@ namespace Impostor.Server.Net.State
 
             _logger.LogInformation("{0} - Player {1} ({2}) has left.", Code, player.Client.Name, playerId);
 
-            if (GameState == GameStates.Started)
+            if (GameState == GameStates.Starting || GameState == GameStates.Started)
             {
                 if (player.Character?.PlayerInfo != null)
                 {
index b48a5b2d5b15bc1acc616a7a7b24ec29c7cd1bd7..7462cd6226aa5dc8c30ad6831cba27082f56b909 100644 (file)
@@ -4,6 +4,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Net;
 using System.Threading.Tasks;
+using Impostor.Api.Events;
 using Impostor.Api.Events.Managers;
 using Impostor.Api.Games;
 using Impostor.Api.Innersloth;
@@ -91,6 +92,18 @@ namespace Impostor.Server.Net.State
             return _players.TryGetValue(clientId, out var clientPlayer) ? clientPlayer : null;
         }
 
+        internal ValueTask StartedAsync()
+        {
+            if (GameState == GameStates.Starting)
+            {
+                GameState = GameStates.Started;
+
+                return _eventManager.CallAsync(new GameStartedEvent(this));
+            }
+
+            return default;
+        }
+
         public ValueTask EndAsync()
         {
             return _gameManager.RemoveAsync(Code);