2 package com.irtimaled.bbor.client.providers;
4 import com.irtimaled.bbor.client.Player;
5 import com.irtimaled.bbor.client.config.BoundingBoxTypeHelper;
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;
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.HashSet;
18 import java.util.Random;
21 public class BedrockCeilingProvider implements IBoundingBoxProvider<BoundingBoxBedrockCeiling>, ICachingProvider {
22 private static final double CHUNK_SIZE = 16d;
23 private static Long lastGameTime = null;
24 private static final Map<String, BedrockChunk> chunks = new HashMap<>();
26 private static class BedrockChunk {
27 private final Set<BoundingBoxBedrockCeiling> boxes = new HashSet<>();
29 public BedrockChunk(int chunkX, int chunkZ) {
30 int chunkStartX = chunkX << 4;
31 int chunkStartZ = chunkZ << 4;
33 if (BedrockCeilingHelper.chunkLoaded(chunkX, chunkZ)) findBoxesFromBlockState(chunkStartX, chunkStartZ);
34 else findBoxesFromRNG(chunkX, chunkZ, chunkStartX, chunkStartZ);
37 private void findBoxesFromBlockState(int chunkStartX, int chunkStartZ) {
38 for (int x = 0; x < 16; x++) {
39 for (int z = 0; z < 16; z++) {
40 Coords coords = getCoordsFromBlockState(chunkStartX + x, chunkStartZ + z);
42 boxes.add(new BoundingBoxBedrockCeiling(coords));
48 private Coords getCoordsFromBlockState(int x, int z) {
50 for (int y = 127; y >= 123; y--) {
51 if (BedrockCeilingHelper.isBedrock(x, y, z)) {
53 coords = new Coords(x, y, z);
62 private void findBoxesFromRNG(int chunkX, int chunkZ, int chunkStartX, int chunkStartZ) {
63 Random random = BedrockCeilingHelper.getRandomForChunk(chunkX, chunkZ);
65 // preseed 16x16x3 calls to nextDouble
66 for (int dummy = 0; dummy < 768; dummy++) {
69 for (int z = 0; z < 16; z++) {
70 for (int x = 0; x < 16; x++) {
71 Coords coords = getBlocksFromRNG(random, chunkStartX + x, chunkStartZ + z);
74 boxes.add(new BoundingBoxBedrockCeiling(coords));
80 private Coords getBlocksFromRNG(Random random, int x, int z) {
82 for (int y = 127; y >= 123; y--) {
83 if (y >= 127 - random.nextInt(5)) {
87 for (int y = 4; y >= 0; y--) {
90 return count == 1 ? new Coords(x, 127, z) : null;
93 public Collection<? extends BoundingBoxBedrockCeiling> getBlocks() {
102 public void clearCache() {
103 chunks.values().forEach(BedrockChunk::clear);
108 public Iterable<BoundingBoxBedrockCeiling> get(DimensionId dimensionId) {
109 boolean shouldRecalculate = shouldRecalculate();
111 int renderDistanceChunks = ClientInterop.getRenderDistanceChunks() / 2;
112 int playerChunkX = MathHelper.floor(Player.getX() / CHUNK_SIZE);
113 int playerChunkZ = MathHelper.floor(Player.getZ() / CHUNK_SIZE);
115 Set<BoundingBoxBedrockCeiling> boxes = new HashSet<>();
117 for (int chunkX = playerChunkX - renderDistanceChunks; chunkX <= playerChunkX + renderDistanceChunks; chunkX++) {
118 for (int chunkZ = playerChunkZ - renderDistanceChunks; chunkZ <= playerChunkZ + renderDistanceChunks; chunkZ++) {
119 String key = String.format("%d,%d", chunkX, chunkZ);
120 if (shouldRecalculate || !chunks.containsKey(key)) {
121 chunks.put(key, new BedrockChunk(chunkX, chunkZ));
123 BedrockChunk chunk = chunks.get(key);
124 boxes.addAll(chunk.getBlocks());
130 public boolean shouldRecalculate() {
131 long gameTime = ClientInterop.getGameTime();
132 if (!((Long) gameTime).equals(lastGameTime) && gameTime % 2L == 0L) {
133 lastGameTime = gameTime;
140 public boolean canProvide(DimensionId dimensionId) {
141 return dimensionId == DimensionId.NETHER && BoundingBoxTypeHelper.shouldRender(BoundingBoxType.BedrockCeiling) && Player.getY() > 110;