//TODO: redesign signs
        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            int start = num - 1;
            short signIndex = ReadInt16(readBuffer);
            int x = ReadInt16(readBuffer);
            int y = ReadInt16(readBuffer);

            short existing = (short)Sign.ReadSign(x, y);
            if (existing >= 0)
                signIndex = existing;

            //string SignText;
            //if (!ParseString(readBuffer, num, length - num + start, out SignText))
            //    return; // invalid characters
            var SignText = ReadString(readBuffer);

            var player = Main.player[whoAmI];

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

            var args = new HookArgs.SignTextSet
            {
                X = x,
                Y = y,
                SignIndex = signIndex,
                Text = SignText,
                OldSign = Main.sign[signIndex],
            };

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

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

            if (Main.sign[signIndex] == null) Main.sign[signIndex] = new Sign();
            Main.sign[signIndex].x = args.X;
            Main.sign[signIndex].y = args.Y;
            Sign.TextSign(signIndex, args.Text);
        }
        private static void ProcessWriteSign(int bufferId)
        {
            var buffer = NetMessage.buffer[bufferId];
            var player = Main.player[bufferId];

            int signId = (int)buffer.reader.ReadInt16();
            int x = (int)buffer.reader.ReadInt16();
            int y = (int)buffer.reader.ReadInt16();
            string text = buffer.reader.ReadString();

            string existing = null;
            if (Main.sign[signId] != null)
            {
                existing = Main.sign[signId].text;
            }

            Main.sign[signId] = new Sign();
            Main.sign[signId].x = x;
            Main.sign[signId].y = y;

            Sign.TextSign(signId, text);
            int ply = (int)buffer.reader.ReadByte();

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

            var args = new HookArgs.SignTextSet
            {
                X = x,
                Y = y,
                SignIndex = signId,
                Text = text,
                OldSign = Main.sign[signId],
            };

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

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

            if (Main.netMode == 2 && existing != text)
            {
                ply = bufferId;
                NetMessage.SendData(47, -1, bufferId, "", signId, (float)ply, 0, 0, 0, 0, 0);
            }

            if (Main.netMode == 1 && ply == Main.myPlayer && Main.sign[signId] != null)
            {
                Main.playerInventory = false;
                Main.player[Main.myPlayer].talkNPC = -1;
                Main.npcChatCornerItem = 0;
                Main.editSign = false;
                Main.PlaySound(10, -1, -1, 1);
                Main.player[Main.myPlayer].sign = signId;
                Main.npcChatText = Main.sign[signId].text;
            }
        }