package codechicken.nei; import codechicken.nei.ThreadOperationTimer.TimeoutException; import codechicken.nei.api.ItemFilter; import codechicken.nei.api.ItemFilter.ItemFilterProvider; import codechicken.nei.api.ItemInfo; import codechicken.nei.guihook.GuiContainerManager; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import net.minecraft.client.resources.model.IBakedModel; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; public class ItemList { /** * Fields are replaced atomically and contents never modified. */ public static volatile List<ItemStack> items = new ArrayList<ItemStack>(); /** * 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 */ public static final List<ItemFilterProvider> itemFilterers = new LinkedList<ItemFilterProvider>(); public static final List<ItemsLoadedCallback> loadCallbacks = new LinkedList<ItemsLoadedCallback>(); private static HashSet<Item> erroredItems = new HashSet<Item>(); private static HashSet<String> stackTraces = new HashSet<String>(); public static class EverythingItemFilter implements ItemFilter { @Override public boolean matches(ItemStack item) { return true; } } public static class NothingItemFilter implements ItemFilter { @Override public boolean matches(ItemStack item) { return false; } } public static class PatternItemFilter implements ItemFilter { public Pattern pattern; public PatternItemFilter(Pattern pattern) { this.pattern = pattern; } @Override public boolean matches(ItemStack item) { return pattern.matcher(ItemInfo.getSearchName(item)).find(); } } public static class AllMultiItemFilter implements ItemFilter { public List<ItemFilter> filters = new LinkedList<ItemFilter>(); public AllMultiItemFilter(List<ItemFilter> filters) { this.filters = filters; } public AllMultiItemFilter() { this(new LinkedList<ItemFilter>()); } @Override public boolean matches(ItemStack item) { for (ItemFilter filter : filters) { try { if (!filter.matches(item)) { return false; } } catch (Exception e) { NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e); } } return true; } } public static class AnyMultiItemFilter implements ItemFilter { public List<ItemFilter> filters = new LinkedList<ItemFilter>(); public AnyMultiItemFilter(List<ItemFilter> filters) { this.filters = filters; } public AnyMultiItemFilter() { this(new LinkedList<ItemFilter>()); } @Override public boolean matches(ItemStack item) { for (ItemFilter filter : filters) { try { if (filter.matches(item)) { return true; } } catch (Exception e) { NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e); } } return false; } } public interface ItemsLoadedCallback { void itemsLoaded(); } public static boolean itemMatchesAll(ItemStack item, List<ItemFilter> filters) { for (ItemFilter filter : filters) { try { if (!filter.matches(item)) { return false; } } catch (Exception e) { NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e); } } return true; } /** * @deprecated use getItemListFilter().matches(item) */ @Deprecated public static boolean itemMatches(ItemStack item) { return getItemListFilter().matches(item); } public static ItemFilter getItemListFilter() { return new AllMultiItemFilter(getItemFilters()); } public static List<ItemFilter> getItemFilters() { LinkedList<ItemFilter> filters = new LinkedList<ItemFilter>(); synchronized (itemFilterers) { for (ItemFilterProvider p : itemFilterers) { filters.add(p.getFilter()); } } return filters; } public static final RestartableTask loadItems = new RestartableTask("NEI Item Loading") { private void damageSearch(Item item, List<ItemStack> permutations) { HashSet<String> damageIconSet = new HashSet<String>(); for (int damage = 0; damage < 16; damage++) { try { ItemStack stack = new ItemStack(item, 1, damage); IBakedModel model = GuiContainerManager.drawItems.getItemModelMesher().getItemModel(stack); String name = GuiContainerManager.concatenatedDisplayName(stack, false); String s = name + "@" + (model == null ? 0 : model.hashCode()); if (!damageIconSet.contains(s)) { damageIconSet.add(s); permutations.add(stack); } } catch (TimeoutException t) { throw t; } catch (Throwable t) { NEIServerUtils.logOnce(t, stackTraces, "Ommiting " + item + ":" + damage + " " + item.getClass().getSimpleName(), item.toString()); } } } @Override public void execute() { ThreadOperationTimer timer = getTimer(500); LinkedList<ItemStack> items = new LinkedList<ItemStack>(); LinkedList<ItemStack> permutations = new LinkedList<ItemStack>(); ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create(); timer.setLimit(500); for (Item 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)); if (permutations.isEmpty()) { item.getSubItems(item, null, permutations); } if (permutations.isEmpty()) { damageSearch(item, permutations); } permutations.addAll(ItemInfo.itemVariants.get(item)); timer.reset(); items.addAll(permutations); itemMap.putAll(item, permutations); } catch (Throwable t) { NEIServerConfig.logger.error("Removing item: " + item + " from list.", t); erroredItems.add(item); } } if (interrupted()) { return; } ItemList.items = items; ItemList.itemMap = itemMap; for (ItemsLoadedCallback callback : loadCallbacks) { callback.itemsLoaded(); } updateFilter.restart(); } }; public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") { @Override public void execute() { ArrayList<ItemStack> filtered = new ArrayList<ItemStack>(); ItemFilter filter = getItemListFilter(); for (ItemStack item : items) { if (interrupted()) { return; } if (filter.matches(item)) { filtered.add(item); } } if (interrupted()) { return; } ItemSorter.sort(filtered); if (interrupted()) { return; } ItemPanel.updateItemList(filtered); } }; }