mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-12 08:17:35 +00:00
Redesign CreativeTab collection event to be a lot more straight forward. (#9198)
This commit is contained in:
1 parent
4cf5508e04
commit
ec3abdea14
41 files changed
+696
-512
No files matched your search
@@ -6,10 +6,6 @@
|
||||
package net.minecraftforge.client;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.graph.ElementOrder;
|
||||
import com.google.common.graph.GraphBuilder;
|
||||
import com.google.common.graph.MutableGraph;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.blaze3d.platform.Window;
|
||||
import com.mojang.blaze3d.shaders.FogShape;
|
||||
@@ -74,7 +70,6 @@ import net.minecraft.client.sounds.SoundEngine;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.locale.Language;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.chat.ChatType;
|
||||
import net.minecraft.network.chat.CommonComponents;
|
||||
@@ -94,9 +89,11 @@ import net.minecraft.world.entity.HumanoidArm;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
import net.minecraft.world.inventory.tooltip.TooltipComponent;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.ItemStackLinkedSet;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.GameType;
|
||||
@@ -144,7 +141,7 @@ import net.minecraftforge.client.textures.ForgeTextureMetadata;
|
||||
import net.minecraftforge.common.ForgeI18n;
|
||||
import net.minecraftforge.common.ForgeMod;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.util.ItemStackMap;
|
||||
import net.minecraftforge.common.util.MutableHashedLinkedMap;
|
||||
import net.minecraftforge.event.CreativeModeTabEvent;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
@@ -153,8 +150,6 @@ import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.fml.ModLoader;
|
||||
import net.minecraftforge.fml.VersionChecker;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.loading.toposort.CyclePresentException;
|
||||
import net.minecraftforge.fml.loading.toposort.TopologicalSort;
|
||||
import net.minecraftforge.network.NetworkConstants;
|
||||
import net.minecraftforge.network.NetworkRegistry;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
@@ -176,7 +171,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -1189,106 +1183,26 @@ public class ForgeHooksClient
|
||||
return new ResourceLocation(loc.getNamespace(), normalised);
|
||||
}
|
||||
|
||||
public static CreativeModeTab.DisplayItemsGenerator onCreativeModeTabBuildContents(CreativeModeTab tab, CreativeModeTab.DisplayItemsGenerator originalGenerator) {
|
||||
Set<CreativeModeTabEvent.DisplayItemsAdapter> customGenerators = new HashSet<>();
|
||||
CreativeModeTabEvent.BuildContents event = ModLoader.get().postEventWithReturn(new net.minecraftforge.event.CreativeModeTabEvent.BuildContents(tab, customGenerators));
|
||||
|
||||
record ModificationEntry(CreativeModeTab.TabVisibility tabVisibility, ItemStack before, ItemStack after) {}
|
||||
|
||||
return (featureFlagSet, output, hasPermissions) -> {
|
||||
final Map<ItemStack, CreativeModeTab.TabVisibility> originalEntries = ItemStackMap.createTypeAndTagLinkedMap();
|
||||
final Map<ItemStack, ModificationEntry> entries = ItemStackMap.createTypeAndTagMap();
|
||||
|
||||
originalGenerator.accept(featureFlagSet, originalEntries::put, hasPermissions);
|
||||
customGenerators.forEach(generator -> generator.accept(featureFlagSet, (stack, visibility, before, after) -> {
|
||||
if (stack.getCount() != 1)
|
||||
throw new IllegalArgumentException("The stack count must be 1");
|
||||
|
||||
entries.put(stack, new ModificationEntry(visibility, before, after));
|
||||
}, hasPermissions));
|
||||
|
||||
// We switch to the stacks tag here, as we need to be able to compare and hash them for the graph!
|
||||
// We could not handle this with an open hashset since the builder does not support this internally.
|
||||
final MutableGraph<CompoundTag> graph = GraphBuilder.directed().nodeOrder(ElementOrder.insertion()).build();
|
||||
final Map<CompoundTag, ItemStack> tagToStack = Maps.newHashMap();
|
||||
|
||||
CompoundTag lastStackTag = null;
|
||||
for (ItemStack stack : originalEntries.keySet())
|
||||
{
|
||||
final CompoundTag tag = stack.serializeNBT();
|
||||
tagToStack.put(tag, stack);
|
||||
if (!stack.isEmpty())
|
||||
{
|
||||
graph.addNode(tag);
|
||||
}
|
||||
if (lastStackTag != null)
|
||||
{
|
||||
graph.putEdge(lastStackTag, tag);
|
||||
}
|
||||
lastStackTag = tag;
|
||||
public static void onCreativeModeTabBuildContents(CreativeModeTab tab, CreativeModeTab.DisplayItemsGenerator originalGenerator, FeatureFlagSet flags, CreativeModeTab.Output output, boolean hasPermisions)
|
||||
{
|
||||
final var entries = new MutableHashedLinkedMap<ItemStack, CreativeModeTab.TabVisibility>(ItemStackLinkedSet.TYPE_AND_TAG,
|
||||
(key, left, right) -> {
|
||||
//throw new IllegalStateException("Accidentally adding the same item stack twice " + key.getDisplayName().getString() + " to a Creative Mode Tab: " + tab.getDisplayName().getString());
|
||||
// Vanilla adds enchanting books twice in both visibilities.
|
||||
// This is just code cleanliness for them. For us lets just increase the visibility and merge the entries.
|
||||
return CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS;
|
||||
}
|
||||
);
|
||||
|
||||
CompoundTag finalLastStackTag = lastStackTag;
|
||||
entries.forEach((stack, modificationEntry) -> {
|
||||
final CompoundTag tag = stack.serializeNBT();
|
||||
if (!stack.isEmpty())
|
||||
{
|
||||
graph.addNode(tag);
|
||||
tagToStack.put(tag, stack);
|
||||
}
|
||||
if (!modificationEntry.after.isEmpty())
|
||||
{
|
||||
final CompoundTag afterTag = modificationEntry.after.serializeNBT();
|
||||
graph.putEdge(afterTag, tag);
|
||||
tagToStack.put(afterTag, modificationEntry.after);
|
||||
}
|
||||
else if (finalLastStackTag != null)
|
||||
{
|
||||
// If the user does not specify an after, we assume it is the last stack and put it after that.
|
||||
graph.putEdge(finalLastStackTag, tag);
|
||||
}
|
||||
if (!modificationEntry.before.isEmpty())
|
||||
{
|
||||
final CompoundTag beforeTag = modificationEntry.before.serializeNBT();
|
||||
graph.putEdge(tag, beforeTag);
|
||||
tagToStack.put(beforeTag, modificationEntry.before);
|
||||
}
|
||||
});
|
||||
originalGenerator.accept(flags, (stack, vis) -> {
|
||||
if (stack.getCount() != 1)
|
||||
throw new IllegalArgumentException("The stack count must be 1");
|
||||
entries.put(stack, vis);
|
||||
}, hasPermisions);
|
||||
|
||||
try
|
||||
{
|
||||
List<CompoundTag> tierList = TopologicalSort.topologicalSort(graph, null);
|
||||
ModLoader.get().postEvent(new CreativeModeTabEvent.BuildContents(tab, flags, hasPermisions, entries));
|
||||
|
||||
// Now we unwind the tags again so that they are sorted neatly.
|
||||
for (CompoundTag tag : tierList)
|
||||
{
|
||||
final ItemStack stack = tagToStack.get(tag);
|
||||
if (originalEntries.containsKey(stack))
|
||||
{
|
||||
output.accept(stack, originalEntries.get(stack));
|
||||
}
|
||||
else if (entries.containsKey(stack))
|
||||
{
|
||||
output.accept(stack, entries.get(stack).tabVisibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (CyclePresentException cyclePresentException)
|
||||
{
|
||||
LOGGER.error("Failed to inject custom items into creative mode tab {} due to a cycle in the dependency graph", tab, cyclePresentException);
|
||||
LOGGER.warn("Detected cycles:");
|
||||
for (Set<Object> cycle : cyclePresentException.getCycles())
|
||||
{
|
||||
graph.edges().forEach(edge -> {
|
||||
if (cycle.contains(edge.nodeU()) && cycle.contains(edge.nodeV()))
|
||||
{
|
||||
LOGGER.warn(" - {} -> {}", tagToStack.get(edge.nodeU()), tagToStack.get(edge.nodeV()));
|
||||
}
|
||||
});
|
||||
}
|
||||
LOGGER.error("Falling back to default!");
|
||||
originalGenerator.accept(featureFlagSet, output, hasPermissions);
|
||||
}
|
||||
};
|
||||
for (var entry : entries)
|
||||
output.accept(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import it.unimi.dsi.fastutil.Hash.Strategy;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
|
||||
|
||||
/**
|
||||
* A mutable linked map with a hashing strategy and a merge function.
|
||||
*
|
||||
* @param <K> the type of keys
|
||||
* @param <V> the type of mapped values
|
||||
*/
|
||||
public class MutableHashedLinkedMap<K, V> implements Iterable<Map.Entry<K, V>>
|
||||
{
|
||||
private final Strategy<? super K> strategy;
|
||||
private final Map<K, Entry> entries;
|
||||
private final MergeFunction<K, V> merge;
|
||||
private Entry head = null;
|
||||
private Entry last = null;
|
||||
|
||||
/**
|
||||
* Creates a mutable linked map with a default new-value-selecting merge function.
|
||||
*
|
||||
* @param strategy the hashing strategy
|
||||
*/
|
||||
public MutableHashedLinkedMap(Strategy<? super K> strategy)
|
||||
{
|
||||
this(strategy, (k, v1, v2) -> v2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public MutableHashedLinkedMap(Strategy<? super K> strategy, MergeFunction<K, V> merge)
|
||||
{
|
||||
this.strategy = strategy;
|
||||
this.entries = new Object2ObjectOpenCustomHashMap<>(strategy);
|
||||
this.merge = merge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the mapping with the specified key and value pair.
|
||||
*
|
||||
* <p>If there is a mapping already associated with this key, then the previous value and the specified (new) value
|
||||
* are merged according to this collection's merge function, and the position of the entry is not modified. If there
|
||||
* is no such mapping, then the key-value mapping is inserted at the end of this collection.</p>
|
||||
*
|
||||
* @param key key to be inserted
|
||||
* @param value (new) value to be associated with the key
|
||||
* @return the previous value associated with the specified key, or {@code null} if there was no mapping for the key
|
||||
*/
|
||||
@Nullable
|
||||
public V put(K key, V value)
|
||||
{
|
||||
var old = entries.get(key);
|
||||
if (old != null)
|
||||
{
|
||||
V ret = old.value;
|
||||
old.value = merge.apply(key, ret, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
var self = new Entry(key, value);
|
||||
|
||||
var l = last;
|
||||
self.previous = l;
|
||||
if (l == null)
|
||||
head = self;
|
||||
else
|
||||
l.next = self;
|
||||
last = self;
|
||||
|
||||
entries.put(key, self);
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean contains(K key) { return this.entries.containsKey(key); }
|
||||
public boolean isEmpty() { return this.entries.isEmpty(); }
|
||||
|
||||
@Nullable
|
||||
public V remove(K key)
|
||||
{
|
||||
var ret = this.entries.remove(key);
|
||||
if (ret == null)
|
||||
return null;
|
||||
|
||||
remove(ret);
|
||||
return ret.getValue();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public V get(K key)
|
||||
{
|
||||
var entry = entries.get(key);
|
||||
return entry == null ? null : entry.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<K, V>> iterator()
|
||||
{
|
||||
return new Iterator<>()
|
||||
{
|
||||
private Entry current = head;
|
||||
@Override public boolean hasNext() { return current != null; }
|
||||
@Override
|
||||
public Map.Entry<K, V> next()
|
||||
{
|
||||
if (!hasNext())
|
||||
throw new NoSuchElementException();
|
||||
var ret = current;
|
||||
current = current.next;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the mapping with the specified key and value pair at the beginning of this map.
|
||||
*
|
||||
* <p>If there is a mapping already associated with this key, then the previous value and the specified (new) value
|
||||
* are first merged according to this map's merge function, then the entry is moved to the beginning of the map.</p>
|
||||
*
|
||||
* @param key key to be inserted at the beginning
|
||||
* @param value (new) value to be associated with the key
|
||||
* @return the previous value associated with the specified key, or {@code null} if there was no mapping for the key
|
||||
*
|
||||
* @see #putBefore(Object, Object, Object)
|
||||
*/
|
||||
@Nullable
|
||||
public V putFirst(K key, V value)
|
||||
{
|
||||
if (head != null)
|
||||
return putBefore(head.getKey(), key, value);
|
||||
return put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the mapping with this key and value pair immediately after the entry with the specified positioning key.
|
||||
*
|
||||
* <p>If the specified positioning key is not present within this map, then this method behaves like
|
||||
* {@link #put(Object, Object)}. If there is a mapping already associated with this key, then the previous value
|
||||
* and the specified (new) value are first merged according to this map's merge function, then the entry is
|
||||
* moved to directly after the entry with the specified positioning key.</p>
|
||||
*
|
||||
* @param after the key to position this new entry afterwards
|
||||
* @param key key to be inserted at the beginning
|
||||
* @param value (new) value to be associated with the key
|
||||
* @return the previous value associated with the specified key, or {@code null} if there was no mapping for the key
|
||||
*
|
||||
* @see #putBefore(Object, Object, Object)
|
||||
*/
|
||||
@Nullable
|
||||
public V putAfter(K after, K key, V value)
|
||||
{
|
||||
var target = entries.get(after);
|
||||
if (target == null)
|
||||
return put(key, value);
|
||||
|
||||
V ret = null;
|
||||
var entry = entries.get(key);
|
||||
if (entry != null)
|
||||
{
|
||||
ret = entry.value;
|
||||
entry.value = merge.apply(key, ret, value);
|
||||
remove(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = new Entry(key, value);
|
||||
entries.put(key, entry);
|
||||
}
|
||||
|
||||
entry.previous = target;
|
||||
if (target.next == null)
|
||||
last = target;
|
||||
else
|
||||
target.next.previous = entry;
|
||||
entry.next = target.next;
|
||||
|
||||
target.next = entry;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the mapping with this key and value pair immediately before the entry with the specified positioning key.
|
||||
*
|
||||
* <p>If the specified positioning key is not present within this map, then this method behaves like
|
||||
* {@link #put(Object, Object)}. If there is a mapping already associated with this key, then the previous value
|
||||
* and the specified (new) value are first merged according to this map's merge function, then the entry is
|
||||
* moved to directly before the entry with the specified positioning key.</p>
|
||||
*
|
||||
* @param before the key to position this new entry afterwards
|
||||
* @param key key to be inserted at the beginning
|
||||
* @param value (new) value to be associated with the key
|
||||
* @return the previous value associated with the specified key, or {@code null} if there was no mapping for the key
|
||||
*
|
||||
* @see #putAfter(Object, Object, Object)
|
||||
*/
|
||||
@Nullable
|
||||
public V putBefore(K before, K key, V value)
|
||||
{
|
||||
var target = entries.get(before);
|
||||
if (target == null)
|
||||
return put(key, value);
|
||||
|
||||
V ret = null;
|
||||
var entry = entries.get(key);
|
||||
if (entry != null)
|
||||
{
|
||||
ret = entry.value;
|
||||
entry.value = merge.apply(key, ret, value);
|
||||
remove(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = new Entry(key, value);
|
||||
entries.put(key, entry);
|
||||
}
|
||||
|
||||
entry.previous = target.previous;
|
||||
if (target.previous == null)
|
||||
head = entry;
|
||||
else
|
||||
target.previous.next = entry;
|
||||
entry.next = target;
|
||||
|
||||
target.previous = entry;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void remove(Entry e)
|
||||
{
|
||||
if (head == null)
|
||||
head = e.next;
|
||||
else if (e.previous != null) // Should never be null, but just in case.
|
||||
{
|
||||
e.previous.next = e.next;
|
||||
e.previous = null;
|
||||
}
|
||||
|
||||
if (last == e)
|
||||
last = e.previous;
|
||||
else if (e.next != null) // Should never be null, but just in case.
|
||||
{
|
||||
e.next.previous = e.previous;
|
||||
e.next = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static interface MergeFunction<Key, Value>
|
||||
{
|
||||
Value apply(Key key, Value left, Value right);
|
||||
}
|
||||
|
||||
private class Entry implements Map.Entry<K, V>
|
||||
{
|
||||
private final K key;
|
||||
private V value;
|
||||
|
||||
private Entry previous;
|
||||
private Entry next;
|
||||
|
||||
private Entry(K key, V value)
|
||||
{
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override public K getKey() { return this.key; }
|
||||
@Override public V getValue() { return this.value; }
|
||||
@Override
|
||||
public V setValue(V value)
|
||||
{
|
||||
var old = this.value;
|
||||
this.value = value;
|
||||
return old;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Entry[" + this.key + ", " + this.value + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (!(o instanceof Map.Entry))
|
||||
return false;
|
||||
|
||||
Map.Entry<?,?> e = (Map.Entry<?, ?>)o;
|
||||
return (key == null ? e.getKey() == null : key.equals(e.getKey())) &&
|
||||
(value == null ? e.getValue() == null : value.equals(e.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return (key == null ? 0 : strategy.hashCode(key)) ^
|
||||
(value == null ? 0 : value.hashCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,18 @@ package net.minecraftforge.event;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.CreativeModeTab.Output;
|
||||
import net.minecraft.world.item.CreativeModeTab.TabVisibility;
|
||||
import net.minecraft.world.item.CreativeModeTabs;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraftforge.common.CreativeModeTabRegistry;
|
||||
import net.minecraftforge.common.util.MutableHashedLinkedMap;
|
||||
import net.minecraftforge.eventbus.api.Cancelable;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.LogicalSide;
|
||||
@@ -106,58 +109,20 @@ public class CreativeModeTabEvent extends Event implements IModBusEvent
|
||||
* This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus},
|
||||
* only on the {@linkplain LogicalSide#CLIENT logical client}.
|
||||
*/
|
||||
public static final class BuildContents extends CreativeModeTabEvent
|
||||
public static final class BuildContents extends CreativeModeTabEvent implements Output
|
||||
{
|
||||
private final CreativeModeTab tab;
|
||||
private final Set<DisplayItemsAdapter> customGenerators;
|
||||
private final FeatureFlagSet flags;
|
||||
private final boolean hasPermissions;
|
||||
private final MutableHashedLinkedMap<ItemStack, TabVisibility> entries;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public BuildContents(CreativeModeTab tab, Set<DisplayItemsAdapter> customGenerators)
|
||||
public BuildContents(CreativeModeTab tab, FeatureFlagSet flags, boolean hasPermissions, MutableHashedLinkedMap<ItemStack, TabVisibility> entries)
|
||||
{
|
||||
this.tab = tab;
|
||||
this.customGenerators = customGenerators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given generator.
|
||||
*/
|
||||
public void register(DisplayItemsAdapter generator)
|
||||
{
|
||||
this.customGenerators.add(generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given generator if the provided creative mode tab matches this event's currently populating tab.
|
||||
*/
|
||||
public void register(CreativeModeTab tab, DisplayItemsAdapter generator)
|
||||
{
|
||||
if (this.tab == tab)
|
||||
this.customGenerators.add(generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given generator if the provided tab name matches this event's currently populating tab's name.
|
||||
*/
|
||||
public void register(ResourceLocation tabName, DisplayItemsAdapter generator)
|
||||
{
|
||||
if (this.tab == CreativeModeTabRegistry.getTab(tabName))
|
||||
this.customGenerators.add(generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given item if the provided creative mode tab matches this event's currently populating tab.
|
||||
*/
|
||||
public void registerSimple(CreativeModeTab tab, ItemLike item)
|
||||
{
|
||||
this.register(tab, (enabledFlags, output, permissions) -> output.accept(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given items if the provided creative mode tab matches this event's currently populating tab.
|
||||
*/
|
||||
public void registerSimple(CreativeModeTab tab, ItemLike... items)
|
||||
{
|
||||
this.register(tab, (enabledFlags, output, permissions) -> output.acceptAll(items));
|
||||
this.flags = flags;
|
||||
this.hasPermissions = hasPermissions;
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,70 +132,36 @@ public class CreativeModeTabEvent extends Event implements IModBusEvent
|
||||
{
|
||||
return this.tab;
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface DisplayItemsAdapter
|
||||
{
|
||||
void accept(FeatureFlagSet enabledFlags, CreativeModeTabPopulator populator, boolean hasPermissions);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CreativeModeTabPopulator
|
||||
{
|
||||
void accept(ItemStack stack, CreativeModeTab.TabVisibility visibility, ItemStack before, ItemStack after);
|
||||
|
||||
default void accept(ItemStack stack, ItemStack before, ItemStack after)
|
||||
public FeatureFlagSet getFlags()
|
||||
{
|
||||
accept(stack, CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS, before, after);
|
||||
return this.flags;
|
||||
}
|
||||
|
||||
default void accept(ItemLike stack, CreativeModeTab.TabVisibility visibility, ItemStack before, ItemStack after)
|
||||
public boolean hasPermissions()
|
||||
{
|
||||
accept(new ItemStack(stack), visibility, before, after);
|
||||
return this.hasPermissions;
|
||||
}
|
||||
|
||||
default void accept(ItemLike stack, ItemStack before, ItemStack after)
|
||||
public MutableHashedLinkedMap<ItemStack, TabVisibility> getEntries()
|
||||
{
|
||||
accept(stack, CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS, before, after);
|
||||
return this.entries;
|
||||
}
|
||||
|
||||
default void accept(ItemStack stack, CreativeModeTab.TabVisibility visibility)
|
||||
@Override
|
||||
public void accept(ItemStack stack, TabVisibility visibility)
|
||||
{
|
||||
accept(stack, visibility, ItemStack.EMPTY, ItemStack.EMPTY);
|
||||
getEntries().put(stack, visibility);
|
||||
}
|
||||
|
||||
default void accept(ItemStack stack)
|
||||
public void accept(Supplier<? extends ItemLike> item, CreativeModeTab.TabVisibility visibility)
|
||||
{
|
||||
this.accept(stack, CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS);
|
||||
this.accept(item.get(), visibility);
|
||||
}
|
||||
|
||||
default void accept(ItemLike itemLike, CreativeModeTab.TabVisibility visibility)
|
||||
public void accept(Supplier<? extends ItemLike> item)
|
||||
{
|
||||
this.accept(new ItemStack(itemLike), visibility);
|
||||
}
|
||||
|
||||
default void accept(ItemLike itemLike)
|
||||
{
|
||||
this.accept(new ItemStack(itemLike), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS);
|
||||
}
|
||||
|
||||
default void acceptAll(Collection<ItemStack> stacks, CreativeModeTab.TabVisibility visibility)
|
||||
{
|
||||
stacks.forEach(stack -> this.accept(stack, visibility));
|
||||
}
|
||||
|
||||
default void acceptAll(Collection<ItemStack> stacks)
|
||||
{
|
||||
this.acceptAll(stacks, CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS);
|
||||
}
|
||||
|
||||
default void acceptAll(ItemLike... items)
|
||||
{
|
||||
for (ItemLike item : items)
|
||||
{
|
||||
this.accept(item);
|
||||
}
|
||||
this.accept(item.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user