private void IoLoop()
{
try {
Server.RaiseSessionConnectedEvent( this );
// try to log the player in, otherwise die.
if ( !LoginSequence() )
return;
BandwidthUseMode = Info.BandwidthUseMode;
// set up some temp variables
Packet packet = new Packet();
int pollCounter = 0,
pingCounter = 0;
// main i/o loop
while ( canSend ) {
int packetsSent = 0;
// detect player disconnect
if ( pollCounter > SocketPollInterval ) {
if ( !client.Connected ||
( client.Client.Poll( 1000, SelectMode.SelectRead ) && client.Client.Available == 0 ) ) {
if ( Info != null ) {
Logger.Log( LogType.Debug,
"Player.IoLoop: Lost connection to player {0} ({1}).", Name, IP );
} else {
Logger.Log( LogType.Debug,
"Player.IoLoop: Lost connection to unidentified player at {0}.", IP );
}
LeaveReason = LeaveReason.ClientQuit;
return;
}
if ( pingCounter > PingInterval ) {
writer.WritePing();
BytesSent++;
pingCounter = 0;
MeasureBandwidthUseRates();
}
pingCounter++;
pollCounter = 0;
if ( IsUsingWoM ) {
MessageNowPrefixed( "", "^detail.user=" + InfoCommands.GetCompassString( Position.R ) );
}
}
pollCounter++;
if ( DateTime.UtcNow.Subtract( lastMovementUpdate ) > movementUpdateInterval ) {
UpdateVisibleEntities();
lastMovementUpdate = DateTime.UtcNow;
}
// send output to player
while ( canSend && packetsSent < Server.MaxSessionPacketsPerTick ) {
if ( !priorityOutputQueue.TryDequeue( out packet ) )
if ( !outputQueue.TryDequeue( out packet ) )
break;
if ( IsDeaf && packet.OpCode == OpCode.Message )
continue;
writer.Write( packet.Data );
BytesSent += packet.Data.Length;
packetsSent++;
if ( packet.OpCode == OpCode.Kick ) {
writer.Flush();
if ( LeaveReason == LeaveReason.Unknown )
LeaveReason = LeaveReason.Kick;
return;
}
if ( DateTime.UtcNow.Subtract( lastMovementUpdate ) > movementUpdateInterval ) {
UpdateVisibleEntities();
lastMovementUpdate = DateTime.UtcNow;
}
}
// check if player needs to change worlds
if ( canSend ) {
lock ( joinWorldLock ) {
if ( forcedWorldToJoin != null ) {
while ( priorityOutputQueue.TryDequeue( out packet ) ) {
writer.Write( packet.Data );
BytesSent += packet.Data.Length;
packetsSent++;
if ( packet.OpCode == OpCode.Kick ) {
writer.Flush();
if ( LeaveReason == LeaveReason.Unknown )
LeaveReason = LeaveReason.Kick;
return;
}
}
if ( !JoinWorldNow( forcedWorldToJoin, useWorldSpawn, worldChangeReason ) ) {
Logger.Log( LogType.Warning,
"Player.IoLoop: Player was asked to force-join a world, but it was full." );
KickNow( "World is full.", LeaveReason.ServerFull );
}
forcedWorldToJoin = null;
}
}
if ( DateTime.UtcNow.Subtract( lastMovementUpdate ) > movementUpdateInterval ) {
UpdateVisibleEntities();
lastMovementUpdate = DateTime.UtcNow;
}
}
// get input from player
while ( canReceive && stream.DataAvailable ) {
byte opcode = reader.ReadByte();
switch ( ( OpCode )opcode ) {
case OpCode.Message:
if ( !ProcessMessagePacket() )
return;
break;
case OpCode.Teleport:
ProcessMovementPacket();
break;
case OpCode.SetBlockClient:
ProcessSetBlockPacket();
break;
case OpCode.Ping:
BytesReceived++;
continue;
default:
Logger.Log( LogType.SuspiciousActivity,
"Player {0} was kicked after sending an invalid opcode ({1}).",
Name, opcode );
KickNow( "Unknown packet opcode " + opcode,
LeaveReason.InvalidOpcodeKick );
return;
}
if ( DateTime.UtcNow.Subtract( lastMovementUpdate ) > movementUpdateInterval ) {
UpdateVisibleEntities();
lastMovementUpdate = DateTime.UtcNow;
}
}
Thread.Sleep( SleepDelay );
}
} catch ( IOException ) {
LeaveReason = LeaveReason.ClientQuit;
} catch ( SocketException ) {
LeaveReason = LeaveReason.ClientQuit;
#if !DEBUG
} catch ( Exception ex ) {
LeaveReason = LeaveReason.ServerError;
Logger.LogAndReportCrash( "Error in Player.IoLoop", "800Craft", ex, false );
#endif
} finally {
canQueue = false;
canSend = false;
Disconnect();
}
}