Build blockstate cache on-demand instead of using a background thread
Should also hide incompatibility with buggy block impls. like Dynamic Trees
This commit is contained in:
parent
38a4776626
commit
00d0885245
|
|
@ -2,11 +2,13 @@ package org.embeddedt.modernfix.blockstate;
|
|||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.core.config.ModernFixConfig;
|
||||
import org.embeddedt.modernfix.duck.IBlockState;
|
||||
import org.embeddedt.modernfix.util.BakeReason;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -15,8 +17,6 @@ import java.util.List;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BlockStateCacheHandler {
|
||||
private static RebuildThread currentRebuildThread = null;
|
||||
|
||||
private static boolean needToBake() {
|
||||
BakeReason reason = BakeReason.getCurrentBakeReason();
|
||||
return !(reason == BakeReason.FREEZE /* startup */
|
||||
|
|
@ -26,73 +26,11 @@ public class BlockStateCacheHandler {
|
|||
}
|
||||
|
||||
public static void rebuildParallel(boolean force) {
|
||||
if(currentRebuildThread != null) {
|
||||
if(currentRebuildThread.isAlive())
|
||||
ModernFix.LOGGER.warn("Interrupting previous blockstate cache rebuild");
|
||||
currentRebuildThread.stopRebuild();
|
||||
try {
|
||||
currentRebuildThread.join(10000);
|
||||
if(currentRebuildThread.isAlive())
|
||||
throw new IllegalStateException("Blockstate cache rebuild thread has hung");
|
||||
} catch(InterruptedException e) {
|
||||
throw new RuntimeException("Don't interrupt Minecraft threads", e);
|
||||
}
|
||||
ModernFix.LOGGER.debug("Rebuild thread exited");
|
||||
currentRebuildThread = null;
|
||||
}
|
||||
if(force || needToBake()) {
|
||||
ArrayList<BlockState> stateList = new ArrayList<>(Block.BLOCK_STATE_REGISTRY.size());
|
||||
ModernFix.LOGGER.warn("Clearing blockstate cache");
|
||||
synchronized (BlockBehaviour.BlockStateBase.Cache.class) {
|
||||
for (BlockState blockState : Block.BLOCK_STATE_REGISTRY) {
|
||||
stateList.add(blockState);
|
||||
((IBlockState)blockState).clearCache();
|
||||
}
|
||||
currentRebuildThread = new RebuildThread(stateList);
|
||||
if(ModernFixConfig.REBUILD_BLOCKSTATES_ASYNC.get())
|
||||
currentRebuildThread.start();
|
||||
else {
|
||||
currentRebuildThread.run();
|
||||
currentRebuildThread = null;
|
||||
}
|
||||
} else {
|
||||
ModernFix.LOGGER.debug("Deferred blockstate cache rebuild");
|
||||
}
|
||||
}
|
||||
|
||||
private static class RebuildThread extends Thread {
|
||||
private boolean stopRebuild = false;
|
||||
private final List<BlockState> blockStateList;
|
||||
|
||||
public RebuildThread(List<BlockState> statesToInit) {
|
||||
this.setName("ModernFix blockstate cache rebuild thread");
|
||||
this.setPriority(Thread.MIN_PRIORITY + 1);
|
||||
this.blockStateList = statesToInit;
|
||||
}
|
||||
|
||||
public void stopRebuild() {
|
||||
this.stopRebuild = true;
|
||||
}
|
||||
|
||||
private void rebuildCache() {
|
||||
Iterator<BlockState> stateIterator = blockStateList.iterator();
|
||||
while(!stopRebuild && stateIterator.hasNext()) {
|
||||
BlockState state = stateIterator.next();
|
||||
try {
|
||||
state.initCache();
|
||||
} catch(Exception e) {
|
||||
ModernFix.LOGGER.warn("Exception encountered while initializing cache", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ModernFix.waitForWorldLoad(() -> stopRebuild);
|
||||
if(stopRebuild)
|
||||
return;
|
||||
Stopwatch realtimeStopwatch = Stopwatch.createStarted();
|
||||
rebuildCache();
|
||||
realtimeStopwatch.stop();
|
||||
if(!stopRebuild)
|
||||
ModernFix.LOGGER.info("Blockstate cache rebuilt in " + realtimeStopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.duck.IBlockState;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Mixin(BlockBehaviour.BlockStateBase.class)
|
||||
public abstract class BlockStateBaseMixin implements IBlockState {
|
||||
@Shadow public abstract void initCache();
|
||||
|
||||
@Shadow private BlockBehaviour.BlockStateBase.Cache cache;
|
||||
|
||||
private volatile boolean cacheInvalid = false;
|
||||
private static boolean buildingCache = false;
|
||||
private static final ThreadLocal<Boolean> isMakingCache = ThreadLocal.withInitial(() -> false);
|
||||
@Override
|
||||
public void clearCache() {
|
||||
cacheInvalid = true;
|
||||
}
|
||||
|
||||
@Redirect(method = "*", at = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.GETFIELD,
|
||||
target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;cache:Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase$Cache;",
|
||||
ordinal = 0
|
||||
))
|
||||
private BlockBehaviour.BlockStateBase.Cache initCacheIfNeeded(BlockBehaviour.BlockStateBase base) {
|
||||
if(cacheInvalid) {
|
||||
// Ensure that only one block's cache is built at a time
|
||||
synchronized (BlockBehaviour.BlockStateBase.Cache.class) {
|
||||
if(cacheInvalid) {
|
||||
// Ensure that if we end up in here recursively, we just use the original cache
|
||||
if(!buildingCache) {
|
||||
buildingCache = true;
|
||||
try {
|
||||
this.initCache();
|
||||
cacheInvalid = false;
|
||||
} finally {
|
||||
buildingCache = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return this.cache;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import com.refinedmods.refinedstorage.block.shape.ShapeCache;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Mixin(ShapeCache.class)
|
||||
public class ShapeCacheMixin {
|
||||
@Final
|
||||
@Mutable
|
||||
@Shadow(remap = false) private static Map<BlockState, VoxelShape> CACHE;
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
||||
private static void useConcurrentMap(CallbackInfo ci) {
|
||||
CACHE = new ConcurrentHashMap<>();
|
||||
ModernFix.LOGGER.info("Successfully replaced ShapeCache with concurrent map");
|
||||
}
|
||||
}
|
||||
|
|
@ -14,14 +14,13 @@
|
|||
"perf.resourcepacks.VanillaPackMixin",
|
||||
"perf.skip_first_datapack_reload.LevelSaveMixin",
|
||||
"perf.skip_first_datapack_reload.SaveFormatAccessor",
|
||||
"perf.reduce_blockstate_cache_rebuilds.GameDataMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.BlockCallbacksMixin",
|
||||
"perf.boost_worker_count.UtilMixin",
|
||||
"perf.thread_priorities.UtilMixin",
|
||||
"perf.preload_block_classes.GameDataMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.BlocksMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.GameDataMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.BlockCallbacksMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.ShapeCacheMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.BlocksMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.BlockStateBaseMixin",
|
||||
"perf.deduplicate_location.MixinResourceLocation",
|
||||
"perf.sync_executor_sleep.SyncExecutorMixin",
|
||||
"perf.compress_biome_container.MixinBiomeContainer",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user