From bbef195e8810c66d4601d2ccdad14916c24d1d20 Mon Sep 17 00:00:00 2001 From: laolitou2004 Date: Fri, 9 Jan 2026 00:09:13 +0800 Subject: [PATCH 1/5] Changes to be committed: modified: common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java modified: common/src/main/java/pro/mikey/xray/core/OutlineRender.java modified: common/src/main/java/pro/mikey/xray/core/ScanController.java modified: common/src/main/java/pro/mikey/xray/core/scanner/BlockScanType.java modified: common/src/main/java/pro/mikey/xray/core/scanner/ScanStore.java modified: common/src/main/java/pro/mikey/xray/core/scanner/ScanType.java modified: common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java --- .../pro/mikey/xray/core/ChunkScanTask.java | 26 +- .../pro/mikey/xray/core/OutlineRender.java | 269 +++++++++++++----- .../pro/mikey/xray/core/ScanController.java | 181 ++++++++++-- .../xray/core/scanner/BlockScanType.java | 5 + .../mikey/xray/core/scanner/ScanStore.java | 18 ++ .../pro/mikey/xray/core/scanner/ScanType.java | 5 + .../mikey/xray/screens/ScanManageScreen.java | 31 +- 7 files changed, 426 insertions(+), 109 deletions(-) diff --git a/common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java b/common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java index cad0c50..790a6e9 100644 --- a/common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java +++ b/common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java @@ -1,6 +1,7 @@ package pro.mikey.xray.core; import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; @@ -15,13 +16,20 @@ public class ChunkScanTask implements Runnable { private final int startX; private final int startZ; + private final boolean iscore; - public ChunkScanTask(Level level, ChunkPos pos) { + public ChunkScanTask(Level level, ChunkPos pos, boolean core) { // Move the chunk pos to block pos by multiplying by 16 this.startX = pos.x << 4; this.startZ = pos.z << 4; this.level = level; + this.iscore = core; + } + + private boolean isNetherDimension() { + ResourceKey dimensionKey = level.dimension(); + return dimensionKey == Level.NETHER; } @Override @@ -39,9 +47,18 @@ public void run() { state = level.getBlockState(pos); fluidState = state.getFluidState(); - if ((fluidState.getType() == Fluids.LAVA || fluidState.getType() == Fluids.FLOWING_LAVA) && ScanController.INSTANCE.isLavaActive()) { - renderQueue.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), 0xffff0000)); - continue; + if (iscore){ + if (( fluidState.getType() == Fluids.LAVA || fluidState.getType() == Fluids.FLOWING_LAVA) && ScanController.INSTANCE.isLavaActive()) { + if (isNetherDimension()) { + if (pos.getY() > 31){ + renderQueue.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), 0xffff0000)); + } + } else { + renderQueue.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), 0xffff0000)); + } + continue; + } + } // Reject blacklisted blocks @@ -51,6 +68,7 @@ public void run() { for (var target : ScanController.INSTANCE.scanStore.activeScanTargets()) { if (target.matches(level, pos, state, fluidState)) { renderQueue.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), target.colorInt())); + break; } } } diff --git a/common/src/main/java/pro/mikey/xray/core/OutlineRender.java b/common/src/main/java/pro/mikey/xray/core/OutlineRender.java index 7060cc0..7de1645 100644 --- a/common/src/main/java/pro/mikey/xray/core/OutlineRender.java +++ b/common/src/main/java/pro/mikey/xray/core/OutlineRender.java @@ -28,8 +28,12 @@ public class OutlineRender { private static final RenderSystem.AutoStorageIndexBuffer indices = RenderSystem.getSequentialBuffer(VertexFormat.Mode.LINES); private static final Map vertexBuffers = new HashMap<>(); + private static final Map vertexBuffersa = new HashMap<>(); private static final Set chunksToRefresh = Collections.synchronizedSet(new HashSet<>()); + private static final Set chunksToRefresha = Collections.synchronizedSet(new HashSet<>()); + private static final Object CHUNKS_TO_REFRESH_LOCK = new Object(); + private static final Object CHUNKS_TO_REFRESH_LOCKA = new Object(); public static void renderBlocks(PoseStack poseStack) { if (!ScanController.INSTANCE.isXRayActive() || Minecraft.getInstance().player == null) { @@ -37,92 +41,189 @@ public static void renderBlocks(PoseStack poseStack) { } if (ScanController.INSTANCE.syncRenderList.isEmpty()) { - return; - } - - if (!chunksToRefresh.isEmpty()) { - // Clear the vertex buffers for the chunks that need to be refreshed - for (ChunkPos pos : chunksToRefresh) { - VBOHolder holder = vertexBuffers.remove(pos); - if (holder != null) { - holder.close(); + //return; + } else { + if (!chunksToRefresh.isEmpty()) { + synchronized (CHUNKS_TO_REFRESH_LOCK) { + // Clear the vertex buffers for the chunks that need to be refreshed + for (ChunkPos pos : chunksToRefresh) { + VBOHolder holder = vertexBuffers.remove(pos); + if (holder != null) { + holder.close(); + } + } + + chunksToRefresh.clear(); } } - - chunksToRefresh.clear(); + + // Clone the entrySet to avoid concurrent modification exceptions + var entries = new ArrayList<>(ScanController.INSTANCE.syncRenderList.entrySet()); + + for (var chunkWithBlockData : entries) { + var chunkPos = chunkWithBlockData.getKey(); + var blocksWithProps = chunkWithBlockData.getValue(); + + if (blocksWithProps.isEmpty()) { + continue; + } + + VBOHolder holder = vertexBuffers.get(chunkPos); + if (holder == null) { + BufferBuilder bufferBuilder = Tesselator.getInstance().begin(RenderPipelines.LINES.getVertexFormatMode(), RenderPipelines.LINES.getVertexFormat()); + + // More concurrent modification exceptions can happen here, so we clone the list + var blockPropsClone = new ArrayList<>(blocksWithProps); + + for (var blockProps : blockPropsClone) { + if (blockProps == null) { + continue; + } + + final int x = blockProps.x(), y = blockProps.y(), z = blockProps.z(); + + ShapeRenderer.renderShape(poseStack, bufferBuilder, Shapes.block(), x, y, z, blockProps.color(), 1f); + } + + try (MeshData meshData = bufferBuilder.buildOrThrow()) { + int indexCount = meshData.drawState().indexCount(); + GpuBuffer vertexBuffer = RenderSystem.getDevice() + .createBuffer(() -> "Xray vertex buffer", GpuBuffer.USAGE_VERTEX, meshData.vertexBuffer()); + + vertexBuffers.put(chunkPos, new VBOHolder(vertexBuffer, indexCount)); + } + } + + holder = vertexBuffers.get(chunkPos); + if (holder == null || holder.vertexBuffer == null || holder.indexCount == 0) { + continue; + } + + Vec3 playerPos = Minecraft.getInstance().gameRenderer.getMainCamera().position().reverse(); + + Matrix4fStack matrix4fStack = RenderSystem.getModelViewStack(); + GpuTextureView colorTextureView = Minecraft.getInstance().getMainRenderTarget().getColorTextureView(); + GpuTextureView depthTextureView = Minecraft.getInstance().getMainRenderTarget().getDepthTextureView(); + + matrix4fStack.pushMatrix(); + matrix4fStack.translate((float) playerPos.x(), (float) playerPos.y(), (float) playerPos.z()); + GpuBufferSlice[] gpubufferslice = RenderSystem.getDynamicUniforms().writeTransforms(new DynamicUniforms.Transform(new Matrix4f(matrix4fStack), new Vector4f(1.0F, 1.0F, 1.0F, 1.0F), new Vector3f(), new Matrix4f())); + + GL11.glDisable(GL11.GL_DEPTH_TEST); + RenderSystem.setShaderFog(gpubufferslice[0]); + + GpuBuffer gpuBuffer = indices.getBuffer(holder.indexCount); + try (RenderPass renderPass = RenderSystem.getDevice() + .createCommandEncoder() + .createRenderPass(() -> "xray", colorTextureView, OptionalInt.empty(), depthTextureView, OptionalDouble.empty())) { + + RenderSystem.bindDefaultUniforms(renderPass); + renderPass.setVertexBuffer(0, holder.vertexBuffer); + renderPass.setIndexBuffer(gpuBuffer, indices.type()); + renderPass.setUniform("DynamicTransforms", gpubufferslice[0]); + renderPass.setPipeline(RenderPipelines.LINES); + renderPass.drawIndexed(0, 0, holder.indexCount, 1); + } + + GL11.glEnable(GL11.GL_DEPTH_TEST); + matrix4fStack.popMatrix(); + } } - // Clone the entrySet to avoid concurrent modification exceptions - var entries = new ArrayList<>(ScanController.INSTANCE.syncRenderList.entrySet()); - - for (var chunkWithBlockData : entries) { - var chunkPos = chunkWithBlockData.getKey(); - var blocksWithProps = chunkWithBlockData.getValue(); - - if (blocksWithProps.isEmpty()) { - continue; + // + if (ScanController.INSTANCE.syncRenderLista.isEmpty()) { + return; + } else { + if (!chunksToRefresha.isEmpty()) { + synchronized (CHUNKS_TO_REFRESH_LOCKA) { + // Clear the vertex buffers for the chunks that need to be refreshed + for (ChunkPos pos : chunksToRefresha) { + VBOHolder holder = vertexBuffersa.remove(pos); + if (holder != null) { + holder.close(); + } + } + + chunksToRefresha.clear(); + } } - - VBOHolder holder = vertexBuffers.get(chunkPos); - if (holder == null) { - BufferBuilder bufferBuilder = Tesselator.getInstance().begin(RenderPipelines.LINES.getVertexFormatMode(), RenderPipelines.LINES.getVertexFormat()); - - // More concurrent modification exceptions can happen here, so we clone the list - var blockPropsClone = new ArrayList<>(blocksWithProps); - - for (var blockProps : blockPropsClone) { - if (blockProps == null) { - continue; + + // Clone the entrySet to avoid concurrent modification exceptions + var entries = new ArrayList<>(ScanController.INSTANCE.syncRenderLista.entrySet()); + + for (var chunkWithBlockData : entries) { + var chunkPos = chunkWithBlockData.getKey(); + var blocksWithProps = chunkWithBlockData.getValue(); + + if (blocksWithProps.isEmpty()) { + continue; + } + + VBOHolder holder = vertexBuffersa.get(chunkPos); + if (holder == null) { + BufferBuilder bufferBuilder = Tesselator.getInstance().begin(RenderPipelines.LINES.getVertexFormatMode(), RenderPipelines.LINES.getVertexFormat()); + + // More concurrent modification exceptions can happen here, so we clone the list + var blockPropsClone = new ArrayList<>(blocksWithProps); + + for (var blockProps : blockPropsClone) { + if (blockProps == null) { + continue; + } + + final int x = blockProps.x(), y = blockProps.y(), z = blockProps.z(); + + ShapeRenderer.renderShape(poseStack, bufferBuilder, Shapes.block(), x, y, z, blockProps.color(), 1f); + } + + try (MeshData meshData = bufferBuilder.buildOrThrow()) { + int indexCount = meshData.drawState().indexCount(); + GpuBuffer vertexBuffer = RenderSystem.getDevice() + .createBuffer(() -> "Xray vertex buffer", GpuBuffer.USAGE_VERTEX, meshData.vertexBuffer()); + + vertexBuffersa.put(chunkPos, new VBOHolder(vertexBuffer, indexCount)); + } catch (Exception e) { } - - final int x = blockProps.x(), y = blockProps.y(), z = blockProps.z(); - - ShapeRenderer.renderShape(poseStack, bufferBuilder, Shapes.block(), x, y, z, blockProps.color(), 1f); } - - try (MeshData meshData = bufferBuilder.buildOrThrow()) { - int indexCount = meshData.drawState().indexCount(); - GpuBuffer vertexBuffer = RenderSystem.getDevice() - .createBuffer(() -> "Xray vertex buffer", GpuBuffer.USAGE_VERTEX, meshData.vertexBuffer()); - - vertexBuffers.put(chunkPos, new VBOHolder(vertexBuffer, indexCount)); + + holder = vertexBuffersa.get(chunkPos); + if (holder == null || holder.vertexBuffer == null || holder.indexCount == 0) { + continue; } + + Vec3 playerPos = Minecraft.getInstance().gameRenderer.getMainCamera().position().reverse(); + + Matrix4fStack matrix4fStack = RenderSystem.getModelViewStack(); + GpuTextureView colorTextureView = Minecraft.getInstance().getMainRenderTarget().getColorTextureView(); + GpuTextureView depthTextureView = Minecraft.getInstance().getMainRenderTarget().getDepthTextureView(); + + matrix4fStack.pushMatrix(); + matrix4fStack.translate((float) playerPos.x(), (float) playerPos.y(), (float) playerPos.z()); + GpuBufferSlice[] gpubufferslice = RenderSystem.getDynamicUniforms().writeTransforms(new DynamicUniforms.Transform(new Matrix4f(matrix4fStack), new Vector4f(1.0F, 1.0F, 1.0F, 1.0F), new Vector3f(), new Matrix4f())); + + GL11.glDisable(GL11.GL_DEPTH_TEST); + RenderSystem.setShaderFog(gpubufferslice[0]); + + GpuBuffer gpuBuffer = indices.getBuffer(holder.indexCount); + try (RenderPass renderPass = RenderSystem.getDevice() + .createCommandEncoder() + .createRenderPass(() -> "xray", colorTextureView, OptionalInt.empty(), depthTextureView, OptionalDouble.empty())) { + + RenderSystem.bindDefaultUniforms(renderPass); + renderPass.setVertexBuffer(0, holder.vertexBuffer); + renderPass.setIndexBuffer(gpuBuffer, indices.type()); + renderPass.setUniform("DynamicTransforms", gpubufferslice[0]); + renderPass.setPipeline(RenderPipelines.LINES); + renderPass.drawIndexed(0, 0, holder.indexCount, 1); + } + + GL11.glEnable(GL11.GL_DEPTH_TEST); + matrix4fStack.popMatrix(); } + } - holder = vertexBuffers.get(chunkPos); - if (holder == null || holder.vertexBuffer == null || holder.indexCount == 0) { - continue; - } - - Vec3 playerPos = Minecraft.getInstance().gameRenderer.getMainCamera().position().reverse(); - - Matrix4fStack matrix4fStack = RenderSystem.getModelViewStack(); - GpuTextureView colorTextureView = Minecraft.getInstance().getMainRenderTarget().getColorTextureView(); - GpuTextureView depthTextureView = Minecraft.getInstance().getMainRenderTarget().getDepthTextureView(); - - matrix4fStack.pushMatrix(); - matrix4fStack.translate((float) playerPos.x(), (float) playerPos.y(), (float) playerPos.z()); - GpuBufferSlice[] gpubufferslice = RenderSystem.getDynamicUniforms().writeTransforms(new DynamicUniforms.Transform(new Matrix4f(matrix4fStack), new Vector4f(1.0F, 1.0F, 1.0F, 1.0F), new Vector3f(), new Matrix4f())); - - GL11.glDisable(GL11.GL_DEPTH_TEST); - RenderSystem.setShaderFog(gpubufferslice[0]); - - GpuBuffer gpuBuffer = indices.getBuffer(holder.indexCount); - try (RenderPass renderPass = RenderSystem.getDevice() - .createCommandEncoder() - .createRenderPass(() -> "xray", colorTextureView, OptionalInt.empty(), depthTextureView, OptionalDouble.empty())) { - RenderSystem.bindDefaultUniforms(renderPass); - renderPass.setVertexBuffer(0, holder.vertexBuffer); - renderPass.setIndexBuffer(gpuBuffer, indices.type()); - renderPass.setUniform("DynamicTransforms", gpubufferslice[0]); - renderPass.setPipeline(RenderPipelines.LINES); - renderPass.drawIndexed(0, 0, holder.indexCount, 1); - } - GL11.glEnable(GL11.GL_DEPTH_TEST); - matrix4fStack.popMatrix(); - } } public static void clearVBOs() { @@ -132,6 +233,12 @@ public static void clearVBOs() { } } vertexBuffers.clear(); + for (VBOHolder holder : vertexBuffersa.values()) { + if (holder != null) { + holder.close(); + } + } + vertexBuffersa.clear(); } public static void clearVBOsFor(List removedChunks) { @@ -139,11 +246,21 @@ public static void clearVBOsFor(List removedChunks) { return; } - chunksToRefresh.addAll(removedChunks); + synchronized (CHUNKS_TO_REFRESH_LOCK) { + chunksToRefresh.addAll(removedChunks); + } } public static void refreshVBOForChunk(ChunkPos pos) { - chunksToRefresh.add(pos); + synchronized (CHUNKS_TO_REFRESH_LOCK) { + chunksToRefresh.add(pos); + } + } + + public static void refreshVBOForChunka(ChunkPos pos) { + synchronized (CHUNKS_TO_REFRESH_LOCKA) { + chunksToRefresha.add(pos); + } } private record VBOHolder(GpuBuffer vertexBuffer, int indexCount) implements Closeable { diff --git a/common/src/main/java/pro/mikey/xray/core/ScanController.java b/common/src/main/java/pro/mikey/xray/core/ScanController.java index 7f1d0a5..4e3eb0a 100644 --- a/common/src/main/java/pro/mikey/xray/core/ScanController.java +++ b/common/src/main/java/pro/mikey/xray/core/ScanController.java @@ -18,6 +18,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; public enum ScanController { INSTANCE; @@ -32,7 +34,7 @@ public Thread newThread(@NotNull Runnable r) { } }); - private final int maxStepsToScan = 5; + private final int maxStepsToScan = 8; // Block blackList // Todo: move this to a configurable thing @@ -45,8 +47,14 @@ public Thread newThread(@NotNull Runnable r) { }}; - public final Map> syncRenderList = Collections.synchronizedMap(new HashMap<>()); // this is accessed by threads + public final Map> syncRenderList = new ConcurrentHashMap<>(); // this is accessed by threads + public final Map> syncRenderLista = new ConcurrentHashMap<>(); // this is accessed by threads private ChunkPos lastChunkPos = null; + private BlockPos lastPos = null; + private Set last3x3 = ConcurrentHashMap.newKeySet(); + private Set lastxxx = ConcurrentHashMap.newKeySet(); + private List lastshi = new ArrayList<>(); + private static final Object RENDER_SET_LOCK = new Object(); public final ScanStore scanStore = new ScanStore(); @@ -74,6 +82,9 @@ public void toggleXRay() { if (!xrayActive) // enable drawing { syncRenderList.clear(); // first, clear the buffer + syncRenderLista.clear(); // first, clear the buffer + last3x3.clear(); + lastxxx.clear(); xrayActive = true; // then, enable drawing requestBlockFinder(true); // finally, force a refresh @@ -108,11 +119,8 @@ public int getVisualRadius() { return Math.max(1, getRadius()); } - public void incrementCurrentDist() { - if (XRay.config().radius.get() < maxStepsToScan) - XRay.config().radius.set(XRay.config().radius.get() + 1); - else - XRay.config().radius.set(0); + public void incrementCurrentDist(int value) { + XRay.config().radius.set(value); } public void decrementCurrentDist() { @@ -131,10 +139,41 @@ private boolean playerHasMoved() { return lastChunkPos == null || !lastChunkPos.equals(plyChunkPos); } + private boolean playerHasMoveda() { + if (Minecraft.getInstance().player == null) + return false; + BlockPos plyChunkPos = Minecraft.getInstance().player.blockPosition(); + return lastPos == null || !lastPos.equals(plyChunkPos); + } + private void updatePlayerPosition() { lastChunkPos = Minecraft.getInstance().player.chunkPosition(); } + private void updatePlayerPositiona() { + lastPos = Minecraft.getInstance().player.blockPosition(); + } + + private List getCore3x3Chunks(ChunkPos playerChunk,int range) { + List coreChunks = new ArrayList<>(); + if (range==0){ + coreChunks.add(new ChunkPos(playerChunk.x, playerChunk.z)); + } else { + for (int x = playerChunk.x - 1; x <= playerChunk.x + 1; x++) { + for (int z = playerChunk.z - 1; z <= playerChunk.z + 1; z++) { + coreChunks.add(new ChunkPos(x, z)); + } + } + } + return coreChunks; + } + + private List getOuterChunks(List allChunks, List core3x3Chunks) { + return allChunks.stream() + .filter(chunk -> !core3x3Chunks.contains(chunk)) + .collect(Collectors.toList()); + } + public synchronized void requestBlockFinder(boolean force) { var player = Minecraft.getInstance().player; if (player == null) { @@ -147,6 +186,9 @@ public synchronized void requestBlockFinder(boolean force) { if (force) { // Clear the render list if we are forcing a scan syncRenderList.clear(); + syncRenderLista.clear(); + last3x3.clear(); + lastxxx.clear(); OutlineRender.clearVBOs(); // Clear the VBOs as well } @@ -167,11 +209,32 @@ public synchronized void requestBlockFinder(boolean force) { // Sort the chunks by distance to the player chunksToScan.sort(Comparator.comparingDouble(chunk -> chunk.distanceSquared(playerChunkPos))); - var knownChunks = syncRenderList.keySet(); + List core3x3Chunks = getCore3x3Chunks(playerChunkPos,range); + List outerChunks = getOuterChunks(chunksToScan, core3x3Chunks); + + var knownChunksa = last3x3; + + var newChunksa = core3x3Chunks.stream().filter(chunk -> !knownChunksa.contains(chunk)).toList(); + var removedChunksa = knownChunksa.stream().filter(chunk -> !core3x3Chunks.contains(chunk)).toList(); + + if (!removedChunksa.isEmpty()) { + OutlineRender.clearVBOsFor(removedChunksa); + } + for (ChunkPos chunk : removedChunksa) { + last3x3.remove(chunk); + syncRenderList.remove(chunk); + } + + for (ChunkPos chunk : newChunksa) { + last3x3.add(chunk); + SCANNER.submit(new ChunkScanTask(player.level(), chunk, true)); + } + + var knownChunks = lastxxx; // New chunks - var newChunks = chunksToScan.stream().filter(chunk -> !knownChunks.contains(chunk)).toList(); - var removedChunks = knownChunks.stream().filter(chunk -> !chunksToScan.contains(chunk)).toList(); + var newChunks = outerChunks.stream().filter(chunk -> !knownChunks.contains(chunk)).toList(); + var removedChunks = knownChunks.stream().filter(chunk -> !outerChunks.contains(chunk)).toList(); if (!removedChunks.isEmpty()) { OutlineRender.clearVBOsFor(removedChunks); @@ -179,13 +242,75 @@ public synchronized void requestBlockFinder(boolean force) { // Push the new chunks to the scanner, remove the old ones from the render list for (ChunkPos chunk : removedChunks) { + lastxxx.remove(chunk); syncRenderList.remove(chunk); } for (ChunkPos chunk : newChunks) { - SCANNER.submit(new ChunkScanTask(player.level(), chunk)); + lastxxx.add(chunk); + SCANNER.submit(new ChunkScanTask(player.level(), chunk, false)); } } + + if (isXRayActive() && (force || playerHasMoveda())) { + updatePlayerPositiona(); + clean(); + add(); + } + } + + public synchronized void clean(){ + if (lastshi != null && !lastshi.isEmpty()) { + Set renderQueuea = new HashSet<>(); + for (BlockPos chunk : lastshi){ + renderQueuea.add(new OutlineRenderTarget(chunk.getX(), chunk.getY(), chunk.getZ(), 0xffff00ff)); + } + var re=ScanController.INSTANCE.syncRenderLista.get(new ChunkPos(1, 1)); + if (re != null){ + re.removeAll(renderQueuea); + } + OutlineRender.refreshVBOForChunka(new ChunkPos(1, 1)); + } + } + + public synchronized void add(){ + BlockPos playerChunkPos = Minecraft.getInstance().player.blockPosition(); + List chunksToScan = new ArrayList<>(); + for (int z = playerChunkPos.getZ() - 5; z <= playerChunkPos.getZ() + 5; z++) { + if (z != playerChunkPos.getZ()) { + chunksToScan.add(new BlockPos(playerChunkPos.getX(),playerChunkPos.getY()-1, z)); + } else { + chunksToScan.add(new BlockPos(playerChunkPos.getX(),playerChunkPos.getY()+7, z)); + chunksToScan.add(new BlockPos(playerChunkPos.getX(),playerChunkPos.getY()+6, z)); + chunksToScan.add(new BlockPos(playerChunkPos.getX(),playerChunkPos.getY()+5, z)); + chunksToScan.add(new BlockPos(playerChunkPos.getX(),playerChunkPos.getY()+4, z)); + chunksToScan.add(new BlockPos(playerChunkPos.getX(),playerChunkPos.getY()+3, z)); + chunksToScan.add(new BlockPos(playerChunkPos.getX(),playerChunkPos.getY()-2, z)); + chunksToScan.add(new BlockPos(playerChunkPos.getX(),playerChunkPos.getY()-3, z)); + chunksToScan.add(new BlockPos(playerChunkPos.getX(),playerChunkPos.getY()-4, z)); + } + }; + for (int x = playerChunkPos.getX() - 5; x <= playerChunkPos.getX() + 5; x++) { + if (x != playerChunkPos.getX()) { + chunksToScan.add(new BlockPos(x,playerChunkPos.getY()-1 ,playerChunkPos.getZ())); + } + }; + Set renderQueue = new HashSet<>(); + for (BlockPos chunk : chunksToScan){ + BlockState state = Minecraft.getInstance().player.level().getBlockState(chunk); + if (chunk.getY()>=playerChunkPos.getY()+3) { + if ((state.getBlock() == Blocks.SAND || state.getBlock() == Blocks.GRAVEL) && ScanController.INSTANCE.isLavaActive()) { + renderQueue.add(new OutlineRenderTarget(chunk.getX(), chunk.getY(), chunk.getZ(), 0xffff00ff)); + ScanController.INSTANCE.syncRenderLista.put(new ChunkPos(1, 1), renderQueue); + } + } else { + if ((state.getBlock() == Blocks.AIR || state.getBlock() == Blocks.CAVE_AIR|| state.getBlock() == Blocks.POWDER_SNOW) && ScanController.INSTANCE.isLavaActive()) { + renderQueue.add(new OutlineRenderTarget(chunk.getX(), chunk.getY(), chunk.getZ(), 0xffff00ff)); + ScanController.INSTANCE.syncRenderLista.put(new ChunkPos(1, 1), renderQueue); + } + } + } + lastshi=new ArrayList<>(chunksToScan); } public static void onBlockChange(Level level, BlockPos pos, BlockState state) { @@ -203,21 +328,30 @@ public static void onBlockChange(Level level, BlockPos pos, BlockState state) { // We're now air baby! if (state.isAir()) { // Remove the block from the render list - var removed = outlineRenderTargets.removeIf(target -> target.x() == pos.getX() && target.y() == pos.getY() && target.z() == pos.getZ()); - if (removed) { - // We need to tell the outline render to refresh the VBO for this chunk - OutlineRender.refreshVBOForChunk(chunkPos); + synchronized (RENDER_SET_LOCK) { + var removed = outlineRenderTargets.removeIf(target -> target.x() == pos.getX() && target.y() == pos.getY() && target.z() == pos.getZ()); + if (removed) { + // We need to tell the outline render to refresh the VBO for this chunk + OutlineRender.refreshVBOForChunk(chunkPos); + } } - + INSTANCE.clean(); + INSTANCE.add(); return; } if (ScanController.INSTANCE.isLavaActive() && state.is(Blocks.LAVA)) { - // We're actively looking at this chunk so let's inject this block - outlineRenderTargets.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), 0xff0000)); - + synchronized (RENDER_SET_LOCK) { + // We're actively looking at this chunk so let's inject this block + outlineRenderTargets.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), 0xffff0000)); + } + // Tell the VBO to refresh for this chunk OutlineRender.refreshVBOForChunk(chunkPos); + + INSTANCE.clean(); + INSTANCE.add(); + return; } // Otherwise, do we have scantarget in the active list of things to find? @@ -228,11 +362,16 @@ public static void onBlockChange(Level level, BlockPos pos, BlockState state) { if (scanType.matches(level, pos, state, state.getFluidState())) { // We need to tell the render system to refresh. We should manually add this black to the renderlist // We're actively looking at this chunk so let's inject this block - outlineRenderTargets.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), scanType.colorInt())); + synchronized (RENDER_SET_LOCK) { + outlineRenderTargets.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), scanType.colorInt())); + } // Tell the VBO to refresh for this chunk OutlineRender.refreshVBOForChunk(chunkPos); noMatchesFound = false; // We found a match, so we can stop checking + + INSTANCE.clean(); + INSTANCE.add(); break; // We found a match, so we can stop checking } } @@ -243,6 +382,8 @@ public static void onBlockChange(Level level, BlockPos pos, BlockState state) { .findFirst(); if (blockFromRenderList.isEmpty()) { + INSTANCE.clean(); + INSTANCE.add(); return; } diff --git a/common/src/main/java/pro/mikey/xray/core/scanner/BlockScanType.java b/common/src/main/java/pro/mikey/xray/core/scanner/BlockScanType.java index c79caf3..afbfe99 100644 --- a/common/src/main/java/pro/mikey/xray/core/scanner/BlockScanType.java +++ b/common/src/main/java/pro/mikey/xray/core/scanner/BlockScanType.java @@ -41,4 +41,9 @@ public boolean matches(Level level, BlockPos pos, BlockState state, FluidState f void writeData(JsonObject obj) { obj.addProperty("block_name", this.blockName); } + + @Override + public Block getBlock() { + return this.block; + } } diff --git a/common/src/main/java/pro/mikey/xray/core/scanner/ScanStore.java b/common/src/main/java/pro/mikey/xray/core/scanner/ScanStore.java index bf0fe19..d74fa62 100644 --- a/common/src/main/java/pro/mikey/xray/core/scanner/ScanStore.java +++ b/common/src/main/java/pro/mikey/xray/core/scanner/ScanStore.java @@ -183,6 +183,24 @@ public void updateActiveTargets() { continue; // Skip disabled scan types } + if (scanType.getBlock()==Blocks.WHITE_BED){ + this.activeScanTargets.add(new BlockScanType(Blocks.WHITE_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.ORANGE_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.MAGENTA_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.LIGHT_BLUE_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.YELLOW_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.LIME_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.PINK_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.GRAY_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.LIGHT_GRAY_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.CYAN_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.PURPLE_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.BLUE_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.BROWN_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.GREEN_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.RED_BED, "", scanType.color(), 0)); + this.activeScanTargets.add(new BlockScanType(Blocks.BLACK_BED, "", scanType.color(), 0)); + } this.activeScanTargets.add(scanType); } } diff --git a/common/src/main/java/pro/mikey/xray/core/scanner/ScanType.java b/common/src/main/java/pro/mikey/xray/core/scanner/ScanType.java index a1fbbcb..fb95819 100644 --- a/common/src/main/java/pro/mikey/xray/core/scanner/ScanType.java +++ b/common/src/main/java/pro/mikey/xray/core/scanner/ScanType.java @@ -7,6 +7,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.FluidState; import pro.mikey.xray.XRay; +import net.minecraft.world.level.block.Block; import java.awt.*; import java.util.Set; @@ -248,4 +249,8 @@ public Identifier getId() { return id; } } + + public Block getBlock() { + return null; + } } diff --git a/common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java b/common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java index beb01b8..80cf6ff 100644 --- a/common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java +++ b/common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java @@ -3,6 +3,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractSliderButton; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.ObjectSelectionList; @@ -14,6 +15,7 @@ import net.minecraft.client.resources.language.I18n; import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; +import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; @@ -151,15 +153,26 @@ public void init() { .build()); - addRenderableWidget(distButtons = Button.builder(Component.translatable("xray.input.distance", ScanController.INSTANCE.getVisualRadius()), btn -> { - ScanController.INSTANCE.incrementCurrentDist(); - btn.setMessage(Component.translatable("xray.input.distance", ScanController.INSTANCE.getVisualRadius())); - }) - .pos(getWidth() / 2 + 79, getHeight() / 2 + 36) - .size(120, 20) - .tooltip(Tooltip.create(Component.translatable("xray.tooltips.distance"))) - .build() - ); + AbstractSliderButton radiusSlider = new AbstractSliderButton( + getWidth() / 2 + 79, getHeight() / 2 + 36, 120, 20, + Component.translatable("xray.input.distance", ScanController.INSTANCE.getVisualRadius()), + Mth.map(XRay.config().radius.get(), 0, 8, 0.0, 1.0) + ) { + @Override + protected void updateMessage() { + int currentRadiusp = Mth.floor(Mth.map(this.value, 0.0, 1.0, 0, 8)) ; + int currentRadius = Math.max(1, currentRadiusp * 3); + this.setMessage(Component.translatable("xray.input.distance", currentRadius)); + } + + @Override + protected void applyValue() { + int currentRadius = Mth.floor(Mth.map(this.value, 0.0, 1.0, 0, 8)); + ScanController.INSTANCE.incrementCurrentDist(currentRadius); + } + }; + radiusSlider.setTooltip(Tooltip.create(Component.translatable("xray.tooltips.distance"))); + addRenderableWidget(radiusSlider); addRenderableWidget( Button.builder(Component.translatable("xray.single.help"), button -> { From 47d116baa2e534d259b67187366fd8a3fe837890 Mon Sep 17 00:00:00 2001 From: laolitou2004 Date: Fri, 9 Jan 2026 06:33:25 +0800 Subject: [PATCH 2/5] Changes to be committed: modified: common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java modified: common/src/main/java/pro/mikey/xray/core/ScanController.java --- .../pro/mikey/xray/core/ChunkScanTask.java | 7 ++--- .../pro/mikey/xray/core/ScanController.java | 29 ++++++++++++------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java b/common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java index 790a6e9..255972a 100644 --- a/common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java +++ b/common/src/main/java/pro/mikey/xray/core/ChunkScanTask.java @@ -47,8 +47,8 @@ public void run() { state = level.getBlockState(pos); fluidState = state.getFluidState(); - if (iscore){ - if (( fluidState.getType() == Fluids.LAVA || fluidState.getType() == Fluids.FLOWING_LAVA) && ScanController.INSTANCE.isLavaActive()) { + if (( fluidState.getType() == Fluids.LAVA || fluidState.getType() == Fluids.FLOWING_LAVA) && ScanController.INSTANCE.isLavaActive()) { + if (iscore){ if (isNetherDimension()) { if (pos.getY() > 31){ renderQueue.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), 0xffff0000)); @@ -56,9 +56,8 @@ public void run() { } else { renderQueue.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), 0xffff0000)); } - continue; } - + continue; } // Reject blacklisted blocks diff --git a/common/src/main/java/pro/mikey/xray/core/ScanController.java b/common/src/main/java/pro/mikey/xray/core/ScanController.java index 4e3eb0a..9103485 100644 --- a/common/src/main/java/pro/mikey/xray/core/ScanController.java +++ b/common/src/main/java/pro/mikey/xray/core/ScanController.java @@ -51,6 +51,7 @@ public Thread newThread(@NotNull Runnable r) { public final Map> syncRenderLista = new ConcurrentHashMap<>(); // this is accessed by threads private ChunkPos lastChunkPos = null; private BlockPos lastPos = null; + private List core3x3Chunks; private Set last3x3 = ConcurrentHashMap.newKeySet(); private Set lastxxx = ConcurrentHashMap.newKeySet(); private List lastshi = new ArrayList<>(); @@ -173,6 +174,10 @@ private List getOuterChunks(List allChunks, List c .filter(chunk -> !core3x3Chunks.contains(chunk)) .collect(Collectors.toList()); } + + private List getcore3x3Chunks() { + return core3x3Chunks; + } public synchronized void requestBlockFinder(boolean force) { var player = Minecraft.getInstance().player; @@ -209,7 +214,7 @@ public synchronized void requestBlockFinder(boolean force) { // Sort the chunks by distance to the player chunksToScan.sort(Comparator.comparingDouble(chunk -> chunk.distanceSquared(playerChunkPos))); - List core3x3Chunks = getCore3x3Chunks(playerChunkPos,range); + core3x3Chunks = getCore3x3Chunks(playerChunkPos,range); List outerChunks = getOuterChunks(chunksToScan, core3x3Chunks); var knownChunksa = last3x3; @@ -341,17 +346,19 @@ public static void onBlockChange(Level level, BlockPos pos, BlockState state) { } if (ScanController.INSTANCE.isLavaActive() && state.is(Blocks.LAVA)) { - synchronized (RENDER_SET_LOCK) { - // We're actively looking at this chunk so let's inject this block - outlineRenderTargets.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), 0xffff0000)); + if (INSTANCE.getcore3x3Chunks().contains(chunkPos)) { + synchronized (RENDER_SET_LOCK) { + // We're actively looking at this chunk so let's inject this block + outlineRenderTargets.add(new OutlineRenderTarget(pos.getX(), pos.getY(), pos.getZ(), 0xffff0000)); + } + + // Tell the VBO to refresh for this chunk + OutlineRender.refreshVBOForChunk(chunkPos); + + INSTANCE.clean(); + INSTANCE.add(); + return; } - - // Tell the VBO to refresh for this chunk - OutlineRender.refreshVBOForChunk(chunkPos); - - INSTANCE.clean(); - INSTANCE.add(); - return; } // Otherwise, do we have scantarget in the active list of things to find? From c5e94bc8b31b372d78ffdfdc18772dd8a76959f5 Mon Sep 17 00:00:00 2001 From: laolitou2004 Date: Sat, 10 Jan 2026 09:29:27 +0800 Subject: [PATCH 3/5] Changes to be committed: modified: common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java --- .../main/java/pro/mikey/xray/screens/ScanManageScreen.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java b/common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java index 80cf6ff..49c137a 100644 --- a/common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java +++ b/common/src/main/java/pro/mikey/xray/screens/ScanManageScreen.java @@ -117,8 +117,8 @@ public void init() { try { Vec3 look = player.getLookAngle(); - Vec3 start = new Vec3(player.blockPosition().getX(), player.blockPosition().getY() + player.getEyeHeight(), player.blockPosition().getZ()); - Vec3 end = new Vec3(player.blockPosition().getX() + look.x * 100, player.blockPosition().getY() + player.getEyeHeight() + look.y * 100, player.blockPosition().getZ() + look.z * 100); + Vec3 start = new Vec3(player.position().x(), player.position().y() + player.getEyeHeight(), player.position().z()); + Vec3 end = new Vec3(player.position().x() + look.x * 100, player.position().y() + player.getEyeHeight() + look.y * 100, player.position().z() + look.z * 100); ClipContext context = new ClipContext(start, end, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player); BlockHitResult result = minecraft.level.clip(context); From 77c5ef84999d7acb2c62551318b593e5853e0050 Mon Sep 17 00:00:00 2001 From: laolitou2004 Date: Sun, 11 Jan 2026 00:49:21 +0800 Subject: [PATCH 4/5] Changes to be committed: modified: common/src/main/java/pro/mikey/xray/core/OutlineRender.java --- .../src/main/java/pro/mikey/xray/core/OutlineRender.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/pro/mikey/xray/core/OutlineRender.java b/common/src/main/java/pro/mikey/xray/core/OutlineRender.java index 7de1645..1df917e 100644 --- a/common/src/main/java/pro/mikey/xray/core/OutlineRender.java +++ b/common/src/main/java/pro/mikey/xray/core/OutlineRender.java @@ -15,7 +15,9 @@ import net.minecraft.resources.Identifier; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.phys.Vec3; -import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraft.world.level.block.Block; + import org.joml.Matrix4f; import org.joml.Matrix4fStack; import org.joml.Vector3f; @@ -34,6 +36,7 @@ public class OutlineRender { private static final Set chunksToRefresha = Collections.synchronizedSet(new HashSet<>()); private static final Object CHUNKS_TO_REFRESH_LOCK = new Object(); private static final Object CHUNKS_TO_REFRESH_LOCKA = new Object(); + private static final VoxelShape BLOCK = Block.box(0.1D, 0.1D, 0.1D, 15.9D, 15.9D, 15.9D); public static void renderBlocks(PoseStack poseStack) { if (!ScanController.INSTANCE.isXRayActive() || Minecraft.getInstance().player == null) { @@ -82,7 +85,7 @@ public static void renderBlocks(PoseStack poseStack) { final int x = blockProps.x(), y = blockProps.y(), z = blockProps.z(); - ShapeRenderer.renderShape(poseStack, bufferBuilder, Shapes.block(), x, y, z, blockProps.color(), 1f); + ShapeRenderer.renderShape(poseStack, bufferBuilder, BLOCK, x, y, z, blockProps.color(), 1f); } try (MeshData meshData = bufferBuilder.buildOrThrow()) { @@ -173,7 +176,7 @@ public static void renderBlocks(PoseStack poseStack) { final int x = blockProps.x(), y = blockProps.y(), z = blockProps.z(); - ShapeRenderer.renderShape(poseStack, bufferBuilder, Shapes.block(), x, y, z, blockProps.color(), 1f); + ShapeRenderer.renderShape(poseStack, bufferBuilder, BLOCK, x, y, z, blockProps.color(), 1f); } try (MeshData meshData = bufferBuilder.buildOrThrow()) { From f680309fb1a3a880e47be7b33579cc1040372259 Mon Sep 17 00:00:00 2001 From: laolitou2004 Date: Sun, 11 Jan 2026 23:14:01 +0800 Subject: [PATCH 5/5] Changes to be committed: modified: common/build.gradle --- common/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/build.gradle b/common/build.gradle index 0f82b75..96f1338 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -26,7 +26,7 @@ dependencies { compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5' - modCompileOnly "curse.maven:irisshaders-455508:${iris_version}" + //modCompileOnly "curse.maven:irisshaders-455508:${iris_version}" } test {