Improve blockstate cache rebuild logic, remove vanilla search trees if JEI is installed
This commit is contained in:
parent
fa9a3bb890
commit
8dc915037c
|
|
@ -2,12 +2,15 @@ package org.embeddedt.modernfix.blockstate;
|
|||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.shapes.ISelectionContext;
|
||||
import net.minecraft.world.EmptyBlockReader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.duck.IBlockState;
|
||||
import org.embeddedt.modernfix.util.BakeReason;
|
||||
|
|
@ -25,39 +28,35 @@ public class BlockStateCacheHandler {
|
|||
.add("cabletiers")
|
||||
.add("extrastorage")
|
||||
.build();
|
||||
public static void handleStateCache(BlockState state) {
|
||||
|
||||
private static boolean needToBake() {
|
||||
BakeReason reason = BakeReason.getCurrentBakeReason();
|
||||
if(reason == BakeReason.FREEZE
|
||||
|| reason == BakeReason.REMOTE_SNAPSHOT_INJECT
|
||||
|| (reason == BakeReason.LOCAL_SNAPSHOT_INJECT && ModernFix.runningFirstInjection)) {
|
||||
//((IBlockState)state).clearCache();
|
||||
} else {
|
||||
state.initCache();
|
||||
}
|
||||
}
|
||||
private static void handleStateCacheParallel(BlockState state, boolean force) {
|
||||
if(force)
|
||||
state.initCache();
|
||||
else
|
||||
handleStateCache(state);
|
||||
return !(reason == BakeReason.FREEZE /* startup */
|
||||
|| reason == BakeReason.REVERT /* crash, in which case cache likely doesn't matter, or exiting world */
|
||||
|| reason == BakeReason.REMOTE_SNAPSHOT_INJECT /* will be handled when tags are reloaded */
|
||||
|| (reason == BakeReason.LOCAL_SNAPSHOT_INJECT && FMLLoader.getDist() == Dist.CLIENT /* will be handled when tags are reloaded */));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void rebuildParallel(boolean force) {
|
||||
/* Run some special sauce for Refined Storage since it has very slow collision shapes */
|
||||
Stopwatch realtimeStopwatch = Stopwatch.createStarted();
|
||||
List<BlockState> specialStates = StreamSupport.stream(Block.BLOCK_STATE_REGISTRY.spliterator(), false)
|
||||
.filter(state -> PRECACHED_COLLISION_SHAPES.contains(state.getBlock().getRegistryName().getNamespace())).collect(Collectors.toList());
|
||||
CompletableFuture.runAsync(() -> {
|
||||
specialStates.parallelStream()
|
||||
.forEach(state -> {
|
||||
/* Force these blocks to compute their shapes ahead of time on worker threads */
|
||||
state.getBlock().getCollisionShape(state, EmptyBlockReader.INSTANCE, BlockPos.ZERO, ISelectionContext.empty());
|
||||
state.getBlock().getOcclusionShape(state, EmptyBlockReader.INSTANCE, BlockPos.ZERO);
|
||||
});
|
||||
}, Util.backgroundExecutor()).join();
|
||||
Block.BLOCK_STATE_REGISTRY.forEach(state -> handleStateCacheParallel(state, force));
|
||||
realtimeStopwatch.stop();
|
||||
ModernFix.LOGGER.info("Real time spent rebuilding blockstate cache: " + realtimeStopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds");
|
||||
if(force || needToBake()) {
|
||||
Stopwatch realtimeStopwatch = Stopwatch.createStarted();
|
||||
/* Run some special sauce for Refined Storage since it has very slow collision shapes */
|
||||
List<BlockState> specialStates = StreamSupport.stream(Block.BLOCK_STATE_REGISTRY.spliterator(), false)
|
||||
.filter(state -> PRECACHED_COLLISION_SHAPES.contains(state.getBlock().getRegistryName().getNamespace())).collect(Collectors.toList());
|
||||
CompletableFuture.runAsync(() -> {
|
||||
specialStates.parallelStream()
|
||||
.forEach(state -> {
|
||||
/* Force these blocks to compute their shapes ahead of time on worker threads */
|
||||
state.getBlock().getCollisionShape(state, EmptyBlockReader.INSTANCE, BlockPos.ZERO, ISelectionContext.empty());
|
||||
state.getBlock().getOcclusionShape(state, EmptyBlockReader.INSTANCE, BlockPos.ZERO);
|
||||
});
|
||||
}, Util.backgroundExecutor()).join();
|
||||
Block.BLOCK_STATE_REGISTRY.forEach(AbstractBlock.AbstractBlockState::initCache);
|
||||
realtimeStopwatch.stop();
|
||||
ModernFix.LOGGER.info("Blockstate cache rebuilt in " + realtimeStopwatch.elapsed(TimeUnit.MILLISECONDS)/1000f + " seconds");
|
||||
} else {
|
||||
ModernFix.LOGGER.warn("Deferred blockstate cache rebuild");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,12 +34,13 @@ public class ModernFixEarlyConfig {
|
|||
this.addMixinRule("perf.preload_block_classes", false);
|
||||
this.addMixinRule("perf.sync_executor_sleep", true);
|
||||
this.addMixinRule("perf.scan_cache", true);
|
||||
this.addMixinRule("perf.parallel_blockstate_cache_rebuild", true);
|
||||
this.addMixinRule("perf.compress_biome_container", true);
|
||||
this.addMixinRule("perf.nuke_empty_chunk_sections", true);
|
||||
this.addMixinRule("perf.flatten_model_predicates", true);
|
||||
this.addMixinRule("perf.deduplicate_location", true);
|
||||
this.addMixinRule("perf.cache_blockstate_cache_arrays", true);
|
||||
/* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */
|
||||
this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null);
|
||||
this.addMixinRule("safety", true);
|
||||
this.addMixinRule("launch.transformer_cache", false);
|
||||
this.addMixinRule("launch.class_search_cache", true);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.blast_search_trees;
|
||||
|
||||
import mezz.jei.ingredients.IIngredientListElementInfo;
|
||||
import mezz.jei.ingredients.IngredientFilter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(IngredientFilter.class)
|
||||
public interface IngredientFilterInvoker {
|
||||
@Invoker
|
||||
List<IIngredientListElementInfo<?>> invokeGetIngredientListUncached(String filterText);
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.blast_search_trees;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.util.SearchTreeManager;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import org.embeddedt.modernfix.searchtree.DummySearchTree;
|
||||
import org.embeddedt.modernfix.searchtree.JEIBackedSearchTree;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
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.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
public class MinecraftMixin {
|
||||
@Shadow @Final private SearchTreeManager searchRegistry;
|
||||
|
||||
@Inject(method = "createSearchTrees", at = @At("HEAD"), cancellable = true)
|
||||
private void replaceSearchTrees(CallbackInfo ci) {
|
||||
ci.cancel();
|
||||
if(ModList.get().getModFileById("jei") != null) {
|
||||
this.searchRegistry.register(SearchTreeManager.CREATIVE_NAMES, new JEIBackedSearchTree(false));
|
||||
this.searchRegistry.register(SearchTreeManager.CREATIVE_TAGS, new JEIBackedSearchTree(true));
|
||||
} else {
|
||||
this.searchRegistry.register(SearchTreeManager.CREATIVE_NAMES, new DummySearchTree<>());
|
||||
this.searchRegistry.register(SearchTreeManager.CREATIVE_TAGS, new DummySearchTree<>());
|
||||
}
|
||||
this.searchRegistry.register(SearchTreeManager.RECIPE_COLLECTIONS, new DummySearchTree<>());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.parallel_blockstate_cache_rebuild;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.ObjectIntIdentityMap;
|
||||
import net.minecraft.world.gen.DebugChunkGenerator;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
import net.minecraftforge.registries.IForgeRegistryInternal;
|
||||
import net.minecraftforge.registries.RegistryManager;
|
||||
import org.embeddedt.modernfix.blockstate.BlockStateCacheHandler;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(targets = { "net/minecraftforge/registries/GameData$BlockCallbacks" })
|
||||
public class BlockCallbacksMixin {
|
||||
@Inject(method = "onBake", at = @At(value = "INVOKE", target = "Ljava/util/Iterator;hasNext()Z"), cancellable = true, remap = false)
|
||||
private void computeCacheParallel(IForgeRegistryInternal<Block> owner, RegistryManager stage, CallbackInfo ci) {
|
||||
ci.cancel();
|
||||
ObjectIntIdentityMap<BlockState> blockstateMap = GameData.getBlockStateIDMap();
|
||||
for (Block block : owner) {
|
||||
for (BlockState state : block.getStateDefinition().getPossibleStates()) {
|
||||
blockstateMap.add(state);
|
||||
}
|
||||
}
|
||||
BlockStateCacheHandler.rebuildParallel(false);
|
||||
DebugChunkGenerator.initValidStates();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import org.embeddedt.modernfix.duck.IBlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Mixin(AbstractBlock.AbstractBlockState.class)
|
||||
public class AbstractBlockStateMixin implements IBlockState {
|
||||
@Shadow @Nullable protected AbstractBlock.AbstractBlockState.Cache cache;
|
||||
|
||||
@Override
|
||||
public void clearCache() {
|
||||
this.cache = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,25 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import net.minecraftforge.registries.IForgeRegistryInternal;
|
||||
import net.minecraftforge.registries.RegistryManager;
|
||||
import org.embeddedt.modernfix.blockstate.BlockStateCacheHandler;
|
||||
import org.embeddedt.modernfix.duck.IBlockState;
|
||||
import org.embeddedt.modernfix.util.BakeReason;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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;
|
||||
|
||||
@Mixin(targets = { "net/minecraftforge/registries/GameData$BlockCallbacks" })
|
||||
public class BlockCallbacksMixin {
|
||||
@Redirect(method = "onBake", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;initCache()V"))
|
||||
private void skipCacheIfAllowed(BlockState state) {
|
||||
BlockStateCacheHandler.handleStateCache(state);
|
||||
private void skipCache(BlockState instance) {
|
||||
|
||||
}
|
||||
|
||||
@Inject(method = "onBake", at = @At(value = "TAIL"), remap = false)
|
||||
private void computeCaches(IForgeRegistryInternal<Block> owner, RegistryManager stage, CallbackInfo ci) {
|
||||
BlockStateCacheHandler.rebuildParallel(false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.parallel_blockstate_cache_rebuild;
|
||||
package org.embeddedt.modernfix.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
import org.embeddedt.modernfix.blockstate.BlockStateCacheHandler;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.parallel_blockstate_cache_rebuild;
|
||||
package org.embeddedt.modernfix.mixin.perf.reduce_blockstate_cache_rebuilds;
|
||||
|
||||
import com.refinedmods.refinedstorage.block.shape.ShapeCache;
|
||||
import net.minecraft.block.BlockState;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.embeddedt.modernfix.searchtree;
|
||||
|
||||
import net.minecraft.client.util.IMutableSearchTree;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Dummy search tree that stores nothing and returns nothing on searches.
|
||||
*/
|
||||
public class DummySearchTree<T> implements IMutableSearchTree<T> {
|
||||
@Override
|
||||
public void add(T pObj) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> search(String pSearchText) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package org.embeddedt.modernfix.searchtree;
|
||||
|
||||
import mezz.jei.Internal;
|
||||
import mezz.jei.ingredients.IIngredientListElementInfo;
|
||||
import mezz.jei.ingredients.IngredientFilter;
|
||||
import mezz.jei.runtime.JeiRuntime;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.embeddedt.modernfix.mixin.perf.blast_search_trees.IngredientFilterInvoker;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Uses JEI to handle search tree lookups.
|
||||
*/
|
||||
public class JEIBackedSearchTree extends DummySearchTree<ItemStack> {
|
||||
private final boolean filteringByTag;
|
||||
private String lastSearchText = "";
|
||||
private final List<ItemStack> listCache = new ArrayList<>();
|
||||
|
||||
public JEIBackedSearchTree(boolean filteringByTag) {
|
||||
this.filteringByTag = filteringByTag;
|
||||
}
|
||||
@Override
|
||||
public List<ItemStack> search(String pSearchText) {
|
||||
JeiRuntime runtime = Internal.getRuntime();
|
||||
if(runtime != null) {
|
||||
return this.searchJEI(Internal.getIngredientFilter(), pSearchText);
|
||||
} else {
|
||||
/* Use the default, dummy implementation */
|
||||
return super.search(pSearchText);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ItemStack> searchJEI(IngredientFilter filter, String pSearchText) {
|
||||
if(!pSearchText.equals(lastSearchText)) {
|
||||
listCache.clear();
|
||||
List<IIngredientListElementInfo<?>> ingredients = ((IngredientFilterInvoker)filter).invokeGetIngredientListUncached(filteringByTag ? ("$" + pSearchText) : pSearchText);
|
||||
for(IIngredientListElementInfo<?> ingredient : ingredients) {
|
||||
if(ingredient.getElement().getIngredient() instanceof ItemStack) {
|
||||
listCache.add((ItemStack)ingredient.getElement().getIngredient());
|
||||
}
|
||||
}
|
||||
lastSearchText = pSearchText;
|
||||
}
|
||||
return listCache;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,15 +12,14 @@
|
|||
"perf.resourcepacks.VanillaPackMixin",
|
||||
"perf.skip_first_datapack_reload.LevelSaveMixin",
|
||||
"perf.skip_first_datapack_reload.SaveFormatAccessor",
|
||||
"perf.reduce_blockstate_cache_rebuilds.AbstractBlockStateMixin",
|
||||
"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.parallel_blockstate_cache_rebuild.BlocksMixin",
|
||||
"perf.parallel_blockstate_cache_rebuild.BlockCallbacksMixin",
|
||||
"perf.parallel_blockstate_cache_rebuild.ShapeCacheMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.BlocksMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.BlockCallbacksMixin",
|
||||
"perf.reduce_blockstate_cache_rebuilds.ShapeCacheMixin",
|
||||
"perf.deduplicate_location.MixinResourceLocation",
|
||||
"perf.sync_executor_sleep.SyncExecutorMixin",
|
||||
"perf.compress_biome_container.MixinBiomeContainer",
|
||||
|
|
@ -47,7 +46,9 @@
|
|||
"safety.BlockColorsMixin",
|
||||
"perf.flatten_model_predicates.AndConditionMixin",
|
||||
"perf.flatten_model_predicates.OrConditionMixin",
|
||||
"perf.flatten_model_predicates.PropertyValueConditionMixin"
|
||||
"perf.flatten_model_predicates.PropertyValueConditionMixin",
|
||||
"perf.blast_search_trees.MinecraftMixin",
|
||||
"perf.blast_search_trees.IngredientFilterInvoker"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user