Skip to content

Commit ad6425f

Browse files
committed
Improve bulk dynamic model loading performance
Filtering by blockstate has been removed as it seems to be slower now than just loading all the models. This will need to be revisited if we end up with issues from Pedestals again.
1 parent 960c394 commit ad6425f

File tree

1 file changed

+42
-3
lines changed

1 file changed

+42
-3
lines changed

common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/BlockStateModelLoaderMixin.java

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
22

3+
import com.google.common.cache.Cache;
4+
import com.google.common.cache.CacheBuilder;
35
import com.google.common.collect.ImmutableList;
6+
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
7+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
8+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
9+
import it.unimi.dsi.fastutil.Pair;
410
import it.unimi.dsi.fastutil.objects.Object2IntMap;
511
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
6-
import net.minecraft.client.Minecraft;
12+
import it.unimi.dsi.fastutil.objects.ReferenceObjectImmutablePair;
713
import net.minecraft.client.color.block.BlockColors;
14+
import net.minecraft.client.renderer.block.model.BlockModelDefinition;
815
import net.minecraft.client.resources.model.BlockStateModelLoader;
916
import net.minecraft.client.resources.model.ModelResourceLocation;
1017
import net.minecraft.client.resources.model.UnbakedModel;
@@ -15,10 +22,8 @@
1522
import net.minecraft.world.level.block.Block;
1623
import net.minecraft.world.level.block.state.BlockState;
1724
import net.minecraft.world.level.block.state.StateDefinition;
18-
import org.embeddedt.modernfix.ModernFix;
1925
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
2026
import org.embeddedt.modernfix.duck.IBlockStateModelLoader;
21-
import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers;
2227
import org.spongepowered.asm.mixin.Final;
2328
import org.spongepowered.asm.mixin.Mixin;
2429
import org.spongepowered.asm.mixin.Mutable;
@@ -31,7 +36,9 @@
3136
import java.util.Collections;
3237
import java.util.Iterator;
3338
import java.util.Map;
39+
import java.util.concurrent.ExecutionException;
3440
import java.util.function.BiConsumer;
41+
import java.util.function.Predicate;
3542

3643
@Mixin(BlockStateModelLoader.class)
3744
@ClientOnlyMixin
@@ -51,13 +58,17 @@ private void makeModelGroupsSynchronized(Map map, ProfilerFiller profilerFiller,
5158
public void loadSpecificBlock(ModelResourceLocation location) {
5259
var optionalBlock = BuiltInRegistries.BLOCK.getOptional(location.id());
5360
if(optionalBlock.isPresent()) {
61+
// embeddedt note - filtering is currently disabled as it's quite inefficient to do vs. just loading
62+
// the extra models and letting LRU deal with it
63+
/*
5464
try {
5565
// Only filter states if we are in a world and not in the loading overlay
5666
filteredStates = (Minecraft.getInstance().getOverlay() == null && Minecraft.getInstance().level != null) ? ModelBakeryHelpers.getBlockStatesForMRL(optionalBlock.get().getStateDefinition(), location) : null;
5767
} catch(RuntimeException e) {
5868
ModernFix.LOGGER.error("Exception filtering states on {}", location, e);
5969
filteredStates = null;
6070
}
71+
*/
6172
try {
6273
this.loadBlockStateDefinitions(location.id(), optionalBlock.get().getStateDefinition());
6374
} finally {
@@ -75,4 +86,32 @@ private Iterator<?> skipIteratingBlocks(DefaultedRegistry instance) {
7586
private ImmutableList<BlockState> getFilteredStates(StateDefinition<Block, BlockState> instance) {
7687
return this.filteredStates != null ? this.filteredStates : instance.getPossibleStates();
7788
}
89+
90+
// Add some caching around key hot paths
91+
92+
private final Cache<ReferenceObjectImmutablePair<BlockStateModelLoader.LoadedJson, ResourceLocation>, BlockModelDefinition> cachedBlockModelDefs = CacheBuilder.newBuilder()
93+
.maximumSize(100)
94+
.build();
95+
96+
private static final Cache<Pair<StateDefinition<Block, BlockState>, String>, Predicate<BlockState>> cachedBlockStatePredicates = CacheBuilder.newBuilder()
97+
.maximumSize(100)
98+
.build();
99+
100+
@WrapOperation(method = "loadBlockStateDefinitions", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/BlockStateModelLoader$LoadedJson;parse(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/renderer/block/model/BlockModelDefinition$Context;)Lnet/minecraft/client/renderer/block/model/BlockModelDefinition;"))
101+
private BlockModelDefinition avoidMultipleParses(BlockStateModelLoader.LoadedJson instance, ResourceLocation blockStateId, BlockModelDefinition.Context context, Operation<BlockModelDefinition> original) {
102+
try {
103+
return cachedBlockModelDefs.get(ReferenceObjectImmutablePair.of(instance, blockStateId), () -> original.call(instance, blockStateId, context));
104+
} catch (ExecutionException e) {
105+
throw new RuntimeException(e);
106+
}
107+
}
108+
109+
@WrapMethod(method = "predicate")
110+
private static Predicate<BlockState> memoizePredicate(StateDefinition<Block, BlockState> stateDefentition, String properties, Operation<Predicate<BlockState>> original) {
111+
try {
112+
return cachedBlockStatePredicates.get(Pair.of(stateDefentition, properties), () -> original.call(stateDefentition, properties));
113+
} catch (ExecutionException e) {
114+
throw new RuntimeException(e);
115+
}
116+
}
78117
}

0 commit comments

Comments
 (0)