|
@@ -1,10 +1,7 @@
|
|
|
package me.shedaniel.lightoverlay.common;
|
|
|
|
|
|
-import com.google.common.base.Stopwatch;
|
|
|
import com.google.common.base.Suppliers;
|
|
|
import com.google.common.collect.Maps;
|
|
|
-import it.unimi.dsi.fastutil.longs.Long2ByteMap;
|
|
|
-import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
|
|
|
import net.minecraft.client.Minecraft;
|
|
|
import net.minecraft.core.BlockPos;
|
|
|
import net.minecraft.core.Direction;
|
|
@@ -26,10 +23,7 @@ import net.minecraft.world.phys.shapes.CollisionContext;
|
|
|
import net.minecraft.world.phys.shapes.Shapes;
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
|
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.HashSet;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Set;
|
|
|
+import java.util.*;
|
|
|
import java.util.concurrent.Executors;
|
|
|
import java.util.concurrent.ThreadPoolExecutor;
|
|
|
import java.util.function.Supplier;
|
|
@@ -45,12 +39,12 @@ public class LightOverlayTicker {
|
|
|
});
|
|
|
public final Set<CubicChunkPos> POS = Collections.synchronizedSet(new HashSet<>());
|
|
|
public final Set<CubicChunkPos> CALCULATING_POS = Collections.synchronizedSet(new HashSet<>());
|
|
|
- public final Map<CubicChunkPos, Long2ByteMap> CHUNK_MAP = Maps.newConcurrentMap();
|
|
|
+ public final Map<CubicChunkPos, ChunkData> CHUNK_MAP = Maps.newConcurrentMap();
|
|
|
private static final Supplier<EntityType<Entity>> TESTING_ENTITY_TYPE = Suppliers.memoize(() ->
|
|
|
EntityType.Builder.createNothing(MobCategory.MONSTER).sized(0f, 0f).noSave().build(null));
|
|
|
|
|
|
public void queueChunk(CubicChunkPos pos) {
|
|
|
- if (LightOverlay.enabled && LightOverlay.caching && !CALCULATING_POS.contains(pos)) {
|
|
|
+ if (LightOverlay.enabled && !CALCULATING_POS.contains(pos)) {
|
|
|
if (minecraft.level != null) {
|
|
|
var chunk = minecraft.level.getChunkSource().getChunk(pos.x, pos.z, ChunkStatus.FULL, false);
|
|
|
if (chunk == null) return;
|
|
@@ -83,123 +77,104 @@ public class LightOverlayTicker {
|
|
|
POS.clear();
|
|
|
CALCULATING_POS.clear();
|
|
|
EXECUTOR.getQueue().clear();
|
|
|
+ for (ChunkData data : CHUNK_MAP.values()) {
|
|
|
+ data.close();
|
|
|
+ }
|
|
|
CHUNK_MAP.clear();
|
|
|
} else {
|
|
|
var player = minecraft.player;
|
|
|
var world = minecraft.level;
|
|
|
var collisionContext = CollisionContext.of(player);
|
|
|
|
|
|
- if (!LightOverlay.caching) {
|
|
|
- CALCULATING_POS.clear();
|
|
|
- POS.clear();
|
|
|
- CHUNK_MAP.clear();
|
|
|
- var playerPos = player.blockPosition();
|
|
|
- var block = world.getLightEngine().getLayerListener(LightLayer.BLOCK);
|
|
|
- var sky = LightOverlay.showNumber ? null : world.getLightEngine().getLayerListener(LightLayer.SKY);
|
|
|
- var downPos = new BlockPos.MutableBlockPos();
|
|
|
- var iterate = BlockPos.betweenClosed(playerPos.getX() - LightOverlay.reach, playerPos.getY() - LightOverlay.reach, playerPos.getZ() - LightOverlay.reach,
|
|
|
- playerPos.getX() + LightOverlay.reach, playerPos.getY() + LightOverlay.reach, playerPos.getZ() + LightOverlay.reach);
|
|
|
- Long2ByteMap chunkData = new Long2ByteOpenHashMap();
|
|
|
- CHUNK_MAP.put(new CubicChunkPos(0, 0, 0), chunkData);
|
|
|
- for (var blockPos : iterate) {
|
|
|
- downPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ());
|
|
|
-// if (LightOverlay.showNumber) {
|
|
|
-// var level = getCrossLevel(blockPos, downPos, world, block, collisionContext);
|
|
|
-// if (level >= 0) {
|
|
|
-// chunkData.put(blockPos.asLong(), (byte) level);
|
|
|
-// }
|
|
|
-// } else {
|
|
|
-// var biome = !LightOverlay.mushroom ? world.getBiome(blockPos) : null;
|
|
|
-// var type = getCrossType(blockPos, biome, downPos, world, block, sky, collisionContext);
|
|
|
-// if (type != LightOverlay.CROSS_NONE) {
|
|
|
-// chunkData.put(blockPos.asLong(), type);
|
|
|
-// }
|
|
|
-// }
|
|
|
- }
|
|
|
- } else {
|
|
|
- var height = Mth.ceil(Minecraft.getInstance().level.getHeight() / 32.0);
|
|
|
- var start = Math.floorDiv(Minecraft.getInstance().level.getMinBuildHeight(), 32);
|
|
|
- var playerPosX = ((int) player.getX()) >> 4;
|
|
|
- var playerPosY = ((int) player.getY()) >> 5;
|
|
|
- var playerPosZ = ((int) player.getZ()) >> 4;
|
|
|
- var chunkRange = LightOverlay.getChunkRange();
|
|
|
- for (var chunkX = playerPosX - chunkRange; chunkX <= playerPosX + chunkRange; chunkX++) {
|
|
|
- for (var chunkY = Math.max(playerPosY - Math.max(1, chunkRange >> 1), start); chunkY <= playerPosY + Math.max(1, chunkRange >> 1) && chunkY <= start + height; chunkY++) {
|
|
|
- for (var chunkZ = playerPosZ - chunkRange; chunkZ <= playerPosZ + chunkRange; chunkZ++) {
|
|
|
- if (Mth.abs(chunkX - playerPosX) > chunkRange || Mth.abs(chunkY - playerPosY) > chunkRange || Mth.abs(chunkZ - playerPosZ) > chunkRange)
|
|
|
- continue;
|
|
|
- var chunkPos = new CubicChunkPos(chunkX, chunkY, chunkZ);
|
|
|
- if (!CHUNK_MAP.containsKey(chunkPos))
|
|
|
- queueChunk(chunkPos);
|
|
|
- }
|
|
|
+ var height = Mth.ceil(Minecraft.getInstance().level.getHeight() / 32.0);
|
|
|
+ var start = Math.floorDiv(Minecraft.getInstance().level.getMinBuildHeight(), 32);
|
|
|
+ var playerPosX = ((int) player.getX()) >> 4;
|
|
|
+ var playerPosY = ((int) player.getY()) >> 5;
|
|
|
+ var playerPosZ = ((int) player.getZ()) >> 4;
|
|
|
+ var chunkRange = LightOverlay.getChunkRange();
|
|
|
+ for (var chunkX = playerPosX - chunkRange; chunkX <= playerPosX + chunkRange; chunkX++) {
|
|
|
+ for (var chunkY = Math.max(playerPosY - Math.max(1, chunkRange >> 1), start); chunkY <= playerPosY + Math.max(1, chunkRange >> 1) && chunkY <= start + height; chunkY++) {
|
|
|
+ for (var chunkZ = playerPosZ - chunkRange; chunkZ <= playerPosZ + chunkRange; chunkZ++) {
|
|
|
+ if (Mth.abs(chunkX - playerPosX) > chunkRange || Mth.abs(chunkY - playerPosY) > chunkRange || Mth.abs(chunkZ - playerPosZ) > chunkRange)
|
|
|
+ continue;
|
|
|
+ var chunkPos = new CubicChunkPos(chunkX, chunkY, chunkZ);
|
|
|
+ if (!CHUNK_MAP.containsKey(chunkPos))
|
|
|
+ queueChunk(chunkPos);
|
|
|
}
|
|
|
}
|
|
|
- for (var p = 0; p < 3; p++) {
|
|
|
- if (EXECUTOR.getQueue().size() >= Runtime.getRuntime().availableProcessors()) break;
|
|
|
- double d1 = Double.MAX_VALUE, d2 = Double.MAX_VALUE, d3 = Double.MAX_VALUE;
|
|
|
- CubicChunkPos c1 = null, c2 = null, c3 = null;
|
|
|
- synchronized (POS) {
|
|
|
- var iterator = POS.iterator();
|
|
|
- while (iterator.hasNext()) {
|
|
|
- var pos = iterator.next();
|
|
|
- if (Mth.abs(pos.x - playerPosX) > chunkRange || Mth.abs(pos.y - playerPosY) > Math.max(1, chunkRange >> 1) || Mth.abs(pos.z - playerPosZ) > chunkRange || CALCULATING_POS.contains(pos)) {
|
|
|
- iterator.remove();
|
|
|
- } else {
|
|
|
- if (LightOverlay.renderer.isFrustumVisible(pos.getMinBlockX(), pos.getMinBlockY(), pos.getMinBlockZ(), pos.getMaxBlockX(), pos.getMaxBlockY(), pos.getMaxBlockZ())) {
|
|
|
- var dx = Math.abs(pos.x - playerPosX);
|
|
|
- var dy = Math.abs(pos.y - playerPosY) << 1;
|
|
|
- var dz = Math.abs(pos.z - playerPosZ);
|
|
|
- var distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
|
- if (distance < d1) {
|
|
|
- d3 = d2;
|
|
|
- d2 = d1;
|
|
|
- d1 = distance;
|
|
|
- c3 = c2;
|
|
|
- c2 = c1;
|
|
|
- c1 = pos;
|
|
|
- } else if (distance < d2) {
|
|
|
- d3 = d2;
|
|
|
- d2 = distance;
|
|
|
- c3 = c2;
|
|
|
- c2 = pos;
|
|
|
- } else if (distance < d3) {
|
|
|
- d3 = distance;
|
|
|
- c3 = pos;
|
|
|
- }
|
|
|
+ }
|
|
|
+ for (var p = 0; p < 3; p++) {
|
|
|
+ if (EXECUTOR.getQueue().size() >= Runtime.getRuntime().availableProcessors()) break;
|
|
|
+ double d1 = Double.MAX_VALUE, d2 = Double.MAX_VALUE, d3 = Double.MAX_VALUE;
|
|
|
+ CubicChunkPos c1 = null, c2 = null, c3 = null;
|
|
|
+ synchronized (POS) {
|
|
|
+ var iterator = POS.iterator();
|
|
|
+ while (iterator.hasNext()) {
|
|
|
+ var pos = iterator.next();
|
|
|
+ if (Mth.abs(pos.x - playerPosX) > chunkRange || Mth.abs(pos.y - playerPosY) > Math.max(1, chunkRange >> 1) || Mth.abs(pos.z - playerPosZ) > chunkRange || CALCULATING_POS.contains(pos)) {
|
|
|
+ iterator.remove();
|
|
|
+ } else {
|
|
|
+ if (LightOverlay.renderer.isFrustumVisible(pos.getMinBlockX(), pos.getMinBlockY(), pos.getMinBlockZ(), pos.getMaxBlockX(), pos.getMaxBlockY(), pos.getMaxBlockZ())) {
|
|
|
+ var dx = Math.abs(pos.x - playerPosX);
|
|
|
+ var dy = Math.abs(pos.y - playerPosY) << 1;
|
|
|
+ var dz = Math.abs(pos.z - playerPosZ);
|
|
|
+ var distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
|
+ if (distance < d1) {
|
|
|
+ d3 = d2;
|
|
|
+ d2 = d1;
|
|
|
+ d1 = distance;
|
|
|
+ c3 = c2;
|
|
|
+ c2 = c1;
|
|
|
+ c1 = pos;
|
|
|
+ } else if (distance < d2) {
|
|
|
+ d3 = d2;
|
|
|
+ d2 = distance;
|
|
|
+ c3 = c2;
|
|
|
+ c2 = pos;
|
|
|
+ } else if (distance < d3) {
|
|
|
+ d3 = distance;
|
|
|
+ c3 = pos;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- var finalC1 = c1;
|
|
|
- var finalC2 = c2;
|
|
|
- var finalC3 = c3;
|
|
|
- if (finalC1 != null) {
|
|
|
- CALCULATING_POS.add(finalC1);
|
|
|
- POS.remove(finalC1);
|
|
|
- if (finalC2 != null) {
|
|
|
- CALCULATING_POS.add(finalC2);
|
|
|
- POS.remove(finalC2);
|
|
|
- if (finalC3 != null) {
|
|
|
- CALCULATING_POS.add(finalC3);
|
|
|
- POS.remove(finalC3);
|
|
|
- }
|
|
|
+ }
|
|
|
+ var finalC1 = c1;
|
|
|
+ var finalC2 = c2;
|
|
|
+ var finalC3 = c3;
|
|
|
+ if (finalC1 != null) {
|
|
|
+ CALCULATING_POS.add(finalC1);
|
|
|
+ POS.remove(finalC1);
|
|
|
+ if (finalC2 != null) {
|
|
|
+ CALCULATING_POS.add(finalC2);
|
|
|
+ POS.remove(finalC2);
|
|
|
+ if (finalC3 != null) {
|
|
|
+ CALCULATING_POS.add(finalC3);
|
|
|
+ POS.remove(finalC3);
|
|
|
}
|
|
|
- EXECUTOR.submit(() -> {
|
|
|
- var playerPosX1 = ((int) minecraft.player.getX()) >> 4;
|
|
|
- var playerPosY1 = ((int) minecraft.player.getY()) >> 5;
|
|
|
- var playerPosZ1 = ((int) minecraft.player.getZ()) >> 4;
|
|
|
- var count = 0;
|
|
|
- if (finalC1 != null) count += processChunk(finalC1, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
|
|
|
- if (finalC2 != null) count += processChunk(finalC2, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
|
|
|
- if (finalC3 != null) count += processChunk(finalC3, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
|
|
|
- synchronized (this) {
|
|
|
- LightOverlay.blocksScanned += count;
|
|
|
- }
|
|
|
- });
|
|
|
}
|
|
|
+ EXECUTOR.submit(() -> {
|
|
|
+ var playerPosX1 = ((int) minecraft.player.getX()) >> 4;
|
|
|
+ var playerPosY1 = ((int) minecraft.player.getY()) >> 5;
|
|
|
+ var playerPosZ1 = ((int) minecraft.player.getZ()) >> 4;
|
|
|
+ var count = 0;
|
|
|
+ if (finalC1 != null) count += processChunk(finalC1, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
|
|
|
+ if (finalC2 != null) count += processChunk(finalC2, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
|
|
|
+ if (finalC3 != null) count += processChunk(finalC3, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
|
|
|
+ synchronized (this) {
|
|
|
+ LightOverlay.blocksScanned += count;
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
- if (ticks % 50 == 0) {
|
|
|
- CHUNK_MAP.entrySet().removeIf(entry -> Mth.abs(entry.getKey().x - playerPosX) > chunkRange * 2 || Mth.abs(entry.getKey().y - playerPosY) > chunkRange * 2 || Mth.abs(entry.getKey().z - playerPosZ) > chunkRange * 2);
|
|
|
+ }
|
|
|
+ if (ticks % 50 == 0) {
|
|
|
+ Iterator<Map.Entry<CubicChunkPos, ChunkData>> iterator = CHUNK_MAP.entrySet().iterator();
|
|
|
+ while (iterator.hasNext()) {
|
|
|
+ Map.Entry<CubicChunkPos, ChunkData> entry = iterator.next();
|
|
|
+ if (Mth.abs(entry.getKey().x - playerPosX) > chunkRange * 2 || Mth.abs(entry.getKey().y - playerPosY) > chunkRange * 2 || Mth.abs(entry.getKey().z - playerPosZ) > chunkRange * 2) {
|
|
|
+ entry.getValue().close();
|
|
|
+ iterator.remove();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -214,13 +189,10 @@ public class LightOverlayTicker {
|
|
|
if (Mth.abs(pos.x - playerPosX) > chunkRange || Mth.abs(pos.y - playerPosY) > Math.max(1, chunkRange >> 1) || Mth.abs(pos.z - playerPosZ) > chunkRange || POS.contains(pos)) {
|
|
|
return 0;
|
|
|
}
|
|
|
- var stopwatch = Stopwatch.createStarted();
|
|
|
try {
|
|
|
return calculateChunk(minecraft.level.getChunkSource().getChunk(pos.x, pos.z, ChunkStatus.FULL, false), minecraft.level, pos, context);
|
|
|
} catch (Throwable throwable) {
|
|
|
LogManager.getLogger().throwing(throwable);
|
|
|
- } finally {
|
|
|
- System.out.println(stopwatch.stop());
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
@@ -229,21 +201,27 @@ public class LightOverlayTicker {
|
|
|
if (world != null && chunk != null) {
|
|
|
var block = world.getLightEngine().getLayerListener(LightLayer.BLOCK);
|
|
|
var sky = LightOverlay.showNumber ? null : world.getLightEngine().getLayerListener(LightLayer.SKY);
|
|
|
- Long2ByteMap chunkData = new Long2ByteOpenHashMap();
|
|
|
+ ChunkData chunkData = new ChunkData();
|
|
|
var count = 0;
|
|
|
var sections = ((LevelChunkAccess) chunk).lightoverlay_getSections();
|
|
|
var firstSectionIndex = chunkPos.y << 1 - chunk.getMinSection();
|
|
|
calculateSection(chunkData, block, sky, world, chunk, sections, firstSectionIndex, chunkPos, 0, collisionContext);
|
|
|
calculateSection(chunkData, block, sky, world, chunk, sections, firstSectionIndex + 1, chunkPos, 16, collisionContext);
|
|
|
- CHUNK_MAP.put(chunkPos, chunkData);
|
|
|
+ var data = CHUNK_MAP.put(chunkPos, chunkData);
|
|
|
+ if (data != null) {
|
|
|
+ data.close();
|
|
|
+ }
|
|
|
return count;
|
|
|
} else {
|
|
|
- CHUNK_MAP.remove(chunkPos);
|
|
|
+ var data = CHUNK_MAP.remove(chunkPos);
|
|
|
+ if (data != null) {
|
|
|
+ data.close();
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void calculateSection(Long2ByteMap chunkData, LayerLightEventListener block, LayerLightEventListener sky, Level world, LevelChunk chunk, LevelChunkSection[] sections,
|
|
|
+ private void calculateSection(ChunkData chunkData, LayerLightEventListener block, LayerLightEventListener sky, Level world, LevelChunk chunk, LevelChunkSection[] sections,
|
|
|
int sectionIndex, CubicChunkPos chunkPos, int yOffset, CollisionContext collisionContext) {
|
|
|
if (sectionIndex >= 0 && sectionIndex < sections.length) {
|
|
|
var section = sections[sectionIndex];
|