From d67863d520926562082a33530f4bcdcb5e779d1f Mon Sep 17 00:00:00 2001 From: dhyces <10985914+dhyces@users.noreply.github.com> Date: Thu, 30 May 2024 20:19:18 -0700 Subject: [PATCH 1/5] Use stack hash strategy --- src/main/java/net/neoforged/neoforge/event/EventHooks.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/neoforged/neoforge/event/EventHooks.java b/src/main/java/net/neoforged/neoforge/event/EventHooks.java index 84b4850fa1..67e7937d10 100644 --- a/src/main/java/net/neoforged/neoforge/event/EventHooks.java +++ b/src/main/java/net/neoforged/neoforge/event/EventHooks.java @@ -69,6 +69,7 @@ import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemStackLinkedSet; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.item.crafting.RecipeType; @@ -1035,7 +1036,7 @@ public static ItemEnchantments getEnchantmentLevel(ItemEnchantments enchantments */ @ApiStatus.Internal public static void onCreativeModeTabBuildContents(CreativeModeTab tab, ResourceKey tabKey, CreativeModeTab.DisplayItemsGenerator originalGenerator, CreativeModeTab.ItemDisplayParameters params, CreativeModeTab.Output output) { - final var entries = new MutableHashedLinkedMap(); + final var entries = new MutableHashedLinkedMap(ItemStackLinkedSet.TYPE_AND_TAG); originalGenerator.accept(params, (stack, vis) -> { if (stack.getCount() != 1) From 0b68ab02f668de4173253ca5a7bb8299f18d1a25 Mon Sep 17 00:00:00 2001 From: dhyces <10985914+dhyces@users.noreply.github.com> Date: Thu, 30 May 2024 20:59:19 -0700 Subject: [PATCH 2/5] Add test --- .../neoforge/oldtest/CreativeModeTabTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/CreativeModeTabTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/CreativeModeTabTest.java index fc0acf507e..fde1e4cdd8 100644 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/CreativeModeTabTest.java +++ b/tests/src/main/java/net/neoforged/neoforge/oldtest/CreativeModeTabTest.java @@ -6,6 +6,8 @@ package net.neoforged.neoforge.oldtest; import java.util.List; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; @@ -16,6 +18,7 @@ import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeItem; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -76,6 +79,18 @@ private static void onCreativeModeTabRegister(RegisterEvent event) { .withTabsBefore(CreativeModeTabs.COLORED_BLOCKS) .build()); + helper.register(new ResourceLocation(MOD_ID, "damaged_swords"), CreativeModeTab.builder().title(Component.literal("Damaged Wooden Swords")) + .displayItems((params, output) -> { + output.accept(new ItemStack(Items.WOODEN_SWORD)); + output.accept(new ItemStack(Items.WOODEN_SWORD)); // Should just overwrite the present entry + for (int i = 1; i <= 59; i++) { + // Each should be added since they have different data component values + output.accept(new ItemStack(Items.WOODEN_SWORD.builtInRegistryHolder(), 1, DataComponentPatch.builder().set(DataComponents.DAMAGE, i).build())); + } + }) + .icon(() -> new ItemStack(Items.WOODEN_SWORD)) + .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); From f34a5281727a90337bf5d3c20e615c125e61984b Mon Sep 17 00:00:00 2001 From: dhyces <10985914+dhyces@users.noreply.github.com> Date: Sun, 2 Jun 2024 22:20:23 -0700 Subject: [PATCH 3/5] Write up unit test for creative tab enchantments --- .../unittest/CreativeTabOrderTest.java | 136 ++++++++++++++++++ .../resources/META-INF/neoforge.mods.toml | 3 + 2 files changed, 139 insertions(+) create mode 100644 tests/src/junit/java/net/neoforged/neoforge/unittest/CreativeTabOrderTest.java diff --git a/tests/src/junit/java/net/neoforged/neoforge/unittest/CreativeTabOrderTest.java b/tests/src/junit/java/net/neoforged/neoforge/unittest/CreativeTabOrderTest.java new file mode 100644 index 0000000000..1d146af5fb --- /dev/null +++ b/tests/src/junit/java/net/neoforged/neoforge/unittest/CreativeTabOrderTest.java @@ -0,0 +1,136 @@ +package net.neoforged.neoforge.unittest; + +import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.Registries; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.flag.FeatureFlags; +import net.minecraft.world.item.*; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; +import net.neoforged.testframework.junit.EphemeralTestServerProvider; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.Map; +import java.util.Set; +import java.util.stream.IntStream; + +@ExtendWith(EphemeralTestServerProvider.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class CreativeTabOrderTest { + public static final String MOD_ID = "creative_tab_order_test"; + private static final Set> ENCHANTABLES = Set.of( + ItemTags.FOOT_ARMOR_ENCHANTABLE, + ItemTags.LEG_ARMOR_ENCHANTABLE, + ItemTags.CHEST_ARMOR_ENCHANTABLE, + ItemTags.HEAD_ARMOR_ENCHANTABLE, + ItemTags.ARMOR_ENCHANTABLE, + ItemTags.SWORD_ENCHANTABLE, + ItemTags.SHARP_WEAPON_ENCHANTABLE, + ItemTags.MACE_ENCHANTABLE, + ItemTags.FIRE_ASPECT_ENCHANTABLE, + ItemTags.WEAPON_ENCHANTABLE, + ItemTags.MINING_ENCHANTABLE, + ItemTags.MINING_LOOT_ENCHANTABLE, + ItemTags.FISHING_ENCHANTABLE, + ItemTags.TRIDENT_ENCHANTABLE, + ItemTags.DURABILITY_ENCHANTABLE, + ItemTags.BOW_ENCHANTABLE, + ItemTags.EQUIPPABLE_ENCHANTABLE, + ItemTags.CROSSBOW_ENCHANTABLE, + ItemTags.VANISHING_ENCHANTABLE + ); + public static Iterable> ingredientsTab; + public static Iterable> searchTab; + + @BeforeAll + static void testSetupTabs(MinecraftServer server) { + CreativeModeTabs.tryRebuildTabContents(FeatureFlags.DEFAULT_FLAGS, true, server.registryAccess()); + } + + /** + * The local tabEnchantments variable comes from {@link CreativeModeTabs#generateEnchantmentBookTypesOnlyMaxLevel(CreativeModeTab.Output, HolderLookup, Set, CreativeModeTab.TabVisibility, FeatureFlagSet)} + * @param server Ephemeral server from extension + */ + @Test + void testIngredientsEnchantmentExistence(MinecraftServer server) { + final Set tabEnchantments = server.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).listElements() + .map(Holder::value) + .filter(enchantment -> enchantment.isEnabled(FeatureFlags.DEFAULT_FLAGS)) + .filter(enchantment -> enchantment.allowedInCreativeTab(Items.ENCHANTED_BOOK, ENCHANTABLES)) + .map(enchantment -> EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, enchantment.getMaxLevel()))) + .collect(() -> new ObjectOpenCustomHashSet<>(ItemStackLinkedSet.TYPE_AND_TAG), ObjectOpenCustomHashSet::add, ObjectOpenCustomHashSet::addAll); + for (Map.Entry entry : ingredientsTab) { + if (entry.getValue() == CreativeModeTab.TabVisibility.SEARCH_TAB_ONLY) { + continue; + } + if (entry.getKey().getItem() == Items.ENCHANTED_BOOK) { + Assertions.assertTrue(tabEnchantments.remove(entry.getKey()), "Enchanted book present that does not exist in the default set?"); + } + } + + Assertions.assertTrue(tabEnchantments.isEmpty(), "Missing enchantments in Ingredient tab."); + } + + /** + * The local tabEnchantments variable comes from {@link CreativeModeTabs#generateEnchantmentBookTypesAllLevels(CreativeModeTab.Output, HolderLookup, Set, CreativeModeTab.TabVisibility, FeatureFlagSet)} + * @param server Ephemeral server from extension + */ + @Test + void testSearchEnchantmentOrder(MinecraftServer server) { + final var tabEnchantments = server.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).listElements() + .map(Holder::value) + .filter(enchantment -> enchantment.isEnabled(FeatureFlags.DEFAULT_FLAGS)) + .filter(enchantment -> enchantment.allowedInCreativeTab(Items.ENCHANTED_BOOK, ENCHANTABLES)) + .flatMap( + enchantment -> IntStream.rangeClosed(enchantment.getMinLevel(), enchantment.getMaxLevel()) + .mapToObj(p_270006_ -> EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, p_270006_))) + ).collect(() -> new ObjectOpenCustomHashSet<>(ItemStackLinkedSet.TYPE_AND_TAG), ObjectOpenCustomHashSet::add, ObjectOpenCustomHashSet::addAll); + + Enchantment enchantment = null; + int level = 0; + for (Map.Entry entry : searchTab) { + if (entry.getKey().getItem() != Items.ENCHANTED_BOOK) { + continue; + } + final var enchantmentEntry = entry.getKey().get(DataComponents.STORED_ENCHANTMENTS).entrySet().iterator().next(); + final var entryEnchantment = enchantmentEntry.getKey().value(); + final var entryEnchantmentLevel = enchantmentEntry.getIntValue(); + if (enchantment == null || enchantment != entryEnchantment) { + enchantment = entryEnchantment; + Assertions.assertFalse(entryEnchantmentLevel > enchantment.getMinLevel(), "Enchantment does not start at the minimum level"); + } else { + Assertions.assertTrue(entryEnchantmentLevel > level); + } + Assertions.assertTrue(tabEnchantments.remove(entry.getKey()), "Enchanted book present that does not exist in the default set?"); + level = entryEnchantmentLevel; + } + + Assertions.assertTrue(tabEnchantments.isEmpty(), "Missing enchantments in Search tab."); + } + + @Mod(MOD_ID) + public static class CreativeTabOrderTestMod { + public CreativeTabOrderTestMod(IEventBus modBus) { + modBus.addListener(this::buildCreativeTab); + } + + private void buildCreativeTab(final BuildCreativeModeTabContentsEvent event) { + if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) { + ingredientsTab = event.getEntries(); + } + if (event.getTabKey() == CreativeModeTabs.SEARCH) { + searchTab = event.getEntries(); + } + } + } +} diff --git a/tests/src/main/resources/META-INF/neoforge.mods.toml b/tests/src/main/resources/META-INF/neoforge.mods.toml index 70d23d99cb..17ee28ce6d 100644 --- a/tests/src/main/resources/META-INF/neoforge.mods.toml +++ b/tests/src/main/resources/META-INF/neoforge.mods.toml @@ -37,6 +37,9 @@ license="LGPL v2.1" [[mods]] modId="multiple_entrypoints_test" +[[mods]] + modId="creative_tab_order_test" + [[mods]] modId="ordered_test_1" [[mods]] From cdac02a806f80bbc72fe99b7fb9ebf65930e1d9f Mon Sep 17 00:00:00 2001 From: dhyces <10985914+dhyces@users.noreply.github.com> Date: Sun, 2 Jun 2024 23:52:35 -0700 Subject: [PATCH 4/5] RFC basically Not a big fan of the impl. Honestly would rather just remove the map entirely and use something else --- .../common/util/MutableHashedLinkedMap.java | 35 ++++++++++++++++++- .../neoforged/neoforge/event/EventHooks.java | 21 +++++++++-- .../unittest/CreativeTabOrderTest.java | 35 +++++++++++++------ .../neoforge/oldtest/CreativeModeTabTest.java | 10 ++++-- 4 files changed, 86 insertions(+), 15 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/util/MutableHashedLinkedMap.java b/src/main/java/net/neoforged/neoforge/common/util/MutableHashedLinkedMap.java index dc173df6db..e1386d0ede 100644 --- a/src/main/java/net/neoforged/neoforge/common/util/MutableHashedLinkedMap.java +++ b/src/main/java/net/neoforged/neoforge/common/util/MutableHashedLinkedMap.java @@ -12,6 +12,7 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.function.BiPredicate; import org.jetbrains.annotations.Nullable; /** @@ -34,6 +35,7 @@ public class MutableHashedLinkedMap implements Iterable> { private final Strategy strategy; private final Map entries; private final MergeFunction merge; + private final BiPredicate insertTest; private Entry head = null; private Entry last = null; /* @@ -58,16 +60,38 @@ public MutableHashedLinkedMap(Strategy strategy) { this(strategy, (k, v1, v2) -> v2); } + /** + * Creates a mutable linked map with a default new-value-selecting merge function. + * + * @param strategy the hashing strategy + * @param merge the function used when merging an existing value and a new value + */ + public MutableHashedLinkedMap(Strategy strategy, MergeFunction merge) { + this(strategy, merge, (k, v) -> true); + } + + /** + * Creates a mutable linked map with a default new-value-selecting merge function. + * + * @param strategy the hashing strategy + * @param insertTest the test to apply before inserting a key and value + */ + public MutableHashedLinkedMap(Strategy strategy, BiPredicate insertTest) { + this(strategy, (k, v1, v2) -> v2, insertTest); + } + /** * Creates a mutable linked map with a custom merge function. * * @param strategy the hashing strategy * @param merge the function used when merging an existing value and a new value + * @param insertTest the test to apply before inserting a key and value */ - public MutableHashedLinkedMap(Strategy strategy, MergeFunction merge) { + public MutableHashedLinkedMap(Strategy strategy, MergeFunction merge, BiPredicate insertTest) { this.strategy = strategy; this.entries = new Object2ObjectOpenCustomHashMap<>(strategy); this.merge = merge; + this.insertTest = insertTest; } /** @@ -84,6 +108,9 @@ public MutableHashedLinkedMap(Strategy strategy, MergeFunction @Nullable public V put(K key, V value) { var old = entries.get(key); + if (!insertTest.test(key, value)) { + return old == null ? null : old.value; + } if (old != null) { V ret = old.value; old.value = merge.apply(key, ret, value); @@ -215,6 +242,9 @@ public V putAfter(K after, K key, V value) { V ret = null; var entry = entries.get(key); + if (!insertTest.test(key, value)) { + return entry == null ? null : entry.value; + } if (entry != null) { ret = entry.value; entry.value = merge.apply(key, ret, value); @@ -260,6 +290,9 @@ public V putBefore(K before, K key, V value) { V ret = null; var entry = entries.get(key); + if (!insertTest.test(key, value)) { + return entry == null ? null : entry.value; + } if (entry != null) { ret = entry.value; entry.value = merge.apply(key, ret, value); diff --git a/src/main/java/net/neoforged/neoforge/event/EventHooks.java b/src/main/java/net/neoforged/neoforge/event/EventHooks.java index 67e7937d10..65825294fd 100644 --- a/src/main/java/net/neoforged/neoforge/event/EventHooks.java +++ b/src/main/java/net/neoforged/neoforge/event/EventHooks.java @@ -8,6 +8,7 @@ import com.mojang.authlib.GameProfile; import com.mojang.brigadier.CommandDispatcher; import com.mojang.datafixers.util.Either; +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenCustomHashSet; import java.io.File; import java.util.EnumSet; import java.util.List; @@ -1036,14 +1037,30 @@ public static ItemEnchantments getEnchantmentLevel(ItemEnchantments enchantments */ @ApiStatus.Internal public static void onCreativeModeTabBuildContents(CreativeModeTab tab, ResourceKey tabKey, CreativeModeTab.DisplayItemsGenerator originalGenerator, CreativeModeTab.ItemDisplayParameters params, CreativeModeTab.Output output) { - final var entries = new MutableHashedLinkedMap(ItemStackLinkedSet.TYPE_AND_TAG); + final var searchDupes = new ObjectLinkedOpenCustomHashSet(ItemStackLinkedSet.TYPE_AND_TAG); + // The ItemStackLinkedSet.TYPE_AND_TAG strategy cannot be used for the MutableHashedLinkedMap due to vanilla + // adding multiple identical ItemStacks with different TabVisibility values. The values also cannot be merged + // because it does not abide by the intended order. For example, vanilla adds all max enchanted books to the + // "ingredient" tab with "parent only" visibility, then also adds all enchanted books again in increasing order + // to their max values but with the "search only" visibility. Because the parent-only is added first and then + // the search-only entries are added after, the max enchantments would show up first and then the enchantments + // in increasing order up to max-1. + final var entries = new MutableHashedLinkedMap(MutableHashedLinkedMap.BASIC, (stack, tabVisibility) -> { + if (!searchDupes.add(stack) && tabVisibility != CreativeModeTab.TabVisibility.SEARCH_TAB_ONLY) { + throw new IllegalStateException( + "Accidentally adding the same item stack twice " + + stack.getDisplayName().getString() + + " to a Creative Mode Tab: " + + tab.getDisplayName().getString()); + } + return true; + }); originalGenerator.accept(params, (stack, vis) -> { if (stack.getCount() != 1) throw new IllegalArgumentException("The stack count must be 1"); entries.put(stack, vis); }); - ModLoader.postEvent(new BuildCreativeModeTabContentsEvent(tab, tabKey, params, entries)); for (var entry : entries) diff --git a/tests/src/junit/java/net/neoforged/neoforge/unittest/CreativeTabOrderTest.java b/tests/src/junit/java/net/neoforged/neoforge/unittest/CreativeTabOrderTest.java index 1d146af5fb..db5ed3cd94 100644 --- a/tests/src/junit/java/net/neoforged/neoforge/unittest/CreativeTabOrderTest.java +++ b/tests/src/junit/java/net/neoforged/neoforge/unittest/CreativeTabOrderTest.java @@ -1,6 +1,14 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + package net.neoforged.neoforge.unittest; import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.IntStream; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponents; @@ -10,20 +18,26 @@ import net.minecraft.tags.TagKey; import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.flag.FeatureFlags; -import net.minecraft.world.item.*; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.CreativeModeTabs; +import net.minecraft.world.item.EnchantedBookItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemStackLinkedSet; +import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.EnchantmentInstance; import net.neoforged.bus.api.IEventBus; import net.neoforged.fml.common.Mod; import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; import net.neoforged.testframework.junit.EphemeralTestServerProvider; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import java.util.Map; -import java.util.Set; -import java.util.stream.IntStream; - @ExtendWith(EphemeralTestServerProvider.class) @TestMethodOrder(MethodOrderer.MethodName.class) public class CreativeTabOrderTest { @@ -47,8 +61,7 @@ public class CreativeTabOrderTest { ItemTags.BOW_ENCHANTABLE, ItemTags.EQUIPPABLE_ENCHANTABLE, ItemTags.CROSSBOW_ENCHANTABLE, - ItemTags.VANISHING_ENCHANTABLE - ); + ItemTags.VANISHING_ENCHANTABLE); public static Iterable> ingredientsTab; public static Iterable> searchTab; @@ -59,6 +72,7 @@ static void testSetupTabs(MinecraftServer server) { /** * The local tabEnchantments variable comes from {@link CreativeModeTabs#generateEnchantmentBookTypesOnlyMaxLevel(CreativeModeTab.Output, HolderLookup, Set, CreativeModeTab.TabVisibility, FeatureFlagSet)} + * * @param server Ephemeral server from extension */ @Test @@ -83,6 +97,7 @@ void testIngredientsEnchantmentExistence(MinecraftServer server) { /** * The local tabEnchantments variable comes from {@link CreativeModeTabs#generateEnchantmentBookTypesAllLevels(CreativeModeTab.Output, HolderLookup, Set, CreativeModeTab.TabVisibility, FeatureFlagSet)} + * * @param server Ephemeral server from extension */ @Test @@ -93,8 +108,8 @@ void testSearchEnchantmentOrder(MinecraftServer server) { .filter(enchantment -> enchantment.allowedInCreativeTab(Items.ENCHANTED_BOOK, ENCHANTABLES)) .flatMap( enchantment -> IntStream.rangeClosed(enchantment.getMinLevel(), enchantment.getMaxLevel()) - .mapToObj(p_270006_ -> EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, p_270006_))) - ).collect(() -> new ObjectOpenCustomHashSet<>(ItemStackLinkedSet.TYPE_AND_TAG), ObjectOpenCustomHashSet::add, ObjectOpenCustomHashSet::addAll); + .mapToObj(p_270006_ -> EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, p_270006_)))) + .collect(() -> new ObjectOpenCustomHashSet<>(ItemStackLinkedSet.TYPE_AND_TAG), ObjectOpenCustomHashSet::add, ObjectOpenCustomHashSet::addAll); Enchantment enchantment = null; int level = 0; diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/CreativeModeTabTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/CreativeModeTabTest.java index fde1e4cdd8..efd70f4790 100644 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/CreativeModeTabTest.java +++ b/tests/src/main/java/net/neoforged/neoforge/oldtest/CreativeModeTabTest.java @@ -34,6 +34,7 @@ public class CreativeModeTabTest { private static final ResourceKey LOGS = ResourceKey.create(Registries.CREATIVE_MODE_TAB, new ResourceLocation(MOD_ID, "logs")); private static final ResourceKey STONE = ResourceKey.create(Registries.CREATIVE_MODE_TAB, new ResourceLocation(MOD_ID, "stone")); + private static final ResourceKey DAMAGED_SWORDS = ResourceKey.create(Registries.CREATIVE_MODE_TAB, new ResourceLocation(MOD_ID, "damaged_swords")); public CreativeModeTabTest(IEventBus modEventBus) { if (!ENABLED) @@ -79,10 +80,10 @@ private static void onCreativeModeTabRegister(RegisterEvent event) { .withTabsBefore(CreativeModeTabs.COLORED_BLOCKS) .build()); - helper.register(new ResourceLocation(MOD_ID, "damaged_swords"), CreativeModeTab.builder().title(Component.literal("Damaged Wooden Swords")) + helper.register(DAMAGED_SWORDS, CreativeModeTab.builder().title(Component.literal("Damaged Wooden Swords")) .displayItems((params, output) -> { output.accept(new ItemStack(Items.WOODEN_SWORD)); - output.accept(new ItemStack(Items.WOODEN_SWORD)); // Should just overwrite the present entry + output.accept(new ItemStack(Items.WOODEN_SWORD), TabVisibility.SEARCH_TAB_ONLY); // Should still be added for (int i = 1; i <= 59; i++) { // Each should be added since they have different data component values output.accept(new ItemStack(Items.WOODEN_SWORD.builtInRegistryHolder(), 1, DataComponentPatch.builder().set(DataComponents.DAMAGE, i).build())); @@ -133,6 +134,11 @@ private static void onCreativeModeTabBuildContents(BuildCreativeModeTabContentsE entries.putBefore(i(Blocks.DIORITE), i(Blocks.POLISHED_DIORITE), vis); entries.putBefore(i(Blocks.ANDESITE), i(Blocks.POLISHED_ANDESITE), vis); } + + // Adding this causes a crash (as it should) when opening the creative inventory +// if (event.getTabKey() == DAMAGED_SWORDS) { +// entries.putBefore(i(Items.WOODEN_SWORD), i(Items.WOODEN_SWORD), vis); +// } } private static class CreativeModeColorTab extends CreativeModeTab { From 07d8083f01dbd1a5c742a927ce93038fc19d1895 Mon Sep 17 00:00:00 2001 From: dhyces <10985914+dhyces@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:04:16 -0700 Subject: [PATCH 5/5] Apply formatting to jdocs --- .../neoforge/common/util/MutableHashedLinkedMap.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/util/MutableHashedLinkedMap.java b/src/main/java/net/neoforged/neoforge/common/util/MutableHashedLinkedMap.java index e1386d0ede..da2026b48d 100644 --- a/src/main/java/net/neoforged/neoforge/common/util/MutableHashedLinkedMap.java +++ b/src/main/java/net/neoforged/neoforge/common/util/MutableHashedLinkedMap.java @@ -64,7 +64,7 @@ public MutableHashedLinkedMap(Strategy strategy) { * Creates a mutable linked map with a default new-value-selecting merge function. * * @param strategy the hashing strategy - * @param merge the function used when merging an existing value and a new value + * @param merge the function used when merging an existing value and a new value */ public MutableHashedLinkedMap(Strategy strategy, MergeFunction merge) { this(strategy, merge, (k, v) -> true); @@ -73,7 +73,7 @@ public MutableHashedLinkedMap(Strategy strategy, MergeFunction /** * Creates a mutable linked map with a default new-value-selecting merge function. * - * @param strategy the hashing strategy + * @param strategy the hashing strategy * @param insertTest the test to apply before inserting a key and value */ public MutableHashedLinkedMap(Strategy strategy, BiPredicate insertTest) { @@ -83,8 +83,8 @@ public MutableHashedLinkedMap(Strategy strategy, BiPredicate in /** * Creates a mutable linked map with a custom merge function. * - * @param strategy the hashing strategy - * @param merge the function used when merging an existing value and a new value + * @param strategy the hashing strategy + * @param merge the function used when merging an existing value and a new value * @param insertTest the test to apply before inserting a key and value */ public MutableHashedLinkedMap(Strategy strategy, MergeFunction merge, BiPredicate insertTest) {