//        static long sameTiles = 0;
//        static long diffTiles = 0;

        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            short size = BitConverter.ToInt16(readBuffer, num);
            int   left = BitConverter.ToInt32(readBuffer, num + 2);
            int   top  = BitConverter.ToInt32(readBuffer, num + 6);

            num += 10;
            var slot = NetPlay.slots[whoAmI];

            var start = num;

            var setting = Program.properties.TileSquareMessages;

            if (setting == "rectify")
            {
                if (size > 7)
                {
                    Logging.ProgramLog.Debug.Log("{0}: Ignoring tile square of size {1}", whoAmI, size);
                    return;
                }

                //Logging.ProgramLog.Debug.Log ("{0}: TILE_SQUARE at {1}, {2}", whoAmI, left, top);

                bool different = false;
                for (int x = left; x < left + (int)size; x++)
                {
                    for (int y = top; y < top + (int)size; y++)
                    {
                        TileData tile = Main.tile.At(x, y).Data;

                        byte b9 = readBuffer[num++];

                        bool wasActive = tile.Active;

                        tile.Active = ((b9 & 1) == 1);
                        different  |= tile.Active != wasActive;

                        if ((b9 & 2) == 2)
                        {
                            different   |= tile.Lighted == false;
                            tile.Lighted = true;
                        }

                        if (tile.Active)
                        {
                            int wasType = (int)tile.Type;
                            tile.Type = readBuffer[num++];

                            different |= tile.Type != wasType;

                            short framex = tile.FrameX;
                            short framey = tile.FrameY;

                            if (tile.Type >= Main.MAX_TILE_SETS)
                            {
                                slot.Kick("Invalid tile received from client.");
                                return;
                            }

                            if (Main.tileFrameImportant[(int)tile.Type])
                            {
                                framex = BitConverter.ToInt16(readBuffer, num);
                                num   += 2;
                                framey = BitConverter.ToInt16(readBuffer, num);
                                num   += 2;
                            }
                            else if (!wasActive || (int)tile.Type != wasType)
                            {
                                framex = -1;
                                framey = -1;
                            }

                            different |= (framex != tile.FrameX) || (framey != tile.FrameY);
                        }

                        if ((b9 & 4) == 4)
                        {
                            different |= tile.Wall == 0;
                            different |= tile.Wall != readBuffer[num++];
                        }

                        if ((b9 & 8) == 8)
                        {
                            // TODO: emit a liquid event
                            different |= tile.Liquid != readBuffer[num++];
                            different |= (tile.Lava ? 1 : 0) != readBuffer[num++];
                        }

                        tile.Wire = (b9 & 16) == 16;

                        if (different)
                        {
                            break;
                        }
                    }
                }

                //Logging.ProgramLog.Debug.Log ("TileSquare({0}): {1}", size, different);
//				if (different)
//				{
//					System.Threading.Interlocked.Add (ref diffTiles, size);
//					if (size != 3)
//						Logging.ProgramLog.Debug.Log ("{0}: TileSquare({1}): {2:0.0} ({3})", whoAmI, size, diffTiles * 100.0 / (sameTiles + diffTiles), diffTiles);
//				}
//				else
//				{
//					System.Threading.Interlocked.Add (ref sameTiles, size);
//					//Logging.ProgramLog.Debug.Log ("{0}: same TileSquare({1}): {2:0.0} ({3})", whoAmI, size, diffTiles * 100.0 / (sameTiles + diffTiles), diffTiles);
//				}

                if (different)
                {
                    NetMessage.SendTileSquare(whoAmI, left, top, size, false);
                }
                return;
            }
            else if (setting == "ignore")
            {
                //if (size == 1) Logging.ProgramLog.Debug.Log ("{0}: TileSquare({1}) from {2}", whoAmI, size, Main.players[whoAmI].Name);
                return;
            }

            var player = Main.players[whoAmI];

            var ctx = new HookContext
            {
                Sender     = player,
                Player     = player,
                Connection = player.Connection
            };

            var args = new HookArgs.TileSquareReceived
            {
                X          = left, Y = top, Size = size,
                readBuffer = readBuffer,
                start      = start,
            };

            HookPoints.TileSquareReceived.Invoke(ref ctx, ref args);

            if (args.applied > 0)
            {
                WorldModify.RangeFrame(null, null, left, top, left + (int)size, top + (int)size);
                NetMessage.SendData(Packet.TILE_SQUARE, -1, whoAmI, "", (int)size, (float)left, (float)top);
            }

            if (ctx.CheckForKick() || ctx.Result == HookResult.IGNORE)
            {
                return;
            }

            args.ForEach(player, this.EachTile);
        }