Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 93 additions & 49 deletions src/main/java/pro/mikey/fabric/xray/ScanController.java
Original file line number Diff line number Diff line change
@@ -1,78 +1,122 @@
package pro.mikey.fabric.xray;

import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import pro.mikey.fabric.xray.records.BlockPosWithColor;
import pro.mikey.fabric.xray.storage.BlockStore;
import pro.mikey.fabric.xray.render.RenderOutlines;
import pro.mikey.fabric.xray.storage.SettingsStore;
import pro.mikey.fabric.xray.tasks.*;

import java.util.concurrent.*;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class ScanController {
public static Set<BlockPosWithColor> renderQueue = Collections.synchronizedSet(new HashSet<>());
private static ChunkPos playerLastChunk;
static ThreadPoolExecutor executor = new ThreadPoolExecutor(
StateSettings.getRadius(), StateSettings.getRadius(),
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>()
);

/**
* No point even running if the player is still in the same chunk.
* This function sets the ThreadPool up properly.
* Technically the threads set their own Priority to one anyways, so a normal Threapool would be sufficient
*/
private static boolean playerLocationChanged() {
if (Minecraft.getInstance().player == null)
return false;
public static void setup(){
executor.setThreadFactory(r -> {
Thread thread = new Thread(r);
thread.setPriority(Thread.MIN_PRIORITY);
return thread;
});
}

ChunkPos plyChunkPos = Minecraft.getInstance().player.chunkPosition();
int range = StateSettings.getHalfRange();
private static void submitTask(Runnable worker){
if(!executor.isShutdown()){
executor.execute(worker);
}
}

return playerLastChunk == null ||
plyChunkPos.x > playerLastChunk.x + range || plyChunkPos.x < playerLastChunk.x - range ||
plyChunkPos.z > playerLastChunk.z + range || plyChunkPos.z < playerLastChunk.z - range;
/**
* Just a security measure to force-close the ThreadPool to make sure it doesn't linger in the background
*/
public static void closeGame() {
executor.shutdownNow();
}


/**
* Runs the scan task by checking if the thread is ready but first attempting to provide the cache
* if the cache is still valid.
*
* @param forceRerun if the task is required to re-run for instance, a block is broken in the
* world.
* This function rebuilds the ChunkCache completly and reloads all Chunks
* without flashing the already rendered Chunks instantly away
*/
public static synchronized void runTask(boolean forceRerun) {
Minecraft client = Minecraft.getInstance();
if (client.player == null && client.level == null) {
return;
public static void reBuildCache(boolean force) {
class RebuildThread extends Thread {
@Override
public synchronized void run() {
RenderOutlines.clearChunks(force);
executor.shutdownNow();
while (!executor.isTerminated()) {
try {
currentThread().wait(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
executor = new ThreadPoolExecutor(
StateSettings.getRadius(), StateSettings.getRadius(),
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>()
);
setup();
Runnable worker = new ReBuildCache();
executor.execute(worker);
}
}
Thread r = new RebuildThread();
r.start();
}

if (!SettingsStore.getInstance().get().isActive() || (!forceRerun && !playerLocationChanged())) {
return;
/**
* This function clears the Cache on a seperate Thread
*/
public static void clearCache(boolean force) {
class ClearThread extends Thread {
@Override
public synchronized void run() {
RenderOutlines.clearChunks(force);
}
}

// Update the players last chunk to eval against above.
playerLastChunk = client.player.chunkPosition();
Util.backgroundExecutor().execute(new ScanTask());
Thread r = new ClearThread();
r.start();
}

public static void blockBroken(Level world, Player playerEntity, BlockPos blockPos, BlockState blockState, BlockEntity blockEntity) {
if (!SettingsStore.getInstance().get().isActive()) return;
public static void reBuildCache() {
reBuildCache(false);
}

if (renderQueue.stream().anyMatch(e -> e.pos().equals(blockPos))) {
runTask(true);
/**
* This function updates a Chunk based on Pos
*/
public static void updateChunk(ChunkPos pos) {
if (SettingsStore.getInstance().get().isActive()) {
Runnable worker = new UpdateChunkTask(pos);
submitTask(worker);
}
}

public static void blockPlaced(BlockPlaceContext context) {
if (!SettingsStore.getInstance().get().isActive()) return;
/**
* This function updates a Chunk based on Pos
*/
public static void updateChunk(BlockPos pos){
int chunkx = SectionPos.blockToSectionCoord(pos.getX());
int chunkz = SectionPos.blockToSectionCoord(pos.getZ());
ChunkPos chunkPos = new ChunkPos(chunkx,chunkz);
updateChunk(chunkPos);
}

BlockState defaultState = Block.byItem(context.getItemInHand().getItem()).defaultBlockState();
if (BlockStore.getInstance().getCache().get().stream().anyMatch(e -> e.getState() == defaultState)) {
runTask(true);
}
/**
* This function removes a chunk from the Rendering
*/
public static void removeChunk(ChunkPos pos){
Runnable worker = new RemoveChunkTask(pos);
submitTask(worker);
}
}
131 changes: 0 additions & 131 deletions src/main/java/pro/mikey/fabric/xray/ScanTask.java

This file was deleted.

8 changes: 4 additions & 4 deletions src/main/java/pro/mikey/fabric/xray/StateSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pro.mikey.fabric.xray.storage.SettingsStore;

public class StateSettings {
private static final int maxStepsToScan = 5;
private static final int MAX_STEPS_TO_SCAN = 5;

private transient boolean isActive;
private boolean showLava;
Expand Down Expand Up @@ -35,7 +35,7 @@ public void setShowLava(boolean showLava) {
}

public static int getRadius() {
return Mth.clamp(SettingsStore.getInstance().get().range, 0, maxStepsToScan) * 3;
return Mth.clamp(SettingsStore.getInstance().get().range, 0, MAX_STEPS_TO_SCAN) * 3;
}

public static int getHalfRange() {
Expand All @@ -47,7 +47,7 @@ public static int getVisualRadius() {
}

public void increaseRange() {
if (SettingsStore.getInstance().get().range < maxStepsToScan)
if (SettingsStore.getInstance().get().range < MAX_STEPS_TO_SCAN)
SettingsStore.getInstance().get().range = SettingsStore.getInstance().get().range + 1;
else
SettingsStore.getInstance().get().range = 0;
Expand All @@ -57,7 +57,7 @@ public void decreaseRange() {
if (SettingsStore.getInstance().get().range > 0)
SettingsStore.getInstance().get().range = SettingsStore.getInstance().get().range - 1;
else
SettingsStore.getInstance().get().range = maxStepsToScan;
SettingsStore.getInstance().get().range = MAX_STEPS_TO_SCAN;
}

public boolean showOverlay() {
Expand Down
Loading