+ public static void queueChunkAndNear(ChunkPos pos) {
+ for (int xOffset = -1; xOffset <= 1; xOffset++) {
+ for (int zOffset = -1; zOffset <= 1; zOffset++) {
+ queueChunk(new ChunkPos(pos.x + xOffset, pos.z + zOffset));
+ }
+ }
+ }
+
+ public static void queueChunk(ChunkPos pos) {
+ if (!POS.contains(pos))
+ POS.add(0, pos);
+ }
+
+ public static int getChunkRange() {
+ return Math.max(MathHelper.ceil(reach / 16f), 1);
+ }
+
+ @SubscribeEvent
+ public static void tick(TickEvent.ClientTickEvent event) {
+ if (event.phase == TickEvent.Phase.END) {
+ try {
+ Minecraft minecraft = Minecraft.getInstance();
+ ticks++;
+ if (minecraft.player == null || !enabled) {
+ POS.clear();
+ } else {
+ ClientPlayerEntity player = minecraft.player;
+ ClientWorld world = minecraft.world;
+ ISelectionContext selectionContext = ISelectionContext.forEntity(player);
+ Vec3d[] playerPos = {null};
+ int playerPosX = ((int) player.getPosX()) >> 4;
+ int playerPosZ = ((int) player.getPosZ()) >> 4;
+ if (ticks % 20 == 0) {
+ for (int chunkX = playerPosX - getChunkRange(); chunkX <= playerPosX + getChunkRange(); chunkX++) {
+ for (int chunkZ = playerPosZ - getChunkRange(); chunkZ <= playerPosZ + getChunkRange(); chunkZ++) {
+ ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
+ if (!CHUNK_MAP.containsKey(chunkPos))
+ queueChunk(chunkPos);
+ }
+ }
+ }
+ if (!POS.isEmpty()) {
+ if (playerPos[0] == null) {
+ playerPos[0] = player.getPositionVec();
+ }
+ ChunkPos pos = POS.stream().min(Comparator.comparingDouble(value -> value.getBlock(8, 0, 8).distanceSq(playerPos[0].x, 0, playerPos[0].z, false))).get();
+ EXECUTOR.submit(() -> {
+ if (MathHelper.abs(pos.x - playerPosX) <= getChunkRange() && MathHelper.abs(pos.z - playerPosZ) <= getChunkRange()) {
+ calculateChunk(world.getChunkProvider().getChunk(pos.x, pos.z, ChunkStatus.FULL, false), world, pos, selectionContext);
+ } else {
+ CHUNK_MAP.remove(pos);
+ }
+ });
+ POS.remove(pos);
+ }
+ Iterator<Map.Entry<ChunkPos, Map<Long, Object>>> chunkMapIterator = CHUNK_MAP.entrySet().iterator();
+ while (chunkMapIterator.hasNext()) {
+ Map.Entry<ChunkPos, Map<Long, Object>> pos = chunkMapIterator.next();
+ if (MathHelper.abs(pos.getKey().x - playerPosX) > getChunkRange() * 2 || MathHelper.abs(pos.getKey().z - playerPosZ) > getChunkRange() * 2) {
+ chunkMapIterator.remove();
+ }
+ }
+ }
+ } catch (Exception e) {
+ LogManager.getLogger().throwing(e);
+ }
+ }
+ }
+
+ private static void calculateChunk(Chunk chunk, World world, ChunkPos chunkPos, ISelectionContext selectionContext) {
+ Map<Long, Object> map = Maps.newHashMap();
+ if (chunk != null) {
+ IWorldLightListener block = chunk.getWorldLightManager().getLightEngine(LightType.BLOCK);
+ IWorldLightListener sky = showNumber ? null : chunk.getWorldLightManager().getLightEngine(LightType.SKY);
+ for (BlockPos pos : BlockPos.getAllInBoxMutable(chunkPos.getXStart(), 0, chunkPos.getZStart(), chunkPos.getXEnd(), 256, chunkPos.getZEnd())) {
+ BlockPos down = pos.down();
+ if (showNumber) {
+ int level = LightOverlayClient.getCrossLevel(pos, down, chunk, block, selectionContext);
+ if (level >= 0) {
+ map.put(pos.toLong(), level);
+ }
+ } else {
+ Biome biome = world.getBiomeManager().getBiome(pos);
+ if (biome.getSpawningChance() > 0 && !biome.getSpawns(EntityClassification.MONSTER).isEmpty()) {
+ CrossType type = LightOverlayClient.getCrossType(pos, down, chunk, block, sky, selectionContext);
+ if (type != CrossType.NONE) {
+ map.put(pos.toLong(), type);
+ }
+ }
+ }
+ }
+ }
+ CHUNK_MAP.put(chunkPos, map);
+ }
+