diff --git a/src/main/java/adris/altoclef/AltoClef.java b/src/main/java/adris/altoclef/AltoClef.java index 83529d66c..743b9dc0a 100644 --- a/src/main/java/adris/altoclef/AltoClef.java +++ b/src/main/java/adris/altoclef/AltoClef.java @@ -181,7 +181,9 @@ public void onClientTick() { _miscBlockTracker.tick(); _trackerManager.tick(); + _blockTracker.preTickTask(); _taskRunner.tick(); + _blockTracker.postTickTask(); _butler.tick(); _messageSender.tick(); diff --git a/src/main/java/adris/altoclef/trackers/BlockTracker.java b/src/main/java/adris/altoclef/trackers/BlockTracker.java index 2a9890a23..8deffc611 100644 --- a/src/main/java/adris/altoclef/trackers/BlockTracker.java +++ b/src/main/java/adris/altoclef/trackers/BlockTracker.java @@ -21,6 +21,7 @@ import net.minecraft.util.math.Vec3d; import java.util.*; +import java.util.concurrent.Semaphore; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -52,12 +53,18 @@ public class BlockTracker extends Tracker { private final TimerGame _forceElapseTimer = new TimerGame(_config.scanIntervalWhenNewBlocksFound); + // A scan can last no more than 15 seconds + private final TimerGame _asyncForceResetScanFlag = new TimerGame(15); + private final Map _trackingBlocks = new HashMap<>(); private final Object _scanMutex = new Object(); private boolean _scanning = false; + // Only perform scans at the END of our frame + private final Semaphore _endOfFrameMutex = new Semaphore(1); + //private Block _currentlyTracking = null; private final AltoClef _mod; @@ -76,6 +83,19 @@ protected void updateState() { } } + // We want our `_trackingBlocks` value to be read AFTER tasks have finished ticking + public void preTickTask() { + try { + _endOfFrameMutex.acquire(); + } catch (InterruptedException e) { + Debug.logWarning("Pre-tick failed to acquire block track mutex! (send logs)"); + e.printStackTrace(); + } + } + public void postTickTask() { + _endOfFrameMutex.release(); + } + @Override protected void reset() { // Tasks will handle de-tracking blocks. @@ -280,21 +300,38 @@ private void update() { _timer.setInterval(_config.scanInterval); CalculationContext ctx = new CalculationContext(_mod.getClientBaritone(), _config.scanAsynchronously); if (_config.scanAsynchronously) { + if (_scanning && _asyncForceResetScanFlag.elapsed()) { + Debug.logMessage("SCANNING TOOK TOO LONG! Will assume it ended mid way. Hopefully this won't break anything..."); + _scanning = false; + } if (!_scanning) { - _scanning = true; Baritone.getExecutor().execute(() -> { - rescanWorld(ctx); + _scanning = true; + _asyncForceResetScanFlag.reset(); + rescanWorld(ctx, true); _scanning = false; }); } } else { // Synchronous scanning. - rescanWorld(ctx); + rescanWorld(ctx, false); } } - private void rescanWorld(CalculationContext ctx) { + private void rescanWorld(CalculationContext ctx, boolean async) { Block[] blocksToScan; + if (async) { + // Wait for end of frame + try { + _endOfFrameMutex.acquire(); + _endOfFrameMutex.release(); + } catch (InterruptedException e) { + Debug.logWarning("RESCAN INTERRUPTED! Will SKIP the scan (see logs)"); + _endOfFrameMutex.release(); + e.printStackTrace(); + return; + } + } synchronized (_trackingBlocks) { Debug.logInternal("Rescanning world for " + _trackingBlocks.size() + " blocks... Hopefully not dummy slow."); blocksToScan = new Block[_trackingBlocks.size()]; @@ -318,7 +355,7 @@ private void rescanWorld(CalculationContext ctx) { // The scanning may run asynchronously. BlockOptionalMetaLookup boml = new BlockOptionalMetaLookup(blocksToScan); - List found = MineProcess.searchWorld(ctx, boml, 64, Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + List found = MineProcess.searchWorld(ctx, boml, _config.maxCacheSizePerBlockType, Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); synchronized (_scanMutex) { if (MinecraftClient.getInstance().world != null) {