diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java
index 1a4dc6ad3..a060c5995 100644
--- a/game/client/src/main/java/net/minecraft/client/Minecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java
@@ -14,7 +14,6 @@ import java.util.*;
 
 import com.mojang.logging.LogUtils;
 import com.mojang.nbt.tags.CompoundTag;
-import it.unimi.dsi.fastutil.objects.Object2IntMap;
 import it.unimi.dsi.fastutil.objects.Object2LongLinkedOpenHashMap;
 import it.unimi.dsi.fastutil.objects.Object2LongMap;
 import net.minecraft.client.console.LogMessageReceiver;
@@ -28,7 +27,6 @@ import net.minecraft.client.gui.chat.ScreenChat;
 import net.minecraft.client.gui.chat.ScreenSleepMP;
 import net.minecraft.client.gui.error.ScreenBadJavaArch;
 import net.minecraft.client.gui.error.ScreenConflictWarning;
-import net.minecraft.client.gui.error.ScreenMissingJCE;
 import net.minecraft.client.gui.error.ScreenMissingMinecraft;
 import net.minecraft.client.gui.error.ScreenOutOfMemory;
 import net.minecraft.client.gui.options.data.OptionsPages;
@@ -80,14 +78,14 @@ import net.minecraft.core.net.command.commands.CommandTestFor;
 import net.minecraft.core.net.command.commands.CommandTime;
 import net.minecraft.core.net.command.commands.CommandWeather;
 import net.minecraft.core.net.command.util.CommandHelper;
-import net.minecraft.core.util.collection.NamespaceID;
+import net.minecraft.core.util.pool.ObjectPool;
+import net.minecraft.core.util.helper.Color;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.LoggedPrintStream;
 import net.minecraft.core.util.helper.UUIDHelper;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.type.WorldTypeGroups;
 
-import javax.crypto.Cipher;
 import javax.imageio.ImageIO;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
@@ -182,7 +180,6 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.helper.Time;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.util.phys.HitResult;
-import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.PortalHandler;
 import net.minecraft.core.world.World;
@@ -672,6 +669,9 @@ public class Minecraft
             rpcThread.start();
         }
 
+        // Game has started - free any pooled objects that were created during startup
+        ObjectPool.freeAllPools();
+
         gameStarted = true;
 
         boolean hasBeta173 = true;
@@ -1014,9 +1014,7 @@ public class Minecraft
                 	
 					long tickStartTime = System.currentTimeMillis();
                     Time.tick();
-                    AABB.initializePool();
-                    Vec3.initializePool();
-                    NamespaceID.initializePool();
+                    ObjectPool.resetAllPools();
 
                     if(gameWindow.shouldClose()) shutdown();
                     if(isGamePaused && currentWorld != null && !(currentScreen instanceof ScreenModelViewer))
@@ -1122,6 +1120,50 @@ public class Minecraft
                     sndManager.setMuted(gameSettings.muteOnLostFocus.value && !gameWindow.isFocused());
                     guiToasts.render(timer.partialTicks);
 
+                    switch (downloadResourcesThread.downloading) {
+                        case DOWNLOADING: {
+                            double b = java.lang.Math.sin((System.currentTimeMillis() / 1000.0) * 4);
+                            b = b * 0.2 + 0.8;
+                            int ib = (int) java.lang.Math.round(b * 255);
+                            int color = 0xFF000000 | (ib << 16) | (ib << 8) | (ib);
+
+                            int barColor = Color.doubleToIntARGB(1, 0.5 * b, 1.0 * b, 0.5 * b);
+
+                            int sWidth = font.stringWidth(I18n.getInstance().translateKey("gui.main_menu.label.downloading_resources.2"));
+
+                            double progress = (double) downloadResourcesThread.downloadProgress.get() / downloadResourcesThread.toDownload;
+
+                            int minX = (resolution.getScaledWidthScreenCoords() - sWidth) / 2;
+                            int maxX = (resolution.getScaledWidthScreenCoords() + sWidth) / 2 + 1;
+
+                            guiToasts.drawRect(minX - 1, 6, maxX + 1, 38, 0xA0000000);
+                            guiToasts.drawStringCenteredShadow(
+                                font, I18n.getInstance().translateKey("gui.main_menu.label.downloading_resources.1"),
+                                resolution.getScaledWidthScreenCoords() / 2, 7, color);
+                            guiToasts.drawRectDouble(minX, 16, minX + sWidth * progress, 28, barColor);
+                            guiToasts.drawBox(minX, 16, maxX, 28, color, 1);
+                            guiToasts.drawStringCenteredShadow(font, String.format("%d / %d", downloadResourcesThread.downloadProgress.get(), downloadResourcesThread.toDownload), resolution.getScaledWidthScreenCoords() / 2, 18, color);
+                            guiToasts.drawStringCenteredShadow(font, I18n.getInstance().translateKey("gui.main_menu.label.downloading_resources.2"), resolution.getScaledWidthScreenCoords() / 2, 29, color);
+                            break;
+                        }
+                        case ERROR: {
+                            long timePassedSinceError = System.currentTimeMillis() - downloadResourcesThread.timeOfError;
+                            if (timePassedSinceError >= 35 * 1000) {
+                                break;
+                            }
+                            int sWidth = font.stringWidth(I18n.getInstance().translateKey("gui.main_menu.label.downloading_resources.connection.error"));
+
+                            int minX = (resolution.getScaledWidthScreenCoords() - sWidth) / 2;
+                            int maxX = (resolution.getScaledWidthScreenCoords() + sWidth) / 2;
+
+                            guiToasts.drawRect(minX - 2, 5, maxX + 2, 17, 0xA0000000);
+                            guiToasts.drawStringCenteredShadow(
+                                font, I18n.getInstance().translateKey("gui.main_menu.label.downloading_resources.connection.error"),
+                                resolution.getScaledWidthScreenCoords() / 2, 7, 0xFFFF0000);
+                            break;
+                        }
+                    }
+
                     Debug.change("post");  // 3
                     renderer.endRenderGame(timer.partialTicks);
                     
@@ -1214,9 +1256,7 @@ public class Minecraft
         try
         {
             System.gc();
-            AABB.deinitializePool();
-            Vec3.deinitializePool();
-            NamespaceID.deinitializePool();
+            ObjectPool.freeAllPools();
         }
         catch(Throwable ignored) { }
         try
diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
index 6fe80bb49..0d00d3633 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
@@ -20,6 +20,7 @@ import net.minecraft.client.gui.ScreenMobPicker;
 import net.minecraft.client.gui.container.ScreenTrommel;
 import net.minecraft.client.gui.ScreenWandMobPicker;
 import net.minecraft.client.gui.guidebook.ScreenGuidebook;
+import net.minecraft.client.gui.nbteditor.ScreenNBTEditor;
 import net.minecraft.client.input.PlayerInput;
 import net.minecraft.client.render.worldtype.WorldTypeFXDispatcher;
 import net.minecraft.core.achievement.Achievement;
@@ -55,8 +56,11 @@ import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 
+import java.util.function.Function;
+
 public class PlayerLocal extends Player
 {
     private static final Logger LOGGER = LogUtils.getLogger();
@@ -295,6 +299,11 @@ public class PlayerLocal extends Player
         displayContainerScreen(container);
     }
 
+    @Override
+    public void displayNBTEditor(@Nullable CompoundTag tag, @Nullable Function<@NotNull CompoundTag, Void> exitAction) {
+        mc.displayScreen(new ScreenNBTEditor("NBT Viewer", tag, exitAction));
+    }
+
     @Override
     public void displayWorkbenchScreen(int x, int y, int z)
     {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/Gui.java b/game/client/src/main/java/net/minecraft/client/gui/Gui.java
index f9d726850..765af2463 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/Gui.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/Gui.java
@@ -23,7 +23,7 @@ public class Gui
         this.zLevel = 0.0F;
     }
 
-    protected void drawLineHorizontal(int minX, int maxX, final int minY, final int argb)
+    public void drawLineHorizontal(int minX, int maxX, final int minY, final int argb)
     {
         if(maxX < minX)
         {
@@ -34,7 +34,7 @@ public class Gui
         drawRect(minX, minY, maxX + 1, minY + 1, argb);
     }
 
-    protected void drawLineHorizontalDouble(double minX, double maxX, final double minY, final int argb)
+    public void drawLineHorizontalDouble(double minX, double maxX, final double minY, final int argb)
     {
         if(maxX < minX)
         {
@@ -45,7 +45,7 @@ public class Gui
         drawRectDouble(minX, minY, maxX + 1, minY + 1, argb);
     }
 
-    protected void drawLineVertical(final int minX, int minY, int maxY, final int argb)
+    public void drawLineVertical(final int minX, int minY, int maxY, final int argb)
     {
         if(maxY < minY)
         {
@@ -56,7 +56,7 @@ public class Gui
         drawRect(minX, minY + 1, minX + 1, maxY, argb);
     }
 
-    protected void drawLineVerticalDouble(final double minX, double minY, double maxY, final int argb)
+    public void drawLineVerticalDouble(final double minX, double minY, double maxY, final int argb)
     {
         if(maxY < minY)
         {
@@ -99,7 +99,7 @@ public class Gui
         GL11.glEnable(GL_TEXTURE_2D);
         GL11.glDisable(GL_BLEND);
     }
-    protected void drawRectDouble(double minX, double minY, double maxX, double maxY, final int argb)
+    public void drawRectDouble(double minX, double minY, double maxX, double maxY, final int argb)
     {
         if(minX < maxX)
         {
@@ -132,14 +132,14 @@ public class Gui
         GL11.glDisable(GL_BLEND);
     }
 
-    protected void drawBox(final int minX, final int minY, final int maxX, final int maxY, final int argb, final int lineThickness) {
+    public void drawBox(final int minX, final int minY, final int maxX, final int maxY, final int argb, final int lineThickness) {
         drawRect(minX, minY, maxX, minY + lineThickness, argb);
         drawRect(minX, maxY - lineThickness, maxX, maxY, argb);
         drawRect(minX, minY + lineThickness, minX + lineThickness, maxY - lineThickness, argb);
         drawRect(maxX - lineThickness, minY + lineThickness, maxX, maxY - lineThickness, argb);
     }
 
-    protected void drawRectNoBlend(int minX, int minY, int maxX, int maxY, final int argb)
+    public void drawRectNoBlend(int minX, int minY, int maxX, int maxY, final int argb)
     {
         if(minX < maxX)
         {
@@ -169,7 +169,7 @@ public class Gui
         GL11.glEnable(GL_TEXTURE_2D);
     }
     
-    protected void drawRectWidthHeight(final int x, final int y, final int width, final int height, final int argb) {
+    public void drawRectWidthHeight(final int x, final int y, final int width, final int height, final int argb) {
     	final float a = ((argb >> 24) & 0xFF) / 255f;
     	final float r = ((argb >> 16) & 0xFF) / 255f;
     	final float g = ((argb >>  8) & 0xFF) / 255f;
@@ -186,7 +186,7 @@ public class Gui
         glEnable(GL_TEXTURE_2D);
     }
 
-    protected void drawGradientRect(final int minX, final int minY, final int maxX, final int maxY, final int argb1, final int argb2)
+    public void drawGradientRect(final int minX, final int minY, final int maxX, final int maxY, final int argb1, final int argb2)
     {
         final float a1 = (float)(argb1 >> 24 & 0xff) / 255F;
         final float r1 = (float)(argb1 >> 16 & 0xff) / 255F;
@@ -219,7 +219,7 @@ public class Gui
     public void drawStringCenteredShadow(final @NotNull FontRenderer fontRenderer, final @NotNull CharSequence chars, final int x, final int y, final int argb) {
         fontRenderer.renderCentered(Tessellator.instance, chars, x, y).setZ(this.zLevel).setShadow().setColor(argb).call();
     }
-    
+
     public void drawStringCenteredNoShadow(final @NotNull FontRenderer fontRenderer, final @NotNull CharSequence chars, final int x, final int y, final int argb) {
         fontRenderer.renderCentered(Tessellator.instance, chars, x, y).setZ(this.zLevel).setColor(argb).call();
     }
@@ -523,10 +523,10 @@ public class Gui
         }
     }
 
-    public void drawGuiIcon(final int x, final int y, final int width, final int height, final IconCoordinate coordinate) {
+    public void drawGuiIcon(final int x, final int y, final int width, final int height, final @NotNull IconCoordinate coordinate) {
         drawGuiIconDouble(x, y, width, height, coordinate);
     }
-    public void drawGuiIconDouble(final double x, final double y, final double width, final double height, final IconCoordinate coordinate) {
+    public void drawGuiIconDouble(final double x, final double y, final double width, final double height, final @NotNull IconCoordinate coordinate) {
         coordinate.parentAtlas.bind();
         final Tessellator t = Tessellator.instance;
         if (coordinate.hasMeta("gui")) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/Screen.java b/game/client/src/main/java/net/minecraft/client/gui/Screen.java
index 9f7b550a4..a107205bf 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/Screen.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/Screen.java
@@ -79,9 +79,11 @@ public abstract class Screen extends Gui {
     public void mouseClicked(int mx, int my, int buttonNum) {
         if (buttonNum == 0) {
             for (ButtonElement button : buttons) {
-                if (button.mouseClicked(mc, mx, my) && button.playSound) {
+                if (button.mouseClicked(mc, mx, my)) {
                     clickedButton = button;
-                    mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
+                    if (button.playSound) {
+                        mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
+                    }
                     if (button.listener != null) {
                         button.listener.listen(button);
                     } else {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java
index 75492bed0..42302ef96 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java
@@ -14,7 +14,7 @@ import java.util.Map;
 
 public class ScreenFontTest extends Screen{
     private static final char[] chars = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
-    private static final @NotNull NamespaceID testId = NamespaceID.getPermanent("test", "value");
+    private static final @NotNull NamespaceID testId = NamespaceID.fromPool("test", "value").copyUnpooled();
     private static final @NotNull StringBuilder builder = new StringBuilder();
     public double scroll = 0;
     public ScreenFontTest(final @Nullable Screen parent) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
index fa534ca2c..a32f30efb 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
@@ -362,18 +362,6 @@ public class ScreenMainMenu extends Screen
         String disclaimer2 = i18n.translateKey("gui.main_menu.label.disclaimer.2");
         drawStringShadow(fontRenderer, disclaimer2, width - MathHelper.ceil(fontRenderer.stringWidthDouble(disclaimer2)) - 2, height - 10, 0xffffff);
         super.render(mx, my, partialTick);
-        
-    	if(mc.downloadResourcesThread.downloading) {
-    		double b = java.lang.Math.sin((System.currentTimeMillis() / 1000.0) * 4);
-    		b = b * 0.2 + 0.8;
-    		int ib = (int) java.lang.Math.round(b * 255);
-    		int color = 0xFF000000 + (ib << 16) + (ib << 8) + (ib);
-
-            drawStringCenteredShadow(
-                mc.font, i18n.translateKeyAndFormat("gui.main_menu.label.downloading_resources.1", mc.downloadResourcesThread.downloadProgress.get(), mc.downloadResourcesThread.toDownload),
-                width / 2, 8, color);
-            drawStringCenteredShadow(mc.font, i18n.translateKey("gui.main_menu.label.downloading_resources.2"), width / 2, 17, color);
-    	}
     }
 
     private void drawLogo(final float partialTick) {
@@ -403,7 +391,7 @@ public class ScreenMainMenu extends Screen
         GL11.glDepthMask(true);
         GL11.glEnable(GL11.GL_DEPTH_TEST);
         Lighting.enableLight(0.5f, 0.16f);
-        
+
         for(int renderPass = 0; renderPass < 3; ++renderPass) {
             GL11.glPushMatrix();
             GL11.glTranslatef(0.4F, 0.6F, -12.0F);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java b/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java
index 3e5d3f2ac..ccfce48e5 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java
@@ -420,7 +420,6 @@ public class ScreenAchievements extends Screen
         }
 
         renderLabels();
-        GL11.glEnable(GL11.GL_LIGHTING);
         GL11.glEnable(GL11.GL_DEPTH_TEST);
 
         hoveredAchievement = null;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java
index 43b57c0dd..3f18e2a5e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java
@@ -650,18 +650,6 @@ public class HudIngame extends Gui
             tessellator.addVertexWithUV(itemEndX,                            20, 0.0f, 0, 0);
             tessellator.draw();
         }
-
-        if (mc.gameSettings.immersiveMode.drawOverlays() && mc.downloadResourcesThread.downloading) {
-            double b = java.lang.Math.sin((System.currentTimeMillis() / 1000.0) * 4);
-            b = b * 0.2 + 0.8;
-            int ib = (int) java.lang.Math.round(b * 255);
-            int color = 0xFF000000 + (ib << 16) + (ib << 8) + (ib);
-            drawStringCenteredShadow(
-                mc.font,
-                stringtranslate.translateKeyAndFormat("gui.main_menu.label.downloading_resources.1", mc.downloadResourcesThread.downloadProgress.get(), mc.downloadResourcesThread.toDownload),
-                width / 2, 16 + sp, color);
-            drawStringCenteredShadow(mc.font, stringtranslate.translateKey("gui.main_menu.label.downloading_resources.2"), width / 2, 25 + sp, color);
-        }
     }
 
     private int debugLine = 0;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/ScreenNBTEditor.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/ScreenNBTEditor.java
new file mode 100644
index 000000000..d9a477db9
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/ScreenNBTEditor.java
@@ -0,0 +1,149 @@
+package net.minecraft.client.gui.nbteditor;
+
+import com.mojang.logging.LogUtils;
+import com.mojang.nbt.tags.CompoundTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.gui.nbteditor.components.AbstractTagComponent;
+import net.minecraft.client.gui.nbteditor.components.CompoundTagComponent;
+import net.minecraft.client.render.Scissor;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Function;
+
+public class ScreenNBTEditor extends Screen {
+    private static final Logger LOGGER = LogUtils.getLogger();
+
+    public final @Nullable String title;
+    public final @Nullable CompoundTag inputTag;
+    public final @Nullable Function<@NotNull CompoundTag, Void> tagAction;
+
+    private final CompoundTagComponent compoundTagComponent;
+    private double scroll = 0;
+
+    public ScreenNBTEditor(@Nullable String title, @Nullable CompoundTag inputTag, @Nullable Function<@NotNull CompoundTag, Void> exitAction) {
+        this(null, title, inputTag, exitAction);
+    }
+
+    public ScreenNBTEditor(@Nullable Screen parentScreen, @Nullable String title, @Nullable CompoundTag inputTag, @Nullable Function<@NotNull CompoundTag, Void> exitAction) {
+        super(parentScreen);
+        this.title = title;
+        this.inputTag = inputTag;
+        this.tagAction = exitAction;
+
+        this.compoundTagComponent = new CompoundTagComponent(this, new CompoundTag(inputTag));
+        this.compoundTagComponent.expanded = true;
+    }
+
+
+    @Override
+    public void removed() {
+        if (this.tagAction != null) {
+            this.tagAction.apply((CompoundTag) compoundTagComponent.tag);
+        }
+    }
+
+    @Override
+    public void render(int mx, int my, float partialTick) {
+        int compHeight = compoundTagComponent.height(-1, -1, partialTick);
+        int minScroll = 0;
+        int maxScroll = Math.max(compHeight - (height - 84), 0);
+        this.scroll += Mouse.getDWheel() * 10;
+        this.scroll = MathHelper.clamp(this.scroll, -maxScroll, minScroll);
+
+        renderBackground();
+        super.render(mx, my, partialTick);
+
+        Tessellator t = Tessellator.instance;
+
+        {
+            int popupWidth = width/2 + 40;
+            int popupHeight = height - 40;
+            int popupX = width / 2 - popupWidth / 2;
+            int popupY = height / 2 - popupHeight / 2;
+
+            GL11.glDisable(GL11.GL_LIGHTING);
+            GL11.glDisable(GL11.GL_FOG);
+            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
+
+            GL11.glEnable(GL11.GL_TEXTURE_2D);
+            float f = 32F;
+            t.startDrawingQuads();
+            mc.textureManager.loadTexture("/assets/minecraft/textures/gui/background.png").bind();
+            t.setColorOpaque_I(0x404040);
+            t.addVertexWithUV(popupX, popupY + popupHeight, 0.0D, 0.0D, (float)popupHeight / f);
+            t.addVertexWithUV(popupX + popupWidth, popupY + popupHeight, 0.0D, (float)popupWidth / f, (float)popupHeight / f);
+            t.addVertexWithUV(popupX + popupWidth, popupY, 0.0D, (float)popupWidth / f, 0);
+            t.addVertexWithUV(popupX, popupY, 0.0D, 0.0D, 0);
+            t.draw();
+
+            drawRect(width/4, 40, (width * 3)/4, height - 40, 0x88000000);
+        }
+
+        fontRenderer.renderCentered(t, title, width/2, 26).setShadow().call();
+
+        if (minScroll != maxScroll) {
+            drawRect((width * 3)/4 - 5, 41, (width * 3)/4 - 1, height - 43, 0xFF000000);
+
+            int scrollableRegion = compHeight;
+            int regionHeight = height - 84;
+            int sMin = (int) scroll;
+
+            int barMinX = (width * 3)/4 - 6;
+            int barMaxX = (width * 3)/4 - 2;
+            int barMinY = (42 - MathHelper.round(((double)sMin/scrollableRegion) * regionHeight));
+            int barMaxY = barMinY + MathHelper.round(((double)regionHeight/scrollableRegion) * regionHeight);
+
+            boolean hovered = mx >= barMinX && mx <= barMaxX && my >= barMinY && my <= barMaxY;
+            drawRect(barMinX, barMinY, barMaxX, barMaxY, hovered ? 0xFFCCCCFF : 0xFFFFFFFF);
+        }
+
+        Scissor.enable(width/4 - 20, 40, width/2 + 13, height - 80);
+        int y = (int) (42 + scroll);
+        boolean inPane =
+            mx >= width/4 - 20 &&
+            mx <=(width * 3)/4 -20 + 13 &&
+            my >= 40 &&
+            my <= height - 40;
+        compoundTagComponent.render(t, width/4 + 2, y, inPane ? mx - width/4 : -1, inPane ? my - y : -1, partialTick);
+        Scissor.disable();
+
+        drawBox(width/4 - 20, 20, (width * 3)/4 + 20, height - 20, 0xFFFFFFFF, 1);
+        drawBox(width/4, 40, (width * 3)/4, height - 40, 0xFFFFFFFF, 1);
+    }
+
+    @Override
+    public void mouseClicked(int mx, int my, int buttonNum) {
+        super.mouseClicked(mx, my, buttonNum);
+
+        int y = (int) (42 + scroll);
+        boolean inPane =
+            mx >= width/4 - 20 &&
+                mx <=(width * 3)/4 -20 + 13 &&
+                my >= 40 &&
+                my <= height - 40;
+        compoundTagComponent.onMouseClick(inPane ? mx - width/4 : -1, inPane ? my - y : -1, buttonNum, 1);
+    }
+
+    @Override
+    public void mouseReleased(int mx, int my, int buttonNum) {
+        super.mouseReleased(mx, my, buttonNum);
+
+        int y = (int) (42 + scroll);
+        boolean inPane =
+            mx >= width/4 - 20 &&
+                mx <=(width * 3)/4 -20 + 13 &&
+                my >= 40 &&
+                my <= height - 40;
+        compoundTagComponent.onMouseRelease(inPane ? mx - width/4 : -1, inPane ? my - y : -1, buttonNum, 1);
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/AbstractTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/AbstractTagComponent.java
new file mode 100644
index 000000000..e31a922bf
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/AbstractTagComponent.java
@@ -0,0 +1,85 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.ByteArrayTag;
+import com.mojang.nbt.tags.ByteTag;
+import com.mojang.nbt.tags.CompoundTag;
+import com.mojang.nbt.tags.DoubleArrayTag;
+import com.mojang.nbt.tags.DoubleTag;
+import com.mojang.nbt.tags.FloatTag;
+import com.mojang.nbt.tags.IntTag;
+import com.mojang.nbt.tags.ListTag;
+import com.mojang.nbt.tags.LongArrayTag;
+import com.mojang.nbt.tags.LongTag;
+import com.mojang.nbt.tags.ShortArrayTag;
+import com.mojang.nbt.tags.ShortTag;
+import com.mojang.nbt.tags.StringTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.opengl.GL11;
+
+public abstract class AbstractTagComponent<T> extends Gui {
+    public static final int COLOR_BACKGROUND = 0x88A0A0A0;
+    public static final int COLOR_BACKGROUND_HIGHLIGHTED = 0x886060A0;
+    public static final int SHIFT_RIGHT = 13;
+    public static final int COMPONENT_PADDING = 1;
+    public static final int TEXT_PADDING = 2;
+
+    public final @NotNull Screen attachedScreen;
+    public final @NotNull Tag<T> tag;
+    public AbstractTagComponent(@NotNull Screen attachedScreen, @NotNull Tag<T> tag) {
+        this.attachedScreen = attachedScreen;
+        this.tag = tag;
+    }
+
+    public void render(@NotNull Tessellator t, int offX, int offY, int mx, int my, float partialTick) {
+        GL11.glColor4f(1, 1, 1, 1);
+        drawGuiIcon(offX, offY, 12, 12, getIcon(mx, my, partialTick));
+    }
+
+    public int height(int mx, int my, float partialTick) {
+        return 12;
+    }
+    public int width(int mx, int my, float partialTick) {
+        return attachedScreen.width/2;
+    }
+
+    public boolean isHovered(int mx, int my, float partialTick) {
+        int h = height(mx, my, partialTick);
+        int w = width(mx, my, partialTick);
+        return mx >= 0 && mx <= w && my >= 0 && my <= h;
+    }
+
+    public void onMouseClick(int mx, int my, int mouseButton, float partialTick) {
+
+    }
+
+    public void onMouseRelease(int mx, int my, int mouseButton, float partialTick) {
+
+    }
+
+    public abstract @NotNull IconCoordinate getIcon(int mx, int my, float partialTick);
+
+    public static @Nullable AbstractTagComponent componentForTag(@NotNull Screen attachedScreen, @NotNull Tag<?> tag) {
+        switch (Tag.TagID.fromId(tag.getId())) {
+            case TAG_BYTE: return new ByteTagComponent(attachedScreen, (ByteTag) tag);
+            case TAG_SHORT: return new ShortTagComponent(attachedScreen, (ShortTag) tag);
+            case TAG_INT: return new IntTagComponent(attachedScreen, (IntTag) tag);
+            case TAG_LONG: return new LongTagComponent(attachedScreen, (LongTag) tag);
+            case TAG_FLOAT: return new FloatTagComponent(attachedScreen, (FloatTag) tag);
+            case TAG_DOUBLE: return new DoubleTagComponent(attachedScreen, (DoubleTag) tag);
+            case TAG_BYTE_ARRAY: return new ByteArrayTagComponent(attachedScreen, (ByteArrayTag) tag);
+            case TAG_STRING: return new StringTagComponent(attachedScreen, (StringTag) tag);
+            case TAG_LIST: return new ListTagComponent(attachedScreen, (ListTag) tag);
+            case TAG_COMPOUND: return new CompoundTagComponent(attachedScreen, (CompoundTag) tag);
+            case TAG_SHORT_ARRAY: return new ShortArrayTagComponent(attachedScreen, (ShortArrayTag) tag);
+            case TAG_DOUBLE_ARRAY: return new DoubleArrayTagComponent(attachedScreen, (DoubleArrayTag) tag);
+            case TAG_LONG_ARRAY: return new LongArrayTagComponent(attachedScreen, (LongArrayTag) tag);
+            default: return null;
+        }
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ArrayTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ArrayTagComponent.java
new file mode 100644
index 000000000..c23eb9589
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ArrayTagComponent.java
@@ -0,0 +1,45 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.logging.LogUtils;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.gui.popup.PopupBuilder;
+import net.minecraft.client.render.tessellator.Tessellator;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+
+import java.lang.reflect.Array;
+
+public abstract class ArrayTagComponent<T> extends AbstractTagComponent<T> {
+    private static final Logger LOGGER = LogUtils.getLogger();
+
+    public ArrayTagComponent(@NotNull Screen attachedScreen, @NotNull Tag<T> tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public void onMouseClick(int mx, int my, int mouseButton, float partialTick) {
+        if (isHovered(mx, my, partialTick)) {
+            if (mouseButton == 0) {
+                attachedScreen.mc.displayScreen(new PopupBuilder(attachedScreen, 400).withTextField("input", valueToString())
+                    .closeOnEsc(0)
+                    .closeOnEnter(0)
+                    .closeOnClickOut(0)
+                    .withOnCloseListener((statusCode, results) -> {
+                        if (statusCode == 0) {
+                            try {
+                                parseValueFromString((String) results.get("input"));
+                            } catch (Exception e) {
+                                LOGGER.error("Failed to parse input '{}' into a '{}'!", results.get("input"), this.tag.getClass().getSimpleName(), e);
+                            }
+                        }
+                    })
+                    .build());
+            }
+        }
+    }
+
+    public abstract @NotNull String valueToString();
+
+    public abstract void parseValueFromString(@NotNull String valueString) throws Exception;
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ByteArrayTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ByteArrayTagComponent.java
new file mode 100644
index 000000000..2c117f799
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ByteArrayTagComponent.java
@@ -0,0 +1,59 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.logging.LogUtils;
+import com.mojang.nbt.tags.ByteArrayTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.gui.popup.PopupBuilder;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.util.helper.DyeColor;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+
+public class ByteArrayTagComponent extends ArrayTagComponent<byte[]> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/byte_array_tag");
+
+    public ByteArrayTagComponent(@NotNull Screen attachedScreen, @NotNull ByteArrayTag tag) {
+        super(attachedScreen, tag);
+
+    }
+
+    @Override
+    public void render(@NotNull Tessellator t, int offX, int offY, int mx, int my, float partialTick) {
+        super.render(t, offX, offY, mx, my, partialTick);
+        drawRect(offX + 12 + COMPONENT_PADDING, offY, offX + width(mx, my, partialTick), offY + height(mx, my, partialTick), isHovered(mx, my, partialTick) ? COLOR_BACKGROUND_HIGHLIGHTED : COLOR_BACKGROUND);
+        attachedScreen.fontRenderer.render(t, tag.getTagName(), offX + 12 + COMPONENT_PADDING + TEXT_PADDING, offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, ": ", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, this.tag.getValue().length, attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+        attachedScreen.fontRenderer.render(t, " bytes", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public @NotNull String valueToString() {
+        StringBuilder builder = new StringBuilder();
+        byte[] bytes = this.tag.getValue();
+        for (int i = 0; i < bytes.length; i++) {
+            if (i != 0) {
+                builder.append(", ");
+            }
+            builder.append(bytes[i]);
+        }
+        return builder.toString();
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) throws Exception {
+        String[] split = valueString.replace(" ", "").split(",");
+        byte[] bytes = new byte[split.length];
+        for (int i = 0; i < split.length; i++) {
+            bytes[i] = Byte.parseByte(split[i]);
+        }
+        this.tag.setValue(bytes);
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ByteTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ByteTagComponent.java
new file mode 100644
index 000000000..0f8d2f715
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ByteTagComponent.java
@@ -0,0 +1,25 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.ByteTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import org.jetbrains.annotations.NotNull;
+
+public class ByteTagComponent extends ValueTagComponent<Byte>{
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/byte_tag");
+
+    public ByteTagComponent(@NotNull Screen attachedScreen, @NotNull ByteTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) {
+        this.tag.setValue(Byte.parseByte(valueString));
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/CompoundTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/CompoundTagComponent.java
new file mode 100644
index 000000000..da7136917
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/CompoundTagComponent.java
@@ -0,0 +1,109 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.CompoundTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.util.helper.DyeColor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class CompoundTagComponent extends AbstractTagComponent<@NotNull Map<String, Tag<?>>> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/compound_tag");
+
+    public boolean expanded = false;
+    public final List<AbstractTagComponent<?>> components = new ArrayList<>();
+
+    public CompoundTagComponent(@NotNull Screen attachedScreen, @NotNull CompoundTag tag) {
+        super(attachedScreen, tag);
+
+        for (Tag<?> t : tag.getValue().values()) {
+            components.add(ArrayTagComponent.componentForTag(attachedScreen,t));
+        }
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void render(@NotNull Tessellator t, int offX, int offY, int mx, int my, float partialTick) {
+        super.render(t, offX, offY, mx, my, partialTick);
+        drawRect(offX + 12 + COMPONENT_PADDING, offY, offX + super.width(mx, my, partialTick), offY + super.height(mx, my, partialTick),
+            (mx >= 0 && mx <= super.width(mx, my, partialTick) && my >= 0 && my <= super.height(mx, my, partialTick)) ? COLOR_BACKGROUND_HIGHLIGHTED : COLOR_BACKGROUND);
+        attachedScreen.fontRenderer.render(t, tag.getTagName(), offX + 12 + COMPONENT_PADDING + TEXT_PADDING, offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, ": ", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, this.tag.getValue().size(), attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+        attachedScreen.fontRenderer.render(t, " entries", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+
+        if (expanded) {
+            int y = offY + super.height(mx, my, partialTick) + COMPONENT_PADDING;
+            for (AbstractTagComponent component : components) {
+                drawLineHorizontal(offX + 6, offX + SHIFT_RIGHT - 2, y + 6, 0xFFFFFFFF);
+
+                component.render(t, offX + SHIFT_RIGHT, y, mx - SHIFT_RIGHT, my - y + offY, partialTick);
+                y += component.height(mx - SHIFT_RIGHT, my - y + offY, partialTick) + COMPONENT_PADDING;
+            }
+            drawLineVertical(offX + 6, offY + super.height(mx, my, partialTick), y - 6, 0xFFFFFFFF);
+        }
+    }
+
+    @Override
+    public int height(int mx, int my, float partialTick) {
+        if (expanded) {
+            int height = super.height(mx, my, partialTick);
+            for (AbstractTagComponent component : components) {
+                my -= component.height(mx - SHIFT_RIGHT, my, partialTick) + COMPONENT_PADDING;
+                height += component.height(mx - SHIFT_RIGHT, my, partialTick) + COMPONENT_PADDING;
+            }
+            return height;
+        }
+        return super.height(mx, my, partialTick);
+    }
+
+    @Override
+    public int width(int mx, int my, float partialTick) {
+        if (expanded) {
+            int width = super.width(mx, my, partialTick);
+            for (AbstractTagComponent component : components) {
+                my -= component.height(mx - SHIFT_RIGHT, my, partialTick) + COMPONENT_PADDING;
+                width = Math.max(width, component.width(mx - SHIFT_RIGHT, my, partialTick));
+            }
+            return width;
+        }
+        return super.width(mx, my, partialTick);
+    }
+
+    @Override
+    public void onMouseClick(int mx, int my, int mouseButton, float partialTick) {
+        if (mx >= 0 && mx <= super.width(mx, my, partialTick) && my >= 0 && my <= super.height(mx, my, partialTick)) {
+            if (mouseButton == 0) {
+                expanded = !expanded;
+            }
+        } else if (expanded) {
+            int y = my - super.height(mx, my, partialTick);
+            for (AbstractTagComponent component : components) {
+                component.onMouseClick(mx - SHIFT_RIGHT, y, mouseButton, partialTick);
+                y -= component.height(mx - SHIFT_RIGHT, y, partialTick) + COMPONENT_PADDING;
+            }
+        }
+    }
+
+    @Override
+    public void onMouseRelease(int mx, int my, int mouseButton, float partialTick) {
+        if (expanded) {
+            int y = my - super.height(mx, my, partialTick);
+            for (AbstractTagComponent component : components) {
+                component.onMouseRelease(mx - SHIFT_RIGHT, y, mouseButton, partialTick);
+                y -= component.height(mx - SHIFT_RIGHT, y, partialTick) + COMPONENT_PADDING;
+            }
+        }
+    }
+
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/DoubleArrayTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/DoubleArrayTagComponent.java
new file mode 100644
index 000000000..591c9a606
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/DoubleArrayTagComponent.java
@@ -0,0 +1,56 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.DoubleArrayTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.util.helper.DyeColor;
+import org.jetbrains.annotations.NotNull;
+
+public class DoubleArrayTagComponent extends ArrayTagComponent<double[]> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/double_array_tag");
+
+    public DoubleArrayTagComponent(@NotNull Screen attachedScreen, @NotNull DoubleArrayTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void render(@NotNull Tessellator t, int offX, int offY, int mx, int my, float partialTick) {
+        super.render(t, offX, offY, mx, my, partialTick);
+        drawRect(offX + 12 + COMPONENT_PADDING, offY, offX + width(mx, my, partialTick), offY + height(mx, my, partialTick), isHovered(mx, my, partialTick) ? COLOR_BACKGROUND_HIGHLIGHTED : COLOR_BACKGROUND);
+        attachedScreen.fontRenderer.render(t, tag.getTagName(), offX + 12 + COMPONENT_PADDING + TEXT_PADDING, offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, ": ", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, this.tag.getValue().length, attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+        attachedScreen.fontRenderer.render(t, " doubles", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+    }
+
+    @Override
+    public @NotNull String valueToString() {
+        StringBuilder builder = new StringBuilder();
+        double[] doubles = this.tag.getValue();
+        for (int i = 0; i < doubles.length; i++) {
+            if (i != 0) {
+                builder.append(", ");
+            }
+            builder.append(doubles[i]);
+        }
+        return builder.toString();
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) throws Exception {
+        String[] split = valueString.replace(" ", "").split(",");
+        double[] doubles = new double[split.length];
+        for (int i = 0; i < split.length; i++) {
+            doubles[i] = Double.parseDouble(split[i]);
+        }
+        this.tag.setValue(doubles);
+    }
+
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/DoubleTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/DoubleTagComponent.java
new file mode 100644
index 000000000..804e13016
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/DoubleTagComponent.java
@@ -0,0 +1,25 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.DoubleTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import org.jetbrains.annotations.NotNull;
+
+public class DoubleTagComponent extends ValueTagComponent<Double>{
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/double_tag");
+
+    public DoubleTagComponent(@NotNull Screen attachedScreen, @NotNull DoubleTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) {
+        this.tag.setValue(Double.parseDouble(valueString));
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/FloatTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/FloatTagComponent.java
new file mode 100644
index 000000000..5a8118603
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/FloatTagComponent.java
@@ -0,0 +1,25 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.FloatTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import org.jetbrains.annotations.NotNull;
+
+public class FloatTagComponent extends ValueTagComponent<Float> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/float_tag");
+
+    public FloatTagComponent(@NotNull Screen attachedScreen, @NotNull FloatTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) {
+        this.tag.setValue(Float.parseFloat(valueString));
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/IntTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/IntTagComponent.java
new file mode 100644
index 000000000..0621b7c75
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/IntTagComponent.java
@@ -0,0 +1,25 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.IntTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import org.jetbrains.annotations.NotNull;
+
+public class IntTagComponent extends ValueTagComponent<Integer> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/int_tag");
+
+    public IntTagComponent(@NotNull Screen attachedScreen, @NotNull IntTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) {
+        this.tag.setValue(Integer.parseInt(valueString));
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ListTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ListTagComponent.java
new file mode 100644
index 000000000..fb4b281ca
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ListTagComponent.java
@@ -0,0 +1,107 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.ListTag;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.util.helper.DyeColor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ListTagComponent extends AbstractTagComponent<List<Tag<?>>>{
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/list_tag");
+
+    public boolean expanded = false;
+    public final List<AbstractTagComponent<?>> components = new ArrayList<>();
+
+    public ListTagComponent(@NotNull Screen attachedScreen, @NotNull ListTag tag) {
+        super(attachedScreen, tag);
+
+        for (Tag<?> t : tag) {
+            components.add(ArrayTagComponent.componentForTag(attachedScreen,t));
+        }
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void render(@NotNull Tessellator t, int offX, int offY, int mx, int my, float partialTick) {
+        super.render(t, offX, offY, mx, my, partialTick);
+        drawRect(offX + 12 + COMPONENT_PADDING, offY, offX + super.width(mx, my, partialTick), offY + super.height(mx, my, partialTick),
+            (mx >= 0 && mx <= super.width(mx, my, partialTick) && my >= 0 && my <= super.height(mx, my, partialTick)) ? COLOR_BACKGROUND_HIGHLIGHTED : COLOR_BACKGROUND);
+        attachedScreen.fontRenderer.render(t, tag.getTagName(), offX + 12 + COMPONENT_PADDING + TEXT_PADDING, offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, ": ", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, this.tag.getValue().size(), attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+        attachedScreen.fontRenderer.render(t, " entries", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+
+        if (expanded) {
+            int y = offY + super.height(mx, my, partialTick) + COMPONENT_PADDING;
+            for (AbstractTagComponent component : components) {
+                drawLineHorizontal(offX + 6, offX + SHIFT_RIGHT - 2, y + 6, 0xFFFFFFFF);
+
+                component.render(t, offX + SHIFT_RIGHT, y, mx - SHIFT_RIGHT, my - y + offY, partialTick);
+                y += component.height(mx - SHIFT_RIGHT, my - y + offY, partialTick) + COMPONENT_PADDING;
+            }
+            drawLineVertical(offX + 6, offY + super.height(mx, my, partialTick), y - 6, 0xFFFFFFFF);
+        }
+    }
+
+    @Override
+    public int height(int mx, int my, float partialTick) {
+        if (expanded) {
+            int height = super.height(mx, my, partialTick);
+            for (AbstractTagComponent component : components) {
+                my -= component.height(mx - SHIFT_RIGHT, my, partialTick) + COMPONENT_PADDING;
+                height += component.height(mx - SHIFT_RIGHT, my, partialTick) + COMPONENT_PADDING;
+            }
+            return height;
+        }
+        return super.height(mx, my, partialTick);
+    }
+
+    @Override
+    public int width(int mx, int my, float partialTick) {
+        if (expanded) {
+            int width = super.width(mx, my, partialTick);
+            for (AbstractTagComponent component : components) {
+                my -= component.height(mx - SHIFT_RIGHT, my, partialTick) + COMPONENT_PADDING;
+                width = Math.max(width, component.width(mx - SHIFT_RIGHT, my, partialTick));
+            }
+            return width;
+        }
+        return super.width(mx, my, partialTick);
+    }
+
+    @Override
+    public void onMouseClick(int mx, int my, int mouseButton, float partialTick) {
+        if (mx >= 0 && mx <= super.width(mx, my, partialTick) && my >= 0 && my <= super.height(mx, my, partialTick)) {
+            if (mouseButton == 0) {
+                expanded = !expanded;
+            }
+        } else if (expanded) {
+            int y = my - super.height(mx, my, partialTick);
+            for (AbstractTagComponent component : components) {
+                component.onMouseClick(mx - SHIFT_RIGHT, y, mouseButton, partialTick);
+                y -= component.height(mx - SHIFT_RIGHT, y, partialTick) + COMPONENT_PADDING;
+            }
+        }
+    }
+
+    @Override
+    public void onMouseRelease(int mx, int my, int mouseButton, float partialTick) {
+        if (expanded) {
+            int y = my - super.height(mx, my, partialTick);
+            for (AbstractTagComponent component : components) {
+                component.onMouseRelease(mx - SHIFT_RIGHT, y, mouseButton, partialTick);
+                y -= component.height(mx - SHIFT_RIGHT, y, partialTick) + COMPONENT_PADDING;
+            }
+        }
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/LongArrayTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/LongArrayTagComponent.java
new file mode 100644
index 000000000..12e9bbe14
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/LongArrayTagComponent.java
@@ -0,0 +1,55 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.LongArrayTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.util.helper.DyeColor;
+import org.jetbrains.annotations.NotNull;
+
+public class LongArrayTagComponent extends ArrayTagComponent<long[]> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/long_array_tag");
+
+    public LongArrayTagComponent(@NotNull Screen attachedScreen, @NotNull LongArrayTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void render(@NotNull Tessellator t, int offX, int offY, int mx, int my, float partialTick) {
+        super.render(t, offX, offY, mx, my, partialTick);
+        drawRect(offX + 12 + COMPONENT_PADDING, offY, offX + width(mx, my, partialTick), offY + height(mx, my, partialTick), isHovered(mx, my, partialTick) ? COLOR_BACKGROUND_HIGHLIGHTED : COLOR_BACKGROUND);
+        attachedScreen.fontRenderer.render(t, tag.getTagName(), offX + 12 + COMPONENT_PADDING + TEXT_PADDING, offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, ": ", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, this.tag.getValue().length, attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+        attachedScreen.fontRenderer.render(t, " longs", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+    }
+
+    @Override
+    public @NotNull String valueToString() {
+        StringBuilder builder = new StringBuilder();
+        long[] longs = this.tag.getValue();
+        for (int i = 0; i < longs.length; i++) {
+            if (i != 0) {
+                builder.append(", ");
+            }
+            builder.append(longs[i]);
+        }
+        return builder.toString();
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) throws Exception {
+        String[] split = valueString.replace(" ", "").split(",");
+        long[] longs = new long[split.length];
+        for (int i = 0; i < split.length; i++) {
+            longs[i] = Long.parseLong(split[i]);
+        }
+        this.tag.setValue(longs);
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/LongTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/LongTagComponent.java
new file mode 100644
index 000000000..ba88f5637
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/LongTagComponent.java
@@ -0,0 +1,25 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.LongTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import org.jetbrains.annotations.NotNull;
+
+public class LongTagComponent extends ValueTagComponent<Long> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/long_tag");
+
+    public LongTagComponent(@NotNull Screen attachedScreen, @NotNull LongTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) {
+        this.tag.setValue(Long.parseLong(valueString));
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ShortArrayTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ShortArrayTagComponent.java
new file mode 100644
index 000000000..3e71cb7e3
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ShortArrayTagComponent.java
@@ -0,0 +1,56 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.ShortArrayTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.util.helper.DyeColor;
+import org.jetbrains.annotations.NotNull;
+
+public class ShortArrayTagComponent extends ArrayTagComponent<short[]> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/short_array_tag");
+
+    public ShortArrayTagComponent(@NotNull Screen attachedScreen, @NotNull ShortArrayTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void render(@NotNull Tessellator t, int offX, int offY, int mx, int my, float partialTick) {
+        super.render(t, offX, offY, mx, my, partialTick);
+        drawRect(offX + 12 + COMPONENT_PADDING, offY, offX + width(mx, my, partialTick), offY + height(mx, my, partialTick), isHovered(mx, my, partialTick) ? COLOR_BACKGROUND_HIGHLIGHTED : COLOR_BACKGROUND);
+        attachedScreen.fontRenderer.render(t, tag.getTagName(), offX + 12 + COMPONENT_PADDING + TEXT_PADDING, offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, ": ", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, this.tag.getValue().length, attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+        attachedScreen.fontRenderer.render(t, " shorts", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).call();
+    }
+
+    @Override
+    public @NotNull String valueToString() {
+        StringBuilder builder = new StringBuilder();
+        short[] shorts = this.tag.getValue();
+        for (int i = 0; i < shorts.length; i++) {
+            if (i != 0) {
+                builder.append(", ");
+            }
+            builder.append(shorts[i]);
+        }
+        return builder.toString();
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) throws Exception {
+        String[] split = valueString.replace(" ", "").split(",");
+        short[] shorts = new short[split.length];
+        for (int i = 0; i < split.length; i++) {
+            shorts[i] = Short.parseShort(split[i]);
+        }
+        this.tag.setValue(shorts);
+    }
+
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ShortTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ShortTagComponent.java
new file mode 100644
index 000000000..b7c5af162
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ShortTagComponent.java
@@ -0,0 +1,25 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.ShortTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import org.jetbrains.annotations.NotNull;
+
+public class ShortTagComponent extends ValueTagComponent<Short> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/short_tag");
+
+    public ShortTagComponent(@NotNull Screen attachedScreen, @NotNull ShortTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) {
+        this.tag.setValue(Short.parseShort(valueString));
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/StringTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/StringTagComponent.java
new file mode 100644
index 000000000..6cd969b7c
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/StringTagComponent.java
@@ -0,0 +1,25 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.nbt.tags.StringTag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.render.texture.stitcher.IconCoordinate;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import org.jetbrains.annotations.NotNull;
+
+public class StringTagComponent extends ValueTagComponent<String> {
+    public static final @NotNull IconCoordinate icon = TextureRegistry.getTexture("minecraft:gui/screen/nbt/string_tag");
+
+    public StringTagComponent(@NotNull Screen attachedScreen, @NotNull StringTag tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public @NotNull IconCoordinate getIcon(int mx, int my, float partialTick) {
+        return icon;
+    }
+
+    @Override
+    public void parseValueFromString(@NotNull String valueString) {
+        this.tag.setValue(valueString);
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ValueTagComponent.java b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ValueTagComponent.java
new file mode 100644
index 000000000..27bcc7032
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/nbteditor/components/ValueTagComponent.java
@@ -0,0 +1,55 @@
+package net.minecraft.client.gui.nbteditor.components;
+
+import com.mojang.logging.LogUtils;
+import com.mojang.nbt.tags.Tag;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.client.gui.popup.PopupBuilder;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.util.helper.DyeColor;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+
+public abstract class ValueTagComponent<T> extends AbstractTagComponent<T>{
+    private static final Logger LOGGER = LogUtils.getLogger();
+    public ValueTagComponent(@NotNull Screen attachedScreen, @NotNull Tag<T> tag) {
+        super(attachedScreen, tag);
+    }
+
+    @Override
+    public void render(@NotNull Tessellator t, int offX, int offY, int mx, int my, float partialTick) {
+        super.render(t, offX, offY, mx, my, partialTick);
+        drawRect(offX + 12 + COMPONENT_PADDING, offY, offX + width(mx, my, partialTick), offY + height(mx, my, partialTick), isHovered(mx, my, partialTick) ? COLOR_BACKGROUND_HIGHLIGHTED : COLOR_BACKGROUND);
+        attachedScreen.fontRenderer.render(t, tag.getTagName(), offX + 12 + COMPONENT_PADDING + TEXT_PADDING, offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, ": ", attachedScreen.fontRenderer.getLastEndingX(), offY + TEXT_PADDING).setColor(DyeColor.YELLOW.color).call();
+        attachedScreen.fontRenderer.render(t, tag.getValue().toString(), attachedScreen.fontRenderer.getLastEndingX(), offY + 2).call();
+    }
+
+    @Override
+    public void onMouseClick(int mx, int my, int mouseButton, float partialTick) {
+        if (isHovered(mx, my, partialTick)) {
+            if (mouseButton == 0) {
+                attachedScreen.mc.displayScreen(new PopupBuilder(attachedScreen, 400).withTextField("input", valueToString())
+                    .closeOnEsc(0)
+                    .closeOnEnter(0)
+                    .closeOnClickOut(0)
+                    .withOnCloseListener((statusCode, results) -> {
+                        if (statusCode == 0) {
+                            try {
+                                parseValueFromString((String) results.get("input"));
+                            } catch (Exception e) {
+                                LOGGER.error("Failed to parse input '{}' into a '{}'!", results.get("input"), this.tag.getClass().getSimpleName(), e);
+                            }
+                        }
+                    })
+                    .build());
+            }
+        }
+    }
+
+    public @NotNull String valueToString() {
+        return tag.getValue().toString();
+    }
+
+    public abstract void parseValueFromString(@NotNull String valueString) throws Exception;
+
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
index 7906d2861..70873e586 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.gui.options.data;
 
 import com.mojang.logging.LogUtils;
+import com.mojang.nbt.NbtIo;
 import net.betterthanadventure.utils.DataDumper;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.enums.EnumGPUVendor;
@@ -11,6 +12,7 @@ import net.minecraft.client.gui.ScreenSoundTest;
 import net.minecraft.client.gui.ScreenTextureViewer;
 import net.minecraft.client.gui.achievements.ScreenAchievements;
 import net.minecraft.client.gui.modelviewer.ScreenModelViewer;
+import net.minecraft.client.gui.nbteditor.ScreenNBTEditor;
 import net.minecraft.client.gui.options.components.*;
 import net.minecraft.client.option.enums.LightmapStyle;
 import net.minecraft.client.player.controller.PlayerControllerSP;
@@ -377,6 +379,13 @@ public abstract class OptionsPages
                     Global.accessor = mc;
                 }))
                 .withComponent(new ShortcutComponent("gui.options.page.debug.button.open.font_tester", () -> mc.displayScreen(new ScreenFontTest(mc.currentScreen))))
+                .withComponent(new ShortcutComponent("gui.options.page.debug.button.open.nbt_tester", () -> {
+                    try {
+                        mc.displayScreen(new ScreenNBTEditor(mc.currentScreen, "NBT Test", NbtIo.readCompressed(OptionsPages.class.getResourceAsStream("/debug/nbt/allTags_1_0_0.dat")), null));
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
+                    }
+                }))
                 .withComponent(new ShortcutComponent("gui.options.page.debug.button.open.datadumper", () ->{
                     DataDumper.main(new String[0]);
                     FileOpener.open(new File(mc.getMinecraftDir(), "infodump"));
diff --git a/game/client/src/main/java/net/minecraft/client/net/command/ClientCommandSource.java b/game/client/src/main/java/net/minecraft/client/net/command/ClientCommandSource.java
index 9df70381f..798d4721c 100644
--- a/game/client/src/main/java/net/minecraft/client/net/command/ClientCommandSource.java
+++ b/game/client/src/main/java/net/minecraft/client/net/command/ClientCommandSource.java
@@ -76,10 +76,10 @@ public class ClientCommandSource implements CommandSource {
     @Override
     public @NotNull Vec3 getBlockCoordinates() {
         if (this.mc.objectMouseOver != null) {
-            return Vec3.getTempVec3(this.mc.objectMouseOver.x, this.mc.objectMouseOver.y, this.mc.objectMouseOver.z);
+            return Vec3.fromPool(this.mc.objectMouseOver.x, this.mc.objectMouseOver.y, this.mc.objectMouseOver.z);
         }
         Vec3 playerCoordinates = this.getCoordinates(true);
-        return Vec3.getTempVec3(MathHelper.floor(playerCoordinates.x), MathHelper.floor(playerCoordinates.y), MathHelper.floor(playerCoordinates.z));
+        return Vec3.fromPool(MathHelper.floor(playerCoordinates.x), MathHelper.floor(playerCoordinates.y), MathHelper.floor(playerCoordinates.z));
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
index e2ab34b49..cf715c1f8 100644
--- a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
+++ b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
@@ -1132,7 +1132,7 @@ public class PacketHandlerClient extends PacketHandler
     {
         NamespaceID id;
         try {
-            id = NamespaceID.getTemp(statisticPacket.statID);
+            id = NamespaceID.fromPool(statisticPacket.statID);
         } catch (HardIllegalArgumentException e) {
             LOGGER.error("Received invalid stat id '{}' from server!", statisticPacket.statID);
             return;
diff --git a/game/client/src/main/java/net/minecraft/client/net/thread/ThreadDownloadResources.java b/game/client/src/main/java/net/minecraft/client/net/thread/ThreadDownloadResources.java
index 8c6653020..19b3025f6 100644
--- a/game/client/src/main/java/net/minecraft/client/net/thread/ThreadDownloadResources.java
+++ b/game/client/src/main/java/net/minecraft/client/net/thread/ThreadDownloadResources.java
@@ -33,7 +33,8 @@ public class ThreadDownloadResources extends Thread {
     public final Minecraft mc;
     public File resourcesFolder;
 
-    public volatile boolean downloading = false;
+    public volatile ThreadDownloadState downloading = ThreadDownloadState.IDLE;
+    public volatile long timeOfError = -1;
     public AtomicInteger downloadProgress = new AtomicInteger(0);
     public volatile int toDownload;
 
@@ -68,7 +69,8 @@ public class ThreadDownloadResources extends Thread {
                 try {
                     downloadResources();
                 } catch (Exception e) {
-                    downloading = false;
+                    downloading = ThreadDownloadState.ERROR;
+                    timeOfError = System.currentTimeMillis();
                     LOGGER.error("Error downloading sounds...", e);
                 }
             }
@@ -114,7 +116,7 @@ public class ThreadDownloadResources extends Thread {
             return;
         }
 
-        downloading = true;
+        downloading = ThreadDownloadState.DOWNLOADING;
         toDownload = entries.size();
 
         for (SoundEntry soundEntry : entries) {
@@ -130,7 +132,7 @@ public class ThreadDownloadResources extends Thread {
         this.mc.sndManager = new SoundEngine();
         this.mc.sndManager.init(this.mc.gameSettings);
 
-        downloading = false;
+        downloading = ThreadDownloadState.IDLE;
     }
 
     private String remapDirectory(String path) {
@@ -170,4 +172,10 @@ public class ThreadDownloadResources extends Thread {
             this.size = size;
         }
     }
+
+    public static enum ThreadDownloadState {
+        IDLE,
+        DOWNLOADING,
+        ERROR;
+    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/Lighting.java b/game/client/src/main/java/net/minecraft/client/render/Lighting.java
index 9585a75f5..4e9a23776 100644
--- a/game/client/src/main/java/net/minecraft/client/render/Lighting.java
+++ b/game/client/src/main/java/net/minecraft/client/render/Lighting.java
@@ -38,13 +38,13 @@ public class Lighting {
 		glEnable(GL_COLOR_MATERIAL);
 		glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
 		
-		Vec3 vec = Vec3.getTempVec3(0.2D, 1.0D, -0.7D).normalize();
+		Vec3 vec = Vec3.fromPool(0.2D, 1.0D, -0.7D).normalize();
 		glLightfv(GL_LIGHT0, GL_POSITION, getBuffer(vec.x, vec.y, vec.z, 0.0D));
 		glLightfv(GL_LIGHT0, GL_DIFFUSE, getBuffer(lightBrightness, lightBrightness, lightBrightness, 1.0F));
 		glLightfv(GL_LIGHT0, GL_AMBIENT, getBuffer(0.0F, 0.0F, 0.0F, 1.0F));
 		glLightfv(GL_LIGHT0, GL_SPECULAR, getBuffer(0.0F, 0.0F, 0.0F, 1.0F));
 		
-		vec = Vec3.getTempVec3(-0.2D, 1.0D, 0.7D).normalize();
+		vec = Vec3.fromPool(-0.2D, 1.0D, 0.7D).normalize();
 		glLightfv(GL_LIGHT1, GL_POSITION, getBuffer(vec.x, vec.y, vec.z, 0.0D));
 		glLightfv(GL_LIGHT1, GL_DIFFUSE, getBuffer(lightBrightness, lightBrightness, lightBrightness, 1.0F));
 		glLightfv(GL_LIGHT1, GL_AMBIENT, getBuffer(0.0F, 0.0F, 0.0F, 1.0F));
diff --git a/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java b/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java
index 79e3b2282..3bb772159 100644
--- a/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java
@@ -1487,7 +1487,7 @@ public class RenderGlobal
             drawInterpolatedEntityBoundingBox(e, head, camera, partialTicks); // Head
 
             glColor4f(1.0f, 0.0f, 1.0f, 1.0f);
-            final AABB feet = AABB.getTemporaryBB(e.bb.minX, e.y - 0.005, e.bb.minZ, e.bb.maxX, e.y + 0.005, e.bb.maxZ);
+            final AABB feet = AABB.fromPool(e.bb.minX, e.y - 0.005, e.bb.minZ, e.bb.maxX, e.y + 0.005, e.bb.maxZ);
             drawInterpolatedEntityBoundingBox(e, feet, camera, partialTicks); // Feet
 
             glColor4f(0.75f, 0.75f, 1.0f, 1.0f);
@@ -1496,7 +1496,7 @@ public class RenderGlobal
             double lerpOffsetX = MathHelper.lerp(e.xo, e.x, partialTicks) - camera.getX(partialTicks);
             double lerpOffsetY = MathHelper.lerp(e.yo, e.y, partialTicks) - camera.getY(partialTicks);
             double lerpOffsetZ = MathHelper.lerp(e.zo, e.z, partialTicks) - camera.getZ(partialTicks);
-            drawDebugVec(Tessellator.instance, Vec3.getTempVec3(lerpOffsetX, lerpOffsetY + e.getHeadHeight(), lerpOffsetZ), e.getViewVector(partialTicks), 1, 0, 1, 0, 1);
+            drawDebugVec(Tessellator.instance, Vec3.fromPool(lerpOffsetX, lerpOffsetY + e.getHeadHeight(), lerpOffsetZ), e.getViewVector(partialTicks), 1, 0, 1, 0, 1);
             glDisable(GL_TEXTURE_2D);
             GL11.glLineWidth(2);
         }
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFence.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFence.java
index 4b1b4ccf9..1e62ca44f 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFence.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFence.java
@@ -26,7 +26,7 @@ public class BlockModelFence<T  extends BlockLogicFence> extends BlockModelStand
     public boolean render(@NotNull Tessellator tessellator, @NotNull WorldSource worldSource, int x, int y, int z) {
         final float f = 0.375F;
         final float f1 = 0.625F;
-        AABB bounds = AABB.getTemporaryBB(f, 0.0F, f, f1, 1.0F, f1);
+        AABB bounds = AABB.fromPool(f, 0.0F, f, f1, 1.0F, f1);
         renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
         boolean flag1 = false;
         boolean flag2 = false;
@@ -100,18 +100,18 @@ public class BlockModelFence<T  extends BlockLogicFence> extends BlockModelStand
             switch (cube) {
                 // Vertical Beams
                 case 0:
-                    bounds = AABB.getTemporaryBB(0.5F - radius, 0.0F, 0.0F, 0.5F + radius, 1.0F, radius * 2.0F);
+                    bounds = AABB.fromPool(0.5F - radius, 0.0F, 0.0F, 0.5F + radius, 1.0F, radius * 2.0F);
                     break;
                 case 1:
-                    bounds = AABB.getTemporaryBB(0.5F - radius, 0.0F, 1.0F - radius * 2.0F, 0.5F + radius, 1.0F, 1.0F);
+                    bounds = AABB.fromPool(0.5F - radius, 0.0F, 1.0F - radius * 2.0F, 0.5F + radius, 1.0F, 1.0F);
                     break;
                 // Horizontal Beams
                 case 2:
-                    bounds = AABB.getTemporaryBB(0.5F - f5, 1.0F - f5 * 3F, -f5 * 2.0F, 0.5F + f5, 1.0F - f5, 1.0F + f5 * 2.0F);
+                    bounds = AABB.fromPool(0.5F - f5, 1.0F - f5 * 3F, -f5 * 2.0F, 0.5F + f5, 1.0F - f5, 1.0F + f5 * 2.0F);
                     break;
                 case 3:
                 default:
-                    bounds = AABB.getTemporaryBB(0.5F - f5, 0.5F - f5 * 3F, -f5 * 2.0F, 0.5F + f5, 0.5F - f5, 1.0F + f5 * 2.0F);
+                    bounds = AABB.fromPool(0.5F - f5, 0.5F - f5 * 3F, -f5 * 2.0F, 0.5F + f5, 0.5F - f5, 1.0F + f5 * 2.0F);
                     break;
             }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java
index 30eeb51bd..282fc5263 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java
@@ -365,7 +365,7 @@ public class BlockModelFenceThin<T extends BlockLogicFenceThin> extends BlockMod
             GL11.glColor4f(f1 * brightness, f3 * brightness, f5 * brightness, alpha);
         }
         GL11.glRotatef(90, 0, 1, 0);
-        AABB bounds = AABB.getTemporaryBB(0, 0, 0, 1, 1, 1);
+        AABB bounds = AABB.fromPool(0, 0, 0, 1, 1, 1);
         for(int i1 = 0; i1 < 2; i1++)
         {
             GL11.glPushMatrix();
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java
index 451b907a5..f98e5308b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java
@@ -90,14 +90,14 @@ public class BlockModelLever<T extends BlockLogic> extends BlockModelStandard<T>
         float f8 = 0.0625F;
         float f9 = 0.0625F;
         float f10 = 0.625F;
-        avec3[0] = Vec3.getTempVec3(-f8, 0.0D, -f9);
-        avec3[1] = Vec3.getTempVec3(f8, 0.0D, -f9);
-        avec3[2] = Vec3.getTempVec3(f8, 0.0D, f9);
-        avec3[3] = Vec3.getTempVec3(-f8, 0.0D, f9);
-        avec3[4] = Vec3.getTempVec3(-f8, f10, -f9);
-        avec3[5] = Vec3.getTempVec3(f8, f10, -f9);
-        avec3[6] = Vec3.getTempVec3(f8, f10, f9);
-        avec3[7] = Vec3.getTempVec3(-f8, f10, f9);
+        avec3[0] = Vec3.fromPool(-f8, 0.0D, -f9);
+        avec3[1] = Vec3.fromPool(f8, 0.0D, -f9);
+        avec3[2] = Vec3.fromPool(f8, 0.0D, f9);
+        avec3[3] = Vec3.fromPool(-f8, 0.0D, f9);
+        avec3[4] = Vec3.fromPool(-f8, f10, -f9);
+        avec3[5] = Vec3.fromPool(f8, f10, -f9);
+        avec3[6] = Vec3.fromPool(f8, f10, f9);
+        avec3[7] = Vec3.fromPool(-f8, f10, f9);
         for(int i2 = 0; i2 < 8; i2++)
         {
             if(flag)
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiston.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiston.java
index a448df03a..db51b879d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiston.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPiston.java
@@ -68,17 +68,17 @@ public class BlockModelPiston<T extends BlockLogicPistonBase> extends BlockModel
                     renderBlocks.uvRotateWest = 3;
                     renderBlocks.uvRotateSouth = 3;
                     renderBlocks.uvRotateNorth = 3;
-                    bounds = AABB.getTemporaryBB(0.0F, headThickness, 0.0F, 1.0F, 1.0F, 1.0F);
+                    bounds = AABB.fromPool(0.0F, headThickness, 0.0F, 1.0F, 1.0F, 1.0F);
                     break;
 
                 case UP: // '\001'
-                    bounds = AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1 - headThickness, 1.0F);
+                    bounds = AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1 - headThickness, 1.0F);
                     break;
 
                 case NORTH: // '\002'
                     renderBlocks.uvRotateSouth = 1;
                     renderBlocks.uvRotateNorth = 2;
-                    bounds = AABB.getTemporaryBB(0.0F, 0.0F, headThickness, 1.0F, 1.0F, 1.0F);
+                    bounds = AABB.fromPool(0.0F, 0.0F, headThickness, 1.0F, 1.0F, 1.0F);
                     break;
 
                 case SOUTH: // '\003'
@@ -86,7 +86,7 @@ public class BlockModelPiston<T extends BlockLogicPistonBase> extends BlockModel
                     renderBlocks.uvRotateNorth = 1;
                     renderBlocks.uvRotateTop = 3;
                     renderBlocks.uvRotateBottom = 3;
-                    bounds = AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1 - headThickness);
+                    bounds = AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1 - headThickness);
                     break;
 
                 case WEST: // '\004'
@@ -94,7 +94,7 @@ public class BlockModelPiston<T extends BlockLogicPistonBase> extends BlockModel
                     renderBlocks.uvRotateWest = 2;
                     renderBlocks.uvRotateTop = 2;
                     renderBlocks.uvRotateBottom = 1;
-                    bounds = AABB.getTemporaryBB(headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
+                    bounds = AABB.fromPool(headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
                     break;
 
                 case EAST: // '\005'
@@ -102,11 +102,11 @@ public class BlockModelPiston<T extends BlockLogicPistonBase> extends BlockModel
                     renderBlocks.uvRotateWest = 1;
                     renderBlocks.uvRotateTop = 1;
                     renderBlocks.uvRotateBottom = 2;
-                    bounds = AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1 - headThickness, 1.0F, 1.0F);
+                    bounds = AABB.fromPool(0.0F, 0.0F, 0.0F, 1 - headThickness, 1.0F, 1.0F);
                     break;
 
                 default:
-                    bounds = AABB.getTemporaryBB(0, 0, 0, 1, 1, 1);
+                    bounds = AABB.fromPool(0, 0, 0, 1, 1, 1);
             }
             renderBlocks.renderStandardBlock(tessellator, worldSource, this, bounds, x, y, z);
             renderBlocks.resetRenderBlocks();
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPistonHead.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPistonHead.java
index 341d80797..598f5c9a9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPistonHead.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPistonHead.java
@@ -67,7 +67,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 renderBlocks.uvRotateWest = 3;
                 renderBlocks.uvRotateSouth = 3;
                 renderBlocks.uvRotateNorth = 3;
-                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, this.headThickness, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, this.headThickness, 1.0F), x, y, z);
                 renderHeadTopBottom(tessellator, x + 0.5 - this.shaftThickness/2, x + 0.5 + this.shaftThickness/2, y + this.headThickness, y + this.headThickness + f1, z + 0.5 + this.shaftThickness/2, z + 0.5 + this.shaftThickness/2, brightness * 0.8F, width);
                 renderHeadTopBottom(tessellator, x + 0.5 + this.shaftThickness/2, x + 0.5 - this.shaftThickness/2, y + this.headThickness, y + this.headThickness + f1, z + 0.5 - this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, brightness * 0.8F, width);
                 renderHeadTopBottom(tessellator, x + 0.5 - this.shaftThickness/2, x + 0.5 - this.shaftThickness/2, y + this.headThickness, y + this.headThickness + f1, z + 0.5 - this.shaftThickness/2, z + 0.5 + this.shaftThickness/2, brightness * 0.6F, width);
@@ -75,7 +75,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 break;
 
             case UP: // TOP
-                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 1 - this.headThickness, 0.0F, 1.0F, 1.0F, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.fromPool(0.0F, 1 - this.headThickness, 0.0F, 1.0F, 1.0F, 1.0F), x, y, z);
                 renderHeadTopBottom(tessellator, x + 0.5 - this.shaftThickness/2, x + 0.5 + this.shaftThickness/2, ((y - this.headThickness) + 1.0F) - f1, (y - this.headThickness) + 1.0F, z + 0.5 + this.shaftThickness/2, z + 0.5 + this.shaftThickness/2, brightness * 0.8F, width);
                 renderHeadTopBottom(tessellator, x + 0.5 + this.shaftThickness/2, x + 0.5 - this.shaftThickness/2, ((y - this.headThickness) + 1.0F) - f1, (y - this.headThickness) + 1.0F, z + 0.5 - this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, brightness * 0.8F, width);
                 renderHeadTopBottom(tessellator, x + 0.5 - this.shaftThickness/2, x + 0.5 - this.shaftThickness/2, ((y - this.headThickness) + 1.0F) - f1, (y - this.headThickness) + 1.0F, z + 0.5 - this.shaftThickness/2, z + 0.5 + this.shaftThickness/2, brightness * 0.6F, width);
@@ -85,7 +85,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
             case NORTH: // NORTH
                 renderBlocks.uvRotateSouth = 1;
                 renderBlocks.uvRotateNorth = 2;
-                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, this.headThickness), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, this.headThickness), x, y, z);
                 renderHeadNorthSouth(tessellator, x + 0.5 - this.shaftThickness/2, x + 0.5 - this.shaftThickness/2, y + 0.5 + this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, z + this.headThickness, z + this.headThickness + f1, brightness * 0.6F, width);
                 renderHeadNorthSouth(tessellator, x + 0.5 + this.shaftThickness/2, x + 0.5 + this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, y + 0.5 + this.shaftThickness/2, z + this.headThickness, z + this.headThickness + f1, brightness * 0.6F, width);
                 renderHeadNorthSouth(tessellator, x + 0.5 - this.shaftThickness/2, x + 0.5 + this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, z + this.headThickness, z + this.headThickness + f1, brightness * 0.5F, width);
@@ -97,7 +97,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 renderBlocks.uvRotateNorth = 1;
                 renderBlocks.uvRotateTop = 3;
                 renderBlocks.uvRotateBottom = 3;
-                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 1 - this.headThickness, 1.0F, 1.0F, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.fromPool(0.0F, 0.0F, 1 - this.headThickness, 1.0F, 1.0F, 1.0F), x, y, z);
                 renderHeadNorthSouth(tessellator, x + 0.5 - this.shaftThickness/2, x + 0.5 - this.shaftThickness/2, y + 0.5 + this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, ((z - this.headThickness) + 1.0F) - f1, (z - this.headThickness) + 1.0F, brightness * 0.6F, width);
                 renderHeadNorthSouth(tessellator, x + 0.5 + this.shaftThickness/2, x + 0.5 + this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, y + 0.5 + this.shaftThickness/2, ((z - this.headThickness) + 1.0F) - f1, (z - this.headThickness) + 1.0F, brightness * 0.6F, width);
                 renderHeadNorthSouth(tessellator, x + 0.5 - this.shaftThickness/2, x + 0.5 + this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, ((z - this.headThickness) + 1.0F) - f1, (z - this.headThickness) + 1.0F, brightness * 0.5F, width);
@@ -109,7 +109,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 renderBlocks.uvRotateWest = 2;
                 renderBlocks.uvRotateTop = 2;
                 renderBlocks.uvRotateBottom = 1;
-                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, this.headThickness, 1.0F, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.fromPool(0.0F, 0.0F, 0.0F, this.headThickness, 1.0F, 1.0F), x, y, z);
                 renderHeadEastWest(tessellator, x + this.headThickness, x + this.headThickness + f1, y + 0.5 - this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, z + 0.5 + this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, brightness * 0.5F, width);
                 renderHeadEastWest(tessellator, x + this.headThickness, x + this.headThickness + f1, y + 0.5 + this.shaftThickness/2, y + 0.5 + this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, z + 0.5 + this.shaftThickness/2, brightness, width);
                 renderHeadEastWest(tessellator, x + this.headThickness, x + this.headThickness + f1, y + 0.5 - this.shaftThickness/2, y + 0.5 + this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, brightness * 0.6F, width);
@@ -121,7 +121,7 @@ public class BlockModelPistonHead extends BlockModelStandard<BlockLogicPistonHea
                 renderBlocks.uvRotateWest = 1;
                 renderBlocks.uvRotateTop = 1;
                 renderBlocks.uvRotateBottom = 2;
-                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(1 - this.headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F), x, y, z);
+                renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.fromPool(1 - this.headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F), x, y, z);
                 renderHeadEastWest(tessellator, ((x - this.headThickness) + 1.0F) - f1, (x - this.headThickness) + 1.0F, y + 0.5 - this.shaftThickness/2, y + 0.5 - this.shaftThickness/2, z + 0.5 + this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, brightness * 0.5F, width);
                 renderHeadEastWest(tessellator, ((x - this.headThickness) + 1.0F) - f1, (x - this.headThickness) + 1.0F, y + 0.5 + this.shaftThickness/2, y + 0.5 + this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, z + 0.5 + this.shaftThickness/2, brightness, width);
                 renderHeadEastWest(tessellator, ((x - this.headThickness) + 1.0F) - f1, (x - this.headThickness) + 1.0F, y + 0.5 - this.shaftThickness/2, y + 0.5 + this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, z + 0.5 - this.shaftThickness/2, brightness * 0.6F, width);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPumice.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPumice.java
index a1ce327dc..ec5131e25 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPumice.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelPumice.java
@@ -55,7 +55,7 @@ public class BlockModelPumice<T extends BlockLogic> extends BlockModelStandard<T
         boolean ob = renderBlocks.overbright;
         renderBlocks.overbright = true;
         final double depthFixOffset = 0.001d;
-        AABB bounds = AABB.getTemporaryBB(depthFixOffset, depthFixOffset, depthFixOffset, 1 - depthFixOffset, 1 - depthFixOffset, 1 - depthFixOffset);
+        AABB bounds = AABB.fromPool(depthFixOffset, depthFixOffset, depthFixOffset, 1 - depthFixOffset, 1 - depthFixOffset, 1 - depthFixOffset);
         renderBlockWithBounds(tessellator, bounds, metadata, brightness, alpha, LightmapHelper.getLightmapCoord(15, 15));
 
         renderBlocks.overbright = ob;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java
index 10f2577dd..0b8234b41 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java
@@ -33,7 +33,7 @@ extends BlockModelStandard<T> {
             !(!hasBlockNegX && !hasBlockPosX && hasBlockNegY && hasBlockPosY && !hasBlockNegZ && !hasBlockPosZ) &&
             !(!hasBlockNegX && !hasBlockPosX && !hasBlockNegY && !hasBlockPosY && hasBlockNegZ && hasBlockPosZ);
 
-        AABB bounds = AABB.getTemporaryBB(0, 0, 0, 1, 1, 1);
+        AABB bounds = AABB.fromPool(0, 0, 0, 1, 1, 1);
 
         final float ropeThickness = (1 / 16f);
         final float knotThickness = (2 / 16f);
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java
index 7cf1a1471..9dd740c5a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java
@@ -26,7 +26,7 @@ public class BlockModelSpikes<T extends BlockLogic> extends BlockModelStandard<T
             texture = renderBlocks.overrideBlockTexture;
         }
 
-        renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F), x, y, z);
+        renderBlocks.renderStandardBlock(tessellator, worldSource, this, AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F), x, y, z);
 
         if(BlockLogicSpikes.isSpikesUp(metaData)) {
             float brightness = 1.0f;
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairs.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairs.java
index 9e79395c1..0503af27e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairs.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStairs.java
@@ -39,7 +39,7 @@ public class BlockModelStairs<T extends BlockLogicStairs> extends BlockModelStan
 
         float stepYOffset = vRotation > 0 ? 0.5f : 0.0f;
 
-        AABB bounds = AABB.getTemporaryBB(0, 0, 0, 1, 1, 1);
+        AABB bounds = AABB.fromPool(0, 0, 0, 1, 1, 1);
 
         if(hRotation == 0)
         {
@@ -85,9 +85,9 @@ public class BlockModelStairs<T extends BlockLogicStairs> extends BlockModelStan
             AABB bounds;
             if(l == 0)
             {
-                bounds = AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
+                bounds = AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
             } else {
-                bounds = AABB.getTemporaryBB(0.5F, 0.5F, 0.0F, 1.0F, 1.0F, 1.0F);
+                bounds = AABB.fromPool(0.5F, 0.5F, 0.0F, 1.0F, 1.0F, 1.0F);
             }
             GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
             tessellator.startDrawingQuads();
diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java
index c2c685dda..f35c93315 100644
--- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java
+++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java
@@ -305,7 +305,7 @@ public class BlockModelStandard<T extends BlockLogic> extends BlockModel<T>{
     }
 
     public BlockModelStandard<T> withCustomItemBounds(double minX, double minY, double minZ, double maxX, double maxY, double maxZ){
-        this.itemRenderBounds = AABB.getPermanentBB(minX, minY, minZ, maxX, maxY, maxZ);
+        this.itemRenderBounds = AABB.fromPool(minX, minY, minZ, maxX, maxY, maxZ).copyUnpooled();
         return this;
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/camera/EntityCameraThirdPersonRear.java b/game/client/src/main/java/net/minecraft/client/render/camera/EntityCameraThirdPersonRear.java
index 09da687bc..4aa1ecb6e 100644
--- a/game/client/src/main/java/net/minecraft/client/render/camera/EntityCameraThirdPersonRear.java
+++ b/game/client/src/main/java/net/minecraft/client/render/camera/EntityCameraThirdPersonRear.java
@@ -44,19 +44,19 @@ public class EntityCameraThirdPersonRear
         double dz = (MathHelper.cos((yRot / 180F) * MathHelper.PI) * MathHelper.cos((xRot / 180F) * MathHelper.PI));
         double dy = (-MathHelper.sin((xRot / 180F) * MathHelper.PI));
 
-        double cameraDistance = Vec3.getTempVec3(x, y, z).distanceTo(Vec3.getTempVec3(x - numSteps * dx, y - numSteps * dy, z - numSteps * dz)) - offset;
+        double cameraDistance = Vec3.fromPool(x, y, z).distanceTo(Vec3.fromPool(x - numSteps * dx, y - numSteps * dy, z - numSteps * dz)) - offset;
 
         for(int i = 0; i <= numSteps; i++)
         {
             HitResult hitResult = mc.currentWorld.checkBlockCollisionBetweenPoints(
-                    Vec3.getTempVec3(x, y, z),
-                    Vec3.getTempVec3(x - i * dx, y - i * dy, z - i * dz),
+                    Vec3.fromPool(x, y, z),
+                    Vec3.fromPool(x - i * dx, y - i * dy, z - i * dz),
                     false,
                     true,
                 false);
             if(hitResult != null)
             {
-                double distance = hitResult.location.distanceTo(Vec3.getTempVec3(x, y, z)) - offset;
+                double distance = hitResult.location.distanceTo(Vec3.fromPool(x, y, z)) - offset;
                 if (distance < 0) distance = 0;
                 cameraDistance = distance;
                 break;
diff --git a/game/client/src/main/java/net/minecraft/client/render/camera/ICamera.java b/game/client/src/main/java/net/minecraft/client/render/camera/ICamera.java
index 42133bd5f..97717663d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/camera/ICamera.java
+++ b/game/client/src/main/java/net/minecraft/client/render/camera/ICamera.java
@@ -36,7 +36,7 @@ public interface ICamera
 
     default Vec3 getPosition(float partialTick)
     {
-        return Vec3.getTempVec3(getX(partialTick), getY(partialTick), getZ(partialTick));
+        return Vec3.fromPool(getX(partialTick), getY(partialTick), getZ(partialTick));
     }
 
     default Vec3 getPosition()
@@ -66,7 +66,7 @@ public interface ICamera
         float x = MathHelper.sin(-yRot * (MathHelper.PI / 180f) - MathHelper.PI);
         float y = MathHelper.sin(-xRot * (MathHelper.PI / 180f));
         float z = MathHelper.cos(-yRot * (MathHelper.PI / 180f) - MathHelper.PI);
-        return Vec3.getTempVec3(x * xzLen, y, z * xzLen);
+        return Vec3.fromPool(x * xzLen, y, z * xzLen);
     }
 
     default Vec3 getRotationVector(float partialTick)
@@ -80,7 +80,7 @@ public interface ICamera
         float x = MathHelper.sin((float) (-yaw * toRads - Math.PI));
         float y = MathHelper.sin((float) (-pitch * toRads));
         float z = MathHelper.cos((float) (-yaw * toRads - Math.PI));
-        return Vec3.getTempVec3(x * xzLen, y, z * xzLen);
+        return Vec3.fromPool(x * xzLen, y, z * xzLen);
     }
 
     default Vec3 getRotationVector()
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFishingBobber.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFishingBobber.java
index b3158088a..1d53b34c9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFishingBobber.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererFishingBobber.java
@@ -22,7 +22,7 @@ public class EntityRendererFishingBobber extends EntityRendererSprite<EntityFish
             int handedNess = entity.owner.isLeftHanded() ? -1 : 1;
             float f11 = entity.owner.getSwingProgress(partialTick);
             float f12 = MathHelper.sin(MathHelper.sqrt_float(f11) * MathHelper.PI);
-            Vec3 vec3 = Vec3.getTempVec3(-0.75D * handedNess, -0.05D, 0.8D);
+            Vec3 vec3 = Vec3.fromPool(-0.75D * handedNess, -0.05D, 0.8D);
             vec3.rotateAroundX((-(entity.owner.xRotO + (entity.owner.xRot - entity.owner.xRotO) * partialTick) * MathHelper.PI) / 180F);
             vec3.rotateAroundY((-(entity.owner.yRotO + (entity.owner.yRot - entity.owner.yRotO) * partialTick) * MathHelper.PI) / 180F);
             vec3.rotateAroundY(f12 * 0.5F);
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererMinecart.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererMinecart.java
index a4aa7d283..e39e9206d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererMinecart.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererMinecart.java
@@ -36,7 +36,7 @@ public class EntityRendererMinecart extends EntityRenderer<EntityMinecart> {
         double renderYaw = yaw;
         boolean doAFlip = false;
         if(vec3 != null) {
-//            drawDebugVec(tessellator, Vec3.getTempVec3(x, y + 1.5, z), Vec3.getTempVec3(-(vec3.x - lerpX), -(vec3.y - lerpY), -(vec3.z - lerpZ)), 1.5, 1, 0, 0, 1);
+//            drawDebugVec(tessellator, Vec3.fromPool(x, y + 1.5, z), Vec3.fromPool(-(vec3.x - lerpX), -(vec3.y - lerpY), -(vec3.z - lerpZ)), 1.5, 1, 0, 0, 1);
             final double scalar = 0.3D;
             Vec3 forVec = minecart.getPosOffs(lerpX, lerpY, lerpZ, scalar);
             Vec3 backVec = minecart.getPosOffs(lerpX, lerpY, lerpZ, -scalar);
@@ -47,8 +47,8 @@ public class EntityRendererMinecart extends EntityRenderer<EntityMinecart> {
                 backVec = vec3;
             }
 
-//            drawDebugVec(tessellator, Vec3.getTempVec3(x, y + 1.6, z), Vec3.getTempVec3(forVec.x - lerpX, forVec.y - lerpY, forVec.z - lerpZ), 1.5, 0, 1, 0, 1);
-//            drawDebugVec(tessellator, Vec3.getTempVec3(x, y + 1.7, z), Vec3.getTempVec3(backVec.x - lerpX, backVec.y - lerpY, backVec.z - lerpZ), 1.5, 0, 0, 1, 1);
+//            drawDebugVec(tessellator, Vec3.fromPool(x, y + 1.6, z), Vec3.fromPool(forVec.x - lerpX, forVec.y - lerpY, forVec.z - lerpZ), 1.5, 0, 1, 0, 1);
+//            drawDebugVec(tessellator, Vec3.fromPool(x, y + 1.7, z), Vec3.fromPool(backVec.x - lerpX, backVec.y - lerpY, backVec.z - lerpZ), 1.5, 0, 0, 1, 1);
 
             renderX += vec3.x - lerpX;
             renderY += (forVec.y + backVec.y) / 2D - lerpY;
@@ -60,11 +60,11 @@ public class EntityRendererMinecart extends EntityRenderer<EntityMinecart> {
                 lerpXRot = Math.atan(velVec.y) * 73D;
             }
 
-            final Vec3 realVecVec = Vec3.getTempVec3(minecart.xd, minecart.yd, minecart.zd);
+            final Vec3 realVecVec = Vec3.fromPool(minecart.xd, minecart.yd, minecart.zd);
 
             doAFlip = velVec.dotProduct(realVecVec) < 0;
 
-//            drawDebugVec(tessellator, Vec3.getTempVec3(x, y + 1.8, z), Vec3.getTempVec3(velVec.x, velVec.y, velVec.z), 1.5, 0, 1, 1, 1);
+//            drawDebugVec(tessellator, Vec3.fromPool(x, y + 1.8, z), Vec3.fromPool(velVec.x, velVec.y, velVec.z), 1.5, 0, 1, 1, 1);
         }
         GL11.glTranslated(renderX, renderY, renderZ);
         GL11.glRotated(180F - renderYaw, 0.0F, 1.0F, 0.0F);
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
index c1de94d76..f06b4670c 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
@@ -375,6 +375,11 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
             .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
             .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
             .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
+        addDispatch(new ItemModelStandard(Items.WAND_NBT, "minecraft")
+            .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND, HANDHELD_FIRST_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.FIRST_PERSON_LEFT_HAND, HANDHELD_FIRST_PERSON_LEFT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_RIGHT_HAND, HANDHELD_THIRD_PERSON_RIGHT_HAND)
+            .setDisplayPos(DisplayPos.THIRD_PERSON_LEFT_HAND, HANDHELD_THIRD_PERSON_LEFT_HAND));
         addDispatch(new ItemModelStandard(Items.DOOR_STEEL, "minecraft"));
         addDispatch(new ItemModelPaintbrush(Items.PAINTBRUSH, "minecraft")
             .setDisplayPos(DisplayPos.FIRST_PERSON_RIGHT_HAND,  new DisplayPos(1.13f/16f, 3.2f/16f, 1.13f/16f, 90, -90, 25, 0.68f, 0.68f, 0.68f))
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
index 63385c488..377bbd9a6 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
@@ -8,6 +8,8 @@ import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.util.collection.NamespaceID;
+import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java
index 3e6a423ea..0fd4bcdfc 100644
--- a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRenderer.java
@@ -88,9 +88,9 @@ public abstract class ChunkRenderer
             yRender = y - yRenderOffs;
             zRender = z - zRenderOffs;
             float f = 6F;
-            bb = AABB.getPermanentBB((float)x - f, (float)y - f, (float)z - f, (float)(x + sizeX) + f, (float)(y + sizeY) + f, (float)(z + sizeZ) + f);
+            bb = AABB.fromPool((float)x - f, (float)y - f, (float)z - f, (float)(x + sizeX) + f, (float)(y + sizeY) + f, (float)(z + sizeZ) + f).copyUnpooled();
             GL11.glNewList(lists + MAX_RENDER_PASSES, GL11.GL_COMPILE);
-            EntityRendererItem.renderFlatAABB(AABB.getTemporaryBB((float) xRenderOffs - f, (float) yRenderOffs - f, (float) zRenderOffs - f, (float)(xRenderOffs + sizeX) + f, (float)(yRenderOffs + sizeY) + f, (float)(zRenderOffs + sizeZ) + f));
+            EntityRendererItem.renderFlatAABB(AABB.fromPool((float) xRenderOffs - f, (float) yRenderOffs - f, (float) zRenderOffs - f, (float)(xRenderOffs + sizeX) + f, (float)(yRenderOffs + sizeY) + f, (float)(zRenderOffs + sizeZ) + f));
             GL11.glEndList();
             setDirty();
         }
diff --git a/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/TextureRegistry.java b/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/TextureRegistry.java
index 0afc1a740..5b0931dab 100644
--- a/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/TextureRegistry.java
+++ b/game/client/src/main/java/net/minecraft/client/render/texture/stitcher/TextureRegistry.java
@@ -53,7 +53,7 @@ public class TextureRegistry {
 
     public static @NotNull IconCoordinate getTexture(@NotNull String key){
         try {
-            return getTexture(NamespaceID.getTemp(key));
+            return getTexture(NamespaceID.fromPool(key));
         } catch (HardIllegalArgumentException e) {
             throw new RuntimeException(e);
         }
@@ -63,11 +63,11 @@ public class TextureRegistry {
         final AtlasStitcher atlas = stitcherMap.get(id.value().substring(0, slashIndex));
         if (atlas == null) throw new IllegalArgumentException("Failed to find atlas '" + id.value().substring(0, slashIndex) + "'!");
 
-        return atlas.getTexture(id, NamespaceID.getTemp(id.namespace(), id.value().substring(slashIndex + 1)));
+        return atlas.getTexture(id, NamespaceID.fromPool(id.namespace(), id.value().substring(slashIndex + 1)));
     }
     public static boolean hasTexture(@NotNull String key) {
         try {
-            return hasTexture(NamespaceID.getTemp(key));
+            return hasTexture(NamespaceID.fromPool(key));
         } catch (HardIllegalArgumentException e) {
             throw new RuntimeException(e);
         }
@@ -77,7 +77,7 @@ public class TextureRegistry {
         final AtlasStitcher atlas = stitcherMap.get(id.value().substring(0, slashIndex));
         if (atlas == null) throw new IllegalArgumentException("Failed to find atlas '" + id.value().substring(0, slashIndex) + "'!");
 
-        return atlas.textureMap.containsKey(NamespaceID.getTemp(id.namespace(), id.value().substring(slashIndex + 1)));
+        return atlas.textureMap.containsKey(NamespaceID.fromPool(id.namespace(), id.value().substring(slashIndex + 1)));
     }
     public static AtlasStitcher register(String id, AtlasStitcher atlas){
         stitcherMap.put(id, atlas);
@@ -104,8 +104,8 @@ public class TextureRegistry {
         for (String s : files) {
 //            System.out.println(s);
 
-            NamespaceID id = NamespaceID.getTemp(namespace, s.replace(".png", "").replace("//", "/"));
-            atlas.getTexture(NamespaceID.getTemp(id.namespace(), stitcherMapReverse.get(atlas) + "/" + id.value()), id);
+            NamespaceID id = NamespaceID.fromPool(namespace, s.replace(".png", "").replace("//", "/"));
+            atlas.getTexture(NamespaceID.fromPool(id.namespace(), stitcherMapReverse.get(atlas) + "/" + id.value()), id);
         }
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
index 283c34a26..1ef003815 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
@@ -205,7 +205,7 @@ public class TileEntityRendererSign extends TileEntityRenderer<TileEntitySign>
 
     @Override
     public boolean isVisible(@NotNull final TileEntitySign tileEntity, final @NotNull ICamera camera, final float partialTick) {
-        return camera.getFrustum().isVisible(AABB.getTemporaryBB(tileEntity.x, tileEntity.y, tileEntity.z, tileEntity.x + 1, tileEntity.y + 1, tileEntity.z + 1), partialTick);
+        return camera.getFrustum().isVisible(AABB.fromPool(tileEntity.x, tileEntity.y, tileEntity.z, tileEntity.x + 1, tileEntity.y + 1, tileEntity.z + 1), partialTick);
     }
 
     public static class BufferedTextMeshRenderer {
diff --git a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFX.java b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFX.java
index d98f60e94..be3214445 100644
--- a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFX.java
+++ b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFX.java
@@ -67,7 +67,7 @@ public class WorldTypeFX {
     }
 
     public Vec3 getFogColor(World world, double x, double y, double z, float celestialAngle, float partialTick) {
-        return Vec3.getTempVec3(1.0, 1.0, 1.0);
+        return Vec3.fromPool(1.0, 1.0, 1.0);
     }
 
     public float[] getSunriseColor(float timeOfDay, float partialTick) {
diff --git a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDrift.java b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDrift.java
index 5852c737a..cd90bba49 100644
--- a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDrift.java
+++ b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXDrift.java
@@ -56,6 +56,6 @@ public class WorldTypeFXDrift extends WorldTypeFX{
         r *= f2 * 0.94F + 0.06F;
         g *= f2 * 0.94F + 0.06F;
         b *= f2 * 0.91F + 0.09F;
-        return Vec3.getTempVec3(r, g, b);
+        return Vec3.fromPool(r, g, b);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXEmpty.java b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXEmpty.java
index 00c54f298..5ecd801fd 100644
--- a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXEmpty.java
+++ b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXEmpty.java
@@ -25,7 +25,7 @@ public class WorldTypeFXEmpty extends WorldTypeFX{
         r *= f2 * 0.94F + 0.06F;
         g *= f2 * 0.94F + 0.06F;
         b *= f2 * 0.91F + 0.09F;
-        return Vec3.getTempVec3(r, g, b);
+        return Vec3.fromPool(r, g, b);
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXNether.java b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXNether.java
index fbd35c2bb..daa9e0208 100644
--- a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXNether.java
+++ b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXNether.java
@@ -32,7 +32,7 @@ public class WorldTypeFXNether extends WorldTypeFX{
             float r = ((color >> 16) & 0xFF) / 255.0f;
             float g = ((color >> 8) & 0xFF) / 255.0f;
             float b = (color & 0xFF) / 255.0f;
-            return Vec3.getTempVec3(r, g, b);
+            return Vec3.fromPool(r, g, b);
         }
 
         float r = 60 / 255.0f;
@@ -53,7 +53,7 @@ public class WorldTypeFXNether extends WorldTypeFX{
             b = MathHelper.lerp(0, b, (float) toLerp);
         }
 
-        return Vec3.getTempVec3(r, g, b);
+        return Vec3.fromPool(r, g, b);
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXOverworld.java b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXOverworld.java
index 039a25abb..b4e34c648 100644
--- a/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXOverworld.java
+++ b/game/client/src/main/java/net/minecraft/client/render/worldtype/WorldTypeFXOverworld.java
@@ -57,6 +57,6 @@ public class WorldTypeFXOverworld extends WorldTypeFX{
         r *= dayProgress * 0.94f + 0.06f;
         g *= dayProgress * 0.94f + 0.06f;
         b *= dayProgress * 0.91f + 0.09f;
-        return Vec3.getTempVec3(r, g, b);
+        return Vec3.fromPool(r, g, b);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/sound/SoundRepository.java b/game/client/src/main/java/net/minecraft/client/sound/SoundRepository.java
index d58bf7cd1..bf3754099 100644
--- a/game/client/src/main/java/net/minecraft/client/sound/SoundRepository.java
+++ b/game/client/src/main/java/net/minecraft/client/sound/SoundRepository.java
@@ -104,7 +104,7 @@ public class SoundRepository extends Registry<NamedSoundRepository> {
             value = split[1];
             if (namespace.isEmpty()) throw new IllegalArgumentException("Invalid key '" + key + "', Namespace must not be empty!");
         }
-        return NamespaceID.getTemp(namespace, value);
+        return NamespaceID.fromPool(namespace, value);
     }
 
     public static void initialize(Minecraft mc) {
diff --git a/game/client/src/main/java/net/minecraft/client/util/linalg/MatrixStack.java b/game/client/src/main/java/net/minecraft/client/util/linalg/MatrixStack.java
new file mode 100644
index 000000000..cc7d68aa6
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/util/linalg/MatrixStack.java
@@ -0,0 +1,92 @@
+package net.minecraft.client.util.linalg;
+
+import net.minecraft.core.util.linalg.Matrix4;
+import org.jetbrains.annotations.NotNull;
+import org.lwjgl.opengl.GL11;
+
+/**
+ * Provides an abstraction over OpenGL's matrix functions, to aid in porting to OpenGL 3 later on.
+ */
+public class MatrixStack {
+    /**
+     * The model-view matrix stack, corresponding to GL_MODELVIEW.
+     */
+    public static final @NotNull MatrixStack MODEL_VIEW = new MatrixStack(GL11.GL_MODELVIEW, GL11.GL_MODELVIEW_MATRIX);
+    /**
+     * The projection matrix stack, corresponding to GL_PROJECTION.
+     */
+    public static final @NotNull MatrixStack PROJECTION = new MatrixStack(GL11.GL_PROJECTION, GL11.GL_PROJECTION_MATRIX);
+    /**
+     * The texture matrix stack, corresponding to GL_TEXTURE.
+     */
+    public static final @NotNull MatrixStack TEXTURE = new MatrixStack(GL11.GL_TEXTURE, GL11.GL_TEXTURE_MATRIX);
+
+    private final int matrixMode;
+    private final int matrixMode2;
+
+    private int depth = 0;
+
+    private MatrixStack(final int matrixMode, final int matrixMode2) {
+        this.matrixMode = matrixMode;
+        this.matrixMode2 = matrixMode2;
+    }
+
+    /**
+     * Returns the top of the matrix stack.
+     */
+    public @NotNull Matrix4 peek() {
+        GL11.glMatrixMode(this.matrixMode);
+
+        final double[] buffer = new double[16];
+        GL11.glGetDoublev(this.matrixMode2, buffer);
+
+        return Matrix4.fromPool(
+            buffer[0], buffer[1], buffer[2], buffer[3],
+            buffer[4], buffer[5], buffer[6], buffer[7],
+            buffer[8], buffer[9], buffer[10], buffer[11],
+            buffer[12], buffer[13], buffer[14], buffer[15]
+        );
+    }
+
+    /**
+     * Pushes a duplicate of the current matrix onto the matrix stack.
+     */
+    public void push() {
+        GL11.glMatrixMode(this.matrixMode);
+
+        GL11.glPushMatrix();
+
+        this.depth += 1;
+    }
+
+    /**
+     * Pops the current matrix from the matrix stack. If the stack becomes empty, an identity matrix will be inserted.
+     */
+    public void pop() {
+        GL11.glMatrixMode(this.matrixMode);
+
+        if (this.depth == 0) {
+            GL11.glLoadIdentity();
+        } else {
+            GL11.glPopMatrix();
+        }
+    }
+
+    /**
+     * Replaces the current matrix with the identity matrix.
+     */
+    public void loadIdentity() {
+        GL11.glMatrixMode(this.matrixMode);
+
+        GL11.glLoadIdentity();
+    }
+
+    /**
+     * Replaces the current matrix with the given matrix.
+     */
+    public void load(final @NotNull Matrix4 matrix) {
+        GL11.glMatrixMode(this.matrixMode);
+
+        GL11.glLoadMatrixd(matrix.asArray());
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java
index 425038471..07dcacda2 100644
--- a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java
+++ b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java
@@ -79,7 +79,7 @@ public class WorldClient extends World {
         r *= f2 * 0.9F + 0.1F;
         g *= f2 * 0.9F + 0.1F;
         b *= f2 * 0.85F + 0.15F;
-        return Vec3.getTempVec3(r, g, b);
+        return Vec3.fromPool(r, g, b);
     }
 
     public Vec3 getFogColor(ICamera camera, float partialTick)
@@ -155,7 +155,7 @@ public class WorldClient extends World {
             g = g * (1.0F - f12) + 0.8F * f12;
             b = b * (1.0F - f12) + f12;
         }
-        return Vec3.getTempVec3(r, g, b);
+        return Vec3.fromPool(r, g, b);
     }
 
     @Override
diff --git a/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/BlockModelMojangData.java b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/BlockModelMojangData.java
index 4454f7bee..954aab092 100644
--- a/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/BlockModelMojangData.java
+++ b/game/client/src/main/java/org/useless/dragonfly/data/block/mojang/BlockModelMojangData.java
@@ -255,7 +255,7 @@ public class BlockModelMojangData implements BlockModelData {
                 }
             }
             try {
-                return new BlockModelMojangData(texturePackList, NamespaceID.getPermanent(id), this.parent, this.ambientOcclusion, this.renderLayer, this.displayPosMap, this.textures, this.particleIndices, elementList);
+                return new BlockModelMojangData(texturePackList, NamespaceID.fromPool(id).copyUnpooled(), this.parent, this.ambientOcclusion, this.renderLayer, this.displayPosMap, this.textures, this.particleIndices, elementList);
             } catch (final HardIllegalArgumentException e) {
                 throw new IllegalArgumentException(e);
             }
diff --git a/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java b/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java
index 83a9f9efc..1770709c5 100644
--- a/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java
+++ b/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java
@@ -291,7 +291,7 @@ public class EntityGeometryMojangData implements EntityModelData {
                         for (final Map.Entry<String, JsonElement> entry : renderersObj.entrySet()) {
                             final NamespaceID id;
                             try {
-                                id = NamespaceID.getPermanent(entry.getKey());
+                                id = NamespaceID.fromPool(entry.getKey()).copyUnpooled();
                             } catch (final HardIllegalArgumentException exception) {
                                 LOGGER.error("Id '{}' is malformed!", entry.getKey(), exception);
                                 continue;
diff --git a/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java b/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java
index f5434543a..b19d17b24 100644
--- a/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java
+++ b/game/client/src/main/java/org/useless/dragonfly/models/entity/mojang/StaticEntityModelMojang.java
@@ -39,13 +39,14 @@ public class StaticEntityModelMojang implements StaticEntityModel {
             i++;
         }
 
-        this.visBounds = AABB.getPermanentBB(
+        this.visBounds = AABB.fromPool(
             (this.data.vBoundsOffset[0] - this.data.vBoundsWidth /2),
             (this.data.vBoundsOffset[1] - this.data.vBoundsHeight/2),
             (this.data.vBoundsOffset[2] - this.data.vBoundsWidth /2),
             (this.data.vBoundsOffset[0] + this.data.vBoundsWidth /2),
             (this.data.vBoundsOffset[1] + this.data.vBoundsHeight/2),
-            (this.data.vBoundsOffset[2] + this.data.vBoundsWidth /2));
+            (this.data.vBoundsOffset[2] + this.data.vBoundsWidth /2)
+        ).copyUnpooled();
     }
 
     @Override
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/byte_array_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/byte_array_tag.png
new file mode 100644
index 000000000..be288d9bb
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/byte_array_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/byte_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/byte_tag.png
new file mode 100644
index 000000000..304f3443d
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/byte_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/compound_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/compound_tag.png
new file mode 100644
index 000000000..7070328a2
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/compound_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/double_array_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/double_array_tag.png
new file mode 100644
index 000000000..bb63962e0
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/double_array_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/double_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/double_tag.png
new file mode 100644
index 000000000..ac64b698d
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/double_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/float_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/float_tag.png
new file mode 100644
index 000000000..048a6a169
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/float_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/int_array_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/int_array_tag.png
new file mode 100644
index 000000000..a05ed09b8
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/int_array_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/int_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/int_tag.png
new file mode 100644
index 000000000..385d1bba7
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/int_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/list_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/list_tag.png
new file mode 100644
index 000000000..1a441cf13
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/list_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/long_array_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/long_array_tag.png
new file mode 100644
index 000000000..9ed19c116
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/long_array_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/long_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/long_tag.png
new file mode 100644
index 000000000..fac0bcdd1
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/long_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/minus.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/minus.png
new file mode 100644
index 000000000..42bc47486
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/minus.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/plus.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/plus.png
new file mode 100644
index 000000000..e5470c344
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/plus.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/short_array_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/short_array_tag.png
new file mode 100644
index 000000000..c3f9e5048
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/short_array_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/short_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/short_tag.png
new file mode 100644
index 000000000..c30402f39
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/short_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/string_tag.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/string_tag.png
new file mode 100644
index 000000000..4a98aee88
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/screen/nbt/string_tag.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/item/wand_nbt.png b/game/client/src/main/resources/assets/minecraft/textures/item/wand_nbt.png
new file mode 100644
index 000000000..90da10cb3
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/item/wand_nbt.png differ
diff --git a/game/client/src/main/resources/debug/nbt/allTags_1_0_0.dat b/game/client/src/main/resources/debug/nbt/allTags_1_0_0.dat
new file mode 100644
index 000000000..49a57f2c1
Binary files /dev/null and b/game/client/src/main/resources/debug/nbt/allTags_1_0_0.dat differ
diff --git a/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java b/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java
index 26c36de60..2783692d9 100644
--- a/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java
+++ b/game/core/src/main/java/net/minecraft/core/achievement/Achievement.java
@@ -25,7 +25,7 @@ public class Achievement extends Stat
 
     public Achievement(NamespaceID id, String name, int iconItemId, Achievement parent)
     {
-        super(NamespaceID.getPermanent(id.namespace(), "achievement/" + id.value()), "achievement." + name);
+        super(NamespaceID.fromPool(id.namespace(), "achievement/" + id.value()), "achievement." + name);
         this.iconItemId = iconItemId;
         this.description = "achievement." + name;
 
diff --git a/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java b/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java
index ab9f2d21a..3dc8201c5 100644
--- a/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java
+++ b/game/core/src/main/java/net/minecraft/core/achievement/Achievements.java
@@ -11,130 +11,130 @@ public abstract class Achievements
 {
     public static List<Achievement> achievementList = new ArrayList<>();
     public static Achievement OPEN_INVENTORY =
-        new Achievement(NamespaceID.getPermanent("minecraft", "open_inventory"), "openInventory", Items.BOOK, null)
+        new Achievement(NamespaceID.fromPool("minecraft", "open_inventory"), "openInventory", Items.BOOK, null)
         .setClientsideAchievement().registerAchievement();
     public static Achievement MINE_WOOD =
-        new Achievement(NamespaceID.getPermanent("minecraft", "mine_wood"), "mineWood", Blocks.LOG_OAK, OPEN_INVENTORY)
+        new Achievement(NamespaceID.fromPool("minecraft", "mine_wood"), "mineWood", Blocks.LOG_OAK, OPEN_INVENTORY)
             .registerAchievement();
     public static Achievement BUILD_WORKBENCH =
-        new Achievement(NamespaceID.getPermanent("minecraft", "build_workbench"), "buildWorkBench", Blocks.WORKBENCH, MINE_WOOD)
+        new Achievement(NamespaceID.fromPool("minecraft", "build_workbench"), "buildWorkBench", Blocks.WORKBENCH, MINE_WOOD)
             .registerAchievement();
     public static Achievement BUILD_PICKAXE =
-        new Achievement(NamespaceID.getPermanent("minecraft", "build_pickaxe"), "buildPickaxe", Items.TOOL_PICKAXE_WOOD, BUILD_WORKBENCH)
+        new Achievement(NamespaceID.fromPool("minecraft", "build_pickaxe"), "buildPickaxe", Items.TOOL_PICKAXE_WOOD, BUILD_WORKBENCH)
             .registerAchievement();
     public static Achievement BUILD_FURNACE =
-        new Achievement(NamespaceID.getPermanent("minecraft", "build_furnace"), "buildFurnace", Blocks.FURNACE_STONE_ACTIVE, BUILD_PICKAXE)
+        new Achievement(NamespaceID.fromPool("minecraft", "build_furnace"), "buildFurnace", Blocks.FURNACE_STONE_ACTIVE, BUILD_PICKAXE)
             .registerAchievement();
     public static Achievement ACQUIRE_IRON =
-        new Achievement(NamespaceID.getPermanent("minecraft", "acquire_iron"), "acquireIron", Items.INGOT_IRON, BUILD_FURNACE)
+        new Achievement(NamespaceID.fromPool("minecraft", "acquire_iron"), "acquireIron", Items.INGOT_IRON, BUILD_FURNACE)
             .registerAchievement();
     public static Achievement GET_DIAMONDS =
-        new Achievement(NamespaceID.getPermanent("minecraft", "get_diamonds"), "getDiamonds", Items.DIAMOND, ACQUIRE_IRON)
+        new Achievement(NamespaceID.fromPool("minecraft", "get_diamonds"), "getDiamonds", Items.DIAMOND, ACQUIRE_IRON)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement BUILD_HOE =
-        new Achievement(NamespaceID.getPermanent("minecraft", "build_hoe"), "buildHoe", Items.TOOL_HOE_WOOD, BUILD_WORKBENCH)
+        new Achievement(NamespaceID.fromPool("minecraft", "build_hoe"), "buildHoe", Items.TOOL_HOE_WOOD, BUILD_WORKBENCH)
             .registerAchievement();
     public static Achievement MAKE_BREAD =
-        new Achievement(NamespaceID.getPermanent("minecraft", "make_bread"), "makeBread", Items.FOOD_BREAD, BUILD_HOE)
+        new Achievement(NamespaceID.fromPool("minecraft", "make_bread"), "makeBread", Items.FOOD_BREAD, BUILD_HOE)
             .registerAchievement();
     public static Achievement BAKE_CAKE =
-        new Achievement(NamespaceID.getPermanent("minecraft", "bake_cake"), "bakeCake", Items.FOOD_CAKE, BUILD_HOE)
+        new Achievement(NamespaceID.fromPool("minecraft", "bake_cake"), "bakeCake", Items.FOOD_CAKE, BUILD_HOE)
             .registerAchievement();
     public static Achievement CRAFT_ICECREAM =
-        new Achievement(NamespaceID.getPermanent("minecraft", "craft_icecream"), "craftIcecream", Items.BUCKET_ICECREAM, BUILD_HOE)
+        new Achievement(NamespaceID.fromPool("minecraft", "craft_icecream"), "craftIcecream", Items.BUCKET_ICECREAM, BUILD_HOE)
             .registerAchievement();
     public static Achievement CRAFT_PUMPKIN_PIE =
-        new Achievement(NamespaceID.getPermanent("minecraft", "craft_pumpkin_pie"), "craftPumpkinPie", Items.FOOD_PUMPKIN_PIE, BUILD_HOE)
+        new Achievement(NamespaceID.fromPool("minecraft", "craft_pumpkin_pie"), "craftPumpkinPie", Items.FOOD_PUMPKIN_PIE, BUILD_HOE)
             .registerAchievement();
     public static Achievement BUILD_BETTER_PICKAXE =
-        new Achievement(NamespaceID.getPermanent("minecraft", "build_better_pickaxe"), "buildBetterPickaxe", Items.TOOL_PICKAXE_STONE, BUILD_PICKAXE)
+        new Achievement(NamespaceID.fromPool("minecraft", "build_better_pickaxe"), "buildBetterPickaxe", Items.TOOL_PICKAXE_STONE, BUILD_PICKAXE)
             .registerAchievement();
     public static Achievement COOK_FISH =
-        new Achievement(NamespaceID.getPermanent("minecraft", "cook_fish"), "cookFish", Items.FOOD_FISH_COOKED, BUILD_FURNACE)
+        new Achievement(NamespaceID.fromPool("minecraft", "cook_fish"), "cookFish", Items.FOOD_FISH_COOKED, BUILD_FURNACE)
             .registerAchievement();
     public static Achievement ON_A_RAIL =
-        new Achievement(NamespaceID.getPermanent("minecraft", "on_a_rail"), "onARail", Blocks.RAIL, ACQUIRE_IRON)
+        new Achievement(NamespaceID.fromPool("minecraft", "on_a_rail"), "onARail", Blocks.RAIL, ACQUIRE_IRON)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement BUILD_SWORD =
-        new Achievement(NamespaceID.getPermanent("minecraft", "build_sword"), "buildSword", Items.TOOL_SWORD_WOOD, BUILD_WORKBENCH)
+        new Achievement(NamespaceID.fromPool("minecraft", "build_sword"), "buildSword", Items.TOOL_SWORD_WOOD, BUILD_WORKBENCH)
             .registerAchievement();
     public static Achievement ALL_ARMOR_TYPES =
-        new Achievement(NamespaceID.getPermanent("minecraft", "all_armor_types"), "allArmorTypes", Items.ARMOR_CHESTPLATE_STEEL, null)
+        new Achievement(NamespaceID.fromPool("minecraft", "all_armor_types"), "allArmorTypes", Items.ARMOR_CHESTPLATE_STEEL, null)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement KILL_ENEMY =
-        new Achievement(NamespaceID.getPermanent("minecraft", "kill_enemy"), "killEnemy", Items.BONE, BUILD_SWORD)
+        new Achievement(NamespaceID.fromPool("minecraft", "kill_enemy"), "killEnemy", Items.BONE, BUILD_SWORD)
             .registerAchievement();
     public static Achievement KILL_COW =
-        new Achievement(NamespaceID.getPermanent("minecraft", "kill_cow"), "killCow", Items.LEATHER, BUILD_SWORD)
+        new Achievement(NamespaceID.fromPool("minecraft", "kill_cow"), "killCow", Items.LEATHER, BUILD_SWORD)
             .registerAchievement();
     public static Achievement FLY_PIG =
-        new Achievement(NamespaceID.getPermanent("minecraft", "fly_pig"), "flyPig", Items.SADDLE, KILL_COW)
+        new Achievement(NamespaceID.fromPool("minecraft", "fly_pig"), "flyPig", Items.SADDLE, KILL_COW)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement GET_SENSED =
-        new Achievement(NamespaceID.getPermanent("minecraft", "get_sensed"), "getSensed", Blocks.MOTION_SENSOR_ACTIVE, KILL_ENEMY)
+        new Achievement(NamespaceID.fromPool("minecraft", "get_sensed"), "getSensed", Blocks.MOTION_SENSOR_ACTIVE, KILL_ENEMY)
             .registerAchievement();
     public static Achievement CRAFT_HANDCANNON =
-        new Achievement(NamespaceID.getPermanent("minecraft", "craft_hand_cannon"), "craftHandCannon", Items.HANDCANNON_UNLOADED, BUILD_BETTER_PICKAXE)
+        new Achievement(NamespaceID.fromPool("minecraft", "craft_hand_cannon"), "craftHandCannon", Items.HANDCANNON_UNLOADED, BUILD_BETTER_PICKAXE)
             .registerAchievement();
     public static Achievement COLLECT_STONE =
-        new Achievement(NamespaceID.getPermanent("minecraft", "collect_stone"), "collectStone", Blocks.COBBLE_LIMESTONE, BUILD_PICKAXE)
+        new Achievement(NamespaceID.fromPool("minecraft", "collect_stone"), "collectStone", Blocks.COBBLE_LIMESTONE, BUILD_PICKAXE)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement CRUSH_BLOCKS =
-        new Achievement(NamespaceID.getPermanent("minecraft", "crush_blocks"), "crushBlocks", Blocks.ICE, BUILD_BETTER_PICKAXE)
+        new Achievement(NamespaceID.fromPool("minecraft", "crush_blocks"), "crushBlocks", Blocks.ICE, BUILD_BETTER_PICKAXE)
             .registerAchievement();
     public static Achievement REPAIR_ARMOR =
-        new Achievement(NamespaceID.getPermanent("minecraft", "repair_armor"), "repairArmor", Items.CHAINLINK, KILL_ENEMY)
+        new Achievement(NamespaceID.fromPool("minecraft", "repair_armor"), "repairArmor", Items.CHAINLINK, KILL_ENEMY)
             .registerAchievement();
     public static Achievement GET_CHAINMAIL =
-        new Achievement(NamespaceID.getPermanent("minecraft", "get_chainmail"), "getChainmail", Items.ARMOR_HELMET_CHAINMAIL, REPAIR_ARMOR)
+        new Achievement(NamespaceID.fromPool("minecraft", "get_chainmail"), "getChainmail", Items.ARMOR_HELMET_CHAINMAIL, REPAIR_ARMOR)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement OPEN_GUIDEBOOK =
-        new Achievement(NamespaceID.getPermanent("minecraft", "open_guidebook"), "openGuidebook", Blocks.BOOKSHELF_PLANKS_OAK, OPEN_INVENTORY)
+        new Achievement(NamespaceID.fromPool("minecraft", "open_guidebook"), "openGuidebook", Blocks.BOOKSHELF_PLANKS_OAK, OPEN_INVENTORY)
             .setClientsideAchievement()
             .registerAchievement();
     public static Achievement CAUGHT_EM_ALL =
-        new Achievement(NamespaceID.getPermanent("minecraft", "caught_em_all"), "caughtEmAll", Items.LANTERN_FIREFLY_GREEN, BUILD_WORKBENCH)
+        new Achievement(NamespaceID.fromPool("minecraft", "caught_em_all"), "caughtEmAll", Items.LANTERN_FIREFLY_GREEN, BUILD_WORKBENCH)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement ALL_MUSIC_DISCS =
-        new Achievement(NamespaceID.getPermanent("minecraft", "all_music_discs"), "allMusicDiscs", Items.RECORD_STAL, null)
+        new Achievement(NamespaceID.fromPool("minecraft", "all_music_discs"), "allMusicDiscs", Items.RECORD_STAL, null)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement TRIPLE_HIT =
-        new Achievement(NamespaceID.getPermanent("minecraft", "triple_hit"), "tripleHit", Items.AMMO_ARROW_GOLD, KILL_ENEMY)
+        new Achievement(NamespaceID.fromPool("minecraft", "triple_hit"), "tripleHit", Items.AMMO_ARROW_GOLD, KILL_ENEMY)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
 
 
     // Nether achievements
     public static Achievement ENTER_NETHER =
-        new Achievement(NamespaceID.getPermanent("minecraft", "enter_nether"), "enterNether", Blocks.OBSIDIAN, null)
+        new Achievement(NamespaceID.fromPool("minecraft", "enter_nether"), "enterNether", Blocks.OBSIDIAN, null)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement GET_NETHERCOAL =
-        new Achievement(NamespaceID.getPermanent("minecraft", "get_nethercoal"), "getNethercoal", Items.NETHERCOAL, ENTER_NETHER)
+        new Achievement(NamespaceID.fromPool("minecraft", "get_nethercoal"), "getNethercoal", Items.NETHERCOAL, ENTER_NETHER)
             .setType(Achievement.TYPE_NORMAL)
             .registerAchievement();
     public static Achievement LIGHT_SIGN =
-        new Achievement(NamespaceID.getPermanent("minecraft", "light_sign"), "lightSign", Items.DUST_GLOWSTONE, ENTER_NETHER)
+        new Achievement(NamespaceID.fromPool("minecraft", "light_sign"), "lightSign", Items.DUST_GLOWSTONE, ENTER_NETHER)
             .setType(Achievement.TYPE_NORMAL)
             .registerAchievement();
     public static Achievement SWIM_NETHER =
-        new Achievement(NamespaceID.getPermanent("minecraft", "swim_nether"), "swimNether", Blocks.ICE, ENTER_NETHER)
+        new Achievement(NamespaceID.fromPool("minecraft", "swim_nether"), "swimNether", Blocks.ICE, ENTER_NETHER)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement HIT_FIREBALL =
-        new Achievement(NamespaceID.getPermanent("minecraft", "hit_fireball"), "hitFireball", Items.AMMO_FIREBALL, ENTER_NETHER)
+        new Achievement(NamespaceID.fromPool("minecraft", "hit_fireball"), "hitFireball", Items.AMMO_FIREBALL, ENTER_NETHER)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
     public static Achievement SLEEP_NETHER =
-        new Achievement(NamespaceID.getPermanent("minecraft", "sleep_nether"), "sleepNether", Items.BED, ENTER_NETHER)
+        new Achievement(NamespaceID.fromPool("minecraft", "sleep_nether"), "sleepNether", Items.BED, ENTER_NETHER)
             .setType(Achievement.TYPE_SPECIAL)
             .registerAchievement();
 //    public static Achievement ENTER_WARRENS =
@@ -142,11 +142,11 @@ public abstract class Achievements
 //            .setType(Achievement.TYPE_NORMAL)
 //            .registerAchievement();
     public static Achievement MOST_WANTED =
-        new Achievement(NamespaceID.getPermanent("minecraft", "most_wanted"), "mostWanted", Items.TOOL_SWORD_GOLD, ENTER_NETHER)
+        new Achievement(NamespaceID.fromPool("minecraft", "most_wanted"), "mostWanted", Items.TOOL_SWORD_GOLD, ENTER_NETHER)
             .setType(Achievement.TYPE_NORMAL)
             .registerAchievement();
     public static Achievement FAST_TRAVEL = // TODO
-        new Achievement(NamespaceID.getPermanent("minecraft", "fast_travel"), "fastTravel", Blocks.GRASS, ENTER_NETHER)
+        new Achievement(NamespaceID.fromPool("minecraft", "fast_travel"), "fastTravel", Blocks.GRASS, ENTER_NETHER)
             .setType(Achievement.TYPE_NORMAL)
             .registerAchievement();
 
diff --git a/game/core/src/main/java/net/minecraft/core/achievement/stat/Stat.java b/game/core/src/main/java/net/minecraft/core/achievement/stat/Stat.java
index a7d3f0f31..b90489c0d 100644
--- a/game/core/src/main/java/net/minecraft/core/achievement/stat/Stat.java
+++ b/game/core/src/main/java/net/minecraft/core/achievement/stat/Stat.java
@@ -25,7 +25,7 @@ public class Stat
     public Stat(NamespaceID id, String key, StatValueFormatter statType)
     {
         clientside = false;
-        statId = id.makePermanent();
+        statId = id.copyUnpooled();
         statKey = key;
         this.statType = statType;
     }
diff --git a/game/core/src/main/java/net/minecraft/core/achievement/stat/StatList.java b/game/core/src/main/java/net/minecraft/core/achievement/stat/StatList.java
index fc6feae96..12e308c1e 100644
--- a/game/core/src/main/java/net/minecraft/core/achievement/stat/StatList.java
+++ b/game/core/src/main/java/net/minecraft/core/achievement/stat/StatList.java
@@ -38,51 +38,51 @@ public abstract class StatList
     public static final String STAT_MINED = "stat_mined";
 
     public static Stat startGameStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "start_game"), "stat.startGame").setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "start_game"), "stat.startGame").setClientside().registerStat();
     public static Stat createWorldStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "create_world"), "stat.createWorld").setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "create_world"), "stat.createWorld").setClientside().registerStat();
     public static Stat loadWorldStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "load_world"), "stat.loadWorld").setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "load_world"), "stat.loadWorld").setClientside().registerStat();
     public static Stat joinMultiplayerStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "join_multiplayer"), "stat.joinMultiplayer").setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "join_multiplayer"), "stat.joinMultiplayer").setClientside().registerStat();
     public static Stat leaveGameStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "leave_game"), "stat.leaveGame").setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "leave_game"), "stat.leaveGame").setClientside().registerStat();
     public static Stat minutesPlayedStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "playtime"), "stat.playOneMinute", Stat.statTypeTime).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "playtime"), "stat.playOneMinute", Stat.statTypeTime).setClientside().registerStat();
     public static Stat distanceWalkedStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "travel_walk"), "stat.walkOneCm", Stat.statTypeDistance).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "travel_walk"), "stat.walkOneCm", Stat.statTypeDistance).setClientside().registerStat();
     public static Stat distanceSwumStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "travel_swim"), "stat.swimOneCm", Stat.statTypeDistance).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "travel_swim"), "stat.swimOneCm", Stat.statTypeDistance).setClientside().registerStat();
     public static Stat distanceFallenStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "travel_fall"), "stat.fallOneCm", Stat.statTypeDistance).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "travel_fall"), "stat.fallOneCm", Stat.statTypeDistance).setClientside().registerStat();
     public static Stat distanceClimbedStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "travel_climb"), "stat.climbOneCm", Stat.statTypeDistance).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "travel_climb"), "stat.climbOneCm", Stat.statTypeDistance).setClientside().registerStat();
     public static Stat distanceFlownStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "travel_fly"), "stat.flyOneCm", Stat.statTypeDistance).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "travel_fly"), "stat.flyOneCm", Stat.statTypeDistance).setClientside().registerStat();
     public static Stat distanceDoveStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "travel_dive"), "stat.diveOneCm", Stat.statTypeDistance).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "travel_dive"), "stat.diveOneCm", Stat.statTypeDistance).setClientside().registerStat();
     public static Stat distanceByMinecartStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "travel_minecart"), "stat.minecartOneCm", Stat.statTypeDistance).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "travel_minecart"), "stat.minecartOneCm", Stat.statTypeDistance).setClientside().registerStat();
     public static Stat distanceByBoatStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "travel_boat"), "stat.boatOneCm", Stat.statTypeDistance).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "travel_boat"), "stat.boatOneCm", Stat.statTypeDistance).setClientside().registerStat();
     public static Stat distanceByPigStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "travel_pig"), "stat.pigOneCm", Stat.statTypeDistance).setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "travel_pig"), "stat.pigOneCm", Stat.statTypeDistance).setClientside().registerStat();
     public static Stat jumpStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "jump"), "stat.jump").setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "jump"), "stat.jump").setClientside().registerStat();
     public static Stat dropStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "drop"), "stat.drop").setClientside().registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "drop"), "stat.drop").setClientside().registerStat();
     public static Stat damageDealtStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "damage_dealt"), "stat.damageDealt").registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "damage_dealt"), "stat.damageDealt").registerStat();
     public static Stat damageTakenStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "damage_taken"), "stat.damageTaken").registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "damage_taken"), "stat.damageTaken").registerStat();
     public static Stat deathsStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "deaths"), "stat.deaths").registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "deaths"), "stat.deaths").registerStat();
     public static Stat mobKillsStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "kills_mob"), "stat.mobKills").registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "kills_mob"), "stat.mobKills").registerStat();
     public static Stat playerKillsStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "kills_player"), "stat.playerKills").registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "kills_player"), "stat.playerKills").registerStat();
     public static Stat fishCaughtStat =
-        new StatBasic(NamespaceID.getPermanent("minecraft", "caught_fish"), "stat.fishCaught").registerStat();
+        new StatBasic(NamespaceID.fromPool("minecraft", "caught_fish"), "stat.fishCaught").registerStat();
 
     public static Map<NamespaceID, Stat> mobEncounterStats;
 
@@ -146,7 +146,7 @@ public abstract class StatList
         mobEncounterStats = new HashMap<>();
         for (Map.Entry<NamespaceID, Class<? extends Entity>> entry : EntityDispatcher.idToClassMap.entrySet())
         {
-            mobEncounterStats.put(entry.getKey(), new StatMob(NamespaceID.getPermanent("minecraft", "encounter_" + entry.getKey().toString().replace(":", "_")), "stat.encounterMob", entry.getKey()).registerStat());
+            mobEncounterStats.put(entry.getKey(), new StatMob(NamespaceID.fromPool("minecraft", "encounter_" + entry.getKey().toString().replace(":", "_")), "stat.encounterMob", entry.getKey()).registerStat());
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/achievement/stat/StatsCounter.java b/game/core/src/main/java/net/minecraft/core/achievement/stat/StatsCounter.java
index 74af0d48f..6fd868976 100644
--- a/game/core/src/main/java/net/minecraft/core/achievement/stat/StatsCounter.java
+++ b/game/core/src/main/java/net/minecraft/core/achievement/stat/StatsCounter.java
@@ -164,7 +164,7 @@ public class StatsCounter {
 				Stat stat;
 				try {
 					if (statId.contains(":")) {
-						stat = StatList.getStat(NamespaceID.getTemp(statId));
+						stat = StatList.getStat(NamespaceID.fromPool(statId));
 					} else {
 						stat = StatList.StatConverter.getStatFromDeprecatedID(Integer.parseInt(statId));
 					}
diff --git a/game/core/src/main/java/net/minecraft/core/block/Block.java b/game/core/src/main/java/net/minecraft/core/block/Block.java
index 1fa72c0a0..d9a330088 100644
--- a/game/core/src/main/java/net/minecraft/core/block/Block.java
+++ b/game/core/src/main/java/net/minecraft/core/block/Block.java
@@ -112,7 +112,7 @@ public final class Block<T extends BlockLogic>
 //            namespaceId = parts[0] + ":" + "block/" + parts[1];
 //        }
         try {
-            return NamespaceID.getPermanent(namespaceId);
+            return NamespaceID.fromPool(namespaceId).copyUnpooled();
         } catch (HardIllegalArgumentException e) {
             throw new RuntimeException(e);
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
index 0c7fe8451..a18bd25aa 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
@@ -34,7 +34,7 @@ import java.util.Objects;
 import java.util.Random;
 
 public class BlockLogic implements BlockInterface, IItemConvertible {
-    protected final AABB bounds = AABB.getPermanentBB(0, 0, 0, 1, 1, 1);
+    protected final AABB bounds = AABB.fromPool(0, 0, 0, 1, 1, 1).copyUnpooled();
     public final @NotNull Block<?> block;
     protected @NotNull Material material;
     public BlockLogic(Block<?> block, Material material) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java
index 41c1e5a65..bc595e9d9 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java
@@ -254,17 +254,17 @@ public class BlockLogicButton extends BlockLogic implements IPaintable
         }
         switch (direction) {
             case SIDE_WEST:
-                return AABB.getTemporaryBB(0.0F, f, 0.5F - f2, f3, f1, 0.5F + f2);
+                return AABB.fromPool(0.0F, f, 0.5F - f2, f3, f1, 0.5F + f2);
             case SIDE_EAST:
-                return AABB.getTemporaryBB(1.0F - f3, f, 0.5F - f2, 1.0F, f1, 0.5F + f2);
+                return AABB.fromPool(1.0F - f3, f, 0.5F - f2, 1.0F, f1, 0.5F + f2);
             case SIDE_NORTH:
-                return AABB.getTemporaryBB(0.5F - f2, f, 0.0F, 0.5F + f2, f1, f3);
+                return AABB.fromPool(0.5F - f2, f, 0.0F, 0.5F + f2, f1, f3);
             case SIDE_SOUTH:
-                return AABB.getTemporaryBB(0.5F - f2, f, 1.0F - f3, 0.5F + f2, f1, 1.0F);
+                return AABB.fromPool(0.5F - f2, f, 1.0F - f3, 0.5F + f2, f1, 1.0F);
             case SIDE_TOP:
-                return AABB.getTemporaryBB(0.5f - f2, 1 - f3, f, 0.5f + f2, 1.0, f1);
+                return AABB.fromPool(0.5f - f2, 1 - f3, f, 0.5f + f2, 1.0, f1);
             case SIDE_BOTTOM:
-                return AABB.getTemporaryBB(0.5f - f2, 0, f, 0.5f + f2, f3, f1);
+                return AABB.fromPool(0.5f - f2, 0, f, 0.5f + f2, f3, f1);
         }
         return super.getBlockBoundsFromState(world, x, y, z);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCake.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCake.java
index 35b817425..a0f40565b 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCake.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCake.java
@@ -21,7 +21,7 @@ public class BlockLogicCake extends BlockLogicEdible
         float f = 0.0625F;
         float f1 = (float)(1 + l * 2) / 16F;
         float f2 = 0.5F;
-        return AABB.getTemporaryBB(f1, 0.0F, f, 1.0F - f, f2, 1.0F - f);
+        return AABB.fromPool(f1, 0.0F, f, 1.0F - f, f2, 1.0F - f);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java
index 78efd1aad..3be0632d0 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java
@@ -37,7 +37,7 @@ public class BlockLogicCropsPumpkin
             size = 14 * onePix;
         }
 
-        return AABB.getTemporaryBB(0.5F - size / 2, 0, 0.5F - size / 2, 0.5F + size / 2, size, 0.5F + size / 2);
+        return AABB.fromPool(0.5F - size / 2, 0, 0.5F - size / 2, 0.5F + size / 2, size, 0.5F + size / 2);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java
index d75c04aa7..4097c59c6 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java
@@ -99,15 +99,15 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
         float f = 0.1875F;
         switch (rotation) {
             case 0:
-                return AABB.getTemporaryBB(0.0F, bottom, 0.0F, 1.0F, top, f);
+                return AABB.fromPool(0.0F, bottom, 0.0F, 1.0F, top, f);
             case 1:
-                return AABB.getTemporaryBB(1.0F - f, bottom, 0.0F, 1.0F, top, 1.0F);
+                return AABB.fromPool(1.0F - f, bottom, 0.0F, 1.0F, top, 1.0F);
             case 2:
-                return AABB.getTemporaryBB(0.0F, bottom, 1.0F - f, 1.0F, top, 1.0F);
+                return AABB.fromPool(0.0F, bottom, 1.0F - f, 1.0F, top, 1.0F);
             case 3:
-                return AABB.getTemporaryBB(0.0F, bottom, 0.0F, f, top, 1.0F);
+                return AABB.fromPool(0.0F, bottom, 0.0F, f, top, 1.0F);
             default:
-                return AABB.getTemporaryBB(0.0F, bottom, 0.0F, 1.0F, top, 1.0F);
+                return AABB.fromPool(0.0F, bottom, 0.0F, 1.0F, top, 1.0F);
         }
     }
     
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
index ea9cf35b6..da3ebee64 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
@@ -64,7 +64,7 @@ public class BlockLogicFarmland extends BlockLogic implements IBonemealable
 	@Override
 	public AABB getCollisionBoundingBoxFromPool(final WorldSource world, final int x, final int y, final int z)
 	{
-		return AABB.getTemporaryBB(x, y, z, x + 1, y + 1, z + 1);
+		return AABB.fromPool(x, y, z, x + 1, y + 1, z + 1);
 	}
 
 	@Override
@@ -72,9 +72,9 @@ public class BlockLogicFarmland extends BlockLogic implements IBonemealable
 		final Material material = world.getBlockMaterial(x, y + 1, z);
 		if (material == Material.vegetable)
 		{
-			return AABB.getTemporaryBB(0, 0, 0, 1, 1, 1);
+			return AABB.fromPool(0, 0, 0, 1, 1, 1);
 		} else {
-			return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.9375F, 1.0F);
+			return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 0.9375F, 1.0F);
 		}
 	}
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFence.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFence.java
index 0f000cc75..356cffe02 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFence.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFence.java
@@ -80,19 +80,19 @@ public class BlockLogicFence extends BlockLogic implements IPaintable
         boolean connectZNeg = canConnectTo(world, x, y, z - 1);
         final double thickness = 0.5 - 0.375;
         if (connectXPos) {
-            addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5 - thickness, 0, 0.5 - thickness, 1, 1.5, 0.5 + thickness).move(x, y, z), aabbList);
+            addIntersectingBoundingBox(aabb, AABB.fromPool(0.5 - thickness, 0, 0.5 - thickness, 1, 1.5, 0.5 + thickness).move(x, y, z), aabbList);
         }
         if (connectXNeg) {
-            addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0, 0, 0.5 - thickness, 0.5 + thickness, 1.5, 0.5 + thickness).move(x, y, z), aabbList);
+            addIntersectingBoundingBox(aabb, AABB.fromPool(0, 0, 0.5 - thickness, 0.5 + thickness, 1.5, 0.5 + thickness).move(x, y, z), aabbList);
         }
         if (connectZPos) {
-            addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5 - thickness, 0, 0.5 - thickness, 0.5 + thickness, 1.5, 1).move(x, y, z), aabbList);
+            addIntersectingBoundingBox(aabb, AABB.fromPool(0.5 - thickness, 0, 0.5 - thickness, 0.5 + thickness, 1.5, 1).move(x, y, z), aabbList);
         }
         if (connectZNeg) {
-            addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5 - thickness, 0, 0, 0.5 + thickness, 1.5, 0.5 + thickness).move(x, y, z), aabbList);
+            addIntersectingBoundingBox(aabb, AABB.fromPool(0.5 - thickness, 0, 0, 0.5 + thickness, 1.5, 0.5 + thickness).move(x, y, z), aabbList);
         }
         if (!connectXPos && !connectXNeg && !connectZPos && !connectZNeg) {
-            addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5 - thickness, 0, 0.5 - thickness, 0.5 + thickness, 1.5, 0.5 + thickness).move(x, y, z), aabbList);
+            addIntersectingBoundingBox(aabb, AABB.fromPool(0.5 - thickness, 0, 0.5 - thickness, 0.5 + thickness, 1.5, 0.5 + thickness).move(x, y, z), aabbList);
         }
     }
 
@@ -121,7 +121,7 @@ public class BlockLogicFence extends BlockLogic implements IPaintable
         boolean connectXNeg = canConnectTo(world, x - 1, y, z);
         boolean connectZPos = canConnectTo(world, x, y, z + 1);
         boolean connectZNeg = canConnectTo(world, x, y, z - 1);
-        return AABB.getTemporaryBB((connectXNeg ? 0.0f : 0.375f), 0, (connectZNeg ? 0.0f : 0.375f), 1 - (connectXPos ? 0.0f : 0.375f), 1, 1 - (connectZPos ? 0.0f : 0.375f));
+        return AABB.fromPool((connectXNeg ? 0.0f : 0.375f), 0, (connectZNeg ? 0.0f : 0.375f), 1 - (connectXPos ? 0.0f : 0.375f), 1, 1 - (connectZPos ? 0.0f : 0.375f));
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java
index a35edb2b4..4159c16f1 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java
@@ -45,11 +45,11 @@ public class BlockLogicFenceGate extends BlockLogic implements IPaintable
     {
     	if (getDirection(meta) == 3 || getDirection(meta) == 1)
     	{
-    		return AABB.getTemporaryBB(0.375f, 0, 0, 1 - 0.375f, 1.0F, 1f);
+    		return AABB.fromPool(0.375f, 0, 0, 1 - 0.375f, 1.0F, 1f);
     	}
     	else
     	{
-    		return AABB.getTemporaryBB(0, 0, 0.375f, 1, 1.0f, 1 - 0.375f);
+    		return AABB.fromPool(0, 0, 0.375f, 1, 1.0f, 1 - 0.375f);
     	}
 
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceThin.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceThin.java
index 7306274d1..1240372f5 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceThin.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceThin.java
@@ -25,7 +25,7 @@ public abstract class BlockLogicFenceThin extends BlockLogic
         boolean connectXNeg = canConnectTo(world, x - 1, y, z);
         boolean connectZPos = canConnectTo(world, x, y, z + 1);
         boolean connectZNeg = canConnectTo(world, x, y, z - 1);
-        return AABB.getTemporaryBB((connectXNeg ? 0.0f : 0.375f), 0, (connectZNeg ? 0.0f : 0.375f), 1 - (connectXPos ? 0.0f : 0.375f), 1, 1 - (connectZPos ? 0.0f : 0.375f));
+        return AABB.fromPool((connectXNeg ? 0.0f : 0.375f), 0, (connectZNeg ? 0.0f : 0.375f), 1 - (connectXPos ? 0.0f : 0.375f), 1, 1 - (connectZPos ? 0.0f : 0.375f));
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java
index 085493472..6467a8ab8 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java
@@ -109,7 +109,7 @@ public abstract class BlockLogicFluid extends BlockLogic
 
     private Vec3 getFlow(WorldSource world, int x, int y, int z)
     {
-        Vec3 result = Vec3.getTempVec3(0.0D, 0.0D, 0.0D);
+        Vec3 result = Vec3.fromPool(0.0D, 0.0D, 0.0D);
         int depthLocal = getRenderedDepth(world, x, y, z);
         for(int i = 0; i < 4; i++)
         {
@@ -325,7 +325,7 @@ public abstract class BlockLogicFluid extends BlockLogic
         float f8 = BlockLogicFluid.getFluidHeight(world, x, y, z + 1, material);
         float f9 = BlockLogicFluid.getFluidHeight(world, x + 1, y, z + 1, material);
         float f10 = BlockLogicFluid.getFluidHeight(world, x + 1, y, z, material);
-        return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, Math.max((f7 + f8 + f9 + f10)/4f, 0.2), 1.0F);
+        return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, Math.max((f7 + f8 + f9 + f10)/4f, 0.2), 1.0F);
     }
 
     public static float getFluidHeight(WorldSource worldSource, int x, int y, int z, Material material)
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java
index 3d55beaf9..a0393aad8 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java
@@ -43,7 +43,7 @@ public class BlockLogicJar extends BlockLogic {
     @Override
     public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z)
     {
-        return AABB.getTemporaryBB(0.3125f, 0, 0.3125f, 1 - 0.3125f, 0.375f, 1 - 0.3125f);
+        return AABB.fromPool(0.3125f, 0, 0.3125f, 1 - 0.3125f, 0.375f, 1 - 0.3125f);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java
index bde6e498a..eba3aa260 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java
@@ -38,7 +38,7 @@ public class BlockLogicJarButterfly extends BlockLogic {
         float offset = 0.0F;
         if ((metadata & MASK_HANGING) != 0)
             offset = 0.3875F;
-        return AABB.getTemporaryBB(0.3125f, offset,  0.3125f, 1 - 0.3125f, 0.5F + offset, 1 - 0.3125f);
+        return AABB.fromPool(0.3125f, offset,  0.3125f, 1 - 0.3125f, 0.5F + offset, 1 - 0.3125f);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java
index e6849807b..067eccb4c 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java
@@ -35,13 +35,13 @@ public class BlockLogicLadder extends BlockLogic {
 		float width = 3.0f / 16.0f;
 
 		if(side == Side.SOUTH) {
-			return AABB.getTemporaryBB(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, width);
+			return AABB.fromPool(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, width);
 		}else if(side == Side.WEST) {
-			return AABB.getTemporaryBB(1.0f - width, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
+			return AABB.fromPool(1.0f - width, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
 		}else if(side == Side.EAST) {
-			return AABB.getTemporaryBB(0.0f, 0.0f, 0.0f, width, 1.0f, 1.0f);
+			return AABB.fromPool(0.0f, 0.0f, 0.0f, width, 1.0f, 1.0f);
 		}else {
-			return AABB.getTemporaryBB(0.0f, 0.0f, 1.0f - width, 1.0f, 1.0f, 1.0f);
+			return AABB.fromPool(0.0f, 0.0f, 1.0f - width, 1.0f, 1.0f, 1.0f);
 		}
 	}
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLanternFirefly.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLanternFirefly.java
index 2ca562e4b..e85ac1ade 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLanternFirefly.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLanternFirefly.java
@@ -37,7 +37,7 @@ public class BlockLogicLanternFirefly extends BlockLogic {
         float offset = 0.0F;
         if ((metadata & MASK_HANGING) != 0)
             offset = 0.3875F;
-        return AABB.getTemporaryBB(0.3125f, offset,  0.3125f, 1 - 0.3125f, 0.5F + offset, 1 - 0.3125f);
+        return AABB.fromPool(0.3125f, offset,  0.3125f, 1 - 0.3125f, 0.5F + offset, 1 - 0.3125f);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java
index 15424f0a8..b50b13458 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java
@@ -34,6 +34,6 @@ public abstract class BlockLogicLayerBase extends BlockLogic
     {
         int l = world.getBlockMetadata(x, y, z) & 7;
         float f = (float)(2 * (1 + l)) / 16F;
-        return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, f, 1.0F);
+        return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, f, 1.0F);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java
index f621491c2..349b7a37f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java
@@ -223,19 +223,19 @@ public class BlockLogicLever extends BlockLogic
         int rotation = getRotation(world.getBlockMetadata(x, y, z));
         float f = 0.1875F;
         if(rotation == ROTATION_EAST) {
-            return AABB.getTemporaryBB(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f);
+            return AABB.fromPool(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f);
         } else if(rotation == ROTATION_WEST) {
-            return AABB.getTemporaryBB(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f);
+            return AABB.fromPool(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f);
         } else if(rotation == ROTATION_SOUTH) {
-            return AABB.getTemporaryBB(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F);
+            return AABB.fromPool(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F);
         } else if(rotation == ROTATION_NORTH) {
-            return AABB.getTemporaryBB(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F);
+            return AABB.fromPool(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F);
         } else if (rotation == ROTATION_TOP_NS || rotation == ROTATION_TOP_WE) {
             float f1 = 0.25F;
-            return AABB.getTemporaryBB(0.5F - f1, 0.0F, 0.5F - f1, 0.5F + f1, 0.6F, 0.5F + f1);
+            return AABB.fromPool(0.5F - f1, 0.0F, 0.5F - f1, 0.5F + f1, 0.6F, 0.5F + f1);
         } else {
             float f1 = 0.25F;
-            return AABB.getTemporaryBB(0.5F - f1, 0.4, 0.5F - f1, 0.5F + f1, 1F, 0.5F + f1);
+            return AABB.fromPool(0.5F - f1, 0.4, 0.5F - f1, 0.5F + f1, 1F, 0.5F + f1);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicNetherrackIgneous.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNetherrackIgneous.java
index 27e3a4e03..1ab71f573 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicNetherrackIgneous.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNetherrackIgneous.java
@@ -20,7 +20,7 @@ public class BlockLogicNetherrackIgneous extends BlockLogic {
     public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z)
     {
         float f = 0.125F;
-        return AABB.getTemporaryBB(x, y, z, x + 1, (float)(y + 1) - f, z + 1);
+        return AABB.fromPool(x, y, z, x + 1, (float)(y + 1) - f, z + 1);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPathDirt.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPathDirt.java
index 2b9271246..baf29ee2c 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPathDirt.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPathDirt.java
@@ -21,7 +21,7 @@ public class BlockLogicPathDirt extends BlockLogic
     @Override
 	public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z)
     {
-        return AABB.getTemporaryBB(x, y, z, x + 1, y + 1, z + 1);
+        return AABB.fromPool(x, y, z, x + 1, y + 1, z + 1);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPiePumpkin.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPiePumpkin.java
index 23709a9e8..370c75b1a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPiePumpkin.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPiePumpkin.java
@@ -27,6 +27,6 @@ public class BlockLogicPiePumpkin extends BlockLogicEdible
         float xMin = l >= 2 ? 0.5f : f;
         float zMin = l >= 3 ? 0.5f : f;
         float f2 = 0.375F;
-        return AABB.getTemporaryBB(xMin, 0.0F, zMin, 1.0F - f, f2, 1.0F - f);
+        return AABB.fromPool(xMin, 0.0F, zMin, 1.0F - f, f2, 1.0F - f);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java
index 85d7ac890..6de96e93e 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java
@@ -53,12 +53,12 @@ public class BlockLogicPortal extends BlockLogicTransparent implements IPainted
         {
             float f1 = 0.125F;
             float f3 = 0.5F;
-            return AABB.getTemporaryBB(0.5F - f1, 0.0F, 0.5F - f3, 0.5F + f1, 1.0F, 0.5F + f3);
+            return AABB.fromPool(0.5F - f1, 0.0F, 0.5F - f3, 0.5F + f1, 1.0F, 0.5F + f3);
         } else
         {
             float f = 0.5F;
             float f2 = 0.125F;
-            return AABB.getTemporaryBB(0.5F - f, 0.0F, 0.5F - f2, 0.5F + f, 1.0F, 0.5F + f2);
+            return AABB.fromPool(0.5F - f, 0.0F, 0.5F - f2, 0.5F + f, 1.0F, 0.5F + f2);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java
index d8b15d3b8..a16cb0c84 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java
@@ -110,13 +110,13 @@ public class BlockLogicPressurePlate<T extends Entity> extends BlockLogic implem
         float pixel = 0.125F;
         List<T> list;
         switch (sideFromMeta(meta)) {
-            case BOTTOM: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.getTemporaryBB(pixel, 0.0F, pixel, 1.0F - pixel, (isPressed ? pixel/2f : pixel), 1.0F - pixel).move(x, y, z)); break;
-            case TOP: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.getTemporaryBB(pixel, 1f - (isPressed ? pixel/2f : pixel), pixel, 1.0F - pixel, 1f, 1.0F - pixel).move(x, y, z)); break;
-            case NORTH: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.getTemporaryBB(pixel, pixel, 0, 1 - pixel, 1 - pixel, (isPressed ? pixel/2f : pixel)).move(x, y, z)); break;
-            case SOUTH: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.getTemporaryBB(pixel, pixel, 1f - (isPressed ? pixel/2f : pixel), 1 - pixel, 1 - pixel, 1).move(x, y, z)); break;
-            case WEST: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.getTemporaryBB(0, pixel, pixel, (isPressed ? pixel/2f : pixel), 1 - pixel, 1 - pixel).move(x, y, z)); break;
+            case BOTTOM: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.fromPool(pixel, 0.0F, pixel, 1.0F - pixel, (isPressed ? pixel/2f : pixel), 1.0F - pixel).move(x, y, z)); break;
+            case TOP: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.fromPool(pixel, 1f - (isPressed ? pixel/2f : pixel), pixel, 1.0F - pixel, 1f, 1.0F - pixel).move(x, y, z)); break;
+            case NORTH: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.fromPool(pixel, pixel, 0, 1 - pixel, 1 - pixel, (isPressed ? pixel/2f : pixel)).move(x, y, z)); break;
+            case SOUTH: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.fromPool(pixel, pixel, 1f - (isPressed ? pixel/2f : pixel), 1 - pixel, 1 - pixel, 1).move(x, y, z)); break;
+            case WEST: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.fromPool(0, pixel, pixel, (isPressed ? pixel/2f : pixel), 1 - pixel, 1 - pixel).move(x, y, z)); break;
             case EAST:
-            default: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.getTemporaryBB(1 - (isPressed ? pixel/2f : pixel), pixel, pixel, 1, 1 - pixel, 1 - pixel).move(x, y, z)); break;
+            default: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.fromPool(1 - (isPressed ? pixel/2f : pixel), pixel, pixel, 1, 1 - pixel, 1 - pixel).move(x, y, z)); break;
         }
 
         if(list != null)
@@ -169,13 +169,13 @@ public class BlockLogicPressurePlate<T extends Entity> extends BlockLogic implem
         boolean isPressed = isPressed(meta);
         float pixel = 0.0625F;
         switch (sideFromMeta(meta)) {
-            case BOTTOM: return AABB.getTemporaryBB(pixel, 0.0F, pixel, 1.0F - pixel, (isPressed ? pixel/2f : pixel), 1.0F - pixel);
-            case TOP: return AABB.getTemporaryBB(pixel, 1f - (isPressed ? pixel/2f : pixel), pixel, 1.0F - pixel, 1f, 1.0F - pixel);
-            case NORTH: return AABB.getTemporaryBB(pixel, pixel, 0, 1 - pixel, 1 - pixel, (isPressed ? pixel/2f : pixel));
-            case SOUTH: return AABB.getTemporaryBB(pixel, pixel, 1f - (isPressed ? pixel/2f : pixel), 1 - pixel, 1 - pixel, 1);
-            case WEST: return AABB.getTemporaryBB(0, pixel, pixel, (isPressed ? pixel/2f : pixel), 1 - pixel, 1 - pixel);
+            case BOTTOM: return AABB.fromPool(pixel, 0.0F, pixel, 1.0F - pixel, (isPressed ? pixel/2f : pixel), 1.0F - pixel);
+            case TOP: return AABB.fromPool(pixel, 1f - (isPressed ? pixel/2f : pixel), pixel, 1.0F - pixel, 1f, 1.0F - pixel);
+            case NORTH: return AABB.fromPool(pixel, pixel, 0, 1 - pixel, 1 - pixel, (isPressed ? pixel/2f : pixel));
+            case SOUTH: return AABB.fromPool(pixel, pixel, 1f - (isPressed ? pixel/2f : pixel), 1 - pixel, 1 - pixel, 1);
+            case WEST: return AABB.fromPool(0, pixel, pixel, (isPressed ? pixel/2f : pixel), 1 - pixel, 1 - pixel);
             case EAST:
-            default: return AABB.getTemporaryBB(1 - (isPressed ? pixel/2f : pixel), pixel, pixel, 1, 1 - pixel, 1 - pixel);
+            default: return AABB.fromPool(1 - (isPressed ? pixel/2f : pixel), pixel, pixel, 1, 1 - pixel, 1 - pixel);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java
index 9781fe381..cb611e085 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java
@@ -55,9 +55,9 @@ public class BlockLogicRail extends BlockLogic {
     public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z) {
         RailDirection direction = getRailDirection(world, x, y, z);
         if(direction.isSloped()) {
-            return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.725F, 1.0F);
+            return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 0.725F, 1.0F);
         } else {
-            return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
+            return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
index e912ac8c7..fa4ede3d8 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
@@ -67,7 +67,7 @@ public class BlockLogicRailDetector extends BlockLogicRail {
         boolean isPowered = (meta & MASK_POWERED) != 0;
         boolean minecartPresent = false;
         float offset = 0.125f;
-        List<EntityMinecart> list = world.getEntitiesWithinAABB(EntityMinecart.class, AABB.getTemporaryBB(x + offset, y + offset, z + offset, x + 1 - offset, y + 1 - offset, z + 1 - offset));
+        List<EntityMinecart> list = world.getEntitiesWithinAABB(EntityMinecart.class, AABB.fromPool(x + offset, y + offset, z + offset, x + 1 - offset, y + 1 - offset, z + 1 - offset));
         if(!list.isEmpty()) {
             minecartPresent = true;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java
index 7bb4ca090..ce16bbeec 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java
@@ -64,7 +64,7 @@ public class BlockLogicRope
         if (hasBlockNegZ) minZ = 0;
         if (hasBlockPosZ) maxZ = 1;
 
-        return AABB.getTemporaryBB(minX, minY, minZ, maxX, maxY, maxZ);
+        return AABB.fromPool(minX, minY, minZ, maxX, maxY, maxZ);
     }
     
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java
index 3ddecd935..00009d94f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java
@@ -51,15 +51,15 @@ public class BlockLogicSign extends BlockLogic implements IPaintable
         float thickness = 2.0f / 16f;
         switch (world.getBlockMetadata(x, y, z) & MASK_SIDE) {
             case SIDE_NORTH:
-                return AABB.getTemporaryBB(0.0F, bottom, 1.0F - thickness, width, top, 1.0F);
+                return AABB.fromPool(0.0F, bottom, 1.0F - thickness, width, top, 1.0F);
             case SIDE_SOUTH:
-                return AABB.getTemporaryBB(0.0F, bottom, 0.0F, width, top, thickness);
+                return AABB.fromPool(0.0F, bottom, 0.0F, width, top, thickness);
             case SIDE_WEST:
-                return AABB.getTemporaryBB(1.0F - thickness, bottom, 0.0F, 1.0F, top, width);
+                return AABB.fromPool(1.0F - thickness, bottom, 0.0F, 1.0F, top, width);
             case SIDE_EAST:
-                return AABB.getTemporaryBB(0.0F, bottom, 0.0F, thickness, top, width);
+                return AABB.fromPool(0.0F, bottom, 0.0F, thickness, top, width);
             default:
-                return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
+                return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java
index e230cf2a4..6cc101808 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java
@@ -57,12 +57,12 @@ public class BlockLogicSlab extends BlockLogic
         int l = world.getBlockMetadata(x, y, z) & 0x3;
         switch (l) {
             case 0:
-                return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
+                return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
             case 1:
-                return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
+                return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
             case 2:
             default:
-                return AABB.getTemporaryBB(0.0F, 0.5F, 0.0F, 1.0F, 1.0F, 1.0F);
+                return AABB.fromPool(0.0F, 0.5F, 0.0F, 1.0F, 1.0F, 1.0F);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulSand.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulSand.java
index b326e2e02..f3ec76a3a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulSand.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSoulSand.java
@@ -18,7 +18,7 @@ public class BlockLogicSoulSand extends BlockLogic
 	public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z)
     {
         float f = 0.125F;
-        return AABB.getTemporaryBB(x, y, z, x + 1, (float)(y + 1) - f, z + 1);
+        return AABB.fromPool(x, y, z, x + 1, (float)(y + 1) - f, z + 1);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java
index 3fc0a62a9..1c815a00b 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java
@@ -71,7 +71,7 @@ public class BlockLogicSpikes extends BlockLogic
 	public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z)
     {
         float thickness = 3/16f;
-        return AABB.getTemporaryBB(x, y, z, x + 1,y + thickness, z + 1);
+        return AABB.fromPool(x, y, z, x + 1,y + thickness, z + 1);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java
index df021c4f0..76b42e69b 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java
@@ -131,20 +131,20 @@ public class BlockLogicStairs extends BlockLogic
 
         switch (hRotation) {
             case 0:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F + stepYOffset, 0.0F, 0.5F, 0.5F + stepYOffset, 1.0F).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F + stepYOffset, 0.0F, 0.5F, 0.5F + stepYOffset, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
                 break;
             case 1:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 0.5F, 1.0F, 1.0F).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 0.0F, 0.5F, 1.0F, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.5F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 1.0F).move(x, y, z), aabbList);
                 break;
             case 2:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 0.5F).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F, 0.5F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 0.5F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 0.5F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
                 break;
             default:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F + stepYOffset, 0.5F, 1.0F, 0.5F + stepYOffset, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F + stepYOffset, 0.5F, 1.0F, 0.5F + stepYOffset, 1.0F).move(x, y, z), aabbList);
                 break;
         }
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java
index 2ff1784a7..277320a62 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java
@@ -40,17 +40,17 @@ public class BlockLogicTorch extends BlockLogic
         int side = world.getBlockMetadata(x, y, z) & MASK_DIRECTION;
         switch (side) {
             case SIDE_WEST:
-                return AABB.getTemporaryBB(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f);
+                return AABB.fromPool(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f);
             case SIDE_EAST:
-                return AABB.getTemporaryBB(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f);
+                return AABB.fromPool(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f);
             case SIDE_NORTH:
-                return AABB.getTemporaryBB(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F);
+                return AABB.fromPool(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F);
             case SIDE_SOUTH:
-                return AABB.getTemporaryBB(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F);
+                return AABB.fromPool(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F);
             case SIDE_BOTTOM:
             default:
                 final float f1 = 0.1F;
-                return AABB.getTemporaryBB(0.5F - f1, 0.0F, 0.5F - f1, 0.5F + f1, 0.6F, 0.5F + f1);
+                return AABB.fromPool(0.5F - f1, 0.0F, 0.5F - f1, 0.5F + f1, 0.6F, 0.5F + f1);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java
index a92405fd2..834428ec4 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java
@@ -63,20 +63,20 @@ public class BlockLogicTrapDoor extends BlockLogic implements IPaintable {
         if (isTrapdoorOpen(meta)) {
             switch (meta & MASK_DIRECTION) {
                 case DIRECTION_SOUTH:  // South
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 1.0F - thickness, 1.0F, 1.0F, 1.0F);
+                    return AABB.fromPool(0.0F, 0.0F, 1.0F - thickness, 1.0F, 1.0F, 1.0F);
                 case DIRECTION_NORTH:  // North
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, thickness);
+                    return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, thickness);
                 case DIRECTION_EAST:  // East
-                    return AABB.getTemporaryBB(1.0F - thickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
+                    return AABB.fromPool(1.0F - thickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
                 case DIRECTION_WEST:  // West
                 default:
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, thickness, 1.0F, 1.0F);
+                    return AABB.fromPool(0.0F, 0.0F, 0.0F, thickness, 1.0F, 1.0F);
             }
         } else {
             if (isUpperHalf(meta)) {
-                return AABB.getTemporaryBB(0.0F, 1.0f - thickness, 0.0F, 1.0F, 1.0f, 1.0F);
+                return AABB.fromPool(0.0F, 1.0f - thickness, 0.0F, 1.0F, 1.0f, 1.0F);
             } else {
-                return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, thickness, 1.0F);
+                return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, thickness, 1.0F);
             }
         }
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java
index ac116064d..cd3486e9c 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java
@@ -153,7 +153,7 @@ public class TileEntityBasket extends TileEntity
             return;
         }
 
-        final AABB aabb = AABB.getTemporaryBB(posX, posY, posZ, posX + 1, posY + 2, posZ + 1);
+        final AABB aabb = AABB.fromPool(posX, posY, posZ, posX + 1, posY + 2, posZ + 1);
 
         final List<EntityItem> entities = workingWorld.getEntitiesWithinAABB(EntityItem.class, aabb);
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispatcher.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispatcher.java
index 94c334efb..3d141b458 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispatcher.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispatcher.java
@@ -4,6 +4,7 @@ import com.mojang.logging.LogUtils;
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.block.piston.TileEntityMovingPistonBlock;
 import net.minecraft.core.util.collection.NamespaceID;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 import java.util.HashMap;
@@ -20,11 +21,12 @@ public class TileEntityDispatcher {
         if(idToClassMap.containsKey(id)) {
             throw new IllegalArgumentException("Duplicate id: " + id);
         }
-        id.makePermanent();
 
-        idToClassMap.put(id, entityClass);
-        stringToClassMap.put(id.toString(), entityClass);
-        classToIdMap.put(entityClass, id);
+        final @NotNull NamespaceID unpooledId = id.copyUnpooled();
+
+        idToClassMap.put(unpooledId, entityClass);
+        stringToClassMap.put(unpooledId.toString(), entityClass);
+        classToIdMap.put(entityClass, unpooledId);
     }
 
     public static TileEntity createAndLoadEntity(CompoundTag compoundTag)
@@ -69,24 +71,24 @@ public class TileEntityDispatcher {
     public static void init() {
         if (hasInit) return;
         hasInit = true;
-        addMapping(TileEntityFurnace.class, NamespaceID.getPermanent("minecraft", "furnace"));
-        addMapping(TileEntityChest.class, NamespaceID.getPermanent("minecraft", "chest"));
-        addMapping(TileEntityJukebox.class, NamespaceID.getPermanent("minecraft", "jukebox"));
-        addMapping(TileEntityDispenser.class, NamespaceID.getPermanent("minecraft", "dispenser"));
-        addMapping(TileEntityActivator.class, NamespaceID.getPermanent("minecraft", "activator"));
-        addMapping(TileEntitySign.class, NamespaceID.getPermanent("minecraft", "sign"));
-        addMapping(TileEntityMobSpawner.class, NamespaceID.getPermanent("minecraft", "mob_spawner"));
-        addMapping(TileEntityMovingPistonBlock.class, NamespaceID.getPermanent("minecraft", "piston_moving"));
-        addMapping(TileEntityFurnaceBlast.class, NamespaceID.getPermanent("minecraft", "furnace_blast"));
-        addMapping(TileEntitySensor.class, NamespaceID.getPermanent("minecraft", "sensor"));
-        addMapping(TileEntityTrommel.class, NamespaceID.getPermanent("minecraft", "trommel"));
-        addMapping(TileEntityBasket.class, NamespaceID.getPermanent("minecraft", "basket"));
-        addMapping(TileEntityFlag.class, NamespaceID.getPermanent("minecraft", "flag"));
-        addMapping(TileEntitySeat.class, NamespaceID.getPermanent("minecraft", "seat"));
-        addMapping(TileEntityFlowerJar.class, NamespaceID.getPermanent("minecraft", "jar_flower"));
-        addMapping(TileEntityJarButterfly.class, NamespaceID.getPermanent("minecraft", "jar_butterfly"));
-        addMapping(TileEntityMeshGold.class, NamespaceID.getPermanent("minecraft", "mesh_gold"));
-        addMapping(TileEntityStatue.class, NamespaceID.getPermanent("minecraft", "statue_stone"));
+        addMapping(TileEntityFurnace.class, NamespaceID.fromPool("minecraft", "furnace"));
+        addMapping(TileEntityChest.class, NamespaceID.fromPool("minecraft", "chest"));
+        addMapping(TileEntityJukebox.class, NamespaceID.fromPool("minecraft", "jukebox"));
+        addMapping(TileEntityDispenser.class, NamespaceID.fromPool("minecraft", "dispenser"));
+        addMapping(TileEntityActivator.class, NamespaceID.fromPool("minecraft", "activator"));
+        addMapping(TileEntitySign.class, NamespaceID.fromPool("minecraft", "sign"));
+        addMapping(TileEntityMobSpawner.class, NamespaceID.fromPool("minecraft", "mob_spawner"));
+        addMapping(TileEntityMovingPistonBlock.class, NamespaceID.fromPool("minecraft", "piston_moving"));
+        addMapping(TileEntityFurnaceBlast.class, NamespaceID.fromPool("minecraft", "furnace_blast"));
+        addMapping(TileEntitySensor.class, NamespaceID.fromPool("minecraft", "sensor"));
+        addMapping(TileEntityTrommel.class, NamespaceID.fromPool("minecraft", "trommel"));
+        addMapping(TileEntityBasket.class, NamespaceID.fromPool("minecraft", "basket"));
+        addMapping(TileEntityFlag.class, NamespaceID.fromPool("minecraft", "flag"));
+        addMapping(TileEntitySeat.class, NamespaceID.fromPool("minecraft", "seat"));
+        addMapping(TileEntityFlowerJar.class, NamespaceID.fromPool("minecraft", "jar_flower"));
+        addMapping(TileEntityJarButterfly.class, NamespaceID.fromPool("minecraft", "jar_butterfly"));
+        addMapping(TileEntityMeshGold.class, NamespaceID.fromPool("minecraft", "mesh_gold"));
+        addMapping(TileEntityStatue.class, NamespaceID.fromPool("minecraft", "statue_stone"));
     }
 
     @Deprecated
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java
index 79bd83c8b..8531e895a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java
@@ -102,7 +102,7 @@ public class TileEntityMobSpawner extends TileEntity
                 {
                     return;
                 }
-                int j = worldObj.getEntitiesWithinAABB(mob.getClass(), AABB.getTemporaryBB(x, y, z, x + 1, y + 1, z + 1).grow(8D, 4D, 8D)).size();
+                int j = worldObj.getEntitiesWithinAABB(mob.getClass(), AABB.fromPool(x, y, z, x + 1, y + 1, z + 1).grow(8D, 4D, 8D)).size();
                 if(j >= 6)
                 {
                     updateDelay();
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySensor.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySensor.java
index 895fa8e4d..3bb024159 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySensor.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySensor.java
@@ -60,7 +60,7 @@ public class TileEntitySensor extends TileEntity {
 		double maxY = Math.max(y1, y2) + 1;
 		double maxZ = Math.max(z1, z2) + 1;
 		
-		return AABB.getTemporaryBB(minX, minY, minZ, maxX, maxY, maxZ);
+		return AABB.fromPool(minX, minY, minZ, maxX, maxY, maxZ);
 	}
 
 	@Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/material/MaterialColor.java b/game/core/src/main/java/net/minecraft/core/block/material/MaterialColor.java
index a31644738..76abee11c 100644
--- a/game/core/src/main/java/net/minecraft/core/block/material/MaterialColor.java
+++ b/game/core/src/main/java/net/minecraft/core/block/material/MaterialColor.java
@@ -132,9 +132,12 @@ public class MaterialColor {
                 registerManualBlockColor(Blocks.TRAPDOOR_PLANKS_PAINTED, i << 4 | j, color);
                 registerManualBlockColor(Blocks.DOOR_PLANKS_PAINTED_BOTTOM, i << 4 | j, color);
                 registerManualBlockColor(Blocks.DOOR_PLANKS_PAINTED_TOP, i << 4 | j, color);
+                registerManualBlockColor(Blocks.PRESSURE_PLATE_PLANKS_OAK_PAINTED, i << 4 | j, color);
             }
             registerManualBlockColor(Blocks.LAMP_ACTIVE, i, color);
             registerManualBlockColor(Blocks.LAMP_IDLE, i, color);
+            registerManualBlockColor(Blocks.LAMP_INVERTED_ACTIVE, i, color);
+            registerManualBlockColor(Blocks.LAMP_INVERTED_IDLE, i, color);
         }
 
         for (int i = 1; i < 256; i++) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
index 47cffcc7a..d1230c773 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
@@ -189,22 +189,22 @@ public class BlockLogicPistonBase extends BlockLogic
             switch(getDirection(data))
             {
                 case DOWN:
-                    return AABB.getTemporaryBB(0.0F, 0.25F, 0.0F, 1.0F, 1.0F, 1.0F);
+                    return AABB.fromPool(0.0F, 0.25F, 0.0F, 1.0F, 1.0F, 1.0F);
                 case UP:
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 0.75F, 1.0F);
+                    return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 0.75F, 1.0F);
                 case NORTH:
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 0.25F, 1.0F, 1.0F, 1.0F);
+                    return AABB.fromPool(0.0F, 0.0F, 0.25F, 1.0F, 1.0F, 1.0F);
                 case SOUTH:
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.75F);
+                    return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.75F);
                 case WEST:
-                    return AABB.getTemporaryBB(0.25F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
+                    return AABB.fromPool(0.25F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
                 case EAST:
                 default:
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 0.75F, 1.0F, 1.0F);
+                    return AABB.fromPool(0.0F, 0.0F, 0.0F, 0.75F, 1.0F, 1.0F);
             }
         } else
         {
-            return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
+            return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSteel.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSteel.java
index 496c5a056..a2d50aa90 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSteel.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBaseSteel.java
@@ -38,22 +38,22 @@ public class BlockLogicPistonBaseSteel extends BlockLogicPistonBase {
             switch(getDirection(data))
             {
                 case DOWN:
-                    return AABB.getTemporaryBB(0.0F, HEAD_THICKNESS_STEEL, 0.0F, 1.0F, 1.0F, 1.0F);
+                    return AABB.fromPool(0.0F, HEAD_THICKNESS_STEEL, 0.0F, 1.0F, 1.0F, 1.0F);
                 case UP:
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1 - HEAD_THICKNESS_STEEL, 1.0F);
+                    return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1 - HEAD_THICKNESS_STEEL, 1.0F);
                 case NORTH:
-                    return AABB.getTemporaryBB(0.0F, 0.0F, HEAD_THICKNESS_STEEL, 1.0F, 1.0F, 1.0F);
+                    return AABB.fromPool(0.0F, 0.0F, HEAD_THICKNESS_STEEL, 1.0F, 1.0F, 1.0F);
                 case SOUTH:
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1 - HEAD_THICKNESS_STEEL);
+                    return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1 - HEAD_THICKNESS_STEEL);
                 case WEST:
-                    return AABB.getTemporaryBB(HEAD_THICKNESS_STEEL, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
+                    return AABB.fromPool(HEAD_THICKNESS_STEEL, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
                 case EAST:
                 default:
-                    return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1 - HEAD_THICKNESS_STEEL, 1.0F, 1.0F);
+                    return AABB.fromPool(0.0F, 0.0F, 0.0F, 1 - HEAD_THICKNESS_STEEL, 1.0F, 1.0F);
             }
         } else
         {
-            return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
+            return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
         }
     }
 
@@ -196,7 +196,7 @@ public class BlockLogicPistonBaseSteel extends BlockLogicPistonBase {
 
     @Override
     public void extendEvent(World world, int x, int y, int z, int data, Direction direction) {
-        List<Entity> entityList = new ArrayList<>(world.getEntitiesWithinAABBExcludingEntity(null, AABB.getTemporaryBB((double)x + direction.getOffsetX(), (double)y + direction.getOffsetY(), (double)z + direction.getOffsetZ(), (double)x + direction.getOffsetX() + 1, (double)y + direction.getOffsetY() + 1, (double)z + direction.getOffsetZ() + 1)));
+        List<Entity> entityList = new ArrayList<>(world.getEntitiesWithinAABBExcludingEntity(null, AABB.fromPool((double)x + direction.getOffsetX(), (double)y + direction.getOffsetY(), (double)z + direction.getOffsetZ(), (double)x + direction.getOffsetX() + 1, (double)y + direction.getOffsetY() + 1, (double)z + direction.getOffsetZ() + 1)));
         for (Entity entity : entityList){
             if (entity == null || entity.noPhysics || entity == flungBlock /*Fix for 1 tick extensions not working properly*/
                 || (entity.world != null && entity.world.isClientSide && entity instanceof Player)) continue;
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java
index cd1757f62..243c3c75d 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java
@@ -87,28 +87,28 @@ public class BlockLogicPistonHead extends BlockLogic
         switch(getDirectionFromMeta(world.getBlockMetadata(x, y, z)))
         {
             case DOWN:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, this.headThickness, 1.0F).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5 - this.shaftThickness/2, this.headThickness, 0.5 - this.shaftThickness/2, 0.5 + this.shaftThickness/2, 1 + this.headThickness, 0.5 + this.shaftThickness/2).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, this.headThickness, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.5 - this.shaftThickness/2, this.headThickness, 0.5 - this.shaftThickness/2, 0.5 + this.shaftThickness/2, 1 + this.headThickness, 0.5 + this.shaftThickness/2).move(x, y, z), aabbList);
                 break;
             case UP:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 1 - this.headThickness, 0.0F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5 - this.shaftThickness/2, -this.headThickness, 0.5 - this.shaftThickness/2, 0.5 + this.shaftThickness/2, 1 - this.headThickness, 0.5 + this.shaftThickness/2).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 1 - this.headThickness, 0.0F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.5 - this.shaftThickness/2, -this.headThickness, 0.5 - this.shaftThickness/2, 0.5 + this.shaftThickness/2, 1 - this.headThickness, 0.5 + this.shaftThickness/2).move(x, y, z), aabbList);
                 break;
             case NORTH:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, this.headThickness).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5 - this.shaftThickness/2, 0.5 - this.shaftThickness/2, this.headThickness, 0.5 + this.shaftThickness/2, 0.5 + this.shaftThickness/2, 1 + this.headThickness).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, this.headThickness).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.5 - this.shaftThickness/2, 0.5 - this.shaftThickness/2, this.headThickness, 0.5 + this.shaftThickness/2, 0.5 + this.shaftThickness/2, 1 + this.headThickness).move(x, y, z), aabbList);
                 break;
             case SOUTH:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F, 1 - this.headThickness, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.5 - this.shaftThickness/2, 0.5 - this.shaftThickness/2, -this.headThickness, 0.5 + this.shaftThickness/2, 0.5 + this.shaftThickness/2, 1 - this.headThickness).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 1 - this.headThickness, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.5 - this.shaftThickness/2, 0.5 - this.shaftThickness/2, -this.headThickness, 0.5 + this.shaftThickness/2, 0.5 + this.shaftThickness/2, 1 - this.headThickness).move(x, y, z), aabbList);
                 break;
             case WEST:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, this.headThickness, 1.0F, 1.0F).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(this.headThickness, 0.5 - this.shaftThickness/2, 0.5 - this.shaftThickness/2, 1 + this.headThickness, 0.5 + this.shaftThickness/2, 0.5 + this.shaftThickness/2).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 0.0F, this.headThickness, 1.0F, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(this.headThickness, 0.5 - this.shaftThickness/2, 0.5 - this.shaftThickness/2, 1 + this.headThickness, 0.5 + this.shaftThickness/2, 0.5 + this.shaftThickness/2).move(x, y, z), aabbList);
                 break;
             case EAST:
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(1 - this.headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
-                addIntersectingBoundingBox(aabb, AABB.getTemporaryBB(-this.headThickness, 0.5 - this.shaftThickness/2, 0.5 - this.shaftThickness/2, 1 - this.headThickness, 0.5 + this.shaftThickness/2, 0.5 + this.shaftThickness/2).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(1 - this.headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
+                addIntersectingBoundingBox(aabb, AABB.fromPool(-this.headThickness, 0.5 - this.shaftThickness/2, 0.5 - this.shaftThickness/2, 1 - this.headThickness, 0.5 + this.shaftThickness/2, 0.5 + this.shaftThickness/2).move(x, y, z), aabbList);
                 break;
         }
     }
@@ -120,17 +120,17 @@ public class BlockLogicPistonHead extends BlockLogic
         switch(getDirectionFromMeta(l))
         {
             case DOWN:
-                return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, this.headThickness, 1.0F);
+                return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, this.headThickness, 1.0F);
             case UP:
-                return AABB.getTemporaryBB(0.0F, 1 - this.headThickness, 0.0F, 1.0F, 1.0F, 1.0F);
+                return AABB.fromPool(0.0F, 1 - this.headThickness, 0.0F, 1.0F, 1.0F, 1.0F);
             case NORTH:
-                return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, this.headThickness);
+                return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, this.headThickness);
             case SOUTH:
-                return AABB.getTemporaryBB(0.0F, 0.0F, 1 - this.headThickness, 1.0F, 1.0F, 1.0F);
+                return AABB.fromPool(0.0F, 0.0F, 1 - this.headThickness, 1.0F, 1.0F, 1.0F);
             case WEST:
-                return AABB.getTemporaryBB(0.0F, 0.0F, 0.0F, this.headThickness, 1.0F, 1.0F);
+                return AABB.fromPool(0.0F, 0.0F, 0.0F, this.headThickness, 1.0F, 1.0F);
             case EAST:
-                return AABB.getTemporaryBB(1 - this.headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
+                return AABB.fromPool(1 - this.headThickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
         }
         return super.getBlockBoundsFromState(world, x, y, z);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java
index 0ecafdb2f..32b9cfe97 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java
@@ -151,7 +151,7 @@ public class BlockLogicPistonMoving extends BlockLogic
             }
             Direction direction = pistonTileEntity.getDirection();
             AABB otherBounds = block.getBlockBoundsFromState(world, x, y, z);
-            return AABB.getTemporaryBB(
+            return AABB.fromPool(
             otherBounds.minX - direction.getOffsetX() * f,
             otherBounds.maxX - direction.getOffsetX() * f,
             otherBounds.minY - direction.getOffsetY() * f,
diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/adapter/ItemStackJsonAdapter.java b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/adapter/ItemStackJsonAdapter.java
index 9ce38edc6..c63f89a1c 100644
--- a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/adapter/ItemStackJsonAdapter.java
+++ b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/adapter/ItemStackJsonAdapter.java
@@ -52,7 +52,7 @@ public class ItemStackJsonAdapter implements JsonDeserializer<ItemStack>, JsonSe
                 item = Item.itemsList[e.getAsInt()];
             } catch (NumberFormatException ignored) { // NumberFormatException thrown if element is not actually convertible to a number
                 try {
-                    item = Item.itemsMap.get(NamespaceID.getTemp(e.getAsString()));
+                    item = Item.itemsMap.get(NamespaceID.fromPool(e.getAsString()));
                 } catch (HardIllegalArgumentException ex) {
                     throw new JsonParseException(ex);
                 }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/Entity.java b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
index 53b096042..20089d7d6 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/Entity.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/Entity.java
@@ -39,6 +39,8 @@ import net.minecraft.core.world.data.SynchedEntityData;
 public abstract class Entity
     implements IVehicle
 {
+    private static @NotNull AABB DEFAULT_AABB = AABB.fromPool(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+
     public static final int DATA_SHARED_FLAGS_ID = 0;
     public static final int FLAG_ONFIRE = 0;
     public static final int FLAG_SNEAKING = 1;
@@ -66,7 +68,7 @@ public abstract class Entity
     public float xRotO;
     public float pushTime;
     public int pushesThisTick;
-    public final @NotNull AABB bb = AABB.getPermanentBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
+    public final @NotNull AABB bb = Entity.DEFAULT_AABB.copyUnpooled();
     public boolean onGround = false;
     public boolean horizontalCollision;
     public boolean verticalCollision;
@@ -467,7 +469,7 @@ public abstract class Entity
         double bbWidth = bb.maxX - bb.minX - 0.05;
         if(isSneaking()) { // Edge safety behavior
 			if(xd != 0.0) {
-				AABB floor = AABB.getTemporaryBB(bb.minX, bb.minY - 1.0, bb.minZ, bb.maxX, bb.minY, bb.maxZ).expand(xd, 0.0, 0.0);
+				AABB floor = AABB.fromPool(bb.minX, bb.minY - 1.0, bb.minZ, bb.maxX, bb.minY, bb.maxZ).expand(xd, 0.0, 0.0);
 				List<AABB> collidingBoxes = world.getCubes(this, floor);
 				if(!collidingBoxes.isEmpty()) {
 					double limitX = 0.0;
@@ -487,7 +489,7 @@ public abstract class Entity
 				}
 			}
 			if(zd != 0.0) {
-				AABB floor = AABB.getTemporaryBB(bb.minX, bb.minY - 1.0, bb.minZ, bb.maxX, bb.minY, bb.maxZ).expand(0.0, 0.0, zd);
+				AABB floor = AABB.fromPool(bb.minX, bb.minY - 1.0, bb.minZ, bb.maxX, bb.minY, bb.maxZ).expand(0.0, 0.0, zd);
 				List<AABB> collidingBoxes = world.getCubes(this, floor);
 				if(!collidingBoxes.isEmpty()) {
 					double limitZ = 0.0;
@@ -625,7 +627,7 @@ public abstract class Entity
             walkDist += (double) MathHelper.sqrt(d10 * d10 + d12 * d12) * 0.6;
             
             // Tiny bounding box
-            AABB boundingBox = AABB.getPermanentBB(this.x - 0.01, this.bb.minY - 0.01, this.z - 0.01, this.x + 0.01, this.bb.minY + 0.01, this.z + 0.01);
+            AABB boundingBox = AABB.fromPool(this.x - 0.01, this.bb.minY - 0.01, this.z - 0.01, this.x + 0.01, this.bb.minY + 0.01, this.z + 0.01);
 
             int blockX = MathHelper.floor(this.x);
             int blockY = MathHelper.floor(boundingBox.minY);
diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java b/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java
index 714838cdc..a6ae82946 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/EntityDispatcher.java
@@ -50,14 +50,15 @@ public final class EntityDispatcher
         if (classToIdMap.containsKey(entityClass)) {
             throw new IllegalArgumentException("EntityDispatcher already contains an assignment for class " + entityClass.getSimpleName() + " with namespace " + classToIdMap.get(entityClass) + "!");
         }
-        namespaceID.makePermanent();
-        classToIdMap.put(entityClass, namespaceID);
-        idToClassMap.put(namespaceID, entityClass);
-        stringIdToClassMap.put(namespaceID.toString(), entityClass);
+        final @NotNull NamespaceID unpooledNamespaceID = namespaceID.copyUnpooled();
+
+        classToIdMap.put(entityClass, unpooledNamespaceID);
+        idToClassMap.put(unpooledNamespaceID, entityClass);
+        stringIdToClassMap.put(unpooledNamespaceID.toString(), entityClass);
 
         int numericId = mappingCount++;
         numericIdToClassMap.put(numericId, entityClass);
-        numericIdToStringIdMap.put(numericId, namespaceID.toString());
+        numericIdToStringIdMap.put(numericId, unpooledNamespaceID.toString());
         classToNumericIdMap.put(entityClass, numericId);
 
         if (nameKey != null) {
@@ -186,51 +187,51 @@ public final class EntityDispatcher
         hasInit = true;
 
         // Misc
-        addMapping(EntityItem.class, NamespaceID.getPermanent("minecraft", "item"));
-        addMapping(EntityPainting.class, NamespaceID.getPermanent("minecraft", "painting"));
-        addMapping(EntityLightning.class, NamespaceID.getPermanent("minecraft", "lightning"));
-        addMapping(EntityFallingBlock.class, NamespaceID.getPermanent("minecraft", "falling_block"));
-        addMapping(EntityMinecart.class, NamespaceID.getPermanent("minecraft", "minecart"));
-        addMapping(EntityBoat.class, NamespaceID.getPermanent("minecraft", "boat"));
-        addMapping(EntityPrimedTNT.class, NamespaceID.getPermanent("minecraft", "primed_tnt"));
+        addMapping(EntityItem.class, NamespaceID.fromPool("minecraft", "item"));
+        addMapping(EntityPainting.class, NamespaceID.fromPool("minecraft", "painting"));
+        addMapping(EntityLightning.class, NamespaceID.fromPool("minecraft", "lightning"));
+        addMapping(EntityFallingBlock.class, NamespaceID.fromPool("minecraft", "falling_block"));
+        addMapping(EntityMinecart.class, NamespaceID.fromPool("minecraft", "minecart"));
+        addMapping(EntityBoat.class, NamespaceID.fromPool("minecraft", "boat"));
+        addMapping(EntityPrimedTNT.class, NamespaceID.fromPool("minecraft", "primed_tnt"));
 
         // Projectiles
-        addMapping(ProjectilePebble.class, NamespaceID.getPermanent("minecraft", "pebble"));
-        addMapping(ProjectileEgg.class, NamespaceID.getPermanent("minecraft", "egg"));
-        addMapping(ProjectileArrow.class, NamespaceID.getPermanent("minecraft", "arrow"));
-        addMapping(ProjectileArrowGolden.class, NamespaceID.getPermanent("minecraft", "arrow_golden"));
-        addMapping(ProjectileArrowPurple.class, NamespaceID.getPermanent("minecraft", "arrow_purple"));
-        addMapping(ProjectileSnowball.class, NamespaceID.getPermanent("minecraft", "snowball"));
-        addMapping(ProjectileFireball.class, NamespaceID.getPermanent("minecraft", "fireball"));
-        addMapping(ProjectileCannonball.class, NamespaceID.getPermanent("minecraft", "cannonball"));
-
-        addMapping(Mob.class, NamespaceID.getPermanent("minecraft", "mob")); // Abstract class, shouldn't ever be instantiated
-        addMapping(MobHuman.class, NamespaceID.getPermanent("minecraft", "human"));
-        addMapping(Player.class, NamespaceID.getPermanent("minecraft", "player"));
+        addMapping(ProjectilePebble.class, NamespaceID.fromPool("minecraft", "pebble"));
+        addMapping(ProjectileEgg.class, NamespaceID.fromPool("minecraft", "egg"));
+        addMapping(ProjectileArrow.class, NamespaceID.fromPool("minecraft", "arrow"));
+        addMapping(ProjectileArrowGolden.class, NamespaceID.fromPool("minecraft", "arrow_golden"));
+        addMapping(ProjectileArrowPurple.class, NamespaceID.fromPool("minecraft", "arrow_purple"));
+        addMapping(ProjectileSnowball.class, NamespaceID.fromPool("minecraft", "snowball"));
+        addMapping(ProjectileFireball.class, NamespaceID.fromPool("minecraft", "fireball"));
+        addMapping(ProjectileCannonball.class, NamespaceID.fromPool("minecraft", "cannonball"));
+
+        addMapping(Mob.class, NamespaceID.fromPool("minecraft", "mob")); // Abstract class, shouldn't ever be instantiated
+        addMapping(MobHuman.class, NamespaceID.fromPool("minecraft", "human"));
+        addMapping(Player.class, NamespaceID.fromPool("minecraft", "player"));
 
         // Hostile
-        addMapping(MobZombie.class, NamespaceID.getPermanent("minecraft", "zombie"), "guidebook.section.mob.zombie.name");
-        addMapping(MobZombieArmored.class, NamespaceID.getPermanent("minecraft", "zombie_armored"), "guidebook.section.mob.armored_zombie.name");
-        addMapping(MobZombiePig.class, NamespaceID.getPermanent("minecraft", "zombie_pigman"), "guidebook.section.mob.zombie_pigman.name");
-        addMapping(MobCreeper.class, NamespaceID.getPermanent("minecraft", "creeper"), "guidebook.section.mob.creeper.name");
-        addMapping(MobSkeleton.class, NamespaceID.getPermanent("minecraft", "skeleton"), "guidebook.section.mob.skeleton.name");
-        addMapping(MobSpider.class, NamespaceID.getPermanent("minecraft", "spider"), "guidebook.section.mob.spider.name");
-        addMapping(MobGiant.class, NamespaceID.getPermanent("minecraft", "giant"));
-        addMapping(MobSlime.class, NamespaceID.getPermanent("minecraft", "slime"), "guidebook.section.mob.slime.name");
-        addMapping(MobGhast.class, NamespaceID.getPermanent("minecraft", "ghast"), "guidebook.section.mob.ghast.name");
-        addMapping(MobSnowman.class, NamespaceID.getPermanent("minecraft", "snowman"), "guidebook.section.mob.snowman.name");
+        addMapping(MobZombie.class, NamespaceID.fromPool("minecraft", "zombie"), "guidebook.section.mob.zombie.name");
+        addMapping(MobZombieArmored.class, NamespaceID.fromPool("minecraft", "zombie_armored"), "guidebook.section.mob.armored_zombie.name");
+        addMapping(MobZombiePig.class, NamespaceID.fromPool("minecraft", "zombie_pigman"), "guidebook.section.mob.zombie_pigman.name");
+        addMapping(MobCreeper.class, NamespaceID.fromPool("minecraft", "creeper"), "guidebook.section.mob.creeper.name");
+        addMapping(MobSkeleton.class, NamespaceID.fromPool("minecraft", "skeleton"), "guidebook.section.mob.skeleton.name");
+        addMapping(MobSpider.class, NamespaceID.fromPool("minecraft", "spider"), "guidebook.section.mob.spider.name");
+        addMapping(MobGiant.class, NamespaceID.fromPool("minecraft", "giant"));
+        addMapping(MobSlime.class, NamespaceID.fromPool("minecraft", "slime"), "guidebook.section.mob.slime.name");
+        addMapping(MobGhast.class, NamespaceID.fromPool("minecraft", "ghast"), "guidebook.section.mob.ghast.name");
+        addMapping(MobSnowman.class, NamespaceID.fromPool("minecraft", "snowman"), "guidebook.section.mob.snowman.name");
 
         // Passive
-        addMapping(MobScorpion.class, NamespaceID.getPermanent("minecraft", "scorpion"));
-        addMapping(MobPig.class, NamespaceID.getPermanent("minecraft", "pig"), "guidebook.section.mob.pig.name");
-        addMapping(MobSheep.class, NamespaceID.getPermanent("minecraft", "sheep"), "guidebook.section.mob.sheep.name");
-        addMapping(MobCow.class, NamespaceID.getPermanent("minecraft", "cow"), "guidebook.section.mob.cow.name");
-        addMapping(MobChicken.class, NamespaceID.getPermanent("minecraft", "chicken"), "guidebook.section.mob.chicken.name");
-        addMapping(MobSquid.class, NamespaceID.getPermanent("minecraft", "squid"), "guidebook.section.mob.squid.name");
-        addMapping(MobWolf.class, NamespaceID.getPermanent("minecraft", "wolf"), "guidebook.section.mob.wolf.name");
-        addMapping(MobFireflyCluster.class, NamespaceID.getPermanent("minecraft", "firefly_cluster"), "guidebook.section.mob.firefly_cluster.name");
-        addMapping(MobButterfly.class, NamespaceID.getPermanent("minecraft", "butterfly"), "guidebook.section.mob.butterfly.name");
-        addMapping(MobDeer.class, NamespaceID.getPermanent("minecraft", "deer"), "guidebook.section.mob.deer.name");
+        addMapping(MobScorpion.class, NamespaceID.fromPool("minecraft", "scorpion"));
+        addMapping(MobPig.class, NamespaceID.fromPool("minecraft", "pig"), "guidebook.section.mob.pig.name");
+        addMapping(MobSheep.class, NamespaceID.fromPool("minecraft", "sheep"), "guidebook.section.mob.sheep.name");
+        addMapping(MobCow.class, NamespaceID.fromPool("minecraft", "cow"), "guidebook.section.mob.cow.name");
+        addMapping(MobChicken.class, NamespaceID.fromPool("minecraft", "chicken"), "guidebook.section.mob.chicken.name");
+        addMapping(MobSquid.class, NamespaceID.fromPool("minecraft", "squid"), "guidebook.section.mob.squid.name");
+        addMapping(MobWolf.class, NamespaceID.fromPool("minecraft", "wolf"), "guidebook.section.mob.wolf.name");
+        addMapping(MobFireflyCluster.class, NamespaceID.fromPool("minecraft", "firefly_cluster"), "guidebook.section.mob.firefly_cluster.name");
+        addMapping(MobButterfly.class, NamespaceID.fromPool("minecraft", "butterfly"), "guidebook.section.mob.butterfly.name");
+        addMapping(MobDeer.class, NamespaceID.fromPool("minecraft", "deer"), "guidebook.section.mob.deer.name");
     }
 
     @Deprecated
diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java b/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java
index 5e37c36ed..186d33348 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java
@@ -212,14 +212,14 @@ public class EntityFishingBobber extends Entity
             }
         }
         ticksInAir++;
-        Vec3 currentPos = Vec3.getTempVec3(x, y, z);
-        Vec3 nextPos = Vec3.getTempVec3(x + xd, y + yd, z + zd);
+        Vec3 currentPos = Vec3.fromPool(x, y, z);
+        Vec3 nextPos = Vec3.fromPool(x + xd, y + yd, z + zd);
         HitResult clip = world.checkBlockCollisionBetweenPoints(currentPos, nextPos);
-        currentPos = Vec3.getTempVec3(x, y, z);
-        nextPos = Vec3.getTempVec3(x + xd, y + yd, z + zd);
+        currentPos = Vec3.fromPool(x, y, z);
+        nextPos = Vec3.fromPool(x + xd, y + yd, z + zd);
         if(clip != null)
         {
-            nextPos = Vec3.getTempVec3(clip.location.x, clip.location.y, clip.location.z);
+            nextPos = Vec3.fromPool(clip.location.x, clip.location.y, clip.location.z);
             if (clip.hitType == HitResult.HitType.TILE && world.getBlockId(clip.x, clip.y, clip.z) == Blocks.ROPE.id()) {
                 setInGround(true);
                 xTile = clip.x;
@@ -283,7 +283,7 @@ public class EntityFishingBobber extends Entity
         {
             double d8 = ((bb.minY + ((bb.maxY - bb.minY) * (double)(l)) / (double)k) - 0.125D) + 0.125D;
             double d9 = ((bb.minY + ((bb.maxY - bb.minY) * (double)(l + 1)) / (double)k) - 0.125D) + 0.125D;
-            AABB axisalignedbb1 = AABB.getTemporaryBB(bb.minX, d8, bb.minZ, bb.maxX, d9, bb.maxZ);
+            AABB axisalignedbb1 = AABB.fromPool(bb.minX, d8, bb.minZ, bb.maxX, d9, bb.maxZ);
 
             if(world.isAABBInMaterial(axisalignedbb1, Material.water))
             {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityLightning.java b/game/core/src/main/java/net/minecraft/core/entity/EntityLightning.java
index b08216347..b6235fd3e 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/EntityLightning.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/EntityLightning.java
@@ -67,7 +67,7 @@ public class EntityLightning extends Entity
         if(life >= 0)
         {
             double radius = 3D;
-            List<Entity> list = world.getEntitiesWithinAABBExcludingEntity(this, AABB.getTemporaryBB(x - radius, y - radius, z - radius, x + radius, y + 6D + radius, z + radius));
+            List<Entity> list = world.getEntitiesWithinAABBExcludingEntity(this, AABB.fromPool(x - radius, y - radius, z - radius, x + radius, y + 6D + radius, z + radius));
             for (Entity entity : list)
             {
                 entity.thunderHit(this);
diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityPainting.java b/game/core/src/main/java/net/minecraft/core/entity/EntityPainting.java
index f10457f4a..821ffff80 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/EntityPainting.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/EntityPainting.java
@@ -376,20 +376,20 @@ public class EntityPainting extends Entity
         }
     }
     private static final HashMap<String, String> borderMaterialMap = new HashMap<>();
-    public static void addBorder(ItemStack stack, NamespaceID imagePath){
+    public static void addBorder(ItemStack stack, NamespaceID imagePath) {
         borderMaterialMap.put(stack.itemID + "|" + stack.getMetadata(), String.format("/assets/%s/textures/art/borders/%s.png", imagePath.namespace(), imagePath.value()));
     }
     public static String getBorder(ItemStack stack){
         return borderMaterialMap.get(stack.itemID + "|" + stack.getMetadata());
     }
     static {
-        addBorder(Items.INGOT_IRON.getDefaultStack(), NamespaceID.getPermanent("minecraft", "border_iron"));
-        addBorder(Items.INGOT_GOLD.getDefaultStack(), NamespaceID.getPermanent("minecraft", "border_gold"));
-        addBorder(Items.INGOT_STEEL.getDefaultStack(), NamespaceID.getPermanent("minecraft", "border_steel"));
-        addBorder(new ItemStack(Items.DYE, 1, 4), NamespaceID.getPermanent("minecraft", "border_lapis"));
-        addBorder(Items.DIAMOND.getDefaultStack(), NamespaceID.getPermanent("minecraft", "border_diamond"));
-        addBorder(Items.DUST_REDSTONE.getDefaultStack(), NamespaceID.getPermanent("minecraft", "border_redstone"));
-        addBorder(Items.OLIVINE.getDefaultStack(), NamespaceID.getPermanent("minecraft", "border_olivine"));
-        addBorder(Items.QUARTZ.getDefaultStack(), NamespaceID.getPermanent("minecraft", "border_quartz"));
+        addBorder(Items.INGOT_IRON.getDefaultStack(), NamespaceID.fromPool("minecraft", "border_iron"));
+        addBorder(Items.INGOT_GOLD.getDefaultStack(), NamespaceID.fromPool("minecraft", "border_gold"));
+        addBorder(Items.INGOT_STEEL.getDefaultStack(), NamespaceID.fromPool("minecraft", "border_steel"));
+        addBorder(new ItemStack(Items.DYE, 1, 4), NamespaceID.fromPool("minecraft", "border_lapis"));
+        addBorder(Items.DIAMOND.getDefaultStack(), NamespaceID.fromPool("minecraft", "border_diamond"));
+        addBorder(Items.DUST_REDSTONE.getDefaultStack(), NamespaceID.fromPool("minecraft", "border_redstone"));
+        addBorder(Items.OLIVINE.getDefaultStack(), NamespaceID.fromPool("minecraft", "border_olivine"));
+        addBorder(Items.QUARTZ.getDefaultStack(), NamespaceID.fromPool("minecraft", "border_quartz"));
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/entity/Mob.java b/game/core/src/main/java/net/minecraft/core/entity/Mob.java
index 7f7b511b8..2d5bf8b3e 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/Mob.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/Mob.java
@@ -101,7 +101,7 @@ public abstract class Mob extends Entity
     protected @NotNull String basePath = "/assets/minecraft/textures/entity/char/";
     protected @NotNull String defaultTexture = "/assets/minecraft/textures/entity/char/0.png";
     protected @NotNull String variantJsonPath = "/assets/minecraft/textures/entity/char/variant.json";
-    protected @NotNull NamespaceID textureIdentifier = NamespaceID.getPermanent("minecraft", "char");
+    protected @NotNull NamespaceID textureIdentifier = NamespaceID.fromPool("minecraft", "char").copyUnpooled();
 
     public boolean isSkating = false;
 
@@ -168,7 +168,7 @@ public abstract class Mob extends Entity
 
     public boolean canEntityBeSeen(Entity entity)
     {
-        return world.checkBlockCollisionBetweenPoints(Vec3.getTempVec3(x, y + (double) getHeadHeight(), z), Vec3.getTempVec3(entity.x, entity.y + (double)entity.getHeadHeight(), entity.z)) == null;
+        return world.checkBlockCollisionBetweenPoints(Vec3.fromPool(x, y + (double) getHeadHeight(), z), Vec3.fromPool(entity.x, entity.y + (double)entity.getHeadHeight(), entity.z)) == null;
     }
 
     @Override
@@ -1225,13 +1225,13 @@ public abstract class Mob extends Entity
     {
         if(partialTick == 1.0F)
         {
-            return Vec3.getTempVec3(x, y + (headOffset ? getHeadHeight() : 0), z);
+            return Vec3.fromPool(x, y + (headOffset ? getHeadHeight() : 0), z);
         } else
         {
             double x = MathHelper.lerp(xo, this.x, partialTick);
             double y = MathHelper.lerp(yo, this.y, partialTick);
             double z = MathHelper.lerp(zo, this.z, partialTick);
-            return Vec3.getTempVec3(x, y + (headOffset ? getHeadHeight() : 0), z);
+            return Vec3.fromPool(x, y + (headOffset ? getHeadHeight() : 0), z);
         }
     }
 
@@ -1244,7 +1244,7 @@ public abstract class Mob extends Entity
             float x = MathHelper.sin(-yRot * (MathHelper.PI / 180f) - MathHelper.PI);
             float xzLen = -MathHelper.cos(-xRot * (MathHelper.PI / 180f));
             float y = MathHelper.sin(-xRot * (MathHelper.PI / 180f));
-            return Vec3.getTempVec3(x * xzLen, y, z * xzLen);
+            return Vec3.fromPool(x * xzLen, y, z * xzLen);
         }
         else
         {
@@ -1254,12 +1254,12 @@ public abstract class Mob extends Entity
             float x = MathHelper.sin(-yaw * (MathHelper.PI / 180f) - MathHelper.PI);
             float y = MathHelper.sin(-pitch * (MathHelper.PI / 180f));
             float z = MathHelper.cos(-yaw * (MathHelper.PI / 180f) - MathHelper.PI);
-            return Vec3.getTempVec3(x * xzLen, y, z * xzLen);
+            return Vec3.fromPool(x * xzLen, y, z * xzLen);
         }
     }
 
 
-    public HitResult rayTrace(double distance, float partialTick, boolean collideWithFluids, boolean ignoreNonColliderBlocks, boolean useSelectorBoxes)
+    public @Nullable HitResult rayTrace(double distance, float partialTick, boolean collideWithFluids, boolean ignoreNonColliderBlocks, boolean useSelectorBoxes)
     {
         Vec3 head = getPosition(partialTick, true);
         Vec3 viewDirection = getViewVector(partialTick);
diff --git a/game/core/src/main/java/net/minecraft/core/entity/MobPathfinder.java b/game/core/src/main/java/net/minecraft/core/entity/MobPathfinder.java
index 4418c052c..bb75ed9c4 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/MobPathfinder.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/MobPathfinder.java
@@ -145,7 +145,7 @@ public abstract class MobPathfinder extends Mob
     }
 
     protected @Nullable Entity getClosestFireflyToEntity (int x, int y, int z, float radius){
-        List<MobFireflyCluster> nearbyFireflies = world.getEntitiesWithinAABB(MobFireflyCluster.class, AABB.getTemporaryBB(this.x, this.y, this.z, this.x + 1.0D, this.y + 1.0D, this.z + 1.0D).grow(radius, 4D, radius));
+        List<MobFireflyCluster> nearbyFireflies = world.getEntitiesWithinAABB(MobFireflyCluster.class, AABB.fromPool(this.x, this.y, this.z, this.x + 1.0D, this.y + 1.0D, this.z + 1.0D).grow(radius, 4D, radius));
 
         double closestDistance = -1D;
         MobFireflyCluster cluster = null;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobDeer.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobDeer.java
index 70dd32174..f99cb2d20 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobDeer.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobDeer.java
@@ -16,6 +16,7 @@ import net.minecraft.core.world.season.Seasons;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class MobDeer
@@ -32,6 +33,8 @@ public class MobDeer
     private final int MAX_RUNAWAY_TIME = 200;
     private final int COUNTER_TIME = 30;
 
+    public List<WeightedRandomLootObject> burningMobDrops = new ArrayList<>();
+
     public MobDeer(World world)
     {
         super(world);
@@ -39,6 +42,7 @@ public class MobDeer
         setSize(0.9F, 1.3F);
         moveSpeed = 0.8F;
         mobDrops.add(new WeightedRandomLootObject(Items.FOOD_VENISON_RAW.getDefaultStack(), 1, 2));
+        burningMobDrops.add(new WeightedRandomLootObject(Items.FOOD_VENISON_COOKED.getDefaultStack(), 1, 2));
         this.age = MobAge.newRandom(this, MobAge.YEAR_LENGTH_DAYS * 5, 14, MobAge.YEAR_LENGTH_DAYS * 4);
         this.jumpHeight = 0.5D;
     }
@@ -107,6 +111,18 @@ public class MobDeer
 
     }
 
+    @Override
+    protected List<WeightedRandomLootObject> getMobDrops()
+    {
+        if(remainingFireTicks > 0)
+        {
+            return burningMobDrops;
+        } else
+        {
+            return mobDrops;
+        }
+    }
+
     protected void findThreatNearby() {
         int dist = 10;
         Player player = world.getClosestPlayer(x, y, z, dist);
@@ -116,7 +132,7 @@ public class MobDeer
         }
 
         if(player == null){
-            List<MobWolf> nearbyWolves = world.getEntitiesWithinAABB(MobWolf.class, AABB.getTemporaryBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(8D, 4D, 8D));
+            List<MobWolf> nearbyWolves = world.getEntitiesWithinAABB(MobWolf.class, AABB.fromPool(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(8D, 4D, 8D));
             if (!nearbyWolves.isEmpty()) {
                 this.closestThreat = nearbyWolves.get(random.nextInt(nearbyWolves.size()));
                 return;
@@ -142,7 +158,7 @@ public class MobDeer
         double nDX = dX / sqrt;
         double nDZ = dZ / sqrt;
 
-        Vec3 safePoint = Vec3.getTempVec3(x + nDX * scale, y, z + nDZ * scale);
+        Vec3 safePoint = Vec3.fromPool(x + nDX * scale, y, z + nDZ * scale);
         pathToEntity = world.getEntityPathToXYZ(this, MathHelper.floor(safePoint.x), MathHelper.floor(y), MathHelper.floor(safePoint.z), 16F);
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
index 7ee1a5e65..3d5829f10 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
@@ -343,7 +343,7 @@ public class MobWolf
         {
             if(!isWolfTamed() && world.rand.nextInt(50) == 0){
                 List<MobAnimal> validTargets = new ArrayList<>();
-                List<MobAnimal> nearbyAnimals = world.getEntitiesWithinAABB(MobAnimal.class, AABB.getTemporaryBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
+                List<MobAnimal> nearbyAnimals = world.getEntitiesWithinAABB(MobAnimal.class, AABB.fromPool(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
                 if (!nearbyAnimals.isEmpty()) {
                     for(int i = 0; i < nearbyAnimals.size(); i++){
                         MobAnimal animal = nearbyAnimals.get(i);
@@ -360,7 +360,7 @@ public class MobWolf
             ItemStack heldItemSlot = getHeldItem();
             if((heldItemSlot == null || heldItemSlot.itemID <= 0)) {
                 List<EntityItem> triedItems = new ArrayList<>();
-                List<EntityItem> nearbyItems = world.getEntitiesWithinAABB(EntityItem.class, AABB.getTemporaryBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
+                List<EntityItem> nearbyItems = world.getEntitiesWithinAABB(EntityItem.class, AABB.fromPool(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
                 if (!nearbyItems.isEmpty()) {
                     while (triedItems.size() != nearbyItems.size())
                     {
@@ -605,7 +605,7 @@ public class MobWolf
                 }
                 if(attacker instanceof Mob)
                 {
-                    List<MobWolf> list = world.getEntitiesWithinAABB(MobWolf.class, AABB.getTemporaryBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
+                    List<MobWolf> list = world.getEntitiesWithinAABB(MobWolf.class, AABB.fromPool(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
                     Iterator<MobWolf> iterator = list.iterator();
                     do
                     {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonster.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonster.java
index 0bd600f44..01e948abf 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonster.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobMonster.java
@@ -43,7 +43,7 @@ public abstract class MobMonster extends MobPathfinder
             dX = dX * scaleFactor;
             dZ = dZ * scaleFactor;
 
-            Vec3 distanceXYZ = Vec3.getTempVec3(x + dX, y, z + dZ);
+            Vec3 distanceXYZ = Vec3.fromPool(x + dX, y, z + dZ);
             pathToEntity = world.getEntityPathToXYZ(this, MathHelper.floor(distanceXYZ.x), MathHelper.floor(y), MathHelper.floor(distanceXYZ.z), 16F);
         }
 
diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
index c99403814..a12fe413a 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -66,6 +66,7 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.*;
+import java.util.function.Function;
 
 public abstract class Player
     extends Mob
@@ -228,7 +229,7 @@ public abstract class Player
         switch (state) {
             case MOTION_STATE_CROUCHED: {
                 final double heightOfMob = isDwarf() ? 0.5 : 1.5f;
-                return AABB.getTemporaryBB(
+                return AABB.fromPool(
                     this.x - center,
                     (this.y - (double) this.heightOffset) + (double) this.ySlideOffset,
                     this.z - center,
@@ -239,7 +240,7 @@ public abstract class Player
             case MOTION_STATE_DEFAULT:
             default: {
                 final double heightOfMob = isDwarf() ? 0.8 : 1.8f;
-                return AABB.getTemporaryBB(
+                return AABB.fromPool(
                     this.x - center,
                     (this.y - (double) this.heightOffset) + (double) this.ySlideOffset,
                     this.z - center,
@@ -890,6 +891,10 @@ public abstract class Player
     {
     }
 
+    public void displayNBTEditor(@Nullable CompoundTag tag, @Nullable Function<@NotNull CompoundTag, Void> exitAction) {
+
+    }
+
     public void displayWorkbenchScreen(int x, int y, int z)
     {
     }
@@ -999,7 +1004,7 @@ public abstract class Player
         {
             return;
         }
-        List<MobWolf> list = world.getEntitiesWithinAABB(MobWolf.class, AABB.getTemporaryBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
+        List<MobWolf> list = world.getEntitiesWithinAABB(MobWolf.class, AABB.fromPool(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D).grow(16D, 4D, 16D));
         for (MobWolf wolf : list) {
             if (wolf.isWolfTamed() && wolf.getTarget() == null && uuid.equals(wolf.getWolfOwner()) && (!flag || !wolf.isWolfSitting())) {
                 wolf.setTarget(attacker);
diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java
index d84b04c5a..ff85cdb33 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java
@@ -165,11 +165,11 @@ public class Projectile extends Entity {
         ticksInAir++;
 
         HitResult movingobjectposition = getHitResult();
-        Vec3 oldPosition = Vec3.getTempVec3(x, y, z);
-        Vec3 newPosition = Vec3.getTempVec3(x + xd, y + yd, z + zd);
+        Vec3 oldPosition = Vec3.fromPool(x, y, z);
+        Vec3 newPosition = Vec3.fromPool(x + xd, y + yd, z + zd);
         if(movingobjectposition != null)
         {
-            newPosition = Vec3.getTempVec3(movingobjectposition.location.x, movingobjectposition.location.y, movingobjectposition.location.z);
+            newPosition = Vec3.fromPool(movingobjectposition.location.x, movingobjectposition.location.y, movingobjectposition.location.z);
         }
         if(!world.isClientSide)
         {
@@ -205,8 +205,8 @@ public class Projectile extends Entity {
         afterTick();
     }
     public HitResult getHitResult(){
-        Vec3 oldPosition = Vec3.getTempVec3(x, y, z);
-        Vec3 newPosition = Vec3.getTempVec3(x + xd, y + yd, z + zd);
+        Vec3 oldPosition = Vec3.fromPool(x, y, z);
+        Vec3 newPosition = Vec3.fromPool(x + xd, y + yd, z + zd);
         return world.checkBlockCollisionBetweenPoints(oldPosition, newPosition);
     }
     public void onHit(HitResult hitResult){
diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java
index b9056918c..dca7fa555 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java
@@ -120,7 +120,7 @@ public class ProjectileArrow extends Projectile
         if(block != null)
         {
             AABB aabb = block.getCollisionBoundingBoxFromPool(world, xTile, yTile, zTile);
-            if(aabb != null && aabb.contains(Vec3.getTempVec3(x, y, z)))
+            if(aabb != null && aabb.contains(Vec3.fromPool(x, y, z)))
             {
                 setGrounded(true);
             }
@@ -154,8 +154,8 @@ public class ProjectileArrow extends Projectile
         super.tick();
     }
     public HitResult getHitResult(){
-        Vec3 oldPosition = Vec3.getTempVec3(x, y, z);
-        Vec3 newPosition = Vec3.getTempVec3(x + xd, y + yd, z + zd);
+        Vec3 oldPosition = Vec3.fromPool(x, y, z);
+        Vec3 newPosition = Vec3.fromPool(x + xd, y + yd, z + zd);
         return world.checkBlockCollisionBetweenPoints(oldPosition, newPosition, false, true, false);
     }
     public void onHit(HitResult hitResult){
diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileCannonballBouncy.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileCannonballBouncy.java
index 9d5aaebe7..fd9e21429 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileCannonballBouncy.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileCannonballBouncy.java
@@ -45,8 +45,8 @@ public class ProjectileCannonballBouncy extends ProjectileCannonball
         float velocity = MathHelper.sqrt(xd * xd + yd * yd + zd * zd);
 
         // Check for block collision
-        Vec3 currentPos = Vec3.getTempVec3(x, y, z);
-        Vec3 nextPos = Vec3.getTempVec3(x + xd, y + yd - 0.25f, z + zd);
+        Vec3 currentPos = Vec3.fromPool(x, y, z);
+        Vec3 nextPos = Vec3.fromPool(x + xd, y + yd - 0.25f, z + zd);
         HitResult hit = world.checkBlockCollisionBetweenPoints(currentPos, nextPos, false, true, false);
         if(hit != null)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java
index b3ad57d07..2553bf9ae 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java
@@ -243,7 +243,7 @@ public class EntityBoat extends Entity
         {
             double minY = (bb.minY + ((bb.maxY - bb.minY) * (double)(i)) / (double)waterSections) - 0.125D;
             double maxY = (bb.minY + ((bb.maxY - bb.minY) * (double)(i + 1)) / (double)waterSections) - 0.125D;
-            AABB axisalignedbb = AABB.getTemporaryBB(bb.minX, minY, bb.minZ, bb.maxX, maxY, bb.maxZ);
+            AABB axisalignedbb = AABB.fromPool(bb.minX, minY, bb.minZ, bb.maxX, maxY, bb.maxZ);
             if(world.isAABBInMaterial(axisalignedbb, Material.water))
             {
                 bouyancy += 1.0D / (double)waterSections;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
index 1be41b0cf..911358920 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityMinecart.java
@@ -1,7 +1,10 @@
 package net.minecraft.core.entity.vehicle;
 
 import com.mojang.nbt.tags.CompoundTag;
+import com.mojang.nbt.tags.IntTag;
 import com.mojang.nbt.tags.ListTag;
+import com.mojang.nbt.tags.ShortTag;
+import com.mojang.nbt.tags.Tag;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicRail;
 import net.minecraft.core.block.Blocks;
@@ -134,7 +137,7 @@ public class EntityMinecart extends Entity implements Container {
 	protected void defineSynchedData() {
         entityData.define(DATA_TYPE, (byte)0, Byte.class);
         entityData.define(DATA_META, 0, Integer.class);
-        entityData.define(DATA_FUEL, (short)0, Short.class);
+        entityData.define(DATA_FUEL, 0, Integer.class);
     }
 
     public void setType(byte type) {entityData.set(DATA_TYPE, type);}
@@ -143,8 +146,8 @@ public class EntityMinecart extends Entity implements Container {
     public void setMeta(int meta) {entityData.set(DATA_META, meta);}
     public int getMeta() {return entityData.getInt(DATA_META);}
 
-    public void setFuel(short fuel) {entityData.set(DATA_FUEL, fuel);}
-    public short getFuel() {return entityData.getShort(DATA_FUEL);}
+    public void setFuel(int fuel) {entityData.set(DATA_FUEL, fuel);}
+    public int getFuel() {return entityData.getInt(DATA_FUEL);}
 
 
     @Override
@@ -529,7 +532,7 @@ public class EntityMinecart extends Entity implements Container {
             passenger = null;
         }
         if(didFurnacePush && random.nextInt(4) == 0) {
-            setFuel((short) (getFuel() - 1));
+            setFuel(getFuel() - 1);
             if(getFuel() < 0) {
                 xPush = 0.0D;
                 zPush = 0.0D;
@@ -625,7 +628,7 @@ public class EntityMinecart extends Entity implements Container {
         if(railsDY > 0.0D) {
             vecY += 0.5D;
         }
-        return Vec3.getTempVec3(vecX, vecY, vecZ);
+        return Vec3.fromPool(vecX, vecY, vecZ);
     }
 
     @Override
@@ -779,12 +782,12 @@ public class EntityMinecart extends Entity implements Container {
                 break;
             case FURNACE_CART:
                 ItemStack itemstack = player.inventory.getCurrentItem();
-                if(itemstack != null && LookupFuelFurnace.instance.getFuelYield(itemstack.itemID) > 0) {
-                    if(--itemstack.stackSize <= 0)
+                if(itemstack != null && LookupFuelFurnace.instance.getFuelYield(itemstack.itemID) > 0 && itemstack.consumeItem(player)) {
+                    if(itemstack.stackSize <= 0)
                     {
                         player.inventory.setItem(player.inventory.getCurrentItemIndex(), null);
                     }
-                    setFuel((short) (getFuel() + ((LookupFuelFurnace.instance.getFuelYield(itemstack.itemID)/1600F) * 1200)));
+                    setFuel(getFuel() + MathHelper.round(((LookupFuelFurnace.instance.getFuelYield(itemstack.itemID)/1600F) * 1200)));
                 }
                 xPush = x - player.x;
                 zPush = z - player.z;
@@ -813,7 +816,7 @@ public class EntityMinecart extends Entity implements Container {
             case FURNACE_CART:
                 tag.putDouble("PushX", xPush);
                 tag.putDouble("PushZ", zPush);
-                tag.putShort("Fuel", getFuel());
+                tag.putInt("Fuel", getFuel());
                 break;
         }
     }
@@ -837,7 +840,12 @@ public class EntityMinecart extends Entity implements Container {
             case FURNACE_CART:
                 xPush = tag.getDouble("PushX");
                 zPush = tag.getDouble("PushZ");
-                setFuel(tag.getShort("Fuel"));
+                Tag<?> t = tag.getTag("Fuel");
+                if (t instanceof ShortTag) {
+                    setFuel(((ShortTag) t).getValue());
+                } else if (t instanceof IntTag) {
+                    setFuel(((IntTag) t).getValue());
+                }
                 break;
         }
     }
diff --git a/game/core/src/main/java/net/minecraft/core/item/Item.java b/game/core/src/main/java/net/minecraft/core/item/Item.java
index bc62d1e4a..09b73dc9a 100644
--- a/game/core/src/main/java/net/minecraft/core/item/Item.java
+++ b/game/core/src/main/java/net/minecraft/core/item/Item.java
@@ -84,7 +84,7 @@ public class Item implements ITaggable<Item>, IItemConvertible
 
     private static NamespaceID makeNamespaceID(final String string){ // This exists because java is idiotic
         try {
-            return NamespaceID.getPermanent(string);
+            return NamespaceID.fromPool(string).copyUnpooled();
         } catch (final HardIllegalArgumentException e) {
             throw new IllegalArgumentException(e);
         }
@@ -100,7 +100,7 @@ public class Item implements ITaggable<Item>, IItemConvertible
                 stat = replaceItem.createStat(statID, nameKey);
             }
         } else {
-            stat = new StatItem(NamespaceID.getPermanent(this.namespaceID.namespace(), this.namespaceID.value() + "_" + statID), nameKey, this.id).registerStat();
+            stat = new StatItem(NamespaceID.fromPool(this.namespaceID.namespace(), this.namespaceID.value() + "_" + statID), nameKey, this.id).registerStat();
         }
 
         putStat(statID, stat);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java b/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java
index 88d499739..76896042d 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBoat.java
@@ -30,7 +30,7 @@ public class ItemBoat extends Item
         double d = entityplayer.xo + (entityplayer.x - entityplayer.xo) * (double)f;
         double d1 = (entityplayer.yo + (entityplayer.y - entityplayer.yo) * (double)f + 1.62D) - (double)entityplayer.heightOffset;
         double d2 = entityplayer.zo + (entityplayer.z - entityplayer.zo) * (double)f;
-        Vec3 vec3 = Vec3.getTempVec3(d, d1, d2);
+        Vec3 vec3 = Vec3.fromPool(d, d1, d2);
         float f3 = MathHelper.cos(-f2 * 0.01745329F - MathHelper.PI);
         float f4 = MathHelper.sin(-f2 * 0.01745329F - MathHelper.PI);
         float f5 = -MathHelper.cos(-f1 * 0.01745329F);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java
index 45971bf95..73fa99245 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucketEmpty.java
@@ -80,7 +80,7 @@ public class ItemBucketEmpty extends Item
             return;
         }
 
-        AABB box = AABB.getTemporaryBB(x, y, z, x + 1, y + 1, z + 1);
+        AABB box = AABB.fromPool(x, y, z, x + 1, y + 1, z + 1);
         List<MobCow> entities = world.getEntitiesWithinAABB(MobCow.class, box);
         if (!entities.isEmpty()) {
             itemStack.itemID = Items.BUCKET_MILK.id;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemLabel.java b/game/core/src/main/java/net/minecraft/core/item/ItemLabel.java
index 4dea72b1b..2150ca357 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemLabel.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemLabel.java
@@ -47,7 +47,7 @@ public class ItemLabel extends Item
 		blockX += direction.getOffsetX();
 		blockY += direction.getOffsetY();
 		blockZ += direction.getOffsetZ();
-		AABB box = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX + 1, blockY + 1, blockZ + 1);
+		AABB box = AABB.fromPool(blockX, blockY, blockZ, blockX + 1, blockY + 1, blockZ + 1);
 		List<Entity> entities = world.getEntitiesWithinAABBExcludingEntity(null, box);
         for (Entity entity : entities) {
             if (!(entity instanceof Player) && entity instanceof Mob && !entity.hadNicknameSet) {
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java b/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java
index 091c83f79..44edd94dc 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemPaintBrush.java
@@ -73,7 +73,7 @@ public class ItemPaintBrush extends Item {
             blockX += direction.getOffsetX();
             blockY += direction.getOffsetY();
             blockZ += direction.getOffsetZ();
-            AABB box = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX + 1, blockY + 1, blockZ + 1);
+            AABB box = AABB.fromPool(blockX, blockY, blockZ, blockX + 1, blockY + 1, blockZ + 1);
             List<MobSheep> entities = world.getEntitiesWithinAABB(MobSheep.class, box);
             if (!entities.isEmpty()) {
                 MobSheep sheep = entities.get(0);
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemPebble.java b/game/core/src/main/java/net/minecraft/core/item/ItemPebble.java
index e9a861bc4..1e4939b8b 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemPebble.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemPebble.java
@@ -93,7 +93,7 @@ public class ItemPebble extends Item implements IDispensable
         {
             final int newMeta = meta + 1;
 
-            final AABB bbBox = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
+            final AABB bbBox = AABB.fromPool(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
             if (!world.checkIfAABBIsClear(bbBox) || !world.canPlaceOnSurfaceOfBlock(blockX, blockY - 1, blockZ))
             {
                 return false;
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemWandNBT.java b/game/core/src/main/java/net/minecraft/core/item/ItemWandNBT.java
new file mode 100644
index 000000000..e4a730cdb
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemWandNBT.java
@@ -0,0 +1,71 @@
+package net.minecraft.core.item;
+
+import com.mojang.nbt.tags.CompoundTag;
+import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.entity.Mob;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.player.inventory.slot.Slot;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.Function;
+
+public class ItemWandNBT extends Item{
+
+    public ItemWandNBT(String translationKey, String namespaceId, int id) {
+        super(translationKey, namespaceId, id);
+    }
+
+    @Override
+    public ItemStack onInventoryInteract(Player player, Slot slot, ItemStack stackInSlot, boolean isItemGrabbed) {
+        if (slot.getItemStack() != null) {
+            player.displayNBTEditor(slot.getItemStack().writeToNBT(new CompoundTag()), new Function<CompoundTag, Void>() {
+                @Override
+                public Void apply(CompoundTag tag) {
+                    slot.getItemStack().readFromNBT(tag);
+                    return null;
+                }
+            });
+        }
+        return stackInSlot;
+    }
+
+    @Override
+    public boolean hasInventoryInteraction() {
+        return true;
+    }
+
+    @Override
+    public boolean onUseItemOnBlock(@NotNull ItemStack itemstack, @Nullable Player player, @NotNull World world, int blockX, int blockY, int blockZ, @NotNull Side side, double xPlaced, double yPlaced) {
+        TileEntity te = world.getTileEntity(blockX, blockY, blockZ);
+        if (te != null) {
+            CompoundTag tag = new CompoundTag();
+            te.writeToNBT(tag);
+            player.displayNBTEditor(tag, new Function<CompoundTag, Void>() {
+                @Override
+                public Void apply(CompoundTag tag) {
+                    te.readAdditionalData(tag);
+                    return null;
+                }
+            });
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean useItemOnEntity(ItemStack itemstack, Mob mob, Player player) {
+        CompoundTag tag = new CompoundTag();
+        mob.save(tag);
+        player.displayNBTEditor(tag, new Function<CompoundTag, Void>() {
+            @Override
+            public Void apply(CompoundTag tag) {
+                mob.load(tag);
+                return null;
+            }
+        });
+        return true;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/item/Items.java b/game/core/src/main/java/net/minecraft/core/item/Items.java
index 2d7b24ffe..3a1e03ea1 100644
--- a/game/core/src/main/java/net/minecraft/core/item/Items.java
+++ b/game/core/src/main/java/net/minecraft/core/item/Items.java
@@ -204,6 +204,7 @@ public final class Items {
     public static Item STATUE_PIGMAN;
     public static Item SIGN_PAINTED;
     public static Item DOUGH;
+    public static Item WAND_NBT;
 
     private static boolean hasInit = false;
     public static void init(){
@@ -428,5 +429,6 @@ public final class Items {
         FOOD_VENISON_RAW = (new ItemFood("food.venison.raw", "minecraft:item/food_venison_raw", 16550, 3, 16, true, 4));
         FOOD_VENISON_COOKED = (new ItemFood("food.venison.cooked", "minecraft:item/food_venison_cooked", 16551, 12, 8, true, 4));
         DOUGH = (new Item("dough", "minecraft:item/dough", 16552));
+        WAND_NBT = new ItemWandNBT("wand.nbt", "minecraft:item/wand_nbt", 16553);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayer.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayer.java
index 496956ef2..527bf67f7 100644
--- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayer.java
+++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayer.java
@@ -47,7 +47,7 @@ public class ItemBlockLayer<T extends BlockLogicLayerBase> extends ItemBlock<T>
 
 			final int newMeta = meta + 1;
 
-			final AABB bbBox = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
+			final AABB bbBox = AABB.fromPool(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
 			if (!world.checkIfAABBIsClear(bbBox))
 			{
 				return false;
@@ -92,7 +92,7 @@ public class ItemBlockLayer<T extends BlockLogicLayerBase> extends ItemBlock<T>
 
 			final int newMeta = meta + 1;
 
-			final AABB bbBox = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
+			final AABB bbBox = AABB.fromPool(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
 			if (!world.checkIfAABBIsClear(bbBox))
 			{
 				return false;
diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayerLeaves.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayerLeaves.java
index 2763ce2d4..a43036a2f 100644
--- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayerLeaves.java
+++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayerLeaves.java
@@ -48,7 +48,7 @@ public class ItemBlockLayerLeaves<T extends BlockLogicLayerLeaves> extends ItemB
 
 			final int newMeta = meta + 1;
 
-			final AABB bbBox = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
+			final AABB bbBox = AABB.fromPool(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
 			if (!world.checkIfAABBIsClear(bbBox))
 			{
 				return false;
@@ -93,7 +93,7 @@ public class ItemBlockLayerLeaves<T extends BlockLogicLayerLeaves> extends ItemB
 
 			final int newMeta = meta + 1;
 
-			final AABB bbBox = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
+			final AABB bbBox = AABB.fromPool(blockX, blockY, blockZ, blockX + 1f, blockY + (2 * (newMeta + 1)) / 16.0f, blockZ + 1f);
 			if (!world.checkIfAABBIsClear(bbBox))
 			{
 				return false;
diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockSlab.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockSlab.java
index eb7b965d0..c7fe9ea9d 100644
--- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockSlab.java
+++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockSlab.java
@@ -46,7 +46,7 @@ public class ItemBlockSlab<T extends BlockLogic> extends ItemBlock<T>
         {
         	if ((side == Side.TOP && meta == 0) || (side == Side.BOTTOM && meta == 2))
         	{
-                AABB bbBox = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX +1f, blockY +1f, blockZ +1f);
+                AABB bbBox = AABB.fromPool(blockX, blockY, blockZ, blockX +1f, blockY +1f, blockZ +1f);
                 if(!world.checkIfAABBIsClear(bbBox))
                     return false;
 
@@ -73,7 +73,7 @@ public class ItemBlockSlab<T extends BlockLogic> extends ItemBlock<T>
         {
         	if ((yPlaced > 0.5f && meta == 0) || (yPlaced <= 0.5f && meta == 2) || (side == Side.BOTTOM && meta == 0) || (side == Side.TOP && meta == 2))
         	{
-                AABB bbBox = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX +1f, blockY +1f, blockZ +1f);
+                AABB bbBox = AABB.fromPool(blockX, blockY, blockZ, blockX +1f, blockY +1f, blockZ +1f);
                 if(!world.checkIfAABBIsClear(bbBox))
                     return false;
 
diff --git a/game/core/src/main/java/net/minecraft/core/item/material/ArmorMaterial.java b/game/core/src/main/java/net/minecraft/core/item/material/ArmorMaterial.java
index 33b9a23ca..6ccc1d40f 100644
--- a/game/core/src/main/java/net/minecraft/core/item/material/ArmorMaterial.java
+++ b/game/core/src/main/java/net/minecraft/core/item/material/ArmorMaterial.java
@@ -31,7 +31,7 @@ public class ArmorMaterial {
 	private final Map<DamageType, Float> protection = new HashMap<>();
 	
 	public ArmorMaterial(NamespaceID identifier, int durability) {
-		this.identifier = identifier.makePermanent();
+		this.identifier = identifier.copyUnpooled();
 		this.durability = durability;
 
 		ARMOR_MATERIALS.add(this);
@@ -50,37 +50,37 @@ public class ArmorMaterial {
 		return this;
 	}
 	
-	public static final ArmorMaterial LEATHER = register(new ArmorMaterial(NamespaceID.getPermanent("minecraft", "cloth"), 180)
+	public static final ArmorMaterial LEATHER = register(new ArmorMaterial(NamespaceID.fromPool("minecraft", "cloth"), 180)
 		.withProtectionPercentage(COMBAT, 20.0f)
 		.withProtectionPercentage(BLAST, 20.0f)
 		.withProtectionPercentage(FIRE, 20.0f)
 		.withProtectionPercentage(FALL, 120.0f)
 	);
-	public static final ArmorMaterial CHAINMAIL = register(new ArmorMaterial(NamespaceID.getPermanent("minecraft", "chain"), 240)
+	public static final ArmorMaterial CHAINMAIL = register(new ArmorMaterial(NamespaceID.fromPool("minecraft", "chain"), 240)
 		.withProtectionPercentage(COMBAT, 120.0f)
 		.withProtectionPercentage(BLAST, 35.0f)
 		.withProtectionPercentage(FIRE, 35.0f)
 		.withProtectionPercentage(FALL, 35.0f)
 	);
-	public static final ArmorMaterial IRON = register(new ArmorMaterial(NamespaceID.getPermanent("minecraft", "iron"), 200)
+	public static final ArmorMaterial IRON = register(new ArmorMaterial(NamespaceID.fromPool("minecraft", "iron"), 200)
 		.withProtectionPercentage(COMBAT, 45.0f)
 		.withProtectionPercentage(BLAST, 45.0f)
 		.withProtectionPercentage(FIRE, 45.0f)
 		.withProtectionPercentage(FALL, 45.0f)
 	);
-	public static final ArmorMaterial GOLD = register(new ArmorMaterial(NamespaceID.getPermanent("minecraft", "gold"), 120)
+	public static final ArmorMaterial GOLD = register(new ArmorMaterial(NamespaceID.fromPool("minecraft", "gold"), 120)
 		.withProtectionPercentage(COMBAT, 70.0f)
 		.withProtectionPercentage(BLAST, 70.0f)
 		.withProtectionPercentage(FIRE, 70.0f)
 		.withProtectionPercentage(FALL, 70.0f)
 	);
-	public static final ArmorMaterial DIAMOND = register(new ArmorMaterial(NamespaceID.getPermanent("minecraft", "diamond"), 800)
+	public static final ArmorMaterial DIAMOND = register(new ArmorMaterial(NamespaceID.fromPool("minecraft", "diamond"), 800)
 		.withProtectionPercentage(COMBAT, 66.0f)
 		.withProtectionPercentage(BLAST, 66.0f)
 		.withProtectionPercentage(FIRE, 124.0f)
 		.withProtectionPercentage(FALL, 66.0f)
 	);
-	public static final ArmorMaterial STEEL = register(new ArmorMaterial(NamespaceID.getPermanent("minecraft", "steel"), 1200)
+	public static final ArmorMaterial STEEL = register(new ArmorMaterial(NamespaceID.fromPool("minecraft", "steel"), 1200)
 		.withProtectionPercentage(COMBAT, 55.0f)
 		.withProtectionPercentage(BLAST, 150.0f)
 		.withProtectionPercentage(FIRE, 55.0f)
diff --git a/game/core/src/main/java/net/minecraft/core/item/tool/ItemToolShears.java b/game/core/src/main/java/net/minecraft/core/item/tool/ItemToolShears.java
index f0f28e0b8..c1f011d87 100644
--- a/game/core/src/main/java/net/minecraft/core/item/tool/ItemToolShears.java
+++ b/game/core/src/main/java/net/minecraft/core/item/tool/ItemToolShears.java
@@ -57,7 +57,7 @@ public class ItemToolShears extends Item
         blockX += direction.getOffsetX();
         blockY += direction.getOffsetY();
         blockZ += direction.getOffsetZ();
-        AABB box = AABB.getTemporaryBB(blockX, blockY, blockZ, blockX + 1, blockY + 1, blockZ + 1);
+        AABB box = AABB.fromPool(blockX, blockY, blockZ, blockX + 1, blockY + 1, blockZ + 1);
         List<MobSheep> entities = world.getEntitiesWithinAABB(MobSheep.class, box);
         if (!entities.isEmpty()) {
             entities.get(0).onItemInteract(itemStack);
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandBiome.java b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandBiome.java
index dced004ad..8c625f5fb 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandBiome.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandBiome.java
@@ -40,7 +40,7 @@ public class CommandBiome implements CommandManager.CommandRegistry {
                                     if (sourcePos == null) {
                                         c.getSource().sendTranslatableMessage("command.commands.biome.locate.success", Registries.BIOMES.getKey(biome), biomeLocation.getX(c.getSource()), biomeLocation.getZ(c.getSource()));
                                     } else {
-                                        int distance = (int)sourcePos.distanceTo(Vec3.getTempVec3(biomeLocation.getX(c.getSource()), sourcePos.y, biomeLocation.getZ(c.getSource())));
+                                        int distance = (int)sourcePos.distanceTo(Vec3.fromPool(biomeLocation.getX(c.getSource()), sourcePos.y, biomeLocation.getZ(c.getSource())));
                                         c.getSource().sendTranslatableMessage(distance == 1 ? "command.commands.biome.locate.success_in_world_single" : "command.commands.biome.locate.success_in_world_multiple", Registries.BIOMES.getKey(biome), biomeLocation.getX(c.getSource()), biomeLocation.getZ(c.getSource()), distance);
                                     }
                                     return Command.SINGLE_SUCCESS;
@@ -51,7 +51,7 @@ public class CommandBiome implements CommandManager.CommandRegistry {
         int[] xPattern = new int[]{0, 1, 0, -1};
         int[] zPattern = new int[]{1, 0, -1, 0};
         Vec3 sourcePos = source.getBlockCoordinates();
-        if (sourcePos == null) sourcePos = Vec3.getTempVec3(0.0, 0.0, 0.0);
+        if (sourcePos == null) sourcePos = Vec3.fromPool(0.0, 0.0, 0.0);
         int runLength = 2;
         int chunkX = (int)(sourcePos.x / 16.0);
         int y = (int)sourcePos.y;
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandClone.java b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandClone.java
index 0fb5cff75..bdc85300d 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandClone.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandClone.java
@@ -141,7 +141,7 @@ public class CommandClone implements CommandManager.CommandRegistry {
         int destinationY = destination.getPosition().getY(source, true);
         int destinationZ = destination.getPosition().getZ(source);
 
-        if (cloneMode == CloneMode.NORMAL && AABB.getTemporaryBB(minX, minY, minZ, maxX, maxY, maxZ).contains(Vec3.getTempVec3(destinationX, destinationY, destinationZ)) && start.getWorld() == destination.getWorld()) {
+        if (cloneMode == CloneMode.NORMAL && AABB.fromPool(minX, minY, minZ, maxX, maxY, maxZ).contains(Vec3.fromPool(destinationX, destinationY, destinationZ)) && start.getWorld() == destination.getWorld()) {
             throw INSIDE_CLONED_AREA.create();
         }
 
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/helpers/BlockArgumentParser.java b/game/core/src/main/java/net/minecraft/core/net/command/helpers/BlockArgumentParser.java
index 190b8c2bf..411d0810d 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/helpers/BlockArgumentParser.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/helpers/BlockArgumentParser.java
@@ -17,7 +17,7 @@ import java.util.function.Consumer;
 
 public class BlockArgumentParser extends ArgumentParser {
     private static final SimpleCommandExceptionType INVALID_BLOCK = new SimpleCommandExceptionType(() -> I18n.getInstance().translateKey("command.argument_types.block.invalid_block"));
-    public static final NamespaceID AIR_BLOCK = NamespaceID.getPermanent("minecraft", "block/air");
+    public static final NamespaceID AIR_BLOCK = NamespaceID.fromPool("minecraft", "block/air").copyUnpooled();
     private Block<?> block;
     private int metadata = 0;
     private CompoundTag tag = new CompoundTag();
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/helpers/EntitySelector.java b/game/core/src/main/java/net/minecraft/core/net/command/helpers/EntitySelector.java
index 915d3165c..dfb149799 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/helpers/EntitySelector.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/helpers/EntitySelector.java
@@ -97,7 +97,7 @@ public class EntitySelector {
                 this.aABB.maxZ = this.aABB.maxZ + position.z;
             }
         } else {
-            position = this.position.apply(Vec3.getTempVec3(0, 0, 0));
+            position = this.position.apply(Vec3.fromPool(0, 0, 0));
         }
 
         List<? extends Entity> temp = new ArrayList<>(entities);
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorParser.java b/game/core/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorParser.java
index d7eaae07c..921213051 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorParser.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/helpers/EntitySelectorParser.java
@@ -188,11 +188,11 @@ public class EntitySelectorParser {
             aABB = this.createAabb(this.deltaX == null ? 0.0 : this.deltaX, this.deltaY == null ? 0.0 : this.deltaY, this.deltaZ == null ? 0.0 : this.deltaZ);
         } else if (this.distance.getMax() != null) {
             double d = (Double) this.distance.getMax();
-            aABB = AABB.getTemporaryBB(-d, -d, -d, d + 1.0, d + 1.0, d + 1.0);
+            aABB = AABB.fromPool(-d, -d, -d, d + 1.0, d + 1.0, d + 1.0);
         } else {
             aABB = null;
         }
-        Function<Vec3, Vec3> position = this.x == null && this.y == null && this.z == null ? vec3 -> vec3 : vec3 -> Vec3.getTempVec3(this.x == null ? vec3.x : this.x, this.y == null ? vec3.y : this.y, this.z == null ? vec3.z : this.z);
+        Function<Vec3, Vec3> position = this.x == null && this.y == null && this.z == null ? vec3 -> vec3 : vec3 -> Vec3.fromPool(this.x == null ? vec3.x : this.x, this.y == null ? vec3.y : this.y, this.z == null ? vec3.z : this.z);
         return new EntitySelector(this.maxResults, this.includesEntities, this.order, this.limitToType, this.typeInverse, this.currentEntity, this.predicate, this.entityId, this.playerName, this.distance, position, aABB);
     }
 
@@ -206,7 +206,7 @@ public class EntitySelectorParser {
         double j = (bl ? 0.0 : d) + 1.0;
         double k = (bl2 ? 0.0 : e) + 1.0;
         double l = (bl3 ? 0.0 : f) + 1.0;
-        return AABB.getTemporaryBB(g, h, i, j, k, l);
+        return AABB.fromPool(g, h, i, j, k, l);
     }
 
     public void addPredicate(Predicate<Entity> predicate) {
diff --git a/game/core/src/main/java/net/minecraft/core/util/collection/NamespaceID.java b/game/core/src/main/java/net/minecraft/core/util/collection/NamespaceID.java
index 06235b798..79c03b28a 100644
--- a/game/core/src/main/java/net/minecraft/core/util/collection/NamespaceID.java
+++ b/game/core/src/main/java/net/minecraft/core/util/collection/NamespaceID.java
@@ -1,51 +1,58 @@
 package net.minecraft.core.util.collection;
 
 import net.minecraft.core.util.HardIllegalArgumentException;
+import net.minecraft.core.util.pool.ObjectPool;
+import net.minecraft.core.util.pool.Poolable;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Objects;
 
-public final class NamespaceID implements Comparable<NamespaceID>, CharSequence {
+public final class NamespaceID implements Comparable<NamespaceID>, CharSequence, Poolable<NamespaceID> {
     public static final @NotNull String DEFAULT_NAMESPACE = "minecraft";
-    private static final List<NamespaceID> pool = new ArrayList<>();
-    private static int poolPointer = 0;
 
+    private static final @NotNull ObjectPool<NamespaceID> POOL = new ObjectPool<>(() -> new NamespaceID("default", "value"));
+
+    @Deprecated
     public static @NotNull NamespaceID getPermanent(final @NotNull String formattedKey) throws HardIllegalArgumentException {
         return new NamespaceID(formattedKey);
     }
 
+    @Deprecated
     public static @NotNull NamespaceID getPermanent(final @NotNull String namespace, final @NotNull String value) {
         return new NamespaceID(namespace, value);
     }
 
+    @Deprecated
     public static @NotNull NamespaceID getTemp(final @NotNull String formattedKey) throws HardIllegalArgumentException {
-        if(poolPointer >= pool.size())
-        {
-            pool.add(getPermanent(formattedKey));
-        }
-        return pool.get(poolPointer++).set(formattedKey);
+        return NamespaceID.POOL.get().set(formattedKey);
     }
 
+    @Deprecated
     public static @NotNull NamespaceID getTemp(final @NotNull String namespace, final @NotNull String value) {
-        if(poolPointer >= pool.size())
-        {
-            pool.add(getPermanent(namespace, value));
-        }
-        return pool.get(poolPointer++).set(namespace, value);
+        return NamespaceID.POOL.get().set(namespace, value);
     }
 
+    @Deprecated
     public static void deinitializePool()
     {
-        pool.clear();
-        poolPointer = 0;
+        NamespaceID.POOL.free();
     }
 
+    @Deprecated
     public static void initializePool()
     {
-        poolPointer = 0;
+        NamespaceID.POOL.reset();
+    }
+
+    public static @NotNull NamespaceID fromPool(final @NotNull String formattedKey)
+        throws HardIllegalArgumentException
+    {
+        return NamespaceID.POOL.get().set(formattedKey);
+    }
+
+    public static @NotNull NamespaceID fromPool(final @NotNull String namespace, final @NotNull String value) {
+        return NamespaceID.POOL.get().set(namespace, value);
     }
 
     private @NotNull String fullString;
@@ -60,6 +67,18 @@ public final class NamespaceID implements Comparable<NamespaceID>, CharSequence
         set(namespace, value);
     }
 
+    @Override
+    public @NotNull ObjectPool<NamespaceID> getPool() {
+        return NamespaceID.POOL;
+    }
+
+    @Override
+    public void set(final @NotNull NamespaceID other) {
+        this.fullString = other.fullString;
+        this.namespace = other.namespace;
+        this.value = other.value;
+    }
+
     @NotNull
     private NamespaceID set(final @NotNull String formattedKey) throws HardIllegalArgumentException {
         Objects.requireNonNull(formattedKey);
@@ -86,13 +105,9 @@ public final class NamespaceID implements Comparable<NamespaceID>, CharSequence
         return this;
     }
 
-    @NotNull
+    @Deprecated @NotNull
     public NamespaceID makePermanent(){
-        if (pool.contains(this)){
-            pool.remove(this);
-            poolPointer--;
-        }
-        return this;
+        return this.copyUnpooled();
     }
 
     public @NotNull String namespace() {
diff --git a/game/core/src/main/java/net/minecraft/core/util/linalg/Matrix4.java b/game/core/src/main/java/net/minecraft/core/util/linalg/Matrix4.java
new file mode 100644
index 000000000..bd8655293
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/util/linalg/Matrix4.java
@@ -0,0 +1,322 @@
+package net.minecraft.core.util.linalg;
+
+import net.minecraft.core.util.pool.ObjectPool;
+import net.minecraft.core.util.pool.Poolable;
+import org.jetbrains.annotations.NotNull;
+
+public class Matrix4
+    implements Poolable<Matrix4>
+{
+    private static final @NotNull ObjectPool<Matrix4> POOL = new ObjectPool<>(Matrix4::new);
+
+    /**
+     * The first column of the matrix.
+     */
+    public final @NotNull Vector4 x;
+
+    /**
+     * The second column of the matrix.
+     */
+    public final @NotNull Vector4 y;
+
+    /**
+     * The third column of the matrix.
+     */
+    public final @NotNull Vector4 z;
+
+    /**
+     * The fourth column of the matrix.
+     */
+    public final @NotNull Vector4 w;
+
+    /**
+     * Produces a pooled matrix with the given values.
+     */
+    public static @NotNull Matrix4 fromPool(
+        final double c0r0, final double c1r0, final double c2r0, final double c3r0,
+        final double c0r1, final double c1r1, final double c2r1, final double c3r1,
+        final double c0r2, final double c1r2, final double c2r2, final double c3r2,
+        final double c0r3, final double c1r3, final double c2r3, final double c3r3
+    ) {
+        return Matrix4.POOL.get().set(
+            c0r0, c1r0, c2r0, c3r0,
+            c0r1, c1r1, c2r1, c3r1,
+            c0r2, c1r2, c2r2, c3r2,
+            c0r3, c1r3, c2r3, c3r3
+        );
+    }
+
+    /**
+     * Produces the 4x4 identity matrix.
+     */
+    public static @NotNull Matrix4 identity() {
+        return Matrix4.fromPool(
+            1.0, 0.0, 0.0, 0.0,
+            0.0, 1.0, 0.0, 0.0,
+            0.0, 0.0, 1.0, 0.0,
+            0.0, 0.0, 0.0, 1.0
+        );
+    }
+
+    /**
+     * Calculates a perspective projection matrix with the given attributes; angles are given in radians.
+     */
+    public static @NotNull Matrix4 perspective(final double fovy, final double aspect, final double near, final double far) {
+        assert fovy > 0.0;
+        assert Math.abs(aspect) != 0.0;
+        assert near > 0.0;
+        assert far > 0.0;
+        assert near != far;
+
+        final double f = 1.0 / Math.tan(fovy / 2.0);
+
+        return Matrix4.fromPool(
+            f / aspect, 0.0, 0.0, 0.0,
+            0.0, f, 0.0, 0.0,
+            0.0, 0.0, (far + near) / (near - far), (2.0 * far * near) / (near - far),
+            0.0, 0.0, -1.0, 0.0
+        );
+    }
+
+    /**
+     * Calculates an orthographic projection matrix with the given attributes.
+     */
+    public static @NotNull Matrix4 ortho(final double left, final double right, final double bottom, final double top, final double near, final double far) {
+        return Matrix4.fromPool(
+            2.0 / (right - left), 0.0, 0.0, -(right + left) / (right - left),
+            0.0, 2.0 / (top - bottom), 0.0, -(top + bottom) / (top - bottom),
+            0.0, 0.0, -2.0 / (far - near), -(far + near) / (far - near),
+            0.0, 0.0, 0.0, 1.0
+        );
+    }
+
+    private Matrix4() {
+        this.x = Vector4.fromPool(0.0, 0.0, 0.0, 0.0).copyUnpooled();
+        this.y = Vector4.fromPool(0.0, 0.0, 0.0, 0.0).copyUnpooled();
+        this.z = Vector4.fromPool(0.0, 0.0, 0.0, 0.0).copyUnpooled();
+        this.w = Vector4.fromPool(0.0, 0.0, 0.0, 0.0).copyUnpooled();
+    }
+
+    @Override
+    public @NotNull ObjectPool<Matrix4> getPool() {
+        return Matrix4.POOL;
+    }
+
+    @Override
+    public void set(final @NotNull Matrix4 other) {
+        this.x.set(other.x);
+        this.y.set(other.y);
+        this.z.set(other.z);
+        this.w.set(other.w);
+    }
+
+    /**
+     * Sets the values of this matrix.
+     */
+    public @NotNull Matrix4 set(
+        final double c0r0, final double c1r0, final double c2r0, final double c3r0,
+        final double c0r1, final double c1r1, final double c2r1, final double c3r1,
+        final double c0r2, final double c1r2, final double c2r2, final double c3r2,
+        final double c0r3, final double c1r3, final double c2r3, final double c3r3
+    ) {
+        this.x.set(c0r0, c0r1, c0r2, c0r3);
+        this.y.set(c1r0, c1r1, c1r2, c1r3);
+        this.z.set(c2r0, c2r1, c2r2, c2r3);
+        this.z.set(c3r0, c3r1, c3r2, c3r3);
+
+        return this;
+    }
+
+    /**
+     * Translates this matrix by a given vector.
+     */
+    public @NotNull Matrix4 translate(final @NotNull Vector3 translation) {
+        return this.copyPooled().translateInPlace(translation);
+    }
+
+    /**
+     * Translates this matrix by a given vector, modifying it in place.
+     */
+    public @NotNull Matrix4 translateInPlace(final @NotNull Vector3 translation) {
+        final @NotNull Matrix4 translationMatrix = Matrix4.fromPool(
+            1.0, 0.0, 0.0, translation.x,
+            0.0, 1.0, 0.0, translation.y,
+            0.0, 0.0, 1.0, translation.z,
+            0.0, 0.0, 0.0, 1.0
+        );
+
+        return this.multInPlace(translationMatrix);
+    }
+
+    /**
+     * Scales this matrix by a given amount on all axes.
+     */
+    public @NotNull Matrix4 scale(final double scale) {
+        return this.copyPooled().scaleInPlace(scale);
+    }
+
+    /**
+     * Scales this matrix by a given amount on all axes, modifying it in place.
+     */
+    public @NotNull Matrix4 scaleInPlace(final double scale) {
+        return this.scaleInPlace(scale, scale, scale);
+    }
+
+    /**
+     * Scales this matrix by a given amount on each axis.
+     */
+    public @NotNull Matrix4 scale(final double x, final double y, final double z) {
+        return this.copyPooled().scaleInPlace(x, y, z);
+    }
+
+    /**
+     * Scales this matrix by a given amount on each axis, modifying it in place.
+     */
+    public @NotNull Matrix4 scaleInPlace(final double x, final double y, final double z) {
+        final @NotNull Matrix4 scaleMatrix = Matrix4.fromPool(
+            x, 0.0, 0.0, 0.0,
+            0.0, y, 0.0, 0.0,
+            0.0, 0.0, z, 0.0,
+            0.0, 0.0, 0.0, 1.0
+        );
+
+        return this.multInPlace(scaleMatrix);
+    }
+
+    /**
+     * Rotates this matrix on the X axis by the given angle.
+     */
+    public @NotNull Matrix4 rotX(final double radians) {
+        return this.copyPooled().rotXInPlace(radians);
+    }
+
+    /**
+     * Rotates this matrix on the X axis by the given angle, modifying it in place.
+     */
+    public @NotNull Matrix4 rotXInPlace(final double radians) {
+        final double sin = Math.sin(radians);
+        final double cos = Math.cos(radians);
+
+        final @NotNull Matrix4 rotMatrix = Matrix4.fromPool(
+            1.0, 0.0, 0.0, 0.0,
+            0.0, cos, -sin, 0.0,
+            0.0, sin, cos, 0.0,
+            0.0, 0.0, 0.0, 1.0
+        );
+
+        return this.multInPlace(rotMatrix);
+    }
+
+    /**
+     * Rotates this matrix on the Y axis by the given angle.
+     */
+    public @NotNull Matrix4 rotY(final double radians) {
+        return this.copyPooled().rotYInPlace(radians);
+    }
+
+    /**
+     * Rotates this matrix on the Y axis by the given angle, modifying it in place.
+     */
+    public @NotNull Matrix4 rotYInPlace(final double radians) {
+        final double sin = Math.sin(radians);
+        final double cos = Math.cos(radians);
+
+        final @NotNull Matrix4 rotMatrix = Matrix4.fromPool(
+            cos, 0.0, sin, 0.0,
+            0.0, 1.0, 0.0, 0.0,
+            -sin, 0.0, cos, 0.0,
+            0.0, 0.0, 0.0, 1.0
+        );
+
+        return this.multInPlace(rotMatrix);
+    }
+
+    /**
+     * Rotates this matrix on the Z axis by the given angle.
+     */
+    public @NotNull Matrix4 rotZ(final double radians) {
+        return this.copyPooled().rotZInPlace(radians);
+    }
+
+    /**
+     * Rotates this matrix on the Z axis by the given angle, modifying it in place.
+     */
+    public @NotNull Matrix4 rotZInPlace(final double radians) {
+        final double sin = Math.sin(radians);
+        final double cos = Math.sin(radians);
+
+        final @NotNull Matrix4 rotMatrix = Matrix4.fromPool(
+            cos, -sin, 0.0, 0.0,
+            sin, cos, 0.0, 0.0,
+            0.0, 0.0, 1.0, 0.0,
+            0.0, 0.0, 0.0, 1.0
+        );
+
+        return this.multInPlace(rotMatrix);
+    }
+
+    /**
+     * Multiplies this matrix by the given matrix.
+     */
+    public @NotNull Matrix4 mult(final @NotNull Matrix4 other) {
+        return this.copyPooled().multInPlace(other);
+    }
+
+    /**
+     * Multiplies this matrix by the given matrix, modifying it in place.
+     */
+    public @NotNull Matrix4 multInPlace(final @NotNull Matrix4 other) {
+        this.x.set(
+            this.x.x * other.x.x + this.y.x * other.x.y + this.z.x * other.x.z + this.w.x * other.x.w,
+            this.x.y * other.x.x + this.y.y * other.x.y + this.z.y * other.x.z + this.w.y * other.x.w,
+            this.x.z * other.x.x + this.y.z * other.x.y + this.z.z * other.x.z + this.w.z * other.x.w,
+            this.x.w * other.x.x + this.y.w * other.x.y + this.z.w * other.x.z + this.w.w * other.x.w
+        );
+        this.y.set(
+            this.x.x * other.y.x + this.y.x * other.y.y + this.z.x * other.y.z + this.w.x * other.y.w,
+            this.x.y * other.y.x + this.y.y * other.y.y + this.z.y * other.y.z + this.w.y * other.y.w,
+            this.x.z * other.y.x + this.y.z * other.y.y + this.z.z * other.y.z + this.w.z * other.y.w,
+            this.x.w * other.y.x + this.y.w * other.y.y + this.z.w * other.y.z + this.w.w * other.y.w
+        );
+        this.z.set(
+            this.x.x * other.z.x + this.y.x * other.z.y + this.z.x * other.z.z + this.w.x * other.z.w,
+            this.x.y * other.z.x + this.y.y * other.z.y + this.z.y * other.z.z + this.w.y * other.z.w,
+            this.x.z * other.z.x + this.y.z * other.z.y + this.z.z * other.z.z + this.w.z * other.z.w,
+            this.x.w * other.z.x + this.y.w * other.z.y + this.z.w * other.z.z + this.w.w * other.z.w
+        );
+        this.w.set(
+            this.x.x * other.w.x + this.y.x * other.w.y + this.z.x * other.w.z + this.w.x * other.w.w,
+            this.x.y * other.w.x + this.y.y * other.w.y + this.z.y * other.w.z + this.w.y * other.w.w,
+            this.x.z * other.w.x + this.y.z * other.w.y + this.z.z * other.w.z + this.w.z * other.w.w,
+            this.x.w * other.w.x + this.y.w * other.w.y + this.z.w * other.w.z + this.w.w * other.w.w
+        );
+
+        return this;
+    }
+
+    /**
+     * Transforms the given vector by this matrix.
+     */
+    public @NotNull Vector4 transform(final @NotNull Vector4 vec) {
+        return this.x.mult(vec.x).addInPlace(this.y.mult(vec.y)).addInPlace(this.z.mult(vec.z)).addInPlace(this.w.mult(vec.w));
+    }
+
+    /**
+     * Transforms the given vector by this matrix.
+     */
+    public @NotNull Vector3 transform(final @NotNull Vector3 vec) {
+        return this.transform(vec.extend(1.0)).truncate();
+    }
+
+    /**
+     * Returns the matrix as a column-major array.
+     */
+    public double @NotNull [] asArray() {
+        return new double[] {
+            this.x.x, this.x.y, this.x.z, this.x.w,
+            this.y.x, this.y.y, this.y.z, this.y.w,
+            this.z.x, this.z.y, this.z.z, this.z.w,
+            this.w.x, this.w.y, this.w.z, this.w.w
+        };
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/util/linalg/Vector3.java b/game/core/src/main/java/net/minecraft/core/util/linalg/Vector3.java
new file mode 100644
index 000000000..0bd7d5a16
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/util/linalg/Vector3.java
@@ -0,0 +1,404 @@
+package net.minecraft.core.util.linalg;
+
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.pool.ObjectPool;
+import net.minecraft.core.util.pool.Poolable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Objects;
+
+public class Vector3
+    implements Poolable<Vector3>
+{
+    private static final @NotNull ObjectPool<Vector3> POOL = new ObjectPool<>(Vector3::new);
+
+    /**
+     * The X component of this vector.
+     */
+    public double x;
+
+    /**
+     * The Y component of this vector.
+     */
+    public double y;
+
+    /**
+     * The Z component of this vector.
+     */
+    public double z;
+
+    /**
+     * Produces a pooled vector with the given components.
+     */
+    public static @NotNull Vector3 fromPool(final double x, final double y, final double z) {
+        return Vector3.POOL.get().set(x, y, z);
+    }
+
+    /**
+     * Produces a pooled unit vector on the X axis.
+     */
+    public static @NotNull Vector3 unitX() {
+        return Vector3.fromPool(1.0, 0.0, 0.0);
+    }
+
+    /**
+     * Produces a pooled unit vector on the Y axis.
+     */
+    public static @NotNull Vector3 unitY() {
+        return Vector3.fromPool(0.0, 1.0, 0.0);
+    }
+
+    /**
+     * Produces a pooled unit vector on the Z axis.
+     */
+    public static @NotNull Vector3 unitZ() {
+        return Vector3.fromPool(0.0, 0.0, 1.0);
+    }
+
+    private Vector3() {
+        this.x = 0.0;
+        this.y = 0.0;
+        this.z = 0.0;
+    }
+
+    @Override
+    public @NotNull ObjectPool<Vector3> getPool() {
+        return Vector3.POOL;
+    }
+
+    @Override
+    public void set(final @NotNull Vector3 other) {
+        this.x = other.x;
+        this.y = other.y;
+        this.z = other.z;
+    }
+
+    /**
+     * Sets the values of this vector.
+     */
+    public @NotNull Vector3 set(final double x, final double y, final double z) {
+        this.x = x;
+        this.y = y;
+        this.z = z;
+
+        return this;
+    }
+
+    /**
+     * Extends this three-dimensional vector into a four-dimensional vector.
+     */
+    public @NotNull Vector4 extend(final double w) {
+        return Vector4.fromPool(this.x, this.y, this.z, w);
+    }
+
+    /**
+     * Calculates the cross product of this and another vector.
+     */
+    public @NotNull Vector3 cross(final @NotNull Vector3 other) {
+        return Vector3.fromPool(
+            (this.y * other.z) - (this.z * other.y),
+            (this.z * other.x) - (this.x * other.z),
+            (this.x * other.y) - (this.y * other.x)
+        );
+    }
+
+    /**
+     * Performs the unary negation operation.
+     */
+    public @NotNull Vector3 neg() {
+        return this.copyPooled().negInPlace();
+    }
+
+    /**
+     * Performs the unary negation operation, modifying this vector in place.
+     */
+    public @NotNull Vector3 negInPlace() {
+        this.x = -this.x;
+        this.y = -this.y;
+        this.z = -this.z;
+
+        return this;
+    }
+
+    /**
+     * Adds another vector to this vector.
+     */
+    public @NotNull Vector3 add(final @NotNull Vector3 other) {
+        return this.copyPooled().addInPlace(other);
+    }
+
+    /**
+     * Adds another vector to this vector, modifying it in place.
+     */
+    public @NotNull Vector3 addInPlace(final @NotNull Vector3 other) {
+        this.x += other.x;
+        this.y += other.y;
+        this.z += other.z;
+
+        return this;
+    }
+
+    /**
+     * Subtracts another vector from this vector.
+     */
+    public @NotNull Vector3 sub(final @NotNull Vector3 other) {
+        return this.copyPooled().subInPlace(other);
+    }
+
+    /**
+     * Subtracts another vector from this vector, modifying it in place.
+     */
+    public @NotNull Vector3 subInPlace(final @NotNull Vector3 other) {
+        this.x -= other.x;
+        this.y -= other.y;
+        this.z -= other.z;
+
+        return this;
+    }
+
+    /**
+     * Returns this vector as an array.
+     */
+    public double @NotNull [] asArray() {
+        return new double[] { this.x, this.y, this.z };
+    }
+
+    /**
+     * Multiplies this vector by a scalar value.
+     */
+    public @NotNull Vector3 mult(final double value) {
+        return this.copyPooled().multInPlace(value);
+    }
+
+    /**
+     * Multiplies this vector by a scalar value, modifying it in place.
+     */
+    public @NotNull Vector3 multInPlace(final double value) {
+        this.x *= value;
+        this.y *= value;
+        this.z *= value;
+
+        return this;
+    }
+
+    /**
+     * Divides this vector by a scalar value.
+     */
+    public @NotNull Vector3 div(final double value) {
+        return this.copyPooled().divInPlace(value);
+    }
+
+    /**
+     * Divides this vector by a scalar value, modifying it in place.
+     */
+    public @NotNull Vector3 divInPlace(final double value) {
+        this.x /= value;
+        this.y /= value;
+        this.z /= value;
+
+        return this;
+    }
+
+    /**
+     * Calculates the dot product of this and another vector.
+     */
+    public double dot(final @NotNull Vector3 other) {
+        return this.x * other.x + this.y * other.y + this.z * other.z;
+    }
+
+    /**
+     * Calculates the squared magnitude of this vector.
+     * <p>
+     * This does not perform a square root operation, and so can be used to more efficiently compare the magnitudes
+     * of two vectors.
+     */
+    public double squaredMagnitude() {
+        return this.dot(this);
+    }
+
+    /**
+     * Calculates the magnitude of this vector.
+     */
+    public double magnitude() {
+        return Math.sqrt(this.squaredMagnitude());
+    }
+
+    /**
+     * Calculates the angle between this and another vector in radians.
+     */
+    public double angle(final @NotNull Vector3 other) {
+        return Math.atan2(this.cross(other).magnitude(), this.dot(other));
+    }
+
+    /**
+     * Returns a vector with the same direction, but a magnitude of 1.
+     */
+    public @NotNull Vector3 normalize() {
+        return this.normalize(1.0);
+    }
+
+    /**
+     * Returns a vector with the same direction and a given magnitude.
+     */
+    public @NotNull Vector3 normalize(final double magnitude) {
+        return this.mult(magnitude / this.magnitude());
+    }
+
+    /**
+     * Returns the squared distance between two vectors.
+     * <p>
+     * This does not perform a square root operation, and so can be used to more efficiently compare the distances
+     * of vectors.
+     */
+    public double squaredDistance(final @NotNull Vector3 other) {
+        return other.sub(this).squaredMagnitude();
+    }
+
+    /**
+     * Returns the distance between two vectors.
+     */
+    public double distance(final @NotNull Vector3 other) {
+        return Math.sqrt(this.squaredDistance(other));
+    }
+
+    /**
+     * Linearly interpolates towards another vector by the specified amount.
+     */
+    public @NotNull Vector3 lerp(final @NotNull Vector3 other, final double amount) {
+        return Vector3.fromPool(
+            this.x + (other.x - this.x) * amount,
+            this.y + (other.y - this.y) * amount,
+            this.z + (other.z - this.z) * amount
+        );
+    }
+
+    /**
+     * Calculates the intersection between a line segment defined by this and another vector, and a plane perpendicular
+     * to the X axis.
+     * @param other The end-point of the line segment.
+     * @param x The X-axis position of the plane.
+     * @return The intersection point, or null if no point exists.
+     */
+    public @Nullable Vector3 clipX(final @NotNull Vector3 other, final double x) {
+        final @NotNull Vector3 delta = other.sub(this);
+        if (delta.x * delta.x < 1.0E-7D) {
+            return null;
+        }
+
+        final double percentage = (x - this.x) - delta.x;
+
+        if (percentage < 0.0 || percentage > 1.0) {
+            return null;
+        } else {
+            return Vector3.fromPool(this.x + delta.x * percentage, this.y + delta.y * percentage, this.z + delta.z * percentage);
+        }
+    }
+
+    /**
+     * Calculates the intersection between a line segment defined by this and another vector, and a plane perpendicular
+     * to the Y axis.
+     * @param other The end-point of the line segment.
+     * @param y The Y-axis position of the plane.
+     * @return The intersection point, or null if no point exists.
+     */
+    public @Nullable Vector3 clipY(final @NotNull Vector3 other, final double y) {
+        final @NotNull Vector3 delta = other.sub(this);
+        if (delta.y * delta.y < 1.0E-7D) {
+            return null;
+        }
+
+        final double percentage = (y - this.y) - delta.y;
+
+        if (percentage < 0.0 || percentage > 1.0) {
+            return null;
+        } else {
+            return Vector3.fromPool(this.x + delta.x * percentage, this.y + delta.y * percentage, this.z + delta.z * percentage);
+        }
+    }
+
+    /**
+     * Calculates the intersection between a line segment defined by this and another vector, and a plane perpendicular
+     * to the Z axis.
+     * @param other The end-point of the line segment.
+     * @param z The Z-axis position of the plane.
+     * @return The intersection point, or null if no point exists.
+     */
+    public @Nullable Vector3 clipZ(final @NotNull Vector3 other, final double z) {
+        final @NotNull Vector3 delta = other.sub(this);
+        if (delta.z * delta.z < 1.0E-7D) {
+            return null;
+        }
+
+        final double percentage = (z - this.z) - delta.z;
+
+        if (percentage < 0.0 || percentage > 1.0) {
+            return null;
+        } else {
+            return Vector3.fromPool(this.x + delta.x * percentage, this.y + delta.y * percentage, this.z + delta.z * percentage);
+        }
+    }
+
+    /**
+     * Rotates the vector by the given angle in radians around the X axis.
+     */
+    public @NotNull Vector3 rotX(final float radians) {
+        final float cos = MathHelper.cos(radians);
+        final float sin = MathHelper.sin(radians);
+
+        return Vector3.fromPool(
+            this.x,
+            this.y * cos + this.z * sin,
+            this.z * cos - this.y * sin
+        );
+    }
+
+    /**
+     * Rotates the vector by the given angle in radians around the Y axis.
+     */
+    public @NotNull Vector3 rotY(final float radians) {
+        final float cos = MathHelper.cos(radians);
+        final float sin = MathHelper.sin(radians);
+
+        return Vector3.fromPool(
+            this.x * cos + this.z * sin,
+            this.y,
+            this.z * cos - this.x * sin
+        );
+    }
+
+    /**
+     * Rotates the vector by the given angle in radians around the Z axis.
+     */
+    public @NotNull Vector3 rotZ(final float radians) {
+        final float cos = MathHelper.cos(radians);
+        final float sin = MathHelper.sin(radians);
+
+        return Vector3.fromPool(
+           this.x * cos + this.y * sin,
+           this.y * cos - this.x * sin,
+           this.z
+        );
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj instanceof Vector3) {
+            final @NotNull Vector3 other = (Vector3) obj;
+
+            return this.x == other.x && this.y == other.y && this.z == other.z;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.x, this.y, this.z);
+    }
+
+    @Override
+    public @NotNull String toString() {
+        return "[ " + this.x + ", " + this.y + ", " + this.z + " ]";
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/util/linalg/Vector4.java b/game/core/src/main/java/net/minecraft/core/util/linalg/Vector4.java
new file mode 100644
index 000000000..b57beeb8e
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/util/linalg/Vector4.java
@@ -0,0 +1,412 @@
+package net.minecraft.core.util.linalg;
+
+import net.minecraft.core.util.pool.ObjectPool;
+import net.minecraft.core.util.pool.Poolable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Objects;
+
+public class Vector4
+    implements Poolable<Vector4>
+{
+    private static final @NotNull ObjectPool<Vector4> POOL = new ObjectPool<>(Vector4::new);
+
+    /**
+     * The X component of this vector.
+     */
+    public double x;
+
+    /**
+     * The Y component of this vector.
+     */
+    public double y;
+
+    /**
+     * The Z component of this vector.
+     */
+    public double z;
+
+    /**
+     * The W component of this vector.
+     */
+    public double w;
+
+    /**
+     * Produces a pooled vector with the given components.
+     */
+    public static @NotNull Vector4 fromPool(final double x, final double y, final double z, final double w) {
+        return Vector4.POOL.get().set(x, y, z, w);
+    }
+
+    /**
+     * Produces a pooled unit vector on the X axis.
+     */
+    public static @NotNull Vector4 unitX() {
+        return Vector4.fromPool(1.0, 0.0, 0.0, 0.0);
+    }
+
+    /**
+     * Produces a pooled unit vector on the Y axis.
+     */
+    public static @NotNull Vector4 unitY() {
+        return Vector4.fromPool(0.0, 1.0, 0.0, 0.0);
+    }
+
+    /**
+     * Produces a pooled unit vector on the Z axis.
+     */
+    public static @NotNull Vector4 unitZ() {
+        return Vector4.fromPool(0.0, 0.0, 1.0, 0.0);
+    }
+
+    /**
+     * Produces a pooled unit vector on the W axis.
+     */
+    public static @NotNull Vector4 unitW() {
+        return Vector4.fromPool(0.0, 0.0, 0.0, 1.0);
+    }
+
+    private Vector4() {
+        this.x = 0.0;
+        this.y = 0.0;
+        this.z = 0.0;
+        this.w = 0.0;
+    }
+
+    @Override
+    public @NotNull ObjectPool<Vector4> getPool() {
+        return Vector4.POOL;
+    }
+
+    @Override
+    public void set(final @NotNull Vector4 other) {
+        this.x = other.x;
+        this.y = other.y;
+        this.z = other.z;
+        this.w = other.w;
+    }
+
+    /**
+     * Sets the values of the vector.
+     */
+    public @NotNull Vector4 set(final double x, final double y, final double z, final double w) {
+        this.x = x;
+        this.y = y;
+        this.z = z;
+        this.w = w;
+
+        return this;
+    }
+
+    /**
+     * Truncates this four-dimensional vector into a three-dimensional vector.
+     */
+    public @NotNull Vector3 truncate() {
+        return Vector3.fromPool(this.x, this.y, this.z);
+    }
+
+    /**
+     * Performs the unary negation operation.
+     */
+    public @NotNull Vector4 neg() {
+        return this.copyPooled().negInPlace();
+    }
+
+    /**
+     * Performs the unary negation operation, modifying this vector in place.
+     */
+    public @NotNull Vector4 negInPlace() {
+        this.x = -this.x;
+        this.y = -this.y;
+        this.z = -this.z;
+        this.w = -this.w;
+
+        return this;
+    }
+
+    /**
+     * Adds another vector to this vector.
+     */
+    public @NotNull Vector4 add(final @NotNull Vector4 other) {
+        return this.copyPooled().addInPlace(other);
+    }
+
+    /**
+     * Adds another vector to this vector, modifying it in place.
+     */
+    public @NotNull Vector4 addInPlace(final @NotNull Vector4 other) {
+        this.x += other.x;
+        this.y += other.y;
+        this.z += other.z;
+        this.w += other.w;
+
+        return this;
+    }
+
+    /**
+     * Subtracts another vector from this vector.
+     */
+    public @NotNull Vector4 sub(final @NotNull Vector4 other) {
+        return this.copyPooled().subInPlace(other);
+    }
+
+    /**
+     * Subtracts another vector from this vector, modifying it in place.
+     */
+    public @NotNull Vector4 subInPlace(final @NotNull Vector4 other) {
+        this.x -= other.x;
+        this.y -= other.y;
+        this.z -= other.z;
+        this.w -= other.w;
+
+        return this;
+    }
+
+    /**
+     * Returns this vector as an array.
+     */
+    public double @NotNull [] asArray() {
+        return new double[] { this.x, this.y, this.z, this.w };
+    }
+
+    /**
+     * Multiplies this vector by a scalar value.
+     */
+    public @NotNull Vector4 mult(final double value) {
+        return this.copyPooled().multInPlace(value);
+    }
+
+    /**
+     * Multiplies this vector by a scalar value, modifying it in place.
+     */
+    public @NotNull Vector4 multInPlace(final double value) {
+        this.x *= value;
+        this.y *= value;
+        this.z *= value;
+        this.w *= value;
+
+        return this;
+    }
+
+    /**
+     * Divides this vector by a scalar value.
+     */
+    public @NotNull Vector4 div(final double value) {
+        return this.copyPooled().divInPlace(value);
+    }
+
+    /**
+     * Divides this vector by a scalar value, modifying it in place.
+     */
+    public @NotNull Vector4 divInPlace(final double value) {
+        this.x /= value;
+        this.y /= value;
+        this.z /= value;
+        this.w /= value;
+
+        return this;
+    }
+
+    /**
+     * Calculates the dot product of this and another vector.
+     */
+    public double dot(final @NotNull Vector4 other) {
+        return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w;
+    }
+
+    /**
+     * Calculates the squared magnitude of this vector.
+     * <p>
+     * This does not perform a square root operation, and so can be used to more efficiently compare the magnitudes
+     * of two vectors.
+     */
+    public double squaredMagnitude() {
+        return this.dot(this);
+    }
+
+    /**
+     * Calculates the magnitude of this vector.
+     */
+    public double magnitude() {
+        return Math.sqrt(this.squaredMagnitude());
+    }
+
+    /**
+     * Calculates the angle between this and another vector in radians.
+     */
+    public double angle(final @NotNull Vector4 other) {
+        return Math.acos(this.dot(other)) / (this.magnitude() * other.magnitude());
+    }
+
+    /**
+     * Returns a vector with the same direction, but a magnitude of 1.
+     */
+    public @NotNull Vector4 normalize() {
+        return this.normalize(1.0);
+    }
+
+    /**
+     * Returns a vector with the same direction and a given magnitude.
+     */
+    public @NotNull Vector4 normalize(final double magnitude) {
+        return this.mult(magnitude / this.magnitude());
+    }
+
+    /**
+     * Returns the squared distance between two vectors.
+     * <p>
+     * This does not perform a square root operation, and so can be used to more efficiently compare the distances
+     * of vectors.
+     */
+    public double squaredDistance(final @NotNull Vector4 other) {
+        return other.sub(this).squaredMagnitude();
+    }
+
+    /**
+     * Returns the distance between two vectors.
+     */
+    public double distance(final @NotNull Vector4 other) {
+        return Math.sqrt(this.squaredDistance(other));
+    }
+
+    /**
+     * Linearly interpolates towards another vector by the specified amount.
+     */
+    public @NotNull Vector3 lerp(final @NotNull Vector3 other, final double amount) {
+        return Vector3.fromPool(
+            this.x + (other.x - this.x) * amount,
+            this.y + (other.y - this.y) * amount,
+            this.z + (other.z - this.z) * amount
+        );
+    }
+
+    /**
+     * Calculates the intersection between a line segment defined by this and another vector, and a plane perpendicular
+     * to the X axis.
+     * @param other The end-point of the line segment.
+     * @param x The X-axis position of the plane.
+     * @return The intersection point, or null if no point exists.
+     */
+    public @Nullable Vector4 clipX(final @NotNull Vector4 other, final double x) {
+        final @NotNull Vector4 delta = other.sub(this);
+        if (delta.x * delta.x < 1.0E-7D) {
+            return null;
+        }
+
+        final double percentage = (x - this.x) - delta.x;
+
+        if (percentage < 0.0 || percentage > 1.0) {
+            return null;
+        } else {
+            return Vector4.fromPool(
+                this.x + delta.x * percentage,
+                this.y + delta.y * percentage,
+                this.z + delta.z * percentage,
+                this.w + delta.w * percentage
+            );
+        }
+    }
+
+    /**
+     * Calculates the intersection between a line segment defined by this and another vector, and a plane perpendicular
+     * to the Y axis.
+     * @param other The end-point of the line segment.
+     * @param y The Y-axis position of the plane.
+     * @return The intersection point, or null if no point exists.
+     */
+    public @Nullable Vector4 clipY(final @NotNull Vector4 other, final double y) {
+        final @NotNull Vector4 delta = other.sub(this);
+        if (delta.y * delta.y < 1.0E-7D) {
+            return null;
+        }
+
+        final double percentage = (y - this.y) - delta.y;
+
+        if (percentage < 0.0 || percentage > 1.0) {
+            return null;
+        } else {
+            return Vector4.fromPool(
+                this.x + delta.x * percentage,
+                this.y + delta.y * percentage,
+                this.z + delta.z * percentage,
+                this.w + delta.w * percentage
+            );
+        }
+    }
+
+    /**
+     * Calculates the intersection between a line segment defined by this and another vector, and a plane perpendicular
+     * to the Z axis.
+     * @param other The end-point of the line segment.
+     * @param z The Z-axis position of the plane.
+     * @return The intersection point, or null if no point exists.
+     */
+    public @Nullable Vector4 clipZ(final @NotNull Vector4 other, final double z) {
+        final @NotNull Vector4 delta = other.sub(this);
+        if (delta.z * delta.z < 1.0E-7D) {
+            return null;
+        }
+
+        final double percentage = (z - this.z) - delta.z;
+
+        if (percentage < 0.0 || percentage > 1.0) {
+            return null;
+        } else {
+            return Vector4.fromPool(
+                this.x + delta.x * percentage,
+                this.y + delta.y * percentage,
+                this.z + delta.z * percentage,
+                this.w + delta.w * percentage
+            );
+        }
+    }
+
+    /**
+     * Calculates the intersection between a line segment defined by this and another vector, and a plane perpendicular
+     * to the W axis.
+     * @param other The end-point of the line segment.
+     * @param w The W-axis position of the plane.
+     * @return The intersection point, or null if no point exists.
+     */
+    public @Nullable Vector4 clipW(final @NotNull Vector4 other, final double w) {
+        final @NotNull Vector4 delta = other.sub(this);
+        if (delta.w * delta.w < 1.0E-7D) {
+            return null;
+        }
+
+        final double percentage = (w - this.w) - delta.w;
+
+        if (percentage < 0.0 || percentage > 1.0) {
+            return null;
+        } else {
+            return Vector4.fromPool(
+                this.x + delta.x * percentage,
+                this.y + delta.y * percentage,
+                this.z + delta.z * percentage,
+                this.w + delta.w * percentage
+            );
+        }
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj instanceof Vector4) {
+            final @NotNull Vector4 other = (Vector4) obj;
+
+            return this.x == other.x && this.y == other.y && this.z == other.z && this.w == other.w;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.x, this.y, this.z, this.w);
+    }
+
+    @Override
+    public String toString() {
+        return "[ " + this.x + ", " + this.y + ", " + this.z + ", " + this.w + " ]";
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/util/phys/AABB.java b/game/core/src/main/java/net/minecraft/core/util/phys/AABB.java
index 3135a9cb7..4e1529d67 100644
--- a/game/core/src/main/java/net/minecraft/core/util/phys/AABB.java
+++ b/game/core/src/main/java/net/minecraft/core/util/phys/AABB.java
@@ -1,14 +1,13 @@
 package net.minecraft.core.util.phys;
 
 import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.util.pool.ObjectPool;
+import net.minecraft.core.util.pool.Poolable;
+import org.jetbrains.annotations.NotNull;
 
-import java.util.ArrayList;
-import java.util.List;
+public class AABB implements Poolable<AABB> {
+    private static final @NotNull ObjectPool<AABB> POOL = new ObjectPool<>(() -> new AABB(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
 
-public class AABB
-{
-    private static final List<AABB> pool = new ArrayList<>();
-    private static int poolPointer = 0;
     public double minX;
     public double minY;
     public double minZ;
@@ -16,30 +15,36 @@ public class AABB
     public double maxY;
     public double maxZ;
 
+    @Deprecated
     public static AABB getPermanentBB(double minX, double minY, double minZ, double maxX, double maxY, double maxZ)
     {
         return new AABB(minX, minY, minZ, maxX, maxY, maxZ);
     }
 
+    @Deprecated
     public static void deinitializePool()
     {
-        pool.clear();
-        poolPointer = 0;
+        AABB.POOL.free();
     }
 
+    @Deprecated
     public static void initializePool()
     {
-        poolPointer = 0;
+        AABB.POOL.reset();
     }
 
+    @Deprecated
     public static AABB getTemporaryBB(double minX, double minY, double minZ, double maxX,
                                       double maxY, double maxZ)
     {
-        if(poolPointer >= pool.size())
-        {
-            pool.add(getPermanentBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D));
-        }
-        return pool.get(poolPointer++).set(minX, minY, minZ, maxX, maxY, maxZ);
+        return AABB.POOL.get().set(minX, minY, minZ, maxX, maxY, maxZ);
+    }
+
+    public static @NotNull AABB fromPool(
+        final double minX, final double minY, final double minZ,
+        final double maxX, final double maxY, final double maxZ
+    ) {
+        return AABB.POOL.get().set(minX, minY, minZ, maxX, maxY, maxZ);
     }
 
     private AABB(double minX, double minY, double minZ, double maxX, double maxY, double maxZ)
@@ -52,6 +57,21 @@ public class AABB
         this.maxZ = maxZ;
     }
 
+    @Override
+    public @NotNull ObjectPool<AABB> getPool() {
+        return AABB.POOL;
+    }
+
+    @Override
+    public void set(final @NotNull AABB other) {
+        this.minX = other.minX;
+        this.minY = other.minY;
+        this.minZ = other.minZ;
+        this.maxX = other.maxX;
+        this.maxY = other.maxY;
+        this.maxZ = other.maxZ;
+    }
+
     public AABB set(double minX, double minY, double minZ, double maxX, double maxY, double maxZ)
     {
         this.minX = minX;
@@ -95,7 +115,7 @@ public class AABB
         {
             maxZ += stretchZ;
         }
-        return getTemporaryBB(minX, minY, minZ, maxX, maxY, maxZ);
+        return fromPool(minX, minY, minZ, maxX, maxY, maxZ);
     }
 
     public AABB grow(double d, double d1, double d2)
@@ -106,12 +126,12 @@ public class AABB
         double d6 = maxX + d;
         double d7 = maxY + d1;
         double d8 = maxZ + d2;
-        return getTemporaryBB(d3, d4, d5, d6, d7, d8);
+        return fromPool(d3, d4, d5, d6, d7, d8);
     }
 
     public AABB cloneMove(double offX, double offY, double offZ)
     {
-        return getTemporaryBB(minX + offX, minY + offY, minZ + offZ, maxX + offX, maxY + offY, maxZ + offZ);
+        return fromPool(minX + offX, minY + offY, minZ + offZ, maxX + offX, maxY + offY, maxZ + offZ);
     }
 
     public double clipXCollide(AABB aabb, double d)
@@ -268,7 +288,7 @@ public class AABB
         if (n3 > 0.0) {
             maxZ -= n3;
         }
-        return getTemporaryBB(minX, minY, minZ, maxX, maxY, maxZ);
+        return fromPool(minX, minY, minZ, maxX, maxY, maxZ);
     }
 
     public AABB getInsetBoundingBox(double d, double d1, double d2)
@@ -279,16 +299,18 @@ public class AABB
         double d6 = maxX - d;
         double d7 = maxY - d1;
         double d8 = maxZ - d2;
-        return getTemporaryBB(d3, d4, d5, d6, d7, d8);
+        return fromPool(d3, d4, d5, d6, d7, d8);
     }
 
+    @Deprecated
     public AABB copy()
     {
-        return getTemporaryBB(minX, minY, minZ, maxX, maxY, maxZ);
+        return fromPool(minX, minY, minZ, maxX, maxY, maxZ);
     }
 
+    @Deprecated
     public AABB copyPermanent() {
-        return getPermanentBB(minX, minY, minZ, maxX, maxY, maxZ);
+        return fromPool(minX, minY, minZ, maxX, maxY, maxZ).copyUnpooled();
     }
 
 	public HitResult clip(Vec3 start, Vec3 end) {
diff --git a/game/core/src/main/java/net/minecraft/core/util/phys/HitResult.java b/game/core/src/main/java/net/minecraft/core/util/phys/HitResult.java
index ea0eab1b2..686af883e 100644
--- a/game/core/src/main/java/net/minecraft/core/util/phys/HitResult.java
+++ b/game/core/src/main/java/net/minecraft/core/util/phys/HitResult.java
@@ -20,7 +20,7 @@ public class HitResult
         this.y = y;
         this.z = z;
         this.side = side;
-        location = Vec3.getTempVec3(vec3.x, vec3.y, vec3.z);
+        location = Vec3.fromPool(vec3.x, vec3.y, vec3.z);
         entity = null;
     }
 
@@ -32,7 +32,7 @@ public class HitResult
         side = Side.NONE;
         hitType = HitType.ENTITY;
         this.entity = entity;
-        location = Vec3.getTempVec3(entity.x, entity.y, entity.z);
+        location = Vec3.fromPool(entity.x, entity.y, entity.z);
     }
 
     public double distanceToSquared(final Entity entity) {
diff --git a/game/core/src/main/java/net/minecraft/core/util/phys/Vec3.java b/game/core/src/main/java/net/minecraft/core/util/phys/Vec3.java
index a6fa29331..0313a4a0c 100644
--- a/game/core/src/main/java/net/minecraft/core/util/phys/Vec3.java
+++ b/game/core/src/main/java/net/minecraft/core/util/phys/Vec3.java
@@ -1,49 +1,49 @@
 package net.minecraft.core.util.phys;
 
 import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.pool.Poolable;
+import org.jetbrains.annotations.NotNull;
+import net.minecraft.core.util.pool.ObjectPool;
 
-import java.util.ArrayList;
-import java.util.List;
-
-public class Vec3
+public class Vec3 implements Poolable<Vec3>
 {
-    private static final List<Vec3> pool = new ArrayList<>();
-    private static int poolPointer = 0;
+    private static final @NotNull ObjectPool<Vec3> POOL = new ObjectPool<>(() -> new Vec3(0.0, 0.0, 0.0));
+
     public double x;
     public double y;
     public double z;
 
+    @Deprecated
     public static Vec3 getPermanentVec3(double x, double y, double z)
     {
         return new Vec3(x, y, z);
     }
 
+    @Deprecated
     public static void deinitializePool()
     {
-        pool.clear();
-        poolPointer = 0;
+        Vec3.POOL.free();
     }
 
+    @Deprecated
     public static void initializePool()
     {
-        poolPointer = 0;
+        Vec3.POOL.reset();
     }
 
+    @Deprecated
     public static Vec3 getTempVec3(double x, double y, double z)
     {
-        if(poolPointer >= pool.size())
-        {
-            pool.add(getPermanentVec3(0.0D, 0.0D, 0.0D));
-        }
-        return pool.get(poolPointer++).set(x, y, z);
+        return Vec3.POOL.get().set(x, y, z);
     }
 
-    public Vec3 makePermanent(){
-        if (pool.contains(this)){
-            pool.remove(this);
-            poolPointer--;
-        }
-        return this;
+    public static @NotNull Vec3 fromPool(final double x, final double y, final double z) {
+        return Vec3.POOL.get().set(x, y, z);
+    }
+
+    @Deprecated
+    public Vec3 makePermanent() {
+        return this.copyUnpooled();
     }
 
     private Vec3(double x, double y, double z) {
@@ -61,7 +61,19 @@ public class Vec3
         this.z = z;
     }
 
-    private Vec3 set(double x, double y, double z)
+    @Override
+    public @NotNull ObjectPool<Vec3> getPool() {
+        return Vec3.POOL;
+    }
+
+    @Override
+    public void set(final @NotNull Vec3 other) {
+        this.x = other.x;
+        this.y = other.y;
+        this.z = other.z;
+    }
+
+    public Vec3 set(double x, double y, double z)
     {
         this.x = x;
         this.y = y;
@@ -71,7 +83,7 @@ public class Vec3
 
     public Vec3 vectorTo(Vec3 vec3)
     {
-        return getTempVec3(vec3.x - x, vec3.y - y, vec3.z - z);
+        return fromPool(vec3.x - x, vec3.y - y, vec3.z - z);
     }
 
     public Vec3 normalize()
@@ -79,7 +91,7 @@ public class Vec3
         double d = MathHelper.sqrt(x * x + y * y + z * z);
         if(d < 0.0001D)
         {
-            return getTempVec3(0.0D, 0.0D, 0.0D);
+            return fromPool(0.0D, 0.0D, 0.0D);
         } else
         {
             return scale(1/d);
@@ -90,16 +102,16 @@ public class Vec3
     }
     public Vec3 crossProduct(Vec3 vec3)
     {
-        return getTempVec3(y * vec3.z - z * vec3.y, z * vec3.x - x * vec3.z, x * vec3.y - y * vec3.x);
+        return fromPool(y * vec3.z - z * vec3.y, z * vec3.x - x * vec3.z, x * vec3.y - y * vec3.x);
     }
 
     public Vec3 add(double x, double y, double z)
     {
-        return getTempVec3(this.x + x, this.y + y, this.z + z);
+        return fromPool(this.x + x, this.y + y, this.z + z);
     }
 
     public Vec3 scale(double scalar){
-        return getTempVec3(this.x * scalar, this.y * scalar, this.z * scalar);
+        return fromPool(this.x * scalar, this.y * scalar, this.z * scalar);
     }
 
     public double distanceTo(Vec3 vec3)
@@ -136,7 +148,7 @@ public class Vec3
         double diffX = vec3.x - x;
         double diffY = vec3.y - y;
         double diffZ = vec3.z - z;
-        if(diffX * diffX < 1.0000000116860974E-007D)
+        if(diffX * diffX < 1E-007D)
         {
             return null;
         }
@@ -146,7 +158,7 @@ public class Vec3
             return null;
         } else
         {
-            return getTempVec3(x + diffX * d4, y + diffY * d4, z + diffZ * d4);
+            return fromPool(x + diffX * d4, y + diffY * d4, z + diffZ * d4);
         }
     }
 
@@ -165,7 +177,7 @@ public class Vec3
             return null;
         } else
         {
-            return getTempVec3(x + diffX * d4, y + diffY * d4, z + diffZ * d4);
+            return fromPool(x + diffX * d4, y + diffY * d4, z + diffZ * d4);
         }
     }
 
@@ -184,7 +196,7 @@ public class Vec3
             return null;
         } else
         {
-            return getTempVec3(x + diffX * d4, y + diffY * d4, z + diffZ * d4);
+            return fromPool(x + diffX * d4, y + diffY * d4, z + diffZ * d4);
         }
     }
 
@@ -195,7 +207,7 @@ public class Vec3
     }
 
     public Vec3 lerp(final Vec3 vec3, final double progress) {
-        return getTempVec3(this.x + (vec3.x - this.x) * progress, this.y + (vec3.y - this.y) * progress, this.z + (vec3.z - this.z) * progress);
+        return fromPool(this.x + (vec3.x - this.x) * progress, this.y + (vec3.y - this.y) * progress, this.z + (vec3.z - this.z) * progress);
     }
     public void rotateAroundX(float radians)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/util/pool/ObjectPool.java b/game/core/src/main/java/net/minecraft/core/util/pool/ObjectPool.java
new file mode 100644
index 000000000..b633a533d
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/util/pool/ObjectPool.java
@@ -0,0 +1,105 @@
+package net.minecraft.core.util.pool;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides an abstraction over a pooled set of objects that can be reused.
+ * @param <T> The type of object to be pooled.
+ */
+public class ObjectPool<T extends Poolable<T>> {
+    /**
+     * A list of all created ObjectPools, used for bulk resets and frees.
+     */
+    private static final @NotNull List<ObjectPool<?>> ALL_POOLS = new ArrayList<>();
+
+    /**
+     * Resets the pool pointer for all pools to 0, but does not free any pooled objects, allowing them to be reused.
+     */
+    public static void resetAllPools() {
+        for (final @NotNull ObjectPool<?> pool : ObjectPool.ALL_POOLS) {
+            pool.reset();
+        }
+    }
+
+    /**
+     * Completely frees all pools, allowing their memory to be freed. Should generally only be called in memory-constrained
+     * situations.
+     */
+    public static void freeAllPools() {
+        for (final @NotNull ObjectPool<?> pool : ObjectPool.ALL_POOLS) {
+            pool.free();
+        }
+    }
+
+    /**
+     * A factory that generates new default instances of the pooled object.
+     * @param <T> The type of object to be pooled.
+     */
+    public interface PooledObjectFactory<T> {
+        @NotNull T createDefault();
+    }
+
+    /**
+     * The factory that generates instances of T.
+     */
+    private final @NotNull ObjectPool.PooledObjectFactory<T> factory;
+
+    /**
+     * The pool containing instances of T.
+     */
+    private final List<T> pool = new ArrayList<>();
+
+    /**
+     * The next index to take a pooled object from when requested.
+     */
+    private int poolPointer = 0;
+
+    /**
+     * Creates a new instance of the ObjectPool.
+     * @param factory A factory that generates instances of T.
+     */
+    public ObjectPool(final @NotNull ObjectPool.PooledObjectFactory<T> factory) {
+        this.factory = factory;
+
+        ObjectPool.ALL_POOLS.add(this);
+    }
+
+    /**
+     * Fetches an instance of T, whose lifetime is not guaranteed beyond the current frame.
+     * @return An instance of T to be used.
+     */
+    public @NotNull T get() {
+        if (this.poolPointer >= this.pool.size()) {
+            this.pool.add(this.factory.createDefault());
+        }
+
+        return this.pool.get(this.poolPointer++);
+    }
+
+    /**
+     * Creates a new instance of T which is not part of the pool.
+     * Do not make this public, or I will have an aneurysm.
+     */
+    /* package-private */ @NotNull T getUnpooled() {
+        return this.factory.createDefault();
+    }
+
+    /**
+     * Resets the pool pointer to 0, but does not free any existing instances of T, allowing them to be reused.
+     */
+    public void reset() {
+        this.poolPointer = 0;
+    }
+
+    /**
+     * Completely frees the pool, de-allocating any memory inside it. Should generally only be called in memory-constrained
+     * situations.
+     */
+    public void free() {
+        this.pool.clear();
+        this.poolPointer = 0;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/util/pool/Poolable.java b/game/core/src/main/java/net/minecraft/core/util/pool/Poolable.java
new file mode 100644
index 000000000..5db41bd1d
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/util/pool/Poolable.java
@@ -0,0 +1,23 @@
+package net.minecraft.core.util.pool;
+
+import org.jetbrains.annotations.NotNull;
+
+public interface Poolable<T extends Poolable<T>> {
+    @NotNull ObjectPool<T> getPool();
+
+    void set(final @NotNull T other);
+
+    default @NotNull T copyUnpooled() {
+        final @NotNull T copy = getPool().getUnpooled();
+        copy.set((T) this);
+
+        return copy;
+    }
+
+    default @NotNull T copyPooled() {
+        final @NotNull T copy = getPool().get();
+        copy.set((T) this);
+
+        return copy;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/Explosion.java b/game/core/src/main/java/net/minecraft/core/world/Explosion.java
index 721d688eb..efaa9e170 100644
--- a/game/core/src/main/java/net/minecraft/core/world/Explosion.java
+++ b/game/core/src/main/java/net/minecraft/core/world/Explosion.java
@@ -151,8 +151,8 @@ public class Explosion {
         int z1 = MathHelper.floor(explosionZ - (double) explosionSize2 - 1.0D);
         int z2 = MathHelper.floor(explosionZ + (double) explosionSize2 + 1.0D);
         
-        List<Entity> list = new ArrayList<>(worldObj.getEntitiesWithinAABBExcludingEntity(exploder, AABB.getTemporaryBB(x1, y1, z1, x2, y2, z2)));
-        Vec3 vec3 = Vec3.getTempVec3(explosionX, explosionY, explosionZ);
+        List<Entity> list = new ArrayList<>(worldObj.getEntitiesWithinAABBExcludingEntity(exploder, AABB.fromPool(x1, y1, z1, x2, y2, z2)));
+        Vec3 vec3 = Vec3.fromPool(explosionX, explosionY, explosionZ);
         for (Entity entity : list) {
             double d4 = entity.distanceTo(explosionX, explosionY, explosionZ) / (double) explosionSize2;
             if (d4 <= 1.0D) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/ExplosionCannonball.java b/game/core/src/main/java/net/minecraft/core/world/ExplosionCannonball.java
index e833a79df..329f6a6f6 100644
--- a/game/core/src/main/java/net/minecraft/core/world/ExplosionCannonball.java
+++ b/game/core/src/main/java/net/minecraft/core/world/ExplosionCannonball.java
@@ -86,8 +86,8 @@ public class ExplosionCannonball extends Explosion{
         int i2 = MathHelper.floor(explosionZ - (double)explosionSize - 1.0D);
         int j2 = MathHelper.floor(explosionZ + (double)explosionSize + 1.0D);
 //        List<Entity> list = worldObj.getEntitiesWithinAABBExcludingEntity(exploder, AABB.getBoundingBoxFromPool(k, k1, i2, i1, l1, j2));
-        List<Entity> list = worldObj.getEntitiesWithinAABB(Entity.class, AABB.getTemporaryBB(k, k1, i2, i1, l1, j2)); // Cannon balls can explode their owners
-        Vec3 vec3 = Vec3.getTempVec3(explosionX, explosionY, explosionZ);
+        List<Entity> list = worldObj.getEntitiesWithinAABB(Entity.class, AABB.fromPool(k, k1, i2, i1, l1, j2)); // Cannon balls can explode their owners
+        Vec3 vec3 = Vec3.fromPool(explosionX, explosionY, explosionZ);
         for(int k2 = 0; k2 < list.size(); k2++)
         {
             Entity entity = list.get(k2);
diff --git a/game/core/src/main/java/net/minecraft/core/world/SpawnerMobs.java b/game/core/src/main/java/net/minecraft/core/world/SpawnerMobs.java
index eeb684cc3..aa187ae6f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/SpawnerMobs.java
+++ b/game/core/src/main/java/net/minecraft/core/world/SpawnerMobs.java
@@ -264,7 +264,7 @@ public final class SpawnerMobs
                         if(pathEntity != null && pathEntity.length > 1)
                         {
                             Node pathPoint = pathEntity.last();
-                            boolean isCollisionFree = world.checkBlockCollisionBetweenPoints(Vec3.getTempVec3(player.x, player.y + 1.5f, player.z), Vec3.getTempVec3(pathPoint.x, pathPoint.y + 1.5f, pathPoint.z)) == null;
+                            boolean isCollisionFree = world.checkBlockCollisionBetweenPoints(Vec3.fromPool(player.x, player.y + 1.5f, player.z), Vec3.fromPool(pathPoint.x, pathPoint.y + 1.5f, pathPoint.z)) == null;
                             if(Math.abs(pathPoint.x + 0.5f - player.x) < 1.5 && Math.abs(pathPoint.z + 0.5f - player.z) < 1.5 && Math.abs(pathPoint.y + 0.5f - player.y) < 1.5 && isCollisionFree) {
                                 return true;
                             }
@@ -358,7 +358,7 @@ public final class SpawnerMobs
 							if(pathEntity != null && pathEntity.length > 1)
                             {
 								Node pathPoint = pathEntity.last();
-                                boolean isCollisionFree = world.checkBlockCollisionBetweenPoints(Vec3.getTempVec3(player.x, player.y + 1.5f, player.z), Vec3.getTempVec3(pathPoint.x, pathPoint.y + 1.5f, pathPoint.z)) == null;
+                                boolean isCollisionFree = world.checkBlockCollisionBetweenPoints(Vec3.fromPool(player.x, player.y + 1.5f, player.z), Vec3.fromPool(pathPoint.x, pathPoint.y + 1.5f, pathPoint.z)) == null;
 								if(Math.abs(pathPoint.x + 0.5f - player.x) < 1.5 && Math.abs(pathPoint.z + 0.5f - player.z) < 1.5 && Math.abs(pathPoint.y + 0.5f - player.y) < 1.5 && isCollisionFree) {
 									ChunkCoordinates pos = BlockLogicBed.getNearestEmptyChunkCoordinates(world, MathHelper.floor(player.x), MathHelper.floor(player.y), MathHelper.floor(player.z), 1);
 									if(pos == null) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/World.java b/game/core/src/main/java/net/minecraft/core/world/World.java
index 583ddf01e..83f15db1f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/World.java
+++ b/game/core/src/main/java/net/minecraft/core/world/World.java
@@ -1275,7 +1275,7 @@ public class World implements WorldSource {
                 start.y += d7 * d5;
                 start.z = d2;
             }
-            Vec3 vec32 = Vec3.getTempVec3(start.x, start.y, start.z);
+            Vec3 vec32 = Vec3.fromPool(start.x, start.y, start.z);
             blockStartX = (int)(vec32.x = MathHelper.floor(start.x));
             if(byte0 == 5)
             {
@@ -1936,7 +1936,7 @@ public class World implements WorldSource {
             return false;
         }
         boolean flag = false;
-        Vec3 vec3 = Vec3.getTempVec3(0.0D, 0.0D, 0.0D);
+        Vec3 vec3 = Vec3.fromPool(0.0D, 0.0D, 0.0D);
         for(int k1 = i; k1 < j; k1++)
         {
             for(int l1 = k; l1 < l; l1++)
@@ -2106,7 +2106,7 @@ public class World implements WorldSource {
                     double d3 = aabb.minX + (aabb.maxX - aabb.minX) * (double)f;
                     double d4 = aabb.minY + (aabb.maxY - aabb.minY) * (double)f1;
                     double d5 = aabb.minZ + (aabb.maxZ - aabb.minZ) * (double)f2;
-                    if(checkBlockCollisionBetweenPoints(Vec3.getTempVec3(d3, d4, d5), vec3) == null)
+                    if(checkBlockCollisionBetweenPoints(Vec3.fromPool(d3, d4, d5), vec3) == null)
                     {
                         i++;
                     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/config/spawning/SpawnerConfig.java b/game/core/src/main/java/net/minecraft/core/world/config/spawning/SpawnerConfig.java
index be63f9911..ca50a4c41 100644
--- a/game/core/src/main/java/net/minecraft/core/world/config/spawning/SpawnerConfig.java
+++ b/game/core/src/main/java/net/minecraft/core/world/config/spawning/SpawnerConfig.java
@@ -63,7 +63,7 @@ public class SpawnerConfig {
         CompoundTag overrides = tag.getCompound("overrides");
         for (Map.Entry<String, Tag<?>> tagEntry : overrides.getValue().entrySet()) {
             try {
-                mobSpawnOverrides.put(NamespaceID.getPermanent(tagEntry.getKey()), ((ByteTag)tagEntry.getValue()).getValue() != 0);
+                mobSpawnOverrides.put(NamespaceID.fromPool(tagEntry.getKey()).copyUnpooled(), ((ByteTag)tagEntry.getValue()).getValue() != 0);
             } catch (HardIllegalArgumentException e) {
                 LOGGER.error("Failed to convert string '{}' to namespace id!", tagEntry.getKey(), e);
             }
diff --git a/game/core/src/main/java/net/minecraft/core/world/pathfinder/Path.java b/game/core/src/main/java/net/minecraft/core/world/pathfinder/Path.java
index 1de15536f..2b349dafd 100644
--- a/game/core/src/main/java/net/minecraft/core/world/pathfinder/Path.java
+++ b/game/core/src/main/java/net/minecraft/core/world/pathfinder/Path.java
@@ -42,6 +42,6 @@ public class Path
         double x = (double) nodes[index].x + (double)(int)(entity.bbWidth + 2.0F) * 0.5D;
         double y = nodes[index].y;
         double z = (double) nodes[index].z + (double)(int)(entity.bbWidth + 2.0F) * 0.5D;
-        return Vec3.getTempVec3(x, y, z);
+        return Vec3.fromPool(x, y, z);
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherStorm.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherStorm.java
index 6c8784f47..6121096ba 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherStorm.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherStorm.java
@@ -66,7 +66,7 @@ public class WeatherStorm extends WeatherRain {
         weight += checkY;
         weight += material.getConductivity();
 
-        final @NotNull List<@NotNull Mob> entityList = world.getEntitiesWithinAABB(Mob.class, AABB.getTemporaryBB(checkX, checkY, checkZ, checkX + 1, checkY + 1, checkZ + 1));
+        final @NotNull List<@NotNull Mob> entityList = world.getEntitiesWithinAABB(Mob.class, AABB.fromPool(checkX, checkY, checkZ, checkX + 1, checkY + 1, checkZ + 1));
         if (!entityList.isEmpty()) {
             weight += 4; // :)
         }
diff --git a/game/core/src/main/resources/lang/en_US/gui.lang b/game/core/src/main/resources/lang/en_US/gui.lang
index 8b02d1c14..5991b3a2c 100644
--- a/game/core/src/main/resources/lang/en_US/gui.lang
+++ b/game/core/src/main/resources/lang/en_US/gui.lang
@@ -172,8 +172,9 @@ gui.main_menu.label.splash.halloween=Happy Halloween!
 gui.main_menu.label.splash.new_year=Happy New Year!
 gui.main_menu.label.disclaimer.1=Copyright Mojang Studios. Not an official Minecraft product.
 gui.main_menu.label.disclaimer.2=Not approved by or associated with Mojang Studios or Microsoft.
-gui.main_menu.label.downloading_resources.1=Downloading resources: %s / %s
+gui.main_menu.label.downloading_resources.1=Downloading resources
 gui.main_menu.label.downloading_resources.2=Sounds may not play during this process!
+gui.main_menu.label.downloading_resources.connection.error=Could not download sounds!
 gui.main_menu.button.singleplayer=Singleplayer
 gui.main_menu.button.multiplayer=Multiplayer
 gui.main_menu.button.multiplayer.disabled=Multiplayer (not ready yet!)
@@ -260,6 +261,7 @@ gui.options.page.debug.button.open.datadumper=Run Data Dumper
 gui.options.page.debug.button.open.sound_test=Open Sound Test
 gui.options.page.debug.button.open.texture_viewer=Open Texture Viewer
 gui.options.page.debug.button.open.font_tester=Open Font Test
+gui.options.page.debug.button.open.nbt_tester=NBT Editor Test
 gui.options.page.debug.button.open.achievements=Open Achievements
 gui.options.page.debug.button.wipestats=Delete Stats
 gui.options.page.debug.button.unlockedall=Unlock all stats
diff --git a/game/core/src/main/resources/lang/en_US/item.lang b/game/core/src/main/resources/lang/en_US/item.lang
index 42ce591a0..34869c379 100644
--- a/game/core/src/main/resources/lang/en_US/item.lang
+++ b/game/core/src/main/resources/lang/en_US/item.lang
@@ -460,6 +460,8 @@ item.rope.desc=Strong enough to climb.
 
 item.wand.monster.name=Summoning Wand
 item.wand.monster.desc=A magical tool allowing the wielder to manifest living entities.
+item.wand.nbt.name=NBT Wand
+item.wand.nbt.desc=A magical tool allowing the wielder to modify an object's data.
 
 item.paintbrush.name=Paintbrush
 item.paintbrush.desc=Can be loaded with dye and used to paint blocks.
diff --git a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
index cf4398576..9ec8e158f 100644
--- a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -55,6 +55,7 @@ import net.minecraft.core.net.command.commands.CommandTestFor;
 import net.minecraft.core.net.command.commands.CommandTime;
 import net.minecraft.core.net.command.commands.CommandWeather;
 import net.minecraft.core.net.command.util.CommandHelper;
+import net.minecraft.core.util.pool.ObjectPool;
 import net.minecraft.core.util.helper.UUIDHelper;
 import net.minecraft.server.entity.player.PlayerServer;
 import net.minecraft.server.net.command.ConsoleCommandSource;
@@ -63,8 +64,6 @@ import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.sound.SoundTypes;
 import net.minecraft.core.util.helper.RSA;
 import net.minecraft.core.util.helper.RestHandler;
-import net.minecraft.core.util.phys.AABB;
-import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.provider.BiomeProviderOverworld;
@@ -118,9 +117,7 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Random;
 
 import static net.minecraft.core.Global.CURRENT_SAVE_VERSION;
@@ -733,8 +730,7 @@ public class MinecraftServer
 
     private void doTick()
     {
-        AABB.initializePool();
-        Vec3.initializePool();
+        ObjectPool.resetAllPools();
         deathTime++;
         for (WorldServer worldServer : dimensionWorlds.values())
         {
diff --git a/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java b/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java
index 92053153e..2f3b13fad 100644
--- a/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java
+++ b/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java
@@ -74,7 +74,7 @@ public class ServerCommandSource implements CommandSource, IServerCommandSource
     @Override
     public @NotNull Vec3 getBlockCoordinates() {
         Vec3 coordinates = this.getCoordinates(true);
-        return Vec3.getTempVec3(MathHelper.floor(coordinates.x), MathHelper.floor(coordinates.y), MathHelper.floor(coordinates.z));
+        return Vec3.fromPool(MathHelper.floor(coordinates.x), MathHelper.floor(coordinates.y), MathHelper.floor(coordinates.z));
     }
 
     @Override
diff --git a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java
index 7f5267794..d5bdbf90f 100644
--- a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java
+++ b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java
@@ -648,7 +648,7 @@ public class PacketHandlerServer extends PacketHandler
                 float f3 = -MathHelper.cos(-playerEntity.xRot * 0.01745329F);
                 float f4 = MathHelper.sin(-playerEntity.xRot * 0.01745329F);
 
-                Vec3 viewVector = Vec3.getTempVec3(f2 * f3, f4, f1 * f3);
+                Vec3 viewVector = Vec3.fromPool(f2 * f3, f4, f1 * f3);
 
                 viewVector.x *= 8;
                 viewVector.y *= 8;
@@ -657,7 +657,7 @@ public class PacketHandlerServer extends PacketHandler
                 viewVector.y += playerEntity.y;
                 viewVector.z += playerEntity.z;
 
-                Vec3 playerViewPos = Vec3.getTempVec3(playerEntity.x, playerEntity.y + playerEntity.getHeadHeight(), playerEntity.z);
+                Vec3 playerViewPos = Vec3.fromPool(playerEntity.x, playerEntity.y + playerEntity.getHeadHeight(), playerEntity.z);
 
                 HitResult movingObjectPosition = targetEntity.bb.clip(playerViewPos, viewVector);
 
diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/TestChunkProvider.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/TestChunkProvider.java
index 0c6416598..266f41298 100644
--- a/util/seed-viewer/src/main/java/org/useless/seedviewer/TestChunkProvider.java
+++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/TestChunkProvider.java
@@ -22,7 +22,7 @@ public class TestChunkProvider implements ChunkProvider {
 
                     @Override
                     public NamespaceID getID() {
-                        return NamespaceID.getPermanent("viewer", "test");
+                        return NamespaceID.fromPool("viewer", "test");
                     }
 
                     @Override
diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTABiome.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTABiome.java
index 38dadc049..e807a1b2a 100644
--- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTABiome.java
+++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTABiome.java
@@ -20,7 +20,7 @@ public class BTABiome implements Biome {
     @Override
     public NamespaceID getID() {
         try {
-            return NamespaceID.getPermanent(Registries.BIOMES.getKey(biome));
+            return NamespaceID.fromPool(Registries.BIOMES.getKey(biome)).copyUnpooled();
         } catch (HardIllegalArgumentException e) {
             throw new IllegalArgumentException(e);
         }
diff --git a/util/seed-viewer/src/test/java/collections/NamespaceTest.java b/util/seed-viewer/src/test/java/collections/NamespaceTest.java
index 29f271278..95c71a96c 100644
--- a/util/seed-viewer/src/test/java/collections/NamespaceTest.java
+++ b/util/seed-viewer/src/test/java/collections/NamespaceTest.java
@@ -11,12 +11,12 @@ public class NamespaceTest {
     @DisplayName("Test Namespace 2String Constructor")
     void namespaceCreation1() {
         // Valid creation
-        NamespaceID namespaceID_1 = NamespaceID.getPermanent("minecraft", "value1");
+        NamespaceID namespaceID_1 = NamespaceID.fromPool("minecraft", "value1");
         Assertions.assertEquals(namespaceID_1.namespace(), "minecraft");
         Assertions.assertEquals(namespaceID_1.value(), "value1");
         Assertions.assertEquals(namespaceID_1.toString(), "minecraft:value1");
 
-        NamespaceID namespaceID_2 = NamespaceID.getPermanent("minecraft", "value1");
+        NamespaceID namespaceID_2 = NamespaceID.fromPool("minecraft", "value1");
         Assertions.assertEquals(namespaceID_2.namespace(), "minecraft");
         Assertions.assertEquals(namespaceID_2.value(), "value1");
         Assertions.assertEquals(namespaceID_2.toString(), "minecraft:value1");
@@ -26,7 +26,7 @@ public class NamespaceTest {
         Assertions.assertEquals(namespaceID_1, namespaceID_2);
         Assertions.assertEquals(namespaceID_1.toString(), namespaceID_2.toString());
 
-        NamespaceID namespaceID_3 = NamespaceID.getPermanent("bta", "value2");
+        NamespaceID namespaceID_3 = NamespaceID.fromPool("bta", "value2");
         Assertions.assertEquals(namespaceID_3.namespace(), "bta");
         Assertions.assertEquals(namespaceID_3.value(), "value2");
         Assertions.assertEquals(namespaceID_3.toString(), "bta:value2");
@@ -46,26 +46,26 @@ public class NamespaceTest {
         Assertions.assertNotEquals(namespaceID_3.toString(), namespaceID_2.toString());
 
         // Invalid creation
-        Assertions.assertThrowsExactly(NullPointerException.class, () -> NamespaceID.getPermanent(null, null));
-        Assertions.assertThrowsExactly(NullPointerException.class, () -> NamespaceID.getPermanent("minecraft", null));
-        Assertions.assertThrowsExactly(NullPointerException.class, () -> NamespaceID.getPermanent(null, "value1"));
+        Assertions.assertThrowsExactly(NullPointerException.class, () -> NamespaceID.fromPool(null, null));
+        Assertions.assertThrowsExactly(NullPointerException.class, () -> NamespaceID.fromPool("minecraft", null));
+        Assertions.assertThrowsExactly(NullPointerException.class, () -> NamespaceID.fromPool(null, "value1"));
 
-        Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> NamespaceID.getPermanent("minecraft:", "value1"));
-        Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> NamespaceID.getPermanent("minecraft", "value1:"));
-        Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> NamespaceID.getPermanent("minecraft:", "value1:"));
+        Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> NamespaceID.fromPool("minecraft:", "value1"));
+        Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> NamespaceID.fromPool("minecraft", "value1:"));
+        Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> NamespaceID.fromPool("minecraft:", "value1:"));
     }
 
     @Test
     @DisplayName("Test Namespace 1String Constructor")
     void namespaceCreation2() throws HardIllegalArgumentException {
         String formatted_1 = "minecraft:value1";
-        NamespaceID namespaceID_1 = NamespaceID.getPermanent(formatted_1);
+        NamespaceID namespaceID_1 = NamespaceID.fromPool(formatted_1);
         Assertions.assertEquals(namespaceID_1.namespace(), "minecraft");
         Assertions.assertEquals(namespaceID_1.value(), "value1");
         Assertions.assertEquals(namespaceID_1.toString(), formatted_1);
         Assertions.assertEquals(namespaceID_1.namespace() + ":" + namespaceID_1.value(), formatted_1);
 
-        NamespaceID namespaceID_2 = NamespaceID.getPermanent(formatted_1);
+        NamespaceID namespaceID_2 = NamespaceID.fromPool(formatted_1);
         Assertions.assertEquals(namespaceID_2.namespace(), "minecraft");
         Assertions.assertEquals(namespaceID_2.value(), "value1");
         Assertions.assertEquals(namespaceID_2.toString(), formatted_1);
@@ -76,12 +76,12 @@ public class NamespaceTest {
         Assertions.assertEquals(namespaceID_1, namespaceID_2);
         Assertions.assertEquals(namespaceID_1.toString(), namespaceID_2.toString());
 
-        Assertions.assertThrowsExactly(NullPointerException.class, () -> NamespaceID.getPermanent(null));
-        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.getPermanent("minecraft::value1"));
-        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.getPermanent("minecraft:value1:"));
-        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.getPermanent(":value1"));
-        Assertions.assertDoesNotThrow(() -> NamespaceID.getPermanent("minecraft:value"));
-        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.getPermanent("minecraft value"));
-        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.getPermanent("minecraft|value"));
+        Assertions.assertThrowsExactly(NullPointerException.class, () -> NamespaceID.fromPool(null));
+        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.fromPool("minecraft::value1"));
+        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.fromPool("minecraft:value1:"));
+        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.fromPool(":value1"));
+        Assertions.assertDoesNotThrow(() -> NamespaceID.fromPool("minecraft:value"));
+        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.fromPool("minecraft value"));
+        Assertions.assertThrowsExactly(HardIllegalArgumentException.class, () -> NamespaceID.fromPool("minecraft|value"));
     }
 }
