]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blob - src/main/java/com/irtimaled/bbor/client/providers/BedrockCeilingProvider.java
3278be4982d9dc79f88775a8fabd27f22486b443
[BoundingBoxOutlineReloaded.git] / src / main / java / com / irtimaled / bbor / client / providers / BedrockCeilingProvider.java
1 package com.irtimaled.bbor.client.providers;
2
3 import com.irtimaled.bbor.client.Player;
4 import com.irtimaled.bbor.client.config.BoundingBoxTypeHelper;
5 import com.irtimaled.bbor.client.config.ConfigManager;
6 import com.irtimaled.bbor.client.interop.BedrockCeilingHelper;
7 import com.irtimaled.bbor.client.interop.ClientInterop;
8 import com.irtimaled.bbor.client.models.BoundingBoxBedrockCeiling;
9 import com.irtimaled.bbor.common.BoundingBoxType;
10 import com.irtimaled.bbor.common.MathHelper;
11 import com.irtimaled.bbor.common.models.Coords;
12 import com.irtimaled.bbor.common.models.DimensionId;
13
14 import java.util.*;
15
16 public class BedrockCeilingProvider implements IBoundingBoxProvider<BoundingBoxBedrockCeiling>, ICachingProvider {
17     private static final double CHUNK_SIZE = 16d;
18     private static Long lastGameTime = null;
19     private static final Map<String, BedrockChunk> chunks = new HashMap<>();
20
21     private static class BedrockChunk {
22         private final Set<BoundingBoxBedrockCeiling> boxes = new HashSet<>();
23
24         public BedrockChunk(int chunkX, int chunkZ) {
25             int chunkStartX = chunkX << 4;
26             int chunkStartZ = chunkZ << 4;
27
28             if (BedrockCeilingHelper.chunkLoaded(chunkX, chunkZ)) findBoxesFromBlockState(chunkStartX, chunkStartZ);
29             else findBoxesFromRNG(chunkX, chunkZ, chunkStartX, chunkStartZ);
30         }
31
32         private void findBoxesFromBlockState(int chunkStartX, int chunkStartZ) {
33             for (int x = 0; x < 16; x++) {
34                 for (int z = 0; z < 16; z++) {
35                     Coords coords = getCoordsFromBlockState(chunkStartX + x, chunkStartZ + z);
36                     if (coords != null) {
37                         boxes.add(new BoundingBoxBedrockCeiling(coords));
38                     }
39                 }
40             }
41         }
42
43         private Coords getCoordsFromBlockState(int x, int z) {
44             Coords coords = null;
45             for (int y = 127; y >= 123; y--) {
46                 if (BedrockCeilingHelper.isBedrock(x, y, z)) {
47                     if (coords == null) {
48                         coords = new Coords(x, y, z);
49                     } else {
50                         return null;
51                     }
52                 }
53             }
54             return coords;
55         }
56
57         private void findBoxesFromRNG(int chunkX, int chunkZ, int chunkStartX, int chunkStartZ) {
58             Random random = BedrockCeilingHelper.getRandomForChunk(chunkX, chunkZ);
59
60             // preseed 16x16x3 calls to nextDouble
61             for (int dummy = 0; dummy < 768; dummy++) {
62                 random.nextDouble();
63             }
64             for (int z = 0; z < 16; z++) {
65                 for (int x = 0; x < 16; x++) {
66                     Coords coords = getBlocksFromRNG(random, chunkStartX + x, chunkStartZ + z);
67
68                     if (coords != null) {
69                         boxes.add(new BoundingBoxBedrockCeiling(coords));
70                     }
71                 }
72             }
73         }
74
75         private Coords getBlocksFromRNG(Random random, int x, int z) {
76             int count = 0;
77             for (int y = 127; y >= 123; y--) {
78                 if (y >= 127 - random.nextInt(5)) {
79                     count++;
80                 }
81             }
82             for (int y = 4; y >= 0; y--) {
83                 random.nextInt(5);
84             }
85             return count == 1 ? new Coords(x, 127, z) : null;
86         }
87
88         public Collection<? extends BoundingBoxBedrockCeiling> getBlocks() {
89             return boxes;
90         }
91
92         public void clear() {
93             boxes.clear();
94         }
95     }
96
97     public void clearCache() {
98         chunks.values().forEach(BedrockChunk::clear);
99         chunks.clear();
100     }
101
102     @Override
103     public Iterable<BoundingBoxBedrockCeiling> get(DimensionId dimensionId) {
104         boolean shouldRecalculate = shouldRecalculate();
105
106         int renderDistanceChunks = ClientInterop.getRenderDistanceChunks() / 2;
107         int playerChunkX = MathHelper.floor(Player.getX() / CHUNK_SIZE);
108         int playerChunkZ = MathHelper.floor(Player.getZ() / CHUNK_SIZE);
109
110         Set<BoundingBoxBedrockCeiling> boxes = new HashSet<>();
111
112         for (int chunkX = playerChunkX - renderDistanceChunks; chunkX <= playerChunkX + renderDistanceChunks; chunkX++) {
113             for (int chunkZ = playerChunkZ - renderDistanceChunks; chunkZ <= playerChunkZ + renderDistanceChunks; chunkZ++) {
114                 String key = String.format("%d,%d", chunkX, chunkZ);
115                 if (shouldRecalculate || !chunks.containsKey(key)) {
116                     chunks.put(key, new BedrockChunk(chunkX, chunkZ));
117                 }
118                 BedrockChunk chunk = chunks.get(key);
119                 boxes.addAll(chunk.getBlocks());
120             }
121         }
122         return boxes;
123     }
124
125     public boolean shouldRecalculate() {
126         long gameTime = ClientInterop.getGameTime();
127         if (!((Long) gameTime).equals(lastGameTime) && gameTime % 2L == 0L) {
128             lastGameTime = gameTime;
129             return true;
130         }
131         return false;
132     }
133
134     @Override
135     public boolean canProvide(DimensionId dimensionId) {
136         return dimensionId == DimensionId.NETHER && BoundingBoxTypeHelper.shouldRender(BoundingBoxType.BedrockCeiling) && Player.getY() > 110;
137     }
138 }