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()); } }
// 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 { } }
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); } }
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."); } }
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); }
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); } }
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(); }
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; } } }
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); } }
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; } } }
/// <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)); }
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)); }
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)); }
public void HandleStartGame(MessageReader message) { GameState = GameStates.Started; using (var packet = MessageWriter.Get(SendOption.Reliable)) { packet.CopyFrom(message); SendToAllExcept(packet, null); } }
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); } }
public async ValueTask SetPrivacyAsync(bool isPublic) { IsPublic = isPublic; using (var writer = MessageWriter.Get(MessageType.Reliable)) { WriteAlterGameMessage(writer, false, IsPublic); await SendToAllAsync(writer); } }
/** * 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(); }
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); }
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)); }
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); } }
/// <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)); }