From ccbc697bad9b689fbb44cb1de090a0650c8925bc Mon Sep 17 00:00:00 2001 From: Sara Freimer Date: Wed, 5 Jul 2023 08:55:13 -0500 Subject: [PATCH] Add unordered creative tabs after vanilla and perform a second level sorting of tabs by registry name to ensure tabs are ordered the same between game restarts (#9612) --- .../common/CreativeModeTabRegistry.java | 56 +++++++++++-------- .../debug/CreativeModeTabTest.java | 14 +++++ 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/main/java/net/minecraftforge/common/CreativeModeTabRegistry.java b/src/main/java/net/minecraftforge/common/CreativeModeTabRegistry.java index d7f2000f6c..b08b72f38d 100644 --- a/src/main/java/net/minecraftforge/common/CreativeModeTabRegistry.java +++ b/src/main/java/net/minecraftforge/common/CreativeModeTabRegistry.java @@ -17,6 +17,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import java.util.Comparator; import net.minecraft.core.Holder; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; @@ -172,7 +173,9 @@ public final class CreativeModeTabRegistry if (keyC != null && valueC != null) graph.putEdge(keyC, valueC); }); - List tierList = TopologicalSort.topologicalSort(graph, null); + //Note: We can ignore the null warning as we validate getting tabs by key before adding to the graph + // so the graph should only contain tabs that we know have names in the registry + List tierList = TopologicalSort.topologicalSort(graph, Comparator.comparing(tab -> getName(tab))); setCreativeModeTabOrder(tierList); } @@ -207,41 +210,37 @@ public final class CreativeModeTabRegistry final List> indexed = new ArrayList<>(); BuiltInRegistries.CREATIVE_MODE_TAB.holders().filter(c -> !DEFAULT_TABS.contains(c.get())).forEach(indexed::add); - for (int i = 0; i < 10; i++) // Vanilla ordering + int vanillaTabs = 10; + + for (int i = 0; i < vanillaTabs; i++) // Vanilla ordering { final Holder value = indexed.get(i); final CreativeModeTab tab = value.get(); final ResourceLocation name = value.unwrapKey().orElseThrow().location(); - final boolean specifiesOrder = !tab.tabsBefore.isEmpty() || !tab.tabsAfter.isEmpty(); - for (final ResourceLocation after : tab.tabsAfter.isEmpty() ? (i + 1 == indexed.size() || specifiesOrder ? - List.of() : List.of(indexed.get(i + 1).unwrapKey().orElseThrow().location())) : tab.tabsAfter) + if (!tab.tabsBefore.isEmpty() || !tab.tabsAfter.isEmpty()) + addTabOrder(tab, name); + else { - edges.put(name, after); - } - - for (final ResourceLocation before : tab.tabsBefore.isEmpty() ? (i == 0 || specifiesOrder ? - List.of() : List.of(indexed.get(i - 1).unwrapKey().orElseThrow().location())) : tab.tabsBefore) - { - edges.put(before, name); + // If there is no order specified ensure vanilla ordering by specifying the previous and next indexed tab as edges + if (i != 0) + edges.put(indexed.get(i - 1).unwrapKey().orElseThrow().location(), name); + if (i + 1 < indexed.size()) + edges.put(name, indexed.get(i + 1).unwrapKey().orElseThrow().location()); } } - for (int i = 10; i < indexed.size(); i++) + ResourceLocation lastVanilla = indexed.get(vanillaTabs - 1).unwrapKey().orElseThrow().location(); + for (int i = vanillaTabs; i < indexed.size(); i++) { final Holder value = indexed.get(i); final CreativeModeTab tab = value.get(); final ResourceLocation name = value.unwrapKey().orElseThrow().location(); - for (final ResourceLocation after : tab.tabsAfter) - { - edges.put(name, after); - } - - for (final ResourceLocation before : tab.tabsBefore) - { - edges.put(before, name); - } + if (!tab.tabsBefore.isEmpty() || !tab.tabsAfter.isEmpty()) + addTabOrder(tab, name); + else // if there is no order specified ensure the tab comes after the last vanilla tab + edges.put(lastVanilla, name); } recalculateItemCreativeModeTabs(); @@ -250,4 +249,17 @@ public final class CreativeModeTabRegistry CreativeModeTabSearchRegistry.createSearchTrees(); } + private static void addTabOrder(CreativeModeTab tab, ResourceLocation name) + { + for (final ResourceLocation after : tab.tabsAfter) + { + edges.put(name, after); + } + + for (final ResourceLocation before : tab.tabsBefore) + { + edges.put(before, name); + } + } + } diff --git a/src/test/java/net/minecraftforge/debug/CreativeModeTabTest.java b/src/test/java/net/minecraftforge/debug/CreativeModeTabTest.java index f0ccef97d4..cda5ab6522 100644 --- a/src/test/java/net/minecraftforge/debug/CreativeModeTabTest.java +++ b/src/test/java/net/minecraftforge/debug/CreativeModeTabTest.java @@ -5,6 +5,7 @@ package net.minecraftforge.debug; +import java.util.List; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; @@ -16,6 +17,7 @@ import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; import net.minecraftforge.eventbus.api.IEventBus; @@ -82,6 +84,18 @@ public class CreativeModeTabTest .withTabsBefore(CreativeModeTabs.COLORED_BLOCKS) .build() ); + + List blocks = List.of(Blocks.GRANITE, Blocks.DIORITE, Blocks.ANDESITE, Blocks.COBBLESTONE); + for (int i = 0; i < blocks.size(); i++) + { + Block block = blocks.get(i); + helper.register(new ResourceLocation(MOD_ID, "dummy" + i), CreativeModeTab.builder() + .title(Component.literal("Dummy " + i)) + .icon(() -> new ItemStack(block)) + .displayItems((params, output) -> output.accept(block)) + .build() + ); + } }); }