]> git.deb.at Git - rhonda/impostor.git/commitdiff
Improve game code, now possible to start / end games
authorAeonLucid <aeonlucid@gmail.com>
Sun, 20 Sep 2020 21:06:20 +0000 (23:06 +0200)
committerMike <aeonlucid@outlook.com>
Sun, 20 Sep 2020 21:13:57 +0000 (23:13 +0200)
src/AmongUs.Server/Net/Client.cs
src/AmongUs.Server/Net/Game.cs
src/AmongUs.Server/Net/Request/RequestFlag.cs [deleted file]
src/AmongUs.Shared/Innersloth/Data/AlterGameTags.cs [new file with mode: 0644]
src/AmongUs.Shared/Innersloth/Data/RequestFlag.cs [new file with mode: 0644]
src/AmongUs.Shared/Innersloth/GameOptionsData.cs

index 0ce555169640893834559519a8a9761a0026092f..6f9db3d7b120fc59ad0c2d94785656a370353f6c 100644 (file)
@@ -1,8 +1,6 @@
 using System;
 using AmongUs.Server.Data;
-using AmongUs.Server.Exceptions;
 using AmongUs.Server.Extensions;
-using AmongUs.Server.Net.Request;
 using AmongUs.Server.Net.Response;
 using AmongUs.Shared.Innersloth;
 using AmongUs.Shared.Innersloth.Data;
@@ -36,6 +34,40 @@ namespace AmongUs.Server.Net
         public Connection Connection { get; }
         public ClientPlayer Player { get; }
 
+        public void Send(MessageWriter writer)
+        {
+            Connection.Send(writer);
+        }
+        
+        private bool IsPacketAllowed(MessageReader message, bool hostOnly)
+        {
+            var game = Player.Game;
+            if (game == null)
+            {
+                return false;
+            }
+
+            // GameCode must match code of the current game assigned to the player.
+            if (message.ReadInt32() != game.Code)
+            {
+                return false;
+            }
+            
+            // Some packets should only be sent by the host of the game.
+            if (hostOnly)
+            {
+                if (game.HostId == Id)
+                {
+                    return true;
+                }
+                
+                Logger.Warning("[{0}] Client sent packet only allowed by the host ({1}).", Id, game.HostId);
+                return false;
+            }
+
+            return true;
+        }
+
         private void OnDataReceived(DataReceivedEventArgs e)
         {
             try
@@ -105,31 +137,41 @@ namespace AmongUs.Server.Net
                     game.HandleJoinGame(Player);
                     break;
                 }
-                
-                // 101A3960
+
                 case RequestFlag.StartGame:
+                {
+                    if (!IsPacketAllowed(message, true))
+                    {
+                        return;
+                    }
+
+                    Player.Game.HandleStartGame(message);
                     break;
+                }
                 
                 // 101A39EC
                 case RequestFlag.RemoveGame:
                     break;
                 
                 case RequestFlag.RemovePlayer:
+                {
+                    if (!IsPacketAllowed(message, true))
+                    {
+                        return;
+                    }
+
+                    var playerId = message.ReadPackedInt32();
+                    var reason = message.ReadByte();
+
+                    Player.Game.HandleRemovePlayer(playerId, reason);
                     break;
+                }
                 
                 case RequestFlag.GameData:
                 case RequestFlag.GameDataTo:
                 {
-                    var game = Player.Game;
-                    if (game == null)
+                    if (!IsPacketAllowed(message, false))
                     {
-                        throw new NullReferenceException("Game was not set for the client.");
-                    }
-                    
-                    var code = message.ReadInt32();
-                    if (code != game.Code)
-                    {
-                        // Packet was meant for another game.
                         return;
                     }
 
@@ -140,12 +182,12 @@ namespace AmongUs.Server.Net
                         {
                             var target = message.ReadPackedInt32();
                             writer.CopyFrom(message);
-                            game.SendTo(writer, target);
+                            Player.Game.SendTo(writer, target);
                         }
                         else
                         {
                             writer.CopyFrom(message);
-                            game.SendToAllExcept(writer, Player);
+                            Player.Game.SendToAllExcept(writer, Player);
                         }
                     }
                     break;
@@ -155,9 +197,16 @@ namespace AmongUs.Server.Net
                 case RequestFlag.JoinedGame:
                     break;
                 
-                // 101A3BD0
                 case RequestFlag.EndGame:
+                {
+                    if (!IsPacketAllowed(message, true))
+                    {
+                        return;
+                    }
+
+                    Player.Game.HandleEndGame(message);
                     break;
+                }
                 
                 default:
                     Logger.Warning("Server received unknown flag {0}.", flag);
index 23318e7db428a58eefe8d2ebc8957f8e929e08ee..b6d348cf89c606d13d53cf9597eafb67efbf0475 100644 (file)
@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Concurrent;
-using System.Collections.Generic;
 using System.Linq;
 using AmongUs.Server.Exceptions;
 using AmongUs.Server.Extensions;
@@ -18,29 +17,36 @@ namespace AmongUs.Server.Net
         private static readonly ILogger Logger = Log.ForContext<Game>();
         
         private readonly ConcurrentDictionary<int, ClientPlayer> _players;
-        private int _hostId;
-        
+
         public Game(int code, GameOptionsData options)
         {
             Code = code;
             CodeStr = GameCode.IntToGameName(code);
+            HostId = -1;
             GameState = GameStates.NotStarted;
             Options = options;
 
-            _hostId = -1;
             _players = new ConcurrentDictionary<int, ClientPlayer>();
         }
         
         public int Code { get; }
         public string CodeStr { get; }
-        public GameStates GameState { get; }
+        public bool IsPublic { get; private set; }
+        public int HostId { get; private set; }
+        public GameStates GameState { get; private set; }
         public GameOptionsData Options { get; }
 
         public void SendToAllExcept(MessageWriter message, ClientPlayer sender)
         {
             foreach (var (_, player) in _players.Where(x => x.Value != sender))
             {
-                player.Client.Connection.Send(message);
+                if (player.Client.Connection.State != ConnectionState.Connected)
+                {
+                    Logger.Warning("[{0}] Tried to sent data to a disconnected player ({1}).", sender?.Client.Id, player.Client.Id);
+                    continue;
+                }
+                
+                player.Client.Send(message);
             }
         }
 
@@ -48,7 +54,13 @@ namespace AmongUs.Server.Net
         {
             if (_players.TryGetValue(playerId, out var player))
             {
-                player.Client.Connection.Send(message);
+                if (player.Client.Connection.State != ConnectionState.Connected)
+                {
+                    Logger.Warning("[{0}] Sending data to {1} failed, player is not connected.", CodeStr, player.Client.Id);
+                    return;
+                }
+                
+                player.Client.Send(message);
             }
             else
             {
@@ -56,6 +68,17 @@ namespace AmongUs.Server.Net
             }
         }
 
+        public void HandleStartGame(MessageReader message)
+        {
+            GameState = GameStates.Started;
+            
+            using (var packet = MessageWriter.Get(SendOption.Reliable))
+            {
+                packet.CopyFrom(message);
+                SendToAllExcept(packet, null);
+            }
+        }
+
         public void HandleJoinGame(ClientPlayer player)
         {
             switch (GameState)
@@ -63,10 +86,10 @@ namespace AmongUs.Server.Net
                 case GameStates.NotStarted:
                     HandleJoinGameNew(player);
                     break;
-                case GameStates.Started:
+                case GameStates.Ended:
                     HandleJoinGameNext(player);
                     break;
-                case GameStates.Ended:
+                case GameStates.Started:
                 case GameStates.Destroyed:
                     player.Client.Connection.Send(new Message1DisconnectReason(DisconnectReason.GameStarted));
                     return;
@@ -75,6 +98,43 @@ namespace AmongUs.Server.Net
             }
         }
 
+        public void HandleEndGame(MessageReader message)
+        {
+            GameState = GameStates.Ended;
+            
+            // Broadcast end of the game.
+            using (var packet = MessageWriter.Get(SendOption.Reliable))
+            {
+                packet.CopyFrom(message);
+                SendToAllExcept(packet, null);
+            }
+            
+            // Remove all players from this game.
+            foreach (var player in _players)
+            {
+                player.Value.Game = null;
+            }
+            
+            _players.Clear();
+        }
+
+        public void HandleRemovePlayer(int playerId, byte reason)
+        {
+            _players.TryRemove(playerId, out var player);
+            
+            // TODO: Host migration
+
+            using (var packet = MessageWriter.Get(SendOption.Reliable))
+            {
+                packet.Write(Code);
+                packet.Write(playerId);
+                packet.Write(HostId);
+                packet.Write(reason);
+                
+                SendToAllExcept(packet, player);
+            }
+        }
+
         private void HandleJoinGameNew(ClientPlayer player)
         {
             Logger.Verbose("[{0}] Player joined.", CodeStr);
@@ -89,55 +149,136 @@ namespace AmongUs.Server.Net
             player.Game = this;
 
             // Assign hostId if none is set.
-            if (_hostId == -1)
+            if (HostId == -1)
             {
-                _hostId = player.Client.Id;
+                HostId = player.Client.Id;
             }
 
-            if (_hostId == player.Client.Id)
+            if (HostId == player.Client.Id)
             {
                 player.LimboState = LimboStates.NotLimbo;
             }
 
             using (var message = MessageWriter.Get(SendOption.Reliable))
             {
-                // TODO: WriteJoinedMessage - Move to own method / class
-                message.StartMessage(7);
-                message.Write(Code);
-                message.Write(player.Client.Id);
-                message.Write(_hostId);
-                message.WritePacked(_players.Count - 1);
-            
-                foreach (var (_, p) in _players.Where(x => x.Value != player))
+                WriteJoinedGameMessage(message, player, false);
+                WriteAlterGameMessage(message, false);
+                
+                player.Client.Send(message);
+
+                BroadcastJoinMessage(message, player, true);
+            }
+        }
+
+        private void HandleJoinGameNext(ClientPlayer sender)
+        {
+            if (sender.Client.Id == HostId)
+            {
+                GameState = GameStates.NotStarted;
+                HandleJoinGameNew(sender);
+
+                using (var message = MessageWriter.Get(SendOption.Reliable))
                 {
-                    message.WritePacked(p.Client.Id);
+                    foreach (var (_, player) in _players.Where(x => x.Value != sender))
+                    {
+                        WriteJoinedGameMessage(message, player, true);
+                        WriteAlterGameMessage(message, false);
+                        player.Client.Send(message);
+                    }
                 }
+                
+                return;
+            }
+
+            if (_players.Count >= 9)
+            {
+                sender.Client.Connection.Send(new Message1DisconnectReason(DisconnectReason.GameFull));
+                return;
+            }
+
+            // Store player.
+            if (!_players.TryAdd(sender.Client.Id, sender))
+            {
+                throw new AmongUsException("Failed to add player to game.");
+            }
             
-                message.EndMessage();
+            // Assign player to this game for future packets.
+            sender.Game = this;
+            
+            // Limbo, yes.
+            sender.LimboState = LimboStates.WaitingForHost;
 
-                message.StartMessage(10);
-                message.Write(Code);
-                message.Write((sbyte)1);
-                message.Write(false); // Private / Public
-                message.EndMessage();
-                
-                player.Client.Connection.Send(message);
+            using (var packet = MessageWriter.Get(SendOption.Reliable))
+            {
+                WriteWaitForHostMessage(packet, sender, false);
+                sender.Client.Send(packet);
+
+                BroadcastJoinMessage(packet, sender, true);
+            }
+        }
+
+        private void WriteJoinedGameMessage(MessageWriter message, ClientPlayer player, bool clear)
+        {
+            if (clear)
+            {
+                message.Clear(SendOption.Reliable);
+            }
             
-                // TODO: BroadcastJoinMessage - Move to own method / class
+            message.StartMessage((byte) RequestFlag.JoinedGame);
+            message.Write(Code);
+            message.Write(player.Client.Id);
+            message.Write(HostId);
+            message.WritePacked(_players.Count - 1);
+            
+            foreach (var (_, p) in _players.Where(x => x.Value != player))
+            {
+                message.WritePacked(p.Client.Id);
+            }
+            
+            message.EndMessage();
+        }
+
+        private void WriteAlterGameMessage(MessageWriter message, bool clear)
+        {
+            if (clear)
+            {
                 message.Clear(SendOption.Reliable);
-                message.StartMessage(1);
-                message.Write(Code);
-                message.Write(player.Client.Id);
-                message.Write(_hostId);
-                message.EndMessage();
-                
-                SendToAllExcept(message, player);
             }
+            
+            message.StartMessage((byte) RequestFlag.AlterGame);
+            message.Write(Code);
+            message.Write((byte) AlterGameTags.ChangePrivacy);
+            message.Write(IsPublic);
+            message.EndMessage();
         }
 
-        private void HandleJoinGameNext(ClientPlayer player)
+        private void WriteWaitForHostMessage(MessageWriter message, ClientPlayer player, bool clear)
+        {
+            if (clear)
+            {
+                message.Clear(SendOption.Reliable);
+            }
+            
+            message.StartMessage((byte) RequestFlag.WaitForHost);
+            message.Write(Code);
+            message.Write(player.Client.Id);
+            message.EndMessage();
+        }
+        
+        private void BroadcastJoinMessage(MessageWriter message, ClientPlayer player, bool clear)
         {
-            throw new NotImplementedException();
+            if (clear)
+            {
+                message.Clear(SendOption.Reliable);
+            }
+            
+            message.StartMessage((byte) RequestFlag.JoinGame);
+            message.Write(Code);
+            message.Write(player.Client.Id);
+            message.Write(HostId);
+            message.EndMessage();
+            
+            SendToAllExcept(message, player);
         }
     }
 }
\ No newline at end of file
diff --git a/src/AmongUs.Server/Net/Request/RequestFlag.cs b/src/AmongUs.Server/Net/Request/RequestFlag.cs
deleted file mode 100644 (file)
index 4f527fb..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace AmongUs.Server.Net.Request
-{
-    public enum RequestFlag : byte
-    {
-        HostGame = 0,
-        JoinGame = 1,
-        StartGame = 2,
-        RemoveGame = 3,
-        RemovePlayer = 4,
-        GameData = 5,
-        GameDataTo = 6,
-        JoinedGame = 7,
-        EndGame = 8,
-        GetGameList = 9,
-        AlterGame = 10,
-        KickPlayer = 11,
-        WaitForHost = 12,
-        Redirect = 13,
-        ReselectServer = 14,
-        GetGameListV2 = 16,
-    }
-}
\ No newline at end of file
diff --git a/src/AmongUs.Shared/Innersloth/Data/AlterGameTags.cs b/src/AmongUs.Shared/Innersloth/Data/AlterGameTags.cs
new file mode 100644 (file)
index 0000000..a89c628
--- /dev/null
@@ -0,0 +1,7 @@
+namespace AmongUs.Shared.Innersloth.Data
+{
+    public enum AlterGameTags : byte
+    {
+        ChangePrivacy = 1
+    }
+}
\ No newline at end of file
diff --git a/src/AmongUs.Shared/Innersloth/Data/RequestFlag.cs b/src/AmongUs.Shared/Innersloth/Data/RequestFlag.cs
new file mode 100644 (file)
index 0000000..8d82426
--- /dev/null
@@ -0,0 +1,22 @@
+namespace AmongUs.Shared.Innersloth.Data
+{
+    public enum RequestFlag : byte
+    {
+        HostGame = 0,
+        JoinGame = 1,
+        StartGame = 2,
+        RemoveGame = 3,
+        RemovePlayer = 4,
+        GameData = 5,
+        GameDataTo = 6,
+        JoinedGame = 7,
+        EndGame = 8,
+        GetGameList = 9,
+        AlterGame = 10,
+        KickPlayer = 11,
+        WaitForHost = 12,
+        Redirect = 13,
+        ReselectServer = 14,
+        GetGameListV2 = 16,
+    }
+}
\ No newline at end of file
index 689b8aa817826eb42d44e1a745d7b155d9acad61..4fd19f6aedb98fb2b956332c0f9679194905ae77 100644 (file)
@@ -26,7 +26,7 @@ namespace AmongUs.Shared.Innersloth
         public int VotingTime { get; set; }
         public bool ConfirmImpostor { get; set; }
         public bool VisualTasks { get; set; }
-        public bool isDefaults { get; set; }
+        public bool IsDefaults { get; set; }
         
         public void Serialize(BinaryWriter writer, byte version)
         {
@@ -56,7 +56,7 @@ namespace AmongUs.Shared.Innersloth
                 result.KillDistance = reader.ReadByte();
                 result.DiscussionTime = reader.ReadInt32();
                 result.VotingTime = reader.ReadInt32();
-                result.isDefaults = reader.ReadBoolean();
+                result.IsDefaults = reader.ReadBoolean();
 
                 if (result.Version > 1)
                 {