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