Skip to content

Commit

Permalink
Refactor CreativeTabManager
Browse files Browse the repository at this point in the history
Use functions provided by Neoforge to add items to creative tabs.
  • Loading branch information
BrokenK3yboard committed Nov 13, 2024
1 parent a68fc31 commit ea87e70
Showing 1 changed file with 89 additions and 169 deletions.
258 changes: 89 additions & 169 deletions src/main/java/org/violetmoon/zeta/registry/CreativeTabManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,19 @@
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTab.TabVisibility;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
import net.neoforged.neoforge.common.util.MutableHashedLinkedMap;
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
import org.violetmoon.zeta.Zeta;
import org.violetmoon.zeta.config.ZetaGeneralConfig;
import org.violetmoon.zeta.module.IDisableable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.*;
import java.util.function.Supplier;

public class CreativeTabManager {

private static final Object MUTEX = new Object();
private static final Map<ItemLike, Item> itemLikeCache = new HashMap<>();

private static final Map<ResourceKey<CreativeModeTab>, CreativeTabAdditions> additions = new HashMap<>();
private static final Multimap<ItemLike, ResourceKey<CreativeModeTab>> mappedItems = HashMultimap.create();
Expand All @@ -47,43 +36,39 @@ public static void endDaisyChain() {
}

public static void addToCreativeTab(ResourceKey<CreativeModeTab> tab, ItemLike item) {
if(daisyChainMode) {
if(daisyChainedSet == null)
throw new IllegalArgumentException("Must start daisy chain with addToCreativeTabNextTo");

if (daisyChainMode) {
if (daisyChainedSet == null) throw new IllegalArgumentException("Must start daisy chain with addToCreativeTabNextTo");
addToDaisyChain(item);
}
else
} else {
getForTab(tab).appendToEnd.add(item);

}
mappedItems.put(item, tab);
}

public static void addToCreativeTabNextTo(ResourceKey<CreativeModeTab> tab, ItemLike item, ItemLike target, boolean behind) {
tab = guessTab(target, tab);
CreativeTabAdditions additions = getForTab(tab);
Map<ItemSet, ItemLike> map = (behind ? additions.appendBehind : additions.appendInFront);

ItemSet toAdd = null;

if(daisyChainMode) {
boolean newSet = daisyChainedSet == null;
ItemSet set = addToDaisyChain(item);

if(newSet)
toAdd = set;
}
else
} else {
toAdd = new ItemSet(item);
}

if(toAdd != null)
map.put(toAdd, target);

mappedItems.put(item, tab);
}

private static ItemSet addToDaisyChain(ItemLike item) {
if(daisyChainMode && daisyChainedSet != null) {
if (daisyChainMode && daisyChainedSet != null) {
daisyChainedSet.items.add(item);
return daisyChainedSet;
}
Expand All @@ -96,194 +81,130 @@ private static ItemSet addToDaisyChain(ItemLike item) {
}

private static ResourceKey<CreativeModeTab> guessTab(ItemLike parent, ResourceKey<CreativeModeTab> tab) {
if(parent != null && mappedItems.containsKey(parent))
tab = mappedItems.get(parent).iterator().next();

return tab;
}
return (parent != null && mappedItems.containsKey(parent)) ? mappedItems.get(parent).iterator().next() : tab;
}

private static CreativeTabAdditions getForTab(ResourceKey<CreativeModeTab> tab) {
return additions.computeIfAbsent(tab, tabRk -> new CreativeTabAdditions());
}

public static void buildContents(BuildCreativeModeTabContentsEvent event) {
synchronized(MUTEX) {

ResourceKey<CreativeModeTab> tabKey = event.getTabKey();
MutableHashedLinkedMap<ItemStack, TabVisibility> entries = event.getEntries();

if(additions.containsKey(tabKey)) {
CreativeTabAdditions add = additions.get(tabKey);

for(ItemLike item : add.appendToEnd)
for(ItemLike item : add.appendToEnd) {
acceptItem(event, item);

}

if(ZetaGeneralConfig.forceCreativeTabAppends) {
for(ItemSet itemset : add.appendInFront.keySet())
for(ItemLike item : itemset.items)
acceptItem(event, item);

for(ItemSet itemset : add.appendBehind.keySet())
for(ItemLike item : itemset.items)
acceptItem(event, item);

return;
}

Map<ItemSet, ItemLike> front = new LinkedHashMap<>(add.appendInFront);
Map<ItemSet, ItemLike> behind = new LinkedHashMap<>(add.appendBehind);

final int failsafe = 100;
final int printThreshold = failsafe - 10;

int misses = 0;
boolean failsafing = false;

while(true) {
boolean missed = false;
logVerbose(() -> "front empty=" + front.isEmpty() + " / behind empty=" + behind.isEmpty());

if(entries.isEmpty()) {
Zeta.GLOBAL_LOG.error("entries map for tab " + tabKey + " is empty, this should never happen");
return;
}

if(!front.isEmpty())
missed = appendNextTo(tabKey, entries, front, false, failsafing);
if(!behind.isEmpty())
missed |= appendNextTo(tabKey, entries, behind, true, failsafing);

if(missed) {
int fMisses = misses;
logVerbose(() -> "Missed " + fMisses + "times out of " + failsafe);

misses++;
}

// arbitrary failsafe, should never happen
if(misses > failsafe) {
logVerbose(() -> {
StringBuilder sb = new StringBuilder();
for(Entry<ItemStack, TabVisibility> entry : entries) {
sb.append(entry.getKey());
sb.append("; ");
}
return sb.toString();
});
new RuntimeException("Creative tab placement misses exceeded failsafe, aborting logic").printStackTrace();
return;
}
if(misses > printThreshold)
failsafing = true;

if(front.isEmpty() && behind.isEmpty())
return;
}
final int maxFails = 100;
final int logThreshold = maxFails - 10;
int failedAttempts = 0;

while (failedAttempts < 100) {
if (!front.isEmpty()) {
failedAttempts = addItems(event, front, false, failedAttempts > logThreshold) ? failedAttempts : failedAttempts + 1;
}
if (!behind.isEmpty()) {
failedAttempts = addItems(event, behind, true, failedAttempts > logThreshold) ? failedAttempts : failedAttempts + 1;
}
}
}
}
}

private static boolean isItemEnabled(ItemLike item) {
if(item instanceof IDisableable<?> id)
return id.isEnabled();

return true;
}

private static void acceptItem(BuildCreativeModeTabContentsEvent event, ItemLike item) {
if(!isItemEnabled(item))
return;

if(item instanceof AppendsUniquely au)
event.acceptAll(au.appendItemsToCreativeTab());
else
event.accept(item);
}

private static void addToEntries(ItemStack target, MutableHashedLinkedMap<ItemStack, CreativeModeTab.TabVisibility> entries, ItemLike item, boolean behind) {
logVerbose(() -> "adding target=" + target + " next to " + item + " with behind=" + behind);
if(!isItemEnabled(item))
return;

List<ItemStack> stacksToAdd = Arrays.asList(new ItemStack(item));
if(item instanceof AppendsUniquely au)
stacksToAdd = au.appendItemsToCreativeTab();

if(!behind)
Collections.reverse(stacksToAdd);

for(ItemStack addStack : stacksToAdd) {
if(behind)
entries.putBefore(target, addStack, TabVisibility.PARENT_AND_SEARCH_TABS);
else
entries.putAfter(target, addStack, TabVisibility.PARENT_AND_SEARCH_TABS);
}
}
private static boolean addItems(BuildCreativeModeTabContentsEvent event, Map<ItemSet, ItemLike> itemsMap, boolean insertAfter, boolean log) {
Collection<ItemSet> collection = itemsMap.keySet();
ItemSet itemsToAdd = collection.iterator().next();
ItemLike firstSetItem = itemsToAdd.items.getFirst();
ItemLike target = itemsMap.get(itemsToAdd);
logVerbose(() -> "target is " + target);

/**
* Returns true if the item needs to be tried again later
*/
private static boolean appendNextTo(ResourceKey<CreativeModeTab> tabKey, MutableHashedLinkedMap<ItemStack, CreativeModeTab.TabVisibility> entries, Map<ItemSet, ItemLike> map, boolean behind, boolean log) {
logVerbose(() -> "appendNextTo " + tabKey + " / behind=" + behind);
Collection<ItemSet> coll = map.keySet();
if(coll.isEmpty())
throw new RuntimeException("Tab collection is empty, this should never happen.");
itemsMap.remove(itemsToAdd);

ItemSet firstSet = coll.iterator().next();
ItemLike firstSetItem = firstSet.items.get(0);
ItemLike target = map.get(firstSet);
logVerbose(() -> "target is " + target);

if(log) {
Zeta.GLOBAL_LOG.error("Creative tab loop found when adding {} next to {}", firstSetItem, target);
Zeta.GLOBAL_LOG.error("For more info enable Creative Verbose Logging in the Zeta config, or set Force Creative Tab Appends to true to disable this behavior");
}

map.remove(firstSet);

if(!isItemEnabled(firstSetItem) || target == null) {
logVerbose(() -> "hit early false return");
return false;
}

if(!itemLikeCache.containsKey(target))
itemLikeCache.put(target, target.asItem());
Item targetItem = itemLikeCache.get(target);

for(Entry<ItemStack, TabVisibility> entry : entries) {
ItemStack stack = entry.getKey();
Item item = stack.getItem();

logVerbose(() -> "Comparing item " + item + " to our target " + targetItem);

if(item == targetItem) {
logVerbose(() -> "Matched! Adding successfully");
for(int i = 0; i < firstSet.items.size(); i++) {
int j = i;
if(!behind)
j = firstSet.items.size() - 1 - i;

addToEntries(stack, entries, firstSet.items.get(j), behind);

if (!isItemEnabled(firstSetItem) || target == null) return true;

ItemStack targetStack = new ItemStack(target);

for (ItemLike item : itemsToAdd.items) {
if (!isItemEnabled(item)) continue;
List<ItemStack> stacksToAdd = List.of(new ItemStack(item));

if (item instanceof AppendsUniquely au) {
stacksToAdd = au.appendItemsToCreativeTab();
}

if(!insertAfter) {
Collections.reverse(stacksToAdd);
}

for(ItemStack addStack : stacksToAdd) {
if (insertAfter) {
try {
event.insertAfter(targetStack, addStack, TabVisibility.PARENT_AND_SEARCH_TABS);
} catch (IllegalArgumentException exception) {
logVerbose(exception::getMessage);
itemsMap.put(itemsToAdd, target);
return false;
}
} else {
try {
event.insertBefore(targetStack, addStack, TabVisibility.PARENT_AND_SEARCH_TABS);
} catch (IllegalArgumentException exception) {
logVerbose(exception::getMessage);
itemsMap.put(itemsToAdd, target);
return false;
}
}

return false;
}
}

// put the set back at the end of the map to try it again after the target is added
map.put(firstSet, target);
return true;
}


private static boolean isItemEnabled(ItemLike item) {
return !(item instanceof IDisableable<?> id) || id.isEnabled();
}

private static void acceptItem(BuildCreativeModeTabContentsEvent event, ItemLike item) {
if (!isItemEnabled(item)) return;

if(item instanceof AppendsUniquely au)
event.acceptAll(au.appendItemsToCreativeTab());
else
event.accept(item);
}

private static void logVerbose(Supplier<String> s) {
if(ZetaGeneralConfig.enableCreativeVerboseLogging)
Zeta.GLOBAL_LOG.warn(s.get());
}

private static class CreativeTabAdditions {

private List<ItemLike> appendToEnd = new ArrayList<>();
private Map<ItemSet, ItemLike> appendInFront = new LinkedHashMap<>();
private Map<ItemSet, ItemLike> appendBehind = new LinkedHashMap<>();

private final List<ItemLike> appendToEnd = new ArrayList<>();
private final Map<ItemSet, ItemLike> appendInFront = new LinkedHashMap<>();
private final Map<ItemSet, ItemLike> appendBehind = new LinkedHashMap<>();
}

private static class ItemSet {
Expand All @@ -293,10 +214,9 @@ private static class ItemSet {
public ItemSet(ItemLike item) {
items.add(item);
}

}

public interface AppendsUniquely extends ItemLike {
List<ItemStack> appendItemsToCreativeTab();
}
}
}

0 comments on commit ea87e70

Please sign in to comment.