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

        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            short size   = ReadInt16(readBuffer);
            int   startX = (int)ReadInt16(readBuffer);
            int   startY = (int)ReadInt16(readBuffer);

            //TODO implement the old methods
            var player = Main.player[whoAmI];

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

            var args = new HookArgs.TileSquareReceived
            {
                X          = startX,
                Y          = startY,
                Size       = size,
                readBuffer = readBuffer,
                start      = num,
            };

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

            if (args.applied > 0)
            {
                WorldGen.RangeFrame(startX, startY, startX + (int)size, startY + (int)size);
                NewNetMessage.SendData((int)Packet.TILE_SQUARE, -1, whoAmI, String.Empty, (int)size, (float)startX, (float)startY, 0f, 0);
            }

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

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

            BitsByte bitsByte6 = 0;
            BitsByte bitsByte7 = 0;

            for (int num46 = startX; num46 < startX + (int)size; num46++)
            {
                for (int num47 = startY; num47 < startY + (int)size; num47++)
                {
                    if (Main.tile[num46, num47] == null)
                    {
                        Main.tile[num46, num47] = new Tile();
                    }
                    Tile tile  = Main.tile[num46, num47];
                    bool flag5 = tile.active();
                    bitsByte6 = ReadByte(readBuffer);
                    bitsByte7 = ReadByte(readBuffer);
                    tile.active(bitsByte6[0]);
                    tile.wall = (byte)(bitsByte6[2] ? 1 : 0);
                    bool flag6 = bitsByte6[3];
                    if (Main.netMode != 2)
                    {
                        tile.liquid = (byte)(flag6 ? 1 : 0);
                    }
                    tile.wire(bitsByte6[4]);
                    tile.halfBrick(bitsByte6[5]);
                    tile.actuator(bitsByte6[6]);
                    tile.inActive(bitsByte6[7]);
                    tile.wire2(bitsByte7[0]);
                    tile.wire3(bitsByte7[1]);
                    if (bitsByte7[2])
                    {
                        tile.color(ReadByte(readBuffer));
                    }
                    if (bitsByte7[3])
                    {
                        tile.wallColor(ReadByte(readBuffer));
                    }
                    if (tile.active())
                    {
                        int type2 = (int)tile.type;
                        tile.type = ReadUInt16(readBuffer);
                        if (Main.tileFrameImportant[(int)tile.type])
                        {
                            tile.frameX = ReadInt16(readBuffer);
                            tile.frameY = ReadInt16(readBuffer);
                        }
                        else
                        {
                            if (!flag5 || (int)tile.type != type2)
                            {
                                tile.frameX = -1;
                                tile.frameY = -1;
                            }
                        }
                        byte b4 = 0;
                        if (bitsByte7[4])
                        {
                            b4 += 1;
                        }
                        if (bitsByte7[5])
                        {
                            b4 += 2;
                        }
                        if (bitsByte7[6])
                        {
                            b4 += 4;
                        }
                        tile.slope(b4);
                    }
                    if (tile.wall > 0)
                    {
                        tile.wall = ReadByte(readBuffer);
                    }
                    if (flag6)
                    {
                        tile.liquid = ReadByte(readBuffer);
                        tile.liquidType((int)ReadByte(readBuffer));
                    }
                }
            }
            WorldGen.RangeFrame(startX, startY, startX + (int)size, startY + (int)size);
            NewNetMessage.SendData((int)Packet.TILE_SQUARE, -1, whoAmI, String.Empty, (int)size, (float)startX, (float)startY, 0f, 0);
        }
//        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);
        }