void IoLoop() { short x, y, h; byte mode, type, opcode; Packet packet; int pollInterval = 200; int pollCounter = 0; int packetsSent = 0; try { LoginSequence(); canSend = true; while( !canDispose ) { Thread.Sleep( 1 ); packetsSent = 0; // detect player disconnect if( pollCounter > pollInterval ) { if( !client.Connected || (client.Client.Poll( 1000, SelectMode.SelectRead ) && client.Client.Available == 0) ) { world.log.Log( "Session.IoLoop: Lost connection to {0}.", LogType.Debug, player.name ); return; } pollCounter = 0; } pollCounter++; // send priority output to player while( canSend && priorityOutputQueue.Count > 0 && packetsSent < Server.maxSessionPacketsPerTick ) { lock( priorityQueueLock ) { packet = priorityOutputQueue.Dequeue(); } writer.Write( packet.data ); packetsSent++; if( packet.data[0] == (byte)OutputCodes.Disconnect ) { world.log.Log( "Session.IoLoop: Kick packet delivered to {0}.", LogType.Debug, player.name ); return; } } // send output to player while( canSend && outputQueue.Count > 0 && packetsSent < Server.maxSessionPacketsPerTick ) { lock( queueLock ) { packet = outputQueue.Dequeue(); } writer.Write( packet.data ); packetsSent++; if( packet.data[0] == (byte)OutputCodes.Disconnect ) { writer.Flush(); world.log.Log( "Session.IoLoop: Kick packet delivered to {0}.", LogType.Debug, player.name ); return; } } // get input from player while( canReceive && client.GetStream().DataAvailable ) { opcode = reader.ReadByte(); switch( (InputCodes)opcode ) { // Message case InputCodes.Message: reader.ReadByte(); string message = ReadString(); if( Player.CheckForIllegalChars( message ) ) { world.log.Log( "Player.ParseMessage: {0} attempted to write illegal characters in chat and was kicked.", LogType.SuspiciousActivity, player.name ); KickNow( "Illegal characters in chat." ); return; } else { player.ParseMessage( message, false ); } break; // Player movement case InputCodes.MoveRotate: reader.ReadByte(); Position newPos = new Position(); newPos.x = IPAddress.NetworkToHostOrder( reader.ReadInt16() ); newPos.h = IPAddress.NetworkToHostOrder( reader.ReadInt16() ); newPos.y = IPAddress.NetworkToHostOrder( reader.ReadInt16() ); newPos.r = reader.ReadByte(); newPos.l = reader.ReadByte(); if( newPos.h < 0 || newPos.x < -32 || newPos.x >= world.map.widthX * 32+32 || newPos.y < -32 || newPos.y > world.map.widthY * 32+32 ) { world.log.Log( player.name + " was kicked for moving out of map boundaries.", LogType.SuspiciousActivity ); world.SendToAll( player.name + " was kicked for moving out of map boundaries.", null ); KickNow( "Hacking detected: out of map boundaries." ); return; } Position delta = new Position(), oldPos = player.pos; bool posChanged, rotChanged; if( !player.isHidden ) { delta.Set( newPos.x - oldPos.x, newPos.y - oldPos.y, newPos.h - oldPos.h, newPos.r, newPos.l ); posChanged = delta.x != 0 || delta.y != 0 || delta.h != 0; rotChanged = newPos.r != oldPos.r || newPos.l != oldPos.l; if( player.isFrozen ) { if( rotChanged ) { world.SendToAll( PacketWriter.MakeRotate( player.id, newPos ), player ); player.pos.r = newPos.r; player.pos.l = newPos.l; } if( posChanged ) { SendNow( PacketWriter.MakeTeleport( 255, player.pos ) ); } } else { if( delta.FitsIntoByte() && fullPositionUpdateCounter < fullPositionUpdateInterval ) { if( posChanged && rotChanged ) { world.SendToAll( PacketWriter.MakeMoveRotate( player.id, delta ), player ); } else if( posChanged ) { world.SendToAll( PacketWriter.MakeMove( player.id, delta ), player ); } else if( rotChanged ) { world.SendToAll( PacketWriter.MakeRotate( player.id, newPos ), player ); } } else if( !delta.IsZero() && !player.isFrozen ) { world.SendToAll( PacketWriter.MakeTeleport( player.id, newPos ), player ); } player.pos = newPos; if( player.isDummySpamming ) { world.cmd.standardCommands.Dummy( player, new Command( "/dummy " + player.name ) ); } } fullPositionUpdateCounter++; if( fullPositionUpdateCounter >= fullPositionUpdateInterval ) fullPositionUpdateCounter = 0; } break; // Set tile case InputCodes.SetTile: x = IPAddress.NetworkToHostOrder( reader.ReadInt16() ); h = IPAddress.NetworkToHostOrder( reader.ReadInt16() ); y = IPAddress.NetworkToHostOrder( reader.ReadInt16() ); mode = reader.ReadByte(); type = reader.ReadByte(); if( type > 49 || x < 0 || x > world.map.widthX || y < 0 || y > world.map.widthY || h < 0 || h > world.map.height ) { world.log.Log( player.name + " was kicked for sending bad SetTile packets.", LogType.SuspiciousActivity ); world.SendToAll( player.name + " was kicked for sending bad SetTile packets.", null ); KickNow( "Hacking detected: illegal SetTile packet." ); return; } else { player.SetTile( x, y, h, mode == 1, (Block)type ); } break; } } } } catch( ThreadAbortException ) { world.log.Log( "Session.IoLoop: Thread aborted!", LogType.Error ); } catch( IOException ex ) { world.log.Log( "Session.IoLoop: {0}.", LogType.Warning, ex.Message ); } catch( SocketException ex ) { world.log.Log( "Session.IoLoop: {0}.", LogType.Warning, ex.Message ); } catch( Exception ex ) { world.log.Log( "Session.IoLoop: {0}: {1}.", LogType.Error, ex.ToString(), ex.Message ); } finally { canQueue = false; canSend = false; canDispose = true; } }
void IoLoop() { short x, y, h; byte mode, type, opcode; Packet packet; int pollInterval = 200; int pollCounter = 0; int packetsSent = 0; try { LoginSequence(); canSend = true; while (!canDispose) { Thread.Sleep(1); packetsSent = 0; // detect player disconnect if (pollCounter > pollInterval) { if (!client.Connected || (client.Client.Poll(1000, SelectMode.SelectRead) && client.Client.Available == 0)) { world.log.Log("Session.IoLoop: Lost connection to {0}.", LogType.Debug, player.name); return; } pollCounter = 0; } pollCounter++; // send priority output to player while (canSend && priorityOutputQueue.Count > 0 && packetsSent < Server.maxSessionPacketsPerTick) { lock ( priorityQueueLock ) { packet = priorityOutputQueue.Dequeue(); } writer.Write(packet.data); packetsSent++; if (packet.data[0] == (byte)OutputCodes.Disconnect) { world.log.Log("Session.IoLoop: Kick packet delivered to {0}.", LogType.Debug, player.name); return; } } // send output to player while (canSend && outputQueue.Count > 0 && packetsSent < Server.maxSessionPacketsPerTick) { lock ( queueLock ) { packet = outputQueue.Dequeue(); } writer.Write(packet.data); packetsSent++; if (packet.data[0] == (byte)OutputCodes.Disconnect) { writer.Flush(); world.log.Log("Session.IoLoop: Kick packet delivered to {0}.", LogType.Debug, player.name); return; } } // get input from player while (canReceive && client.GetStream().DataAvailable) { opcode = reader.ReadByte(); switch ((InputCodes)opcode) { // Message case InputCodes.Message: reader.ReadByte(); string message = ReadString(); if (Player.CheckForIllegalChars(message)) { world.log.Log("Player.ParseMessage: {0} attempted to write illegal characters in chat and was kicked.", LogType.SuspiciousActivity, player.name); KickNow("Illegal characters in chat."); return; } else { player.ParseMessage(message, false); } break; // Player movement case InputCodes.MoveRotate: reader.ReadByte(); Position newPos = new Position(); newPos.x = IPAddress.NetworkToHostOrder(reader.ReadInt16()); newPos.h = IPAddress.NetworkToHostOrder(reader.ReadInt16()); newPos.y = IPAddress.NetworkToHostOrder(reader.ReadInt16()); newPos.r = reader.ReadByte(); newPos.l = reader.ReadByte(); if (newPos.h < 0 || newPos.x < -32 || newPos.x >= world.map.widthX * 32 + 32 || newPos.y < -32 || newPos.y > world.map.widthY * 32 + 32) { world.log.Log(player.name + " was kicked for moving out of map boundaries.", LogType.SuspiciousActivity); world.SendToAll(player.name + " was kicked for moving out of map boundaries.", null); KickNow("Hacking detected: out of map boundaries."); return; } Position delta = new Position(), oldPos = player.pos; bool posChanged, rotChanged; if (!player.isHidden) { delta.Set(newPos.x - oldPos.x, newPos.y - oldPos.y, newPos.h - oldPos.h, newPos.r, newPos.l); posChanged = delta.x != 0 || delta.y != 0 || delta.h != 0; rotChanged = newPos.r != oldPos.r || newPos.l != oldPos.l; if (player.isFrozen) { if (rotChanged) { world.SendToAll(PacketWriter.MakeRotate(player.id, newPos), player); player.pos.r = newPos.r; player.pos.l = newPos.l; } if (posChanged) { SendNow(PacketWriter.MakeTeleport(255, player.pos)); } } else { if (delta.FitsIntoByte() && fullPositionUpdateCounter < fullPositionUpdateInterval) { if (posChanged && rotChanged) { world.SendToAll(PacketWriter.MakeMoveRotate(player.id, delta), player); } else if (posChanged) { world.SendToAll(PacketWriter.MakeMove(player.id, delta), player); } else if (rotChanged) { world.SendToAll(PacketWriter.MakeRotate(player.id, newPos), player); } } else if (!delta.IsZero() && !player.isFrozen) { world.SendToAll(PacketWriter.MakeTeleport(player.id, newPos), player); } player.pos = newPos; if (player.isDummySpamming) { world.cmd.standardCommands.Dummy(player, new Command("/dummy " + player.name)); } } fullPositionUpdateCounter++; if (fullPositionUpdateCounter >= fullPositionUpdateInterval) { fullPositionUpdateCounter = 0; } } break; // Set tile case InputCodes.SetTile: x = IPAddress.NetworkToHostOrder(reader.ReadInt16()); h = IPAddress.NetworkToHostOrder(reader.ReadInt16()); y = IPAddress.NetworkToHostOrder(reader.ReadInt16()); mode = reader.ReadByte(); type = reader.ReadByte(); if (type > 49 || x < 0 || x > world.map.widthX || y < 0 || y > world.map.widthY || h < 0 || h > world.map.height) { world.log.Log(player.name + " was kicked for sending bad SetTile packets.", LogType.SuspiciousActivity); world.SendToAll(player.name + " was kicked for sending bad SetTile packets.", null); KickNow("Hacking detected: illegal SetTile packet."); return; } else { player.SetTile(x, y, h, mode == 1, (Block)type); } break; } } } } catch (ThreadAbortException) { world.log.Log("Session.IoLoop: Thread aborted!", LogType.Error); } catch (IOException ex) { world.log.Log("Session.IoLoop: {0}.", LogType.Warning, ex.Message); } catch (SocketException ex) { world.log.Log("Session.IoLoop: {0}.", LogType.Warning, ex.Message); } catch (Exception ex) { world.log.Log("Session.IoLoop: {0}: {1}.", LogType.Error, ex.ToString(), ex.Message); } finally { canQueue = false; canSend = false; canDispose = true; } }