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;
}
}