]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blobdiff - src/main/java/com/irtimaled/bbor/client/ClientRenderer.java
Change keyboard to support multi key presses
[BoundingBoxOutlineReloaded.git] / src / main / java / com / irtimaled / bbor / client / ClientRenderer.java
index ba230499fe9c7f4f9eecf7ac16d5f18c63ed91cf..7cca95d4feb0a6fdb4c27f9e4c4a3850448f660a 100644 (file)
 package com.irtimaled.bbor.client;
 
+import com.irtimaled.bbor.client.interop.ClientInterop;
 import com.irtimaled.bbor.client.renderers.*;
+import com.irtimaled.bbor.common.BoundingBoxCache;
+import com.irtimaled.bbor.common.BoundingBoxType;
+import com.irtimaled.bbor.common.Dimensions;
+import com.irtimaled.bbor.common.MathHelper;
 import com.irtimaled.bbor.common.models.*;
 import com.irtimaled.bbor.config.ConfigManager;
-import net.minecraft.world.DimensionType;
 import org.lwjgl.opengl.GL11;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 public class ClientRenderer {
-    private final ClientBoundingBoxProvider clientBoundingBoxProvider;
-    private static final Map<Class<? extends BoundingBox>, Renderer> boundingBoxRendererMap = new HashMap<>();
+    private static final int CHUNK_SIZE = 16;
+    private static final Map<Class<? extends AbstractBoundingBox>, AbstractRenderer> boundingBoxRendererMap = new HashMap<>();
 
-    ClientRenderer(ClientDimensionCache dimensionCache) {
-        this.clientBoundingBoxProvider = new ClientBoundingBoxProvider(dimensionCache);
+    private static boolean active;
+
+    public static boolean getActive() {
+        return active;
+    }
+
+    public static void toggleActive() {
+        active = !active;
+        if (!active) return;
+
+        PlayerCoords.setActiveY();
+    }
+
+    static void deactivate() {
+        active = false;
+    }
+
+    private final GetCache getCache;
+    private long seed;
+    private Set<AbstractBoundingBox> spawnChunkBoundingBoxes = new HashSet<>();
+
+    ClientRenderer(GetCache getCache) {
+        this.getCache = getCache;
         boundingBoxRendererMap.put(BoundingBoxVillage.class, new VillageRenderer());
         boundingBoxRendererMap.put(BoundingBoxSlimeChunk.class, new SlimeChunkRenderer());
         boundingBoxRendererMap.put(BoundingBoxWorldSpawn.class, new WorldSpawnRenderer());
-        boundingBoxRendererMap.put(BoundingBoxStructure.class, new StructureRenderer());
+        boundingBoxRendererMap.put(BoundingBoxCuboid.class, new CuboidRenderer());
+        boundingBoxRendererMap.put(BoundingBoxMobSpawner.class, new MobSpawnerRenderer());
+    }
+
+    private boolean isWithinRenderDistance(AbstractBoundingBox boundingBox) {
+        int renderDistanceBlocks = ClientInterop.getRenderDistanceChunks() * CHUNK_SIZE;
+        int minX = MathHelper.floor(PlayerCoords.getX() - renderDistanceBlocks);
+        int maxX = MathHelper.floor(PlayerCoords.getX() + renderDistanceBlocks);
+        int minZ = MathHelper.floor(PlayerCoords.getZ() - renderDistanceBlocks);
+        int maxZ = MathHelper.floor(PlayerCoords.getZ() + renderDistanceBlocks);
+
+        return boundingBox.intersectsBounds(minX, minZ, maxX, maxZ);
     }
 
-    public void render(DimensionType dimensionType, Boolean outerBoxesOnly) {
-        Set<BoundingBox> boundingBoxes = clientBoundingBoxProvider.getBoundingBoxes(dimensionType, outerBoxesOnly);
-        if (boundingBoxes == null || boundingBoxes.size() == 0)
-            return;
+    public void render(int dimensionId) {
+        if(!active) return;
+
+        Map<AbstractBoundingBox, Set<AbstractBoundingBox>> boundingBoxes = getBoundingBoxes(dimensionId);
 
         GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
         GL11.glLineWidth(2.0f);
         GL11.glDisable(GL11.GL_TEXTURE_2D);
         GL11.glDisable(GL11.GL_CULL_FACE);
 
-        if (ConfigManager.alwaysVisible.getBoolean()) {
+        if (ConfigManager.alwaysVisible.get()) {
             GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
         }
-        for (BoundingBox bb : boundingBoxes) {
-            Renderer renderer = boundingBoxRendererMap.get(bb.getClass());
-            if (renderer != null) {
-                renderer.render(bb);
+
+        Boolean outerBoxesOnly = ConfigManager.outerBoxesOnly.get();
+        for (Map.Entry<AbstractBoundingBox, Set<AbstractBoundingBox>> entry : boundingBoxes.entrySet()) {
+            AbstractBoundingBox key = entry.getKey();
+            if (!key.shouldRender()) continue;
+
+            AbstractRenderer renderer = boundingBoxRendererMap.get(key.getClass());
+            if (renderer == null) continue;
+
+            if (!outerBoxesOnly) {
+                Set<AbstractBoundingBox> children = entry.getValue();
+                if (children != null) {
+                    children.forEach(renderer::render);
+                    continue;
+                }
             }
+            renderer.render(key);
         }
 
         GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
         GL11.glEnable(GL11.GL_CULL_FACE);
         GL11.glEnable(GL11.GL_TEXTURE_2D);
     }
+
+    private Map<AbstractBoundingBox, Set<AbstractBoundingBox>> getBoundingBoxes(int dimensionId) {
+        Map<AbstractBoundingBox, Set<AbstractBoundingBox>> boundingBoxes = new HashMap<>();
+        if (dimensionId == Dimensions.OVERWORLD) {
+            if (BoundingBoxType.SlimeChunks.shouldRender()) {
+                addSlimeChunks(boundingBoxes);
+            }
+
+            for (AbstractBoundingBox boundingBox : spawnChunkBoundingBoxes) {
+                if (boundingBox.shouldRender() && isWithinRenderDistance(boundingBox)) {
+                    boundingBoxes.put(boundingBox, null);
+                }
+            }
+        }
+
+        BoundingBoxCache cache = getCache.apply(dimensionId);
+        if (cache != null) {
+            for (Map.Entry<AbstractBoundingBox, Set<AbstractBoundingBox>> entry : cache.getBoundingBoxes().entrySet()) {
+                AbstractBoundingBox key = entry.getKey();
+                if (key.shouldRender() && isWithinRenderDistance(key)) {
+                    boundingBoxes.put(key, entry.getValue());
+                }
+            }
+        }
+        return boundingBoxes;
+    }
+
+    private void addSlimeChunks(Map<AbstractBoundingBox, Set<AbstractBoundingBox>> boundingBoxes) {
+        int renderDistanceChunks = ClientInterop.getRenderDistanceChunks();
+        int playerChunkX = MathHelper.floor(PlayerCoords.getX() / 16.0D);
+        int playerChunkZ = MathHelper.floor(PlayerCoords.getZ() / 16.0D);
+        for (int chunkX = playerChunkX - renderDistanceChunks; chunkX <= playerChunkX + renderDistanceChunks; ++chunkX) {
+            for (int chunkZ = playerChunkZ - renderDistanceChunks; chunkZ <= playerChunkZ + renderDistanceChunks; ++chunkZ) {
+                if (isSlimeChunk(chunkX, chunkZ)) {
+                    int chunkXStart = chunkX << 4;
+                    int chunkZStart = chunkZ << 4;
+                    Coords minCoords = new Coords(chunkXStart, 1, chunkZStart);
+                    Coords maxCoords = new Coords(chunkXStart + 15, 38, chunkZStart + 15);
+                    boundingBoxes.put(BoundingBoxSlimeChunk.from(minCoords, maxCoords), null);
+                }
+            }
+        }
+    }
+
+    private boolean isSlimeChunk(int chunkX, int chunkZ) {
+        Random r = new Random(seed +
+                (long) (chunkX * chunkX * 4987142) +
+                (long) (chunkX * 5947611) +
+                (long) (chunkZ * chunkZ) * 4392871L +
+                (long) (chunkZ * 389711) ^ 987234911L);
+        return r.nextInt(10) == 0;
+    }
+
+    void setSeed(long seed) {
+        this.seed = seed;
+    }
+
+    void setWorldSpawn(int spawnX, int spawnZ) {
+        spawnChunkBoundingBoxes = getSpawnChunkBoundingBoxes(spawnX, spawnZ);
+    }
+
+    private Set<AbstractBoundingBox> getSpawnChunkBoundingBoxes(int spawnX, int spawnZ) {
+        Set<AbstractBoundingBox> boundingBoxes = new HashSet<>();
+        boundingBoxes.add(getWorldSpawnBoundingBox(spawnX, spawnZ));
+        boundingBoxes.add(buildSpawnChunksBoundingBox(spawnX, spawnZ, 12, BoundingBoxType.SpawnChunks));
+        boundingBoxes.add(buildSpawnChunksBoundingBox(spawnX, spawnZ, 16, BoundingBoxType.LazySpawnChunks));
+        return boundingBoxes;
+    }
+
+    private AbstractBoundingBox getWorldSpawnBoundingBox(int spawnX, int spawnZ) {
+        Coords minCoords = new Coords(spawnX - 10, 0, spawnZ - 10);
+        Coords maxCoords = new Coords(spawnX + 10, 0, spawnZ + 10);
+
+        return BoundingBoxWorldSpawn.from(minCoords, maxCoords, BoundingBoxType.WorldSpawn);
+    }
+
+    private AbstractBoundingBox buildSpawnChunksBoundingBox(int spawnX, int spawnZ, int size, BoundingBoxType type) {
+        double midOffset = CHUNK_SIZE * (size / 2.0);
+        double midX = Math.round((float) (spawnX / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
+        double midZ = Math.round((float) (spawnZ / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
+        Coords maxCoords = new Coords(midX + midOffset, 0, midZ + midOffset);
+        if ((spawnX / (double) CHUNK_SIZE) % 1.0D == 0.5D) {
+            midX -= (double) CHUNK_SIZE;
+        }
+        if ((spawnZ / (double) CHUNK_SIZE) % 1.0D == 0.5D) {
+            midZ -= (double) CHUNK_SIZE;
+        }
+        Coords minCoords = new Coords(midX - midOffset, 0, midZ - midOffset);
+        return BoundingBoxWorldSpawn.from(minCoords, maxCoords, type);
+    }
+
+    void clear() {
+        spawnChunkBoundingBoxes = new HashSet<>();
+    }
 }