From 5e8953ae97badb54c36f66faabda137b3350c57b Mon Sep 17 00:00:00 2001 From: ishland Date: Thu, 5 Aug 2021 00:04:54 +0800 Subject: [PATCH] General performance improvements and serverside fixes Adds early frustum culling to reduce sorting overhead Added biome caching for better performance of biome borders and flower forest --- .../irtimaled/bbor/client/ClientRenderer.java | 59 +++++++++---------- .../irtimaled/bbor/client/RenderCulling.java | 4 +- .../bbor/client/config/ConfigManager.java | 2 - .../bbor/client/gui/IntSettingSlider.java | 14 ----- .../bbor/client/gui/SettingsScreen.java | 4 +- .../client/interop/BiomeBorderHelper.java | 30 +++++++++- .../bbor/client/interop/ClientInterop.java | 5 ++ .../bbor/client/models/BoundingBoxBeacon.java | 2 +- .../models/BoundingBoxBedrockCeiling.java | 2 +- .../client/models/BoundingBoxBiomeBorder.java | 8 ++- .../client/models/BoundingBoxConduit.java | 2 +- .../models/BoundingBoxFlowerForest.java | 8 ++- .../bbor/client/models/BoundingBoxLine.java | 8 ++- .../client/models/BoundingBoxMobSpawner.java | 2 +- .../client/models/BoundingBoxSlimeChunk.java | 2 +- .../models/BoundingBoxSpawnableBlocks.java | 2 +- .../models/BoundingBoxSpawningSphere.java | 2 +- .../bbor/client/models/BoundingBoxSphere.java | 7 ++- .../client/models/BoundingBoxWorldSpawn.java | 2 +- .../client/renderers/AbstractRenderer.java | 29 ++++----- .../client/renderers/BiomeBorderRenderer.java | 4 +- .../bbor/client/renderers/LineRenderer.java | 2 +- .../client/renderers/MobSpawnerRenderer.java | 2 +- .../bbor/client/renderers/OffsetPoint.java | 15 +++++ .../bbor/client/renderers/RenderBatch.java | 59 +++++++++---------- .../bbor/client/renderers/RenderHelper.java | 20 +++++++ .../common/models/AbstractBoundingBox.java | 4 ++ .../bbor/common/models/BoundingBoxCuboid.java | 8 ++- .../play/MixinClientPlayNetHandler.java | 6 ++ 29 files changed, 199 insertions(+), 115 deletions(-) diff --git a/src/main/java/com/irtimaled/bbor/client/ClientRenderer.java b/src/main/java/com/irtimaled/bbor/client/ClientRenderer.java index 76af6f2..554dcdc 100644 --- a/src/main/java/com/irtimaled/bbor/client/ClientRenderer.java +++ b/src/main/java/com/irtimaled/bbor/client/ClientRenderer.java @@ -25,7 +25,10 @@ import com.irtimaled.bbor.common.MathHelper; import com.irtimaled.bbor.common.TypeHelper; import com.irtimaled.bbor.common.models.AbstractBoundingBox; import com.irtimaled.bbor.common.models.DimensionId; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.fabricmc.api.EnvType; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.util.math.MatrixStack; import java.util.ArrayList; @@ -36,10 +39,11 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; public class ClientRenderer { private static final int CHUNK_SIZE = 16; - private static final Map, AbstractRenderer> boundingBoxRendererMap = new Object2ObjectOpenHashMap<>(); + private static final Map, AbstractRenderer> boundingBoxRendererMap = Object2ObjectMaps.synchronize(new Object2ObjectOpenHashMap<>()); private static boolean active; private static final Set providers = new HashSet<>(); @@ -62,38 +66,33 @@ public class ClientRenderer { } static { - - - - - - - - - - registerProvider(new SlimeChunkProvider()); - registerProvider(new WorldSpawnProvider()); - registerProvider(new SpawningSphereProvider()); - registerProvider(new BeaconProvider()); - registerProvider(new CustomBoxProvider()); - registerProvider(new CustomBeaconProvider()); - registerProvider(new BiomeBorderProvider()); - registerProvider(new MobSpawnerProvider()); - registerProvider(new ConduitProvider()); - registerProvider(new SpawnableBlocksProvider()); - registerProvider(new CustomLineProvider()); - registerProvider(new CustomSphereProvider()); - registerProvider(new FlowerForestProvider()); - registerProvider(new BedrockCeilingProvider()); + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { + registerProvider(new SlimeChunkProvider()); + registerProvider(new WorldSpawnProvider()); + registerProvider(new SpawningSphereProvider()); + registerProvider(new BeaconProvider()); + registerProvider(new CustomBoxProvider()); + registerProvider(new CustomBeaconProvider()); + registerProvider(new BiomeBorderProvider()); + registerProvider(new MobSpawnerProvider()); + registerProvider(new ConduitProvider()); + registerProvider(new SpawnableBlocksProvider()); + registerProvider(new CustomLineProvider()); + registerProvider(new CustomSphereProvider()); + registerProvider(new FlowerForestProvider()); + registerProvider(new BedrockCeilingProvider()); + } } public static void registerProvider(IBoundingBoxProvider provider) { providers.add(provider); } - public static AbstractRenderer registerRenderer(Class type, AbstractRenderer renderer) { - boundingBoxRendererMap.put(type, renderer); - return renderer; + public static AbstractRenderer registerRenderer(Class type, Supplier> renderer) { + if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) return null; + final AbstractRenderer renderer1 = renderer.get(); + boundingBoxRendererMap.put(type, renderer1); + return renderer1; } public static AbstractRenderer getRenderer(Class clazz) { @@ -117,10 +116,10 @@ public class ClientRenderer { matrixStack.push(); RenderHelper.beforeRender(); - getBoundingBoxes(dimensionId).forEach(key -> { + for (AbstractBoundingBox key : getBoundingBoxes(dimensionId)) { AbstractRenderer renderer = key.getRenderer(); if (renderer != null) renderer.render(matrixStack, key); - }); + } RenderQueue.renderDeferred(); @@ -134,7 +133,7 @@ public class ClientRenderer { for (IBoundingBoxProvider provider : providers) { if (provider.canProvide(dimensionId)) { for (AbstractBoundingBox boundingBox : provider.get(dimensionId)) { - if (isWithinRenderDistance(boundingBox)) { + if (boundingBox.isVisibleCulling() && isWithinRenderDistance(boundingBox)) { tmp.add(boundingBox); } } diff --git a/src/main/java/com/irtimaled/bbor/client/RenderCulling.java b/src/main/java/com/irtimaled/bbor/client/RenderCulling.java index c76a923..4a31ecb 100644 --- a/src/main/java/com/irtimaled/bbor/client/RenderCulling.java +++ b/src/main/java/com/irtimaled/bbor/client/RenderCulling.java @@ -50,8 +50,8 @@ public class RenderCulling { } } - public static boolean cullRayTrace(Box box) { - return true; + public static boolean isVisibleCulling(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + return isVisibleCulling(new Box(minX, minY, minZ, maxX, maxY, maxZ)); } public static boolean isVisibleCulling(Box box) { diff --git a/src/main/java/com/irtimaled/bbor/client/config/ConfigManager.java b/src/main/java/com/irtimaled/bbor/client/config/ConfigManager.java index a15959c..ceeda12 100644 --- a/src/main/java/com/irtimaled/bbor/client/config/ConfigManager.java +++ b/src/main/java/com/irtimaled/bbor/client/config/ConfigManager.java @@ -9,7 +9,6 @@ public class ConfigManager { private static File configDir; public static Setting fill; - public static Setting lineWidthModifier; public static Setting drawVillages; public static Setting drawDesertTemples; public static Setting drawJungleTemples; @@ -118,7 +117,6 @@ public class ConfigManager { invertBoxColorPlayerInside = setup(config, "general", "invertBoxColorPlayerInside", false, "If set to true the color of any bounding box the player is inside will be inverted."); renderSphereAsDots = setup(config, "general", "renderSphereAsDots", false, "If set to true spheres will be rendered as dots."); buttonOnOverlay = setup(config, "general", "buttonEnabledOverlay", HexColor.from("#3000ff00"), "The color and alpha of the button overlay when a button is on."); - lineWidthModifier = setup(config, "general", "lineWidthModifier", 1, ""); drawBeacons = setup(config, "beacons", "drawBeacons", true, "If set to true beacon bounding boxes will be drawn."); diff --git a/src/main/java/com/irtimaled/bbor/client/gui/IntSettingSlider.java b/src/main/java/com/irtimaled/bbor/client/gui/IntSettingSlider.java index fb643d0..a681e6d 100644 --- a/src/main/java/com/irtimaled/bbor/client/gui/IntSettingSlider.java +++ b/src/main/java/com/irtimaled/bbor/client/gui/IntSettingSlider.java @@ -1,7 +1,5 @@ package com.irtimaled.bbor.client.gui; -import com.google.common.base.Function; -import com.google.common.base.Preconditions; import com.irtimaled.bbor.client.config.Setting; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; import net.minecraft.client.resource.language.I18n; @@ -9,7 +7,6 @@ import net.minecraft.text.LiteralText; import java.util.HashMap; import java.util.Map; -import java.util.stream.IntStream; class IntSettingSlider extends AbstractSlider { private final String format; @@ -39,17 +36,6 @@ class IntSettingSlider extends AbstractSlider { return this; } - IntSettingSlider addDisplayValueRange(int start, int end) { - return addDisplayValueRange(start, end, String::valueOf); - } - - IntSettingSlider addDisplayValueRange(int start, int end, Function formatter) { - Preconditions.checkArgument(start <= end); - Preconditions.checkNotNull(formatter); - IntStream.range(start, end).forEach(value -> addDisplayValue(value, formatter.apply(value))); - return this; - } - protected Integer getSettingValue() { return minValue + getPosition(); } diff --git a/src/main/java/com/irtimaled/bbor/client/gui/SettingsScreen.java b/src/main/java/com/irtimaled/bbor/client/gui/SettingsScreen.java index 73f2835..49e5e68 100644 --- a/src/main/java/com/irtimaled/bbor/client/gui/SettingsScreen.java +++ b/src/main/java/com/irtimaled/bbor/client/gui/SettingsScreen.java @@ -53,9 +53,7 @@ public class SettingsScreen extends ListScreen { } }, width -> new BoolSettingButton(width, I18n.translate("bbor.options.outerBoxOnly"), ConfigManager.outerBoxesOnly), - width -> new BoolSettingButton(width, I18n.translate("bbor.options.fill"), ConfigManager.fill), - width -> new IntSettingSlider(width, 1, 25, I18n.translate("bbor.options.lineWidthModifier"), ConfigManager.lineWidthModifier) - .addDisplayValueRange(1, 25)) + width -> new BoolSettingButton(width, I18n.translate("bbor.options.fill"), ConfigManager.fill)) .section(I18n.translate("bbor.features.spawnChunks"), width -> new BoundingBoxTypeButton(width, I18n.translate("bbor.features.spawnChunks"), BoundingBoxType.WorldSpawn), width -> new BoundingBoxTypeButton(width, I18n.translate("bbor.features.lazyChunks"), BoundingBoxType.LazySpawnChunks), diff --git a/src/main/java/com/irtimaled/bbor/client/interop/BiomeBorderHelper.java b/src/main/java/com/irtimaled/bbor/client/interop/BiomeBorderHelper.java index 0da6216..7cde22b 100644 --- a/src/main/java/com/irtimaled/bbor/client/interop/BiomeBorderHelper.java +++ b/src/main/java/com/irtimaled/bbor/client/interop/BiomeBorderHelper.java @@ -1,21 +1,47 @@ package com.irtimaled.bbor.client.interop; import com.irtimaled.bbor.common.models.Coords; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.client.MinecraftClient; import net.minecraft.client.world.ClientWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; import net.minecraft.util.registry.Registry; import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.source.BiomeArray; +import net.minecraft.world.biome.source.BiomeCoords; +import net.minecraft.world.chunk.WorldChunk; public class BiomeBorderHelper { + + private static final Long2ObjectOpenHashMap biomeCache = new Long2ObjectOpenHashMap<>(); + + public static void onChunkLoaded(int chunkX, int chunkZ) { + assert MinecraftClient.getInstance().world != null; + final WorldChunk chunk = MinecraftClient.getInstance().world.getChunk(chunkX, chunkZ); + if (chunk == null) return; + biomeCache.put(ChunkPos.toLong(chunkX, chunkZ), chunk.getBiomeArray()); + } + + public static void onChunkUnload(int chunkX, int chunkZ) { + biomeCache.remove(ChunkPos.toLong(chunkX, chunkZ)); + } + public static int getBiomeId(Coords coords) { return getBiomeId(coords.getX(), coords.getY(), coords.getZ()); } public static int getBiomeId(int x, int y, int z) { BlockPos pos = new BlockPos(x, y, z); - ClientWorld world = MinecraftClient.getInstance().world; - Biome biome = world.getBiome(pos); + final BiomeArray biomeArray = biomeCache.get(ChunkPos.toLong(pos)); + final ClientWorld world = MinecraftClient.getInstance().world; + final Biome biome; + if (biomeArray != null) { + biome = biomeArray.getBiomeForNoiseGen(BiomeCoords.fromBlock(x & 15), y, BiomeCoords.fromBlock(z & 15)); + } else { + assert world != null; + biome = world.getBiome(pos); + } return world.getRegistryManager().get(Registry.BIOME_KEY).getRawId(biome); } } diff --git a/src/main/java/com/irtimaled/bbor/client/interop/ClientInterop.java b/src/main/java/com/irtimaled/bbor/client/interop/ClientInterop.java index 9d91ad8..e0cee81 100644 --- a/src/main/java/com/irtimaled/bbor/client/interop/ClientInterop.java +++ b/src/main/java/com/irtimaled/bbor/client/interop/ClientInterop.java @@ -107,6 +107,11 @@ public class ClientInterop { public static void receivedChunk(int chunkX, int chunkZ) { SaveGameStructureLoader.loadStructures(chunkX, chunkZ); + BiomeBorderHelper.onChunkLoaded(chunkX, chunkZ); + } + + public static void unloadChunk(int chunkX, int chunkZ) { + BiomeBorderHelper.onChunkUnload(chunkX, chunkZ); } public static void saveLoaded(String fileName, long seed) { diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBeacon.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBeacon.java index 7e4575f..14b4973 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBeacon.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBeacon.java @@ -8,7 +8,7 @@ import com.irtimaled.bbor.common.models.BoundingBoxCuboid; import com.irtimaled.bbor.common.models.Coords; public class BoundingBoxBeacon extends BoundingBoxCuboid { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxBeacon.class, new BeaconRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxBeacon.class, () -> new BeaconRenderer()); private final Coords coords; private final int level; diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBedrockCeiling.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBedrockCeiling.java index 62e0ddd..354b086 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBedrockCeiling.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBedrockCeiling.java @@ -8,7 +8,7 @@ import com.irtimaled.bbor.common.models.BoundingBoxCuboid; import com.irtimaled.bbor.common.models.Coords; public class BoundingBoxBedrockCeiling extends BoundingBoxCuboid { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxBedrockCeiling.class, new CuboidRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxBedrockCeiling.class, () -> new CuboidRenderer()); public BoundingBoxBedrockCeiling(Coords coords) { super(coords, coords, BoundingBoxType.BedrockCeiling); diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBiomeBorder.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBiomeBorder.java index e7b4481..daf6b1c 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBiomeBorder.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxBiomeBorder.java @@ -1,6 +1,7 @@ package com.irtimaled.bbor.client.models; import com.irtimaled.bbor.client.ClientRenderer; +import com.irtimaled.bbor.client.RenderCulling; import com.irtimaled.bbor.client.renderers.AbstractRenderer; import com.irtimaled.bbor.client.renderers.BiomeBorderRenderer; import com.irtimaled.bbor.common.BoundingBoxType; @@ -8,7 +9,7 @@ import com.irtimaled.bbor.common.models.AbstractBoundingBox; import com.irtimaled.bbor.common.models.Coords; public class BoundingBoxBiomeBorder extends AbstractBoundingBox { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxBiomeBorder.class, new BiomeBorderRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxBiomeBorder.class, () -> new BiomeBorderRenderer()); private final Coords coords; private final boolean north; @@ -72,4 +73,9 @@ public class BoundingBoxBiomeBorder extends AbstractBoundingBox { public AbstractRenderer getRenderer() { return RENDERER; } + + @Override + public boolean isVisibleCulling() { + return RenderCulling.isVisibleCulling(coords.getX(), coords.getY(), coords.getZ(), coords.getX() + 1, coords.getY() + 1, coords.getZ() + 1); + } } diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxConduit.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxConduit.java index bdbf3c6..3741808 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxConduit.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxConduit.java @@ -8,7 +8,7 @@ import com.irtimaled.bbor.common.TypeHelper; import com.irtimaled.bbor.common.models.Coords; public class BoundingBoxConduit extends BoundingBoxSphere { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxConduit.class, new ConduitRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxConduit.class, () -> new ConduitRenderer()); private final int level; diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxFlowerForest.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxFlowerForest.java index e13e386..23439b8 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxFlowerForest.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxFlowerForest.java @@ -1,6 +1,7 @@ package com.irtimaled.bbor.client.models; import com.irtimaled.bbor.client.ClientRenderer; +import com.irtimaled.bbor.client.RenderCulling; import com.irtimaled.bbor.client.config.ColorHelper; import com.irtimaled.bbor.client.config.HexColor; import com.irtimaled.bbor.client.config.Setting; @@ -13,7 +14,7 @@ import com.irtimaled.bbor.common.models.Coords; import java.awt.*; public class BoundingBoxFlowerForest extends AbstractBoundingBox { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxFlowerForest.class, new FlowerForestRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxFlowerForest.class, () -> new FlowerForestRenderer()); private final Coords coords; private final Setting colorSetting; @@ -56,4 +57,9 @@ public class BoundingBoxFlowerForest extends AbstractBoundingBox { public AbstractRenderer getRenderer() { return RENDERER; } + + @Override + public boolean isVisibleCulling() { + return RenderCulling.isVisibleCulling(coords.getX(), coords.getY() + 0.01d, coords.getZ(), coords.getX() + 1, coords.getY(), coords.getZ()); + } } diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxLine.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxLine.java index 26ba5b7..39e487e 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxLine.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxLine.java @@ -1,6 +1,7 @@ package com.irtimaled.bbor.client.models; import com.irtimaled.bbor.client.ClientRenderer; +import com.irtimaled.bbor.client.RenderCulling; import com.irtimaled.bbor.client.renderers.AbstractRenderer; import com.irtimaled.bbor.client.renderers.LineRenderer; import com.irtimaled.bbor.common.BoundingBoxType; @@ -9,7 +10,7 @@ import com.irtimaled.bbor.common.TypeHelper; import com.irtimaled.bbor.common.models.AbstractBoundingBox; public class BoundingBoxLine extends AbstractBoundingBox { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxLine.class, new LineRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxLine.class, () -> new LineRenderer()); private final Point minPoint; private final Point maxPoint; @@ -118,4 +119,9 @@ public class BoundingBoxLine extends AbstractBoundingBox { public AbstractRenderer getRenderer() { return RENDERER; } + + @Override + public boolean isVisibleCulling() { + return RenderCulling.isVisibleCulling(minPoint.getX(), minPoint.getY(), minPoint.getZ(), maxPoint.getX(), maxPoint.getY(), maxPoint.getZ()); // TODO better culling + } } diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxMobSpawner.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxMobSpawner.java index 71e919e..d7573f2 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxMobSpawner.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxMobSpawner.java @@ -8,7 +8,7 @@ import com.irtimaled.bbor.common.models.BoundingBoxCuboid; import com.irtimaled.bbor.common.models.Coords; public class BoundingBoxMobSpawner extends BoundingBoxCuboid { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxMobSpawner.class, new MobSpawnerRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxMobSpawner.class, () -> new MobSpawnerRenderer()); private final Coords coords; diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSlimeChunk.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSlimeChunk.java index cd7470b..8c31514 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSlimeChunk.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSlimeChunk.java @@ -11,7 +11,7 @@ import com.irtimaled.bbor.common.models.BoundingBoxCuboid; import com.irtimaled.bbor.common.models.Coords; public class BoundingBoxSlimeChunk extends BoundingBoxCuboid { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxSlimeChunk.class, new SlimeChunkRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxSlimeChunk.class, () -> new SlimeChunkRenderer()); public BoundingBoxSlimeChunk(Coords minCoords, Coords maxCoords) { super(minCoords, maxCoords, BoundingBoxType.SlimeChunks); diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSpawnableBlocks.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSpawnableBlocks.java index 797481f..4976744 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSpawnableBlocks.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSpawnableBlocks.java @@ -11,7 +11,7 @@ import java.util.HashSet; import java.util.Set; public class BoundingBoxSpawnableBlocks extends AbstractBoundingBox { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxSpawnableBlocks.class, new SpawnableBlocksRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxSpawnableBlocks.class, () -> new SpawnableBlocksRenderer()); private final Set blocks = new HashSet<>(); diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSpawningSphere.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSpawningSphere.java index 47a2e3a..396a5c4 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSpawningSphere.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSpawningSphere.java @@ -10,7 +10,7 @@ import java.util.HashSet; import java.util.Set; public class BoundingBoxSpawningSphere extends BoundingBoxSphere { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxSpawningSphere.class, new SpawningSphereRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxSpawningSphere.class, () -> new SpawningSphereRenderer()); public static final int SAFE_RADIUS = 24; public static final int SPAWN_RADIUS = 128; diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSphere.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSphere.java index 8b4b9b5..9198bac 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSphere.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxSphere.java @@ -8,7 +8,7 @@ import com.irtimaled.bbor.common.models.AbstractBoundingBox; import com.irtimaled.bbor.common.models.Coords; public class BoundingBoxSphere extends AbstractBoundingBox { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxSphere.class, new SphereRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxSphere.class, () -> new SphereRenderer()); private final double radius; private final double minX; @@ -59,4 +59,9 @@ public class BoundingBoxSphere extends AbstractBoundingBox { public Point getPoint() { return point; } + + @Override + public AbstractRenderer getRenderer() { + return RENDERER; + } } diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxWorldSpawn.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxWorldSpawn.java index 89de627..22afcf5 100644 --- a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxWorldSpawn.java +++ b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxWorldSpawn.java @@ -8,7 +8,7 @@ import com.irtimaled.bbor.common.models.BoundingBoxCuboid; import com.irtimaled.bbor.common.models.Coords; public class BoundingBoxWorldSpawn extends BoundingBoxCuboid { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxWorldSpawn.class, new WorldSpawnRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxWorldSpawn.class, () -> new WorldSpawnRenderer()); public BoundingBoxWorldSpawn(Coords minCoords, Coords maxCoords, BoundingBoxType type) { super(minCoords, maxCoords, type); diff --git a/src/main/java/com/irtimaled/bbor/client/renderers/AbstractRenderer.java b/src/main/java/com/irtimaled/bbor/client/renderers/AbstractRenderer.java index 7a7a464..8074e49 100644 --- a/src/main/java/com/irtimaled/bbor/client/renderers/AbstractRenderer.java +++ b/src/main/java/com/irtimaled/bbor/client/renderers/AbstractRenderer.java @@ -57,24 +57,24 @@ public abstract class AbstractRenderer { (float) (maxZ - minZ)); if (fillOnly || ConfigManager.fill.get()) { - RenderBatch.drawSolidBox(stack.peek(), ORIGIN_BOX, color, fillAlpha, mask); + RenderBatch.drawSolidBox(stack.peek(), ORIGIN_BOX, color, fillAlpha, mask, minX == maxX, minY == maxY, minZ == maxZ); } if (!fillOnly) { stack.push(); stack.peek().getModel().load(lastStack.getModel()); stack.peek().getNormal().load(lastStack.getNormal()); - renderLine(stack, new OffsetPoint(minX, minY, minZ), new OffsetPoint(maxX, minY, minZ), color); - renderLine(stack, new OffsetPoint(maxX, minY, minZ), new OffsetPoint(maxX, minY, maxZ), color); - renderLine(stack, new OffsetPoint(maxX, minY, maxZ), new OffsetPoint(minX, minY, maxZ), color); - renderLine(stack, new OffsetPoint(minX, minY, maxZ), new OffsetPoint(minX, minY, minZ), color); - renderLine(stack, new OffsetPoint(minX, minY, minZ), new OffsetPoint(minX, maxY, minZ), color); - renderLine(stack, new OffsetPoint(maxX, minY, minZ), new OffsetPoint(maxX, maxY, minZ), color); - renderLine(stack, new OffsetPoint(maxX, minY, maxZ), new OffsetPoint(maxX, maxY, maxZ), color); - renderLine(stack, new OffsetPoint(minX, minY, maxZ), new OffsetPoint(minX, maxY, maxZ), color); - renderLine(stack, new OffsetPoint(minX, maxY, minZ), new OffsetPoint(maxX, maxY, minZ), color); - renderLine(stack, new OffsetPoint(maxX, maxY, minZ), new OffsetPoint(maxX, maxY, maxZ), color); - renderLine(stack, new OffsetPoint(maxX, maxY, maxZ), new OffsetPoint(minX, maxY, maxZ), color); - renderLine(stack, new OffsetPoint(minX, maxY, maxZ), new OffsetPoint(minX, maxY, minZ), color); + renderLine(stack, new OffsetPoint(minX, minY, minZ), new OffsetPoint(maxX, minY, minZ), color, true); + renderLine(stack, new OffsetPoint(maxX, minY, minZ), new OffsetPoint(maxX, minY, maxZ), color, true); + renderLine(stack, new OffsetPoint(maxX, minY, maxZ), new OffsetPoint(minX, minY, maxZ), color, true); + renderLine(stack, new OffsetPoint(minX, minY, maxZ), new OffsetPoint(minX, minY, minZ), color, true); + renderLine(stack, new OffsetPoint(minX, minY, minZ), new OffsetPoint(minX, maxY, minZ), color, true); + renderLine(stack, new OffsetPoint(maxX, minY, minZ), new OffsetPoint(maxX, maxY, minZ), color, true); + renderLine(stack, new OffsetPoint(maxX, minY, maxZ), new OffsetPoint(maxX, maxY, maxZ), color, true); + renderLine(stack, new OffsetPoint(minX, minY, maxZ), new OffsetPoint(minX, maxY, maxZ), color, true); + renderLine(stack, new OffsetPoint(minX, maxY, minZ), new OffsetPoint(maxX, maxY, minZ), color, true); + renderLine(stack, new OffsetPoint(maxX, maxY, minZ), new OffsetPoint(maxX, maxY, maxZ), color, true); + renderLine(stack, new OffsetPoint(maxX, maxY, maxZ), new OffsetPoint(minX, maxY, maxZ), color, true); + renderLine(stack, new OffsetPoint(minX, maxY, maxZ), new OffsetPoint(minX, maxY, minZ), color, true); stack.pop(); } @@ -88,7 +88,7 @@ public abstract class AbstractRenderer { } - void renderLine(MatrixStack matrixStack, OffsetPoint startPoint, OffsetPoint endPoint, Color color) { + void renderLine(MatrixStack matrixStack, OffsetPoint startPoint, OffsetPoint endPoint, Color color, boolean cullIfEmpty) { // if ((startPoint.getY() == endPoint.getY() && startPoint.getZ() == endPoint.getZ()) || // (startPoint.getX() == endPoint.getX() && startPoint.getZ() == endPoint.getZ()) || // (startPoint.getX() == endPoint.getX() && startPoint.getY() == endPoint.getY())) { @@ -96,6 +96,7 @@ public abstract class AbstractRenderer { // return; // } + if (cullIfEmpty && startPoint.equals(endPoint)) return; if (!RenderCulling.isVisibleCulling(new OffsetBox(startPoint, endPoint).toBox())) return; // TODO better culling matrixStack.push(); diff --git a/src/main/java/com/irtimaled/bbor/client/renderers/BiomeBorderRenderer.java b/src/main/java/com/irtimaled/bbor/client/renderers/BiomeBorderRenderer.java index fc50eab..c82cd09 100644 --- a/src/main/java/com/irtimaled/bbor/client/renderers/BiomeBorderRenderer.java +++ b/src/main/java/com/irtimaled/bbor/client/renderers/BiomeBorderRenderer.java @@ -46,11 +46,11 @@ public class BiomeBorderRenderer extends AbstractRenderer { if (boundingBox.getWidth() == 0) { OffsetPoint startPoint = new OffsetPoint(boundingBox.getMinPoint()).offset(0, 0.001f, 0); OffsetPoint endPoint = new OffsetPoint(boundingBox.getMaxPoint()).offset(0, 0.001f, 0); - renderLine(matrixStack, startPoint, endPoint, color); + renderLine(matrixStack, startPoint, endPoint, color, false); return; } diff --git a/src/main/java/com/irtimaled/bbor/client/renderers/MobSpawnerRenderer.java b/src/main/java/com/irtimaled/bbor/client/renderers/MobSpawnerRenderer.java index 7d4784c..81e1df8 100644 --- a/src/main/java/com/irtimaled/bbor/client/renderers/MobSpawnerRenderer.java +++ b/src/main/java/com/irtimaled/bbor/client/renderers/MobSpawnerRenderer.java @@ -34,7 +34,7 @@ public class MobSpawnerRenderer extends AbstractRenderer if (distance <= 20) { OffsetPoint playerPoint = playerPos.offset(0, 0.1, 0); - renderLine(matrixStack, centerPoint, playerPoint, getColor(distance)); + renderLine(matrixStack, centerPoint, playerPoint, getColor(distance), false); } } diff --git a/src/main/java/com/irtimaled/bbor/client/renderers/OffsetPoint.java b/src/main/java/com/irtimaled/bbor/client/renderers/OffsetPoint.java index 2b8675b..cb7ffda 100644 --- a/src/main/java/com/irtimaled/bbor/client/renderers/OffsetPoint.java +++ b/src/main/java/com/irtimaled/bbor/client/renderers/OffsetPoint.java @@ -3,6 +3,8 @@ package com.irtimaled.bbor.client.renderers; import com.irtimaled.bbor.client.models.Point; import com.irtimaled.bbor.common.models.Coords; +import java.util.Objects; + class OffsetPoint { private final Point point; @@ -41,4 +43,17 @@ class OffsetPoint { Point getPoint() { return point; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OffsetPoint that = (OffsetPoint) o; + return point.equals(that.point); + } + + @Override + public int hashCode() { + return Objects.hash(point); + } } diff --git a/src/main/java/com/irtimaled/bbor/client/renderers/RenderBatch.java b/src/main/java/com/irtimaled/bbor/client/renderers/RenderBatch.java index c2dfa8c..016b457 100644 --- a/src/main/java/com/irtimaled/bbor/client/renderers/RenderBatch.java +++ b/src/main/java/com/irtimaled/bbor/client/renderers/RenderBatch.java @@ -36,7 +36,7 @@ public class RenderBatch { lineBufferBuilder.begin(VertexFormat.DrawMode.DEBUG_LINES, VertexFormats.POSITION_COLOR); } - public static void drawSolidBox(MatrixStack.Entry matrixEntry, Box box, Color color, int alpha, boolean mask) { + public static void drawSolidBox(MatrixStack.Entry matrixEntry, Box box, Color color, int alpha, boolean mask, boolean sameX, boolean sameY, boolean sameZ) { final float minX = (float) box.minX; final float minY = (float) box.minY; final float minZ = (float) box.minZ; @@ -49,58 +49,55 @@ public class RenderBatch { final BufferBuilder bufferBuilder = mask ? RenderBatch.quadBufferBuilderMasked : RenderBatch.quadBufferBuilderNonMasked; - if (minX != maxX && minZ != maxZ) { + if (!sameX && !sameZ) { if (mask) quadMaskedCount.getAndIncrement(); else quadNonMaskedCount.getAndIncrement(); bufferBuilder.vertex(matrixEntry.getModel(), minX, minY, minZ).color(red, green, blue, alpha).next(); bufferBuilder.vertex(matrixEntry.getModel(), maxX, minY, minZ).color(red, green, blue, alpha).next(); bufferBuilder.vertex(matrixEntry.getModel(), maxX, minY, maxZ).color(red, green, blue, alpha).next(); bufferBuilder.vertex(matrixEntry.getModel(), minX, minY, maxZ).color(red, green, blue, alpha).next(); + if (!sameY) { + if (mask) quadMaskedCount.getAndIncrement(); + else quadNonMaskedCount.getAndIncrement(); + bufferBuilder.vertex(matrixEntry.getModel(), minX, maxY, minZ).color(red, green, blue, alpha).next(); + bufferBuilder.vertex(matrixEntry.getModel(), minX, maxY, maxZ).color(red, green, blue, alpha).next(); + bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, maxZ).color(red, green, blue, alpha).next(); + bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, minZ).color(red, green, blue, alpha).next(); + } } - if (minX != maxX && minZ != maxZ) { - if (mask) quadMaskedCount.getAndIncrement(); - else quadNonMaskedCount.getAndIncrement(); - bufferBuilder.vertex(matrixEntry.getModel(), minX, maxY, minZ).color(red, green, blue, alpha).next(); - bufferBuilder.vertex(matrixEntry.getModel(), minX, maxY, maxZ).color(red, green, blue, alpha).next(); - bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, maxZ).color(red, green, blue, alpha).next(); - bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, minZ).color(red, green, blue, alpha).next(); - } - - if (minX != maxX && minY != maxY) { + if (!sameX && !sameY) { if (mask) quadMaskedCount.getAndIncrement(); else quadNonMaskedCount.getAndIncrement(); bufferBuilder.vertex(matrixEntry.getModel(), minX, minY, minZ).color(red, green, blue, alpha).next(); bufferBuilder.vertex(matrixEntry.getModel(), minX, maxY, minZ).color(red, green, blue, alpha).next(); bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, minZ).color(red, green, blue, alpha).next(); bufferBuilder.vertex(matrixEntry.getModel(), maxX, minY, minZ).color(red, green, blue, alpha).next(); + if (!sameZ) { + if (mask) quadMaskedCount.getAndIncrement(); + else quadNonMaskedCount.getAndIncrement(); + bufferBuilder.vertex(matrixEntry.getModel(), minX, minY, maxZ).color(red, green, blue, alpha).next(); + bufferBuilder.vertex(matrixEntry.getModel(), maxX, minY, maxZ).color(red, green, blue, alpha).next(); + bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, maxZ).color(red, green, blue, alpha).next(); + bufferBuilder.vertex(matrixEntry.getModel(), minX, maxY, maxZ).color(red, green, blue, alpha).next(); + } } - if (minY != maxY && minZ != maxZ) { - if (mask) quadMaskedCount.getAndIncrement(); - else quadNonMaskedCount.getAndIncrement(); - bufferBuilder.vertex(matrixEntry.getModel(), maxX, minY, minZ).color(red, green, blue, alpha).next(); - bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, minZ).color(red, green, blue, alpha).next(); - bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, maxZ).color(red, green, blue, alpha).next(); - bufferBuilder.vertex(matrixEntry.getModel(), maxX, minY, maxZ).color(red, green, blue, alpha).next(); - } - - if (minX != maxX && minY != maxY) { - if (mask) quadMaskedCount.getAndIncrement(); - else quadNonMaskedCount.getAndIncrement(); - bufferBuilder.vertex(matrixEntry.getModel(), minX, minY, maxZ).color(red, green, blue, alpha).next(); - bufferBuilder.vertex(matrixEntry.getModel(), maxX, minY, maxZ).color(red, green, blue, alpha).next(); - bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, maxZ).color(red, green, blue, alpha).next(); - bufferBuilder.vertex(matrixEntry.getModel(), minX, maxY, maxZ).color(red, green, blue, alpha).next(); - } - - if (minY != maxY && minZ != maxZ) { + if (!sameY && !sameZ) { if (mask) quadMaskedCount.getAndIncrement(); else quadNonMaskedCount.getAndIncrement(); bufferBuilder.vertex(matrixEntry.getModel(), minX, minY, minZ).color(red, green, blue, alpha).next(); bufferBuilder.vertex(matrixEntry.getModel(), minX, minY, maxZ).color(red, green, blue, alpha).next(); bufferBuilder.vertex(matrixEntry.getModel(), minX, maxY, maxZ).color(red, green, blue, alpha).next(); bufferBuilder.vertex(matrixEntry.getModel(), minX, maxY, minZ).color(red, green, blue, alpha).next(); + if (!sameX) { + if (mask) quadMaskedCount.getAndIncrement(); + else quadNonMaskedCount.getAndIncrement(); + bufferBuilder.vertex(matrixEntry.getModel(), maxX, minY, minZ).color(red, green, blue, alpha).next(); + bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, minZ).color(red, green, blue, alpha).next(); + bufferBuilder.vertex(matrixEntry.getModel(), maxX, maxY, maxZ).color(red, green, blue, alpha).next(); + bufferBuilder.vertex(matrixEntry.getModel(), maxX, minY, maxZ).color(red, green, blue, alpha).next(); + } } } diff --git a/src/main/java/com/irtimaled/bbor/client/renderers/RenderHelper.java b/src/main/java/com/irtimaled/bbor/client/renderers/RenderHelper.java index 5e53961..4580f61 100644 --- a/src/main/java/com/irtimaled/bbor/client/renderers/RenderHelper.java +++ b/src/main/java/com/irtimaled/bbor/client/renderers/RenderHelper.java @@ -6,6 +6,7 @@ import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.math.Quaternion; +import net.minecraft.util.math.Vec3d; import org.lwjgl.opengl.GL11; public class RenderHelper { @@ -162,4 +163,23 @@ public class RenderHelper { matrixStack.translate(regionX - Camera.getX(), -Camera.getY(), regionZ - Camera.getZ()); } + + /** + * Compute hash code for vec3d + * @see Vec3d#hashCode() + * + * @param x x value + * @param y y value + * @param z z value + * @return hash code + */ + public static long hashVec3d(double x, double y, double z) { + long l = Double.doubleToLongBits(x); + int i = (int)(l ^ l >>> 32); + l = Double.doubleToLongBits(y); + i = 31 * i + (int)(l ^ l >>> 32); + l = Double.doubleToLongBits(z); + i = 31 * i + (int)(l ^ l >>> 32); + return i; + } } diff --git a/src/main/java/com/irtimaled/bbor/common/models/AbstractBoundingBox.java b/src/main/java/com/irtimaled/bbor/common/models/AbstractBoundingBox.java index 7682249..9036fb2 100644 --- a/src/main/java/com/irtimaled/bbor/common/models/AbstractBoundingBox.java +++ b/src/main/java/com/irtimaled/bbor/common/models/AbstractBoundingBox.java @@ -33,4 +33,8 @@ public abstract class AbstractBoundingBox { public AbstractRenderer getRenderer() { return ClientRenderer.getRenderer(this.getClass()); } + + public boolean isVisibleCulling() { + return true; + } } diff --git a/src/main/java/com/irtimaled/bbor/common/models/BoundingBoxCuboid.java b/src/main/java/com/irtimaled/bbor/common/models/BoundingBoxCuboid.java index 6cfa81a..1e55a4e 100644 --- a/src/main/java/com/irtimaled/bbor/common/models/BoundingBoxCuboid.java +++ b/src/main/java/com/irtimaled/bbor/common/models/BoundingBoxCuboid.java @@ -1,6 +1,7 @@ package com.irtimaled.bbor.common.models; import com.irtimaled.bbor.client.ClientRenderer; +import com.irtimaled.bbor.client.RenderCulling; import com.irtimaled.bbor.client.renderers.AbstractRenderer; import com.irtimaled.bbor.client.renderers.CuboidRenderer; import com.irtimaled.bbor.common.BoundingBoxType; @@ -8,7 +9,7 @@ import com.irtimaled.bbor.common.MathHelper; import com.irtimaled.bbor.common.TypeHelper; public class BoundingBoxCuboid extends AbstractBoundingBox { - private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxCuboid.class, new CuboidRenderer()); + private static final AbstractRenderer RENDERER = ClientRenderer.registerRenderer(BoundingBoxCuboid.class, () -> new CuboidRenderer()); private final Coords minCoords; private final Coords maxCoords; @@ -80,4 +81,9 @@ public class BoundingBoxCuboid extends AbstractBoundingBox { public AbstractRenderer getRenderer() { return RENDERER; } + + @Override + public boolean isVisibleCulling() { + return RenderCulling.isVisibleCulling(minCoords.getX(), minCoords.getY(), minCoords.getZ(), maxCoords.getX(), maxCoords.getY(), maxCoords.getZ()); + } } diff --git a/src/main/java/com/irtimaled/bbor/mixin/client/network/play/MixinClientPlayNetHandler.java b/src/main/java/com/irtimaled/bbor/mixin/client/network/play/MixinClientPlayNetHandler.java index 6000c6c..3c2704b 100644 --- a/src/main/java/com/irtimaled/bbor/mixin/client/network/play/MixinClientPlayNetHandler.java +++ b/src/main/java/com/irtimaled/bbor/mixin/client/network/play/MixinClientPlayNetHandler.java @@ -2,6 +2,7 @@ package com.irtimaled.bbor.mixin.client.network.play; import com.irtimaled.bbor.client.interop.ClientInterop; import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.packet.s2c.play.UnloadChunkS2CPacket; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -13,4 +14,9 @@ public class MixinClientPlayNetHandler { private void onDisconnect(CallbackInfo ci) { ClientInterop.disconnectedFromRemoteServer(); } + + @Inject(method = "onUnloadChunk", at = @At("RETURN")) + private void onChunkUnload(UnloadChunkS2CPacket packet, CallbackInfo ci) { + ClientInterop.unloadChunk(packet.getX(), packet.getZ()); + } } -- 2.44.0