Files
NotEnoughItems/src/main/java/codechicken/nei/ItemList.java
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

390 lines
13 KiB
Java
Raw Normal View History

2014-04-29 10:54:20 +10:00
package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
2024-07-26 18:44:54 +03:00
import java.util.HashMap;
2014-04-29 10:54:20 +10:00
import java.util.HashSet;
import java.util.LinkedList;
2014-04-29 10:54:20 +10:00
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
2024-10-04 21:46:29 +02:00
import java.util.concurrent.ForkJoinWorkerThread;
2014-04-29 10:54:20 +10:00
import java.util.regex.Pattern;
2021-01-17 12:03:33 -08:00
import java.util.stream.Collectors;
2024-06-27 18:03:50 +03:00
import net.minecraft.client.Minecraft;
2023-09-25 00:35:24 +02:00
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
2024-08-17 23:24:27 +03:00
import net.minecraft.util.EnumChatFormatting;
2023-09-25 00:35:24 +02:00
import net.minecraft.util.IIcon;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import codechicken.nei.ThreadOperationTimer.TimeoutException;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
public class ItemList {
/**
* Fields are replaced atomically and contents never modified.
*/
public static volatile List<ItemStack> items = new ArrayList<>();
/**
* Fields are replaced atomically and contents never modified.
*/
public static volatile ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
/**
* Updates to this should be synchronised on this
*/
2019-12-30 20:19:16 -08:00
public static final List<ItemFilterProvider> itemFilterers = new LinkedList<>();
public static final List<ItemsLoadedCallback> loadCallbacks = new LinkedList<>();
2024-07-26 18:44:54 +03:00
public static final CollapsibleItems collapsibleItems = new CollapsibleItems();
2014-04-29 10:54:20 +10:00
2019-12-30 20:19:16 -08:00
private static final HashSet<Item> erroredItems = new HashSet<>();
private static final HashSet<String> stackTraces = new HashSet<>();
2024-07-26 18:44:54 +03:00
private static final HashMap<ItemStack, Integer> ordering = new HashMap<>();
2022-08-31 17:43:22 +09:00
/**
* Unlike {@link LayoutManager#itemsLoaded}, this indicates whether item loading is actually finished or not.
*/
public static boolean loadFinished;
2014-04-29 10:54:20 +10:00
public static class EverythingItemFilter implements ItemFilter {
@Override
public boolean matches(ItemStack item) {
return true;
}
2014-04-29 10:54:20 +10:00
}
public static class NothingItemFilter implements ItemFilter {
2014-04-29 10:54:20 +10:00
@Override
public boolean matches(ItemStack item) {
2014-04-29 10:54:20 +10:00
return false;
}
}
2014-04-29 10:54:20 +10:00
2024-06-27 18:03:50 +03:00
public static class NegatedItemFilter implements ItemFilter {
public ItemFilter filter;
public NegatedItemFilter(ItemFilter filter) {
this.filter = filter;
}
@Override
public boolean matches(ItemStack item) {
return this.filter == null || !this.filter.matches(item);
}
}
public static class PatternItemFilter implements ItemFilter {
2014-12-14 17:10:00 +10:00
public Pattern pattern;
2014-04-29 10:54:20 +10:00
public PatternItemFilter(Pattern pattern) {
2014-04-29 10:54:20 +10:00
this.pattern = pattern;
}
@Override
public boolean matches(ItemStack item) {
2024-08-17 23:24:27 +03:00
String displayName = EnumChatFormatting.getTextWithoutFormattingCodes(item.getDisplayName());
2024-09-01 23:19:12 +03:00
if (!displayName.isEmpty() && pattern.matcher(displayName).find()) {
return true;
}
if (item.hasDisplayName()) {
displayName = EnumChatFormatting
.getTextWithoutFormattingCodes(item.getItem().getItemStackDisplayName(item));
return !displayName.isEmpty() && pattern.matcher(displayName).find();
}
return false;
2014-04-29 10:54:20 +10:00
}
}
public static class AllMultiItemFilter implements ItemFilter {
2019-12-30 20:19:16 -08:00
public List<ItemFilter> filters;
2014-12-14 17:10:00 +10:00
public AllMultiItemFilter(List<ItemFilter> filters) {
this.filters = filters;
}
public AllMultiItemFilter(ItemFilter... filters) {
2024-08-29 23:14:52 +03:00
this(new LinkedList<>(Arrays.asList(filters)));
}
2014-12-14 17:10:00 +10:00
public AllMultiItemFilter() {
2019-12-30 20:19:16 -08:00
this(new LinkedList<>());
2014-12-14 17:10:00 +10:00
}
@Override
public boolean matches(ItemStack item) {
for (ItemFilter filter : filters) try {
if (filter != null && !filter.matches(item)) return false;
2014-12-14 17:10:00 +10:00
} catch (Exception e) {
NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e);
2014-12-14 17:10:00 +10:00
}
return true;
}
}
public static class AnyMultiItemFilter implements ItemFilter {
2019-12-30 20:19:16 -08:00
public List<ItemFilter> filters;
2014-12-14 17:10:00 +10:00
public AnyMultiItemFilter(List<ItemFilter> filters) {
this.filters = filters;
}
public AnyMultiItemFilter() {
2019-12-30 20:19:16 -08:00
this(new LinkedList<>());
2014-12-14 17:10:00 +10:00
}
@Override
public boolean matches(ItemStack item) {
for (ItemFilter filter : filters) try {
2024-08-29 23:14:52 +03:00
if (filter != null && filter.matches(item)) return true;
2014-12-14 17:10:00 +10:00
} catch (Exception e) {
NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e);
2014-12-14 17:10:00 +10:00
}
return false;
}
}
public static interface ItemsLoadedCallback {
public void itemsLoaded();
2014-04-29 10:54:20 +10:00
}
public static boolean itemMatchesAll(ItemStack item, List<ItemFilter> filters) {
for (ItemFilter filter : filters) {
try {
2024-08-29 23:14:52 +03:00
if (filter != null && !filter.matches(item)) return false;
} catch (Exception e) {
NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e);
}
}
2014-04-29 10:54:20 +10:00
return true;
2014-04-29 10:54:20 +10:00
}
2014-12-14 17:10:00 +10:00
/**
* @deprecated use getItemListFilter().matches(item)
*/
@Deprecated
public static boolean itemMatches(ItemStack item) {
2014-12-14 17:10:00 +10:00
return getItemListFilter().matches(item);
}
public static ItemFilter getItemListFilter() {
return new AllMultiItemFilter(getItemFilters());
2014-04-29 10:54:20 +10:00
}
public static List<ItemFilter> getItemFilters() {
2019-12-30 20:19:16 -08:00
LinkedList<ItemFilter> filters = new LinkedList<>();
synchronized (itemFilterers) {
2024-06-27 18:03:50 +03:00
for (ItemFilterProvider p : itemFilterers) {
filters.add(p.getFilter());
}
2014-04-29 10:54:20 +10:00
}
return filters;
2014-04-29 10:54:20 +10:00
}
public static final RestartableTask loadItems = new RestartableTask("NEI Item Loading") {
private void damageSearch(Item item, List<ItemStack> permutations) {
2019-12-30 20:19:16 -08:00
HashSet<String> damageIconSet = new HashSet<>();
for (int damage = 0; damage < 16; damage++) try {
ItemStack itemstack = new ItemStack(item, 1, damage);
IIcon icon = item.getIconIndex(itemstack);
2024-06-27 18:03:50 +03:00
String name = getTooltip(itemstack);
String s = name + "@" + (icon == null ? 0 : icon.hashCode());
if (!damageIconSet.contains(s)) {
damageIconSet.add(s);
permutations.add(itemstack);
}
} catch (TimeoutException t) {
throw t;
} catch (Throwable t) {
NEIServerUtils.logOnce(
t,
stackTraces,
"Ommiting " + item + ":" + damage + " " + item.getClass().getSimpleName(),
item.toString());
}
2014-04-29 10:54:20 +10:00
}
2024-06-27 18:03:50 +03:00
private String getTooltip(ItemStack stack) {
try {
2024-08-29 23:14:52 +03:00
return String.join("\n", stack.getTooltip(Minecraft.getMinecraft().thePlayer, false));
2024-06-27 18:03:50 +03:00
} catch (Throwable ignored) {}
return "";
}
2024-07-26 18:44:54 +03:00
private void updateOrdering(List<ItemStack> items) {
ItemList.ordering.clear();
ItemSorter.sort(items);
2024-08-17 23:24:27 +03:00
if (!ItemList.collapsibleItems.isEmpty()) {
2024-07-26 18:44:54 +03:00
HashMap<Integer, Integer> groups = new HashMap<>();
int orderIndex = 0;
for (ItemStack stack : items) {
final int groupIndex = ItemList.collapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
ItemList.ordering.put(stack, orderIndex++);
} else {
if (!groups.containsKey(groupIndex)) {
groups.put(groupIndex, orderIndex++);
}
ItemList.ordering.put(stack, groups.get(groupIndex));
}
}
} else {
int orderIndex = 0;
for (ItemStack stack : items) {
ItemList.ordering.put(stack, orderIndex++);
}
}
}
2014-04-29 10:54:20 +10:00
@Override
2021-04-10 15:32:59 -07:00
@SuppressWarnings("unchecked")
public void execute() {
2021-10-16 06:07:25 +02:00
ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
2024-08-29 23:14:52 +03:00
LayoutManager.itemsLoaded = true;
2022-08-31 17:43:22 +09:00
loadFinished = false;
2014-04-29 10:54:20 +10:00
2024-07-26 18:44:54 +03:00
List<ItemStack> items = new LinkedList<>();
List<ItemStack> permutations = new LinkedList<>();
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
2014-04-29 10:54:20 +10:00
2021-10-16 06:07:25 +02:00
timer.setLimit(NEIClientConfig.getItemLoadingTimeout());
for (Item item : (Iterable<Item>) Item.itemRegistry) {
if (interrupted()) return;
if (item == null || erroredItems.contains(item)) continue;
try {
timer.reset(item);
permutations.clear();
permutations.addAll(ItemInfo.itemOverrides.get(item));
2024-08-29 23:14:52 +03:00
if (permutations.isEmpty()) {
item.getSubItems(item, null, permutations);
}
2024-08-29 23:14:52 +03:00
if (permutations.isEmpty()) {
damageSearch(item, permutations);
}
permutations.addAll(ItemInfo.itemVariants.get(item));
timer.reset();
2024-08-29 23:14:52 +03:00
permutations = permutations.stream().filter(stack -> !ItemInfo.isHidden(stack))
.collect(Collectors.toCollection(ArrayList::new));
items.addAll(permutations);
itemMap.putAll(item, permutations);
} catch (Throwable t) {
NEIServerConfig.logger.error("Removing item: " + item + " from list.", t);
erroredItems.add(item);
}
}
2014-04-29 10:54:20 +10:00
if (interrupted()) return;
ItemList.items = items;
ItemList.itemMap = itemMap;
for (ItemsLoadedCallback callback : loadCallbacks) callback.itemsLoaded();
2024-07-26 18:44:54 +03:00
if (interrupted()) return;
ItemList.collapsibleItems.updateCache(items);
updateOrdering(items);
2022-08-31 17:43:22 +09:00
loadFinished = true;
2024-07-26 18:44:54 +03:00
updateFilter.restart();
2014-04-29 10:54:20 +10:00
}
};
2014-04-29 10:54:20 +10:00
2024-10-04 21:46:29 +02:00
public static ForkJoinPool forkJoinPool;
2024-10-04 21:46:29 +02:00
static {
final ForkJoinPool.ForkJoinWorkerThreadFactory factory = new ForkJoinPool.ForkJoinWorkerThreadFactory() {
private int workerId;
2024-10-04 21:46:29 +02:00
@Override
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
worker.setName("NEI-worker-thread-" + workerId++);
return worker;
}
};
int poolSize = Runtime.getRuntime().availableProcessors() * 2 / 3;
if (poolSize < 1) poolSize = 1;
forkJoinPool = new ForkJoinPool(poolSize, factory, null, false);
}
public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") {
2024-07-26 18:44:54 +03:00
private int compare(ItemStack o1, ItemStack o2) {
return Integer.compare(ItemList.ordering.get(o1), ItemList.ordering.get(o2));
}
2014-04-29 10:54:20 +10:00
@Override
public void execute() {
2024-07-26 18:44:54 +03:00
if (!loadFinished) return;
2014-12-14 17:10:00 +10:00
ItemFilter filter = getItemListFilter();
2024-07-26 18:44:54 +03:00
ArrayList<ItemStack> filtered;
2019-12-24 13:37:41 -08:00
try {
filtered = ItemList.forkJoinPool.submit(
() -> items.parallelStream().filter(filter::matches)
.collect(Collectors.toCollection(ArrayList::new)))
.get();
} catch (InterruptedException | ExecutionException e) {
2021-01-17 12:03:33 -08:00
filtered = new ArrayList<>();
e.printStackTrace();
stop();
}
if (interrupted()) return;
2024-07-26 18:44:54 +03:00
filtered.sort(this::compare);
if (interrupted()) return;
2019-12-30 20:19:16 -08:00
ItemPanel.updateItemList(filtered);
2014-04-29 10:54:20 +10:00
}
};
2014-04-29 10:54:20 +10:00
/**
* @deprecated Use updateFilter.restart()
*/
@Deprecated
public static void updateFilter() {
updateFilter.restart();
2014-04-29 10:54:20 +10:00
}
/**
* @deprecated Use loadItems.restart()
*/
@Deprecated
2014-04-29 10:54:20 +10:00
public static void loadItems() {
loadItems.restart();
2014-04-29 10:54:20 +10:00
}
}