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