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
parent 63aeef1ba0
commit 8c2c33093b
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
3 changed files with 79 additions and 1 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

@ -63,4 +63,5 @@ accessible field net/minecraft/client/renderer/entity/EnderDragonRenderer$Dragon
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/world/item/crafting/Ingredient$Value
accessible class net/minecraft/world/item/crafting/Ingredient$ItemValue
accessible class net/minecraft/world/item/crafting/Ingredient$ItemValue
accessible class net/minecraft/client/searchtree/SearchRegistry$TreeEntry