Merge remote-tracking branch 'origin/1.19.2' into 1.19.4

This commit is contained in:
embeddedt 2023-05-16 11:11:00 -04:00
commit 119f9ec6dd
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
18 changed files with 235 additions and 110 deletions

View File

@ -23,6 +23,10 @@ dependencies {
modCompileOnly("me.shedaniel:RoughlyEnoughItems-fabric:${rei_version}") {
transitive = false
}
// compile against the JEI API but do not include it at runtime
modCompileOnly("mezz.jei:jei-${minecraft_version}-common:${jei_version}")
modCompileOnly("mezz.jei:jei-${minecraft_version}-gui:${jei_version}")
modCompileOnly("mezz.jei:jei-${minecraft_version}-lib:${jei_version}")
// Remove the next line if you don't want to depend on the API
// modApi "me.shedaniel:architectury:${rootProject.architectury_version}"
}

View File

@ -14,6 +14,9 @@ import net.minecraft.world.entity.Entity;
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
import org.embeddedt.modernfix.searchtree.JEIBackedSearchTree;
import org.embeddedt.modernfix.searchtree.REIBackedSearchTree;
import org.embeddedt.modernfix.searchtree.SearchTreeProviderRegistry;
import org.embeddedt.modernfix.world.IntegratedWatchdog;
import java.lang.management.ManagementFactory;
@ -36,6 +39,8 @@ public class ModernFixClient {
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.branding.F3Screen")) {
brandingString = "ModernFix " + ModernFixPlatformHooks.getVersionString();
}
SearchTreeProviderRegistry.register(JEIBackedSearchTree.PROVIDER);
SearchTreeProviderRegistry.register(REIBackedSearchTree.PROVIDER);
}
public void resetWorldLoadStateMachine() {

View File

@ -0,0 +1,43 @@
package org.embeddedt.modernfix.common.mixin.perf.blast_search_trees;
import net.minecraft.client.Minecraft;
import net.minecraft.client.searchtree.SearchRegistry;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
import org.embeddedt.modernfix.searchtree.DummySearchTree;
import org.embeddedt.modernfix.searchtree.SearchTreeProviderRegistry;
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;
import java.util.List;
import java.util.Map;
@Mixin(Minecraft.class)
@ClientOnlyMixin
public abstract class MinecraftMixin {
@Shadow @Final private SearchRegistry searchRegistry;
@Shadow public abstract <T> void populateSearchTree(SearchRegistry.Key<T> key, List<T> list);
@Inject(method = "createSearchTrees", at = @At("HEAD"), cancellable = true)
private void replaceSearchTrees(CallbackInfo ci) {
SearchTreeProviderRegistry.Provider provider = SearchTreeProviderRegistry.getSearchTreeProvider();
if(provider == null)
return;
ModernFix.LOGGER.info("Replacing search trees with '{}' provider", provider.getName());
SearchRegistry.TreeBuilderSupplier<ItemStack> nameSupplier = list -> provider.getSearchTree(false);
SearchRegistry.TreeBuilderSupplier<ItemStack> tagSupplier = list -> provider.getSearchTree(true);
this.searchRegistry.register(SearchRegistry.CREATIVE_NAMES, nameSupplier);
this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, tagSupplier);
this.searchRegistry.register(SearchRegistry.RECIPE_COLLECTIONS, list -> new DummySearchTree<>());
ModernFixPlatformHooks.registerCreativeSearchTrees(this.searchRegistry, nameSupplier, tagSupplier, this::populateSearchTree);
ci.cancel();
}
}

View File

@ -4,14 +4,15 @@ import net.minecraft.world.level.block.Blocks;
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;
import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(Blocks.class)
import java.util.function.Consumer;
@Mixin(value = Blocks.class, priority = 1100)
public class BlocksMixin {
@Inject(method = "rebuildCache", at = @At("HEAD"), cancellable = true)
private static void rebuildParallel(CallbackInfo ci) {
ci.cancel();
@ModifyArg(method = "rebuildCache", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/IdMapper;forEach(Ljava/util/function/Consumer;)V"), index = 0)
private static Consumer getEmptyConsumer(Consumer original) {
BlockStateCacheHandler.rebuildParallel(true);
return o -> {};
}
}

View File

@ -130,13 +130,8 @@ public class ModernFixEarlyConfig {
}
}
private static final boolean shouldReplaceSearchTrees;
private static final boolean isDevEnv = ModernFixPlatformHooks.isDevEnv();
static {
shouldReplaceSearchTrees = modPresent("jei");
}
private static final ImmutableMap<String, Boolean> DEFAULT_SETTING_OVERRIDES = ImmutableMap.<String, Boolean>builder()
.put("mixin.perf.dynamic_resources", false)
.put("mixin.feature.direct_stack_trace", false)
@ -148,7 +143,6 @@ public class ModernFixEarlyConfig {
.put("mixin.perf.dynamic_entity_renderers", false)
.put("mixin.feature.integrated_server_watchdog", true)
.put("mixin.perf.faster_item_rendering", false)
.put("mixin.perf.blast_search_trees", shouldReplaceSearchTrees)
.put("mixin.devenv", isDevEnv)
.put("mixin.perf.remove_spawn_chunks", isDevEnv)
.build();

View File

@ -2,12 +2,16 @@ package org.embeddedt.modernfix.platform;
import dev.architectury.injectables.annotations.ExpectPlatform;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.client.searchtree.SearchRegistry;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import org.objectweb.asm.tree.ClassNode;
import java.nio.file.Path;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class ModernFixPlatformHooks {
@ -70,4 +74,9 @@ public class ModernFixPlatformHooks {
public static void onServerCommandRegister(Consumer<CommandDispatcher<CommandSourceStack>> handler) {
throw new AssertionError();
}
@ExpectPlatform
public static void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier<ItemStack> nameSupplier, SearchRegistry.TreeBuilderSupplier<ItemStack> tagSupplier, BiConsumer<SearchRegistry.Key<ItemStack>, List<ItemStack>> populator) {
throw new AssertionError();
}
}

View File

@ -1,6 +1,7 @@
package org.embeddedt.modernfix.searchtree;
import net.minecraft.client.searchtree.RefreshableSearchTree;
import net.minecraft.world.item.ItemStack;
import java.util.Collections;
import java.util.List;
@ -22,4 +23,22 @@ public class DummySearchTree<T> implements RefreshableSearchTree<T> {
public List<T> search(String pSearchText) {
return Collections.emptyList();
}
static final SearchTreeProviderRegistry.Provider PROVIDER = new SearchTreeProviderRegistry.Provider() {
@Override
public RefreshableSearchTree<ItemStack> getSearchTree(boolean tag) {
return new DummySearchTree<>();
}
@Override
public boolean canUse() {
return true;
}
@Override
public String getName() {
return "Dummy";
}
};
}

View File

@ -1,15 +1,19 @@
package org.embeddedt.modernfix.forge.searchtree;
package org.embeddedt.modernfix.searchtree;
import com.google.common.collect.ImmutableList;
import mezz.jei.api.ingredients.ITypedIngredient;
import mezz.jei.gui.ingredients.IngredientFilter;
import mezz.jei.gui.ingredients.IngredientFilterApi;
import mezz.jei.library.runtime.JeiRuntime;
import net.minecraft.client.searchtree.RefreshableSearchTree;
import net.minecraft.world.item.ItemStack;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.forge.mixin.perf.blast_search_trees.IngredientFilterInvoker;
import org.embeddedt.modernfix.searchtree.DummySearchTree;
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -23,7 +27,25 @@ public class JEIBackedSearchTree extends DummySearchTree<ItemStack> {
private String lastSearchText = "";
private final List<ItemStack> listCache = new ArrayList<>();
private static Field filterField = null;
private static final Field filterField;
private static final MethodHandle getIngredientListUncached;
static {
MethodHandle m;
Field f;
try {
Method jeiMethod = IngredientFilter.class.getDeclaredMethod("getIngredientListUncached", String.class);
jeiMethod.setAccessible(true);
m = MethodHandles.lookup().unreflect(jeiMethod);
f = IngredientFilterApi.class.getDeclaredField("ingredientFilter");
f.setAccessible(true);
} catch(ReflectiveOperationException | RuntimeException | NoClassDefFoundError e) {
m = null;
f = null;
}
getIngredientListUncached = m;
filterField = f;
}
public JEIBackedSearchTree(boolean filteringByTag) {
this.filteringByTag = filteringByTag;
@ -35,10 +57,6 @@ public class JEIBackedSearchTree extends DummySearchTree<ItemStack> {
IngredientFilterApi iFilterApi = (IngredientFilterApi)runtime.get().getIngredientFilter();
IngredientFilter filter;
try {
if(filterField == null) {
filterField = IngredientFilterApi.class.getDeclaredField("ingredientFilter");
filterField.setAccessible(true);
}
filter = (IngredientFilter)filterField.get(iFilterApi);
} catch(ReflectiveOperationException e) {
ModernFix.LOGGER.error(e);
@ -54,7 +72,14 @@ public class JEIBackedSearchTree extends DummySearchTree<ItemStack> {
private List<ItemStack> searchJEI(IngredientFilter filter, String pSearchText) {
if(!pSearchText.equals(lastSearchText)) {
listCache.clear();
List<ITypedIngredient<?>> ingredients = ((IngredientFilterInvoker)filter).invokeGetIngredientListUncached(filteringByTag ? ("$" + pSearchText) : pSearchText);
List<ITypedIngredient<?>> ingredients;
String finalSearchTerm = filteringByTag ? ("$" + pSearchText) : pSearchText;
try {
ingredients = (List<ITypedIngredient<?>>)getIngredientListUncached.invokeExact(filter, finalSearchTerm);
} catch(Throwable e) {
ModernFix.LOGGER.error("Error searching", e);
ingredients = ImmutableList.of();
}
for(ITypedIngredient<?> ingredient : ingredients) {
if(ingredient.getIngredient() instanceof ItemStack) {
listCache.add((ItemStack)ingredient.getIngredient());
@ -64,4 +89,21 @@ public class JEIBackedSearchTree extends DummySearchTree<ItemStack> {
}
return listCache;
}
public static final SearchTreeProviderRegistry.Provider PROVIDER = new SearchTreeProviderRegistry.Provider() {
@Override
public RefreshableSearchTree<ItemStack> getSearchTree(boolean tag) {
return new JEIBackedSearchTree(tag);
}
@Override
public boolean canUse() {
return ModernFixPlatformHooks.modPresent("jei") && getIngredientListUncached != null && filterField != null;
}
@Override
public String getName() {
return "JEI";
}
};
}

View File

@ -1,4 +1,4 @@
package org.embeddedt.modernfix.forge.searchtree;
package org.embeddedt.modernfix.searchtree;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin;

View File

@ -4,8 +4,10 @@ import me.shedaniel.rei.api.client.registry.entry.EntryRegistry;
import me.shedaniel.rei.api.common.entry.EntryStack;
import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
import me.shedaniel.rei.impl.client.search.AsyncSearchManager;
import net.minecraft.client.searchtree.RefreshableSearchTree;
import net.minecraft.world.item.ItemStack;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
import java.util.ArrayList;
import java.util.Collections;
@ -53,4 +55,21 @@ public class REIBackedSearchTree extends DummySearchTree<ItemStack> {
}
return listCache;
}
public static final SearchTreeProviderRegistry.Provider PROVIDER = new SearchTreeProviderRegistry.Provider() {
@Override
public RefreshableSearchTree<ItemStack> getSearchTree(boolean tag) {
return new REIBackedSearchTree(tag);
}
@Override
public boolean canUse() {
return ModernFixPlatformHooks.modPresent("roughlyenoughitems");
}
@Override
public String getName() {
return "REI";
}
};
}

View File

@ -0,0 +1,36 @@
package org.embeddedt.modernfix.searchtree;
import net.minecraft.client.searchtree.RefreshableSearchTree;
import net.minecraft.world.item.ItemStack;
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
import org.embeddedt.modernfix.core.config.Option;
import java.util.ArrayList;
import java.util.List;
public class SearchTreeProviderRegistry {
private static final List<Provider> searchTreeProviders = new ArrayList<>();
public static synchronized Provider getSearchTreeProvider() {
for(Provider p : searchTreeProviders) {
if(p.canUse())
return p;
}
Option option = ModernFixMixinPlugin.instance.config.getEffectiveOptionForMixin("perf.blast_search_trees.Registry");
if(option != null && option.isOverridden())
return DummySearchTree.PROVIDER;
else
return null;
}
public static synchronized void register(Provider p) {
if(p.canUse())
searchTreeProviders.add(p);
}
public interface Provider {
RefreshableSearchTree<ItemStack> getSearchTree(boolean tag);
boolean canUse();
String getName();
}
}

View File

@ -5,13 +5,17 @@ import net.fabricmc.api.EnvType;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.client.searchtree.SearchRegistry;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import org.embeddedt.modernfix.ModernFixFabric;
import org.objectweb.asm.tree.*;
import java.nio.file.Path;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class ModernFixPlatformHooksImpl {
@ -67,4 +71,8 @@ public class ModernFixPlatformHooksImpl {
public static void onServerCommandRegister(Consumer<CommandDispatcher<CommandSourceStack>> handler) {
CommandRegistrationCallback.EVENT.register((dispatcher, arg, env) -> handler.accept(dispatcher));
}
public static void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier<ItemStack> nameSupplier, SearchRegistry.TreeBuilderSupplier<ItemStack> tagSupplier, BiConsumer<SearchRegistry.Key<ItemStack>, List<ItemStack>> populator) {
/* no-op on Fabric */
}
}

View File

@ -22,7 +22,8 @@
"client": [
"org.embeddedt.modernfix.ModernFixClientFabric"
],
"modmenu": [ "org.embeddedt.modernfix.fabric.modmenu.ModernFixModMenuApiImpl" ]
"modmenu": [ "org.embeddedt.modernfix.fabric.modmenu.ModernFixModMenuApiImpl" ],
"jei_mod_plugin": [ "org.embeddedt.modernfix.searchtree.JEIRuntimeCapturer"]
},
"mixins": [
"modernfix-fabric.mixins.json",

View File

@ -38,11 +38,6 @@ dependencies {
modCompileOnly("curse.maven:refinedstorage-243076:${refined_storage_version}")
// compile against the JEI API but do not include it at runtime
modCompileOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}")
modCompileOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}")
modCompileOnly("curse.maven:jeresources-240630:3951643")
modCompileOnly("me.shedaniel:RoughlyEnoughItems-forge:${rei_version}") { transitive false }
modCompileOnly("dev.latvian.mods:kubejs-forge:${kubejs_version}")

View File

@ -1,6 +1,7 @@
package org.embeddedt.modernfix.forge.mixin.core;
import net.minecraft.server.Bootstrap;
import net.minecraftforge.network.NetworkConstants;
import org.slf4j.Logger;
import org.embeddedt.modernfix.forge.load.ModWorkManagerQueue;
import org.spongepowered.asm.mixin.Final;
@ -23,4 +24,10 @@ public class BootstrapMixin {
ModWorkManagerQueue.replace();
}
}
/* for https://github.com/MinecraftForge/MinecraftForge/issues/9505 */
@Inject(method = "bootStrap", at = @At("RETURN"))
private static void doClassloadHack(CallbackInfo ci) {
NetworkConstants.init();
}
}

View File

@ -1,14 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.blast_search_trees;
import mezz.jei.api.ingredients.ITypedIngredient;
import mezz.jei.gui.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(remap = false)
List<ITypedIngredient<?>> invokeGetIngredientListUncached(String filterText);
}

View File

@ -1,68 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.blast_search_trees;
import net.minecraft.client.Minecraft;
import net.minecraft.client.searchtree.SearchRegistry;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.client.CreativeModeTabSearchRegistry;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.searchtree.DummySearchTree;
import org.embeddedt.modernfix.searchtree.REIBackedSearchTree;
import org.embeddedt.modernfix.forge.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;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Mixin(Minecraft.class)
@ClientOnlyMixin
public abstract class MinecraftMixin {
@Shadow @Final private SearchRegistry searchRegistry;
@Shadow public abstract <T> void populateSearchTree(SearchRegistry.Key<T> arg, List<T> list);
@Inject(method = "createSearchTrees", at = @At("HEAD"), cancellable = true)
private void replaceSearchTrees(CallbackInfo ci) {
ci.cancel();
Optional<? extends ModContainer> jeiContainer = ModList.get().getModContainerById("jei");
SearchRegistry.TreeBuilderSupplier<ItemStack> nameSupplier, tagSupplier;
if(ModList.get().isLoaded("roughlyenoughitems")) {
ModernFix.LOGGER.info("Replaced creative search logic with REI");
nameSupplier = list -> new REIBackedSearchTree(false);
tagSupplier = list -> new REIBackedSearchTree(true);
} else if(jeiContainer.isPresent()) {
ModernFix.LOGGER.info("Replaced creative search logic with JEI");
nameSupplier = list -> new JEIBackedSearchTree(false);
tagSupplier = list -> new JEIBackedSearchTree(true);
} else {
ModernFix.LOGGER.info("Replaced creative search logic with dummy implementation");
nameSupplier = tagSupplier = list -> new DummySearchTree<>();
}
this.searchRegistry.register(SearchRegistry.CREATIVE_NAMES, nameSupplier);
for(SearchRegistry.Key<ItemStack> nameKey : CreativeModeTabSearchRegistry.getNameSearchKeys().values()) {
this.searchRegistry.register(nameKey, nameSupplier);
}
this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, tagSupplier);
for(SearchRegistry.Key<ItemStack> tagKey : CreativeModeTabSearchRegistry.getTagSearchKeys().values()) {
this.searchRegistry.register(tagKey, tagSupplier);
}
Map<CreativeModeTab, SearchRegistry.Key<ItemStack>> tagSearchKeys = CreativeModeTabSearchRegistry.getTagSearchKeys();
CreativeModeTabSearchRegistry.getNameSearchKeys().forEach((tab, nameSearchKey) -> {
SearchRegistry.Key<ItemStack> tagSearchKey = tagSearchKeys.get(tab);
tab.setSearchTreeBuilder((contents) -> {
this.populateSearchTree(nameSearchKey, contents);
this.populateSearchTree(tagSearchKey, contents);
});
});
this.searchRegistry.register(SearchRegistry.RECIPE_COLLECTIONS, list -> new DummySearchTree<>());
}
}

View File

@ -1,10 +1,14 @@
package org.embeddedt.modernfix.platform.forge;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.client.searchtree.SearchRegistry;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.CreativeModeTabSearchRegistry;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.fml.ModLoader;
@ -23,6 +27,9 @@ import org.spongepowered.asm.mixin.injection.struct.InjectorGroupInfo;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class ModernFixPlatformHooksImpl {
@ -92,4 +99,21 @@ public class ModernFixPlatformHooksImpl {
handler.accept(event.getDispatcher());
});
}
public static void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier<ItemStack> nameSupplier, SearchRegistry.TreeBuilderSupplier<ItemStack> tagSupplier, BiConsumer<SearchRegistry.Key<ItemStack>, List<ItemStack>> populator) {
for(SearchRegistry.Key<ItemStack> nameKey : CreativeModeTabSearchRegistry.getNameSearchKeys().values()) {
registry.register(nameKey, nameSupplier);
}
for(SearchRegistry.Key<ItemStack> tagKey : CreativeModeTabSearchRegistry.getTagSearchKeys().values()) {
registry.register(tagKey, tagSupplier);
}
Map<CreativeModeTab, SearchRegistry.Key<ItemStack>> tagSearchKeys = CreativeModeTabSearchRegistry.getTagSearchKeys();
CreativeModeTabSearchRegistry.getNameSearchKeys().forEach((tab, nameSearchKey) -> {
SearchRegistry.Key<ItemStack> tagSearchKey = tagSearchKeys.get(tab);
tab.setSearchTreeBuilder((contents) -> {
populator.accept(nameSearchKey, contents);
populator.accept(tagSearchKey, contents);
});
});
}
}