void ReceiveMethod(IAsyncResult result) { byte[] data = new byte[0]; IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 15000); try { data = Client.EndReceive(result, ref RemoteIpEndPoint); } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.ConnectionReset && connected) { RemoveClient(); } } catch { } try { DateTime now = DateTime.Now; Client.BeginReceive(ReceiveMethod, null); if (data.Length > 0) { switch ((PkgType)data[0]) { case PkgType.ACK: { if (data.Length != 6) { break; } PkgType ackType = (PkgType)data[1]; UInt32 ackIndx = BitConverter.ToUInt32(data, 2); lock (PkgQueue) { for (int i = PkgQueue.Count - 1; i >= 0; i--) { Pkg pkg = PkgQueue[i]; if (pkg.Type == ackType && pkg.Index == ackIndx) { if (pkg.Type == PkgType.Ping) { for (int j = 1; j < ping.Length; j++) { ping[j - 1] = j; } ping[ping.Length - 1] = (int)(now - pkg.Time).TotalMilliseconds; } else if (pkg.Type == PkgType.LevelInfo) { // CONNECTED CLIENT connected = true; remote = RemoteIpEndPoint; Game.Paddles[1] = new Paddle(1); // SEND other data; SendGameState(); SendBallData(); SendPaddleData(1); SendPaddleData(0); } PkgQueue.RemoveAt(i); unAckCount = 0; break; } } } break; } case PkgType.Ping: { if (data.Length == 5) { Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6, RemoteIpEndPoint); } break; } case PkgType.ServerInfo: { byte[] response = new byte[3]; response[0] = data[0]; response[1] = 0; if (connected) { response[2] = 0; } else { response[2] = 1; } Client.Send(response, response.Length, RemoteIpEndPoint); break; } case PkgType.Greet: { if (connected && !remote.Equals(RemoteIpEndPoint)) { SendReject(RemoteIpEndPoint, 0); } else if (data.Length == 5) { // send ACK Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6, RemoteIpEndPoint); // Send back LvlInfo and wait for ACK to finish connecting SendLvlData(RemoteIpEndPoint); } break; } case PkgType.PaddleInfo: { if (connected && remote.Equals(RemoteIpEndPoint) && data.Length == 5) { Game.Paddles[1].Position = 1f - BitConverter.ToSingle(data, 1); } break; } case PkgType.Disconnect: { if (connected && remote.Equals(RemoteIpEndPoint)) { RemoveClient(); } break; } } } } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.ConnectionReset && connected) { RemoveClient(); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }
void ReceiveMethod(IAsyncResult result) { byte[] data = new byte[0]; IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 15000); try { data = Client.EndReceive(result, ref RemoteIpEndPoint); } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.ConnectionReset && connected) { Disconnect("Lost connection to server"); } } catch { } try { DateTime now = DateTime.Now; Client.BeginReceive(ReceiveMethod, null); if (data.Length > 0) { // Console.WriteLine("[{1}] {0}", (PkgType)data[0], RemoteIpEndPoint.Address); switch ((PkgType)data[0]) { case PkgType.ACK: { if (data.Length != 6) { break; } PkgType ackType = (PkgType)data[1]; UInt32 ackIndx = BitConverter.ToUInt32(data, 2); // Console.WriteLine("[ACK] {0} Id:{1}", ackType.ToString(), ackIndx); lock (PkgQueue) { for (int i = PkgQueue.Count - 1; i >= 0; i--) { Pkg pkg = PkgQueue[i]; if (pkg.Type == ackType && pkg.Index == ackIndx) { if (pkg.Type == PkgType.Ping) { for (int j = 1; j < ping.Length; j++) { ping[j - 1] = j; } ping[ping.Length - 1] = (int)(now - pkg.Time).TotalMilliseconds; } else if (pkg.Type == PkgType.Greet) { // conected to server, server will send lvl info to finish connecting connected = true; remote = RemoteIpEndPoint; } PkgQueue.RemoveAt(i); break; } } } break; } case PkgType.Ping: { if (data.Length == 5) { Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6); } break; } case PkgType.LevelInfo: { if (connected && remote.Equals(RemoteIpEndPoint)) { UInt32 pckIndex = BitConverter.ToUInt32(data, 1); if (pckIndex > RecIndex[PkgType.LevelInfo]) { RecIndex[PkgType.LevelInfo] = pckIndex; Game.Lives = data[5]; Game.score = BitConverter.ToInt32(data, 6); byte[] lvldata = new byte[data.Length - 10]; Array.Copy(data, 10, lvldata, 0, lvldata.Length); Game.LevelFromBytes(lvldata); Game.State = Play.PlayState.Playing; if (Main.Audio.State == 2) { Main.Audio.NextSong(); } else { Main.Audio.State = 2; } Game.NextBG(); Game.gui.ClearChildren(); } // send back ACK Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6); } break; } case PkgType.BallInfo: { if (connected && remote.Equals(RemoteIpEndPoint) && Game.level != null) { int index = 1; UInt32 pckIndx = BitConverter.ToUInt32(data, index); if (pckIndx > RecIndex[PkgType.BallInfo]) { RecIndex[PkgType.BallInfo] = pckIndx; index += 4; byte ballcount = data[index++]; Ball[] balls = new Ball[ballcount]; int[] ballCollisionIndices = new int[ballcount]; for (int i = 0; i < ballcount; i++) { byte type = data[index++]; bool touched = BitConverter.ToBoolean(data, index++); float size = BitConverter.ToSingle(data, index); index += 4; float speed = BitConverter.ToSingle(data, index); index += 4; Vector2 pos = new Vector2(1f - BitConverter.ToSingle(data, index), 1f - BitConverter.ToSingle(data, index + 4)); // read and invert index += 8; Vector2 vel = new Vector2(BitConverter.ToSingle(data, index), BitConverter.ToSingle(data, index + 4)) * -1; // read and invert index += 8; pos += vel * speed * Ping / 2000f; // modify position by half ping time to compensate for lag Ball ball = new Ball() { Index = (byte)i, Position = pos, Velocity = vel, Size = size, Type = type, Speed = speed, TouchedLast = !touched }; ball.NoCollisionPaddle = BitConverter.ToBoolean(data, index++); // ball no-collision data, save index for procesing ballCollisionIndices[i] = index; int count = BitConverter.ToInt32(data, index); index += 4; index += count; // skip ahead count = BitConverter.ToInt32(data, index); index += 4; for (int b = 0; b < count; b++) { int brickID = BitConverter.ToInt32(data, index); index += 4; ball.NoCollisionBrick.Add(Game.level.Blocks[brickID]); } balls[i] = ball; } // now process balls no-collision data; for (int i = 0; i < ballcount; i++) { int dataIndex = ballCollisionIndices[i]; int count = BitConverter.ToInt32(data, dataIndex); dataIndex += 4; for (int b = 0; b < count; b++) { int ballIndex = data[dataIndex++]; balls[i].NoCollisionBall.Add(balls[ballIndex]); } } Game.Balls = balls; } // sent back ACK Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6); } break; } case PkgType.PaddleInfo: { if (connected && remote.Equals(RemoteIpEndPoint) && data.Length == 12) { UInt32 pckIndex = BitConverter.ToUInt32(data, 1); byte paddleID = data[5]; if (paddleID == 0) // invert paddle ids { paddleID = 1; } else { paddleID = 0; } if (paddleID == 0) { // sent back ACK Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6); if (pckIndex > RecIndex[PkgType.PaddleInfo]) { RecIndex[PkgType.PaddleInfo] = pckIndex; } else { break; } } if (Game.Paddles[paddleID] == null) { Game.Paddles[paddleID] = new Paddle(0); } Game.Paddles[paddleID].Position = 1f - BitConverter.ToSingle(data, 6); // invert position Game.Paddles[paddleID].Length = data[10]; Game.Paddles[paddleID].Color = data[11]; } break; } case PkgType.BrickInfo: { if (connected && remote.Equals(RemoteIpEndPoint) && Game.level != null) // if level data havent been received yet, dont send ACK and server will resend pkg. { UInt32 pckIndex = BitConverter.ToUInt32(data, 1); // apply only the latest brick info if (pckIndex > RecIndex[PkgType.BrickInfo]) { RecIndex[PkgType.BrickInfo] = pckIndex; int index = BitConverter.ToInt32(data, 5); // extract x y coordinates from index int x = index % Game.level.Width; int y = index / Game.level.Width; // invert x y index = (Game.level.Width - 1 - x) + (Game.level.Height - 1 - y) * Game.level.Width; byte str = data[9]; byte color = data[10]; if (str == 0) { Game.level.Blocks[index] = null; } else if (Game.level.Blocks[index] == null) { Game.level.Blocks[index] = new Brick(index, color, str); } else { Game.level.Blocks[index].Color = color; Game.level.Blocks[index].Strength = str; } } // send back ACK Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6); } break; } case PkgType.LifeInfo: { if (connected && remote.Equals(RemoteIpEndPoint) && data.Length == 6) { UInt32 pkgIndex = BitConverter.ToUInt32(data, 1); if (pkgIndex > RecIndex[PkgType.LifeInfo]) { RecIndex[PkgType.LifeInfo] = pkgIndex; Game.Lives = data[5]; } // send back ACK Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6); } break; } case PkgType.DropInfo: { if (connected && remote.Equals(RemoteIpEndPoint)) { int index = 1; UInt32 pckIndx = BitConverter.ToUInt32(data, index); if (pckIndx > RecIndex[PkgType.DropInfo]) { RecIndex[PkgType.DropInfo] = pckIndx; index += 4; byte dropcount = data[index++]; List <Drop> drops = new List <Drop>(); for (int i = 0; i < dropcount; i++) { byte type = data[index++]; Vector2 pos = new Vector2(1f - BitConverter.ToSingle(data, index), 1f - BitConverter.ToSingle(data, index + 4)); // read and invert index += 8; Vector2 vel = new Vector2(BitConverter.ToSingle(data, index), BitConverter.ToSingle(data, index + 4)) * -1; // read and invert index += 8; pos += vel * Ping / 2000f; // modify position by half ping time to compensate for lag drops.Add(new Drop() { Type = (DropType)type, Position = pos, Velocity = vel }); } Game.Drops = drops; } // sent back ACK Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6); } break; } case PkgType.Disconnect: { if (connected && remote.Equals(RemoteIpEndPoint)) { Disconnect("Server has disconnected"); } break; } case PkgType.GameState: { if (connected && remote.Equals(RemoteIpEndPoint) && data.Length == 6) { UInt32 pkgIndex = BitConverter.ToUInt32(data, 1); if (pkgIndex > RecIndex[PkgType.GameState]) { RecIndex[PkgType.GameState] = pkgIndex; Game.State = (Play.PlayState)data[5]; } // sent back ACK Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6); } break; } case PkgType.Score: { if (connected && remote.Equals(RemoteIpEndPoint) && data.Length == 9) { UInt32 pkgIndex = BitConverter.ToUInt32(data, 1); if (pkgIndex > RecIndex[PkgType.Score]) { RecIndex[PkgType.Score] = pkgIndex; Game.score = BitConverter.ToInt32(data, 5); } // sent back ACK Client.Send(new byte[] { (byte)PkgType.ACK, data[0], data[1], data[2], data[3], data[4] }, 6); } break; } case PkgType.Reject: { if (!connected) { rejected = true; } break; } } } } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.ConnectionReset && connected) { Disconnect("Lost connection to server"); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }