From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sat, 22 Sep 2018 15:56:59 -0400
Subject: [PATCH] Catch JsonParseException in Entity and TE names

As a result, data that no longer parses correctly will not crash the server
instead just logging the exception and continuing (and in most cases should
fix the data)

Player data is fixed pretty much immediately but some block data (like
Shulkers) may need to be changed in order for it to re-save properly

No more crashing though.

diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
index 5c290f263fc2b643987c96ea75729bf1ff493760..2d0c10c72a9ddc5a26352fad6baae2f6c2678923 100644
--- a/src/main/java/net/minecraft/server/MCUtil.java
+++ b/src/main/java/net/minecraft/server/MCUtil.java
@@ -6,6 +6,8 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.chat.Component;
 import net.minecraft.server.level.ServerLevel;
 import net.minecraft.world.entity.Entity;
 import net.minecraft.world.level.ChunkPos;
@@ -513,6 +515,21 @@ public final class MCUtil {
         }
     }
 
+    @Nullable
+    public static Component getBaseComponentFromNbt(String key, CompoundTag compound) {
+        if (!compound.contains(key)) {
+            return null;
+        }
+        String string = compound.getString(key);
+        try {
+            return Component.Serializer.fromJson(string);
+        } catch (com.google.gson.JsonParseException e) {
+            org.bukkit.Bukkit.getLogger().warning("Unable to parse " + key + " from " + compound +": " + e.getMessage());
+        }
+
+        return null;
+    }
+
     public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) {
         return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status);
     }
diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
index 04a3627667498b841fbff547d1874d99cc708af4..2e6172930526efc536a214e420e690a5ea42ac3e 100644
--- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
@@ -12,6 +12,7 @@ import net.minecraft.commands.CommandSourceStack;
 import net.minecraft.nbt.CompoundTag;
 import net.minecraft.network.chat.Component;
 import net.minecraft.network.chat.TextComponent;
+import net.minecraft.server.MCUtil;
 import net.minecraft.server.MinecraftServer;
 import net.minecraft.server.level.ServerLevel;
 import net.minecraft.util.StringUtil;
@@ -73,7 +74,7 @@ public abstract class BaseCommandBlock implements CommandSource {
         this.command = nbt.getString("Command");
         this.successCount = nbt.getInt("SuccessCount");
         if (nbt.contains("CustomName", 8)) {
-            this.setName(Component.Serializer.fromJson(nbt.getString("CustomName")));
+            this.setName(MCUtil.getBaseComponentFromNbt("CustomName", nbt)); // Paper - Catch ParseException
         }
 
         if (nbt.contains("TrackOutput", 1)) {
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
index e07c9e7e37a2c6aa3fc4b7fdc2d547d9c8a2177e..83f27ede626fc7e263acf2c9417a2c2699e4c79a 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
@@ -10,6 +10,7 @@ import net.minecraft.nbt.ListTag;
 import net.minecraft.network.chat.Component;
 import net.minecraft.network.chat.TranslatableComponent;
 import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
+import net.minecraft.server.MCUtil;
 import net.minecraft.world.Nameable;
 import net.minecraft.world.item.DyeColor;
 import net.minecraft.world.item.ItemStack;
@@ -95,7 +96,7 @@ public class BannerBlockEntity extends BlockEntity implements Nameable {
     public void load(CompoundTag nbt) {
         super.load(nbt);
         if (nbt.contains("CustomName", 8)) {
-            this.name = Component.Serializer.fromJson(nbt.getString("CustomName"));
+            this.name = MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException
         }
 
         this.itemPatterns = nbt.getList("Patterns", 10);
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
index 16fd9b356fee79b56893fe0a7c71721ae81664ab..67e39ebc7984d47bdf9081c24cb26845d70b83bb 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
@@ -5,6 +5,7 @@ import net.minecraft.core.BlockPos;
 import net.minecraft.nbt.CompoundTag;
 import net.minecraft.network.chat.Component;
 import net.minecraft.network.chat.TranslatableComponent;
+import net.minecraft.server.MCUtil;
 import net.minecraft.sounds.SoundEvents;
 import net.minecraft.sounds.SoundSource;
 import net.minecraft.world.Container;
@@ -31,7 +32,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
         super.load(nbt);
         this.lockKey = LockCode.fromTag(nbt);
         if (nbt.contains("CustomName", 8)) {
-            this.name = Component.Serializer.fromJson(nbt.getString("CustomName"));
+            this.name = MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException
         }
 
     }
