From 7ac07ac07ac07ac07ac07ac07ac07ac07ac07ac0 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 20:55:47 -0400
Subject: [PATCH] MC Utils


diff --git a/src/main/java/net/minecraft/server/AttributeInstance.java b/src/main/java/net/minecraft/server/AttributeInstance.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/AttributeInstance.java
+++ b/src/main/java/net/minecraft/server/AttributeInstance.java
@@ -20,8 +20,10 @@ public interface AttributeInstance {
     @Nullable
     AttributeModifier a(UUID var1);
 
+    default void addModifier(AttributeModifier modifier) { b(modifier); } // Paper - OBFHELPER
     void b(AttributeModifier var1);
 
+    default void removeModifier(AttributeModifier modifier) { c(modifier); } // Paper - OBFHELPER
     void c(AttributeModifier var1);
 
     void b(UUID var1);
diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/BlockPosition.java
+++ b/src/main/java/net/minecraft/server/BlockPosition.java
@@ -9,7 +9,7 @@ import org.apache.logging.log4j.Logger;
 
 @Immutable
 public class BlockPosition extends BaseBlockPosition {
-    private static final Logger b = LogManager.getLogger();
+    //private static final Logger b = LogManager.getLogger(); // Paper - variable name conflict, logger isn't used
     public static final BlockPosition ZERO = new BlockPosition(0, 0, 0);
     private static final int c = 1 + MathHelper.e(MathHelper.c(30000000));
     private static final int d = c;
@@ -44,6 +44,7 @@ public class BlockPosition extends BaseBlockPosition {
         return d0 == 0.0D && d1 == 0.0D && d2 == 0.0D ? this : new BlockPosition((double)this.getX() + d0, (double)this.getY() + d1, (double)this.getZ() + d2);
     }
 
+    public BlockPosition add(int i, int j, int k) {return a(i, j, k);} // Paper - OBFHELPER
     public BlockPosition a(int ix, int jx, int kx) {
         return ix == 0 && jx == 0 && kx == 0 ? this : new BlockPosition(this.getX() + ix, this.getY() + jx, this.getZ() + kx);
     }
@@ -186,6 +187,7 @@ public class BlockPosition extends BaseBlockPosition {
         };
     }
 
+    public BlockPosition asImmutable() { return h(); } // Paper - OBFHELPER
     public BlockPosition h() {
         return this;
     }
@@ -282,6 +284,7 @@ public class BlockPosition extends BaseBlockPosition {
             return this.d;
         }
 
+        public BlockPosition.MutableBlockPosition setValues(int i, int j, int k) { return c(i, j, k);} // Paper - OBFHELPER
         public BlockPosition.MutableBlockPosition c(int i, int j, int k) {
             this.b = i;
             this.c = j;
@@ -289,6 +292,7 @@ public class BlockPosition extends BaseBlockPosition {
             return this;
         }
 
+        public BlockPosition.MutableBlockPosition setValues(double d0, double d1, double d2) { return c(d0, d1, d2);} // Paper - OBFHELPER
         public BlockPosition.MutableBlockPosition c(double d0, double d1, double d2) {
             return this.c(MathHelper.floor(d0), MathHelper.floor(d1), MathHelper.floor(d2));
         }
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -27,7 +27,7 @@ import com.google.common.collect.Lists; // CraftBukkit
 public class Chunk implements IChunkAccess {
 
     private static final Logger d = LogManager.getLogger();
-    public static final ChunkSection a = null;
+    public static final ChunkSection a = null; public static final ChunkSection EMPTY_CHUNK_SECTION = Chunk.a; // Paper - OBFHELPER
     private final ChunkSection[] sections;
     private final BiomeBase[] f;
     private final boolean[] g;
@@ -700,6 +700,7 @@ public class Chunk implements IChunkAccess {
         return this.a(blockposition, Chunk.EnumTileEntityState.CHECK);
     }
 
+    @Nullable public final TileEntity getTileEntityImmediately(BlockPosition pos) { return this.a(pos, EnumTileEntityState.IMMEDIATE); } // Paper - OBFHELPER
     @Nullable
     public TileEntity a(BlockPosition blockposition, Chunk.EnumTileEntityState chunk_enumtileentitystate) {
         // CraftBukkit start
diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
+++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
@@ -23,6 +23,8 @@ public class ChunkCoordIntPair {
         return a(this.x, this.z);
     }
 
+    public static long asLong(final BlockPosition pos) { return a(pos.getX() >> 4, pos.getZ() >> 4); } // Paper - OBFHELPER
+    public static long asLong(int x, int z) { return a(x, z); } // Paper - OBFHELPER
     public static long a(int i, int j) {
         return (long)i & 4294967295L | ((long)j & 4294967295L) << 32;
     }
diff --git a/src/main/java/net/minecraft/server/ChunkTaskScheduler.java b/src/main/java/net/minecraft/server/ChunkTaskScheduler.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/ChunkTaskScheduler.java
+++ b/src/main/java/net/minecraft/server/ChunkTaskScheduler.java
@@ -16,7 +16,7 @@ import org.apache.logging.log4j.Logger;
 public class ChunkTaskScheduler extends Scheduler<ChunkCoordIntPair, ChunkStatus, ProtoChunk> {
 
     private static final Logger b = LogManager.getLogger();
-    private final World c;
+    private final World c; private final World getWorld() { return this.c; } // Paper - OBFHELPER
     private final ChunkGenerator<?> d;
     private final IChunkLoader e;
     private final IAsyncTaskHandler f;
diff --git a/src/main/java/net/minecraft/server/DataBits.java b/src/main/java/net/minecraft/server/DataBits.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/DataBits.java
+++ b/src/main/java/net/minecraft/server/DataBits.java
@@ -54,6 +54,7 @@ public class DataBits {
         }
     }
 
+    public long[] getDataBits() { return this.a(); } // Paper - OBFHELPER
     public long[] a() {
         return this.a;
     }
diff --git a/src/main/java/net/minecraft/server/DataPalette.java b/src/main/java/net/minecraft/server/DataPalette.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/DataPalette.java
+++ b/src/main/java/net/minecraft/server/DataPalette.java
@@ -3,10 +3,11 @@ package net.minecraft.server;
 import javax.annotation.Nullable;
 
 public interface DataPalette<T> {
+    default int getOrCreateIdFor(T object) { return this.a(object); } // Paper - OBFHELPER
     int a(T var1);
 
-    @Nullable
-    T a(int var1);
+    @Nullable default T getObject(int dataBits) { return this.a(dataBits); } // Paper - OBFHELPER
+    @Nullable T a(int var1);
 
     void b(PacketDataSerializer var1);
 
diff --git a/src/main/java/net/minecraft/server/DataPaletteBlock.java b/src/main/java/net/minecraft/server/DataPaletteBlock.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/DataPaletteBlock.java
+++ b/src/main/java/net/minecraft/server/DataPaletteBlock.java
@@ -7,7 +7,7 @@ import java.util.function.Function;
 import java.util.stream.Collectors;
 
 public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
-    private final DataPalette<T> b;
+    private final DataPalette<T> b;private final DataPalette<T> getDataPaletteGlobal() { return this.b; } // Paper - OBFHELPER
     private final DataPaletteExpandable<T> c = (var0, var1) -> {
         return 0;
     };
@@ -15,9 +15,9 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
     private final Function<NBTTagCompound, T> e;
     private final Function<T, NBTTagCompound> f;
     private final T g;
-    protected DataBits a;
-    private DataPalette<T> h;
-    private int i;
+    protected DataBits a; protected DataBits getDataBits() { return this.a; } // Paper - OBFHELPER
+    private DataPalette<T> h; private DataPalette<T> getDataPalette() { return this.h; } // Paper - OBFHELPER
+    private int i; private int getBitsPerObject() { return this.i; } // Paper - OBFHELPER
     private final ReentrantLock j = new ReentrantLock();
 
     private void b() {
@@ -51,6 +51,7 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
         return jx << 8 | k << 4 | ix;
     }
 
+    private void initialize(int bitsPerObject) { this.b(bitsPerObject); } // Paper - OBFHELPER
     private void b(int ix) {
         if (ix != this.i) {
             this.i = ix;
@@ -107,6 +108,7 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
         return (T)(object == null ? this.g : object);
     }
 
+    public void writeDataPaletteBlock(PacketDataSerializer packetDataSerializer) { this.b(packetDataSerializer); } // Paper - OBFHELPER
     public void b(PacketDataSerializer packetdataserializer) {
         this.b();
         packetdataserializer.writeByte(this.i);
diff --git a/src/main/java/net/minecraft/server/EntityCreature.java b/src/main/java/net/minecraft/server/EntityCreature.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/EntityCreature.java
+++ b/src/main/java/net/minecraft/server/EntityCreature.java
@@ -6,6 +6,7 @@ import org.bukkit.event.entity.EntityUnleashEvent;
 
 public abstract class EntityCreature extends EntityInsentient {
 
+    public org.bukkit.craftbukkit.entity.CraftCreature getBukkitCreature() { return (org.bukkit.craftbukkit.entity.CraftCreature) super.getBukkitEntity(); } // Paper
     private BlockPosition a;
     private float b;
 
diff --git a/src/main/java/net/minecraft/server/EntityInsentient.java b/src/main/java/net/minecraft/server/EntityInsentient.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/EntityInsentient.java
+++ b/src/main/java/net/minecraft/server/EntityInsentient.java
@@ -124,6 +124,7 @@ public abstract class EntityInsentient extends EntityLiving {
         return this.goalTarget;
     }
 
+    public org.bukkit.craftbukkit.entity.CraftMob getBukkitMob() { return (org.bukkit.craftbukkit.entity.CraftMob) super.getBukkitEntity(); } // Paper
     public void setGoalTarget(@Nullable EntityLiving entityliving) {
         // CraftBukkit start - fire event
         setGoalTarget(entityliving, EntityTargetEvent.TargetReason.UNKNOWN, true);
diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/EntityLiving.java
+++ b/src/main/java/net/minecraft/server/EntityLiving.java
@@ -122,6 +122,7 @@ public abstract class EntityLiving extends Entity {
     public org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes;
     public boolean collides = true;
     public boolean canPickUpLoot;
+    public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper
 
     @Override
     public float getBukkitYaw() {
diff --git a/src/main/java/net/minecraft/server/EntityMonster.java b/src/main/java/net/minecraft/server/EntityMonster.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/EntityMonster.java
+++ b/src/main/java/net/minecraft/server/EntityMonster.java
@@ -1,11 +1,14 @@
 package net.minecraft.server;
 
 public abstract class EntityMonster extends EntityCreature implements IMonster {
+
+    public org.bukkit.craftbukkit.entity.CraftMonster getBukkitMonster() { return (org.bukkit.craftbukkit.entity.CraftMonster) super.getBukkitEntity(); } // Paper
     protected EntityMonster(EntityTypes<?> entitytypes, World world) {
         super(entitytypes, world);
         this.b_ = 5;
     }
 
+    public SoundCategory getSoundCategory() { return bV(); } // Paper - OBFHELPER
     public SoundCategory bV() {
         return SoundCategory.HOSTILE;
     }
diff --git a/src/main/java/net/minecraft/server/EntityTypes.java b/src/main/java/net/minecraft/server/EntityTypes.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/EntityTypes.java
+++ b/src/main/java/net/minecraft/server/EntityTypes.java
@@ -3,6 +3,7 @@ package net.minecraft.server;
 import com.mojang.datafixers.DataFixUtils;
 import com.mojang.datafixers.types.Type;
 
+import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import java.util.function.Function;
@@ -123,9 +124,20 @@ public class EntityTypes<T extends Entity> {
     public static <T extends Entity> EntityTypes<T> a(String s, EntityTypes.a<T> entitytypes_a) {
         EntityTypes entitytypes = entitytypes_a.a(s);
 
+        // Paper start
+        if (clsToKeyMap == null ) clsToKeyMap = new java.util.HashMap<>();
+        if (clsToTypeMap == null ) clsToTypeMap = new java.util.HashMap<>();
+
+        MinecraftKey key = new MinecraftKey(s);
+        Class<? extends T> entityClass = entitytypes_a.getEntityClass();
         IRegistry.ENTITY_TYPE.a(new MinecraftKey(s), entitytypes); // CraftBukkit - decompile error
+        clsToKeyMap.put(entityClass, key);
+        clsToTypeMap.put(entityClass, org.bukkit.entity.EntityType.fromName(s));
         return entitytypes;
     }
+    public static Map<Class<? extends Entity>, MinecraftKey> clsToKeyMap;
+    public static Map<Class<? extends Entity>, org.bukkit.entity.EntityType> clsToTypeMap;
+    // Paper end
 
     @Nullable
     public static MinecraftKey getName(EntityTypes<?> entitytypes) {
@@ -287,7 +299,7 @@ public class EntityTypes<T extends Entity> {
 
     public static class a<T extends Entity> {
 
-        private final Class<? extends T> a;
+        private final Class<? extends T> a; public Class<? extends T> getEntityClass() { return a; } // Paper - OBFHELPER
         private final Function<? super World, ? extends T> b;
         private boolean c = true;
         private boolean d = true;
@@ -338,7 +350,7 @@ public class EntityTypes<T extends Entity> {
 
     // Paper start
     public static Set<MinecraftKey> getEntityNameList() {
-        return REGISTRY.keySet();
+        return IRegistry.ENTITY_TYPE.keySet();
     }
     // Paper end
 }
diff --git a/src/main/java/net/minecraft/server/ItemStack.java b/src/main/java/net/minecraft/server/ItemStack.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/ItemStack.java
+++ b/src/main/java/net/minecraft/server/ItemStack.java
@@ -26,6 +26,7 @@ import org.bukkit.TreeType;
 import org.bukkit.block.BlockState;
 import org.bukkit.craftbukkit.block.CraftBlock;
 import org.bukkit.craftbukkit.block.CraftBlockState;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
 import org.bukkit.craftbukkit.util.CraftMagicNumbers;
 import org.bukkit.entity.Player;
 import org.bukkit.event.block.BlockFertilizeEvent;
@@ -561,6 +562,17 @@ public final class ItemStack {
         return this.tag != null ? this.tag.getList("Enchantments", 10) : new NBTTagList();
     }
 
+    // Paper start - (this is just a good no conflict location)
+    public org.bukkit.inventory.ItemStack asBukkitMirror() {
+        return CraftItemStack.asCraftMirror(this);
+    }
+    public org.bukkit.inventory.ItemStack asBukkitCopy() {
+        return CraftItemStack.asCraftMirror(this.cloneItemStack());
+    }
+    public static ItemStack fromBukkitCopy(org.bukkit.inventory.ItemStack itemstack) {
+        return CraftItemStack.asNMSCopy(itemstack);
+    }
+    // Paper end
     public void setTag(@Nullable NBTTagCompound nbttagcompound) {
         this.tag = nbttagcompound;
     }
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
new file mode 100644
index 7ac07ac07ac0..7ac07ac07ac0
--- /dev/null
+++ b/src/main/java/net/minecraft/server/MCUtil.java
@@ -0,0 +1,316 @@
+package net.minecraft.server;
+
+import com.destroystokyo.paper.block.TargetBlockInfo;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import org.bukkit.Location;
+import org.bukkit.block.BlockFace;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.util.Waitable;
+import org.spigotmc.AsyncCatcher;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Queue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Supplier;
+
+public final class MCUtil {
+    private static final Executor asyncExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("Paper Async Task Handler Thread - %1$d").build());
+
+    private MCUtil() {}
+
+
+    public static boolean isMainThread() {
+        return MinecraftServer.getServer().isMainThread();
+    }
+
+    private static class DelayedRunnable implements Runnable {
+
+        private final int ticks;
+        private final Runnable run;
+
+        private DelayedRunnable(int ticks, Runnable run) {
+            this.ticks = ticks;
+            this.run = run;
+        }
+
+        @Override
+        public void run() {
+            if (ticks <= 0) {
+                run.run();
+            } else {
+                scheduleTask(ticks-1, run);
+            }
+        }
+    }
+
+    public static void scheduleTask(int ticks, Runnable runnable) {
+        // We use post to main instead of process queue as we don't want to process these mid tick if
+        // Someone uses processQueueWhileWaiting
+        MinecraftServer.getServer().postToMainThread(new DelayedRunnable(ticks, runnable));
+    }
+
+    public static void processQueue() {
+        Runnable runnable;
+        Queue<Runnable> processQueue = getProcessQueue();
+        while ((runnable = processQueue.poll()) != null) {
+            try {
+                runnable.run();
+            } catch (Exception e) {
+                MinecraftServer.LOGGER.error("Error executing task", e);
+            }
+        }
+    }
+    public static <T> T processQueueWhileWaiting(CompletableFuture <T> future) {
+        try {
+            if (isMainThread()) {
+                while (!future.isDone()) {
+                    try {
+                        return future.get(1, TimeUnit.MILLISECONDS);
+                    } catch (TimeoutException ignored) {
+                        processQueue();
+                    }
+                }
+            }
+            return future.get();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void ensureMain(Runnable run) {
+        ensureMain(null, run);
+    }
+    /**
+     * Ensures the target code is running on the main thread
+     * @param reason
+     * @param run
+     * @return
+     */
+    public static void ensureMain(String reason, Runnable run) {
+        if (AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().primaryThread) {
+            if (reason != null) {
+                new IllegalStateException("Asynchronous " + reason + "!").printStackTrace();
+            }
+            getProcessQueue().add(run);
+            return;
+        }
+        run.run();
+    }
+
+    private static Queue<Runnable> getProcessQueue() {
+        return MinecraftServer.getServer().processQueue;
+    }
+
+    public static <T> T ensureMain(Supplier<T> run) {
+        return ensureMain(null, run);
+    }
+    /**
+     * Ensures the target code is running on the main thread
+     * @param reason
+     * @param run
+     * @param <T>
+     * @return
+     */
+    public static <T> T ensureMain(String reason, Supplier<T> run) {
+        if (AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().primaryThread) {
+            if (reason != null) {
+                new IllegalStateException("Asynchronous " + reason + "! Blocking thread until it returns ").printStackTrace();
+            }
+            Waitable<T> wait = new Waitable<T>() {
+                @Override
+                protected T evaluate() {
+                    return run.get();
+                }
+            };
+            getProcessQueue().add(wait);
+            try {
+                return wait.get();
+            } catch (InterruptedException | ExecutionException e) {
+                e.printStackTrace();
+            }
+            return null;
+        }
+        return run.get();
+    }
+
+    /**
+     * Calculates distance between 2 entities
+     * @param e1
+     * @param e2
+     * @return
+     */
+    public static double distance(Entity e1, Entity e2) {
+        return Math.sqrt(distanceSq(e1, e2));
+    }
+
+
+    /**
+     * Calculates distance between 2 block positions
+     * @param e1
+     * @param e2
+     * @return
+     */
+    public static double distance(BlockPosition e1, BlockPosition e2) {
+        return Math.sqrt(distanceSq(e1, e2));
+    }
+
+    /**
+     * Gets the distance between 2 positions
+     * @param x1
+     * @param y1
+     * @param z1
+     * @param x2
+     * @param y2
+     * @param z2
+     * @return
+     */
+    public static double distance(double x1, double y1, double z1, double x2, double y2, double z2) {
+        return Math.sqrt(distanceSq(x1, y1, z1, x2, y2, z2));
+    }
+
+    /**
+     * Get's the distance squared between 2 entities
+     * @param e1
+     * @param e2
+     * @return
+     */
+    public static double distanceSq(Entity e1, Entity e2) {
+        return distanceSq(e1.locX,e1.locY,e1.locZ, e2.locX,e2.locY,e2.locZ);
+    }
+
+    /**
+     * Gets the distance sqaured between 2 block positions
+     * @param pos1
+     * @param pos2
+     * @return
+     */
+    public static double distanceSq(BlockPosition pos1, BlockPosition pos2) {
+        return distanceSq(pos1.getX(), pos1.getY(), pos1.getZ(), pos2.getX(), pos2.getY(), pos2.getZ());
+    }
+
+    /**
+     * Gets the distance squared between 2 positions
+     * @param x1
+     * @param y1
+     * @param z1
+     * @param x2
+     * @param y2
+     * @param z2
+     * @return
+     */
+    public static double distanceSq(double x1, double y1, double z1, double x2, double y2, double z2) {
+        return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2);
+    }
+
+    /**
+     * Converts a NMS World/BlockPosition to Bukkit Location
+     * @param world
+     * @param x
+     * @param y
+     * @param z
+     * @return
+     */
+    public static Location toLocation(World world, double x, double y, double z) {
+        return new Location(world.getWorld(), x, y, z);
+    }
+
+    /**
+     * Converts a NMS World/BlockPosition to Bukkit Location
+     * @param world
+     * @param pos
+     * @return
+     */
+    public static Location toLocation(World world, BlockPosition pos) {
+        return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ());
+    }
+
+    /**
+     * Converts an NMS entity's current location to a Bukkit Location
+     * @param entity
+     * @return
+     */
+    public static Location toLocation(Entity entity) {
+        return new Location(entity.getWorld().getWorld(), entity.locX, entity.locY, entity.locZ);
+    }
+
+    public static org.bukkit.block.Block toBukkitBlock(World world, BlockPosition pos) {
+        return world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
+    }
+
+    public static BlockPosition toBlockPosition(Location loc) {
+        return new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
+    }
+
+    public static boolean isEdgeOfChunk(BlockPosition pos) {
+        final int modX = pos.getX() & 15;
+        final int modZ = pos.getZ() & 15;
+        return (modX == 0 || modX == 15 || modZ == 0 || modZ == 15);
+    }
+
+    /**
+     * Posts a task to be executed asynchronously
+     * @param run
+     */
+    public static void scheduleAsyncTask(Runnable run) {
+        asyncExecutor.execute(run);
+    }
+
+    @Nullable
+    public static TileEntityHopper getHopper(World world, BlockPosition pos) {
+        Chunk chunk = world.getChunkIfLoaded(pos.getX() >> 4, pos.getZ() >> 4);
+        if (chunk != null && chunk.getBlockData(pos.getX(), pos.getY(), pos.getZ()).getBlock() == Blocks.HOPPER) {
+            TileEntity tileEntity = chunk.getTileEntityImmediately(pos);
+            if (tileEntity instanceof TileEntityHopper) {
+                return (TileEntityHopper) tileEntity;
+            }
+        }
+        return null;
+    }
+
+    @Nonnull
+    public static World getNMSWorld(@Nonnull org.bukkit.World world) {
+        return ((CraftWorld) world).getHandle();
+    }
+
+    public static World getNMSWorld(@Nonnull org.bukkit.entity.Entity entity) {
+        return getNMSWorld(entity.getWorld());
+    }
+
+    public static FluidCollisionOption getNMSFluidCollisionOption(TargetBlockInfo.FluidMode fluidMode) {
+        if (fluidMode == TargetBlockInfo.FluidMode.NEVER) {
+            return FluidCollisionOption.NEVER;
+        }
+        if (fluidMode == TargetBlockInfo.FluidMode.SOURCE_ONLY) {
+            return FluidCollisionOption.SOURCE_ONLY;
+        }
+        if (fluidMode == TargetBlockInfo.FluidMode.ALWAYS) {
+            return FluidCollisionOption.ALWAYS;
+        }
+        return null;
+    }
+
+    public static BlockFace toBukkitBlockFace(EnumDirection enumDirection) {
+        switch (enumDirection) {
+            case DOWN:
+                return BlockFace.DOWN;
+            case UP:
+                return BlockFace.UP;
+            case NORTH:
+                return BlockFace.NORTH;
+            case SOUTH:
+                return BlockFace.SOUTH;
+            case WEST:
+                return BlockFace.WEST;
+            case EAST:
+                return BlockFace.EAST;
+            default:
+                return null;
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/server/NBTTagCompound.java b/src/main/java/net/minecraft/server/NBTTagCompound.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/NBTTagCompound.java
+++ b/src/main/java/net/minecraft/server/NBTTagCompound.java
@@ -23,7 +23,7 @@ import org.apache.logging.log4j.Logger;
 public class NBTTagCompound implements NBTBase {
     private static final Logger f = LogManager.getLogger();
     private static final Pattern g = Pattern.compile("[A-Za-z0-9._+-]+");
-    private final Map<String, NBTBase> map = Maps.newHashMap();
+    public final Map<String, NBTBase> map = Maps.newHashMap(); // Paper
 
     public NBTTagCompound() {
     }
@@ -89,11 +89,13 @@ public class NBTTagCompound implements NBTBase {
         this.map.put(s, new NBTTagLong(i));
     }
 
+    public void setUUID(String prefix, UUID uuid) { a(prefix, uuid); } // Paper - OBFHELPER
     public void a(String s, UUID uuid) {
         this.setLong(s + "Most", uuid.getMostSignificantBits());
         this.setLong(s + "Least", uuid.getLeastSignificantBits());
     }
 
+    public UUID getUUID(String prefix) { return a(prefix); } // Paper - OBFHELPER
     @Nullable
     public UUID a(String s) {
         return new UUID(this.getLong(s + "Most"), this.getLong(s + "Least"));
@@ -322,7 +324,7 @@ public class NBTTagCompound implements NBTBase {
 
     public String toString() {
         StringBuilder stringbuilder = new StringBuilder("{");
-        Object object = this.map.keySet();
+        Collection<String> object = this.map.keySet(); // Paper - decompile fix
         if (f.isDebugEnabled()) {
             ArrayList arraylist = Lists.newArrayList(this.map.keySet());
             Collections.sort(arraylist);
@@ -476,7 +478,7 @@ public class NBTTagCompound implements NBTBase {
     }
 
     // $FF: synthetic method
-    public NBTBase clone() {
+    public NBTBase clone_bad() { // Paper - decompile fix
         return this.clone();
     }
 }
diff --git a/src/main/java/net/minecraft/server/NetworkManager.java b/src/main/java/net/minecraft/server/NetworkManager.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/NetworkManager.java
+++ b/src/main/java/net/minecraft/server/NetworkManager.java
@@ -44,7 +44,7 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
         return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).build());
     });
     private final EnumProtocolDirection h;
-    private final Queue<NetworkManager.QueuedPacket> i = Queues.newConcurrentLinkedQueue();
+    private final Queue<NetworkManager.QueuedPacket> i = Queues.newConcurrentLinkedQueue(); private final Queue<NetworkManager.QueuedPacket> getPacketQueue() { return this.i; } // Paper - OBFHELPER
     private final ReentrantReadWriteLock j = new ReentrantReadWriteLock();
     public Channel channel;
     // Spigot Start // PAIL
@@ -168,6 +168,7 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
 
     }
 
+    private void dispatchPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> genericFutureListener) { this.b(packet, genericFutureListener); } // Paper - OBFHELPER
     private void b(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> genericfuturelistener) {
         EnumProtocol enumprotocol = EnumProtocol.a(packet);
         EnumProtocol enumprotocol1 = (EnumProtocol) this.channel.attr(NetworkManager.c).get();
@@ -208,6 +209,7 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
 
     }
 
+    private void sendPacketQueue() { this.o(); } // Paper - OBFHELPER
     private void o() {
         if (this.channel != null && this.channel.isOpen()) {
             this.j.readLock().lock();
@@ -338,9 +340,9 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
 
     static class QueuedPacket {
 
-        private final Packet<?> a;
+        private final Packet<?> a; private final Packet<?> getPacket() { return this.a; } // Paper - OBFHELPER
         @Nullable
-        private final GenericFutureListener<? extends Future<? super Void>> b;
+        private final GenericFutureListener<? extends Future<? super Void>> b; private final GenericFutureListener<? extends Future<? super Void>> getGenericFutureListener() { return this.b; } // Paper - OBFHELPER
 
         public QueuedPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> genericfuturelistener) {
             this.a = packet;
diff --git a/src/main/java/net/minecraft/server/PacketDataSerializer.java b/src/main/java/net/minecraft/server/PacketDataSerializer.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/PacketDataSerializer.java
+++ b/src/main/java/net/minecraft/server/PacketDataSerializer.java
@@ -33,6 +33,7 @@ public class PacketDataSerializer extends ByteBuf {
         this.a = bytebuf;
     }
 
+    public static int countBytes(int i) { return PacketDataSerializer.a(i); } // Paper - OBFHELPER
     public static int a(int i) {
         for (int j = 1; j < 5; ++j) {
             if ((i & -1 << j * 7) == 0) {
diff --git a/src/main/java/net/minecraft/server/PacketEncoder.java b/src/main/java/net/minecraft/server/PacketEncoder.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/PacketEncoder.java
+++ b/src/main/java/net/minecraft/server/PacketEncoder.java
@@ -38,6 +38,7 @@ public class PacketEncoder extends MessageToByteEncoder<Packet<?>> {
                     packet.b(packetdataserializer);
                 } catch (Throwable throwable) {
                     a.error(throwable);
+                    throwable.printStackTrace(); // Paper - WHAT WAS IT? WHO DID THIS TO YOU? WHAT DID YOU SEE?
                     if (packet.a()) {
                         throw new SkipEncodeException(throwable);
                     } else {
diff --git a/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java b/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java
+++ b/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java
@@ -11,7 +11,7 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
     private int a;
     private int b;
     private int c;
-    private byte[] d;
+    private byte[] d; private byte[] getData() { return this.d; } // Paper - OBFHELPER
     private List<NBTTagCompound> e;
     private boolean f;
 
@@ -85,6 +85,7 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
         return bytebuf;
     }
 
+    public int writeChunk(PacketDataSerializer packetDataSerializer, Chunk chunk, boolean writeSkyLightArray, int chunkSectionSelector) { return this.a(packetDataSerializer, chunk, writeSkyLightArray, chunkSectionSelector); } // Paper - OBFHELPER
     public int a(PacketDataSerializer packetdataserializer, Chunk chunk, boolean flag, int i) {
         int j = 0;
         ChunkSection[] achunksection = chunk.getSections();
diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
@@ -68,9 +68,9 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
     private final MinecraftServer minecraftServer;
     public EntityPlayer player;
     private int e;
-    private long f;
-    private boolean g;
-    private long h;
+    private long f; private void setLastPing(long lastPing) { this.f = lastPing;}; private long getLastPing() { return this.f;}; // Paper - OBFHELPER
+    private boolean g; private void setPendingPing(boolean isPending) { this.g = isPending;}; private boolean isPendingPing() { return this.g;}; // Paper - OBFHELPER
+    private long h; private void setKeepAliveID(long keepAliveID) { this.h = keepAliveID;}; private long getKeepAliveID() {return this.h; };  // Paper - OBFHELPER
     // CraftBukkit start - multithreaded fields
     private volatile int chatThrottle;
     private static final AtomicIntegerFieldUpdater chatSpamField = AtomicIntegerFieldUpdater.newUpdater(PlayerConnection.class, "chatThrottle");
diff --git a/src/main/java/net/minecraft/server/PotionUtil.java b/src/main/java/net/minecraft/server/PotionUtil.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/PotionUtil.java
+++ b/src/main/java/net/minecraft/server/PotionUtil.java
@@ -103,6 +103,7 @@ public class PotionUtil {
         return nbttagcompound == null ? Potions.EMPTY : PotionRegistry.a(nbttagcompound.getString("Potion"));
     }
 
+    public static ItemStack addPotionToItemStack(ItemStack itemstack, PotionRegistry potionregistry) { return a(itemstack, potionregistry); } // Paper - OBFHELPER
     public static ItemStack a(ItemStack itemstack, PotionRegistry potionregistry) {
         MinecraftKey minecraftkey = IRegistry.POTION.getKey(potionregistry);
         if (potionregistry == Potions.EMPTY) {
diff --git a/src/main/java/net/minecraft/server/RegistryBlockID.java b/src/main/java/net/minecraft/server/RegistryBlockID.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/RegistryBlockID.java
+++ b/src/main/java/net/minecraft/server/RegistryBlockID.java
@@ -54,6 +54,7 @@ public class RegistryBlockID<T> implements Registry<T> {
         return Iterators.filter(this.c.iterator(), Predicates.notNull());
     }
 
+    public int size() { return this.a(); } // Paper - OBFHELPER
     public int a() {
         return this.b.size();
     }
diff --git a/src/main/java/net/minecraft/server/SystemUtils.java b/src/main/java/net/minecraft/server/SystemUtils.java
index 7ac07ac07ac0..7ac07ac07ac0 100644
--- a/src/main/java/net/minecraft/server/SystemUtils.java
+++ b/src/main/java/net/minecraft/server/SystemUtils.java
@@ -34,8 +34,8 @@ public class SystemUtils {
         return Collectors.toMap(Entry::getKey, Entry::getValue);
     }
 
-    public static <T extends Comparable<T>> String a(IBlockState<T> iblockstate, Object object) {
-        return iblockstate.a((Comparable)object);
+    public static <T extends Comparable<T>> String a(IBlockState<T> iblockstate, T object) { // Paper - decompile fix
+        return iblockstate.a(object); // Paper - decompile fix
     }
 
     public static String a(String s, @Nullable MinecraftKey minecraftkey) {
@@ -43,11 +43,11 @@ public class SystemUtils {
     }
 
     public static long b() {
-        return c() / 1000000L;
+        return System.nanoTime() / 1000000L; // Paper
     }
 
     public static long c() {
-        return a.getAsLong();
+        return System.nanoTime(); // Paper
     }
 
     public static long d() {
@@ -109,7 +109,7 @@ public class SystemUtils {
             futuretask.run();
             return (V)futuretask.get();
         } catch (ExecutionException executionexception) {
-            logger.fatal("Error executing task", executionexception);
+            logger.fatal("Error executing task", executionexception.getCause() != null ? executionexception.getCause() : executionexception); // Paper
         } catch (InterruptedException interruptedexception) {
             logger.fatal("Error executing task", interruptedexception);
         }
@@ -169,7 +169,7 @@ public class SystemUtils {
     }
 
     public static <K> Strategy<K> g() {
-        return SystemUtils.IdentityHashingStrategy.INSTANCE;
+        return (Strategy<K>) IdentityHashingStrategy.INSTANCE; // Paper - decompile fix
     }
 
     static enum IdentityHashingStrategy implements Strategy<Object> {
-- 
2.19.1