--- a/net/minecraft/world/level/block/entity/TileEntitySign.java
+++ b/net/minecraft/world/level/block/entity/TileEntitySign.java
@@ -25,7 +25,7 @@
 import net.minecraft.world.phys.Vec2F;
 import net.minecraft.world.phys.Vec3D;
 
-public class TileEntitySign extends TileEntity {
+public class TileEntitySign extends TileEntity implements ICommandListener { // CraftBukkit - implements
 
     public static final int LINES = 4;
     private static final String[] RAW_TEXT_FIELD_NAMES = new String[]{"Text1", "Text2", "Text3", "Text4"};
@@ -65,6 +65,12 @@
             }
         }
 
+        // CraftBukkit start
+        if (Boolean.getBoolean("convertLegacySigns")) {
+            nbttagcompound.setBoolean("Bukkit.isConverted", true);
+        }
+        // CraftBukkit end
+
         nbttagcompound.setString("Color", this.color.b());
         nbttagcompound.setBoolean("GlowingText", this.hasGlowingText);
         return nbttagcompound;
@@ -76,8 +82,24 @@
         super.load(nbttagcompound);
         this.color = EnumColor.a(nbttagcompound.getString("Color"), EnumColor.BLACK);
 
+        // CraftBukkit start - Add an option to convert signs correctly
+        // This is done with a flag instead of all the time because
+        // we have no way to tell whether a sign is from 1.7.10 or 1.8
+        boolean oldSign = Boolean.getBoolean("convertLegacySigns") && !nbttagcompound.getBoolean("Bukkit.isConverted");
+        // CraftBukkit end
+
         for (int i = 0; i < 4; ++i) {
             String s = nbttagcompound.getString(TileEntitySign.RAW_TEXT_FIELD_NAMES[i]);
+            // CraftBukkit start
+            if (s != null && s.length() > 2048) {
+                s = "\"\"";
+            }
+
+            if (oldSign) {
+                messages[i] = org.bukkit.craftbukkit.util.CraftChatMessage.fromString(s)[0];
+                continue;
+            }
+            // CraftBukkit end
             IChatBaseComponent ichatbasecomponent = this.a(s);
 
             this.messages[i] = ichatbasecomponent;
@@ -115,6 +137,10 @@
             if (ichatmutablecomponent != null) {
                 return ichatmutablecomponent;
             }
+            // CraftBukkit start
+        } catch (com.google.gson.JsonParseException jsonparseexception) {
+            return new ChatComponentText(s);
+            // CraftBukkit end
         } catch (Exception exception) {
             ;
         }
@@ -207,11 +233,37 @@
         return true;
     }
 
+    // CraftBukkit start
+    @Override
+    public void sendMessage(IChatBaseComponent ichatbasecomponent, java.util.UUID uuid) {}
+
+    @Override
+    public org.bukkit.command.CommandSender getBukkitSender(CommandListenerWrapper wrapper) {
+        return wrapper.getEntity() != null ? wrapper.getEntity().getBukkitSender(wrapper) : new org.bukkit.craftbukkit.command.CraftBlockCommandSender(wrapper, this);
+    }
+
+    @Override
+    public boolean shouldSendSuccess() {
+        return false;
+    }
+
+    @Override
+    public boolean shouldSendFailure() {
+        return false;
+    }
+
+    @Override
+    public boolean shouldBroadcastCommands() {
+        return false;
+    }
+    // CraftBukkit end
+
     public CommandListenerWrapper b(@Nullable EntityPlayer entityplayer) {
         String s = entityplayer == null ? "Sign" : entityplayer.getDisplayName().getString();
         Object object = entityplayer == null ? new ChatComponentText("Sign") : entityplayer.getScoreboardDisplayName();
 
-        return new CommandListenerWrapper(ICommandListener.NULL, Vec3D.a((BaseBlockPosition) this.worldPosition), Vec2F.ZERO, (WorldServer) this.level, 2, s, (IChatBaseComponent) object, this.level.getMinecraftServer(), entityplayer);
+        // CraftBukkit - this
+        return new CommandListenerWrapper(this, Vec3D.a((BaseBlockPosition) this.worldPosition), Vec2F.ZERO, (WorldServer) this.level, 2, s, (IChatBaseComponent) object, this.level.getMinecraftServer(), entityplayer);
     }
 
     public EnumColor getColor() {
@@ -244,6 +296,6 @@
 
     private void i() {
         this.update();
-        this.level.notify(this.getPosition(), this.getBlock(), this.getBlock(), 3);
+        if (this.level != null) this.level.notify(this.getPosition(), this.getBlock(), this.getBlock(), 3); // CraftBukkit - skip notify if world is null (SPIGOT-5122)
     }
 }
