From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 6 Nov 2017 21:08:22 -0500
Subject: [PATCH] API to get a BlockState without a snapshot

This allows you to get a BlockState without creating a snapshot, operating
on the real tile entity.

This is useful for where performance is needed

also Avoid NPE during CraftBlockEntityState load if could not get TE

If Tile Entity was null, correct Sign to return empty lines instead of null

diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java
index cea42d98aa6e1f96df0fa70234086dceb124fbbf..34d92491830c99172bec5251fa80300b6315e5ef 100644
--- a/src/main/java/net/minecraft/server/TileEntity.java
+++ b/src/main/java/net/minecraft/server/TileEntity.java
@@ -33,6 +33,7 @@ public abstract class TileEntity implements KeyedObject { // Paper
     public TileEntity(TileEntityTypes<?> tileentitytypes) {
         this.position = BlockPosition.ZERO;
         this.tileType = tileentitytypes;
+        persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY); // Paper - always init
     }
 
     // Paper start
@@ -81,7 +82,7 @@ public abstract class TileEntity implements KeyedObject { // Paper
     public void load(IBlockData iblockdata, NBTTagCompound nbttagcompound) {
         this.position = new BlockPosition(nbttagcompound.getInt("x"), nbttagcompound.getInt("y"), nbttagcompound.getInt("z"));
         // CraftBukkit start - read container
-        this.persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY);
+        this.persistentDataContainer.clear(); // Paper - clear instead of reinit
 
         NBTBase persistentDataTag = nbttagcompound.get("PublicBukkitValues");
         if (persistentDataTag instanceof NBTTagCompound) {
@@ -231,7 +232,12 @@ public abstract class TileEntity implements KeyedObject { // Paper
     }
 
     // CraftBukkit start - add method
+    // Paper start
     public InventoryHolder getOwner() {
+        return getOwner(true);
+    }
+    public InventoryHolder getOwner(boolean useSnapshot) {
+        // Paper end
         if (world == null) return null;
         // Spigot start
         org.bukkit.block.Block block = world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ());
@@ -240,7 +246,7 @@ public abstract class TileEntity implements KeyedObject { // Paper
             return null;
         }
         // Spigot end
-        org.bukkit.block.BlockState state = block.getState();
+        org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper
         if (state instanceof InventoryHolder) return (InventoryHolder) state;
         return null;
     }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index 5de8463c94612edd11e02ac5d9757382c9598e7d..661bb54c27966c8050644b293d99dfe86e3c04ce 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -316,6 +316,20 @@ public class CraftBlock implements Block {
 
     @Override
     public BlockState getState() {
+        // Paper start - allow disabling the use of snapshots
+        return getState(true);
+    }
+    public BlockState getState(boolean useSnapshot) {
+        boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT;
+        CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot;
+        try {
+            return getState0();
+        } finally {
+            CraftBlockEntityState.DISABLE_SNAPSHOT = prev;
+        }
+    }
+    public BlockState getState0() {
+        // Paper end
         Material material = getType();
 
         switch (material) {
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
index 26cc40e57f5b73b9c32859bff37c4a3d94904c56..feeae1a9eb309ae4101783b191bb2bffe9aeb7d3 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
@@ -26,20 +26,40 @@ public class CraftBlockEntityState<T extends TileEntity> extends CraftBlockState
         this.tileEntity = tileEntityClass.cast(world.getHandle().getTileEntity(this.getPosition()));
         Preconditions.checkState(this.tileEntity != null, "Tile is null, asynchronous access? " + block);
 
+        // Paper start
+        this.snapshotDisabled = DISABLE_SNAPSHOT;
+        if (DISABLE_SNAPSHOT) {
+            this.snapshot = this.tileEntity;
+        } else {
+            this.snapshot = this.createSnapshot(this.tileEntity);
+        }
         // copy tile entity data:
-        this.snapshot = this.createSnapshot(tileEntity);
-        this.load(snapshot);
+        if(this.snapshot != null) {
+            this.load(this.snapshot);
+        }
+        // Paper end
     }
 
+    public final boolean snapshotDisabled; // Paper
+    public static boolean DISABLE_SNAPSHOT = false; // Paper
+
     public CraftBlockEntityState(Material material, T tileEntity) {
         super(material);
 
         this.tileEntityClass = (Class<T>) tileEntity.getClass();
         this.tileEntity = tileEntity;
-
+        // Paper start
+        this.snapshotDisabled = DISABLE_SNAPSHOT;
+        if (DISABLE_SNAPSHOT) {
+            this.snapshot = this.tileEntity;
+        } else {
+            this.snapshot = this.createSnapshot(this.tileEntity);
+        }
         // copy tile entity data:
-        this.snapshot = this.createSnapshot(tileEntity);
-        this.load(snapshot);
+        if(this.snapshot != null) {
+            this.load(this.snapshot);
+        }
+        // Paper end
     }
 
     private T createSnapshot(T tileEntity) {
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
index 15022ada0c2fd0f4302b45c55f46d0fdd3bfd57f..af15656cc4b4c1e9da4fc8a5bfffa95eb6caf903 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
@@ -17,10 +17,12 @@ public class CraftSign extends CraftBlockEntityState<TileEntitySign> implements
 
     public CraftSign(final Block block) {
         super(block, TileEntitySign.class);
+        if (lines == null) { lines = new String[]{"", "", "", ""}; } // Paper
     }
 
     public CraftSign(final Material material, final TileEntitySign te) {
         super(material, te);
+        if (lines == null) { lines = new String[]{"", "", "", ""}; } // Paper
     }
 
     @Override
diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
index 58e2db5da178af6a8c30f563353fefe720ff9781..b704f550de290e0bc1235bf7e68c7eb347162c69 100644
--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
@@ -155,4 +155,10 @@ public final class CraftPersistentDataContainer implements PersistentDataContain
     public Map<String, Object> serialize() {
         return (Map<String, Object>) CraftNBTTagConfigSerializer.serialize(toTagCompound());
     }
+
+    // Paper start
+    public void clear() {
+        this.customDataTags.clear();
+    }
+    // Paper end
 }
