Example #1
0
        public void HandleKickPlayer(int playerId, bool isBan)
        {
            _players.TryGetValue(playerId, out var p);
            Logger.Information("{0} - Player {1} ({2}) has left.", CodeStr, p?.Client.Name, playerId);

            using (var message = MessageWriter.Get(SendOption.Reliable))
            {
                WriteKickPlayerMessage(message, false, playerId, isBan);
                SendToAllExcept(message, null);

                if (_players.TryRemove(playerId, out var player))
                {
                    player.Game = null;

                    if (isBan)
                    {
                        _bannedIps.Add(player.Client.Connection.EndPoint.Address);
                    }
                }

                WriteRemovePlayerMessage(message, true, playerId, isBan
                    ? DisconnectReason.Banned
                    : DisconnectReason.Kicked);
                SendToAllExcept(message, player);
            }
        }
        public void ServerExtraDataDisconnectTest()
        {
            using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296)))
                using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296)))
                {
                    MessageReader    received = null;
                    ManualResetEvent mutex    = new ManualResetEvent(false);

                    connection.Disconnected += delegate(object sender, DisconnectedEventArgs args)
                    {
                        received = args.Message;
                        mutex.Set();
                    };

                    listener.NewConnection += delegate(NewConnectionEventArgs args)
                    {
                        MessageWriter writer = MessageWriter.Get(SendOption.None);
                        writer.Write("Goodbye");
                        args.Connection.Disconnect("Testing", writer);
                    };

                    listener.Start();

                    connection.Connect();

                    mutex.WaitOne();

                    Assert.IsNotNull(received);
                    Assert.AreEqual("Goodbye", received.ReadString());
                }
        }
Example #3
0
        // Let's tell the existing players about the new player
        // And tell the new player about all the existing players
        public void AddPlayer(Player newPlayer)
        {
            var msg = MessageWriter.Get(SendOption.Reliable);

            msg.StartMessage((byte)PlayerMessageTags.PlayerJoined);
            msg.WritePacked(newPlayer.Id);
            msg.EndMessage();
            this.Broadcast(msg);

            lock (this.PlayerList)
            {
                msg.Clear(SendOption.Reliable);
                msg.StartMessage((byte)PlayerMessageTags.PlayersInGame);
                foreach (var player in this.PlayerList)
                {
                    msg.WritePacked(player.Id);
                }
                msg.EndMessage();

                this.PlayerList.Add(newPlayer);
            }

            try
            {
                newPlayer.Connection.Send(msg);
            }
            catch { }
        }
Example #4
0
        private async ValueTask HandleJoinGameNext(ClientPlayer sender, bool isNew)
        {
            _logger.LogInformation("{0} - Player {1} ({2}) is rejoining.", Code, sender.Client.Name, sender.Client.Id);

            // Add player to the game.
            if (isNew)
            {
                await PlayerAdd(sender);
            }

            // Check if the host joined and let everyone join.
            if (sender.Client.Id == HostId)
            {
                GameState = GameStates.NotStarted;

                // Spawn the host.
                await HandleJoinGameNew(sender, false);

                // Pull players out of limbo.
                await CheckLimboPlayers();

                return;
            }

            sender.Limbo = LimboStates.WaitingForHost;

            using (var packet = MessageWriter.Get(MessageType.Reliable))
            {
                WriteWaitForHostMessage(packet, false, sender);

                await SendToAsync(packet, sender.Client.Id);
                await BroadcastJoinMessage(packet, true, sender);
            }
        }
Example #5
0
        private void HandleJoinGameNew(ClientPlayer sender)
        {
            Logger.Information("{0} - Player {1} ({2}) is joining.", CodeStr, sender.Client.Name, sender.Client.Id);

            // Store player.
            if (!_players.TryAdd(sender.Client.Id, sender))
            {
                throw new AmongUsException("Failed to add player to game.");
            }

            // Assign player to this game for future packets.
            sender.Game = this;

            // Assign hostId if none is set.
            if (HostId == -1)
            {
                HostId = sender.Client.Id;
            }

            if (HostId == sender.Client.Id)
            {
                sender.LimboState = LimboStates.NotLimbo;
            }

            using (var message = MessageWriter.Get(SendOption.Reliable))
            {
                WriteJoinedGameMessage(message, false, sender);
                WriteAlterGameMessage(message, false);

                sender.Client.Send(message);

                BroadcastJoinMessage(message, true, sender);
            }
        }
        public void ServerExtraDataDisconnectTest()
        {
            using (ThreadLimitedUdpConnectionListener listener = this.CreateListener(2, new IPEndPoint(IPAddress.Any, 4296), new TestLogger()))
                using (UdpConnection connection = this.CreateConnection(new IPEndPoint(IPAddress.Loopback, 4296), new TestLogger()))
                {
                    string           received = null;
                    ManualResetEvent mutex    = new ManualResetEvent(false);

                    connection.Disconnected += delegate(object sender, DisconnectedEventArgs args)
                    {
                        // We don't own the message, we have to read the string now
                        received = args.Message.ReadString();
                        mutex.Set();
                    };

                    listener.NewConnection += delegate(NewConnectionEventArgs args)
                    {
                        MessageWriter writer = MessageWriter.Get(SendOption.None);
                        writer.Write("Goodbye");
                        args.Connection.Disconnect("Testing", writer);
                    };

                    listener.Start();

                    connection.Connect();

                    mutex.WaitOne(5000);

                    Assert.IsNotNull(received);
                    Assert.AreEqual("Goodbye", received);
                }
        }
        public void UdpUnreliableMessageSendTest()
        {
            byte[] TestData = new byte[] { 1, 2, 3, 4, 5, 6 };
            using (ThreadLimitedUdpConnectionListener listener = this.CreateListener(2, new IPEndPoint(IPAddress.Any, 4296), new TestLogger()))
                using (UdpConnection connection = this.CreateConnection(new IPEndPoint(IPAddress.Loopback, 4296), new TestLogger()))
                {
                    MessageReader output = null;
                    listener.NewConnection += delegate(NewConnectionEventArgs e)
                    {
                        e.Connection.DataReceived += delegate(DataReceivedEventArgs evt)
                        {
                            output = evt.Message.Duplicate();
                        };
                    };

                    listener.Start();
                    connection.Connect();

                    for (int i = 0; i < 4; ++i)
                    {
                        var msg = MessageWriter.Get(SendOption.None);
                        msg.Write(TestData);
                        connection.Send(msg);
                        msg.Recycle();
                    }

                    Thread.Sleep(10);
                    for (int i = 0; i < TestData.Length; ++i)
                    {
                        Assert.AreEqual(TestData[i], output.ReadByte());
                    }
                }
        }
        private void OnNewConnection(NewConnectionEventArgs e)
        {
            try
            {
                // Handshake.
                var clientVersion = e.HandshakeData.ReadInt32();
                var clientName    = e.HandshakeData.ReadString();

                e.HandshakeData.Recycle();

                if (clientVersion != 50516550)
                {
                    using (var packet = MessageWriter.Get(SendOption.Reliable))
                    {
                        Message01JoinGame.SerializeError(packet, false, DisconnectReason.IncorrectVersion);
                        e.Connection.Send(packet);
                    }
                    return;
                }

                // Create client.
                _clientManager.Create(clientName, e.Connection);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error in new connection.");
            }
        }
Example #9
0
            public static bool Prefix(out Il2CppStructArray <byte> __result)
            {
                var handshake = MessageWriter.Get(SendOption.Reliable);

                var plugins = IL2CPPChainloader.Instance.Plugins;

                if (plugins.Values
                    .Select(pluginInfo => pluginInfo.Instance.GetType().GetCustomAttribute <ReactorPluginSideAttribute>())
                    .Any(attribute => attribute == null || attribute.Side == PluginSide.Both))
                {
                    handshake.Write(-1);
                }

                handshake.Write(Constants.GetBroadcastVersion());
                handshake.Write(SaveManager.PlayerName);

                handshake.WritePacked(plugins.Count);

                foreach (var plugin in plugins)
                {
                    handshake.Write(plugin.Key);
                    handshake.Write(plugin.Value.Metadata.Version.ToString());
                }

                __result = handshake.ToByteArray(false);
                handshake.Recycle();

                return(false);
            }
Example #10
0
        private void HandleJoinGameNext(ClientPlayer sender)
        {
            Logger.Information("{0} - Player {1} ({2}) is rejoining.", CodeStr, sender.Client.Name, sender.Client.Id);

            // Add player to the game.
            if (sender.Game == null)
            {
                PlayerAdd(sender);
            }

            // Check if the host joined and let everyone join.
            if (sender.Client.Id == HostId)
            {
                GameState = GameStates.NotStarted;

                // Spawn the host.
                HandleJoinGameNew(sender);

                // Pull players out of limbo.
                CheckLimboPlayers();
                return;
            }

            sender.Limbo = LimboStates.WaitingForHost;

            using (var packet = MessageWriter.Get(SendOption.Reliable))
            {
                WriteWaitForHostMessage(packet, false, sender);
                sender.Client.Send(packet);

                BroadcastJoinMessage(packet, true, sender);
            }
        }
Example #11
0
        private async ValueTask InitGameDataAsync(ClientPlayer player)
        {
            if (Interlocked.Exchange(ref _gamedataInitialized, 1) != 0)
            {
                return;
            }

            /*
             * The Among Us client on 20.9.22i spawns some components on the host side and
             * only spawns these on other clients when someone else connects. This means that we can't
             * parse data until someone connects because we don't know which component belongs to the NetId.
             *
             * We solve this by spawning a fake player and removing the player when the spawn GameData
             * is received in HandleGameDataAsync.
             */
            using (var message = MessageWriter.Get(MessageType.Reliable))
            {
                // Spawn a fake player.
                Message01JoinGameS2C.SerializeJoin(message, false, Code, FakeClientId, HostId);

                message.StartMessage(MessageFlags.GameData);
                message.Write(Code);
                message.StartMessage(GameDataTag.SceneChangeFlag);
                message.WritePacked(FakeClientId);
                message.Write("OnlineGame");
                message.EndMessage();
                message.EndMessage();

                await player.Client.Connection.SendAsync(message);
            }
        }
        public void TestAcksForNotReceivedMessages()
        {
            List <MessageReader> messagesReceived = new List <MessageReader>();

            UdpConnectionTestHarness dut = new UdpConnectionTestHarness();

            dut.DataReceived += evt =>
            {
                messagesReceived.Add(evt.Message);
            };

            MessageWriter data = MessageWriter.Get(SendOption.Reliable);

            SetReliableId(data, 1);
            dut.Test_Receive(data);

            SetReliableId(data, 3);
            dut.Test_Receive(data);

            MessageReader ackPacket = dut.BytesSent[1];

            // Must be ack
            Assert.AreEqual(4, ackPacket.Length);

            byte recentPackets = ackPacket.Buffer[3];

            // Last packet was not received
            Assert.AreEqual(0, recentPackets & 1);
            // The packet before that was.
            Assert.AreEqual(1, (recentPackets >> 1) & 1);
        }
        public void TestReliableWrapOffByOne()
        {
            List <MessageReader> messagesReceived = new List <MessageReader>();

            UdpConnectionTestHarness dut = new UdpConnectionTestHarness();

            dut.DataReceived += evt =>
            {
                messagesReceived.Add(evt.Message);
            };

            MessageWriter data = MessageWriter.Get(SendOption.Reliable);

            Assert.AreEqual(ushort.MaxValue, dut.ReliableReceiveLast);

            SetReliableId(data, 10);
            dut.Test_Receive(data);

            // This message may not be received if there is an off-by-one error when marking missed pkts up to 10.
            SetReliableId(data, 9);
            dut.Test_Receive(data);

            // Both messages should be received.
            Assert.AreEqual(2, messagesReceived.Count);
            messagesReceived.Clear();

            Assert.AreEqual(2, dut.BytesSent.Count);
            dut.BytesSent.Clear();
        }
Example #14
0
        public void HandleRemovePlayer(int playerId, DisconnectReason reason)
        {
            if (_players.TryRemove(playerId, out var player))
            {
                player.Game = null;
            }

            Logger.Information("{0} - Player {1} ({2}) has left.", CodeStr, player?.Client.Name, playerId);

            // Game is empty, remove it.
            if (_players.Count == 0)
            {
                GameState = GameStates.Destroyed;

                // Remove instance reference.
                _gameManager.Remove(Code);
                return;
            }

            // Host migration.
            if (HostId == playerId)
            {
                var newHost = _players.First().Value;
                HostId = newHost.Client.Id;
                Logger.Information("{0} - Assigned {1} ({2}) as new host.", CodeStr, newHost.Client.Name, newHost.Client.Id);
            }

            using (var packet = MessageWriter.Get(SendOption.Reliable))
            {
                WriteRemovePlayerMessage(packet, false, playerId, reason);
                SendToAllExcept(packet, player);
            }
        }
        private void OnMessageReceived(MessageReader message)
        {
            var flag = message.Tag;

            Logger.Verbose("Server got {0}.", flag);

            switch (flag)
            {
            case MessageFlags.HostGame:
            {
                using (var packet = MessageWriter.Get(SendOption.Reliable))
                {
                    Message13Redirect.Serialize(packet, false, _nodeProvider.Get());
                    _connection.Send(packet);
                }
                break;
            }

            case MessageFlags.JoinGame:
            {
                Message01JoinGame.Deserialize(message,
                                              out var gameCode,
                                              out var unknown);

                using (var packet = MessageWriter.Get(SendOption.Reliable))
                {
                    var endpoint = _nodeLocator.Find(GameCode.IntToGameName(gameCode));
                    if (endpoint == null)
                    {
                        Message01JoinGame.SerializeError(packet, false, DisconnectReason.GameMissing);
                    }
                    else
                    {
                        Message13Redirect.Serialize(packet, false, endpoint);
                    }

                    _connection.Send(packet);
                }
                break;
            }

            case MessageFlags.GetGameListV2:
            {
                // TODO: Implement.
                using (var packet = MessageWriter.Get(SendOption.Reliable))
                {
                    Message01JoinGame.SerializeError(packet, false, DisconnectReason.Custom, DisconnectMessages.NotImplemented);
                    _connection.Send(packet);
                }
                break;
            }

            default:
            {
                Logger.Warning("Received unsupported message flag on the redirector ({0}).", flag);
                break;
            }
            }
        }
Example #16
0
            public static void Postfix([HarmonyArgument(0)] NewConnectionEventArgs evt)
            {
                var writer = MessageWriter.Get(SendOption.Reliable);

                ModdedHandshakeS2C.Serialize(writer, "Among Us", Application.version, 0);
                evt.Connection.Send(writer);
                writer.Recycle();
            }
 public void SendDisconnectReason(DisconnectReason reason, string message = null)
 {
     using (var packet = MessageWriter.Get(SendOption.Reliable))
     {
         Message01JoinGame.SerializeError(packet, false, reason, message);
         Client.Connection.Send(packet);
     }
 }
Example #18
0
        public override async ValueTask HandleMessageAsync(IMessageReader reader, MessageType messageType)
        {
            var flag = reader.Tag;

            Logger.Verbose("Server got {0}.", flag);

            switch (flag)
            {
            case MessageFlags.HostGame:
            {
                using var packet = MessageWriter.Get(MessageType.Reliable);
                Message13RedirectS2C.Serialize(packet, false, _nodeProvider.Get());
                await Connection.SendAsync(packet);

                break;
            }

            case MessageFlags.JoinGame:
            {
                Message01JoinGameC2S.Deserialize(
                    reader,
                    out var gameCode,
                    out _);

                using var packet = MessageWriter.Get(MessageType.Reliable);
                var endpoint = await _nodeLocator.FindAsync(GameCodeParser.IntToGameName(gameCode));

                if (endpoint == null)
                {
                    Message01JoinGameS2C.SerializeError(packet, false, DisconnectReason.GameMissing);
                }
                else
                {
                    Message13RedirectS2C.Serialize(packet, false, endpoint);
                }

                await Connection.SendAsync(packet);

                break;
            }

            case MessageFlags.GetGameListV2:
            {
                // TODO: Implement.
                using var packet = MessageWriter.Get(MessageType.Reliable);
                Message01JoinGameS2C.SerializeError(packet, false, DisconnectReason.Custom, DisconnectMessages.NotImplemented);
                await Connection.SendAsync(packet);

                break;
            }

            default:
            {
                Logger.Warning("Received unsupported message flag on the redirector ({0}).", flag);
                break;
            }
            }
        }
Example #19
0
        /// <summary>
        ///     Triggered when the connected client requests the game listing.
        /// </summary>
        /// <param name="options">
        ///     All options given.
        ///     At this moment, the client can only specify the map, impostor count and chat language.
        /// </param>
        private ValueTask OnRequestGameListAsync(GameOptionsData options)
        {
            using MessageWriter? message = MessageWriter.Get(MessageType.Reliable);

            var games = _gameManager.FindListings((MapFlags)options.Map, options.NumImpostors, options.Keywords);

            Message16GetGameListS2C.Serialize(message, games);

            return(Connection.SendAsync(message));
        }
Example #20
0
        public async ValueTask HandleAlterGame(IMessageReader message, IClientPlayer sender, bool isPublic)
        {
            IsPublic = isPublic;

            using var packet = MessageWriter.Get(MessageType.Reliable);
            message.CopyTo(packet);
            await SendToAllExceptAsync(packet, sender.Client.Id);

            await _eventManager.CallAsync(new GameAlterEvent(this, isPublic));
        }
Example #21
0
        public async ValueTask HandleStartGame(IMessageReader message)
        {
            GameState = GameStates.Starting;

            using var packet = MessageWriter.Get(MessageType.Reliable);
            message.CopyTo(packet);
            await SendToAllAsync(packet);

            await _eventManager.CallAsync(new GameStartingEvent(this));
        }
Example #22
0
        public void HandleStartGame(MessageReader message)
        {
            GameState = GameStates.Started;

            using (var packet = MessageWriter.Get(SendOption.Reliable))
            {
                packet.CopyFrom(message);
                SendToAllExcept(packet, null);
            }
        }
Example #23
0
        public void HandleAlterGame(MessageReader message, ClientPlayer sender, bool isPublic)
        {
            IsPublic = isPublic;

            using (var packet = MessageWriter.Get(SendOption.Reliable))
            {
                packet.CopyFrom(message);
                SendToAllExcept(packet, sender);
            }
        }
        /// <summary>
        ///     Triggered when the connected client requests the game listing.
        /// </summary>
        /// <param name="options">
        ///     All options given.
        ///     At this moment, the client can only specify the map, impostor count and chat language.
        /// </param>
        public void OnRequestGameList(GameOptionsData options)
        {
            using (var message = MessageWriter.Get(SendOption.Reliable))
            {
                var games = _gameManager.FindListings((MapFlags)options.MapId, options.NumImpostors, options.Keywords);

                Message16GetGameListV2.Serialize(message, games);

                Client.Send(message);
            }
        }
Example #25
0
        public async ValueTask SetPrivacyAsync(bool isPublic)
        {
            IsPublic = isPublic;

            using (var writer = MessageWriter.Get(MessageType.Reliable))
            {
                WriteAlterGameMessage(writer, false, IsPublic);

                await SendToAllAsync(writer);
            }
        }
Example #26
0
        /**
         * Helper method that fetches a new Reliable message writer for the specified connection,
         * invokes the specified write method, then sends the resulting message to the server.
         * Any errors during message sending will be ignored.
         */
        public static void SendReliableMessage(this UdpClientConnection connection, Action <MessageWriter> write)
        {
            var writer = MessageWriter.Get(SendOption.Reliable);

            try
            {
                write(writer);
                connection.Send(writer);
            } catch { /* Ignored */ Console.Out.WriteLine("Oops"); }
            writer.Recycle();
        }
Example #27
0
        public async ValueTask DisconnectAsync(DisconnectReason reason, string?message = null)
        {
            if (!Connection.IsConnected)
            {
                return;
            }

            using var writer = MessageWriter.Get();
            MessageDisconnect.Serialize(writer, true, reason, message);

            await Connection.DisconnectAsync(message ?? reason.ToString(), writer);
        }
Example #28
0
        private ValueTask ConnectionOnNewConnection(NewConnectionEventArgs e)
        {
            MessageHandshake.Deserialize(e.HandshakeData, out var clientVersion, out var platform, out var clientId);

            _logger.LogTrace("New authentication request: {clientVersion}, {platform}, {clientId}", clientVersion, platform, clientId);

            using var writer = MessageWriter.Get(MessageType.Reliable);

            writer.StartMessage(1);
            Message01Complete.Serialize(writer, (uint)RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue));
            writer.EndMessage();

            return(e.Connection.SendAsync(writer));
        }
Example #29
0
        private async ValueTask CheckLimboPlayers()
        {
            using var message = MessageWriter.Get(MessageType.Reliable);

            foreach (var(_, player) in _players.Where(x => x.Value.Limbo == LimboStates.WaitingForHost))
            {
                WriteJoinedGameMessage(message, true, player);
                WriteAlterGameMessage(message, false, IsPublic);

                player.Limbo = LimboStates.NotLimbo;

                await SendToAsync(message, player.Client.Id);
            }
        }
Example #30
0
        /// <summary>
        ///     Triggered when the connected client requests the game listing.
        /// </summary>
        /// <param name="options">
        ///     All options given.
        ///     At this moment, the client can only specify the map, impostor count and chat language.
        /// </param>
        private ValueTask OnRequestGameListAsync(GameOptionsData options)
        {
            using var message = MessageWriter.Get(MessageType.Reliable);

            var games = _gameManager.FindListings((MapFlags)options.MapId, options.NumImpostors, options.Keywords);

            var skeldGameCount  = _gameManager.GetGameCount(MapFlags.Skeld);
            var miraHqGameCount = _gameManager.GetGameCount(MapFlags.MiraHQ);
            var polusGameCount  = _gameManager.GetGameCount(MapFlags.Polus);

            Message16GetGameListS2C.Serialize(message, skeldGameCount, miraHqGameCount, polusGameCount, games);

            return(Connection.SendAsync(message));
        }