diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHealthBar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHealthBar.java
index 8eb71cb96..1009b1b4d 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHealthBar.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentHealthBar.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.gui.hud.component;
 
-import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.Gui;
 import net.minecraft.client.gui.hud.HudIngame;
 import net.minecraft.client.gui.hud.component.layout.Layout;
@@ -8,7 +7,6 @@ import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicEdible;
 import net.minecraft.core.item.Item;
-import net.minecraft.core.item.ItemBucketIceCream;
 import net.minecraft.core.item.ItemFood;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.player.gamemode.Gamemode;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentVehicleHealthBar.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentVehicleHealthBar.java
new file mode 100644
index 000000000..049f2df6f
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentVehicleHealthBar.java
@@ -0,0 +1,112 @@
+package net.minecraft.client.gui.hud.component;
+
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.hud.HudIngame;
+import net.minecraft.client.gui.hud.component.layout.Layout;
+import net.minecraft.client.render.texture.stitcher.TextureRegistry;
+import net.minecraft.core.entity.Mob;
+import net.minecraft.core.util.helper.MathHelper;
+import org.lwjgl.opengl.GL11;
+
+import java.util.Random;
+
+public class HudComponentVehicleHealthBar
+    extends HudComponentMovable {
+    private final Random random = new Random();
+
+    public HudComponentVehicleHealthBar(String key, Layout layout) {
+        super(key, 81, 10, layout);
+    }
+
+    @Override
+    public boolean isVisible() {
+        return mc.thePlayer.vehicle instanceof Mob && mc.gameSettings.immersiveMode.drawHotbar();
+    }
+
+    @Override
+    public void render(HudIngame hud, int xSizeScreen, int ySizeScreen, float partialTick) {
+        if (mc.thePlayer.vehicle instanceof Mob mobVehicle) {
+            int x = this.getLayout().getComponentX(this, xSizeScreen);
+            int y = this.getLayout().getComponentY(this, ySizeScreen);
+
+            // Setup rendering
+            GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Reset color
+            GL11.glDisable(GL11.GL_BLEND);
+
+            boolean heartsFlash = (mobVehicle.heartsFlashTime / 3) % 2 == 1;
+            if (mobVehicle.heartsFlashTime < 10)
+            {
+                heartsFlash = false;
+            }
+            int health = mobVehicle.getHealth();
+            int prevHealth = mobVehicle.prevHealth;
+            random.setSeed(hud.updateCounter * 0x4c627L);
+
+            int hearts = MathHelper.ceil(mobVehicle.getMaxHealth()/2f);
+            for (int i = 0; i < hearts; i++) {
+                int heartOffset = 0;
+                if (heartsFlash)
+                {
+                    heartOffset = 1;
+                }
+                int xHeart = (x + 9 * 8) - i * 8;
+                int yHeart = y;
+                if (health <= 4)
+                {
+                    yHeart += random.nextInt(2);
+                }
+
+                hud.drawGuiIcon(xHeart, yHeart, 9, 9, heartOffset == 0 ? TextureRegistry.getTexture("minecraft:gui/hud/heart/pig/container") : TextureRegistry.getTexture("minecraft:gui/hud/heart/pig/container_blinking"));
+                if (heartsFlash)
+                {
+                    if (i * 2 + 1 < prevHealth)
+                    {
+                        // Half flash heart icon
+                        hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/pig/full_blinking"));
+                    }
+                    if (i * 2 + 1 == prevHealth)
+                    {
+                        // Full flash heart icon
+                        hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/pig/half_blinking"));
+                    }
+                }
+                if (i * 2 + 1 < health)
+                {
+                    // Full heart icon
+                    hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/pig/full"));
+                }
+                if (i * 2 + 1 == health)
+                {
+                    // Half heart icon
+                    hud.drawGuiIcon(xHeart, yHeart, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/pig/half"));
+                }
+            }
+        }
+    }
+
+    @Override
+    public void renderPreview(Gui gui, Layout layout, int xSizeScreen, int ySizeScreen) {
+        int x = layout.getComponentX(this, xSizeScreen);
+        int y = layout.getComponentY(this, ySizeScreen);
+
+        // Setup rendering
+        GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Reset color
+        GL11.glDisable(GL11.GL_BLEND);
+
+        int health = 11;
+        for (int i = 0; i < 10; i++) {
+            int xHeart = x + i * 8;
+            gui.drawGuiIcon(xHeart, y, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/pig/container"));
+            if (i * 2 + 1 < health)
+            {
+                // Full heart icon
+                gui.drawGuiIcon(xHeart, y, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/pig/full"));
+            }
+            if (i * 2 + 1 == health)
+            {
+                // Half heart icon
+                gui.drawGuiIcon(xHeart, y, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/pig/half"));
+            }
+        }
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java
index 8dc127e0c..50cd463ff 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java
@@ -61,7 +61,8 @@ public class HudComponents {
     public static final HudComponent HOTBAR = register(new HudComponentHotbar("hotbar", new LayoutAbsolute(0.5f, 1.0f, ComponentAnchor.BOTTOM_CENTER)));
     public static final HudComponent CROSSHAIR = register(new HudComponentCrosshair("crosshair", new LayoutAbsolute(0.5f, 0.5f, ComponentAnchor.CENTER)));
     public static final HudComponent HEALTH_BAR = register(new HudComponentHealthBar("health_bar", new LayoutSnap(HOTBAR, ComponentAnchor.TOP_LEFT, ComponentAnchor.BOTTOM_LEFT)));
-    public static final HudComponent ARMOR_BAR = register(new HudComponentArmorBar("armor_bar", new LayoutSnap(HOTBAR, ComponentAnchor.TOP_RIGHT, ComponentAnchor.BOTTOM_RIGHT)));
+//    public static final HudComponent ARMOR_BAR = register(new HudComponentArmorBar("armor_bar", new LayoutSnap(HOTBAR, ComponentAnchor.TOP_RIGHT, ComponentAnchor.BOTTOM_RIGHT)));
+    public static final HudComponent VEHICLE_BAR = register(new HudComponentVehicleHealthBar("vehicle_bar", new LayoutSnap(HOTBAR, ComponentAnchor.TOP_RIGHT, ComponentAnchor.BOTTOM_RIGHT)));
     public static final HudComponent OXYGEN_BAR = register(new HudComponentOxygenBar("oxygen_bar", new LayoutSnap(HEALTH_BAR, ComponentAnchor.TOP_LEFT, ComponentAnchor.BOTTOM_LEFT)));
     public static final HudComponent FIRE_BAR = register(new HudComponentFireBar("fire_bar", new LayoutSnap(OXYGEN_BAR, ComponentAnchor.TOP_LEFT, ComponentAnchor.BOTTOM_LEFT)));
     public static final HudComponent ROTATION_LOCK = register(new HudComponentRotationLock("rotation_lock", new LayoutSnap(CROSSHAIR, ComponentAnchor.CENTER_RIGHT, ComponentAnchor.CENTER_LEFT)));
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/FloatOptionComponent.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/FloatOptionComponent.java
index 3b0599380..085adda56 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/FloatOptionComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/FloatOptionComponent.java
@@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.SliderElement;
 import net.minecraft.client.option.OptionFloat;
 import net.minecraft.client.render.window.CursorShape;
+import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.Nullable;
 
 public class FloatOptionComponent
@@ -11,32 +12,47 @@ public class FloatOptionComponent
 {
     protected final OptionFloat option;
     protected final SliderElement slider;
+    protected final float minValue;
+    protected final float maxValue;
 
     public FloatOptionComponent(OptionFloat option)
     {
-        this(option, null);
+        this(option, 0, 1, null);
+    }
+
+    public FloatOptionComponent(OptionFloat option, float minValue, float maxValue)
+    {
+        this(option, minValue, maxValue, null);
     }
 
     public FloatOptionComponent(OptionFloat option, @Nullable String tooltipTranslationKey)
+    {
+        this(option, 0, 1, tooltipTranslationKey);
+    }
+
+    public FloatOptionComponent(OptionFloat option, float minValue, float maxValue, @Nullable String tooltipTranslationKey)
     {
         super("options." + option.name, tooltipTranslationKey);
 
         this.option = option;
         this.option.addCallback(__ -> onChanged());
         this.slider = new SliderElement(0, 0, 0, 150, 20, this.option.getDisplayStringValue(), this.option.value);
+
+        this.minValue = minValue;
+        this.maxValue = maxValue;
     }
 
     @Override
     protected void buttonClicked(int mouseButton, int x, int y, int width, int height, int relativeMouseX, int relativeMouseY) {
         this.slider.mouseClicked(mc, this.slider.xPosition + relativeMouseX, this.slider.yPosition + relativeMouseY);
-        this.option.set((float) this.slider.sliderValue);
+        this.option.set((float) MathHelper.lerp(minValue, maxValue, this.slider.sliderValue));
         onChanged();
         this.option.onUpdate();
     }
 
     @Override
     protected void buttonDragged(int x, int y, int width, int height, int relativeMouseX, int relativeMouseY) {
-        this.option.set((float) this.slider.sliderValue);
+        this.option.set((float) MathHelper.lerp(minValue, maxValue, this.slider.sliderValue));
         this.slider.mouseDragged(mc, this.slider.xPosition + relativeMouseX, this.slider.yPosition + relativeMouseY);
         onChanged();
         this.option.onUpdate();
@@ -45,7 +61,7 @@ public class FloatOptionComponent
     @Override
     protected void buttonReleased(int mouseButton, int x, int y, int width, int height, int relativeMouseX, int relativeMouseY) {
         this.slider.mouseReleased(this.slider.xPosition + relativeMouseX, this.slider.yPosition + relativeMouseY);
-        this.option.set((float) this.slider.sliderValue);
+        this.option.set((float) MathHelper.lerp(minValue, maxValue, this.slider.sliderValue));
         onChanged();
         this.option.onUpdate();
     }
@@ -70,14 +86,14 @@ public class FloatOptionComponent
     @Override
     public void resetValue() {
         option.set(option.getDefaultValue());
-        slider.sliderValue = option.value;
+        slider.sliderValue = MathHelper.unlerp(minValue, maxValue, option.value);
         onChanged();
         option.onUpdate();
     }
 
     @Override
     public void init(Minecraft mc){
-        slider.sliderValue = option.value;
+        slider.sliderValue = MathHelper.unlerp(minValue, maxValue, option.value);
         onChanged();
     }
 
@@ -87,6 +103,7 @@ public class FloatOptionComponent
 
     @Override
     public boolean isDefault() {
-        return option.value.equals(option.getDefaultValue());
+        float diff = Math.abs(option.value - option.getDefaultValue());
+        return diff < 0.0001f;
     }
 }
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 5ada75d6f..1e020bf29 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
@@ -175,7 +175,7 @@ public abstract class OptionsPages
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.vignette))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.items3D))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.clouds))
-                .withComponent(new FloatOptionComponent(mc.gameSettings.cloudHeight))
+                .withComponent(new FloatOptionComponent(mc.gameSettings.cloudHeight, -0.5f, 1f))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.aurora))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.slimeParticles))
                 .withComponent(new FloatOptionComponent(mc.gameSettings.blockOutlineWidth))
diff --git a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java
index 67d096a7a..3b118fc33 100644
--- a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java
@@ -10,6 +10,7 @@ import net.minecraft.client.render.window.CursorShape;
 import net.minecraft.client.render.worldtype.WorldTypeFXDispatcher;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.entity.Mob;
+import net.minecraft.core.entity.animal.MobPig;
 import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.weather.IPrecipitation;
 import org.jetbrains.annotations.NotNull;
@@ -245,7 +246,7 @@ public class WorldRenderer
         }
     }
 
-    private void setupViewBobbing(float partialTick)
+    private void setupViewBobbing(float partialTick, boolean isHand)
     {
         if (mc.activeCamera instanceof EntityCamera && ((EntityCamera) mc.activeCamera).mob instanceof Player)
         {
@@ -253,6 +254,11 @@ public class WorldRenderer
             float walkDist = -MathHelper.lerp(player.walkDistO, player.walkDist, partialTick);
             float cameraVel = MathHelper.lerp(player.cameraVelocityOld, player.cameraVelocity, partialTick);
             float cameraPitch = MathHelper.lerp(player.prevCameraPitch, player.cameraPitch, partialTick);
+            if (isHand && player.vehicle instanceof MobPig) {
+                cameraVel /= 4;
+//                cameraPitch /= 4;
+                walkDist /= 2;
+            }
             if (player.isSkating) {
                 walkDist *= 0.25f;
                 cameraPitch *= 0.25f;
@@ -343,7 +349,7 @@ public class WorldRenderer
         hurtCameraEffect(partialTicks);
         if(this.mc.gameSettings.viewBobbing.value && !(this.mc.currentScreen instanceof ScreenPhotoMode))
         {
-            setupViewBobbing(partialTicks);
+            setupViewBobbing(partialTicks, false);
         }
         final float portalIntensity = this.mc.gameSettings.screenMotionEffects.value ? MathHelper.lerp(this.mc.thePlayer.prevTimeInPortal, this.mc.thePlayer.timeInPortal, partialTicks) : 0f;
         if(portalIntensity > 0.0F)
@@ -379,7 +385,7 @@ public class WorldRenderer
         hurtCameraEffect(partialTick);
         if(mc.gameSettings.viewBobbing.value)
         {
-            setupViewBobbing(partialTick);
+            setupViewBobbing(partialTick, true);
         }
         if(mc.gameSettings.thirdPersonView.value == 0 && !(mc.currentScreen instanceof ScreenPhotoMode) && !(!(mc.activeCamera instanceof EntityCamera) || ((EntityCamera) mc.activeCamera).mob.isPlayerSleeping()) && mc.gameSettings.immersiveMode.drawHand())
         {
@@ -399,7 +405,7 @@ public class WorldRenderer
         }
         if(mc.gameSettings.viewBobbing.value)
         {
-            setupViewBobbing(partialTick);
+            setupViewBobbing(partialTick, false);
         }
     }
     private float getZoomedFOV(float currentFov, float partialTick){
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 1b491f4a0..3f3239bd4 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
@@ -166,7 +166,7 @@ public class WorldClient extends World {
     }
 
     @Override
-    public int getLightmapCoord(int skylight, int blocklight) {
-        return LightmapHelper.getLightmapCoord(skylight, blocklight);
+    public int getLightmapCoord(int skyLight, int blockLight) {
+        return LightmapHelper.getLightmapCoord(skyLight, blockLight);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/world/WorldClientMP.java b/game/client/src/main/java/net/minecraft/client/world/WorldClientMP.java
index 982700b31..82b9e4d56 100644
--- a/game/client/src/main/java/net/minecraft/client/world/WorldClientMP.java
+++ b/game/client/src/main/java/net/minecraft/client/world/WorldClientMP.java
@@ -12,6 +12,8 @@ import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.chunk.ChunkCoordinates;
 import net.minecraft.core.world.chunk.provider.IChunkProvider;
 import net.minecraft.client.world.save.SaveHandlerClientMP;
+import net.minecraft.core.world.pos.TilePos;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -106,8 +108,8 @@ public class WorldClientMP extends WorldClient {
     }
 
     @Override
-	public void scheduleBlockUpdate(int x, int y, int z, int id, long delay)
-    {
+    public void scheduleBlockUpdate(final @NotNull TilePos tilePos, final int id, final long delay, final boolean loaded) {
+        // Do nothing
     }
 
     @Override
@@ -201,46 +203,37 @@ public class WorldClientMP extends WorldClient {
     }
 
     @Override
-	public boolean setBlockMetadata(int x, int y, int z, int meta)
-    {
-        int blockID = getBlockId(x, y, z);
-        int currentMeta = getBlockMetadata(x, y, z);
-        if(super.setBlockMetadata(x, y, z, meta))
-        {
-            positionTypesList.add(new WorldBlockPositionType(x, y, z, blockID, currentMeta));
+    public boolean setBlockData(final @NotNull TilePos tilePos, final int data) {
+        final int id = this.getBlockId(tilePos);
+        final int currentData = this.getBlockData(tilePos);
+        if (super.setBlockData(tilePos, data)) {
+            this.positionTypesList.add(new WorldBlockPositionType(tilePos.x, tilePos.y, tilePos.z, id, currentData));
             return true;
-        } else
-        {
+        } else {
             return false;
         }
     }
 
     @Override
-	public boolean setBlockAndMetadata(int x, int y, int z, int id, int meta)
-    {
-        int blockId = getBlockId(x, y, z);
-        int blockMeta = getBlockMetadata(x, y, z);
-        if(super.setBlockAndMetadata(x, y, z, id, meta))
-        {
-            positionTypesList.add(new WorldBlockPositionType(x, y, z, blockId, blockMeta));
+    public boolean setBlockIdData(final @NotNull TilePos tilePos, final int id, final int data) {
+        final int currentId = this.getBlockId(tilePos);
+        final int currentData = this.getBlockData(tilePos);
+        if (super.setBlockIdData(tilePos, id, data)) {
+            this.positionTypesList.add(new WorldBlockPositionType(tilePos.x, tilePos.y, tilePos.z, currentId, currentData));
             return true;
-        } else
-        {
+        } else {
             return false;
         }
     }
 
     @Override
-	public boolean setBlock(int x, int y, int z, int id)
-    {
-        int blockId = getBlockId(x, y, z);
-        int meta = getBlockMetadata(x, y, z);
-        if(super.setBlock(x, y, z, id))
-        {
-            positionTypesList.add(new WorldBlockPositionType(x, y, z, blockId, meta));
+    public boolean setBlockId(final @NotNull TilePos tilePos, final int id) {
+        final int currentId = this.getBlockId(tilePos);
+        final int data = this.getBlockData(tilePos);
+        if (super.setBlockId(tilePos, id)) {
+            this.positionTypesList.add(new WorldBlockPositionType(tilePos.x, tilePos.y, tilePos.z, currentId, data));
             return true;
-        } else
-        {
+        } else {
             return false;
         }
     }
diff --git a/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderDynamic.java b/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderDynamic.java
index 46cfe5563..840a5abe3 100644
--- a/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderDynamic.java
+++ b/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderDynamic.java
@@ -224,7 +224,7 @@ public class ChunkProviderDynamic implements IChunkProvider
         }
         catch(IOException ioexception)
         {
-            LOGGER.error("Failed to save chunk at {}, {}!", chunk.xPosition, chunk.zPosition, ioexception);
+            LOGGER.error("Failed to save chunk at {}, {}!", chunk.pos.x, chunk.pos.z, ioexception);
         }
     }
 
@@ -252,7 +252,7 @@ public class ChunkProviderDynamic implements IChunkProvider
         int dropped = 0;
         for (Chunk chunk : chunkMap.values()) {
             if(dropped >= maxUnloadPerTick) break;
-            isChunkLoaded(chunk.xPosition,chunk.zPosition); //droppedChunksSet gets updated as side-effect
+            isChunkLoaded(chunk.pos.x, chunk.pos.z); //droppedChunksSet gets updated as side-effect
         }
         if(!droppedChunksSet.isEmpty()){
             int unloaded = 0;
diff --git a/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderStatic.java b/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderStatic.java
index 8f93b4bd1..6d23651e8 100644
--- a/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderStatic.java
+++ b/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderStatic.java
@@ -219,7 +219,7 @@ public class ChunkProviderStatic
         }
         catch(IOException e)
         {
-            LOGGER.error("Error saving chunk at X:{}, Z:{}", chunk.xPosition, chunk.zPosition, e);
+            LOGGER.error("Error saving chunk at X:{}, Z:{}", chunk.pos.x, chunk.pos.x, e);
         }
     }
 
diff --git a/game/client/src/main/resources/assets/minecraft/models/entity/secret.geo.json b/game/client/src/main/resources/assets/minecraft/models/entity/secret.geo.json
index 77e0cde5c..28b10f977 100644
--- a/game/client/src/main/resources/assets/minecraft/models/entity/secret.geo.json
+++ b/game/client/src/main/resources/assets/minecraft/models/entity/secret.geo.json
@@ -8,7 +8,7 @@
 				"texture_height": 64,
 				"visible_bounds_width": 3,
 				"visible_bounds_height": 4,
-				"visible_bounds_offset": [0, 2, 0]
+				"visible_bounds_offset": [0, 1, 0]
 			},
 			"bones": [
 				{
@@ -25,60 +25,146 @@
 					"parent": "body",
 					"pivot": [0, 24, 0],
 					"cubes": [
-						{"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]}
+						{
+							"origin": [-2.5, 17, -3],
+							"size": [5, 3.5, 2],
+							"pivot": [0, 18.25, -0.25],
+							"rotation": [-10, 0, 0],
+							"uv": {
+								"north": {"uv": [12, 16.25], "uv_size": [5, 3.5]},
+								"east": {"uv": [12, 16.25], "uv_size": [1, 3.5]},
+								"west": {"uv": [16, 16.25], "uv_size": [1, 3.5]},
+								"up": {"uv": [16, 16], "uv_size": [1, 3.75], "uv_rotation": 90},
+								"down": {"uv": [17, 16.25], "uv_size": [-1, 3.5], "uv_rotation": 90}
+							}
+						},
+						{
+							"origin": [-3, 15.75, -2],
+							"size": [6, 5, 4],
+							"pivot": [0, 18, 0],
+							"rotation": [-17.5, 0, 0],
+							"uv": {
+								"north": {"uv": [57, 33], "uv_size": [6, 5]},
+								"east": {"uv": [54, 16], "uv_size": [4, 5]},
+								"south": {"uv": [57, 33], "uv_size": [6, 5]},
+								"west": {"uv": [54, 16], "uv_size": [4, 5]},
+								"up": {"uv": [21, 17], "uv_size": [6, 4]},
+								"down": {"uv": [57, 41], "uv_size": [6, -4], "uv_rotation": 180}
+							}
+						},
+						{
+							"origin": [-3.5, 10, -2],
+							"size": [7, 4, 4],
+							"pivot": [0.25, 12, 0],
+							"rotation": [7.5, 0, 0],
+							"uv": {
+								"north": {"uv": [12, 32], "uv_size": [7, 4]},
+								"east": {"uv": [0, 32], "uv_size": [4, 4]},
+								"south": {"uv": [37, 16], "uv_size": [7, 4]},
+								"west": {"uv": [4, 32], "uv_size": [-4, 4]},
+								"up": {"uv": [36, 32], "uv_size": [7, 4]},
+								"down": {"uv": [36, 36], "uv_size": [7, -4]}
+							}
+						},
+						{
+							"origin": [-1.5, 13, -1.5],
+							"size": [3, 4, 2.25],
+							"uv": {
+								"north": {"uv": [26, 2], "uv_size": [3, 4]},
+								"east": {"uv": [24, 2], "uv_size": [2, 4]},
+								"south": {"uv": [27, 3], "uv_size": [3, 4]},
+								"west": {"uv": [29, 2], "uv_size": [2, 4]},
+								"up": {"uv": [26, 0], "uv_size": [3, 2]},
+								"down": {"uv": [29, 2], "uv_size": [3, -2]}
+							}
+						},
+						{"origin": [-1, 20, -1], "size": [2, 3, 2.25], "pivot": [0.5, 18, -0.5], "rotation": [-10, 0, 0], "uv": [24, 1]}
 					]
 				},
 				{
 					"name": "jacket",
 					"parent": "torso",
-					"pivot": [0, 18, 0],
-					"cubes": [
-						{"origin": [-4, 12, -2], "size": [8, 12, 4], "inflate": 0.25, "uv": [16, 32]}
-					]
+					"pivot": [0, 18, 0]
 				},
 				{
-					"name": "rightArm",
+					"name": "leftArm",
 					"parent": "torso",
-					"pivot": [-5, 22, 0],
+					"pivot": [3.5, 20, 0],
 					"cubes": [
-						{"origin": [-7, 12, -2], "size": [3, 12, 4], "uv": [40, 16]}
-					]
-				},
-				{
-					"name": "rightSleeve",
-					"parent": "rightArm",
-					"pivot": [-6, 18, 0],
-					"cubes": [
-						{"origin": [-7, 12, -2], "size": [3, 12, 4], "inflate": 0.25, "uv": [40, 32]}
+						{
+							"origin": [-5.25, 15, -0.25],
+							"size": [2, 5.25, 2.75],
+							"pivot": [0.75, -2.75, 0.75],
+							"rotation": [-180, 0, 175],
+							"uv": {
+								"north": {"uv": [32, 53], "uv_size": [3, 5]},
+								"east": {"uv": [39, 55], "uv_size": [2, 5]},
+								"south": {"uv": [36, 53], "uv_size": [2, 5]},
+								"west": {"uv": [43, 55], "uv_size": [2, 5]},
+								"up": {"uv": [37, 48], "uv_size": [2, 2]}
+							}
+						},
+						{
+							"origin": [3.38988, 9.68153, -0.5],
+							"size": [2.5, 6, 3.25],
+							"pivot": [4.6, 14.25, 0.75],
+							"rotation": [-180, 0, 170],
+							"uv": {
+								"north": {"uv": [59, 58], "uv_size": [2, 6]},
+								"east": {"uv": [56, 58], "uv_size": [3, 6]},
+								"south": {"uv": [52, 58], "uv_size": [2, 6]},
+								"west": {"uv": [48, 58], "uv_size": [3, 6]},
+								"up": {"uv": [53, 55], "uv_size": [2, 3]},
+								"down": {"uv": [56, 51], "uv_size": [2, -3]}
+							}
+						}
 					]
 				},
 				{
 					"name": "rightItem",
-					"parent": "rightArm",
+					"parent": "leftArm",
 					"pivot": [-5.5, 12, -2],
 					"rotation": [90, 0, 0]
 				},
 				{
-					"name": "leftArm",
+					"name": "rightArm",
 					"parent": "torso",
-					"pivot": [5, 22, 0],
+					"pivot": [-3.5, 20, 0],
 					"cubes": [
-						{"origin": [4, 12, -2], "size": [3, 12, 4], "uv": [32, 48]}
-					]
-				},
-				{
-					"name": "leftSleeve",
-					"parent": "leftArm",
-					"pivot": [5, 18, 0],
-					"cubes": [
-						{"origin": [4, 12, -2], "size": [3, 12, 4], "inflate": 0.25, "uv": [48, 48]}
+						{
+							"origin": [-6.75, 15, -1],
+							"size": [2, 5.25, 2.75],
+							"pivot": [-0.75, -2.75, 0],
+							"rotation": [0, 0, 5],
+							"uv": {
+								"north": {"uv": [45, 22], "uv_size": [2, 5]},
+								"east": {"uv": [42, 22], "uv_size": [2, 5]},
+								"south": {"uv": [51, 22], "uv_size": [2, 5]},
+								"west": {"uv": [48, 22], "uv_size": [2, 5]},
+								"up": {"uv": [48, 16], "uv_size": [2, 2]}
+							}
+						},
+						{
+							"origin": [-5.76012, 9.68153, -1.25],
+							"size": [2.5, 6, 3.25],
+							"pivot": [-4.55, 14.25, 0],
+							"rotation": [0, 0, 10],
+							"uv": {
+								"north": {"uv": [45, 41], "uv_size": [2, 6]},
+								"east": {"uv": [40, 41], "uv_size": [3, 6]},
+								"south": {"uv": [50, 41], "uv_size": [2, 6]},
+								"west": {"uv": [47, 41], "uv_size": [3, 6]},
+								"up": {"uv": [46, 25], "uv_size": [2, 3]},
+								"down": {"uv": [48, 35], "uv_size": [2, -3]}
+							}
+						}
 					]
 				},
 				{
-					"name": "leftItem",
-					"parent": "leftArm",
-					"pivot": [5.5, 12, -2],
-					"rotation": [-90, 180, 0]
+					"name": "leftitem",
+					"parent": "rightArm",
+					"pivot": [-5.5, 12, -2],
+					"rotation": [90, 0, 0]
 				},
 				{
 					"name": "cape",
@@ -91,91 +177,26 @@
 					"pivot": [0, 24, 0],
 					"cubes": [
 						{
-							"origin": [0, 26, -2],
-							"size": [9, 10, 4],
+							"origin": [-4, 22, -3],
+							"size": [8, 7, 5],
 							"uv": {
-								"north": {
-									"uv": [64, 16],
-									"uv_size": [-9, 10]
-								},
-								"south": {
-									"uv": [64, 30],
-									"uv_size": [-9, 10]
-								},
-								"west": {
-									"uv": [54, 26],
-									"uv_size": [10, 4],
-									"uv_rotation": 270
-								},
-								"up": {
-									"uv": [55, 26],
-									"uv_size": [9, 4],
-									"uv_rotation": 180
-								},
-								"down": {
-									"uv": [55, 30],
-									"uv_size": [9, -4],
-									"uv_rotation": 180
-								}
+								"north": {"uv": [8, 8], "uv_size": [8, 7]},
+								"east": {"uv": [3, 8], "uv_size": [5, 7]},
+								"south": {"uv": [24, 9], "uv_size": [8, 7]},
+								"west": {"uv": [16, 8], "uv_size": [5, 7]},
+								"up": {"uv": [8, 3], "uv_size": [8, 5]},
+								"down": {"uv": [16, 8], "uv_size": [8, -5]}
 							}
 						},
 						{
-							"origin": [-9, 26, -2],
-							"size": [9, 10, 4],
+							"origin": [-3.5, 22, 2],
+							"size": [7, 5, 2],
 							"uv": {
-								"north": {
-									"uv": [55, 16],
-									"uv_size": [9, 10]
-								},
-								"east": {
-									"uv": [54, 26],
-									"uv_size": [10, 4],
-									"uv_rotation": 90
-								},
-								"south": {
-									"uv": [55, 30],
-									"uv_size": [9, 10]
-								},
-								"up": {
-									"uv": [55, 26],
-									"uv_size": [9, 4],
-									"uv_rotation": 180
-								},
-								"down": {
-									"uv": [55, 30],
-									"uv_size": [9, -4],
-									"uv_rotation": 180
-								}
-							}
-						},
-						{
-							"origin": [-1, 23, -1],
-							"size": [2, 3, 2],
-							"uv": {
-								"north": {
-									"uv": [62, 42],
-									"uv_size": [2, 3]
-								},
-								"east": {
-									"uv": [62, 42],
-									"uv_size": [2, 3]
-								},
-								"south": {
-									"uv": [62, 42],
-									"uv_size": [2, 3]
-								},
-								"west": {
-									"uv": [62, 42],
-									"uv_size": [2, 3]
-								},
-								"up": {
-									"uv": [62, 40],
-									"uv_size": [2, 2]
-								},
-								"down": {
-									"uv": [62, 42],
-									"uv_size": [2, -2]
-								}
+								"east": {"uv": [6, 0], "uv_size": [2, 5]},
+								"south": {"uv": [0, 0], "uv_size": [7, 5]},
+								"west": {"uv": [6, 0], "uv_size": [2, 5]},
+								"up": {"uv": [8, 4], "uv_size": [7, 2]},
+								"down": {"uv": [0, 7], "uv_size": [7, -2]}
 							}
 						}
 					]
@@ -186,13 +207,12 @@
 					"pivot": [0, 28, 0],
 					"cubes": [
 						{
-							"origin": [-12, 33, 0],
-							"size": [8, 8, 0],
+							"origin": [3.8, 28.75, 0],
+							"size": [7, 5, 0],
+							"pivot": [7.3, 4.75, 1],
+							"rotation": [0, 0, -22.5],
 							"uv": {
-								"north": {
-									"uv": [56, 0],
-									"uv_size": [8, 8]
-								}
+								"north": {"uv": [33, 9], "uv_size": [7, 5]}
 							}
 						}
 					]
@@ -200,33 +220,39 @@
 				{
 					"name": "rightLeg",
 					"parent": "body",
-					"pivot": [-1.9, 12, 0],
+					"pivot": [-1.9, 11, 0],
 					"cubes": [
-						{"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 16]}
-					]
-				},
-				{
-					"name": "rightPant",
-					"parent": "rightLeg",
-					"pivot": [-2, 6, 0],
-					"cubes": [
-						{"origin": [-4, 0, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [0, 32]}
+						{"origin": [-3.4, 0.25, -2], "size": [3, 10.75, 3.5], "pivot": [-1.15, -1, -0.5], "rotation": [-2, 0, 0], "uv": [17, 50]},
+						{
+							"origin": [-3.65, 0, -2],
+							"size": [3.5, 7, 4],
+							"uv": {
+								"north": {"uv": [54, 21.25], "uv_size": [1, 6.75]},
+								"east": {"uv": [58, 21.25], "uv_size": [-4, 6.75]},
+								"south": {"uv": [57.25, 21.25], "uv_size": [3.5, 6.75]},
+								"west": {"uv": [54, 21.25], "uv_size": [4, 6.75]},
+								"down": {"uv": [8.25, 52], "uv_size": [3.5, -4]}
+							}
+						}
 					]
 				},
 				{
 					"name": "leftLeg",
 					"parent": "body",
-					"pivot": [1.9, 12, 0],
-					"cubes": [
-						{"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [16, 48]}
-					]
-				},
-				{
-					"name": "leftPant",
-					"parent": "leftLeg",
-					"pivot": [2, 6, 0],
+					"pivot": [1.9, 11, 0],
 					"cubes": [
-						{"origin": [0, 0, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [0, 48]}
+						{"origin": [0.15, 0.25, -2], "size": [3, 10.75, 3.5], "pivot": [5.6, -1, -0.5], "rotation": [-2, 0, 0], "uv": [1, 19]},
+						{
+							"origin": [0.1, 0, -2],
+							"size": [3.5, 7, 4],
+							"uv": {
+								"north": {"uv": [54.25, 21.25], "uv_size": [0.5, 6.75]},
+								"east": {"uv": [58, 21.25], "uv_size": [-4, 6.75]},
+								"south": {"uv": [57.25, 21], "uv_size": [3.5, 7]},
+								"west": {"uv": [54, 21.25], "uv_size": [4, 6.75]},
+								"down": {"uv": [8.25, 52], "uv_size": [3.5, -4]}
+							}
+						}
 					]
 				}
 			]
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/container.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/container.png
new file mode 100644
index 000000000..f5cbef096
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/container.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/container_blinking.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/container_blinking.png
new file mode 100644
index 000000000..284d5ce1e
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/container_blinking.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/full.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/full.png
new file mode 100644
index 000000000..5ea26940a
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/full.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/full_blinking.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/full_blinking.png
new file mode 100644
index 000000000..17d833e0f
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/full_blinking.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/half.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/half.png
new file mode 100644
index 000000000..4ae53162f
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/half.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/half_blinking.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/half_blinking.png
new file mode 100644
index 000000000..00fa330a7
Binary files /dev/null and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/hud/heart/pig/half_blinking.png differ
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 5275da452..990fe0d91 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
@@ -26,8 +26,10 @@ import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.util.phys.BoundingVolume;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.LevelListener;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import net.minecraft.core.world.pos.TilePos;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -282,28 +284,14 @@ public final class Block<T extends BlockLogic>
         return new ItemStack(this);
     }
 
-    public static boolean isBuried (World world, int x, int y, int z)
-    {
-        boolean buried = true;
-        if(Blocks.lightBlock[world.getBlockId(x + 1, y, z)] <= 2)
-            buried = false;
-        if(Blocks.lightBlock[world.getBlockId(x - 1, y, z)] <= 2)
-            buried = false;
-        if(Blocks.lightBlock[world.getBlockId(x, y, z + 1)] <= 2)
-            buried = false;
-        if(Blocks.lightBlock[world.getBlockId(x, y, z - 1)] <= 2)
-            buried = false;
-        if(Blocks.lightBlock[world.getBlockId(x, y + 1, z)] <= 2)
-            buried = false;
-        if(Blocks.lightBlock[world.getBlockId(x, y - 1, z)] <= 2)
-            buried = false;
-        return buried;
-    }
-
-    public static boolean getIsLitInteriorSurface (World world, int x, int y, int z)
-    {
-        int l = world.getBlockId(x, y, z);
-        return l != 0 && Blocks.blocksList[l] != null && Blocks.blocksList[l].isLitInteriorSurface;
+    public static boolean getIsLitInteriorSurface(final @NotNull WorldSource source, final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = source.getBlock(tilePos);
+        return block != null && block.isLitInteriorSurface;
+    }
+
+    @Deprecated
+    public static boolean getIsLitInteriorSurface(final @NotNull WorldSource source, final int x, final int y, final int z) {
+        return getIsLitInteriorSurface(source, new TilePos(x, y, z));
     }
 
     @SafeVarargs
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 067fb5261..de389dd89 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
@@ -590,7 +590,7 @@ public abstract class Entity
 				bb.move(0.0D, yd, 0.0D);
 			}
 			cubes = world.getCubes(this, bb);
-			if(oldX * oldX + oldZ * oldZ >= xd * xd + zd * zd || cubes.size() > 0) {
+			if(oldX * oldX + oldZ * oldZ >= xd * xd + zd * zd || !cubes.isEmpty()) {
 				xd = oldX;
 				yd = oldY;
 				zd = oldZ;
@@ -834,9 +834,9 @@ public abstract class Entity
         return world.isMaterialInBB(bb/*.expand(-0.1D, -0.4D, -0.1D)*/, Material.lava);
     }
 
-    public void moveRelative(float f, float f1, float f2)
+    public void moveRelative(float strafe, float forward, float speed)
     {
-        float f3 = MathHelper.sqrt_float(f * f + f1 * f1);
+        float f3 = MathHelper.sqrt_float(strafe * strafe + forward * forward);
         if(f3 < 0.01F)
         {
             return;
@@ -845,14 +845,14 @@ public abstract class Entity
         {
             f3 = 1.0F;
         }
-        f3 = f2 / f3;
-        f *= f3;
-        f1 *= f3;
+        f3 = speed / f3;
+        strafe *= f3;
+        forward *= f3;
 
         float sinYaw = MathHelper.sin((yRot * MathHelper.PI) / 180F);
         float cosYaw = MathHelper.cos((yRot * MathHelper.PI) / 180F);
-        xd += f * cosYaw - f1 * sinYaw ;
-        zd += f1 * cosYaw + f * sinYaw;
+        xd += strafe * cosYaw - forward * sinYaw ;
+        zd += forward * cosYaw + strafe * sinYaw;
     }
 
     public float getBrightness(float partialTick)
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 eebfdd8fe..5942b6401 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
@@ -211,6 +211,8 @@ public abstract class Mob extends Entity
         return !removed;
     }
 
+    public boolean isJumping() { return isJumping; }
+
     @Override
 	public float getHeadHeight()
     {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java
index 93292301d..0ecda8f7f 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java
@@ -13,6 +13,7 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.Items;
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.util.collection.NamespaceID;
+import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
 
@@ -27,6 +28,7 @@ public class MobPig
 
     public List<WeightedRandomLootObject> burningMobDrops = new ArrayList<>();
     private final @NotNull MobAge age;
+    protected float speedProgress = 0f;
 
     public MobPig(World world)
     {
@@ -71,6 +73,79 @@ public class MobPig
         this.age.tick(this.world);
     }
 
+    @Override
+    protected void updateAI() {
+        if (passenger instanceof Player) {
+            target = null;
+            pathToEntity = null;
+
+            moveForward = 0f;
+            moveStrafing = 0f;
+
+            final float accel = MathHelper.lerp(3, 10f, speedProgress) * (!onGround ? 0.25f : 1f) * (isInWater() ? 0.5f : 1f);
+            final float maxSpeed = MathHelper.lerp(3, 10f, speedProgress) * (!(onGround || yd < 0) ? 0.25f : 1f) * (isInWater() ? 0.5f : 1f);
+
+            final double pXd = MathHelper.clamp(passenger.xd, -0.02, 0.02);
+            final double pZd = MathHelper.clamp(passenger.zd, -0.02, 0.02);
+
+            this.xd += pXd * accel;
+            this.zd += pZd * accel;
+            this.xd = MathHelper.clamp(this.xd, -maxSpeed, maxSpeed);
+            this.zd = MathHelper.clamp(this.zd, -maxSpeed, maxSpeed);
+
+            this.xRot = passenger.xRot;
+            this.yRot = passenger.yRot;
+            this.yBodyRot = passenger.yRot;
+
+            this.isJumping = isInWater() || ((Player) passenger).isJumping();
+
+            if ((onGround || yd < 0) && !isInWater() && !isJumping) {
+                if (pXd * pXd + pZd * pZd > 0.000005f) {
+                    speedProgress += 1/200f;
+                    speedProgress *= 1.025f;
+                } else {
+                    speedProgress *= 0.9f;
+                }
+                speedProgress = MathHelper.clamp(speedProgress, 0, 1);
+            } else {
+                speedProgress = 0f;
+            }
+        } else {
+            this.footSize = 0.5f;
+            super.updateAI();
+        }
+    }
+
+    @Override
+    public void positionRider() {
+        super.positionRider();
+        if (passenger instanceof Player) {
+            ((Player) passenger).yBodyRotO = this.yBodyRotO;
+            ((Player) passenger).yBodyRot = this.yBodyRot;
+            passenger.walkDist = this.walkDist;
+            passenger.walkDistO = this.walkDistO;
+
+
+            // The pig should probably not be the one setting up the view bobbing params
+            double velocity = MathHelper.sqrt(xd * xd + zd * zd);
+            double pitch = (float) Math.atan(-yd * 0.2D) * 15F;
+            if(velocity > 0.1F)
+            {
+                velocity = 0.1F;
+            }
+            if(!onGround || getHealth() <= 0)
+            {
+                velocity = 0.0F;
+            }
+            if(onGround || getHealth() <= 0)
+            {
+                pitch = 0.0F;
+            }
+            ((Player)passenger).cameraVelocity += (float) ((velocity - ((Player)passenger).cameraVelocity) * 0.4F);
+            ((Player)passenger).cameraPitch += (float) ((pitch - cameraPitch) * 0.8F);
+        }
+    }
+
     @Override
     public String getLivingSound()
     {
@@ -93,15 +168,31 @@ public class MobPig
 	public boolean interact(@NotNull Player player)
     {
         if (super.interact(player)) return true;
-        if (getSaddled() && !world.isClientSide && (passenger == null || passenger == player))
-        {
-            player.startRiding(this);
+        ItemStack heldItem = player.getHeldItem();
+        if (heldItem != null && (heldItem.itemID == Blocks.MUSHROOM_BROWN.id() || heldItem.itemID == Blocks.MUSHROOM_RED.id()) && heldItem.consumeItem(player)) {
+            heal(4);
             return true;
         }
-        else
-        {
-            return false;
+        if (!world.isClientSide) {
+            if (getSaddled()) {
+                if (player.isSneaking()) {
+                    if (passenger == null) {
+                        setSaddled(false);
+                        ItemStack toInsert = new ItemStack(Items.SADDLE);
+                        player.inventory.insertItem(toInsert, true);
+                        if (toInsert.stackSize > 0) {
+                            dropItem(toInsert, 0.0f);
+                        }
+                        return true;
+                    }
+                }
+                if (passenger == null || passenger == player) {
+                    player.startRiding(this);
+                    return true;
+                }
+            }
         }
+        return false;
     }
 
     @Override
@@ -150,10 +241,13 @@ public class MobPig
 	public void thunderHit(EntityLightning bolt)
     {
         if (!world.isClientSide) {
-            MobZombiePig entitypigzombie = new MobZombiePig(world);
-            entitypigzombie.moveTo(x, y, z, yRot, xRot);
-            world.entityJoinedWorld(entitypigzombie);
+            MobZombiePig pigZombie = new MobZombiePig(world);
+            pigZombie.moveTo(x, y, z, yRot, xRot);
+            world.entityJoinedWorld(pigZombie);
             remove();
+            if (passenger != null) {
+                passenger.startRiding(pigZombie);
+            }
         }
     }
 
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 8d227861f..e8d238d42 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
@@ -357,8 +357,6 @@ public abstract class Player
         double ydO = y;
         double zdO = z;
         super.rideTick();
-        cameraVelocityOld = cameraVelocity;
-        cameraVelocity = 0.0F;
         addMountedMovementStat(x - xdO, y - ydO, z - zdO);
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java b/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java
index 58b40e401..004b0ef17 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java
@@ -16,12 +16,12 @@ public class ItemSaddle extends Item
     @Override
     public boolean useItemOnEntity(ItemStack itemstack, Mob mob, Player player)
     {
-        if(mob instanceof MobPig && itemstack.consumeItem(player))
+        if(!player.isSneaking() && mob instanceof MobPig && itemstack.consumeItem(player))
         {
-            MobPig entitypig = (MobPig) mob;
-            if(!entitypig.getSaddled())
+            MobPig pig = (MobPig) mob;
+            if(!pig.getSaddled())
             {
-                entitypig.setSaddled(true);
+                pig.setSaddled(true);
                 return true;
             }
         }
diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java b/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java
index 8983428c0..d5a20ef39 100644
--- a/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java
+++ b/game/core/src/main/java/net/minecraft/core/util/helper/MathHelper.java
@@ -42,10 +42,6 @@ public class MathHelper
         return d >= (double)truncated ? truncated : truncated - 1;
     }
 
-    public static int floorIntDiv(final int a, final int b) {
-        return floor((double) a / (double) b);
-    }
-
     public static int ceil(double d)
     {
         int truncated = (int)d;
@@ -113,6 +109,13 @@ public class MathHelper
     public static double lerp(double a, double b, double amount) {
         return a + ((b - a) * amount);
     }
+
+    public static float unlerp(float a, float b, float value) {
+        return (value - a)/(b - a);
+    }
+    public static double unlerp(double a, double b, double value) {
+        return (value - a)/(b - a);
+    }
 	
 	public static float getInterpolate(float[] array, float index) {
 		int index0 = (int) index;
diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/Side.java b/game/core/src/main/java/net/minecraft/core/util/helper/Side.java
index cc33de425..eb49332df 100644
--- a/game/core/src/main/java/net/minecraft/core/util/helper/Side.java
+++ b/game/core/src/main/java/net/minecraft/core/util/helper/Side.java
@@ -101,7 +101,7 @@ public enum Side {
 		return opposite;
 	}
 	
-	public Direction getDirection() {
+	public @NotNull Direction getDirection() {
 		return direction;
 	}
 	
diff --git a/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java b/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java
index fb71c4755..5192a569d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java
+++ b/game/core/src/main/java/net/minecraft/core/world/BlocksContainer.java
@@ -8,160 +8,238 @@ import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.chunk.ChunkCoordinates;
+import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.season.SeasonManager;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
-public class BlocksContainer implements WorldSource {
-    public final World world;
-    private final Map<ChunkCoordinates, BlockEntry> blockEntryMap = new HashMap<>();
-    private Entity lightRefEntity = null;
-    public BlocksContainer(World world) {
+public class BlocksContainer implements MutableWorldSource {
+    public final @NotNull World world;
+    private final @NotNull Map<@NotNull TilePos, @NotNull BlockEntry> blockEntryMap = new HashMap<>();
+    private @Nullable Entity lightRefEntity = null;
+
+    public BlocksContainer(final @NotNull World world) {
         this.world = world;
     }
 
-    public void setLightReferenceEntity(Entity entity) {
+    @Override
+    public int getHeightBlocks() {
+        return this.world.getHeightBlocks();
+    }
+
+    public void setLightReferenceEntity(final @Nullable Entity entity) {
         this.lightRefEntity = entity;
     }
 
+    @Override
+    public boolean setBlockId(final @NotNull TilePos tilePos, final int id) {
+        this.blockEntryMap.put(tilePos, new BlockEntry(id, 0, null));
+        return true;
+    }
 
-    public void setBlock(int x, int y, int z, int blockID, int blockMeta, TileEntity entity) {
-        blockEntryMap.put(new ChunkCoordinates(x, y, z), new BlockEntry(blockID, blockMeta, entity, x, y, z));
+    @Deprecated
+    public void setBlock(final int x, final int y, final int z, final int id, final int data, final @Nullable TileEntity tileEntity) {
+        final @NotNull TilePos tilePos = new TilePos(x, y, z);
+
+        this.setBlockIdData(tilePos, id, data);
+        if (tileEntity != null) {
+            this.setTileEntity(tilePos, tileEntity);
+        }
     }
 
-    public BlockEntry getEntry(int x, int y, int z) {
-        return blockEntryMap.get(new ChunkCoordinates(x, y, z));
+    @Override
+    public boolean setBlockData(final @NotNull TilePos tilePos, final int data) {
+        final @Nullable BlockEntry entry = this.getEntry(tilePos);
+        if (entry != null) {
+            entry.data = data;
+        } else {
+            this.blockEntryMap.put(tilePos, new BlockEntry(this.world.getBlockId(tilePos), data, this.world.getTileEntity(tilePos)));
+        }
+
+        return true;
     }
 
-    public Collection<BlockEntry> getEntries() {
-        return blockEntryMap.values();
+    @Override
+    public boolean setBlockIdData(final @NotNull TilePos tilePos, final int id, final int data) {
+        this.blockEntryMap.put(tilePos, new BlockEntry(id, data, null));
+        return true;
     }
 
-    public void clear() {
-        blockEntryMap.clear();
+    @Override
+    public void setLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePos tilePos, final int value) {
+        // Do nothing
+    }
+
+    @Override
+    public void setTileEntity(final @NotNull TilePos tilePos, final @NotNull TileEntity tileEntity) {
+        final @Nullable BlockEntry entry = this.getEntry(tilePos);
+        if (entry != null) {
+            entry.tileEntity = tileEntity;
+        } else {
+            this.blockEntryMap.put(tilePos, new BlockEntry(this.world.getBlockId(tilePos), this.world.getBlockData(tilePos), tileEntity));
+        }
+    }
+
+    @Override
+    public void removeTileEntity(final @NotNull TilePos tilePos) {
+        final @Nullable BlockEntry entry = this.getEntry(tilePos);
+        if (entry != null) {
+            entry.tileEntity = null;
+        } else {
+            this.blockEntryMap.put(tilePos, new BlockEntry(this.world.getBlockId(tilePos), this.world.getBlockData(tilePos), null));
+        }
+    }
+
+    public @Nullable BlockEntry getEntry(final @NotNull TilePos tilePos) {
+        return this.blockEntryMap.get(tilePos);
     }
 
+    @Deprecated
+    public @Nullable BlockEntry getEntry(final int x, final int y, final int z) {
+        return this.getEntry(new TilePos(x, y, z));
+    }
+
+    public @NotNull Collection<@NotNull BlockEntry> getEntries() {
+        return this.blockEntryMap.values();
+    }
+
+    public void clear() {
+        this.blockEntryMap.clear();
+    }
 
     @Override
-    public int getBlockId(int x, int y, int z) {
-        ChunkCoordinates c = new ChunkCoordinates(x, y, z);
-        if (blockEntryMap.containsKey(c)){
-            return blockEntryMap.get(c).blockID;
+    public int getBlockId(final @NotNull TilePos tilePos) {
+        final @Nullable BlockEntry entry = this.getEntry(tilePos);
+        if (entry != null) {
+            return entry.id;
         }
-        return world.getBlockId(x, y, z);
+
+        return this.world.getBlockId(tilePos);
     }
 
     @Override
-    public @Nullable Block<?> getBlock(int x, int y, int z) {
-        return Blocks.getBlock(getBlockId(x, y, z));
+    public @Nullable Block<?> getBlock(final @NotNull TilePos tilePos) {
+        return Blocks.getBlock(this.getBlockId(tilePos));
     }
 
     @Override
-    public TileEntity getTileEntity(int x, int y, int z) {
-        ChunkCoordinates c = new ChunkCoordinates(x, y, z);
-        if (blockEntryMap.containsKey(c)){
-            return blockEntryMap.get(c).tileEntity;
+    public @Nullable TileEntity getTileEntity(final @NotNull TilePos tilePos) {
+        final @Nullable BlockEntry entry = this.getEntry(tilePos);
+        if (entry != null) {
+            return entry.tileEntity;
         }
-        return world.getTileEntity(x, y, z);
+
+        return this.world.getTileEntity(tilePos);
     }
 
     @Override
-    public float getBrightness(int x, int y, int z, int blockLightValue) {
-        if (lightRefEntity != null) return lightRefEntity.getBrightness(1f);
-        return world.getBrightness(x, y, z, blockLightValue);
+    public float getBrightness(final @NotNull TilePos tilePos, final int lightEmission) {
+        if (this.lightRefEntity != null) {
+            return this.lightRefEntity.getBrightness(1.0f);
+        }
+
+        return this.world.getBrightness(tilePos, lightEmission);
+    }
+
+    @Override
+    public int getLightmapCoord(final @NotNull TilePos tilePos, final int lightEmission) {
+        if (this.lightRefEntity != null) {
+            return this.lightRefEntity.getLightmapCoord(1.0f);
+        }
+
+        return this.world.getLightmapCoord(tilePos, lightEmission);
     }
 
     @Override
-    public int getLightmapCoord(int x, int y, int z, int blockLightValue) {
-        if (lightRefEntity != null) return lightRefEntity.getLightmapCoord(1f);
-        return world.getLightmapCoord(x, y, z, blockLightValue);
+    public int getLightmapCoord(final int skyLight, final int blockLight) {
+        return this.world.getLightmapCoord(skyLight, blockLight);
     }
 
     @Override
-    public int getLightmapCoord(int skylight, int blocklight) {
-        return world.getLightmapCoord(skylight, blocklight);
+    public float getLightBrightness(final @NotNull TilePos tilePos) {
+        return this.world.getLightBrightness(tilePos);
     }
 
     @Override
-    public float getLightBrightness(int x, int y, int z) {
-        return world.getLightBrightness(x, y, z);
+    public int getBlockData(final @NotNull TilePos tilePos) {
+        final @Nullable BlockEntry entry = this.getEntry(tilePos);
+        if (entry != null) {
+            return entry.data;
+        }
+
+        return this.world.getBlockData(tilePos);
     }
 
     @Override
-    public int getBlockMetadata(int x, int y, int z) {
-        ChunkCoordinates c = new ChunkCoordinates(x, y, z);
-        if (blockEntryMap.containsKey(c)){
-            return blockEntryMap.get(c).blockMeta;
+    public @NotNull Material getBlockMaterial(final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        if (block == null) {
+            return Material.air;
+        } else {
+            return block.getMaterial();
         }
-        return world.getBlockMetadata(x, y, z);
     }
 
     @Override
-    public Material getBlockMaterial(int x, int y, int z) {
-        Block<?> b = getBlock(x, y, z);
-        return b == null ? Material.air : b.getMaterial();
+    public boolean isBlockOpaqueCube(final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        return block != null && block.isSolidRender();
     }
 
     @Override
-    public boolean isBlockOpaqueCube(int x, int y, int z) {
-        Block<?> b = getBlock(x, y, z);
-        return b != null && b.isSolidRender();
+    public boolean isBlockNormalCube(final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        return block != null && block.getMaterial().isSolidBlocking() && block.renderAsNormalBlockOnCondition(this, tilePos.x, tilePos.y, tilePos.z);
     }
 
     @Override
-    public boolean isBlockNormalCube(int x, int y, int z) {
-        Block<?> b = getBlock(x, y, z);
-        return b != null && b.getMaterial().isSolidBlocking() && b.renderAsNormalBlockOnCondition(this, x, y, z);
+    public double getBlockTemperature(final @NotNull TilePos tilePos) {
+        return this.world.getBlockTemperature(tilePos);
     }
 
     @Override
-    public double getBlockTemperature(int x, int z) {
-        return world.getBlockTemperature(x, z);
+    public double getBlockHumidity(final @NotNull TilePos tilePos) {
+        return this.world.getBlockHumidity(tilePos);
     }
 
     @Override
-    public double getBlockHumidity(int x, int z) {
-        return world.getBlockHumidity(x, z);
+    public double getBlockVariety(final @NotNull TilePos tilePos) {
+        return this.world.getBlockVariety(tilePos);
     }
 
     @Override
-    public SeasonManager getSeasonManager() {
-        return world.getSeasonManager();
+    public @NotNull SeasonManager getSeasonManager() {
+        return this.world.getSeasonManager();
     }
 
     @Override
-    public Biome getBlockBiome(int x, int y, int z) {
-        return world.getBlockBiome(x, y, z);
+    public @NotNull Biome getBlockBiome(final @NotNull TilePos tilePos) {
+        return this.world.getBlockBiome(tilePos);
     }
 
     @Override
-    public int getSavedLightValue(LightLayer layer, int x, int y, int z) {
-        return world.getSavedLightValue(layer, x, y, z);
+    public int getSavedLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePos tilePos) {
+        return this.world.getSavedLightValue(lightLayer, tilePos);
     }
 
     @Override
     public boolean isRetro() {
-        return world.isRetro();
+        return this.world.isRetro();
     }
 
     public static class BlockEntry {
-        public final int blockID;
-        public final int blockMeta;
-        @Nullable
-        public final TileEntity tileEntity;
-        public final int x;
-        public final int y;
-        public final int z;
-        public BlockEntry(int blockID, int blockMeta, @Nullable TileEntity tileEntity, int x, int y, int z){
-            this.blockID = blockID;
-            this.blockMeta = blockMeta;
+        public int id;
+        public int data;
+        public @Nullable TileEntity tileEntity;
+
+        public BlockEntry(final int id, final int data, final @Nullable TileEntity tileEntity) {
+            this.id = id;
+            this.data = data;
             this.tileEntity = tileEntity;
-            this.x = x;
-            this.y = y;
-            this.z = z;
         }
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/MutableWorldSource.java b/game/core/src/main/java/net/minecraft/core/world/MutableWorldSource.java
new file mode 100644
index 000000000..0d8597a8a
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/MutableWorldSource.java
@@ -0,0 +1,62 @@
+package net.minecraft.core.world;
+
+import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.enums.LightLayer;
+import net.minecraft.core.world.pos.TilePos;
+import org.jetbrains.annotations.NotNull;
+
+public interface MutableWorldSource
+    extends WorldSource {
+
+    boolean setBlockId(final @NotNull TilePos tilePos, final int id);
+
+    @Deprecated
+    default boolean setBlock(final int x, final int y, final int z, final int id) {
+        return this.setBlockId(new TilePos(x, y, z), id);
+    }
+
+    boolean setBlockData(final @NotNull TilePos tilePos, final int data);
+
+    @Deprecated
+    default boolean setBlockMetadata(final int x, final int y, final int z, final int data) {
+        return this.setBlockData(new TilePos(x, y, z), data);
+    }
+
+    boolean setBlockIdData(final @NotNull TilePos tilePos, final int id, final int data);
+
+    @Deprecated
+    default boolean setBlockAndMetadata(final int x, final int y, final int z, final int id, final int data) {
+        return this.setBlockIdData(new TilePos(x, y, z), id, data);
+    }
+
+    void setLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePos tilePos, final int value);
+
+    @Deprecated
+    default void setLightValue(final @NotNull LightLayer lightLayer, final int x, final int y, final int z, final int value) {
+        this.setLightValue(lightLayer, new TilePos(x, y, z), value);
+    }
+
+    void setTileEntity(final @NotNull TilePos tilePos, final @NotNull TileEntity tileEntity);
+
+    @Deprecated
+    default void setTileEntity(final int x, final int y, final int z, final @NotNull TileEntity tileEntity) {
+        this.setTileEntity(new TilePos(x, y, z), tileEntity);
+    }
+
+    void removeTileEntity(final @NotNull TilePos tilePos);
+
+    @Deprecated
+    default void removeBlockTileEntity(final int x, final int y, final int z) {
+        this.removeTileEntity(new TilePos(x, y, z));
+    }
+
+    default void replaceTileEntity(final @NotNull TilePos tilePos, final @NotNull TileEntity tileEntity) {
+        this.removeTileEntity(tilePos);
+        this.setTileEntity(tilePos, tileEntity);
+    }
+
+    @Deprecated
+    default void replaceBlockTileEntity(final int x, final int y, final int z, final @NotNull TileEntity tileEntity) {
+        this.replaceTileEntity(new TilePos(x, y, z), tileEntity);
+    }
+}
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 57433468e..240f39051 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
@@ -51,6 +51,8 @@ import net.minecraft.core.world.lighting.LightingEngine;
 import net.minecraft.core.world.lighting.LightingEngineLegacy;
 import net.minecraft.core.world.pathfinder.Path;
 import net.minecraft.core.world.pathfinder.PathFinder;
+import net.minecraft.core.world.pos.ChunkPos;
+import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.save.DimensionData;
 import net.minecraft.core.world.save.LevelData;
 import net.minecraft.core.world.save.LevelStorage;
@@ -67,7 +69,7 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 
-public class World implements WorldSource {
+public class World implements MutableWorldSource {
     private static final Logger LOGGER = LogUtils.getLogger();
     public static boolean AUTOSAVE = true;
 
@@ -115,7 +117,7 @@ public class World implements WorldSource {
     protected boolean enoughPlayersSleeping;
     public SavedDataStorage savedDataStorage;
     protected final LightingEngine lightingEngine = new LightingEngineLegacy(this);
-    private boolean updatingBlockEntities;
+    private boolean updatingTileEntities;
 
     private int caveSoundCounter = this.rand.nextInt(12000);
     public boolean isClientSide = false;
@@ -304,8 +306,8 @@ public class World implements WorldSource {
         return levelData.getSpawnerConfig();
     }
 
-    public int getHeightBlocks()
-    {
+    @Override
+    public int getHeightBlocks() {
         return Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y;
     }
 
@@ -426,56 +428,45 @@ public class World implements WorldSource {
     }
 
     @Override
-    public int getBlockId(int x, int y, int z)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
+    public int getBlockId(final @NotNull TilePos tilePos) {
+        if (!tilePos.inBounds(this)) {
             return 0;
-        }
-        if(y < 0)
-        {
-            return 0;
-        }
-        if(y >= getHeightBlocks())
-        {
-            return 0;
-        } else
-        {
-            return getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z)).getBlockID(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
+        } else {
+            return this.getChunkFromChunkCoords(
+                Math.floorDiv(tilePos.x, Chunk.CHUNK_SIZE_X),
+                Math.floorDiv(tilePos.z, Chunk.CHUNK_SIZE_Z)
+            ).getBlockID(
+                tilePos.x & (Chunk.CHUNK_SIZE_X - 1),
+                tilePos.y,
+                tilePos.z & (Chunk.CHUNK_SIZE_Z - 1)
+            );
         }
     }
 
     @Override
-    public @Nullable Block<?> getBlock(int x, int y, int z) {
-        return Blocks.getBlock(getBlockId(x, y, z));
+    public @Nullable Block<?> getBlock(final @NotNull TilePos tilePos) {
+        return Blocks.getBlock(this.getBlockId(tilePos));
     }
 
     @Override
-    public double getBlockTemperature(int x, int z)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
+    public double getBlockTemperature(final @NotNull TilePos tilePos) {
+        if (tilePos.x < MIN_BLOCK_X || tilePos.z < MIN_BLOCK_Z || tilePos.x > MAX_BLOCK_X || tilePos.z > MAX_BLOCK_Z) {
             return 0;
-        }
-        else
-        {
-            int chunkX = Math.floorDiv(x, Chunk.CHUNK_SIZE_X);
-            int chunkZ = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z);
+        } else {
+            final int chunkX = Math.floorDiv(tilePos.x, Chunk.CHUNK_SIZE_X);
+            final int chunkZ = Math.floorDiv(tilePos.z, Chunk.CHUNK_SIZE_Z);
             double temperature = Double.NEGATIVE_INFINITY;
-            Chunk chunk = null;
+            @Nullable Chunk chunk = null;
 
-            if (isChunkLoaded(chunkX, chunkZ))
-            {
-                chunk = getChunkFromChunkCoords(chunkX, chunkZ);
-                temperature = chunk.getBlockTemperature(x & (Chunk.CHUNK_SIZE_X - 1), z & (Chunk.CHUNK_SIZE_Z - 1));
+            if (this.isChunkLoaded(chunkX, chunkZ)) {
+                chunk = this.getChunkFromChunkCoords(chunkX, chunkZ);
+                temperature = chunk.getBlockTemperature(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.z & (Chunk.CHUNK_SIZE_Z - 1));
             }
 
-            if (temperature == Double.NEGATIVE_INFINITY)
-            {
-                temperature = getBiomeProvider().getTemperature(x, z);
-                if (chunk != null)
-                {
-                    chunk.setBlockTemperature(x & (Chunk.CHUNK_SIZE_X - 1), z & (Chunk.CHUNK_SIZE_Z - 1), temperature);
+            if (temperature == Double.NEGATIVE_INFINITY) {
+                temperature = getBiomeProvider().getTemperature(tilePos.x, tilePos.z);
+                if (chunk != null) {
+                    chunk.setBlockTemperature(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.z & (Chunk.CHUNK_SIZE_Z - 1), temperature);
                 }
             }
 
@@ -483,31 +474,24 @@ public class World implements WorldSource {
         }
     }
     @Override
-    public double getBlockHumidity(int x, int z)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
+    public double getBlockHumidity(final @NotNull TilePos tilePos) {
+        if (tilePos.x < MIN_BLOCK_X || tilePos.z < MIN_BLOCK_Z || tilePos.x > MAX_BLOCK_X || tilePos.z > MAX_BLOCK_Z) {
             return 0;
-        }
-        else
-        {
-            int chunkX = Math.floorDiv(x, Chunk.CHUNK_SIZE_X);
-            int chunkZ = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z);
+        } else {
+            final int chunkX = Math.floorDiv(tilePos.x, Chunk.CHUNK_SIZE_X);
+            final int chunkZ = Math.floorDiv(tilePos.z, Chunk.CHUNK_SIZE_Z);
             double humidity = Double.NEGATIVE_INFINITY;
-            Chunk chunk = null;
+            @Nullable Chunk chunk = null;
 
-            if (isChunkLoaded(chunkX, chunkZ))
-            {
-                chunk = getChunkFromChunkCoords(chunkX, chunkZ);
-                humidity = chunk.getBlockHumidity(x & (Chunk.CHUNK_SIZE_X - 1), z & (Chunk.CHUNK_SIZE_Z - 1));
+            if (this.isChunkLoaded(chunkX, chunkZ)) {
+                chunk = this.getChunkFromChunkCoords(chunkX, chunkZ);
+                humidity = chunk.getBlockHumidity(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.z & (Chunk.CHUNK_SIZE_Z - 1));
             }
 
-            if (humidity == Double.NEGATIVE_INFINITY)
-            {
-                humidity = getBiomeProvider().getHumidity(x, z);
-                if (chunk != null)
-                {
-                    chunk.setBlockHumidity(x & (Chunk.CHUNK_SIZE_X - 1), z & (Chunk.CHUNK_SIZE_Z - 1), humidity);
+            if (humidity == Double.NEGATIVE_INFINITY) {
+                humidity = this.getBiomeProvider().getHumidity(tilePos.x, tilePos.z);
+                if (chunk != null) {
+                    chunk.setBlockHumidity(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.z & (Chunk.CHUNK_SIZE_Z - 1), humidity);
                 }
             }
 
@@ -516,35 +500,29 @@ public class World implements WorldSource {
     }
 
     @Override
-    public SeasonManager getSeasonManager() {
-        return seasonManager;
+    public @NotNull SeasonManager getSeasonManager() {
+        return this.seasonManager;
     }
 
-    public double getBlockVariety(int x, int z)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
+    @Override
+    public double getBlockVariety(final @NotNull TilePos tilePos) {
+        if (tilePos.x < MIN_BLOCK_X || tilePos.z < MIN_BLOCK_Z || tilePos.x > MAX_BLOCK_X || tilePos.z > MAX_BLOCK_Z) {
             return 0;
-        }
-        else
-        {
-            int chunkX = Math.floorDiv(x, Chunk.CHUNK_SIZE_X);
-            int chunkZ = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z);
+        } else {
+            final int chunkX = Math.floorDiv(tilePos.x, Chunk.CHUNK_SIZE_X);
+            final int chunkZ = Math.floorDiv(tilePos.z, Chunk.CHUNK_SIZE_Z);
             double variety = Double.NEGATIVE_INFINITY;
-            Chunk chunk = null;
+            @Nullable Chunk chunk = null;
 
-            if (isChunkLoaded(chunkX, chunkZ))
-            {
-                chunk = getChunkFromChunkCoords(chunkX, chunkZ);
-                variety = chunk.getBlockVariety(x & (Chunk.CHUNK_SIZE_X - 1), z & (Chunk.CHUNK_SIZE_Z - 1));
+            if (this.isChunkLoaded(chunkX, chunkZ)) {
+                chunk = this.getChunkFromChunkCoords(chunkX, chunkZ);
+                variety = chunk.getBlockVariety(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.z & (Chunk.CHUNK_SIZE_Z - 1));
             }
 
-            if (variety == Double.NEGATIVE_INFINITY)
-            {
-                variety = getBiomeProvider().getVariety(x, z);
-                if (chunk != null)
-                {
-                    chunk.setBlockVariety(x & (Chunk.CHUNK_SIZE_X - 1), z & (Chunk.CHUNK_SIZE_Z - 1), variety);
+            if (variety == Double.NEGATIVE_INFINITY) {
+                variety = this.getBiomeProvider().getVariety(tilePos.x, tilePos.z);
+                if (chunk != null) {
+                    chunk.setBlockVariety(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.z & (Chunk.CHUNK_SIZE_Z - 1), variety);
                 }
             }
 
@@ -553,31 +531,25 @@ public class World implements WorldSource {
     }
 
     @Override
-    public @NotNull Biome getBlockBiome(int x, int y, int z)
+    public @NotNull Biome getBlockBiome(final @NotNull TilePos tilePos)
     {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
+        if (!tilePos.inBounds(this)) {
             return Biomes.OVERWORLD_PLAINS;
-        }
-        else
-        {
-            int chunkX = Math.floorDiv(x, Chunk.CHUNK_SIZE_X);
-            int chunkZ = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z);
-            Biome biome = null;
-            Chunk chunk = null;
+        } else {
+            final int chunkX = Math.floorDiv(tilePos.x, Chunk.CHUNK_SIZE_X);
+            final int chunkZ = Math.floorDiv(tilePos.z, Chunk.CHUNK_SIZE_Z);
+            @Nullable Biome biome = null;
+            @Nullable Chunk chunk = null;
 
-            if (isChunkLoaded(chunkX, chunkZ))
-            {
-                chunk = getChunkFromChunkCoords(chunkX, chunkZ);
-                biome = chunk.getBlockBiome(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
+            if (this.isChunkLoaded(chunkX, chunkZ)) {
+                chunk = this.getChunkFromChunkCoords(chunkX, chunkZ);
+                biome = chunk.getBlockBiome(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.y, tilePos.z & (Chunk.CHUNK_SIZE_Z - 1));
             }
 
-            if (biome == null)
-            {
-                biome = getBiomeProvider().getBiome(x, y, z);
-                if (chunk != null)
-                {
-                    chunk.setBlockBiome(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), biome);
+            if (biome == null) {
+                biome = this.getBiomeProvider().getBiome(tilePos.x, tilePos.y, tilePos.z);
+                if (chunk != null) {
+                    chunk.setBlockBiome(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.y, tilePos.z & (Chunk.CHUNK_SIZE_Z - 1), biome);
                 }
             }
 
@@ -587,63 +559,67 @@ public class World implements WorldSource {
         }
     }
 
-    public boolean getBlockLitInteriorSurface(int x, int y, int z)
+    public boolean getBlockLitInteriorSurface(final @NotNull TilePos tilePos)
     {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
-            return true;
-        }
-        if(y < 0)
-        {
-            return true;
-        }
-        if(y >= getHeightBlocks())
-        {
+        if (!tilePos.inBounds(this)) {
             return true;
-        } else
-        {
-            return Block.getIsLitInteriorSurface(this, x, y, z);
+        } else {
+            return Block.getIsLitInteriorSurface(this, tilePos.x, tilePos.y, tilePos.z);
         }
     }
 
-    public boolean isAirBlock(int x, int y, int z)
-    {
-        return getBlockId(x, y, z) == 0;
+    @Deprecated
+    public final boolean getBlockLitInteriorSurface(final int x, final int y, final int z) {
+        return this.getBlockLitInteriorSurface(new TilePos(x, y, z));
     }
 
-    public boolean isBlockLoaded(int x, int y, int z)
-    {
-        if(y < 0 || y >= getHeightBlocks())
-        {
-            return false;
-        }
-        else
-        {
-            return isChunkLoaded(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-        }
+    public boolean isAirBlock(final @NotNull TilePos tilePos) {
+        return this.getBlockId(tilePos) == 0;
     }
 
-    public boolean areBlocksLoaded(int x, int y, int z, int range)
-    {
-        return areBlocksLoaded(x - range, y - range, z - range, x + range, y + range, z + range);
+    @Deprecated
+    public final boolean isAirBlock(final int x, final int y, final int z) {
+        return this.isAirBlock(new TilePos(x, y, z));
     }
 
-    public boolean areBlocksLoaded(int minX, int minY, int minZ, int maxX, int maxY, int maxZ)
-    {
-        if(maxY < 0 || minY >= getHeightBlocks())
-        {
+    public boolean isBlockLoaded(final @NotNull TilePos tilePos) {
+        if (!tilePos.inBounds(this)) {
             return false;
+        } else {
+            return this.isChunkLoaded(tilePos.toChunkPos());
         }
+    }
+
+    @Deprecated
+    public final boolean isBlockLoaded(final int x, final int y, final int z) {
+        return this.isBlockLoaded(new TilePos(x, y, z));
+    }
+
+    public boolean areBlocksLoaded(final @NotNull TilePos tilePos, final int range) {
+        return this.areBlocksLoaded(tilePos.sub(range, range, range), tilePos.add(range, range, range));
+    }
+
+    @Deprecated
+    public final boolean areBlocksLoaded(final int x, final int y, final int z, final int range) {
+        return this.areBlocksLoaded(new TilePos(x, y, z), range);
+    }
+
+    public boolean areBlocksLoaded(final @NotNull TilePos min, final @NotNull TilePos max) {
+        int minX = Math.min(min.x, max.x);
+        int minZ = Math.min(min.z, max.z);
+        int maxX = Math.max(min.x, max.x);
+        int maxZ = Math.max(min.z, max.z);
+
         minX >>= 4;
         minZ >>= 4;
         maxX >>= 4;
         maxZ >>= 4;
-        for (int chunkX = minX; chunkX <= maxX; chunkX++)
-        {
-            for (int chunkZ = minZ; chunkZ <= maxZ; chunkZ++)
-            {
-                if (!isChunkLoaded(chunkX, chunkZ))
-                {
+
+        final @NotNull ChunkPos chunkPos = new ChunkPos(minX, minZ);
+
+        for (; chunkPos.x <= maxX; chunkPos.x++) {
+            for (; chunkPos.z <= maxZ; chunkPos.z++) {
+                if (!this.isChunkLoaded(chunkPos)) {
                     return false;
                 }
             }
@@ -652,481 +628,397 @@ public class World implements WorldSource {
         return true;
     }
 
-    public boolean isChunkLoaded(int x, int z)
-    {
-        return chunkProvider.isChunkLoaded(x, z);
+    @Deprecated
+    public final boolean areBlocksLoaded(final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ) {
+        return this.areBlocksLoaded(new TilePos(minX, minY, minZ), new TilePos(maxX, maxY, maxZ));
     }
 
-    public Chunk getChunkFromBlockCoords(int x, int z)
-    {
-        return getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
+    public boolean isChunkLoaded(final @NotNull ChunkPos chunkPos) {
+        return this.chunkProvider.isChunkLoaded(chunkPos.x, chunkPos.z);
     }
 
-    public Chunk getChunkFromChunkCoords(int x, int z)
-    {
-        return chunkProvider.provideChunk(x, z);
+    @Deprecated
+    public final boolean isChunkLoaded(final int x, final int z) {
+        return this.isChunkLoaded(new ChunkPos(x, z));
     }
 
-    public boolean setBlockAndMetadata(int x, int y, int z, int id, int meta)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
-            return false;
-        }
-        if(y < 0)
-        {
-            return false;
-        }
-        if(y >= getHeightBlocks())
-        {
-            return false;
-        } else
-        {
-            Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-            return chunk.setBlockIDWithMetadata(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), id, meta);
-        }
+    public @NotNull Chunk getChunk(final @NotNull TilePos tilePos) {
+        return this.getChunk(tilePos.toChunkPos());
     }
 
-    public boolean setBlockRaw(int x, int y, int z, int id) {
-        return setBlockAndMetadataRaw(x, y, z, id, getBlockMetadata(x, y, z));
+    @Deprecated
+    public final @NotNull Chunk getChunkFromBlockCoords(final int x, final int z) {
+        return this.getChunk(new TilePos(x, 0, z));
     }
-    public boolean setBlockAndMetadataRaw(int x, int y, int z, int id, int meta)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
-            return false;
-        }
-        if(y < 0)
-        {
-            return false;
-        }
-        if(y >= getHeightBlocks())
-        {
-            return false;
-        } else
-        {
-            Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-            return chunk.setBlockIDWithMetadataRaw(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), id, meta);
-        }
+
+    public @NotNull Chunk getChunk(final @NotNull ChunkPos chunkPos) {
+        return this.chunkProvider.provideChunk(chunkPos.x, chunkPos.z);
     }
 
-    public boolean setBlock(int x, int y, int z, int id)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
+    @Deprecated
+    public final @NotNull Chunk getChunkFromChunkCoords(final int x, final int z) {
+        return this.getChunk(new ChunkPos(x, z));
+    }
+
+    @Override
+    public boolean setBlockIdData(final @NotNull TilePos tilePos, final int id, final int data) {
+        if (!tilePos.inBounds(this)) {
             return false;
+        } else {
+            return this.getChunk(tilePos).setBlockIdData(tilePos.toChunkTilePos(), id, data);
         }
-        if(y < 0)
-        {
+    }
+
+    public boolean setBlockIdRaw(final @NotNull TilePos tilePos, final int id) {
+        return this.setBlockIdDataRaw(tilePos, id, this.getBlockData(tilePos));
+    }
+
+    @Deprecated
+    public final boolean setBlockRaw(final int x, final int y, final int z, final int id) {
+        return this.setBlockIdRaw(new TilePos(x, y, z), id);
+    }
+
+    public boolean setBlockIdDataRaw(final @NotNull TilePos tilePos, final int id, final int data) {
+        if (!tilePos.inBounds(this)) {
             return false;
+        } else {
+            return this.getChunk(tilePos).setBlockIdDataRaw(tilePos.toChunkTilePos(), id, data);
         }
-        if(y >= getHeightBlocks())
-        {
+    }
+
+    @Deprecated
+    public final boolean setBlockAndMetadataRaw(final int x, final int y, final int z, final int id, final int metadata) {
+        return this.setBlockIdDataRaw(new TilePos(x, y, z), id, metadata);
+    }
+
+    @Override
+    public boolean setBlockId(@NotNull final TilePos tilePos, final int id) {
+        if (!tilePos.inBounds(this)) {
             return false;
-        } else
-        {
-            Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-            return chunk.setBlockID(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), id);
+        } else {
+            return this.getChunk(tilePos).setBlockId(tilePos.toChunkTilePos(), id);
         }
     }
 
     @Override
-    public Material getBlockMaterial(int x, int y, int z)
-    {
-        int l = getBlockId(x, y, z);
-        if(l == 0)
-        {
+    public @NotNull Material getBlockMaterial(@NotNull final TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        if (block == null) {
             return Material.air;
-        } else
-        {
-            return Blocks.blocksList[l].getMaterial();
+        } else {
+            return block.getMaterial();
         }
     }
 
     @Override
-    public int getBlockMetadata(int x, int y, int z)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
-            return 0;
-        }
-        if(y < 0)
-        {
-            return 0;
-        }
-        if(y >= getHeightBlocks())
-        {
+    public int getBlockData(final @NotNull TilePos tilePos) {
+        if (!tilePos.inBounds(this)) {
             return 0;
-        } else
-        {
-            Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-            x &= (Chunk.CHUNK_SIZE_X - 1);
-            z &= (Chunk.CHUNK_SIZE_Z - 1);
-            return chunk.getBlockMetadata(x, y, z);
+        } else {
+            return this.getChunk(tilePos).getBlockData(tilePos.toChunkTilePos());
         }
     }
 
-    public void setBlockMetadataWithNotify(int x, int y, int z, int meta)
-    {
-        if(setBlockMetadata(x, y, z, meta))
-        {
-            markBlockNeedsUpdate(x, y, z);
-            int id = getBlockId(x, y, z);
-            // TODO The name neighborNotifyOnMetadataChangeDisabled suggests that this should be inverted, but doing that breaks redstone
-            if(Blocks.neighborNotifyOnMetadataChangeDisabled[id & 0x3fff])
-            {
-                notifyBlocksOfNeighborChange(x, y, z, id);
+    public boolean setBlockDataNotify(final @NotNull TilePos tilePos, final int data) {
+        if (this.setBlockData(tilePos, data)) {
+            this.markBlockNeedsUpdate(tilePos);
+
+            final int id = this.getBlockId(tilePos);
+            if (Blocks.neighborNotifyOnMetadataChangeDisabled[id & 0x3FFF]) {
+                this.notifyBlocksOfNeighborChange(tilePos, id);
+                return true;
             }
         }
+
+        return false;
     }
 
-    public boolean setBlockMetadata(int x, int y, int z, int meta)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
-            return false;
-        }
-        if(y < 0)
-        {
-            return false;
-        }
-        if(y >= getHeightBlocks())
-        {
+    @Deprecated
+    public final void setBlockMetadataWithNotify(final int x, final int y, final int z, final int data) {
+        this.setBlockDataNotify(new TilePos(x, y, z), data);
+    }
+
+    @Override
+    public boolean setBlockData(final @NotNull TilePos tilePos, final int data) {
+        if (!tilePos.inBounds(this)) {
             return false;
-        } else
-        {
-            Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-            x &= (Chunk.CHUNK_SIZE_X - 1);
-            z &= (Chunk.CHUNK_SIZE_Z - 1);
-            chunk.setBlockMetadata(x, y, z, meta);
+        } else {
+            this.getChunk(tilePos).setBlockData(tilePos.toChunkTilePos(), data);
             return true;
         }
     }
 
-    public boolean setBlockWithNotify(int x, int y, int z, int id)
-    {
-        if(setBlock(x, y, z, id))
-        {
-            notifyBlockChange(x, y, z, id);
+    public boolean setBlockIdNotify(final @NotNull TilePos tilePos, final int id) {
+        if (this.setBlockId(tilePos, id)) {
+            this.notifyBlockChange(tilePos, id);
             return true;
-        } else
-        {
-            return false;
         }
+
+        return false;
     }
 
-    public boolean setBlockAndMetadataWithNotify(int x, int y, int z, int id, int meta)
-    {
-        if(setBlockAndMetadata(x, y, z, id, meta))
-        {
-            notifyBlockChange(x, y, z, id);
+    @Deprecated
+    public final boolean setBlockWithNotify(final int x, final int y, final int z, final int id) {
+        return this.setBlockIdNotify(new TilePos(x, y, z), id);
+    }
+
+    public boolean setBlockIdDataNotify(final @NotNull TilePos tilePos, final int id, final int data) {
+        if (this.setBlockIdData(tilePos, id, data)) {
+            this.notifyBlockChange(tilePos, id);
             return true;
-        } else
-        {
-            return false;
         }
+
+        return false;
     }
 
-    public void markBlockNeedsUpdate(int x, int y, int z)
-    {
-        for (LevelListener listener : listeners)
-        {
-            listener.blockChanged(x, y, z);
+    @Deprecated
+    public final boolean setBlockAndMetadataWithNotify(final int x, final int y, final int z, final int id, final int data) {
+        return this.setBlockIdDataNotify(new TilePos(x, y, z), id, data);
+    }
+
+    public void markBlockNeedsUpdate(final @NotNull TilePos tilePos) {
+        for (final @NotNull LevelListener listener : this.listeners) {
+            listener.blockChanged(tilePos.x, tilePos.y, tilePos.z);
         }
     }
 
-    public void notifyBlockChange(int x, int y, int z, int id)
-    {
-        markBlockNeedsUpdate(x, y, z);
-        notifyBlocksOfNeighborChange(x, y, z, id);
+    @Deprecated
+    public final void markBlockNeedsUpdate(final int x, final int y, final int z) {
+        this.markBlockNeedsUpdate(new TilePos(x, y, z));
     }
 
-    public void markBlocksDirtyVertical(int x, int z, int y0, int y1)
-    {
-        if(y0 > y1)
-        {
-            int t = y1;
-            y1 = y0;
-            y0 = t;
-        }
-        markBlocksDirty(x, y0, z, x, y1, z);
+    public void notifyBlockChange(final @NotNull TilePos tilePos, final int id) {
+        this.markBlockNeedsUpdate(tilePos);
+        this.notifyBlocksOfNeighborChange(tilePos, id);
     }
 
-    public void markBlockDirty(int x, int y, int z)
-    {
-        for (LevelListener listener : listeners)
-        {
-            listener.setBlocksDirty(x, y, z, x, y, z);
+    @Deprecated
+    public final void notifyBlockChange(final int x, final int y, final int z, final int id) {
+        this.notifyBlockChange(new TilePos(x, y, z), id);
+    }
+
+    public void markBlocksDirtyVertical(final int x, final int z, final int y0, final int y1) {
+        this.markBlocksDirty(new TilePos(x, Math.min(y0, y1), z), new TilePos(x, Math.max(y0, y1), z));
+    }
+
+    public void markBlockDirty(final @NotNull TilePos tilePos) {
+        for (final @NotNull LevelListener listener : this.listeners) {
+            listener.setBlocksDirty(tilePos.x, tilePos.y, tilePos.z, tilePos.x, tilePos.y, tilePos.z);
         }
     }
 
-    public void markBlocksDirty(int minX, int minY, int minZ, int maxX, int maxY, int maxZ)
-    {
-        for (LevelListener listener : listeners)
-        {
-            listener.setBlocksDirty(minX, minY, minZ, maxX, maxY, maxZ);
+    @Deprecated
+    public final void markBlockDirty(final int x, final int y, final int z) {
+        this.markBlockDirty(new TilePos(x, y, z));
+    }
+
+    public void markBlocksDirty(final @NotNull TilePos min, final @NotNull TilePos max) {
+        for (final @NotNull LevelListener listener : this.listeners) {
+            listener.setBlocksDirty(
+                Math.min(min.x, max.x),
+                Math.min(min.y, max.y),
+                Math.min(min.z, max.z),
+                Math.max(min.x, max.x),
+                Math.max(min.y, max.y),
+                Math.max(min.z, max.z)
+            );
         }
     }
 
-    public void notifyBlocksOfNeighborChange(int x, int y, int z, int blockId)
-    {
-        notifyBlockOfNeighborChange(x - 1, y, z, blockId);
-        notifyBlockOfNeighborChange(x + 1, y, z, blockId);
-        notifyBlockOfNeighborChange(x, y - 1, z, blockId);
-        notifyBlockOfNeighborChange(x, y + 1, z, blockId);
-        notifyBlockOfNeighborChange(x, y, z - 1, blockId);
-        notifyBlockOfNeighborChange(x, y, z + 1, blockId);
+    @Deprecated
+    public final void markBlocksDirty(final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ) {
+        this.markBlocksDirty(new TilePos(minX, minY, minZ), new TilePos(maxX, maxY, maxZ));
     }
 
-    private void notifyBlockOfNeighborChange(int x, int y, int z, int blockId)
-    {
-        if(noNeighborUpdate || isClientSide)
-        {
+    public void notifyBlocksOfNeighborChange(final @NotNull TilePos tilePos, final int id) {
+        this.notifyBlockOfNeighborChange(tilePos.west(), id);
+        this.notifyBlockOfNeighborChange(tilePos.east(), id);
+        this.notifyBlockOfNeighborChange(tilePos.down(), id);
+        this.notifyBlockOfNeighborChange(tilePos.up(), id);
+        this.notifyBlockOfNeighborChange(tilePos.north(), id);
+        this.notifyBlockOfNeighborChange(tilePos.south(), id);
+    }
+
+    @Deprecated
+    public final void notifyBlocksOfNeighborChange(final int x, final int y, final int z, final int id) {
+        this.notifyBlocksOfNeighborChange(new TilePos(x, y, z), id);
+    }
+
+    private void notifyBlockOfNeighborChange(final @NotNull TilePos tilePos, final int id) {
+        if (this.noNeighborUpdate || this.isClientSide) {
             return;
         }
-        Block<?> block = Blocks.blocksList[getBlockId(x, y, z)];
-        if(block != null)
-        {
-            block.onNeighborBlockChange(this, x, y, z, blockId);
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        if (block != null) {
+            block.onNeighborBlockChange(this, tilePos.x, tilePos.y, tilePos.z, id);
         }
     }
 
-    public boolean canBlockSeeTheSky(int x, int y, int z)
-    {
-        return getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z)).canBlockSeeTheSky(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
+    public boolean canBlockSeeSky(final @NotNull TilePos tilePos) {
+        return this.getChunk(tilePos).canBlockSeeSky(tilePos.toChunkTilePos());
     }
 
-    public int getFullBlockLightValue(int x, int y, int z)
-    {
-        if(y < 0)
-        {
+    @Deprecated
+    public final boolean canBlockSeeTheSky(final int x, final int y, final int z) {
+        return this.canBlockSeeSky(new TilePos(x, y, z));
+    }
+
+    public int getFullBlockLightValue(final @NotNull TilePos tilePos) {
+        if (tilePos.y < 0) {
             return 0;
+        } else {
+            return this.getChunk(tilePos).getRawBrightness(new TilePos(tilePos.x, Math.min(tilePos.y, this.getHeightBlocks() - 1), tilePos.z).toChunkTilePos(), 0);
         }
-        if(y >= getHeightBlocks())
-        {
-            y = getHeightBlocks() - 1;
-        }
-        return getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z)).getRawBrightness(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), 0);
     }
 
-    public int getBlockLightValue(int x, int y, int z)
-    {
-        return getBlockLightValue_do(x, y, z, true);
+    @Deprecated
+    public final int getFullBlockLightValue(final int x, final int y, final int z) {
+        return this.getFullBlockLightValue(new TilePos(x, y, z));
     }
 
-    public int getBlockLightValue_do(int x, int y, int z, boolean first)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
+    public int getBlockLightValue(final @NotNull TilePos tilePos) {
+        return this.getBlockLightValue_do(tilePos, true);
+    }
+
+    @Deprecated
+    public final int getBlockLightValue(final int x, final int y, final int z) {
+        return this.getBlockLightValue(new TilePos(x, y, z));
+    }
+
+    private int getBlockLightValue_do(final @NotNull TilePos tilePos, final boolean first) {
+        if (tilePos.x < MIN_BLOCK_X || tilePos.z < MIN_BLOCK_Z || tilePos.x > MAX_BLOCK_X || tilePos.z > MAX_BLOCK_Z) {
             return MAX_BRIGHTNESS;
         }
-        if(first)
-        {
-            if(getBlockLitInteriorSurface(x, y, z))
-            {
-                int i1 = getBlockLightValue_do(x, y + 1, z, false);
-                int j1 = getBlockLightValue_do(x + 1, y, z, false);
-                int k1 = getBlockLightValue_do(x - 1, y, z, false);
-                int l1 = getBlockLightValue_do(x, y, z + 1, false);
-                int i2 = getBlockLightValue_do(x, y, z - 1, false);
-                if(j1 > i1)
-                {
-                    i1 = j1;
-                }
-                if(k1 > i1)
-                {
-                    i1 = k1;
-                }
-                if(l1 > i1)
-                {
-                    i1 = l1;
-                }
-                if(i2 > i1)
-                {
-                    i1 = i2;
-                }
-                return i1;
+
+        if (first) {
+            if (this.getBlockLitInteriorSurface(tilePos)) {
+                final int lightUp = this.getBlockLightValue_do(tilePos.up(), false);
+                final int lightEast = this.getBlockLightValue_do(tilePos.east(), false);
+                final int lightWest = this.getBlockLightValue_do(tilePos.west(), false);
+                final int lightSouth = this.getBlockLightValue_do(tilePos.south(), false);
+                final int lightNorth = this.getBlockLightValue_do(tilePos.north(), false);
+                return Math.max(lightUp, Math.max(lightEast, Math.max(lightWest, Math.max(lightSouth, lightNorth))));
             }
         }
-        if(y < 0)
-        {
+
+        if (tilePos.y < 0) {
             return 0;
         }
-        if(y >= getHeightBlocks())
-        {
-            y = getHeightBlocks() - 1;
-        }
-        Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-        x &= (Chunk.CHUNK_SIZE_X - 1);
-        z &= (Chunk.CHUNK_SIZE_Z - 1);
-        return chunk.getRawBrightness(x, y, z, skyDarken);
+        return this.getChunk(tilePos).getRawBrightness(new TilePos(tilePos.x, Math.min(tilePos.y, this.getHeightBlocks() - 1), tilePos.z).toChunkTilePos(), this.skyDarken);
     }
 
-    public boolean canExistingBlockSeeTheSky(int x, int y, int z)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
-            return false;
-        }
-        if(y < 0)
-        {
-            return false;
-        }
-        if(y >= getHeightBlocks())
-        {
+    public boolean canLoadedBlockSeeSky(final @NotNull TilePos tilePos) {
+        if (tilePos.y >= this.getHeightBlocks()) {
             return true;
-        }
-        if(!isChunkLoaded(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z)))
-        {
+        } else if (!tilePos.inBounds(this)) {
+            return false;
+        } else if (!this.isBlockLoaded(tilePos)) {
             return false;
-        } else
-        {
-            Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-            x &= (Chunk.CHUNK_SIZE_X - 1);
-            z &= (Chunk.CHUNK_SIZE_Z - 1);
-            return chunk.canBlockSeeTheSky(x, y, z);
         }
+
+        return this.getChunk(tilePos).canBlockSeeSky(tilePos.toChunkTilePos());
     }
 
-    public int getHeightValue(int x, int z)
-    {
-        if(x < World.MIN_BLOCK_X || z < World.MIN_BLOCK_Z || x >= World.MAX_BLOCK_X || z > World.MAX_BLOCK_Z)
-        {
+    @Deprecated
+    public final boolean canExistingBlockSeeTheSky(final int x, final int y, final int z) {
+        return this.canLoadedBlockSeeSky(new TilePos(x, y, z));
+    }
+
+    public int getHeightValue(final int x, final int z) {
+        if (x < World.MIN_BLOCK_X || z < World.MIN_BLOCK_Z || x > World.MAX_BLOCK_X || z > World.MAX_BLOCK_Z) {
             return 0;
         }
-        if(!isChunkLoaded(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z)))
-        {
+        final @NotNull TilePos tilePos = new TilePos(x, 0, z);
+
+        if (!this.isBlockLoaded(new TilePos(x, 0, z))) {
             return 0;
-        }
-        else
-        {
-            Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-            return chunk.getHeightValue(x & (Chunk.CHUNK_SIZE_X - 1), z & (Chunk.CHUNK_SIZE_Z - 1));
+        } else {
+            return this.getChunk(tilePos).getHeightValue(x & (Chunk.CHUNK_SIZE_X - 1), z & (Chunk.CHUNK_SIZE_Z - 1));
         }
     }
 
     @Override
-    public int getSavedLightValue(LightLayer layer, int x, int y, int z)
-    {
-        if(y < 0)
-        {
-            y = 0;
-        }
-        if(y >= getHeightBlocks())
-        {
-            y = getHeightBlocks() - 1;
-        }
-        if(y < 0 || y >= getHeightBlocks() || x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
-            return layer.defaultLightLevel;
-        }
-        int l = Math.floorDiv(x, Chunk.CHUNK_SIZE_X);
-        int i1 = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z);
-        if(!isChunkLoaded(l, i1))
-        {
+    public int getSavedLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePos tilePos) {
+        if (!tilePos.inBounds(this)) {
+            return lightLayer.defaultLightLevel;
+        } else if (!this.isBlockLoaded(tilePos)) {
             return 0;
-        }
-        else
-        {
-            Chunk chunk = getChunkFromChunkCoords(l, i1);
-            return chunk.getBrightness(layer, x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
+        } else {
+            return this.getChunk(tilePos).getBrightness(lightLayer, tilePos.toChunkTilePos());
         }
     }
 
     @Override
     public boolean isRetro() {
-        return worldType.isRetro();
+        return this.worldType.isRetro();
     }
 
-    public void setLightValue(LightLayer layer, int x, int y, int z, int value)
-    {
-        if(x < MIN_BLOCK_X || z < MIN_BLOCK_Z || x >= MAX_BLOCK_X || z > MAX_BLOCK_Z)
-        {
-            return;
-        }
-        if(y < 0)
-        {
-            return;
-        }
-        if(y >= getHeightBlocks())
-        {
-            return;
-        }
-        if(!isChunkLoaded(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z)))
-        {
-            return;
-        }
-        Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-        chunk.setBrightness(layer, x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), value);
-        for (LevelListener listener : listeners)
-        {
-            listener.blockChanged(x, y, z);
+    @Override
+    public void setLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePos tilePos, final int value) {
+        if (tilePos.inBounds(this) && this.isBlockLoaded(tilePos)) {
+            this.getChunk(tilePos).setBrightness(lightLayer, tilePos.toChunkTilePos(), value);
+            for (final @NotNull LevelListener listener : this.listeners) {
+                listener.blockChanged(tilePos.x, tilePos.y, tilePos.z);
+            }
         }
     }
 
-	@Override
-	public float getBrightness(int x, int y, int z, int blockLightValue) {
-		int i1 = getBlockLightValue(x, y, z);
-		if(i1 < blockLightValue) {
-			i1 = blockLightValue;
-		}
-		return worldType.getBrightnessRamp()[i1];
-	}
-    
     @Override
-    public int getLightmapCoord(int x, int y, int z, int blockLightValue) {
-        int skyLight = getSavedLightValue(LightLayer.Sky, x, y, z);
-        int blockLight = Math.max(getSavedLightValue(LightLayer.Block, x, y, z), blockLightValue);
+    public float getBrightness(final @NotNull TilePos tilePos, final int lightEmission) {
+        final int lightValue = this.getBlockLightValue(tilePos);
+        return this.worldType.getBrightnessRamp()[Math.max(lightValue, lightEmission)];
+    }
+
+    @Override
+    public int getLightmapCoord(final @NotNull TilePos tilePos, final int lightEmission) {
+        int skyLight = this.getSavedLightValue(LightLayer.Sky, tilePos);
+        int blockLight = Math.max(this.getSavedLightValue(LightLayer.Block, tilePos), lightEmission);
 
-        if(getBlockLitInteriorSurface(x, y, z)) {
-            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, x, y + 1, z));
-            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, x, y - 1, z));
-            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, x + 1, y, z));
-            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, x - 1, y, z));
-            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, x, y, z + 1));
-            skyLight = Math.max(skyLight, getSavedLightValue(LightLayer.Sky, x, y, z - 1));
+        if (this.getBlockLitInteriorSurface(tilePos)) {
+            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.up()));
+            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.down()));
+            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.east()));
+            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.west()));
+            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.south()));
+            skyLight = Math.max(skyLight, this.getSavedLightValue(LightLayer.Sky, tilePos.north()));
 
-            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, x, y + 1, z));
-            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, x, y - 1, z));
-            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, x + 1, y, z));
-            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, x - 1, y, z));
-            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, x, y, z + 1));
-            blockLight = Math.max(blockLight, getSavedLightValue(LightLayer.Block, x, y, z - 1));
+            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.up()));
+            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.down()));
+            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.east()));
+            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.west()));
+            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.south()));
+            blockLight = Math.max(blockLight, this.getSavedLightValue(LightLayer.Block, tilePos.north()));
         }
 
-        return getLightmapCoord(skyLight, blockLight);
+        return this.getLightmapCoord(skyLight, blockLight);
     }
 
     @Override
-    public int getLightmapCoord(int skylight, int blocklight) {
+    public int getLightmapCoord(final int skyLight, final int blockLight) {
         return 0; // TODO figure out if/how we would get this working in core
     }
 
     @Override
-    public float getLightBrightness(int x, int y, int z)
-    {
-        return worldType.getBrightnessRamp()[getBlockLightValue(x, y, z)];
+    public float getLightBrightness(final @NotNull TilePos tilePos) {
+        return this.worldType.getBrightnessRamp()[this.getBlockLightValue(tilePos)];
     }
 
-    public boolean isDaytime()
-    {
-        return skyDarken < 4;
+    public boolean isDaytime() {
+        return this.skyDarken < 4;
     }
 
-    @Nullable
-    public HitResult checkBlockCollisionBetweenPoints(Vec3 start, Vec3 end)
+    public @Nullable HitResult checkBlockCollisionBetweenPoints(Vec3 start, Vec3 end)
     {
         return checkBlockCollisionBetweenPoints(start, end, false, false, false);
     }
 
-    @Nullable
-    public HitResult checkBlockCollisionBetweenPoints(Vec3 start, Vec3 end, boolean shouldCollideWithFluids)
+
+    public @Nullable HitResult checkBlockCollisionBetweenPoints(Vec3 start, Vec3 end, boolean shouldCollideWithFluids)
     {
         return checkBlockCollisionBetweenPoints(start, end, shouldCollideWithFluids, false, false);
     }
 
-    @Nullable
-    public HitResult checkBlockCollisionBetweenPoints(Vec3 start, Vec3 end, boolean shouldCollideWithFluids, boolean ignoreNonColliderBlocks, boolean useSelectorBoxes)
+    public @Nullable HitResult checkBlockCollisionBetweenPoints(Vec3 start, Vec3 end, boolean shouldCollideWithFluids, boolean ignoreNonColliderBlocks, boolean useSelectorBoxes)
     {
         if(Double.isNaN(start.x) || Double.isNaN(start.y) || Double.isNaN(start.z))
         {
@@ -1336,48 +1228,50 @@ public class World implements WorldSource {
         playSoundEffect(player, SoundCategory.WORLD_SOUNDS, x, y, z, name, soundType.modifyVolume(sound.getVolume()), soundType.modifyPitch(sound.getPitch()));
     }
 
-    public void playRecord(String soundPath, String author, int x, int y, int z)
-    {
-        for(int l = 0; l < listeners.size(); l++)
-        {
-            listeners.get(l).playStreamingMusic(soundPath, author, x, y, z);
+    public void playRecord(final @Nullable String soundPath, final @Nullable String author, final @NotNull TilePos tilePos) {
+        for (final @NotNull LevelListener listener : listeners) {
+            listener.playStreamingMusic(soundPath, author, tilePos.x, tilePos.y, tilePos.z);
         }
+    }
 
+    @Deprecated
+    public final void playRecord(final @Nullable String soundPath, final @Nullable String author, final int x, final int y, final int z) {
+        this.playRecord(soundPath, author, new TilePos(x, y, z));
     }
 
-    public void spawnParticle(String particleKey, double x, double y, double z,
-                              double motionX, double motionY, double motionZ, int data, double maxDistance)
-    {
-        for(int i = 0; i < listeners.size(); i++)
-        {
-            listeners.get(i).addParticle(particleKey, x, y, z, motionX, motionY, motionZ, data, maxDistance);
+    public void spawnParticle(
+        final @NotNull String particleKey,
+        final double x, final double y, final double z,
+        final double motionX, final double motionY, final double motionZ,
+        final int data,
+        final double maxDistance
+    ) {
+        for (final @NotNull LevelListener listener : this.listeners) {
+            listener.addParticle(particleKey, x, y, z, motionX, motionY, motionZ, data, maxDistance);
         }
-
     }
 
-
-    public void spawnParticle(String particleKey, double x, double y, double z,
-                              double motionX, double motionY, double motionZ, int data)
-    {
-        for(int i = 0; i < listeners.size(); i++)
-        {
-            listeners.get(i).addParticle(particleKey, x, y, z, motionX, motionY, motionZ, data);
+    public void spawnParticle(
+        final @NotNull String particleKey,
+        final double x, final double y, final double z,
+        final double motionX, final double motionY, final double motionZ,
+        final int data
+    ) {
+        for (final @NotNull LevelListener listener : this.listeners) {
+            listener.addParticle(particleKey, x, y, z, motionX, motionY, motionZ, data);
         }
-
     }
 
-    public boolean addWeatherEffect(Entity entity)
-    {
-        weatherEffects.add(entity);
+    public boolean addWeatherEffect(final @NotNull Entity entity) {
+        this.weatherEffects.add(entity);
         return true;
     }
 
-    public void addRainbow(int rainbowTicks){
-        this.rainbowTicks = startingRainbowTicks = rainbowTicks;
+    public void addRainbow(final int rainbowTicks){
+        this.rainbowTicks = this.startingRainbowTicks = rainbowTicks;
     }
 
-    public boolean entityJoinedWorld(Entity entity)
-    {
+    public boolean entityJoinedWorld(Entity entity) {
         int i = MathHelper.floor(entity.x / Chunk.CHUNK_SIZE_X);
         int j = MathHelper.floor(entity.z / Chunk.CHUNK_SIZE_Z);
         boolean flag = entity instanceof Player;
@@ -1645,14 +1539,19 @@ public class World implements WorldSource {
         return f2 * f2 * 0.5F;
     }
 
-    public void scheduleBlockUpdate(int x, int y, int z, int id, long delay) {
-        this.scheduleBlockUpdate(x, y, z, id, delay, false);
+    public final void scheduleBlockUpdate(final @NotNull TilePos tilePos, final int id, final long delay) {
+        this.scheduleBlockUpdate(tilePos, id, delay, false);
+    }
+
+    @Deprecated
+    public final void scheduleBlockUpdate(final int x, final int y, final int z, final int id, final long delay) {
+        this.scheduleBlockUpdate(new TilePos(x, y, z), id, delay);
     }
 
-    public void scheduleBlockUpdate(int x, int y, int z, int id, long delay, boolean loaded) {
-        NextTickListEntry entry = new NextTickListEntry(x, y, z, id, getWorldTime());
+    public void scheduleBlockUpdate(final @NotNull TilePos tilePos, final int id, final long delay, final boolean loaded) {
+        NextTickListEntry entry = new NextTickListEntry(tilePos.x, tilePos.y, tilePos.z, id, getWorldTime());
         entry.loaded = loaded;
-        byte radius = 8;
+        final byte radius = 8;
 
         if(scheduledUpdatesAreImmediate && !immediatelyUpdatedPositions.contains(entry)) {
             if(entry.loaded || areBlocksLoaded(entry.x - radius, entry.y - radius, entry.z - radius, entry.x + radius, entry.y + radius, entry.z + radius)) {
@@ -1664,17 +1563,23 @@ public class World implements WorldSource {
             }
             return;
         }
-        if(entry.loaded || areBlocksLoaded(x - radius, y - radius, z - radius, x + radius, y + radius, z + radius)) {
+        if(entry.loaded || areBlocksLoaded(tilePos, radius)) {
             if(id > 0) {
                 entry.setDelay(delay);
             }
             if(!tickNextTickList.contains(entry)) {
                 tickNextTickList.add(entry);
-                final @NotNull Chunk chunk = Objects.requireNonNull(this.getChunkFromBlockCoords(x, z));
+                final @NotNull Chunk chunk = Objects.requireNonNull(this.getChunk(tilePos));
                 chunk.addTick(entry);
             }
         }
     }
+
+    @Deprecated
+    public final void scheduleBlockUpdate(final int x, final int y, final int z, final int id, final long delay, final boolean loaded) {
+        this.scheduleBlockUpdate(new TilePos(x, y, z), id, delay, loaded);
+    }
+
     public void updateEntities()
     {
         for(int i = 0; i < weatherEffects.size(); i++)
@@ -1735,7 +1640,7 @@ public class World implements WorldSource {
             releaseEntitySkin(entity2);
         }
 
-        updatingBlockEntities = true;
+        updatingTileEntities = true;
         for (int i = tileEntityList.size() - 1; i >= 0; i--) {
             TileEntity tileEntity = tileEntityList.get(i);
             if (!tileEntity.isInvalid() && isBlockLoaded(tileEntity.x, tileEntity.y, tileEntity.z)) {
@@ -1749,7 +1654,7 @@ public class World implements WorldSource {
                 }
             }
         }
-        updatingBlockEntities = false;
+        updatingTileEntities = false;
     }
 
     public void addAllBlockEntities(Collection<TileEntity> blockEntities)
@@ -1767,7 +1672,7 @@ public class World implements WorldSource {
         int i = MathHelper.floor(entity.x);
         int j = MathHelper.floor(entity.z);
         byte byte0 = 32;
-        if(flag && !areBlocksLoaded(i - byte0, 0, j - byte0, i + byte0, getHeightBlocks(), j + byte0))
+        if(flag && !areBlocksLoaded(i - byte0, 0, j - byte0, i + byte0, getHeightBlocks() - 1, j + byte0))
         {
             //try to despawn if entity wanders into nonexistant chunk
             if(entity instanceof Mob) {
@@ -2114,18 +2019,21 @@ public class World implements WorldSource {
         return (float)i / (float)j;
     }
 
-    public void onBlockHit(Player entityplayer, int x, int y, int z, Side side)
-    {
-        x += side.getOffsetX();
-        y += side.getOffsetY();
-        z += side.getOffsetZ();
-        if(getBlockId(x, y, z) == Blocks.FIRE.id() || getBlockId(x, y, z) == Blocks.FIRE_COLD.id())
-        {
-            playBlockEvent(entityplayer, LevelListener.EVENT_FIRE_EXTINGUISH, x, y, z, 0);
-            setBlockWithNotify(x, y, z, 0);
+    public void onBlockHit(final @NotNull Player player, final @NotNull TilePos tilePos, final @NotNull Side side) {
+        final @NotNull TilePos offsetPos = tilePos.add(side.getDirection());
+        final @Nullable Block<?> block = this.getBlock(offsetPos);
+
+        if (block == Blocks.FIRE || block == Blocks.FIRE_COLD) {
+            this.playBlockEvent(player, offsetPos, LevelListener.EVENT_FIRE_EXTINGUISH, 0);
+            this.setBlockIdNotify(tilePos, 0);
         }
     }
 
+    @Deprecated
+    public final void onBlockHit(final @NotNull Player player, final int x, final int y, final int z, final @NotNull Side side) {
+        this.onBlockHit(player, new TilePos(x, y, z), side);
+    }
+
     public @Nullable Entity getEntityByID(int id)
     {
         for(int i = 0; i < entities.size(); i++)
@@ -2151,107 +2059,80 @@ public class World implements WorldSource {
     }
 
     @Override
-    public TileEntity getTileEntity(int x, int y, int z)
-    {
-        Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-        if(chunk != null)
-        {
-            return chunk.getTileEntity(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
-        } else
-        {
-            return null;
-        }
+    public @Nullable TileEntity getTileEntity(final @NotNull TilePos tilePos) {
+        final @NotNull Chunk chunk = this.getChunk(tilePos);
+        return chunk.getTileEntity(tilePos.toChunkTilePos());
     }
 
-    public void setTileEntity(int x, int y, int z, TileEntity tileEntity)
-    {
-        if(!tileEntity.isInvalid())
-        {
-            Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-            if(chunk != null)
-            {
-                if (chunk.setTileEntity(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), tileEntity) && !tileEntityList.contains(tileEntity)) {
-                    tileEntityList.add(tileEntity);
-                }
+    @Override
+    public void setTileEntity(final @NotNull TilePos tilePos, final @NotNull TileEntity tileEntity) {
+        if (!tileEntity.isInvalid()) {
+            if (this.getChunk(tilePos).setTileEntity(tilePos.toChunkTilePos(), tileEntity) && !this.tileEntityList.contains(tileEntity)) {
+                this.tileEntityList.add(tileEntity);
             }
         }
     }
 
-    public void removeBlockTileEntity(int x, int y, int z)
-    {
-        TileEntity tileEntity = getTileEntity(x, y, z);
+    @Override
+    public void removeTileEntity(final @NotNull TilePos tilePos) {
+        final @Nullable TileEntity tileEntity = this.getTileEntity(tilePos);
 
-        if(tileEntity != null && updatingBlockEntities)
-        {
+        if (tileEntity != null && this.updatingTileEntities) {
             tileEntity.invalidate();
-        } else
-        {
-            if(tileEntity != null)
-            {
-                tileEntityList.remove(tileEntity);
-            }
-            Chunk chunk = getChunkFromChunkCoords(Math.floorDiv(x, Chunk.CHUNK_SIZE_X), Math.floorDiv(z, Chunk.CHUNK_SIZE_Z));
-            if(chunk != null)
-            {
-                chunk.removeTileEntity(tileEntity);
+        } else {
+            if (tileEntity != null) {
+                this.tileEntityList.remove(tileEntity);
             }
+
+            this.getChunk(tilePos).removeTileEntity(tileEntity);
         }
     }
 
-    public void replaceBlockTileEntity(int x, int y, int z, TileEntity tileEntity) {
-        removeBlockTileEntity(x, y, z);
-        setTileEntity(x, y, z, tileEntity);
+    @Override
+    public boolean isBlockOpaqueCube(final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        return block != null && block.isSolidRender();
     }
 
-    @Override
-    public boolean isBlockOpaqueCube(int x, int y, int z)
-    {
-        Block<?> block = Blocks.blocksList[getBlockId(x, y, z)];
-        if(block == null)
-        {
-            return false;
-        } else
-        {
-            return block.isSolidRender();
-        }
+    public boolean canPlaceOnSurfaceOfBlock(final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        return block != null && block.canPlaceOnSurfaceOnCondition(this, tilePos.x, tilePos.y, tilePos.z);
     }
 
-    public boolean canPlaceOnSurfaceOfBlock(int x, int y, int z)
-    {
-        Block<?> block = Blocks.blocksList[getBlockId(x, y, z)];
-        if(block == null)
-        {
-            return false;
-        } else
-        {
-            return block.canPlaceOnSurfaceOnCondition(this, x, y, z);
+    @Deprecated
+    public final boolean canPlaceOnSurfaceOfBlock(final int x, final int y, final int z) {
+        return this.canPlaceOnSurfaceOfBlock(new TilePos(x, y, z));
+    }
+
+    public @NotNull ISupport getSupport(final @NotNull TilePos tilePos, final @NotNull Side side) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        if (block == null) {
+            return PartialSupport.INSTANCE;
         }
+
+        return block.getSupport(this, tilePos.x, tilePos.y, tilePos.z, side);
     }
 
-    public @NotNull ISupport getSupport(int x, int y, int z, @NotNull Side side) {
-        Block<?> b = getBlock(x, y, z);
-        if (b == null) return PartialSupport.INSTANCE;
-        return b.getSupport(this, x, y, z, side);
+    @Deprecated
+    public final @NotNull ISupport getSupport(final int x, final int y, final int z, final @NotNull Side side) {
+        return this.getSupport(new TilePos(x, y, z), side);
     }
 
     @Override
-    public boolean isBlockNormalCube(int x, int y, int z)
-    {
-        // Determines if you suffocate in a block, among other things
-        Block<?> block = Blocks.blocksList[getBlockId(x, y, z)];
-        if(block == null)
-        {
-            return false;
-        } else
-        {
-            return block.getMaterial().isSolidBlocking() && block.renderAsNormalBlockOnCondition(this, x, y, z);
-        }
+    public boolean isBlockNormalCube(final @NotNull TilePos tilePos) {
+        // Determines if you suffocate in a block, among other things.
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        return block != null && block.getMaterial().isSolidBlocking() && block.renderAsNormalBlockOnCondition(this, tilePos.x, tilePos.y, tilePos.z);
+    }
+
+    public boolean canPlaceInsideBlock(final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        return block == null || block.hasTag(BlockTags.PLACE_OVERWRITES);
     }
-    
-    public boolean canPlaceInsideBlock(int x, int y, int z) {
-        int id = getBlockId(x, y, z);
 
-        return id == 0 || Blocks.getBlock(id).hasTag(BlockTags.PLACE_OVERWRITES);
+    @Deprecated
+    public final boolean canPlaceInsideBlock(final int x, final int y, final int z) {
+        return this.canPlaceInsideBlock(new TilePos(x, y, z));
     }
 
     public void onUnload()
@@ -2278,9 +2159,25 @@ public class World implements WorldSource {
         return this.lightingEngine.updatingLighting();
     }
 
-    public void scheduleLightingUpdate(final LightLayer layer, final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ)
-    {
-        this.lightingEngine.scheduleLightingUpdate(layer, minX, minY, minZ, maxX, maxY, maxZ);
+    public void scheduleLightingUpdate(final @NotNull LightLayer lightLayer, final @NotNull TilePos tilePos) {
+        this.scheduleLightingUpdate(lightLayer, tilePos, tilePos);
+    }
+
+    public void scheduleLightingUpdate(final @NotNull LightLayer lightLayer, final @NotNull TilePos min, final @NotNull TilePos max) {
+        this.lightingEngine.scheduleLightingUpdate(
+            lightLayer,
+            Math.min(min.x, max.x),
+            Math.min(min.y, max.y),
+            Math.min(min.z, max.z),
+            Math.max(min.x, max.x),
+            Math.max(min.y, max.y),
+            Math.max(min.z, max.z)
+        );
+    }
+
+    @Deprecated
+    public final void scheduleLightingUpdate(final @NotNull LightLayer lightLayer, final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ) {
+        this.scheduleLightingUpdate(lightLayer, new TilePos(minX, minY, minZ), new TilePos(maxX, maxY, maxZ));
     }
 
     public void updateSkyBrightness()
@@ -2497,21 +2394,27 @@ public class World implements WorldSource {
         return !tickNextTickList.isEmpty();
     }
 
-    public void randomDisplayUpdates(int x, int y, int z)
-    {
-        final byte radius = 16;
-        Random random = new Random();
-        for(int i = 0; i < ANIMATION_TICKS_PER_TICK; i++)
-        {
-            int rx = (x + rand.nextInt(radius)) - rand.nextInt(radius);
-            int ry = (y + rand.nextInt(radius)) - rand.nextInt(radius);
-            int rz = (z + rand.nextInt(radius)) - rand.nextInt(radius);
-            Block<?> block = getBlock(rx, ry, rz);
+    public void randomDisplayUpdates(final @NotNull TilePos tilePos) {
+        final int radius = 16;
+        final @NotNull Random random = new Random();
+
+        for(int i = 0; i < ANIMATION_TICKS_PER_TICK; i++) {
+            final @NotNull TilePos randomPos = tilePos.add(
+                this.rand.nextInt(radius) - this.rand.nextInt(radius),
+                this.rand.nextInt(radius) - this.rand.nextInt(radius),
+                this.rand.nextInt(radius) - this.rand.nextInt(radius)
+            );
+
+            final @Nullable Block<?> block = this.getBlock(randomPos);
             if (block != null) {
-                block.animationTick(this, rx, ry, rz, random);
+                block.animationTick(this, randomPos.x, randomPos.y, randomPos.z, random);
             }
         }
+    }
 
+    @Deprecated
+    public final void randomDisplayUpdates(final int x, final int y, final int z) {
+        this.randomDisplayUpdates(new TilePos(x, y, z));
     }
 
     public List<Entity> getEntitiesWithinAABBExcludingEntity(Entity entity, AABB aabb)
@@ -2567,18 +2470,21 @@ public class World implements WorldSource {
         return tileEntityList;
     }
 
-    public void updateTileEntityChunkAndSendToPlayer(int x, int y, int z, TileEntity tileEntity)
-    {
-        if(isBlockLoaded(x, y, z))
-        {
-            getChunkFromBlockCoords(x, z).setChunkModified();
+    public void updateTileEntityChunkAndSendToPlayer(final @NotNull TilePos tilePos, final @NotNull TileEntity tileEntity) {
+        if (this.isBlockLoaded(tilePos)) {
+            this.getChunk(tilePos).setChunkModified();
         }
-        for(int l = 0; l < listeners.size(); l++)
-        {
-            listeners.get(l).tileEntityChanged(x, y, z, tileEntity);
+
+        for (final @NotNull LevelListener listener : this.listeners) {
+            listener.tileEntityChanged(tilePos.x, tilePos.y, tilePos.z, tileEntity);
         }
     }
 
+    @Deprecated
+    public final void updateTileEntityChunkAndSendToPlayer(final int x, final int y, final int z, final @NotNull TileEntity tileEntity) {
+        this.updateTileEntityChunkAndSendToPlayer(new TilePos(x, y, z), tileEntity);
+    }
+
     public int countEntities(Class<?> clazz)
     {
         int i = 0;
@@ -2612,28 +2518,38 @@ public class World implements WorldSource {
         while(chunkProvider.tick());
     }
 
-    public boolean canBlockBePlacedAt(int blockId, int x, int y, int z, boolean flag, Side side)
-    {
-    	if(y < 0 || y >= getHeightBlocks()) {
-    		return false;
-    	}
-        int j1 = getBlockId(x, y, z);
-        Block<?> block = Blocks.blocksList[j1];
-        Block<?> block1 = Blocks.blocksList[blockId];
-        AABB axisalignedbb = block1.getCollisionBoundingBoxFromPool(this, x, y, z);
-        if(flag)
-        {
-            axisalignedbb = null;
+    public boolean canBlockIdBePlacedAt(final int id, final @NotNull TilePos tilePos, final boolean ignoreCollision, final @NotNull Side side) {
+        if (tilePos.y < 0 || tilePos.y >= this.getHeightBlocks()) {
+            return false;
         }
-        if(axisalignedbb != null && !checkIfAABBIsClear(axisalignedbb))
-        {
+
+        final @Nullable Block<?> currentBlock = this.getBlock(tilePos);
+        final @Nullable Block<?> newBlock = Blocks.blocksList[id];
+        if (newBlock == null) {
             return false;
         }
-        if(block != null && block.hasTag(BlockTags.PLACE_OVERWRITES))
-        {
-            block = null;
+
+        final @Nullable AABB bb;
+        if (ignoreCollision) {
+            bb = null;
+        } else {
+            bb = newBlock.getCollisionBoundingBoxFromPool(this, tilePos.x, tilePos.y, tilePos.z);
         }
-        return blockId > 0 && block == null && block1.canPlaceBlockOnSide(this, x, y, z, side);
+
+        if (bb != null && !this.checkIfAABBIsClear(bb)) {
+            return false;
+        }
+
+        if (currentBlock == null || currentBlock.hasTag(BlockTags.PLACE_OVERWRITES)) {
+            return newBlock.canPlaceBlockOnSide(this, tilePos.x, tilePos.y, tilePos.z, side);
+        } else {
+            return false;
+        }
+    }
+
+    @Deprecated
+    public final boolean canBlockBePlacedAt(final int id, final int x, final int y, final int z, final boolean ignoreCollision, final @NotNull Side side) {
+        return this.canBlockIdBePlacedAt(id, new TilePos(x, y, z), ignoreCollision, side);
     }
 
     public @Nullable Path getPathToEntity(Entity entity, Entity entityToTravelTo, float distance)
@@ -2652,62 +2568,74 @@ public class World implements WorldSource {
         return (new PathFinder(chunkcache)).findPath(entity, entityToTravelTo, distance);
     }
 
-    public @Nullable Path getEntityPathToXYZ(Entity entity, int x, int y, int z, float distance)
-    {
-        int eBlockX = MathHelper.floor(entity.x);
-        int eBlockY = MathHelper.floor(entity.y);
-        int eBlockZ = MathHelper.floor(entity.z);
-        int cacheRadius = (int)(distance + 8F);
-        int cacheMinX = eBlockX - cacheRadius;
-        int cacheMinY = eBlockY - cacheRadius;
-        int cacheMinZ = eBlockZ - cacheRadius;
-        int cacheMaxX = eBlockX + cacheRadius;
-        int cacheMaxY = eBlockY + cacheRadius;
-        int cacheMaxZ = eBlockZ + cacheRadius;
-        ChunkCache chunkcache = new ChunkCache(this, cacheMinX, cacheMinY, cacheMinZ, cacheMaxX, cacheMaxY, cacheMaxZ);
-        return (new PathFinder(chunkcache)).findPath(entity, x, y, z, distance);
+    public @Nullable Path getEntityPathToTilePos(final @NotNull Entity entity, final @NotNull TilePos tilePos, final float distance) {
+        final @NotNull TilePos entityPos = new TilePos(entity);
+        final int cacheRadius = (int) (distance + 8F);
+        final @NotNull TilePos cacheMin = entityPos.sub(cacheRadius, cacheRadius, cacheRadius);
+        final @NotNull TilePos cacheMax = entityPos.add(cacheRadius, cacheRadius, cacheRadius);
+
+        final @NotNull ChunkCache cache = new ChunkCache(this, cacheMin.x, cacheMin.y, cacheMin.z, cacheMax.x, cacheMax.y, cacheMax.z);
+        return new PathFinder(cache).findPath(entity, tilePos.x, tilePos.y, tilePos.z, distance);
     }
 
-    public boolean getDirectSignal(int x, int y, int z, Side side) {
-        Block<?> block = getBlock(x, y, z);
-        if (block == null) return false;
-        return block.getDirectSignal(this, x, y, z, side);
+    @Deprecated
+    public final @Nullable Path getEntityPathToXYZ(final @NotNull Entity entity, final int x, final int y, final int z, final float distance) {
+        return this.getEntityPathToTilePos(entity, new TilePos(x, y, z), distance);
     }
 
-    public boolean hasDirectSignal(int x, int y, int z) {
-        for (Side side : Side.sides){
-            if (getDirectSignal(
-                x + side.getOffsetX(),
-                y + side.getOffsetY(),
-                z + side.getOffsetZ(),
-                side))
-            {
+    public boolean hasDirectSignal(final @NotNull TilePos tilePos, final @NotNull Side side) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        return block != null && block.getDirectSignal(this, tilePos.x, tilePos.y, tilePos.z, side);
+    }
+
+    @Deprecated
+    public final boolean getDirectSignal(final int x, final int y, final int z, final @NotNull Side side) {
+        return this.hasDirectSignal(new TilePos(x, y, z), side);
+    }
+
+    public boolean hasDirectSignal(final @NotNull TilePos tilePos) {
+        for (final @NotNull Side side : Side.sides) {
+            if (this.hasDirectSignal(tilePos.add(side.getDirection()), side)) {
                 return true;
             }
         }
+
         return false;
     }
 
-    public boolean getSignal(int x, int y, int z, Side side) {
-        Block<?> block = getBlock(x, y, z);
-        if(isBlockNormalCube(x, y, z) && block != Blocks.BLOCK_REDSTONE  && block != Blocks.PUMPKIN_REDSTONE && block != Blocks.MATCHER_ACTIVE) {
-            return hasDirectSignal(x, y, z);
+    @Deprecated
+    public final boolean hasDirectSignal(final int x, final int y, final int z) {
+        return this.hasDirectSignal(new TilePos(x, y, z));
+    }
+
+    public boolean hasSignal(final @NotNull TilePos tilePos, final @NotNull Side side) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        if (this.isBlockNormalCube(tilePos) && block != Blocks.BLOCK_REDSTONE && block != Blocks.PUMPKIN_REDSTONE && block != Blocks.MATCHER_ACTIVE) {
+            return this.hasDirectSignal(tilePos);
         }
-        if(block == null) {
+        if (block == null) {
             return false;
         }
 
-        if (block == Blocks.PUMPKIN_REDSTONE) { // TODO make actual block methods to handle sided-ness
-            return pumpkinHasDirectSignal(x, y, z) || block.getSignal(this, x, y, z, side);
+        if (block == Blocks.PUMPKIN_REDSTONE) {
+            return this.pumpkinHasDirectSignal(tilePos) || block.getSignal(this, tilePos.x, tilePos.y, tilePos.z, side);
         } else {
-            return block.getSignal(this, x, y, z, side);
+            return block.getSignal(this, tilePos.x, tilePos.y, tilePos.z, side);
         }
     }
+
+    @Deprecated
+    public final boolean getSignal(final int x, final int y, final int z, final @NotNull Side side) {
+        return this.hasSignal(new TilePos(x, y, z), side);
+    }
+
     // Special version of hasDirectSignal that excludes the front side of the redstone lantern.
-    private boolean pumpkinHasDirectSignal(int x, int y, int z) {
-        for (Side side : Side.sides) {
-            if(Side.getSideById(getBlockMetadata(x, y, z)) == side) continue;
-            if (getDirectSignal(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side)) {
+    private boolean pumpkinHasDirectSignal(final @NotNull TilePos tilePos) {
+        for (final @NotNull Side side : Side.sides) {
+            if (Side.getSideById(this.getBlockData(tilePos)) == side) {
+                continue;
+            }
+            if (this.hasDirectSignal(tilePos.add(side.getDirection()), side)) {
                 return true;
             }
         }
@@ -2715,21 +2643,21 @@ public class World implements WorldSource {
         return false;
     }
 
-
-    public boolean hasNeighborSignal(int x, int y, int z) {
-        for (Side side : Side.sides){
-            if (getSignal(
-                x + side.getOffsetX(),
-                y + side.getOffsetY(),
-                z + side.getOffsetZ(),
-                side))
-            {
+    public boolean hasNeighborSignal(final @NotNull TilePos tilePos) {
+        for (final @NotNull Side side : Side.sides) {
+            if (this.hasSignal(tilePos.add(side.getDirection()), side)) {
                 return true;
             }
         }
+
         return false;
     }
 
+    @Deprecated
+    public final boolean hasNeighborSignal(final int x, final int y, final int z) {
+        return this.hasNeighborSignal(new TilePos(x, y, z));
+    }
+
     public Player getClosestPlayerToEntity(Entity entity, double radius)
     {
         return getClosestPlayer(entity.x, entity.y, entity.z, radius);
@@ -2965,11 +2893,15 @@ public class World implements WorldSource {
         }
     }
 
-    public boolean canMineBlock(final Player player, final int x, final int y, final int z)
-    {
+    public boolean canMineBlock(final @NotNull Player player, final @NotNull TilePos tilePos) {
         return true;
     }
 
+    @Deprecated
+    public final boolean canMineBlock(final @NotNull Player player, final int x, final int y, final int z) {
+        return this.canMineBlock(player, new TilePos(x, y, z));
+    }
+
     public void sendTrackedEntityStatusUpdatePacket(Entity entityId, byte entityStatus)
     {
     }
@@ -3035,14 +2967,17 @@ public class World implements WorldSource {
         return chunkProvider;
     }
 
-    public void triggerEvent(int x, int y, int z, int index, int data)
-    {
-        int j1 = getBlockId(x, y, z);
-        if(j1 > 0)
-        {
-            Blocks.blocksList[j1].triggerEvent(this, x, y, z, index, data);
+    public void triggerEvent(final @NotNull TilePos tilePos, final int index, final int data) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        if (block != null) {
+            block.triggerEvent(this, tilePos.x, tilePos.y, tilePos.z, index, data);
         }
     }
+
+    @Deprecated
+    public final void triggerEvent(final int x, final int y, final int z, final int index, final int data) {
+        this.triggerEvent(new TilePos(x, y, z), index, data);
+    }
     
     public LevelStorage getSaveHandler()
     {
@@ -3100,32 +3035,31 @@ public class World implements WorldSource {
         }
     }
 
-    public boolean canBlockBeRainedOn(int x, int y, int z)
-    {
-        if(getCurrentWeather() == null)
-        {
+    public boolean isBlockBeingRainedOn(final @NotNull TilePos tilePos) {
+        if (
+            this.getCurrentWeather() == null ||
+            !(this.getCurrentWeather() instanceof IPrecipitation) ||
+            !this.canBlockSeeSky(tilePos) ||
+            this.getHeightValue(tilePos.x, tilePos.z) > tilePos.y
+        ) {
             return false;
         }
-        if (!(getCurrentWeather() instanceof IPrecipitation))
-        {
-            return false;
-        }
-        if(!canBlockSeeTheSky(x, y, z))
-        {
-            return false;
-        }
-        if(getHeightValue(x, z) > y)
-        {
-            return false;
-        }
-        Biome biome = getBlockBiome(x, y, z);
-        for (int q = 0; q < biome.blockedWeathers.length; q++)
-        {
-            if (biome.blockedWeathers[q] == getCurrentWeather()) return false;
+
+        final @NotNull Biome biome = this.getBlockBiome(tilePos);
+        for (final @NotNull Weather weather : biome.blockedWeathers) {
+            if (weather == this.getCurrentWeather()) {
+                return false;
+            }
         }
+
         return true;
     }
 
+    @Deprecated
+    public final boolean canBlockBeRainedOn(final int x, final int y, final int z) {
+        return this.isBlockBeingRainedOn(new TilePos(x, y, z));
+    }
+
     public void setSavedData(String id, SavedData savedData)
     {
         savedDataStorage.set(id, savedData);
@@ -3141,36 +3075,50 @@ public class World implements WorldSource {
         return savedDataStorage.getFreeMetadataFor(s);
     }
 
-    public void playBlockEvent(int id, int x, int y, int z, int data)
-    {
-        playBlockEvent(null, id, x, y, z, data);
+    public void playBlockEvent(final @NotNull TilePos tilePos, final int id, final int data) {
+        this.playBlockEvent(null, tilePos, id, data);
     }
 
-    public void playBlockEvent(@Nullable Player player, int id, int x, int y, int z, int data)
-    {
-        for (LevelListener listener : listeners) {
-            listener.levelEvent(player, id, x, y, z, data);
+    @Deprecated
+    public final void playBlockEvent(final int id, final int x, final int y, final int z, final int data) {
+        this.playBlockEvent(new TilePos(x, y, z), id, data);
+    }
+
+    public void playBlockEvent(final @Nullable Player player, final @NotNull TilePos tilePos, final int id, final int data) {
+        for (final @NotNull LevelListener listener : this.listeners) {
+            listener.levelEvent(player, id, tilePos.x, tilePos.y, tilePos.z, data);
         }
+    }
 
+    @Deprecated
+    public final void playBlockEvent(final @Nullable Player player, final int id, final int x, final int y, final int z, final int data) {
+        this.playBlockEvent(player, new TilePos(x, y, z), id, data);
     }
     
-    public WorldType getWorldType()
+    public @NotNull WorldType getWorldType()
     {
         return worldType;
     }
 
-    public EntityItem dropItem(int x, int y, int z, ItemStack itemStack) {
-        float f = 0.7F;
-        double x1 = (double) (rand.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
-        double y1 = (double) (rand.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
-        double z1 = (double) (rand.nextFloat() * f) + (double) (1.0F - f) * 0.5D;
-        EntityItem item = new EntityItem(this, (double) x + x1, (double) y + y1, (double) z + z1, itemStack);
+    public @NotNull EntityItem dropItem(final @NotNull TilePos tilePos, final @NotNull ItemStack itemStack) {
+        final float radius = 0.7f;
+        final double x = (this.rand.nextFloat() * radius) + (1.0F - radius) * 0.5D;
+        final double y = (this.rand.nextFloat() * radius) + (1.0F - radius) * 0.5D;
+        final double z = (this.rand.nextFloat() * radius) + (1.0F - radius) * 0.5D;
+
+        final @NotNull EntityItem item = new EntityItem(this, tilePos.x + x, tilePos.y + y, tilePos.z + z, itemStack);
         item.pickupDelay = 10;
-        entityJoinedWorld(item);
+        this.entityJoinedWorld(item);
         return item;
     }
+
+    @Deprecated
+    public final @NotNull EntityItem dropItem(final int x, final int y, final int z, final @NotNull ItemStack itemStack) {
+        return this.dropItem(new TilePos(x, y, z), itemStack);
+    }
+
     public void sendGlobalMessage(String message){
-        for (Player player: players){
+        for (Player player : players){
             player.sendMessage(message);
         }
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/WorldSource.java b/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
index 1ebdfe1ef..67969e846 100644
--- a/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
+++ b/game/core/src/main/java/net/minecraft/core/world/WorldSource.java
@@ -6,49 +6,141 @@ import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.season.SeasonManager;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public interface WorldSource
-{
+public interface WorldSource {
+    int getHeightBlocks();
 
-    int getBlockId(int x, int y, int z);
+    int getBlockId(final @NotNull TilePos tilePos);
 
-    @Nullable Block<?> getBlock(int x, int y, int z);
+    @Deprecated
+    default int getBlockId(final int x, final int y, final int z) {
+        return this.getBlockId(new TilePos(x, y, z));
+    }
+
+    @Nullable Block<?> getBlock(final @NotNull TilePos tilePos);
+
+    @Deprecated
+    default @Nullable Block<?> getBlock(final int x, final int y, final int z) {
+        return this.getBlock(new TilePos(x, y, z));
+    }
+
+    @Nullable TileEntity getTileEntity(final @NotNull TilePos tilePos);
 
-    TileEntity getTileEntity(int x, int y, int z);
+    @Deprecated
+    default @Nullable TileEntity getTileEntity(final int x, final int y, final int z) {
+        return this.getTileEntity(new TilePos(x, y, z));
+    }
 
-    default <T> @Nullable T getBlockLogic(final int x, final int y, final int z, final Class<T> logicClass) {
-        final Block<?> block = getBlock(x, y, z);
-        if (block == null) return null;
-        final BlockLogic logic = block.getLogic();
+    default <T> @Nullable T getBlockLogic(final @NotNull TilePos tilePos, final @NotNull Class<T> logicClass) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        if (block == null) {
+            return null;
+        }
+
+        final @NotNull BlockLogic logic = block.getLogic();
         if (logicClass.isAssignableFrom(logic.getClass())) {
             return logicClass.cast(logic);
         }
+
         return null;
     }
 
-    float getBrightness(int x, int y, int z, int blockLightValue);
-    
-    int getLightmapCoord(int x, int y, int z, int blockLightValue);
+    @Deprecated
+    default <T> @Nullable T getBlockLogic(final int x, final int y, final int z, final @NotNull Class<T> logicClass) {
+        return this.getBlockLogic(new TilePos(x, y, z), logicClass);
+    }
+
+    float getBrightness(final @NotNull TilePos tilePos, final int lightEmission);
+
+    @Deprecated
+    default float getBrightness(final int x, final int y, final int z, final int lightEmission) {
+        return this.getBrightness(new TilePos(x, y, z), lightEmission);
+    }
+
+    int getLightmapCoord(final @NotNull TilePos tilePos, final int lightEmission);
+
+    @Deprecated
+    default int getLightmapCoord(final int x, final int y, final int z, final int lightEmission) {
+        return this.getLightmapCoord(new TilePos(x, y, z), lightEmission);
+    }
+
+    int getLightmapCoord(int skyLight, int blockLight);
+
+    float getLightBrightness(final @NotNull TilePos tilePos);
+
+    @Deprecated
+    default float getLightBrightness(final int x, final int y, final int z) {
+        return this.getLightBrightness(new TilePos(x, y, z));
+    }
+
+    int getBlockData(final @NotNull TilePos tilePos);
 
-    int getLightmapCoord(int skylight, int blocklight);
+    @Deprecated
+    default int getBlockMetadata(final int x, final int y, final int z) {
+        return this.getBlockData(new TilePos(x, y, z));
+    }
+
+    @NotNull Material getBlockMaterial(final @NotNull TilePos tilePos);
+
+    @Deprecated
+    default @NotNull Material getBlockMaterial(final int x, final int y, final int z) {
+        return this.getBlockMaterial(new TilePos(x, y, z));
+    }
 
-    float getLightBrightness(int x, int y, int z);
+    boolean isBlockOpaqueCube(final @NotNull TilePos tilePos);
 
-    int getBlockMetadata(int x, int y, int z);
+    @Deprecated
+    default boolean isBlockOpaqueCube(final int x, final int y, final int z) {
+        return this.isBlockOpaqueCube(new TilePos(x, y, z));
+    }
 
-    Material getBlockMaterial(int x, int y, int z);
+    boolean isBlockNormalCube(final @NotNull TilePos tilePos);
 
-    boolean isBlockOpaqueCube(int x, int y, int z);
+    @Deprecated
+    default boolean isBlockNormalCube(final int x, final int y, final int z) {
+        return this.isBlockNormalCube(new TilePos(x, y, z));
+    }
 
-    boolean isBlockNormalCube(int x, int y, int z);
-    double getBlockTemperature(int x, int z);
-    double getBlockHumidity(int x, int z);
-    SeasonManager getSeasonManager();
-    Biome getBlockBiome(int x, int y, int z);
-    
-    int getSavedLightValue(LightLayer layer, int x, int y, int z);
+    double getBlockTemperature(final @NotNull TilePos tilePos);
+
+    @Deprecated
+    default double getBlockTemperature(final int x, final int z) {
+        return this.getBlockTemperature(new TilePos(x, 0, z));
+    }
+
+    double getBlockHumidity(final @NotNull TilePos tilePos);
+
+    @Deprecated
+    default double getBlockHumidity(final int x, final int z) {
+        return this.getBlockHumidity(new TilePos(x, 0, z));
+    }
+
+    double getBlockVariety(final @NotNull TilePos tilePos);
+
+    @Deprecated
+    default double getBlockVariety(final int x, final int z) {
+        return this.getBlockVariety(new TilePos(x, 0, z));
+    }
+
+    @NotNull SeasonManager getSeasonManager();
+
+    @NotNull Biome getBlockBiome(final @NotNull TilePos tilePos);
+
+    @Deprecated
+    default @Nullable Biome getBlockBiome(final int x, final int y, final int z) {
+        return this.getBlockBiome(new TilePos(x, y, z));
+    }
+
+    int getSavedLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePos tilePos);
+
+    @Deprecated
+    default int getSavedLightValue(final @NotNull LightLayer layer, final int x, final int y, final int z) {
+        return this.getSavedLightValue(layer, new TilePos(x, y, z));
+    }
 
     boolean isRetro();
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java
index 16c7d2869..6a9ce7265 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java
@@ -13,6 +13,9 @@ import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.pos.ChunkPos;
+import net.minecraft.core.world.pos.ChunkTilePos;
+import net.minecraft.core.world.pos.TilePos;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -27,74 +30,76 @@ public class Chunk
     public static final int CHUNK_SECTIONS = 16;
     public static boolean isLit;
     public boolean isLoaded;
-    public World world;
-    public short[] heightMap;
-    public int lowestY;
-    public final int xPosition;
-    public final int zPosition;
+    public final @NotNull World world;
+    public short @NotNull [] heightMap = new short[CHUNK_SIZE_X * CHUNK_SIZE_Z];
+    public final @NotNull ChunkPos pos;
     public long ticksOnUnload = -1;
-    public Map<ChunkPosition, TileEntity> tileEntityMap;
-    public double[] temperature;
-    public double[] humidity;
-    public double[] variety;
-    public @NotNull Int2ObjectMap<NextTickListEntry> tickList;
+    public final @NotNull Map<@NotNull ChunkTilePos, @NotNull TileEntity> tileEntityMap = new HashMap<>();
+    public double @NotNull [] temperature = new double[CHUNK_SIZE_X * CHUNK_SIZE_Z];
+    public double @NotNull [] humidity = new double[CHUNK_SIZE_X * CHUNK_SIZE_Z];
+    public double @NotNull [] variety = new double[CHUNK_SIZE_X * CHUNK_SIZE_Z];
+    public @NotNull Int2ObjectMap<NextTickListEntry> tickList = new Int2ObjectArrayMap<>();
     public int averageBlockHeight;
-    public boolean isTerrainPopulated;
-    public boolean isModified;
+    public boolean isTerrainPopulated = false;
+    public boolean isModified = false;
     public boolean neverSave;
-    public boolean hasEntities;
-    public long lastSaveTime;
-    protected final ChunkSection[] sections = new ChunkSection[CHUNK_SECTIONS];
+    public boolean hasEntities = false;
+    public long lastSaveTime = 0L;
+    protected final @NotNull ChunkSection @NotNull [] sections = new ChunkSection[CHUNK_SECTIONS];
 
-    public Chunk(World world, int x, int z)
-    {
-        tileEntityMap = new HashMap<>();
-        isTerrainPopulated = false;
-        isModified = false;
-        hasEntities = false;
-        lastSaveTime = 0L;
+    public Chunk(final @NotNull World world, final @NotNull ChunkPos pos) {
         this.world = world;
-        xPosition = x;
-        zPosition = z;
-        heightMap = new short[CHUNK_SIZE_X * CHUNK_SIZE_Z];
-        temperature = new double[CHUNK_SIZE_X * CHUNK_SIZE_Z];
-        humidity = new double[CHUNK_SIZE_X * CHUNK_SIZE_Z];
-        variety = new double[CHUNK_SIZE_X * CHUNK_SIZE_Z];
-        tickList = new Int2ObjectArrayMap<>();
+        this.pos = pos;
 
-        for (int i = 0; i < sections.length; i++) {
-            sections[i] = new ChunkSection(this, i);
+        for (int i = 0; i < this.sections.length; i++) {
+            this.sections[i] = new ChunkSection(this, i);
         }
     }
 
-    public static int makeBlockIndex(int x, int y, int z) {
+    @Deprecated
+    public Chunk(final @NotNull World world, final int x, final int z) {
+        this(world, new ChunkPos(x, z));
+    }
+
+    public static int makeBlockIndex(final @NotNull ChunkTilePos chunkTilePos) {
+        return (chunkTilePos.y * CHUNK_SIZE_Z * CHUNK_SIZE_X) + (chunkTilePos.z * CHUNK_SIZE_X) + chunkTilePos.x;
+    }
+
+    @Deprecated
+    public static int makeBlockIndex(final int x, final int y, final int z) {
         return (y * CHUNK_SIZE_Z * CHUNK_SIZE_X) + (z * CHUNK_SIZE_X) + x;
     }
 
-    public ChunkSection getSection(int index) {
+    public @Nullable ChunkSection getSection(final int index) {
         if (index < 0 || index >= CHUNK_SECTIONS) return null;
-        return sections[index];
+        return this.sections[index];
+    }
+
+    public @Nullable ChunkSection getSection(final @NotNull ChunkTilePos chunkTilePos) {
+        return this.getSection(chunkTilePos.getSectionIndex());
     }
 
     public void init() {
-        Arrays.fill(temperature, Double.NEGATIVE_INFINITY);
-        Arrays.fill(humidity, Double.NEGATIVE_INFINITY);
-        Arrays.fill(variety, Double.NEGATIVE_INFINITY);
+        Arrays.fill(this.temperature, Double.NEGATIVE_INFINITY);
+        Arrays.fill(this.humidity, Double.NEGATIVE_INFINITY);
+        Arrays.fill(this.variety, Double.NEGATIVE_INFINITY);
     }
 
-    public boolean isAtLocation(int x, int z)
-    {
-        return x == xPosition && z == zPosition;
+    public boolean isAtLocation(final @NotNull ChunkPos chunkPos) {
+        return this.pos.equals(chunkPos);
     }
 
-    public int getHeightValue(int x, int z)
-    {
-        return heightMap[z * CHUNK_SIZE_X + x];
+    @Deprecated
+    public final boolean isAtLocation(final int x, final int z) {
+        return x == this.pos.x && z == this.pos.z;
     }
 
-    private void setHeightValue(int x, int z, int y)
-    {
-        heightMap[z * CHUNK_SIZE_X + x] = (short) y;
+    public int getHeightValue(final int x, final int z) {
+        return this.heightMap[z * CHUNK_SIZE_X + x];
+    }
+
+    private void setHeightValue(int x, int z, int y) {
+        this.heightMap[z * CHUNK_SIZE_X + x] = (short) y;
     }
 
     public void addTick(final @NotNull NextTickListEntry entry) {
@@ -110,10 +115,8 @@ public class Chunk
         this.tickList.remove(pos);
     }
 
-    public void recalcHeightmapOnly()
-    {
+    public void recalcHeightmapOnly() {
         int acc = 0;
-        int lowestY = CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y - 1;
         for(int x = 0; x < CHUNK_SIZE_X; x++)
         {
             for(int z = 0; z < CHUNK_SIZE_Z; z++)
@@ -124,14 +127,9 @@ public class Chunk
                 }
                 setHeightValue(x, z, y);
                 acc += y;
-                if(y < lowestY)
-                {
-                    lowestY = y;
-                }
             }
         }
 
-        this.lowestY = lowestY;
         isModified = true;
         averageBlockHeight = acc / (CHUNK_SIZE_X * CHUNK_SIZE_Z);
     }
@@ -167,327 +165,388 @@ public class Chunk
         isModified = true;
     }
 
-    private void lightGaps(int x, int z)
-    {
+    private void lightGaps(int x, int z) {
         int y = getHeightValue(x, z);
-        int worldX = xPosition * CHUNK_SIZE_X + x;
-        int worldZ = zPosition * CHUNK_SIZE_Z + z;
+        int worldX = this.pos.x * CHUNK_SIZE_X + x;
+        int worldZ = this.pos.z * CHUNK_SIZE_Z + z;
         lightGap(worldX - 1, worldZ, y);
         lightGap(worldX + 1, worldZ, y);
         lightGap(worldX, worldZ - 1, y);
         lightGap(worldX, worldZ + 1, y);
     }
 
-    private void lightGap(int x, int z, int heightValue)
+    private void lightGap(int x, int z, int y)
     {
         int blockHeight = world.getHeightValue(x, z);
-        if(blockHeight > heightValue)
+        if(blockHeight > y)
         {
-            world.scheduleLightingUpdate(LightLayer.Sky, x, heightValue, z, x, blockHeight, z);
+            world.scheduleLightingUpdate(LightLayer.Sky, x, y, z, x, blockHeight, z);
             isModified = true;
         }
-        else if(blockHeight < heightValue)
+        else if(blockHeight < y)
         {
-            world.scheduleLightingUpdate(LightLayer.Sky, x, blockHeight, z, x, heightValue, z);
+            world.scheduleLightingUpdate(LightLayer.Sky, x, blockHeight, z, x, y, z);
             isModified = true;
         }
     }
 
-    private void recalcHeight(int x, int y, int z)
-    {
-        int heightValue = getHeightValue(x, z);
-        int iy = heightValue;
-        if(y > heightValue)
-        {
-            iy = y;
+    private void recalcHeight(final @NotNull ChunkTilePos tilePos) {
+        final int heightValue = this.getHeightValue(tilePos.x, tilePos.z);
+        final @NotNull ChunkTilePos iPos = new ChunkTilePos(tilePos.x, heightValue, tilePos.z);
+        if(tilePos.y > heightValue) {
+            iPos.y = tilePos.y;
         }
-        for(; iy > 0 && Blocks.lightBlock[getBlockID(x, iy - 1, z) & 0x3fff] == 0; iy--) { }
-        if(iy == heightValue)
-        {
+        for (; iPos.y > 0 && Blocks.lightBlock[this.getBlockId(iPos.down()) & 0x3fff] == 0; iPos.y--) { }
+
+        if (iPos.y == heightValue) {
             return;
         }
-        world.markBlocksDirtyVertical(x, z, iy, heightValue);
-        setHeightValue(x, z, iy);
-        if(iy < lowestY)
-        {
-            lowestY = iy;
-        }
-        else
-        {
-            int lowestY = (CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y) - 1;
-            for(int ix = 0; ix < CHUNK_SIZE_X; ix++)
-            {
-                for(int iz = 0; iz < CHUNK_SIZE_Z; iz++)
-                {
-                    int iHeightValue = getHeightValue(x, z);
-                    if(iHeightValue < lowestY)
-                    {
-                        lowestY = iHeightValue;
-                    }
-                }
 
-            }
+        this.world.markBlocksDirtyVertical(iPos.x, iPos.z, iPos.y, heightValue);
+        this.setHeightValue(iPos.x, iPos.z, iPos.y);
 
-            this.lowestY = lowestY;
-        }
-        int worldX = xPosition * CHUNK_SIZE_X + x;
-        int worldZ = zPosition * CHUNK_SIZE_Z + z;
-        if(iy < heightValue)
-        {
-            for(int dy = iy; dy < heightValue; dy++)
-            {
-                setBrightness(LightLayer.Sky, x, dy, z, 15);
+        final @NotNull TilePos worldPos = new TilePos(this.pos, tilePos);
+        if(iPos.y < heightValue) {
+            for (int dy = iPos.y; dy < heightValue; dy++) {
+                this.setBrightness(LightLayer.Sky, iPos.x, dy, iPos.z, World.MAX_BRIGHTNESS);
             }
-        }
-        else
-        {
-            world.scheduleLightingUpdate(LightLayer.Sky, worldX, heightValue, worldZ, worldX, iy, worldZ);
-            for(int dy = heightValue; dy < iy; dy++)
-            {
-                setBrightness(LightLayer.Sky, x, dy, z, 0);
+        } else {
+            this.world.scheduleLightingUpdate(LightLayer.Sky, new TilePos(worldPos.x, heightValue, worldPos.z), new TilePos(worldPos.x, iPos.y, worldPos.z));
+            for (int dy = heightValue; dy < iPos.y; dy++) {
+                setBrightness(LightLayer.Sky, iPos.x, dy, iPos.z, 0);
             }
         }
-        int lightValue = 15;
-        int lightY = iy;
-        while(iy > 0 && lightValue > 0)
-        {
-            iy--;
-            int lightBlock = Blocks.lightBlock[getBlockID(x, iy, z)];
-            if(lightBlock == 0)
-            {
+
+        int lightValue = World.MAX_BRIGHTNESS;
+        final int lightY = iPos.y;
+        while (iPos.y > 0 && lightValue > 0) {
+            iPos.y--;
+            int lightBlock = Blocks.lightBlock[this.getBlockId(iPos)];
+            if(lightBlock == 0) {
                 lightBlock = 1;
             }
             lightValue -= lightBlock;
-            if(lightValue < 0)
-            {
+            if(lightValue < 0) {
                 lightValue = 0;
             }
-            setBrightness(LightLayer.Sky, x, iy, z, lightValue);
+            this.setBrightness(LightLayer.Sky, iPos, lightValue);
         }
-        for(; iy > 0 && Blocks.lightBlock[getBlockID(x, iy - 1, z)] == 0; iy--) { }
-        if(iy != lightY)
-        {
-            world.scheduleLightingUpdate(LightLayer.Sky, worldX - 1, iy, worldZ - 1, worldX + 1, lightY, worldZ + 1);
+
+        for(; iPos.y > 0 && Blocks.lightBlock[this.getBlockId(iPos.down())] == 0; iPos.y--) { }
+
+        if(iPos.y != lightY) {
+            this.world.scheduleLightingUpdate(LightLayer.Sky, new TilePos(worldPos.x - 1, iPos.y, worldPos.z - 1), new TilePos(worldPos.x + 1, lightY, worldPos.z + 1));
         }
-        isModified = true;
 
+        this.isModified = true;
     }
 
-    public int getBlockID(int x, int y, int z)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return 0;
-        return getSection(y / ChunkSection.SECTION_SIZE_Y).getBlock(x, y % ChunkSection.SECTION_SIZE_Y, z);
+    public int getBlockId(final @NotNull ChunkTilePos tilePos) {
+        if (!tilePos.inBounds()) {
+            return 0;
+        }
+
+        return Objects.requireNonNull(this.getSection(tilePos)).getBlockId(tilePos.toChunkSectionTilePos());
+    }
+
+    @Deprecated
+    public final int getBlockID(final int x, final int y, final int z) {
+        return this.getBlockId(new ChunkTilePos(x, y, z));
+    }
+
+    public @Nullable Block<?> getBlock(final @NotNull ChunkTilePos tilePos) {
+        return Blocks.getBlock(this.getBlockId(tilePos));
+    }
+
+    public boolean setBlockIdDataRaw(final @NotNull ChunkTilePos tilePos, final int id, final int data) {
+        return this.setBlockIdData(tilePos, id, data, true);
+    }
+
+    public boolean setBlockIdData(final @NotNull ChunkTilePos tilePos, final int id, final int data) {
+        return this.setBlockIdData(tilePos, id, data, false);
     }
 
     // will not trigger onBlockRemoved or onBlockPlacedByWorld
-    public boolean setBlockIDWithMetadataRaw(int x, int y, int z, int id, int data)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return false;
+    @Deprecated
+    public final boolean setBlockIDWithMetadataRaw(final int x, final int y, final int z, final int id, final int data) {
+        return this.setBlockIdDataRaw(new ChunkTilePos(x, y, z), id, data);
+    }
+
+    private boolean setBlockIdData(final @NotNull ChunkTilePos tilePos, final int id, final int data, final boolean raw) {
+        if (!tilePos.inBounds()) {
+            return false;
+        }
+
+        final @NotNull ChunkSection section = Objects.requireNonNull(this.getSection(tilePos));
+        final int heightValue = this.getHeightValue(tilePos.x, tilePos.z);
 
-        ChunkSection section = getSection(y / ChunkSection.SECTION_SIZE_Y);
-        int heightValue = getHeightValue(x, z);
+        final int currentId = section.getBlockId(tilePos.toChunkSectionTilePos());
+        final int currentData = section.getData(tilePos.toChunkSectionTilePos());
 
-        int currentId = section.getBlock(x, y % ChunkSection.SECTION_SIZE_Y, z);
-        int currentData = section.getData(x, y % ChunkSection.SECTION_SIZE_Y, z);
+        final @Nullable Block<?> currentBlock = Blocks.getBlock(currentId);
+        final @Nullable Block<?> newBlock = Blocks.getBlock(id);
 
-        if(currentId == id && currentData == data) {
+        if (currentId == id && currentData == data) {
             return false;
         }
 
-        section.setBlock(x, y % ChunkSection.SECTION_SIZE_Y, z, id);
-        section.setData(x, y % ChunkSection.SECTION_SIZE_Y, z, data);
+        section.setBlockId(tilePos.toChunkSectionTilePos(), id);
+        section.setData(tilePos.toChunkSectionTilePos(), id);
 
-        int worldX = xPosition * CHUNK_SIZE_X + x;
-        int worldZ = zPosition * CHUNK_SIZE_Z + z;
+        final @NotNull TilePos worldPos = new TilePos(this.pos, tilePos);
+        if (!raw && currentBlock != null && !this.world.isClientSide) {
+            currentBlock.onBlockRemoved(this.world, worldPos.x, worldPos.y, worldPos.z, currentData);
+        }
 
-        if(!world.worldType.hasCeiling())
-        {
-            if(Blocks.lightBlock[id & 0x3fff] != 0) {
-                if(y >= heightValue) {
-                    recalcHeight(x, y + 1, z);
+        if (!this.world.getWorldType().hasCeiling()) {
+            if (Blocks.lightBlock[id & 0x3FFF] != 0) {
+                if (tilePos.y >= heightValue) {
+                    this.recalcHeight(tilePos.up());
                 }
+            } else if (tilePos.y == heightValue - 1) {
+                this.recalcHeight(tilePos);
             }
-            else if(y == heightValue - 1) {
-                recalcHeight(x, y, z);
-            }
-            world.scheduleLightingUpdate(LightLayer.Sky, worldX, y, worldZ, worldX, y, worldZ);
+            this.world.scheduleLightingUpdate(LightLayer.Sky, worldPos);
         }
 
-        world.scheduleLightingUpdate(LightLayer.Block, worldX, y, worldZ, worldX, y, worldZ);
-        lightGaps(x, z);
+        this.world.scheduleLightingUpdate(LightLayer.Block, worldPos);
+        this.lightGaps(tilePos.x, tilePos.z);
 
-        isModified = true;
+        if (!raw && newBlock != null) {
+            newBlock.onBlockPlacedByWorld(this.world, worldPos.x, worldPos.y, worldPos.z);
+        }
+
+        this.isModified = true;
         return true;
     }
 
-    public boolean setBlockIDWithMetadata(int x, int y, int z, int id, int data)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return false;
+    @Deprecated
+    public final boolean setBlockIDWithMetadata(final int x, final int y, final int z, final int id, final int data) {
+        return this.setBlockIdData(new ChunkTilePos(x, y, z), id, data);
+    }
 
-        ChunkSection section = getSection(y / ChunkSection.SECTION_SIZE_Y);
-        int heightValue = getHeightValue(x, z);
+    public boolean setBlockId(final @NotNull ChunkTilePos tilePos, final int id) {
+        return this.setBlockIdData(tilePos, id, 0);
+    }
 
-        int currentId = section.getBlock(x, y % ChunkSection.SECTION_SIZE_Y, z);
-        int currentData = section.getData(x, y % ChunkSection.SECTION_SIZE_Y, z);
+    @Deprecated
+    public final boolean setBlockID(final int x, final int y, final int z, final int id) {
+        return this.setBlockId(new ChunkTilePos(x, y, z), id);
+    }
 
-        if(currentId == id && currentData == data) {
-            return false;
+    public int getBlockData(final @NotNull ChunkTilePos tilePos) {
+        if (!tilePos.inBounds()) {
+            return 0;
         }
 
-        section.setBlock(x, y % ChunkSection.SECTION_SIZE_Y, z, id);
-        section.setData(x, y % ChunkSection.SECTION_SIZE_Y, z, data);
+        return Objects.requireNonNull(this.getSection(tilePos)).getData(tilePos.toChunkSectionTilePos());
+    }
+
+    @Deprecated
+    public final int getBlockMetadata(final int x, final int y, final int z) {
+        return this.getBlockData(new ChunkTilePos(x, y, z));
+    }
 
-        int worldX = xPosition * CHUNK_SIZE_X + x;
-        int worldZ = zPosition * CHUNK_SIZE_Z + z;
-        if(currentId != 0 && !world.isClientSide)
-        {
-            Blocks.blocksList[currentId].onBlockRemoved(world, worldX, y, worldZ, currentData);
+    public boolean setBlockData(final @NotNull ChunkTilePos tilePos, final int value) {
+        if (!tilePos.inBounds()) {
+            return false;
         }
 
-        if(!world.worldType.hasCeiling())
-        {
-            if(Blocks.lightBlock[id & 0x3fff] != 0) {
-                if(y >= heightValue) {
-                    recalcHeight(x, y + 1, z);
-                }
-            }
-            else if(y == heightValue - 1) {
-                recalcHeight(x, y, z);
-            }
-            world.scheduleLightingUpdate(LightLayer.Sky, worldX, y, worldZ, worldX, y, worldZ);
+        Objects.requireNonNull(this.getSection(tilePos)).setData(tilePos.toChunkSectionTilePos(), value);
+        this.isModified = true;
+
+        return true;
+    }
+
+    @Deprecated
+    public final void setBlockMetadata(final int x, final int y, final int z, final int value) {
+        this.setBlockData(new ChunkTilePos(x, y, z), value);
+    }
+
+    public @Nullable Biome getBlockBiome(final @NotNull ChunkTilePos tilePos) {
+        if (!tilePos.inBounds()) {
+            return null;
         }
 
-        world.scheduleLightingUpdate(LightLayer.Block, worldX, y, worldZ, worldX, y, worldZ);
-        lightGaps(x, z);
+        return Objects.requireNonNull(this.getSection(tilePos)).getBiome(tilePos.toChunkSectionTilePos());
+    }
+
+    @Deprecated
+    public final @Nullable Biome getBlockBiome(final int x, final int y, final int z) {
+        return this.getBlockBiome(new ChunkTilePos(x, y, z));
+    }
 
-        if(Blocks.getBlock(id) != null) {
-            Blocks.blocksList[id].onBlockPlacedByWorld(world, worldX, y, worldZ);
+    public boolean setBlockBiome(final @NotNull ChunkTilePos tilePos, final @NotNull Biome biome) {
+        if (!tilePos.inBounds()) {
+            return false;
         }
 
-        isModified = true;
+        Objects.requireNonNull(this.getSection(tilePos)).setBiome(tilePos.toChunkSectionTilePos(), biome);
+        this.isModified = true;
+
         return true;
     }
 
-    public boolean setBlockID(int x, int y, int z, int id)
-    {
-        return setBlockIDWithMetadata(x, y, z, id, 0);
+    @Deprecated
+    public final boolean setBlockBiome(final int x, final int y, final int z, final @NotNull Biome biome) {
+        return this.setBlockBiome(new ChunkTilePos(x, y, z), biome);
     }
 
-    public int getBlockMetadata(int x, int y, int z)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return 0;
+    public double getBlockTemperature(final @NotNull ChunkTilePos tilePos) {
+        if (!tilePos.inBounds()) {
+            return Double.NEGATIVE_INFINITY;
+        }
 
-        return getSection(y / ChunkSection.SECTION_SIZE_Y).getData(x, y % ChunkSection.SECTION_SIZE_Y, z);
+        return this.temperature[tilePos.x * CHUNK_SIZE_Z + tilePos.z];
     }
 
-    public void setBlockMetadata(int x, int y, int z, int value)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return;
-
-        getSection(y / ChunkSection.SECTION_SIZE_Y).setData(x, y % ChunkSection.SECTION_SIZE_Y, z, value);
-        isModified = true;
+    @Deprecated
+    public final double getBlockTemperature(final int x, final int z) {
+        return this.getBlockTemperature(new ChunkTilePos(x, 0, z));
     }
-    
-    public @Nullable Biome getBlockBiome(int x, int y, int z)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return null;
 
-        return getSection(y / ChunkSection.SECTION_SIZE_Y).getBiome(x, y % ChunkSection.SECTION_SIZE_Y, z);
+    public void setBlockTemperature(final @NotNull ChunkTilePos tilePos, final double temperature) {
+        if (!tilePos.inBounds()) {
+            return;
+        }
+
+        this.temperature[tilePos.x * CHUNK_SIZE_Z + tilePos.z] = temperature;
+        this.isModified = true;
     }
-    
-    public boolean setBlockBiome(int x, int y, int z, Biome biome)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return false;
 
-        getSection(y / ChunkSection.SECTION_SIZE_Y).setBiome(x, y % ChunkSection.SECTION_SIZE_Y, z, biome);
-        isModified = true;
+    @Deprecated
+    public final boolean setBlockTemperature(final int x, final int z, final double temperature) {
+        if (temperature == this.temperature[x * CHUNK_SIZE_Z + z]) {
+            return false;
+        }
 
+        this.setBlockTemperature(new ChunkTilePos(x, 0, z), temperature);
         return true;
     }
-    
-    public double getBlockTemperature(int x, int z)
-    {
-        return temperature[x * CHUNK_SIZE_Z + z];
+
+    public double getBlockHumidity(final @NotNull ChunkTilePos tilePos) {
+        if (!tilePos.inBounds()) {
+            return Double.NEGATIVE_INFINITY;
+        }
+
+        return this.humidity[tilePos.x * CHUNK_SIZE_Z + tilePos.z];
     }
-    
-    public boolean setBlockTemperature(int x, int z, double temperature)
-    {
-        double presentTemperature = this.temperature[x * CHUNK_SIZE_Z + z];
-        if (presentTemperature == temperature) return false;
-        this.temperature[x * CHUNK_SIZE_Z + z] = temperature;
-        isModified = true;
-        return true;
+
+    @Deprecated
+    public final double getBlockHumidity(final int x, final int z) {
+        return this.getBlockHumidity(new ChunkTilePos(x, 0, z));
     }
-    
-    public double getBlockHumidity(int x, int z)
-    {
-        return humidity[x * CHUNK_SIZE_Z + z];
+
+    public void setBlockHumidity(final @NotNull ChunkTilePos tilePos, final double humidity) {
+        if (!tilePos.inBounds()) {
+            return;
+        }
+
+        this.humidity[tilePos.x * CHUNK_SIZE_Z + tilePos.z] = humidity;
+        this.isModified = true;
     }
-    
-    public boolean setBlockHumidity(int x, int z, double humidity)
-    {
-        double presentHumidity = this.humidity[x * CHUNK_SIZE_Z + z];
-        if (presentHumidity == humidity) return false;
-        this.humidity[x * CHUNK_SIZE_Z + z] = humidity;
-        isModified = true;
+
+    @Deprecated
+    public final boolean setBlockHumidity(final int x, final int z, final double humidity) {
+        if (humidity == this.humidity[x * CHUNK_SIZE_Z + z]) {
+            return false;
+        }
+
+        this.setBlockHumidity(new ChunkTilePos(x, 0, z), humidity);
         return true;
     }
-    public double getBlockVariety(int x, int z)
-    {
-        return variety[x * CHUNK_SIZE_Z + z];
+
+    public double getBlockVariety(final @NotNull ChunkTilePos tilePos) {
+        if (!tilePos.inBounds()) {
+            return Double.NEGATIVE_INFINITY;
+        }
+
+        return this.variety[tilePos.x * CHUNK_SIZE_Z + tilePos.z];
     }
-    public boolean setBlockVariety(int x, int z, double variety)
-    {
-        double presentVariety = this.variety[x * CHUNK_SIZE_Z + z];
-        if (presentVariety == variety) return false;
-        this.variety[x * CHUNK_SIZE_Z + z] = variety;
-        isModified = true;
+
+    @Deprecated
+    public final double getBlockVariety(final int x, final int z) {
+        return this.getBlockVariety(new ChunkTilePos(x, 0, z));
+    }
+
+    public void setBlockVariety(final @NotNull ChunkTilePos tilePos, final double variety) {
+        if (!tilePos.inBounds()) {
+            return;
+        }
+
+        this.variety[tilePos.x * CHUNK_SIZE_Z + tilePos.z] = variety;
+        this.isModified = true;
+    }
+
+    @Deprecated
+    public final boolean setBlockVariety(final int x, final int z, final double variety) {
+        if (variety == this.variety[x * CHUNK_SIZE_Z + z]) {
+            return false;
+        }
+
+        this.setBlockVariety(new ChunkTilePos(x, 0, z), variety);
         return true;
     }
 
-    public int getBrightness(LightLayer layer, int x, int y, int z)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return 0;
+    public int getBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePos tilePos) {
+        if (!tilePos.inBounds()) {
+            return 0;
+        }
 
-        return getSection(y / ChunkSection.SECTION_SIZE_Y).getBrightness(layer, x, y % ChunkSection.SECTION_SIZE_Y, z);
+        return Objects.requireNonNull(this.getSection(tilePos)).getBrightness(lightLayer, tilePos.toChunkSectionTilePos());
     }
 
-    public void setBrightness(LightLayer layer, int x, int y, int z, int value)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return;
+    @Deprecated
+    public final int getBrightness(final @NotNull LightLayer lightLayer, final int x, final int y, final int z) {
+        return this.getBrightness(lightLayer, new ChunkTilePos(x, y, z));
+    }
 
-        getSection(y / ChunkSection.SECTION_SIZE_Y).setBrightness(layer, x, y % ChunkSection.SECTION_SIZE_Y, z, value);
-        isModified = true;
+    public void setBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePos tilePos, final int value) {
+        if (!tilePos.inBounds()) {
+            return;
+        }
+
+        Objects.requireNonNull(this.getSection(tilePos)).setBrightness(lightLayer, tilePos.toChunkSectionTilePos(), value);
+        this.isModified = true;
     }
 
-    public int getRawBrightness(int x, int y, int z, int skySubtract)
-    {
-        if (x < 0 || x >= CHUNK_SIZE_X || y < 0 || y >= CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y || z < 0 || z >= CHUNK_SIZE_Z) return 0;
+    @Deprecated
+    public final void setBrightness(final @NotNull LightLayer lightLayer, final int x, final int y, final int z, final int value) {
+        this.setBrightness(lightLayer, new ChunkTilePos(x, y, z), value);
+    }
+
+    public int getRawBrightness(final @NotNull ChunkTilePos tilePos, final int subtractedSkyLight) {
+        if (!tilePos.inBounds()) {
+            return 0;
+        }
 
-        int lightValue = getSection(y / ChunkSection.SECTION_SIZE_Y).getRawBrightness(x, y % ChunkSection.SECTION_SIZE_Y, z, skySubtract);
+        final int lightValue = Objects.requireNonNull(this.getSection(tilePos)).getRawBrightness(tilePos.toChunkSectionTilePos(), subtractedSkyLight);
         if (lightValue > 0) {
-            isLit = true;
+            Chunk.isLit = true;
         }
 
         return lightValue;
     }
 
-    public void addEntity(Entity entity)
-    {
+    @Deprecated
+    public final int getRawBrightness(final int x, final int y, final int z, final int subtractedSkyLight) {
+        return this.getRawBrightness(new ChunkTilePos(x, y, z), subtractedSkyLight);
+    }
+
+    public void addEntity(final @NotNull Entity entity) {
         hasEntities = true;
         isModified = true;
-        int x = MathHelper.floor(entity.x / CHUNK_SIZE_X);
-        int z = MathHelper.floor(entity.z / CHUNK_SIZE_Z);
-        if(x != xPosition || z != zPosition)
+        final @NotNull ChunkPos entityChunkPos = new ChunkPos(entity);
+        if(!entityChunkPos.equals(this.pos))
         {
             LOGGER.warn("Wrong location! {}", entity);
             Thread.dumpStack();
         }
         int section = MathHelper.clamp(MathHelper.floor(entity.y / 16D), 0, CHUNK_SECTIONS - 1);
         entity.addedToChunk = true;
-        entity.chunkCoordX = xPosition;
+        entity.chunkCoordX = this.pos.x;
         entity.chunkCoordY = section;
-        entity.chunkCoordZ = zPosition;
+        entity.chunkCoordZ = this.pos.z;
         getSection(section).addEntity(entity);
     }
 
@@ -502,98 +561,109 @@ public class Chunk
         getSection(index).removeEntity(entity);
     }
 
-    public boolean canBlockSeeTheSky(int x, int y, int z)
-    {
-        return y >= getHeightValue(x, z);
+    public boolean canBlockSeeSky(final @NotNull ChunkTilePos tilePos) {
+        return tilePos.y >= this.getHeightValue(tilePos.x, tilePos.z);
     }
 
-    public TileEntity getTileEntity(int x, int y, int z)
-    {
-        ChunkPosition pos = new ChunkPosition(x, y, z);
-        TileEntity tileEntity = tileEntityMap.get(pos);
-        if(tileEntity == null)
-        {
-            Block<?> block = Blocks.getBlock(getBlockID(x, y, z));
-            if(block == null || !block.isEntityTile)
-            {
+    @Deprecated
+    public final boolean canBlockSeeTheSky(final int x, final int y, final int z) {
+        return this.canBlockSeeSky(new ChunkTilePos(x, y, z));
+    }
+
+    public @Nullable TileEntity getTileEntity(final @NotNull ChunkTilePos tilePos) {
+        @Nullable TileEntity tileEntity = this.tileEntityMap.get(tilePos);
+
+        if (tileEntity == null) {
+            final @Nullable Block<?> block = this.getBlock(tilePos);
+            if (block == null || !block.isEntityTile) {
                 return null;
+            } else {
+                block.onBlockPlacedByWorld(this.world, this.pos.x * CHUNK_SIZE_X + tilePos.x, tilePos.y, this.pos.z * CHUNK_SIZE_Z + tilePos.z);
+                tileEntity = this.tileEntityMap.get(tilePos);
             }
-            block.onBlockPlacedByWorld(world, xPosition * CHUNK_SIZE_X + x, y, zPosition * CHUNK_SIZE_Z + z);
-            tileEntity = tileEntityMap.get(pos);
         }
-        if(tileEntity != null && tileEntity.isInvalid())
-        {
-            tileEntityMap.remove(pos);
+
+        if (tileEntity != null && tileEntity.isInvalid()) {
+            this.tileEntityMap.remove(tilePos);
             return null;
         }
-        else
-        {
-            return tileEntity;
-        }
+
+        return tileEntity;
     }
 
-    public void addTileEntity(TileEntity tileEntity)
-    {
-        int x = tileEntity.x - xPosition * CHUNK_SIZE_X;
-        int y = tileEntity.y;
-        int z = tileEntity.z - zPosition * CHUNK_SIZE_Z;
-        setTileEntity(x, y, z, tileEntity);
-        if(isLoaded)
-        {
-            world.tileEntityList.add(tileEntity);
+    @Deprecated
+    public final @Nullable TileEntity getTileEntity(final int x, final int y, final int z) {
+        return this.getTileEntity(new ChunkTilePos(x, y, z));
+    }
+
+    public void addTileEntity(final @NotNull TileEntity tileEntity) {
+        final @NotNull TilePos tilePos = new TilePos(tileEntity.x, tileEntity.y, tileEntity.z);
+
+        this.setTileEntity(tilePos.toChunkTilePos(), tileEntity);
+        if(this.isLoaded) {
+            this.world.tileEntityList.add(tileEntity);
         }
     }
 
     /**
-     * @return True if the specified block entity was set
+     * @return True if the specified tile entity was set
      */
-    public boolean setTileEntity(int x, int y, int z, TileEntity tileEntity)
-    {
-        ChunkPosition chunkposition = new ChunkPosition(x, y, z);
-        tileEntity.worldObj = world;
-        tileEntity.x = xPosition * CHUNK_SIZE_X + x;
-        tileEntity.y = y;
-        tileEntity.z = zPosition * CHUNK_SIZE_Z + z;
-        Block<?> b = Blocks.blocksList[getBlockID(x, y, z)];
-        if (b == null || !b.isEntityTile)
-        {
-            LOGGER.warn("Attempted to place a tile entity {} at {} {} {} where there was no tile entity block!", tileEntity.getClass(), x, y, z);
+    public boolean setTileEntity(final @NotNull ChunkTilePos tilePos, final @NotNull TileEntity tileEntity) {
+        final @NotNull TilePos worldPos = new TilePos(this.pos, tilePos);
+
+        tileEntity.worldObj = this.world;
+        tileEntity.x = worldPos.x;
+        tileEntity.y = worldPos.y;
+        tileEntity.z = worldPos.z;
+
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        if (block == null || !block.isEntityTile) {
+            LOGGER.warn("Attempted to place a tile entity {} at {} {} {} where there was no tile entity block!", tileEntity.getClass(), worldPos.x, worldPos.y, worldPos.z);
             Thread.dumpStack();
-        }
-        else
-        {
+        } else {
             tileEntity.validate();
-            TileEntity previous = tileEntityMap.put(chunkposition, tileEntity);
+            final @Nullable TileEntity previous = this.tileEntityMap.put(tilePos, tileEntity);
             if (previous != null) {
                 previous.invalidate();
             }
+
             return true;
         }
+
         return false;
     }
 
-    public void removeTileEntity(int x, int y, int z)
-    {
-        ChunkPosition pos = new ChunkPosition(x, y, z);
-        if(isLoaded)
-        {
-            TileEntity tileEntity = tileEntityMap.remove(pos);
-            if(tileEntity != null)
-            {
+    /**
+     * @return True if the specified tile entity was set
+     */
+    @Deprecated
+    public final boolean setTileEntity(final int x, final int y, final int z, final @NotNull TileEntity tileEntity) {
+        return this.setTileEntity(new ChunkTilePos(x, y, z), tileEntity);
+    }
+
+    public void removeTileEntity(final @NotNull ChunkTilePos tilePos) {
+        if (this.isLoaded) {
+            final @Nullable TileEntity tileEntity = this.tileEntityMap.remove(tilePos);
+            if (tileEntity != null) {
                 tileEntity.invalidate();
             }
         }
     }
 
+    @Deprecated
+    public final void removeTileEntity(final int x, final int y, final int z) {
+        this.removeTileEntity(new ChunkTilePos(x, y, z));
+    }
+
     public void removeTileEntity(TileEntity tileEntity) {
-        if (isLoaded && tileEntity != null && tileEntityMap.containsValue(tileEntity)) {
-            tileEntityMap.remove(new ChunkPosition(tileEntity.x & (Chunk.CHUNK_SIZE_X - 1), tileEntity.y, tileEntity.z & (Chunk.CHUNK_SIZE_Z - 1)));
+        if (this.isLoaded && tileEntity != null && tileEntityMap.containsValue(tileEntity)) {
+            final @NotNull ChunkTilePos tilePos = new ChunkTilePos(tileEntity.x, tileEntity.y, tileEntity.z);
+            this.tileEntityMap.remove(tilePos);
             tileEntity.invalidate();
         }
     }
 
-    public void onLoad()
-    {
+    public void onLoad() {
         isLoaded = true;
         world.addAllBlockEntities(tileEntityMap.values());
 
@@ -612,10 +682,6 @@ public class Chunk
             }
         }
 
-        if (this.xPosition == 0 && this.zPosition == 0) {
-            System.out.println("Loaded 0, 0");
-        }
-
         this.scheduleLoadedUpdates();
     }
 
@@ -623,15 +689,14 @@ public class Chunk
         final @NotNull Int2ObjectMap<NextTickListEntry> oldTickList = this.tickList;
         this.tickList = new Int2ObjectArrayMap<>();
 
-        final int worldX = this.xPosition * CHUNK_SIZE_X;
-        final int worldZ = this.zPosition * CHUNK_SIZE_Z;
+        final @NotNull TilePos worldPos = new TilePos(this.pos, new ChunkTilePos(0, 0, 0));
         for (final @NotNull NextTickListEntry entry : oldTickList.values()) {
-            this.world.scheduleBlockUpdate(worldX + entry.x, entry.y, worldZ + entry.z, entry.blockId, entry.delay, true);
+            final @NotNull TilePos entryPos = new TilePos(entry.x, entry.y, entry.z);
+            this.world.scheduleBlockUpdate(worldPos.add(entryPos), entry.blockId, entry.delay, true);
         }
     }
 
-    public void onUnload()
-    {
+    public void onUnload() {
         isLoaded = false;
         TileEntity tileentity;
         for(Iterator<TileEntity> iterator = tileEntityMap.values().iterator(); iterator.hasNext(); tileentity.invalidate())
@@ -642,10 +707,6 @@ public class Chunk
         for (ChunkSection section : sections) {
             section.onUnload(world);
         }
-
-        if (this.xPosition == 0 && this.zPosition == 0) {
-            System.out.println("Unloaded 0, 0");
-        }
     }
 
     public void setChunkModified()
@@ -774,9 +835,9 @@ public class Chunk
         return startIndex;
     }
 
-    public Random getChunkRandom(long xor)
+    public @NotNull Random getChunkRandom(long xor)
     {
-        return new Random(world.getRandomSeed() + (xPosition * xPosition * 0x4c1906L) + (xPosition * 0x5ac0dbL) + (zPosition * zPosition * 0x4307a7L) + (zPosition * 0x5f24fL) ^ xor);
+        return new Random(world.getRandomSeed() + (this.pos.x * this.pos.x * 0x4c1906L) + (this.pos.x * 0x5ac0dbL) + (this.pos.z * this.pos.z * 0x4307a7L) + (this.pos.z * 0x5f24fL) ^ xor);
     }
 
     public boolean isChunkEmpty()
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
index 178a006c3..2ab5f7fb7 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
@@ -8,283 +8,228 @@ import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.biome.Biome;
+import net.minecraft.core.world.pos.ChunkPos;
+import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.core.world.season.SeasonManager;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class ChunkCache
     implements WorldSource
 {
-    private final int chunkX;
-    private final int chunkZ;
-    private final Chunk[][] chunkArray;
-    private final World worldObj;
-
-    public ChunkCache(World world, int minX, int minY, int minZ, int maxX, int maxY, int maxZ)
-    {
-        worldObj = world;
-        chunkX = Math.floorDiv(minX, Chunk.CHUNK_SIZE_X);
-        chunkZ = Math.floorDiv(minZ, Chunk.CHUNK_SIZE_Z);
-        int maxChunkX = Math.floorDiv(maxX, Chunk.CHUNK_SIZE_X);
-        int maxChunkZ = Math.floorDiv(maxZ, Chunk.CHUNK_SIZE_Z);
-        chunkArray = new Chunk[(maxChunkX - chunkX) + 1][(maxChunkZ - chunkZ) + 1];
-        for(int x = chunkX; x <= maxChunkX; x++)
-        {
-            for(int z = chunkZ; z <= maxChunkZ; z++)
-            {
-                chunkArray[x - chunkX][z - chunkZ] = world.getChunkFromChunkCoords(x, z);
+    private final @NotNull ChunkPos origin;
+    private final @NotNull Chunk @NotNull [] @NotNull [] chunkArray;
+    private final @NotNull World world;
+
+    public ChunkCache(final @NotNull World world, final @NotNull TilePos min, final @NotNull TilePos max) {
+        this.world = world;
+        this.origin = min.toChunkPos();
+
+        final @NotNull ChunkPos chunkMax = max.toChunkPos();
+        this.chunkArray = new Chunk[(chunkMax.x - this.origin.x) + 1][(chunkMax.z - this.origin.z) + 1];
+        for (int x = this.origin.x; x <= chunkMax.x; x++) {
+            for (int z = this.origin.z; z <= chunkMax.z; z++) {
+                this.chunkArray[x - this.origin.x][z - this.origin.z] = this.world.getChunk(new ChunkPos(x, z));
             }
-
         }
+    }
 
+    @Deprecated
+    public ChunkCache(final @NotNull World world, final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ) {
+        this(world, new TilePos(minX, minY, minZ), new TilePos(maxX, maxY, maxZ));
     }
 
     @Override
-	public int getBlockId(int x, int y, int z)
-    {
-        if(y < 0)
-        {
-            return 0;
-        }
-        if(y >= worldObj.getHeightBlocks())
-        {
-            return 0;
-        }
-        int l = Math.floorDiv(x, Chunk.CHUNK_SIZE_X) - chunkX;
-        int i1 = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z) - chunkZ;
-        if(l < 0 || l >= chunkArray.length || i1 < 0 || i1 >= chunkArray[l].length)
-        {
+    public int getHeightBlocks() {
+        return this.world.getHeightBlocks();
+    }
+
+    @Override
+    public int getBlockId(final @NotNull TilePos tilePos) {
+        if (tilePos.y < 0 || tilePos.y >= this.getHeightBlocks()) {
             return 0;
         }
-        Chunk chunk = chunkArray[l][i1];
-        if(chunk == null)
-        {
+
+        final @NotNull ChunkPos cachePos = tilePos.toChunkPos().sub(this.origin);
+        if (cachePos.x < 0 || cachePos.x >= this.chunkArray.length || cachePos.z < 0 || cachePos.z >= this.chunkArray[cachePos.x].length) {
             return 0;
-        } else
-        {
-            return chunk.getBlockID(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
         }
+
+        final @NotNull Chunk chunk = this.chunkArray[cachePos.x][cachePos.z];
+        return chunk.getBlockID(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.y, tilePos.z & (Chunk.CHUNK_SIZE_Z - 1));
     }
 
     @Override
-    public @Nullable Block<?> getBlock(int x, int y, int z) {
-        return Blocks.getBlock(getBlockId(x, y, z));
+    public @Nullable Block<?> getBlock(final @NotNull TilePos tilePos) {
+        return Blocks.getBlock(this.getBlockId(tilePos));
     }
 
     @Override
-	public TileEntity getTileEntity(int x, int y, int z)
-    {
-        int l = Math.floorDiv(x, Chunk.CHUNK_SIZE_X) - chunkX;
-        int i1 = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z) - chunkZ;
-        return chunkArray[l][i1].getTileEntity(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
+    public @Nullable TileEntity getTileEntity(final @NotNull TilePos tilePos) {
+        final @NotNull ChunkPos cachePos = tilePos.toChunkPos().sub(this.origin);
+        return this.chunkArray[cachePos.x][cachePos.z].getTileEntity(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.y, tilePos.z & (Chunk.CHUNK_SIZE_Z - 1));
     }
 
-    public boolean getBlockLitInteriorSurface(int x, int y, int z)
-    {
-        if(x < World.MIN_BLOCK_X || z < World.MIN_BLOCK_Z || x >= World.MAX_BLOCK_X || z > World.MAX_BLOCK_Z)
-        {
-            return true;
-        }
-        if(y < 0)
-        {
+    public boolean getBlockLitInteriorSurface(final @NotNull TilePos tilePos) {
+        if (!tilePos.inBounds(this)) {
             return true;
-        }
-        if(y >= worldObj.getHeightBlocks())
-        {
-            return true;
-        } else
-        {
-            return Block.getIsLitInteriorSurface(worldObj, x, y, z);
+        } else {
+            return Block.getIsLitInteriorSurface(this.world, tilePos);
         }
     }
 
-	@Override
-	public float getBrightness(int x, int y, int z, int blockLightValue) {
-		int i1 = getLightValue(x, y, z);
-		if(i1 < blockLightValue) {
-			i1 = blockLightValue;
-		}
-		return worldObj.worldType.getBrightnessRamp()[i1];
-	}
-
-	@Override
-	public int getLightmapCoord(int x, int y, int z, int blockLightValue) {
-		int skyLight = worldObj.getSavedLightValue(LightLayer.Sky, x, y, z);
-		int blockLight = Math.max(worldObj.getSavedLightValue(LightLayer.Block, x, y, z), blockLightValue);
-		
-		if(getBlockLitInteriorSurface(x, y, z)) {
-			skyLight = Math.max(skyLight, worldObj.getSavedLightValue(LightLayer.Sky, x, y + 1, z));
-			skyLight = Math.max(skyLight, worldObj.getSavedLightValue(LightLayer.Sky, x, y - 1, z));
-			skyLight = Math.max(skyLight, worldObj.getSavedLightValue(LightLayer.Sky, x + 1, y, z));
-			skyLight = Math.max(skyLight, worldObj.getSavedLightValue(LightLayer.Sky, x - 1, y, z));
-			skyLight = Math.max(skyLight, worldObj.getSavedLightValue(LightLayer.Sky, x, y, z + 1));
-			skyLight = Math.max(skyLight, worldObj.getSavedLightValue(LightLayer.Sky, x, y, z - 1));
-			
-			blockLight = Math.max(blockLight, worldObj.getSavedLightValue(LightLayer.Block, x, y + 1, z));
-			blockLight = Math.max(blockLight, worldObj.getSavedLightValue(LightLayer.Block, x, y - 1, z));
-			blockLight = Math.max(blockLight, worldObj.getSavedLightValue(LightLayer.Block, x + 1, y, z));
-			blockLight = Math.max(blockLight, worldObj.getSavedLightValue(LightLayer.Block, x - 1, y, z));
-			blockLight = Math.max(blockLight, worldObj.getSavedLightValue(LightLayer.Block, x, y, z + 1));
-			blockLight = Math.max(blockLight, worldObj.getSavedLightValue(LightLayer.Block, x, y, z - 1));
-		}
-		
-		return getLightmapCoord(skyLight, blockLight);
-	}
+    @Deprecated
+    public boolean getBlockLitInteriorSurface(final int x, final int y, final int z) {
+        return this.getBlockLitInteriorSurface(new TilePos(x, y, z));
+    }
 
     @Override
-    public int getLightmapCoord(int skylight, int blocklight) {
-        return worldObj.getLightmapCoord(skylight, blocklight);
+    public float getBrightness(final @NotNull TilePos tilePos, final int lightEmission) {
+        final int lightValue = this.getBlockLightValue(tilePos);
+        return this.world.getWorldType().getBrightnessRamp()[Math.max(lightValue, lightEmission)];
     }
 
     @Override
-	public float getLightBrightness(int x, int y, int z)
-    {
-        return worldObj.worldType.getBrightnessRamp()[getLightValue(x, y, z)];
+    public int getLightmapCoord(final @NotNull TilePos tilePos, final int lightEmission) {
+        int skyLight = this.world.getSavedLightValue(LightLayer.Sky, tilePos);
+        int blockLight = Math.max(this.world.getSavedLightValue(LightLayer.Block, tilePos), lightEmission);
+
+        if (this.getBlockLitInteriorSurface(tilePos)) {
+            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.up()));
+            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.down()));
+            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.east()));
+            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.west()));
+            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.south()));
+            skyLight = Math.max(skyLight, this.world.getSavedLightValue(LightLayer.Sky, tilePos.north()));
+
+            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.up()));
+            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.down()));
+            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.east()));
+            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.west()));
+            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.south()));
+            blockLight = Math.max(blockLight, this.world.getSavedLightValue(LightLayer.Block, tilePos.north()));
+        }
+
+        return this.getLightmapCoord(skyLight, blockLight);
     }
 
-    public int getLightValue(int x, int y, int z)
-    {
-        return getLightValueExt(x, y, z, true);
+    @Override
+    public int getLightmapCoord(final int skyLight, final int blockLight) {
+        return this.world.getLightmapCoord(skyLight, blockLight);
     }
 
-    public int getLightValueExt(int x, int y, int z, boolean first)
-    {
-        if(x < World.MIN_BLOCK_X || z < World.MIN_BLOCK_Z || x >= World.MAX_BLOCK_X || z > World.MAX_BLOCK_Z)
-        {
+    @Override
+    public float getLightBrightness(final @NotNull TilePos tilePos) {
+        return this.world.worldType.getBrightnessRamp()[this.getBlockLightValue(tilePos)];
+    }
+
+    public int getBlockLightValue(final @NotNull TilePos tilePos) {
+        return this.getBlockLightValue_do(tilePos, true);
+    }
+
+    @Deprecated
+    public int getLightValue(final int x, final int y, final int z) {
+        return this.getBlockLightValue(new TilePos(x, y, z));
+    }
+
+    @Deprecated
+    private int getBlockLightValue_do(final @NotNull TilePos tilePos, final boolean first) {
+        if (tilePos.x < World.MIN_BLOCK_X || tilePos.z < World.MIN_BLOCK_Z || tilePos.x >= World.MAX_BLOCK_X || tilePos.z > World.MAX_BLOCK_Z) {
             return 15;
         }
-        if(first)
-        {
-            if(getBlockLitInteriorSurface(x, y, z))
+
+        if(first) {
+            if (this.getBlockLitInteriorSurface(tilePos))
             {
-                int k1 = getLightValueExt(x, y + 1, z, false);
-                int i2 = getLightValueExt(x + 1, y, z, false);
-                int j2 = getLightValueExt(x - 1, y, z, false);
-                int k2 = getLightValueExt(x, y, z + 1, false);
-                int l2 = getLightValueExt(x, y, z - 1, false);
-                if(i2 > k1)
-                {
-                    k1 = i2;
-                }
-                if(j2 > k1)
-                {
-                    k1 = j2;
-                }
-                if(k2 > k1)
-                {
-                    k1 = k2;
-                }
-                if(l2 > k1)
-                {
-                    k1 = l2;
-                }
-                return k1;
+                final int lightUp = this.getBlockLightValue_do(tilePos.up(), false);
+                final int lightEast = this.getBlockLightValue_do(tilePos.east(), false);
+                final int lightWest = this.getBlockLightValue_do(tilePos.west(), false);
+                final int lightSouth = this.getBlockLightValue_do(tilePos.south(), false);
+                final int lightNorth = this.getBlockLightValue_do(tilePos.north(), false);
+                return Math.max(lightUp, Math.max(lightEast, Math.max(lightWest, Math.max(lightSouth, lightNorth))));
             }
         }
-        if(y < 0)
-        {
+
+        if (tilePos.y < 0) {
             return 0;
         }
-        if(y >= worldObj.getHeightBlocks())
-        {
-            int i1 = 15 - worldObj.skyDarken;
-            if(i1 < 0)
-            {
-                i1 = 0;
+
+        if (tilePos.y >= this.getHeightBlocks()) {
+            int brightness = 15 - this.world.skyDarken;
+            if(brightness < 0) {
+                brightness = 0;
             }
-            return i1;
-        } else
-        {
-            int j1 = Math.floorDiv(x, Chunk.CHUNK_SIZE_X) - chunkX;
-            int l1 = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z) - chunkZ;
-            return chunkArray[j1][l1].getRawBrightness(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1), worldObj.skyDarken);
+            return brightness;
+        } else {
+            final @NotNull ChunkPos cachePos = tilePos.toChunkPos().sub(this.origin);
+            return this.chunkArray[cachePos.x][cachePos.z].getRawBrightness(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.y, tilePos.z & (Chunk.CHUNK_SIZE_Z - 1), this.world.skyDarken);
         }
     }
 
     @Override
-	public int getBlockMetadata(int x, int y, int z)
-    {
-        if(y < 0)
-        {
+    public int getBlockData(final @NotNull TilePos tilePos) {
+        if (tilePos.y < 0 || tilePos.y >= this.getHeightBlocks()) {
             return 0;
-        }
-        if(y >= worldObj.getHeightBlocks())
-        {
-            return 0;
-        }
-        else
-        {
-            int chunkX = Math.floorDiv(x, Chunk.CHUNK_SIZE_X) - this.chunkX;
-            int chunkZ = Math.floorDiv(z, Chunk.CHUNK_SIZE_Z) - this.chunkZ;
-            return chunkArray[chunkX][chunkZ].getBlockMetadata(x & (Chunk.CHUNK_SIZE_X - 1), y, z & (Chunk.CHUNK_SIZE_Z - 1));
+        } else {
+            final @NotNull ChunkPos cachePos = tilePos.toChunkPos().sub(this.origin);
+            return this.chunkArray[cachePos.x][cachePos.z].getBlockMetadata(tilePos.x & (Chunk.CHUNK_SIZE_X - 1), tilePos.y, tilePos.z & (Chunk.CHUNK_SIZE_Z - 1));
         }
     }
 
     @Override
-	public Material getBlockMaterial(int x, int y, int z)
-    {
-        int l = getBlockId(x, y, z);
-        if(l == 0)
-        {
+    public @NotNull Material getBlockMaterial(final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        if (block == null) {
             return Material.air;
-        } else
-        {
-            return Blocks.blocksList[l].getMaterial();
+        } else {
+            return block.getMaterial();
         }
     }
 
     @Override
-	public boolean isBlockOpaqueCube(int x, int y, int z)
-    {
-        Block<?> block = Blocks.blocksList[getBlockId(x, y, z)];
-        if(block == null)
-        {
-            return false;
-        } else
-        {
-            return block.isSolidRender();
-        }
+    public boolean isBlockOpaqueCube(final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        return block != null && block.isSolidRender();
     }
 
     @Override
-	public boolean isBlockNormalCube(int x, int y, int z)
-    {
-        Block<?> block = Blocks.blocksList[getBlockId(x, y, z)];
-        if(block == null)
-        {
-            return false;
-        } else
-        {
-            return block.getMaterial().blocksMotion() && block.isCubeShaped();
-        }
+    public boolean isBlockNormalCube(final @NotNull TilePos tilePos) {
+        final @Nullable Block<?> block = this.getBlock(tilePos);
+        return block != null && block.getMaterial().isSolidBlocking() && block.renderAsNormalBlockOnCondition(this, tilePos.x, tilePos.y, tilePos.z);
     }
 
     @Override
-    public double getBlockTemperature(int x, int z) {
-        return worldObj.getBlockTemperature(x, z);
+    public double getBlockTemperature(final @NotNull TilePos tilePos) {
+        return this.world.getBlockTemperature(tilePos);
     }
 
     @Override
-    public double getBlockHumidity(int x, int z) {
-        return worldObj.getBlockHumidity(x, z);
+    public double getBlockHumidity(final @NotNull TilePos tilePos) {
+        return this.world.getBlockHumidity(tilePos);
     }
 
     @Override
-    public SeasonManager getSeasonManager() {
-        return worldObj.getSeasonManager();
+    public double getBlockVariety(final @NotNull TilePos tilePos) {
+        return this.world.getBlockVariety(tilePos);
     }
 
     @Override
-    public Biome getBlockBiome(int x, int y, int z) {
-        return worldObj.getBlockBiome(x, y, z);
+    public @NotNull SeasonManager getSeasonManager() {
+        return this.world.getSeasonManager();
     }
 
-	@Override
-	public int getSavedLightValue(LightLayer layer, int x, int y, int z) {
-		return worldObj.getSavedLightValue(layer, x, y, z);
-	}
+    @Override
+    public @NotNull Biome getBlockBiome(final @NotNull TilePos tilePos) {
+        return this.world.getBlockBiome(tilePos);
+    }
+
+    @Override
+    public int getSavedLightValue(final @NotNull LightLayer lightLayer, final @NotNull TilePos tilePos) {
+        return this.world.getSavedLightValue(lightLayer, tilePos);
+    }
 
     @Override
     public boolean isRetro() {
-        return worldObj.isRetro();
+        return this.world.isRetro();
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderLegacy.java b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderLegacy.java
index 1914a817b..139b653f5 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderLegacy.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderLegacy.java
@@ -104,7 +104,7 @@ public class ChunkLoaderLegacy
                 Chunk chunk = loadChunkIntoWorldFromCompound(world, tag.getCompound("Level"));
                 if(!chunk.isAtLocation(x, z))
                 {
-                    LOGGER.warn("Chunk file at {},{} is in the wrong location; relocating. (Expected {}, {}, got {}, {})", x, z, x, z, chunk.xPosition, chunk.zPosition);
+                    LOGGER.warn("Chunk file at {},{} is in the wrong location; relocating. (Expected {}, {}, got {}, {})", x, z, x, z, chunk.pos.x, chunk.pos.z);
                     tag.putInt("xPos", x);
                     tag.putInt("zPos", z);
                     chunk = loadChunkIntoWorldFromCompound(world, tag.getCompound("Level"));
@@ -125,7 +125,7 @@ public class ChunkLoaderLegacy
         throws IOException
     {
         world.checkSessionLock();
-        File chunkFile = chunkFileForXZ(chunk.xPosition, chunk.zPosition);
+        File chunkFile = chunkFileForXZ(chunk.pos.x, chunk.pos.z);
         if(chunkFile.exists())
         {
             LevelData levelData = world.getLevelData();
@@ -151,7 +151,7 @@ public class ChunkLoaderLegacy
         }
         catch(Exception exception)
         {
-            LOGGER.error("Exception while attempting to save chunk at X:{}, Z:{}", chunk.xPosition, chunk.zPosition, exception);
+            LOGGER.error("Exception while attempting to save chunk at X:{}, Z:{}", chunk.pos.x, chunk.pos.z, exception);
         }
     }
 
@@ -168,8 +168,8 @@ public class ChunkLoaderLegacy
         tag.putInt("Version", Global.CURRENT_CHUNK_VERSION);
 
         // Write tags
-        writer.putXPos(chunk.xPosition);
-        writer.putZPos(chunk.zPosition);
+        writer.putXPos(chunk.pos.x);
+        writer.putZPos(chunk.pos.z);
         writer.putTicksOnUnload(world.getWorldTime());
         writer.putHeightMap(chunk.heightMap);
         writer.putAverageBlockHeight(chunk.averageBlockHeight);
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderRegion.java b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderRegion.java
index 926eeecc7..b79a94178 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderRegion.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkLoaderRegion.java
@@ -53,7 +53,7 @@ public class ChunkLoaderRegion
         Chunk chunk = ChunkLoaderLegacy.loadChunkIntoWorldFromCompound(world, tag.getCompound("Level"));
         if(!chunk.isAtLocation(x, z))
         {
-            LOGGER.warn("Chunk file at {},{} is in the wrong location; relocating. (Expected {}, {}, got {}, {})", x, z, x, z, chunk.xPosition, chunk.zPosition);
+            LOGGER.warn("Chunk file at {},{} is in the wrong location; relocating. (Expected {}, {}, got {}, {})", x, z, x, z, chunk.pos.x, chunk.pos.z);
             final CompoundTag level = tag.getCompound("Level");
             level.putInt("xPos", x);
             level.putInt("zPos", z);
@@ -71,7 +71,7 @@ public class ChunkLoaderRegion
         world.checkSessionLock();
         try
         {
-            DataOutputStream regionStream = RegionFileCache.getChunkOutputStream(worldDir, chunk.xPosition, chunk.zPosition);
+            DataOutputStream regionStream = RegionFileCache.getChunkOutputStream(worldDir, chunk.pos.x, chunk.pos.z);
             CompoundTag levelTag = new CompoundTag();
             CompoundTag chunkDataTag = new CompoundTag();
             levelTag.put("Level", chunkDataTag);
@@ -79,11 +79,11 @@ public class ChunkLoaderRegion
             NbtIo.write(levelTag, regionStream);
             regionStream.close();
             LevelData levelData = world.getLevelData();
-            levelData.setSizeOnDisk(levelData.getSizeOnDisk() + (long)RegionFileCache.getSizeDelta(worldDir, chunk.xPosition, chunk.zPosition));
+            levelData.setSizeOnDisk(levelData.getSizeOnDisk() + (long)RegionFileCache.getSizeDelta(worldDir, chunk.pos.x, chunk.pos.z));
         }
         catch (Exception exception)
         {
-            LOGGER.error("Exception while attempting to save chunk at X:{}, Z:{}", chunk.xPosition, chunk.zPosition, exception);
+            LOGGER.error("Exception while attempting to save chunk at X:{}, Z:{}", chunk.pos.x, chunk.pos.z, exception);
         }
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkSection.java b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkSection.java
index b4b0cfb22..ca300f887 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkSection.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/ChunkSection.java
@@ -9,7 +9,9 @@ import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.Biome;
 import net.minecraft.core.world.data.ChunkNibbleArray;
 import net.minecraft.core.world.data.ChunkUnsignedByteArray;
+import net.minecraft.core.world.pos.ChunkSectionTilePos;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.nio.ByteBuffer;
 import java.nio.ShortBuffer;
@@ -20,136 +22,217 @@ import java.util.List;
 public class ChunkSection {
     public static final int SECTION_SIZE_Y = 16;
 
-    public Chunk chunk;
+    public final @NotNull Chunk chunk;
     public int yPosition;
 
-    public short[] blocks;
-    public ChunkUnsignedByteArray data;
-    public ChunkNibbleArray skylightMap;
-    public ChunkNibbleArray blocklightMap;
-    public byte[] biome;
-    public List<Entity> entities;
+    public short @Nullable [] blocks;
+    public @Nullable ChunkUnsignedByteArray data = null;
+    public @Nullable ChunkNibbleArray skylightMap = null;
+    public @Nullable ChunkNibbleArray blocklightMap = null;
+    public byte @NotNull [] biome = new byte[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Z * (SECTION_SIZE_Y >> 3)];
+    public @NotNull List<@NotNull Entity> entities = new ArrayList<>();
 
-    public ChunkSection(Chunk chunk, int yPosition) {
+    public ChunkSection(final @NotNull Chunk chunk, final int yPosition) {
         this.chunk = chunk;
         this.yPosition = yPosition;
-
-        this.entities = new ArrayList<>();
-        this.biome = new byte[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SIZE_Z * (SECTION_SIZE_Y >> 3)];
     }
 
     public void init() {
         this.data = new ChunkUnsignedByteArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
         this.skylightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
         this.blocklightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-        Arrays.fill(biome, (byte)-1);
+        Arrays.fill(this.biome, (byte)-1);
+    }
+
+    public static int makeBlockIndex(final @NotNull ChunkSectionTilePos sectionPos) {
+        return (sectionPos.y * Chunk.CHUNK_SIZE_Z * Chunk.CHUNK_SIZE_X) + (sectionPos.z * Chunk.CHUNK_SIZE_X) + sectionPos.x;
+    }
+
+    @Deprecated
+    public static int makeBlockIndex(final int x, final int y, final int z) {
+        return ChunkSection.makeBlockIndex(new ChunkSectionTilePos(x, y, z));
+    }
+
+    public static int makeBiomeIndex(final @NotNull ChunkSectionTilePos sectionPos) {
+        return ((sectionPos.y >> 3) * Chunk.CHUNK_SIZE_Z * Chunk.CHUNK_SIZE_X) + (sectionPos.z * Chunk.CHUNK_SIZE_X) + sectionPos.x;
     }
 
-    public static int makeBlockIndex(int x, int y, int z) {
-        return (y * Chunk.CHUNK_SIZE_Z * Chunk.CHUNK_SIZE_X) + (z * Chunk.CHUNK_SIZE_X) + x;
+    @Deprecated
+    public static int makeBiomeIndex(final int x, final int y, final int z) {
+        return ChunkSection.makeBiomeIndex(new ChunkSectionTilePos(x, y, z));
     }
 
-    public static int makeBiomeIndex(int x, int y, int z) {
-        y >>= 3;
-        return (y * Chunk.CHUNK_SIZE_Z * Chunk.CHUNK_SIZE_X) + (z * Chunk.CHUNK_SIZE_X) + x;
+    public int getBlockId(final @NotNull ChunkSectionTilePos sectionPos) {
+        if (!sectionPos.inBounds() || this.blocks == null) {
+            return 0;
+        }
+
+        return this.blocks[makeBlockIndex(sectionPos)] & 0x3FFF;
     }
 
-    public int getBlock(int x, int y, int z) {
-        if (x < 0 || x >= Chunk.CHUNK_SIZE_X || y < 0 || y >= SECTION_SIZE_Y || z < 0 || z >= Chunk.CHUNK_SIZE_Z) return 0;
-        if (blocks == null) return 0;
-        return blocks[makeBlockIndex(x, y, z)] & 0x3FFF;
+    @Deprecated
+    public int getBlock(final int x, final int y, final int z) {
+        return this.getBlockId(new ChunkSectionTilePos(x, y, z));
     }
 
-    public void setBlock(int x, int y, int z, int id) {
+    public void setBlockId(final @NotNull ChunkSectionTilePos sectionPos, final int id) {
         assert id == 0 || Blocks.getBlock(id) != null;
 
-        if (x < 0 || x >= Chunk.CHUNK_SIZE_X || y < 0 || y >= SECTION_SIZE_Y || z < 0 || z >= Chunk.CHUNK_SIZE_Z) return;
-        if (blocks == null && id == 0) {
+        if (!sectionPos.inBounds() || (this.blocks == null && id == 0)) {
             return;
-        } else if (blocks == null) {
-            blocks = new short[Chunk.CHUNK_SIZE_X * SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z];
+        } else if (this.blocks == null) {
+            this.blocks = new short[Chunk.CHUNK_SIZE_X * SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z];
         }
-        this.blocks[makeBlockIndex(x, y, z)] = (short)(id & 0x3FFF);
+
+        this.blocks[makeBlockIndex(sectionPos)] = (short) (id & 0x3FFF);
     }
 
-    public int getData(int x, int y, int z) {
-        if (x < 0 || x >= Chunk.CHUNK_SIZE_X || y < 0 || y >= SECTION_SIZE_Y || z < 0 || z >= Chunk.CHUNK_SIZE_Z) return 0;
-        if (blocks == null || data == null) {
+    @Deprecated
+    public void setBlock(final int x, final int y, final int z, final int id) {
+        this.setBlockId(new ChunkSectionTilePos(x, y, z), id);
+    }
+
+    public int getData(final @NotNull ChunkSectionTilePos sectionPos) {
+        if (!sectionPos.inBounds() || this.blocks == null || this.data == null) {
             return 0;
         }
-        return this.data.get(x, y, z);
+        return this.data.get(sectionPos.x, sectionPos.y, sectionPos.z);
+    }
+
+    @Deprecated
+    public int getData(final int x, final int y, final int z) {
+        return this.getData(new ChunkSectionTilePos(x, y, z));
     }
 
-    public void setData(int x, int y, int z, int data) {
-        if (x < 0 || x >= Chunk.CHUNK_SIZE_X || y < 0 || y >= SECTION_SIZE_Y || z < 0 || z >= Chunk.CHUNK_SIZE_Z) return;
-        if (blocks == null) {
+    public void setData(final @NotNull ChunkSectionTilePos sectionPos, final int data) {
+        if (!sectionPos.inBounds() || this.blocks == null) {
             return;
-        }
-        if (this.data == null) {
+        } else if (this.data == null) {
             this.data = new ChunkUnsignedByteArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
         }
-        this.data.set(x, y, z, data);
+
+        this.data.set(sectionPos.x, sectionPos.y, sectionPos.z, data);
     }
 
-    public Biome getBiome(int x, int y, int z) {
-        if (x < 0 || x >= Chunk.CHUNK_SIZE_X || y < 0 || y >= SECTION_SIZE_Y || z < 0 || z >= Chunk.CHUNK_SIZE_Z) return null;
-        byte biomeId = biome[makeBiomeIndex(x, y, z)];
-        if (biomeId < 0) return null;
+    @Deprecated
+    public void setData(final int x, final int y, final int z, final int data) {
+        this.setData(new ChunkSectionTilePos(x, y, z), data);
+    }
+
+    public @Nullable Biome getBiome(final @NotNull ChunkSectionTilePos sectionPos) {
+        if (!sectionPos.inBounds()) {
+            return null;
+        }
+
+        final byte biomeId = this.biome[makeBiomeIndex(sectionPos)];
+        if (biomeId < 0) {
+            return null;
+        }
+
         return Registries.BIOMES.getItemByNumericId(biomeId);
     }
 
-    public void setBiome(int x, int y, int z, Biome biome) {
-        if (x < 0 || x >= Chunk.CHUNK_SIZE_X || y < 0 || y >= SECTION_SIZE_Y || z < 0 || z >= Chunk.CHUNK_SIZE_Z) return;
-        int biomeId = Registries.BIOMES.getNumericIdOfItem(biome);
-        this.biome[makeBiomeIndex(x, y, z)] = (byte) biomeId;
+    @Deprecated
+    public @Nullable Biome getBiome(final int x, final int y, final int z) {
+        return this.getBiome(new ChunkSectionTilePos(x, y, z));
+    }
+
+    public void setBiome(final @NotNull ChunkSectionTilePos sectionPos, final @NotNull Biome biome) {
+        if (!sectionPos.inBounds()) {
+            return;
+        }
+
+        final int biomeId = Registries.BIOMES.getNumericIdOfItem(biome);
+        this.biome[makeBiomeIndex(sectionPos)] = (byte) biomeId;
+    }
+
+    @Deprecated
+    public void setBiome(final int x, final int y, final int z, final @NotNull Biome biome) {
+        this.setBiome(new ChunkSectionTilePos(x, y, z), biome);
     }
 
-    public int getBrightness(LightLayer layer, int x, int y, int z) {
-        if (x < 0 || x >= Chunk.CHUNK_SIZE_X || y < 0 || y >= SECTION_SIZE_Y || z < 0 || z >= Chunk.CHUNK_SIZE_Z) return 0;
+    public int getBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkSectionTilePos sectionPos) {
+        if (!sectionPos.inBounds()) {
+            return 0;
+        }
+
+        switch (lightLayer) {
+            case Sky -> {
+                if (this.skylightMap == null) {
+                    return 0;
+                }
+
+                return this.skylightMap.get(sectionPos.x, sectionPos.y, sectionPos.z);
+            }
+            case Block -> {
+                if (this.blocklightMap == null) {
+                    return 0;
+                }
 
-        switch (layer) {
-            case Sky:
-                if (skylightMap == null) return 0;
-                return skylightMap.get(x, y, z);
-            case Block:
-                if (blocklightMap == null) return 0;
-                return blocklightMap.get(x, y, z);
-            default:
+                return this.blocklightMap.get(sectionPos.x, sectionPos.y, sectionPos.z);
+            }
+            default -> {
                 return 0;
+            }
         }
     }
 
-    public void setBrightness(LightLayer layer, int x, int y, int z, int brightness) {
-        if (x < 0 || x >= Chunk.CHUNK_SIZE_X || y < 0 || y >= SECTION_SIZE_Y || z < 0 || z >= Chunk.CHUNK_SIZE_Z) return;
+    @Deprecated
+    public int getBrightness(final @NotNull LightLayer lightLayer, final int x, final int y, final int z) {
+        return this.getBrightness(lightLayer, new ChunkSectionTilePos(x, y, z));
+    }
+
+    public void setBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkSectionTilePos sectionPos, final int brightness) {
+        if (!sectionPos.inBounds()) {
+            return;
+        }
+
+        switch (lightLayer) {
+            case Sky -> {
+                if (this.skylightMap == null) {
+                    this.skylightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
+                }
 
-        switch (layer) {
-            case Sky:
-                if (skylightMap == null) skylightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-                skylightMap.set(x, y, z, brightness);
-                break;
-            case Block:
-                if (blocklightMap == null) blocklightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
-                blocklightMap.set(x, y, z, brightness);
-                break;
+                this.skylightMap.set(sectionPos.x, sectionPos.y, sectionPos.z, brightness);
+            }
+            case Block -> {
+                if (this.blocklightMap == null) {
+                    this.blocklightMap = new ChunkNibbleArray(Chunk.CHUNK_SIZE_X, SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z);
+                }
+
+                this.blocklightMap.set(sectionPos.x, sectionPos.y, sectionPos.z, brightness);
+            }
         }
     }
 
-    public int getRawBrightness(int x, int y, int z, int skySubtract) {
-        if (x < 0 || x >= Chunk.CHUNK_SIZE_X || y < 0 || y >= SECTION_SIZE_Y || z < 0 || z >= Chunk.CHUNK_SIZE_Z) return 0;
+    @Deprecated
+    public void setBrightness(final @NotNull LightLayer lightLayer, final int x, final int y, final int z, final int brightness) {
+        this.setBrightness(lightLayer, new ChunkSectionTilePos(x, y, z), brightness);
+    }
+
+    public int getRawBrightness(final @NotNull ChunkSectionTilePos sectionPos, final int subtractedSkyLight) {
+        if (!sectionPos.inBounds()) {
+            return 0;
+        }
 
-        return Math.max(getBrightness(LightLayer.Sky, x, y, z) - skySubtract, getBrightness(LightLayer.Block, x, y, z));
+        return Math.max(this.getBrightness(LightLayer.Sky, sectionPos) - subtractedSkyLight, this.getBrightness(LightLayer.Block, sectionPos));
     }
 
-    public void addEntity(Entity entity) {
-        entities.add(entity);
+    @Deprecated
+    public int getRawBrightness(final int x, final int y, final int z, final int subtractedSkyLight) {
+        return this.getRawBrightness(new ChunkSectionTilePos(x, y, z), subtractedSkyLight);
     }
 
-    public void removeEntity(Entity entity) {
-        entities.remove(entity);
+    public void addEntity(final @NotNull Entity entity) {
+        this.entities.add(entity);
     }
 
-    public void getEntitiesWithin(Entity toExclude, AABB aabb, List<Entity> entities) {
-        for (Entity e : this.entities) {
+    public void removeEntity(final @NotNull Entity entity) {
+        this.entities.remove(entity);
+    }
+
+    public void getEntitiesWithin(final @Nullable Entity toExclude, final @NotNull AABB aabb, final @NotNull List<@NotNull Entity> entities) {
+        for (final @NotNull Entity e : this.entities) {
             if (e != toExclude && e.bb.intersects(aabb)) {
                 entities.add(e);
             }
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java
index 0edb4b840..d71e185b7 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java
@@ -3,6 +3,10 @@ package net.minecraft.core.world.chunk;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.pos.ChunkPos;
+import net.minecraft.core.world.pos.ChunkTilePos;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class DisplayChunk extends EmptyChunk{
     public static int displayBlockId = 0;
@@ -10,59 +14,69 @@ public class DisplayChunk extends EmptyChunk{
     public static int displayBlockPosX = 0;
     public static int displayBlockPosY = 0;
     public static int displayBlockPosZ = 0;
-    public static TileEntity displayTileEntity = null;
-    public DisplayChunk(World world, int x, int z) {
-        super(world, x, z);
+    public static @Nullable TileEntity displayTileEntity = null;
+
+    public DisplayChunk(final @NotNull World world, final @NotNull ChunkPos chunkPos) {
+        super(world, chunkPos);
+    }
+
+    @Deprecated
+    public DisplayChunk(final @NotNull World world, int x, int z) {
+        this(world, new ChunkPos(x, z));
     }
+
     @Override
-    public int getBlockID(int x, int y, int z)
-    {
-        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+    public int getBlockId(final @NotNull ChunkTilePos tilePos) {
+        if (tilePos.x == displayBlockPosX && tilePos.y == displayBlockPosY && tilePos.z == displayBlockPosZ) {
             return displayBlockId;
         }
+
         return 0;
     }
+
     @Override
-    public int getBlockMetadata(int x, int y, int z)
-    {
-        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+    public int getBlockData(final @NotNull ChunkTilePos tilePos) {
+        if (tilePos.x == displayBlockPosX && tilePos.y == displayBlockPosY && tilePos.z == displayBlockPosZ) {
             return displayBlockMeta;
         }
+
         return 0;
     }
+
     @Override
-    public int getBrightness(LightLayer layer, int x, int y, int z)
-    {
+    public int getBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePos tilePos) {
         return 15;
     }
+
     @Override
-    public boolean setTileEntity(int x, int y, int z, TileEntity tileEntity)
-    {
-        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+    public boolean setTileEntity(final @NotNull ChunkTilePos tilePos, final @NotNull TileEntity tileEntity) {
+        if (tilePos.x == displayBlockPosX && tilePos.y == displayBlockPosY && tilePos.z == displayBlockPosZ) {
             displayTileEntity = tileEntity;
-            displayTileEntity.worldObj = world;
-            displayTileEntity.x = x;
-            displayTileEntity.y = y;
-            displayTileEntity.z = z;
+            displayTileEntity.worldObj = this.world;
+            displayTileEntity.x = tilePos.x;
+            displayTileEntity.y = tilePos.y;
+            displayTileEntity.z = tilePos.z;
         }
+
         return true;
     }
 
     @Override
-    public void removeTileEntity(int x, int y, int z)
-    {
-        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+    public void removeTileEntity(final @NotNull ChunkTilePos tilePos) {
+        if (tilePos.x == displayBlockPosX && tilePos.y == displayBlockPosY && tilePos.z == displayBlockPosZ) {
             displayTileEntity = null;
         }
     }
+
     @Override
-    public TileEntity getTileEntity(int x, int y, int z)
-    {
-        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+    public @Nullable TileEntity getTileEntity(final @NotNull ChunkTilePos tilePos) {
+        if (tilePos.x == displayBlockPosX && tilePos.y == displayBlockPosY && tilePos.z == displayBlockPosZ) {
             return displayTileEntity;
         }
+
         return null;
     }
+
     public static void setDisplayTileEntity(World world, TileEntity entity){
         displayTileEntity = entity;
         if (displayTileEntity != null){
@@ -74,17 +88,17 @@ public class DisplayChunk extends EmptyChunk{
     }
 
     @Override
-    public double getBlockHumidity(final int x, final int z) {
+    public double getBlockHumidity(final @NotNull ChunkTilePos tilePos) {
         return 0.5;
     }
 
     @Override
-    public double getBlockTemperature(final int x, final int z) {
+    public double getBlockTemperature(final @NotNull ChunkTilePos tilePos) {
         return 0.5;
     }
 
     @Override
-    public double getBlockVariety(final int x, final int z) {
+    public double getBlockVariety(final @NotNull ChunkTilePos tilePos) {
         return 0.5;
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java
index c1aa0b772..0d16c9da0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java
+++ b/game/core/src/main/java/net/minecraft/core/world/chunk/EmptyChunk.java
@@ -5,203 +5,156 @@ import net.minecraft.core.entity.Entity;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.enums.LightLayer;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.pos.ChunkPos;
+import net.minecraft.core.world.pos.ChunkTilePos;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 
-public class EmptyChunk extends Chunk
-{
+public class EmptyChunk extends Chunk {
+    public EmptyChunk(final @NotNull World world, final @NotNull ChunkPos chunkPos) {
+        super(world, chunkPos);
 
-    public EmptyChunk(World world, int i, int j)
-    {
-        super(world, i, j);
-        // TODO, find out why we have init methods that are never actually used
-        for (ChunkSection section : sections) {
-            if (section != null) {
-                section.init();
-            }
-        }
-        neverSave = true;
+        this.neverSave = true;
     }
 
-    @Override
-    public boolean isAtLocation(int x, int z)
-    {
-        return x == xPosition && z == zPosition;
+    @Deprecated
+    public EmptyChunk(final @NotNull World world, final int x, final int z) {
+        this(world, new ChunkPos(x, z));
     }
 
     @Override
-    public int getHeightValue(int x, int z)
-    {
+    public int getHeightValue(final int x, final int z) {
         return 0;
     }
 
     @Override
-    public void recalcHeightmapOnly()
-    {
-    }
+    public void recalcHeightmapOnly() { }
 
     @Override
-    public void recalcHeightmap()
-    {
-    }
+    public void recalcHeightmap() { }
 
     @Override
-	public int getBlockID(int x, int y, int z)
-    {
+    public int getBlockId(final @NotNull ChunkTilePos tilePos) {
         return 0;
     }
 
     @Override
-	public boolean setBlockIDWithMetadata(int x, int y, int z, int id, int data)
-    {
+    public boolean setBlockIdData(final @NotNull ChunkTilePos tilePos, final int id, final int data) {
         return true;
     }
 
     @Override
-	public boolean setBlockID(int x, int y, int z, int id)
-    {
+    public boolean setBlockId(final @NotNull ChunkTilePos tilePos, final int id) {
         return true;
     }
 
     @Override
-	public int getBlockMetadata(int x, int y, int z)
-    {
+    public int getBlockData(final @NotNull ChunkTilePos tilePos) {
         return 0;
     }
 
     @Override
-	public void setBlockMetadata(int x, int y, int z, int value)
-    {
+    public boolean setBlockData(final @NotNull ChunkTilePos tilePos, final int value) {
+        return true;
     }
 
     @Override
-	public int getBrightness(LightLayer layer, int x, int y, int z)
-    {
+    public int getBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePos tilePos) {
         return 0;
     }
 
     @Override
-	public void setBrightness(LightLayer layer, int x, int y, int z, int value)
-    {
-    }
+    public void setBrightness(final @NotNull LightLayer lightLayer, final @NotNull ChunkTilePos tilePos, final int value) { }
 
     @Override
-	public int getRawBrightness(int x, int y, int z, int skySubtract)
-    {
+    public int getRawBrightness(final @NotNull ChunkTilePos tilePos, final int subtractedSkyLight) {
         return 0;
     }
 
     @Override
-	public void addEntity(Entity entity)
-    {
-    }
+    public void addEntity(final @NotNull Entity entity) { }
 
     @Override
-	public void removeEntity(Entity entity)
-    {
-    }
+    public void removeEntity(final @NotNull Entity entity) { }
 
     @Override
-	public void removeEntityAtIndex(Entity entity, int index)
-    {
-    }
+    public void removeEntityAtIndex(final @NotNull Entity entity, final int index) { }
 
     @Override
-	public boolean canBlockSeeTheSky(int x, int y, int z)
-    {
+    public boolean canBlockSeeSky(final @NotNull ChunkTilePos tilePos) {
         return false;
     }
 
     @Override
-	public TileEntity getTileEntity(int x, int y, int z)
-    {
+    public @Nullable TileEntity getTileEntity(final @NotNull ChunkTilePos tilePos) {
         return null;
     }
 
     @Override
-	public void addTileEntity(TileEntity tileEntity)
-    {
-    }
+    public void addTileEntity(final @NotNull TileEntity tileEntity) { }
 
     @Override
-	public boolean setTileEntity(int x, int y, int z, TileEntity tileEntity)
-    {
+    public boolean setTileEntity(final @NotNull ChunkTilePos tilePos, final @NotNull TileEntity tileEntity) {
         return false;
     }
 
     @Override
-	public void removeTileEntity(int x, int y, int z)
-    {
-    }
+    public void removeTileEntity(final @NotNull ChunkTilePos tilePos) { }
 
     @Override
-	public void onLoad()
-    {
-    }
+    public void onLoad() { }
 
     @Override
-	public void onUnload()
-    {
-    }
+    public void onUnload() { }
 
     @Override
-	public void setChunkModified()
-    {
-    }
+    public void setChunkModified() { }
 
     @Override
-	public void getEntitiesWithin(Entity toExclude, AABB aabb, List<Entity> entities)
-    {
-    }
+    public void getEntitiesWithin(final Entity toExclude, final AABB aabb, final List<Entity> entities) { }
 
     @Override
-    public <T extends Entity> void getEntitiesWithin(Class<T> ofClass, AABB aabb, List<@NotNull T> entities) {
-
-    }
+    public <T extends Entity> void getEntitiesWithin(final Class<T> ofClass, final AABB aabb, final List<@NotNull T> entities) { }
 
     @Override
-	public boolean needsSaving(boolean saveImmediately)
-    {
+    public boolean needsSaving(final boolean saveImmediately) {
         return false;
     }
 
     @Override
-	public int setChunkData(byte data[], int minX, int minY, int minZ, int maxX, int maxY, int maxZ,
-                            int startIndex)
-    {
-        int dx = maxX - minX;
-        int dy = maxY - minY;
-        int dz = maxZ - minZ;
-        int chunkSizeBlocks = dx * dy * dz;
+    public int setChunkData(final byte[] data, final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ,
+                            final int startIndex) {
+        final int dx = maxX - minX;
+        final int dy = maxY - minY;
+        final int dz = maxZ - minZ;
+        final int chunkSizeBlocks = dx * dy * dz;
         return (chunkSizeBlocks * 2) + chunkSizeBlocks + (chunkSizeBlocks / 2) * 2;
     }
-    
-    @Override
-	public int getChunkData(byte data[], int minX, int minY, int minZ, int maxX, int maxY, int maxZ,
-                            int startIndex)
-    {
-        int dx = maxX - minX;
-        int dy = maxY - minY;
-        int dz = maxZ - minZ;
-        int chunkSizeBlocks = dx * dy * dz;
-        int dataSize = (chunkSizeBlocks * 2) + chunkSizeBlocks + (chunkSizeBlocks / 2) * 2;
-        Arrays.fill(data, startIndex, startIndex + dataSize, (byte)0);
+
+    @Override
+    public int getChunkData(final byte[] data, final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ,
+                            final int startIndex) {
+        final int dx = maxX - minX;
+        final int dy = maxY - minY;
+        final int dz = maxZ - minZ;
+        final int chunkSizeBlocks = dx * dy * dz;
+        final int dataSize = (chunkSizeBlocks * 2) + chunkSizeBlocks + (chunkSizeBlocks / 2) * 2;
+        Arrays.fill(data, startIndex, startIndex + dataSize, (byte) 0);
         return dataSize;
     }
 
 
     @Override
-	public Random getChunkRandom(long xor)
-    {
-        return new Random(world.getRandomSeed() + (long)(xPosition * xPosition * 0x4c1906) + (long)(xPosition * 0x5ac0db) + (long)(zPosition * zPosition) * 0x4307a7L + (long)(zPosition * 0x5f24f) ^ xor);
+    public @NotNull Random getChunkRandom(final long xor) {
+        return new Random(this.world.getRandomSeed() + ((long) this.pos.x * this.pos.x * 0x4c1906) + (this.pos.x * 0x5ac0dbL) + (long) this.pos.z * this.pos.z * 0x4307a7L + (this.pos.z * 0x5f24fL) ^ xor);
     }
 
     @Override
-	public boolean isChunkEmpty()
-    {
+    public boolean isChunkEmpty() {
         return true;
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/data/ChunkNibbleArray.java b/game/core/src/main/java/net/minecraft/core/world/data/ChunkNibbleArray.java
index 616f2e242..3bf581205 100644
--- a/game/core/src/main/java/net/minecraft/core/world/data/ChunkNibbleArray.java
+++ b/game/core/src/main/java/net/minecraft/core/world/data/ChunkNibbleArray.java
@@ -1,5 +1,7 @@
 package net.minecraft.core.world.data;
 
+import org.jetbrains.annotations.NotNull;
+
 /**
  * Models an array of nibbles that is accessible by X, Y and Z coordinates.
  */
@@ -34,7 +36,7 @@ public class ChunkNibbleArray
     }
 
     @Override
-    public Integer get(int x, int y, int z)
+    public @NotNull Integer get(int x, int y, int z)
     {
         int index = (y * zSize * xSize) + (z * xSize) + x;
         int nibbleIndex = index >> 1;
diff --git a/game/core/src/main/java/net/minecraft/core/world/data/ChunkUnsignedByteArray.java b/game/core/src/main/java/net/minecraft/core/world/data/ChunkUnsignedByteArray.java
index 91540d6ec..093a0b00c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/data/ChunkUnsignedByteArray.java
+++ b/game/core/src/main/java/net/minecraft/core/world/data/ChunkUnsignedByteArray.java
@@ -1,6 +1,8 @@
 package net.minecraft.core.world.data;
 
 
+import org.jetbrains.annotations.NotNull;
+
 /**
  * Models an array of unsigned bytes that is accessible by X, Y and Z coordinates.
  */
@@ -35,7 +37,7 @@ public class ChunkUnsignedByteArray
     }
 
     @Override
-    public Integer get(int x, int y, int z)
+    public @NotNull Integer get(int x, int y, int z)
     {
         int index = (y * zSize * xSize) + (z * xSize) + x;
         return Byte.toUnsignedInt(data[index]);
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java
index 5f39eaa7d..ccbdcc2df 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java
@@ -44,8 +44,8 @@ public abstract class ChunkFeatureDecorator
         this.world.scheduledUpdatesAreImmediate = true;
         BlockLogicSand.fallInstantly = true;
 
-        final int chunkX = chunk.xPosition;
-        final int chunkZ = chunk.zPosition;
+        final int chunkX = chunk.pos.x;
+        final int chunkZ = chunk.pos.z;
         final int worldX = chunkX * 16;
         final int worldZ = chunkZ * 16;
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
index 9e640a581..45986e208 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/classic/ChunkGeneratorClassic.java
@@ -47,8 +47,8 @@ public class ChunkGeneratorClassic
     {
         ChunkGeneratorResult result = new ChunkGeneratorResult();
 
-        int chunkX = chunk.xPosition;
-        int chunkZ = chunk.zPosition;
+        int chunkX = chunk.pos.x;
+        int chunkZ = chunk.pos.z;
 
         final float mod = 1.3F;
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/debug/ChunkDecoratorDebug.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/debug/ChunkDecoratorDebug.java
index 131e1dc52..a052ce914 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/debug/ChunkDecoratorDebug.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/debug/ChunkDecoratorDebug.java
@@ -10,8 +10,8 @@ public class ChunkDecoratorDebug
     @Override
     public void decorate(Chunk chunk)
     {
-        int chunkX = chunk.xPosition;
-        int chunkZ = chunk.zPosition;
+        int chunkX = chunk.pos.x;
+        int chunkZ = chunk.pos.z;
 
         int chunkBlockOffset = chunkX * (Chunk.CHUNK_SIZE_X / 2);
         int chunkMetaOffset = chunkZ * (Chunk.CHUNK_SIZE_Z / 2);
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/empty/ChunkDecoratorEmpty.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/empty/ChunkDecoratorEmpty.java
index 2fbafffa9..8376e7b5f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/empty/ChunkDecoratorEmpty.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/empty/ChunkDecoratorEmpty.java
@@ -10,7 +10,7 @@ public class ChunkDecoratorEmpty
     @Override
     public void decorate(Chunk chunk)
     {
-        if (chunk.xPosition == 0 && chunk.zPosition == 0)
+        if (chunk.pos.x == 0 && chunk.pos.z == 0)
         {
             chunk.setBlockID(0, 0, 0, Blocks.BEDROCK.id());
         }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/indev/ChunkGeneratorIndev.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/indev/ChunkGeneratorIndev.java
index a490a6f92..9073d64aa 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/indev/ChunkGeneratorIndev.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/indev/ChunkGeneratorIndev.java
@@ -31,8 +31,8 @@ public class ChunkGeneratorIndev
     {
         ChunkGeneratorResult result = new ChunkGeneratorResult();
 
-        int chunkX = chunk.xPosition;
-        int chunkZ = chunk.zPosition;
+        int chunkX = chunk.pos.x;
+        int chunkZ = chunk.pos.z;
 
         lg.generate(world, result, chunkX * Chunk.CHUNK_SIZE_X, chunkZ * Chunk.CHUNK_SIZE_Z);
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/ChunkGeneratorPerlin.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/ChunkGeneratorPerlin.java
index 59acb350e..eccb5ddb1 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/ChunkGeneratorPerlin.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/ChunkGeneratorPerlin.java
@@ -36,7 +36,7 @@ public class ChunkGeneratorPerlin
         ChunkGeneratorResult result = terrainGenerator.generateTerrain(chunk, densityMap);
         surfaceGenerator.generateSurface(chunk, result);
         for (LargeFeature largeFeature : largeFeatures) {
-            largeFeature.generate(world, chunk.xPosition, chunk.zPosition, result);
+            largeFeature.generate(world, chunk.pos.x, chunk.pos.z, result);
         }
 
         return result;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/TerrainGeneratorLerp.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/TerrainGeneratorLerp.java
index 95f030f9d..227e6d6a0 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/TerrainGeneratorLerp.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/TerrainGeneratorLerp.java
@@ -25,7 +25,7 @@ public abstract class TerrainGeneratorLerp
     {
         int terrainHeight = (world.getWorldType().getMaxY() + 1) - world.getWorldType().getMinY();
 
-        rand.setSeed((long) chunk.xPosition * 0x4F9939F508L + (long) chunk.zPosition * 0x1EF1565BD5L);
+        rand.setSeed((long) chunk.pos.x * 0x4F9939F508L + (long) chunk.pos.z * 0x1EF1565BD5L);
 
         // Number of blocks per chunk.
         final int xBlocksPerChunk = Chunk.CHUNK_SIZE_X;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
index 8e3b726d9..f379e4f54 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/drift/DensityGeneratorDrift.java
@@ -35,9 +35,9 @@ public class DensityGeneratorDrift
         int xSize = 4 + 1;
         int ySize = (terrainHeight / 8) + 1;
         int zSize = 4 + 1;
-        int x = chunk.xPosition * 4;
+        int x = chunk.pos.x * 4;
         int y = 0;
-        int z = chunk.zPosition * 4;
+        int z = chunk.pos.z * 4;
 
         double[] densityMapArray = new double[xSize * ySize * zSize];
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java
index 4122b4bc5..0dda34cd8 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/ChunkDecoratorNether.java
@@ -27,8 +27,8 @@ public class ChunkDecoratorNether
     @Override
     public void decorate(Chunk chunk)
     {
-        int chunkX = chunk.xPosition;
-        int chunkZ = chunk.zPosition;
+        int chunkX = chunk.pos.x;
+        int chunkZ = chunk.pos.z;
 
         int minY = world.getWorldType().getMinY();
         int maxY = world.getWorldType().getMaxY();
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
index bb68f8bda..d47ca2b9a 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/DensityGeneratorNether.java
@@ -75,9 +75,9 @@ public class DensityGeneratorNether
         int xSize = 4 + 1;
         int ySize = (terrainHeight / 8) + 1;
         int zSize = 4 + 1;
-        int x = chunk.xPosition * 4;
+        int x = chunk.pos.x * 4;
         int y = 0;
-        int z = chunk.zPosition * 4;
+        int z = chunk.pos.z * 4;
 
         int quarterYSize = ((terrainHeight / 4) / 8) + 1;
         int threeQuarterYSize = ((int) (terrainHeight * 0.75f) / 8) + 1;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
index 49223206e..96324187b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/SurfaceGeneratorNether.java
@@ -30,8 +30,8 @@ public class SurfaceGeneratorNether
         int oceanY = world.getWorldType().getOceanY();
         int minY = world.getWorldType().getMinY();
         int maxY = world.getWorldType().getMaxY();
-        int chunkX = chunk.xPosition;
-        int chunkZ = chunk.zPosition;
+        int chunkX = chunk.pos.x;
+        int chunkZ = chunk.pos.z;
 
         int oceanBlock = world.getWorldType().getOceanBlockId();
         int worldFillBlock = world.getWorldType().getFillerBlockId();
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
index 71a31876d..38764c185 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/nether/TerrainGeneratorNether.java
@@ -75,10 +75,10 @@ public class TerrainGeneratorNether
                 lastBiomePosZ = chunk.getBlockBiome(x, 0, z + 1);
             }
         }
-        if (lastChunkX != chunk.xPosition || lastChunkZ != chunk.zPosition) {
-            lastChunkX = chunk.xPosition;
-            lastChunkZ = chunk.zPosition;
-            noise.get(cache, chunk.xPosition * Chunk.CHUNK_SIZE_X, 0, chunk.zPosition * Chunk.CHUNK_SIZE_Z, Chunk.CHUNK_SIZE_X, Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, 0.2, 0.2, 0.2);
+        if (lastChunkX != chunk.pos.x || lastChunkZ != chunk.pos.z) {
+            lastChunkX = chunk.pos.x;
+            lastChunkZ = chunk.pos.z;
+            noise.get(cache, chunk.pos.x * Chunk.CHUNK_SIZE_X, 0, chunk.pos.z * Chunk.CHUNK_SIZE_Z, Chunk.CHUNK_SIZE_X, Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, 0.2, 0.2, 0.2);
 
             float avg = 0;
             for (int i = 0; i < cache.length; i++) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
index 63a25d670..0ac0bb076 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
@@ -47,8 +47,8 @@ public class ChunkDecoratorOverworld
     public void decorate(Chunk chunk)
     {
         world.scheduledUpdatesAreImmediate = true;
-        int chunkX = chunk.xPosition;
-        int chunkZ = chunk.zPosition;
+        int chunkX = chunk.pos.x;
+        int chunkZ = chunk.pos.z;
 
         int minY = world.getWorldType().getMinY();
         int maxY = world.getWorldType().getMaxY();
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java
index 4d985b1bb..3097a4e04 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/DensityGeneratorOverworld.java
@@ -165,9 +165,9 @@ public class DensityGeneratorOverworld
         int xSize = 4 + 1;
         int ySize = (terrainHeight / 8) + 1;
         int zSize = 4 + 1;
-        int x = chunk.xPosition * 4;
+        int x = chunk.pos.x * 4;
         int y = 0;
-        int z = chunk.zPosition * 4;
+        int z = chunk.pos.z * 4;
 
         double[] densityMapArray = new double[xSize * ySize * zSize];
 
@@ -304,8 +304,8 @@ public class DensityGeneratorOverworld
 
         if (generateRivers)
         {
-            modifyDensityMapSmoothingRivers(chunk.xPosition, chunk.zPosition, terrainHeight, densityMapArray);
-            modifyDensityMapCarvingRivers(chunk.xPosition, chunk.zPosition, terrainHeight, densityMapArray);
+            modifyDensityMapSmoothingRivers(chunk.pos.x, chunk.pos.z, terrainHeight, densityMapArray);
+            modifyDensityMapCarvingRivers(chunk.pos.x, chunk.pos.z, terrainHeight, densityMapArray);
         }
 
         return densityMapArray;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
index 62086b02e..5b19f7e02 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/SurfaceGeneratorOverworld.java
@@ -49,8 +49,8 @@ public class SurfaceGeneratorOverworld
         int minY = world.getWorldType().getMinY();
         int maxY = world.getWorldType().getMaxY();
         int terrainHeight = (maxY + 1) - minY;
-        int chunkX = chunk.xPosition;
-        int chunkZ = chunk.zPosition;
+        int chunkX = chunk.pos.x;
+        int chunkZ = chunk.pos.z;
 
         int oceanBlock = world.getWorldType().getOceanBlockId();
         int worldFillBlock = world.getWorldType().getFillerBlockId();
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
index 432c9a201..316ad138b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/b173/ChunkDecoratorOverworldB173.java
@@ -32,8 +32,8 @@ public class ChunkDecoratorOverworldB173
         this.world.scheduledUpdatesAreImmediate = true;
         BlockLogicSand.fallInstantly = true;
 
-        final int x = chunk.xPosition;
-        final int z = chunk.zPosition;
+        final int x = chunk.pos.x;
+        final int z = chunk.pos.z;
 
         final int minY = this.world.getWorldType().getMinY();
         final int maxY = this.world.getWorldType().getMaxY();
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
index 52c6c1440..367024d93 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
@@ -229,10 +229,10 @@ public class ChunkDecoratorOverworldHell
 
     @Override
     public void postDecorate(@NotNull final World world, @NotNull final Chunk chunk) {
-        final int chunkX = chunk.xPosition;
-        final int chunkZ = chunk.zPosition;
-        final int worldX = chunkX * 16;
-        final int worldZ = chunkZ * 16;
+        final int x = chunk.pos.x;
+        final int z = chunk.pos.z;
+        final int worldX = x * 16;
+        final int worldZ = z * 16;
 
         final int minY = world.getWorldType().getMinY();
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java
index b10498dcc..cbb5bea1e 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/retro/ChunkDecoratorOverworldRetro.java
@@ -39,8 +39,8 @@ public class ChunkDecoratorOverworldRetro
     public void decorate(Chunk chunk)
     {
         world.scheduledUpdatesAreImmediate = true;
-        int chunkX = chunk.xPosition;
-        int chunkZ = chunk.zPosition;
+        int chunkX = chunk.pos.x;
+        int chunkZ = chunk.pos.z;
 
         int minY = world.getWorldType().getMinY();
         int maxY = world.getWorldType().getMaxY();
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java
index 28d803342..2f734c0e9 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblock.java
@@ -43,7 +43,7 @@ public class ChunkDecoratorSkyblock
     }
 
     private boolean contains(Chunk chunk, int xBlock, int zBlock) {
-        return chunk.xPosition == xBlock >> 4 && chunk.zPosition == zBlock >> 4;
+        return chunk.pos.x == xBlock >> 4 && chunk.pos.z == zBlock >> 4;
     }
 
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblockNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblockNether.java
index 465c27272..9ec3ab391 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblockNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkDecoratorSkyblockNether.java
@@ -39,7 +39,7 @@ public class ChunkDecoratorSkyblockNether
     }
 
     private boolean contains(Chunk chunk, int xBlock, int zBlock) {
-        return chunk.xPosition == xBlock >> 4 && chunk.zPosition == zBlock >> 4;
+        return chunk.pos.x == xBlock >> 4 && chunk.pos.z == zBlock >> 4;
     }
 
     private void tryPlace(Chunk chunk, int xBlock, int yBlock, int zBlock, int blockId) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkGeneratorSkyblock.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkGeneratorSkyblock.java
index 553869805..559ff5511 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkGeneratorSkyblock.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkGeneratorSkyblock.java
@@ -55,7 +55,7 @@ public class ChunkGeneratorSkyblock
     }
 
     private boolean contains(Chunk chunk, int xBlock, int zBlock) {
-        return chunk.xPosition == xBlock >> 4 && chunk.zPosition == zBlock >> 4;
+        return chunk.pos.x == xBlock >> 4 && chunk.pos.z == zBlock >> 4;
     }
 
     private void tryPlace(Chunk chunk, ChunkGeneratorResult result, int xBlock, int yBlock, int zBlock, int blockId) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkGeneratorSkyblockNether.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkGeneratorSkyblockNether.java
index 3fe19c1dd..5111ca851 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkGeneratorSkyblockNether.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/skyblock/ChunkGeneratorSkyblockNether.java
@@ -46,7 +46,7 @@ public class ChunkGeneratorSkyblockNether
     }
 
     private boolean contains(Chunk chunk, int xBlock, int zBlock) {
-        return chunk.xPosition == xBlock >> 4 && chunk.zPosition == zBlock >> 4;
+        return chunk.pos.x == xBlock >> 4 && chunk.pos.z == zBlock >> 4;
     }
 
     private void tryPlace(Chunk chunk, ChunkGeneratorResult result, int xBlock, int yBlock, int zBlock, int blockId) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMudPatch.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMudPatch.java
index 99a477556..46f213224 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMudPatch.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMudPatch.java
@@ -12,8 +12,8 @@ public class WorldFeatureMudPatch extends WorldFeature
 
     @Override
 	public boolean place(World world, Random random, int x, int y, int z) {
-        int chunkCoordX = world.getChunkFromBlockCoords(x, z).xPosition * 16;
-        int chunkCoordZ = world.getChunkFromBlockCoords(x, z).zPosition * 16;
+        int chunkCoordX = world.getChunkFromBlockCoords(x, z).pos.x * 16;
+        int chunkCoordZ = world.getChunkFromBlockCoords(x, z).pos.z * 16;
 
 
         for (int chunkX = chunkCoordX; chunkX < chunkCoordX + 16; chunkX++) {
diff --git a/game/core/src/main/java/net/minecraft/core/world/pos/ChunkPos.java b/game/core/src/main/java/net/minecraft/core/world/pos/ChunkPos.java
index 296231e86..d3b7d675d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/pos/ChunkPos.java
+++ b/game/core/src/main/java/net/minecraft/core/world/pos/ChunkPos.java
@@ -1,12 +1,12 @@
 package net.minecraft.core.world.pos;
 
 import net.minecraft.core.entity.Entity;
-import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.chunk.Chunk;
 import org.jetbrains.annotations.NotNull;
 
-public final class ChunkPos {
+public final class ChunkPos
+ implements Pos2i<ChunkPos> {
     public int x;
     public int z;
 
@@ -17,8 +17,8 @@ public final class ChunkPos {
 
     public ChunkPos(final @NotNull TilePos tilePos) {
         this(
-            MathHelper.floorIntDiv(tilePos.x, Chunk.CHUNK_SIZE_X),
-            MathHelper.floorIntDiv(tilePos.z, Chunk.CHUNK_SIZE_Z)
+            Math.floorDiv(tilePos.x, Chunk.CHUNK_SIZE_X),
+            Math.floorDiv(tilePos.z, Chunk.CHUNK_SIZE_Z)
         );
     }
 
@@ -29,32 +29,22 @@ public final class ChunkPos {
         );
     }
 
-    public @NotNull TilePos toTilePos(final @NotNull ChunkTilePos chunkTilePos) {
-        return new TilePos(this, chunkTilePos);
-    }
-
-    public @NotNull ChunkPos add(final int x, final int z) {
-        return new ChunkPos(this.x + x, this.z + z);
-    }
-
-    public @NotNull ChunkPos add(final @NotNull ChunkPos other) {
-        return new ChunkPos(this.x + other.x, this.z + other.z);
-    }
-
-    public @NotNull ChunkPos add(final @NotNull Direction direction, final int distance) {
-        return new ChunkPos(this.x + direction.getOffsetX() * distance, this.z + direction.getOffsetZ() * distance);
+    @Override
+    public int x() {
+        return this.x;
     }
 
-    public @NotNull ChunkPos add(final @NotNull Direction direction) {
-        return this.add(direction, 1);
+    @Override
+    public int z() {
+        return this.z;
     }
 
-    public @NotNull ChunkPos sub(final int x, final int z) {
-        return new ChunkPos(this.x - x, this.z - z);
+    public @NotNull ChunkPos add(final int x, final int z) {
+        return new ChunkPos(this.x + x, this.z + z);
     }
 
-    public @NotNull ChunkPos sub(final @NotNull ChunkPos other) {
-        return new ChunkPos(this.x - other.x, this.z - other.z);
+    public @NotNull TilePos toTilePos(final @NotNull ChunkTilePos chunkTilePos) {
+        return new TilePos(this, chunkTilePos);
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/pos/ChunkSectionTilePos.java b/game/core/src/main/java/net/minecraft/core/world/pos/ChunkSectionTilePos.java
new file mode 100644
index 000000000..75ca95dc9
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/pos/ChunkSectionTilePos.java
@@ -0,0 +1,87 @@
+package net.minecraft.core.world.pos;
+
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.chunk.Chunk;
+import net.minecraft.core.world.chunk.ChunkSection;
+import org.jetbrains.annotations.NotNull;
+
+public class ChunkSectionTilePos
+    implements Pos3i<ChunkSectionTilePos> {
+    public int x;
+    public int y;
+    public int z;
+
+    public ChunkSectionTilePos(final int x, final int y, final int z) {
+        this.x = Integer.remainderUnsigned(x, Chunk.CHUNK_SIZE_X);
+        this.y = Integer.remainderUnsigned(y, ChunkSection.SECTION_SIZE_Y);
+        this.z = Integer.remainderUnsigned(z, Chunk.CHUNK_SIZE_Z);
+    }
+
+    public ChunkSectionTilePos(final float x, final float y, final float z) {
+        this(MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z));
+    }
+
+    public ChunkSectionTilePos(final double x, final double y, final double z) {
+        this(MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z));
+    }
+
+    public ChunkSectionTilePos(final @NotNull ChunkTilePos tilePos) {
+        this(tilePos.x, tilePos.y, tilePos.z);
+    }
+
+    public ChunkSectionTilePos(final @NotNull TilePos tilePos) {
+        this(tilePos.x, tilePos.y, tilePos.z);
+    }
+
+    public ChunkSectionTilePos(final @NotNull Vec3 vec) {
+        this(vec.x, vec.y, vec.z);
+    }
+
+    public ChunkSectionTilePos(final @NotNull Entity entity) {
+        this(entity.x, entity.y, entity.z);
+    }
+
+    @Override
+    public int x() {
+        return this.x;
+    }
+
+    @Override
+    public int y() {
+        return this.y;
+    }
+
+    @Override
+    public int z() {
+        return this.z;
+    }
+
+    @Override
+    public @NotNull ChunkSectionTilePos add(final int x, final int y, final int z) {
+        return new ChunkSectionTilePos(this.x + x, this.y + y, this.z + z);
+    }
+
+    public @NotNull ChunkTilePos toChunkTilePos(final int sectionIndex) {
+        return new ChunkTilePos(this.x, this.y + sectionIndex * ChunkSection.SECTION_SIZE_Y, this.z);
+    }
+
+    public boolean inBounds() {
+        return this.x >= 0 && this.x < Chunk.CHUNK_SIZE_X && this.y >= 0 && this.y < ChunkSection.SECTION_SIZE_Y && this.z >= 0 && this.z < Chunk.CHUNK_SIZE_Z;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (!(obj instanceof final @NotNull ChunkSectionTilePos other)) {
+            return false;
+        } else {
+            return this.x == other.x && this.y == other.y && this.z == other.z;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return MathHelper.cantor(MathHelper.cantor(this.x, this.y), this.z);
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/pos/ChunkTilePos.java b/game/core/src/main/java/net/minecraft/core/world/pos/ChunkTilePos.java
index c579e6c2e..7a8a5571f 100644
--- a/game/core/src/main/java/net/minecraft/core/world/pos/ChunkTilePos.java
+++ b/game/core/src/main/java/net/minecraft/core/world/pos/ChunkTilePos.java
@@ -1,14 +1,15 @@
 package net.minecraft.core.world.pos;
 
 import net.minecraft.core.entity.Entity;
-import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.Vec3;
 import net.minecraft.core.world.chunk.Chunk;
+import net.minecraft.core.world.chunk.ChunkSection;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public final class ChunkTilePos {
+public final class ChunkTilePos
+    implements Pos3i<ChunkTilePos> {
     public int x;
     public int y;
     public int z;
@@ -39,32 +40,39 @@ public final class ChunkTilePos {
         this(entity.x, entity.y, entity.z);
     }
 
-    public @NotNull TilePos toTilePos(final @NotNull ChunkPos chunkPos) {
-        return new TilePos(chunkPos, this);
+    @Override
+    public int x() {
+        return this.x;
     }
 
-    public @NotNull ChunkTilePos add(final int x, final int y, final int z) {
-        return new ChunkTilePos(this.x + x, this.y + y, this.z + z);
+    @Override
+    public int y() {
+        return this.y;
     }
 
-    public @NotNull ChunkTilePos add(final @NotNull TilePos other) {
-        return new ChunkTilePos(this.x + other.x, this.y + other.y, this.z + other.z);
+    @Override
+    public int z() {
+        return this.z;
     }
 
-    public @NotNull ChunkTilePos add(final @NotNull Direction direction, final int distance) {
-        return new ChunkTilePos(this.x + direction.getOffsetX() * distance, this.y + direction.getOffsetY() * distance, this.z + direction.getOffsetZ() * distance);
+    public @NotNull ChunkTilePos add(final int x, final int y, final int z) {
+        return new ChunkTilePos(this.x + x, this.y + y, this.z + z);
+    }
+
+    public @NotNull TilePos toTilePos(final @NotNull ChunkPos chunkPos) {
+        return new TilePos(chunkPos, this);
     }
 
-    public @NotNull ChunkTilePos add(final @NotNull Direction direction) {
-        return this.add(direction, 1);
+    public @NotNull ChunkSectionTilePos toChunkSectionTilePos() {
+        return new ChunkSectionTilePos(this);
     }
 
-    public @NotNull ChunkTilePos sub(final int x, final int y, final int z) {
-        return new ChunkTilePos(this.x - x, this.y - y, this.z - z);
+    public boolean inBounds() {
+        return this.x >= 0 && this.x < Chunk.CHUNK_SIZE_X && this.y >= 0 && this.y < Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y && this.z >= 0 && this.z < Chunk.CHUNK_SIZE_Z;
     }
 
-    public @NotNull ChunkTilePos sub(final @NotNull TilePos other) {
-        return new ChunkTilePos(this.x - other.x, this.y - other.y, this.z - other.z);
+    public int getSectionIndex() {
+        return this.y / ChunkSection.SECTION_SIZE_Y;
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/pos/Pos2i.java b/game/core/src/main/java/net/minecraft/core/world/pos/Pos2i.java
new file mode 100644
index 000000000..57f454d2d
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/pos/Pos2i.java
@@ -0,0 +1,47 @@
+package net.minecraft.core.world.pos;
+
+import net.minecraft.core.util.helper.Direction;
+import org.jetbrains.annotations.NotNull;
+
+public interface Pos2i<T extends Pos2i<T>> {
+    int x();
+    int z();
+
+    @NotNull T add(final int x, final int z);
+
+    default @NotNull T add(final @NotNull T other) {
+        return this.add(other.x(), other.z());
+    }
+
+    default @NotNull T add(final @NotNull Direction direction, final int distance) {
+        return this.add(direction.getOffsetX() * distance, direction.getOffsetZ() * distance);
+    }
+
+    default @NotNull T add(final @NotNull Direction direction) {
+        return this.add(direction, 1);
+    }
+
+    default @NotNull T north() {
+        return this.add(Direction.NORTH);
+    }
+
+    default @NotNull T east() {
+        return this.add(Direction.EAST);
+    }
+
+    default @NotNull T south() {
+        return this.add(Direction.SOUTH);
+    }
+
+    default @NotNull T west() {
+        return this.add(Direction.WEST);
+    }
+
+    default @NotNull T sub(final int x, final int z) {
+        return this.add(-x, -z);
+    }
+
+    default @NotNull T sub(final @NotNull T other) {
+        return this.sub(other.x(), other.z());
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/pos/Pos3i.java b/game/core/src/main/java/net/minecraft/core/world/pos/Pos3i.java
new file mode 100644
index 000000000..e20595bd2
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/pos/Pos3i.java
@@ -0,0 +1,58 @@
+package net.minecraft.core.world.pos;
+
+import net.minecraft.core.util.helper.Direction;
+import org.jetbrains.annotations.NotNull;
+
+public interface Pos3i<T extends Pos3i<T>> {
+    int x();
+
+    int y();
+
+    int z();
+
+    @NotNull T add(final int x, final int y, final int z);
+
+    default @NotNull T add(final @NotNull T other) {
+        return this.add(other.x(), other.y(), other.z());
+    }
+
+    default @NotNull T add(final @NotNull Direction direction, final int distance) {
+        return this.add(direction.getOffsetX() * distance, direction.getOffsetY() * distance, direction.getOffsetZ() * distance);
+    }
+
+    default @NotNull T add(final @NotNull Direction direction) {
+        return this.add(direction, 1);
+    }
+
+    default @NotNull T north() {
+        return this.add(Direction.NORTH);
+    }
+
+    default @NotNull T east() {
+        return this.add(Direction.EAST);
+    }
+
+    default @NotNull T south() {
+        return this.add(Direction.SOUTH);
+    }
+
+    default @NotNull T west() {
+        return this.add(Direction.WEST);
+    }
+
+    default @NotNull T up() {
+        return this.add(Direction.UP);
+    }
+
+    default @NotNull T down() {
+        return this.add(Direction.DOWN);
+    }
+
+    default @NotNull T sub(final int x, final int y, final int z) {
+        return this.add(-x, -y, -z);
+    }
+
+    default @NotNull T sub(final @NotNull T other) {
+        return this.sub(other.x(), other.y(), other.z());
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/pos/TilePos.java b/game/core/src/main/java/net/minecraft/core/world/pos/TilePos.java
index ee02ec8eb..7ec5f4dd8 100644
--- a/game/core/src/main/java/net/minecraft/core/world/pos/TilePos.java
+++ b/game/core/src/main/java/net/minecraft/core/world/pos/TilePos.java
@@ -4,11 +4,14 @@ import net.minecraft.core.entity.Entity;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.Vec3;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.chunk.Chunk;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public final class TilePos {
+public final class TilePos
+implements Pos3i<TilePos> {
     public int x;
     public int y;
     public int z;
@@ -39,36 +42,41 @@ public final class TilePos {
         this(entity.x, entity.y, entity.z);
     }
 
-    public @NotNull ChunkPos toChunkPos() {
-        return new ChunkPos(this);
-    }
-
-    public @NotNull ChunkTilePos toChunkTilePos() {
-        return new ChunkTilePos(this);
+    @Override
+    public int x() {
+        return this.x;
     }
 
-    public @NotNull TilePos add(final int x, final int y, final int z) {
-        return new TilePos(this.x + x, this.y + y, this.z + z);
+    @Override
+    public int y() {
+        return this.y;
     }
 
-    public @NotNull TilePos add(final @NotNull TilePos other) {
-        return new TilePos(this.x + other.x, this.y + other.y, this.z + other.z);
+    @Override
+    public int z() {
+        return this.z;
     }
 
-    public @NotNull TilePos add(final @NotNull Direction direction, final int distance) {
-        return new TilePos(this.x + direction.getOffsetX() * distance, this.y + direction.getOffsetY() * distance, this.z + direction.getOffsetZ() * distance);
+    public @NotNull TilePos add(final int x, final int y, final int z) {
+        return new TilePos(this.x + x, this.y + y, this.z + z);
     }
 
-    public @NotNull TilePos add(final @NotNull Direction direction) {
-        return this.add(direction, 1);
+    public @NotNull ChunkPos toChunkPos() {
+        return new ChunkPos(this);
     }
 
-    public @NotNull TilePos sub(final int x, final int y, final int z) {
-        return new TilePos(this.x - x, this.y - y, this.z - z);
+    public @NotNull ChunkTilePos toChunkTilePos() {
+        return new ChunkTilePos(this);
     }
 
-    public @NotNull TilePos sub(final @NotNull TilePos other) {
-        return new TilePos(this.x - other.x, this.y - other.y, this.z - other.z);
+    public boolean inBounds(final @NotNull WorldSource source) {
+        return
+            this.x >= World.MIN_BLOCK_X &&
+                this.y >= 0 &&
+                this.z >= World.MIN_BLOCK_Z &&
+                this.x <= World.MAX_BLOCK_X &&
+                this.y < source.getHeightBlocks() &&
+                this.z <= World.MAX_BLOCK_Z;
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java b/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java
index b35de9227..ce6d5835d 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/Weather.java
@@ -106,7 +106,7 @@ public abstract class Weather {
                 int blockId = chunk.getBlockID(x, y, z);
                 int blockIdBelow = chunk.getBlockID(x, y - 1, z);
 
-                if (world.getBlockBiome(chunk.xPosition * 16 + x, y, chunk.zPosition * 16 + z).hasSurfaceSnow()) {
+                if (world.getBlockBiome(chunk.pos.x * 16 + x, y, chunk.pos.z * 16 + z).hasSurfaceSnow()) {
                     if (blockId == Blocks.LAYER_SNOW.id()) {
                         chunk.setBlockMetadata(x, y, z, 0);
                     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java
index 6db888133..3f44abb55 100644
--- a/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java
+++ b/game/core/src/main/java/net/minecraft/core/world/weather/WeatherSnow.java
@@ -43,10 +43,10 @@ public class WeatherSnow
     public void doChunkLoadEffect(@NotNull World world, @NotNull Chunk chunk) {
         if (world.weatherManager.getWeatherPower() <= 0.6f) return;
         for (int x = 0; x < 16; x++) {
-            int worldX = chunk.xPosition * 16 + x;
+            int worldX = chunk.pos.x * 16 + x;
             zLoop:
             for (int z = 0; z < 16; z++) {
-                int worldZ = chunk.zPosition * 16 + z;
+                int worldZ = chunk.pos.z * 16 + z;
                 int y = world.findTopSolidBlock(worldX, worldZ);
 
                 Biome biome = world.getBlockBiome(worldX, y, worldZ);
diff --git a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
index 063497fa0..db87dc28b 100644
--- a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
+++ b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java
@@ -15,10 +15,12 @@ import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.net.packet.*;
 import net.minecraft.core.world.chunk.IChunkLoader;
 import net.minecraft.core.world.chunk.provider.IChunkProvider;
+import net.minecraft.core.world.pos.TilePos;
 import net.minecraft.server.world.chunk.provider.ChunkProviderServer;
 import net.minecraft.core.world.save.LevelStorage;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.server.MinecraftServer;
+import org.jetbrains.annotations.NotNull;
 
 public class WorldServer extends World
 {
@@ -55,11 +57,10 @@ public class WorldServer extends World
     }
 
     @Override
-    public boolean canMineBlock(final Player player, final int x, final int y, final int z)
-    {
-        if (this.mcServer.spawnProtectionRange <= 0 || this.mcServer.playerList.isOp(player.uuid)) return super.canMineBlock(player, x, y, z);
-        final int dx = (int)MathHelper.abs(x - this.levelData.getSpawnX());
-        final int dz = (int)MathHelper.abs(z - this.levelData.getSpawnZ());
+    public boolean canMineBlock(final @NotNull Player player, final @NotNull TilePos tilePos) {
+        if (this.mcServer.spawnProtectionRange <= 0 || this.mcServer.playerList.isOp(player.uuid)) return super.canMineBlock(player, tilePos);
+        final int dx = (int)MathHelper.abs(tilePos.x - this.levelData.getSpawnX());
+        final int dz = (int)MathHelper.abs(tilePos.z - this.levelData.getSpawnZ());
         return Math.max(dx, dz) > this.mcServer.spawnProtectionRange;
     }
 
@@ -200,11 +201,11 @@ public class WorldServer extends World
         mcServer.playerList.sendPacketToPlayersAroundPoint(x, y, z, 64D, dimension.id, new PacketExplosion(x, y, z, explosionSize, explosion.destroyedBlockPositions, isCannonBall));
         return explosion;
     }
+
     @Override
-    public void triggerEvent(int x, int y, int z, int index, int data)
-    {
-        super.triggerEvent(x, y, z, index, data);
-        mcServer.playerList.sendPacketToPlayersAroundPoint(x, y, z, 64D, dimension.id, new PacketBlockEvent(x, y, z, index, data));
+    public void triggerEvent(final @NotNull TilePos tilePos, final int index, final int data) {
+        super.triggerEvent(tilePos, index, data);
+        mcServer.playerList.sendPacketToPlayersAroundPoint(tilePos.x, tilePos.y, tilePos.z, 64.0, dimension.id, new PacketBlockEvent(tilePos.x, tilePos.y, tilePos.z, index, data));
     }
 
     public void checkLock()
diff --git a/game/server/src/main/java/net/minecraft/server/world/chunk/provider/ChunkProviderServer.java b/game/server/src/main/java/net/minecraft/server/world/chunk/provider/ChunkProviderServer.java
index f32caa13c..516d5c72b 100644
--- a/game/server/src/main/java/net/minecraft/server/world/chunk/provider/ChunkProviderServer.java
+++ b/game/server/src/main/java/net/minecraft/server/world/chunk/provider/ChunkProviderServer.java
@@ -201,7 +201,7 @@ public class ChunkProviderServer
         }
         catch (IOException ioexception)
         {
-            LOGGER.error("Failed to save chunk at X:{}, Z:{} to disk!", chunk.xPosition, chunk.zPosition, ioexception);
+            LOGGER.error("Failed to save chunk at X:{}, Z:{} to disk!", chunk.pos.x, chunk.pos.z, ioexception);
         }
     }
 
diff --git a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAComplexChunk.java b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAComplexChunk.java
index 519993199..5302ec8d9 100644
--- a/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAComplexChunk.java
+++ b/util/seed-viewer/src/main/java/org/useless/seedviewer/bta/BTAComplexChunk.java
@@ -22,7 +22,7 @@ public class BTAComplexChunk implements ViewerChunk {
     public ViewerBiome getBiome(ChunkPos3D pos) {
         net.minecraft.core.world.biome.Biome b = chunk.getBlockBiome(pos.x, pos.y, pos.z);
         if (b != null) return new BTABiome(b);;
-        return new BTABiome(provider.getBiome(chunk.xPosition * ViewerChunk.CHUNK_SIZE_X + pos.x, pos.y, chunk.zPosition * ViewerChunk.CHUNK_SIZE_Z + pos.z));
+        return new BTABiome(provider.getBiome(chunk.pos.x * ViewerChunk.CHUNK_SIZE_X + pos.x, pos.y, chunk.pos.z * ViewerChunk.CHUNK_SIZE_Z + pos.z));
     }
 
     @Override
