Build creative mode tab search tree on first use

This avoids holding search trees for many creative tabs that will
likely never be searched during gameplay.
This commit is contained in:
embeddedt 2025-04-26 16:15:24 -04:00 committed by DerCommander323
parent 64ee2d2914
commit def8968de1
3 changed files with 93 additions and 5 deletions

View File

@ -0,0 +1,17 @@
package org.embeddedt.modernfix.common.mixin.perf.lazy_search_tree_registry;
import net.minecraft.client.searchtree.SearchRegistry;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.searchtree.LazySearchTree;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Mixin(SearchRegistry.class)
@ClientOnlyMixin
public class SearchRegistryMixin {
@ModifyVariable(method = "register", at = @At("HEAD"), ordinal = 0, argsOnly = true)
private <T> SearchRegistry.TreeBuilderSupplier<T> useLazyBuilder(SearchRegistry.TreeBuilderSupplier<T> supplier) {
return LazySearchTree.decorate(supplier);
}
}

View File

@ -0,0 +1,60 @@
package org.embeddedt.modernfix.searchtree;
import com.google.common.base.Stopwatch;
import net.minecraft.client.searchtree.RefreshableSearchTree;
import net.minecraft.client.searchtree.SearchRegistry;
import org.embeddedt.modernfix.ModernFix;
import java.util.List;
import java.util.function.Function;
public class LazySearchTree<T> implements RefreshableSearchTree<T> {
private final List<T> contents;
private final Function<List<T>, RefreshableSearchTree<T>> treeBuilder;
private volatile RefreshableSearchTree<T> realTree;
public LazySearchTree(List<T> contents, Function<List<T>, RefreshableSearchTree<T>> treeBuilder) {
this.contents = contents;
this.treeBuilder = treeBuilder;
}
private RefreshableSearchTree<T> getRealTree() {
var t = realTree;
if (t == null) {
synchronized (this) {
t = realTree;
if (t == null) {
ModernFix.LOGGER.info("Building search tree for {} items (this may take a while)...", contents.size());
Stopwatch s = Stopwatch.createStarted();
t = this.treeBuilder.apply(contents);
t.refresh();
s.stop();
ModernFix.LOGGER.info("Building search tree for {} items took {}", contents.size(), s);
realTree = t;
}
}
}
return t;
}
@Override
public List<T> search(String query) {
if (query.isEmpty()) {
return this.contents;
}
return getRealTree().search(query);
}
@Override
public void refresh() {
var t = this.realTree;
if (t != null) {
t.refresh();
}
}
public static <T> SearchRegistry.TreeBuilderSupplier<T> decorate(SearchRegistry.TreeBuilderSupplier<T> originalSupplier) {
return list -> new LazySearchTree<>(list, originalSupplier);
}
}

View File

@ -32,12 +32,22 @@ accessible field net/minecraft/client/renderer/texture/Stitcher$Holder width I
accessible field net/minecraft/client/renderer/texture/Stitcher$Holder height I
accessible field net/minecraft/network/syncher/EntityDataAccessor id I
mutable field net/minecraft/network/syncher/EntityDataAccessor id I
accessible class net/minecraft/client/resources/model/ModelBakery$BlockStateDefinitionException
accessible field net/minecraft/network/syncher/SynchedEntityData itemsById Lit/unimi/dsi/fastutil/ints/Int2ObjectMap;
accessible field net/minecraft/network/syncher/SynchedEntityData ENTITY_ID_POOL Lit/unimi/dsi/fastutil/objects/Object2IntMap;
accessible field net/minecraft/network/syncher/SynchedEntityData lock Ljava/util/concurrent/locks/ReadWriteLock;
accessible method net/minecraft/Util makeExecutor (Ljava/lang/String;)Ljava/util/concurrent/ExecutorService;
accessible field net/minecraft/server/level/ChunkMap updatingChunkMap Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
accessible field net/minecraft/server/level/ChunkMap visibleChunkMap Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
accessible field net/minecraft/server/level/ChunkMap pendingUnloads Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
accessible method net/minecraft/resources/ResourceKey <init> (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/resources/ResourceLocation;)V
accessible field net/minecraft/client/renderer/block/model/BlockModel GSON Lcom/google/gson/Gson;
accessible class net/minecraft/server/level/ChunkMap$DistanceManager
accessible class net/minecraft/client/resources/model/ModelBakery$BakedCacheKey
accessible field net/minecraft/client/resources/model/ModelBakery bakedCache Ljava/util/Map;
accessible field net/minecraft/client/resources/model/ModelBakery ITEM_MODEL_GENERATOR Lnet/minecraft/client/renderer/block/model/ItemModelGenerator;
accessible method net/minecraft/client/resources/model/ModelBakery loadTopLevel (Lnet/minecraft/client/resources/model/ModelResourceLocation;)V
accessible field net/minecraft/client/resources/model/ModelBakery topLevelModels Ljava/util/Map;
accessible class net/minecraft/client/resources/model/ModelBakery$ModelBakerImpl
accessible class net/minecraft/client/resources/model/ModelManager$ReloadState
accessible method net/minecraft/client/resources/model/BlockStateModelLoader loadBlockStateDefinitionStack (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/world/level/block/state/StateDefinition;Ljava/util/List;)Lnet/minecraft/client/resources/model/BlockStateModelLoader$LoadedModels;
@ -48,10 +58,11 @@ accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/s
accessible class net/minecraft/server/MinecraftServer$ReloadableResources
accessible method net/minecraft/client/gui/screens/Screen addRenderableWidget (Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener;
accessible field net/minecraft/client/KeyMapping ALL Ljava/util/Map;
accessible field net/minecraft/client/renderer/block/model/multipart/MultiPart definition Lnet/minecraft/world/level/block/state/StateDefinition;
accessible field net/minecraft/client/renderer/block/model/ItemOverrides$BakedOverride model Lnet/minecraft/client/resources/model/BakedModel;
mutable field net/minecraft/client/renderer/block/model/ItemOverrides$BakedOverride model Lnet/minecraft/client/resources/model/BakedModel;
accessible field net/minecraft/client/renderer/entity/EnderDragonRenderer$DragonModel entity Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;
accessible method net/minecraft/world/level/block/state/StateDefinition appendPropertyCodec (Lcom/mojang/serialization/MapCodec;Ljava/util/function/Supplier;Ljava/lang/String;Lnet/minecraft/world/level/block/state/properties/Property;)Lcom/mojang/serialization/MapCodec;
accessible class net/minecraft/client/multiplayer/SessionSearchTrees$Key
accessible class net/minecraft/client/resources/model/ModelDiscovery$ModelWrapper
accessible method net/minecraft/client/resources/model/ModelDiscovery$ModelWrapper <init> (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/UnbakedModel;Z)V
accessible field net/minecraft/client/resources/model/ModelDiscovery$ModelWrapper parent Lnet/minecraft/client/resources/model/ModelDiscovery$ModelWrapper;
accessible method net/minecraft/client/resources/model/BlockStateDefinitions definitionLocationToBlockStateMapper ()Ljava/util/function/Function;
accessible class net/minecraft/world/item/crafting/Ingredient$Value
accessible class net/minecraft/world/item/crafting/Ingredient$ItemValue