Compare commits

...
18 changed files with 365 additions and 113 deletions

No files matched your search

@@ -8,6 +8,7 @@ import org.lwjgl.opengl.GL11;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.ShortcutInputHandler;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
@@ -55,12 +56,14 @@ public abstract class AbstractSubpanel<T extends ItemsGrid<? extends ItemsGridSl
}
protected void updateLinePadding() {
GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
final INEIGuiHandler[] handlers = GuiInfo.getGuiHandlersSnapshot();
final Rectangle4i rect = new Rectangle4i(this.x, this.y - 1, 10, 2);
this.linePaddingStart = 0;
while (GuiInfo
.hideItemPanelSlot(guiContainer, new Rectangle4i(this.x + this.linePaddingStart, this.y - 1, 10, 2))) {
while (this.linePaddingStart < this.w && GuiInfo.hideItemPanelSlot(guiContainer, rect, handlers)) {
this.linePaddingStart += 10;
rect.x += 10;
}
}
@@ -0,0 +1,188 @@
package codechicken.nei;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.function.Predicate;
import net.minecraft.client.gui.inventory.GuiContainer;
import codechicken.lib.vec.Rectangle4i;
final class GridOverlapScanner {
private static boolean scanRequested = true;
private static boolean scanFrame = true;
private static boolean wasShowTooltip = true;
private static WeakReference<GuiContainer> lastGui = new WeakReference<>(null);
private boolean invalidated = true;
private final Rectangle4i rect = new Rectangle4i();
private boolean[] checked = new boolean[0];
private int[] queue = new int[0];
private int tail;
private Predicate<Rectangle4i> isHidden;
private boolean[] hidden;
private int hiddenCount;
private int left;
private int top;
private int slotSize;
private int columns;
public static void requestScan() {
scanRequested = true;
}
public static void beginFrame(GuiContainer gui, boolean shouldShowTooltip) {
if (wasShowTooltip != shouldShowTooltip) {
scanRequested = true;
}
wasShowTooltip = shouldShowTooltip;
if (lastGui.get() != gui) {
lastGui = new WeakReference<>(gui);
scanRequested = true;
}
scanFrame = scanRequested;
scanRequested = false;
}
public static boolean isScanFrame() {
return scanFrame;
}
public void invalidate() {
this.invalidated = true;
}
public boolean shouldRefresh() {
final boolean refresh = this.invalidated || scanFrame;
this.invalidated = false;
return refresh;
}
public int scan(Predicate<Rectangle4i> isHidden, int left, int top, int slotSize, int rows, int columns,
boolean seedLeft, boolean seedRight, boolean[] hidden) {
final int size = rows * columns;
if (this.checked.length < size) {
this.checked = new boolean[size];
this.queue = new int[size];
} else {
Arrays.fill(this.checked, 0, size, false);
}
this.isHidden = isHidden;
this.hidden = hidden;
this.hiddenCount = 0;
this.tail = 0;
this.left = left;
this.top = top;
this.slotSize = slotSize;
this.columns = columns;
for (int r = 0; r < rows; r++) {
if (seedLeft) {
probe(r, 0);
}
if (seedRight) {
probe(r, columns - 1);
}
}
for (int head = 0; head < this.tail; head++) {
final int row = this.queue[head] / columns;
final int column = this.queue[head] % columns;
for (int r = Math.max(0, row - 1); r <= Math.min(rows - 1, row + 1); r++) {
for (int c = Math.max(0, column - 1); c <= Math.min(columns - 1, column + 1); c++) {
probe(r, c);
}
}
}
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
if (this.checked[r * columns + c]) {
continue;
}
int c1 = c;
while (c1 + 1 < columns && !this.checked[r * columns + c1 + 1]) {
c1++;
}
int r1 = r;
while (r1 + 1 < rows && isUnchecked(r1 + 1, c, c1)) {
r1++;
}
scanArea(r, r1, c, c1);
c = c1;
}
}
this.isHidden = null;
this.hidden = null;
return this.hiddenCount;
}
private void probe(int row, int column) {
final int idx = row * this.columns + column;
if (!this.checked[idx]) {
this.checked[idx] = true;
if (test(row, row, column, column)) {
this.hidden[idx] = true;
this.queue[this.tail++] = idx;
this.hiddenCount++;
}
}
}
private void scanArea(int r0, int r1, int c0, int c1) {
if (!test(r0, r1, c0, c1)) {
for (int r = r0; r <= r1; r++) {
Arrays.fill(this.checked, r * this.columns + c0, r * this.columns + c1 + 1, true);
}
} else if (r0 == r1 && c0 == c1) {
this.checked[r0 * this.columns + c0] = true;
this.hidden[r0 * this.columns + c0] = true;
this.hiddenCount++;
} else if (r1 - r0 >= c1 - c0) {
final int mid = (r0 + r1) / 2;
scanArea(r0, mid, c0, c1);
scanArea(mid + 1, r1, c0, c1);
} else {
final int mid = (c0 + c1) / 2;
scanArea(r0, r1, c0, mid);
scanArea(r0, r1, mid + 1, c1);
}
}
private boolean isUnchecked(int row, int c0, int c1) {
for (int c = c0; c <= c1; c++) {
if (this.checked[row * this.columns + c]) {
return false;
}
}
return true;
}
private boolean test(int r0, int r1, int c0, int c1) {
this.rect.set(
this.left + c0 * this.slotSize,
this.top + r0 * this.slotSize,
(c1 - c0 + 1) * this.slotSize,
(r1 - r0 + 1) * this.slotSize);
return this.isHidden.test(this.rect);
}
}
+6 -1
View File
@@ -127,7 +127,12 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
this.displayName = "Unnamed";
}
this.stack = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
// Copying the stack copies its whole NBT, so it is only done when the hovered stack changes
final boolean sameStack = this.stack != null && this.stack.isItemEqual(stack)
&& ItemStack.areItemStackTagsEqual(this.stack, stack);
if (!sameStack) {
this.stack = StackInfo.withAmount(stack, 0);
}
} else {
this.stack = null;
this.displayName = "";
+26 -36
View File
@@ -282,6 +282,8 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
protected boolean[] invalidSlotMap;
private final GridOverlapScanner overlapScanner = new GridOverlapScanner();
protected ScreenCapture screenCapture = null;
public ArrayList<ItemStack> getItems() {
@@ -359,12 +361,13 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
width = newWidth;
height = newHeight;
columns = width / SLOT_SIZE;
rows = height / SLOT_SIZE;
this.columns = newWidth / SLOT_SIZE;
this.rows = newHeight / SLOT_SIZE;
paddingLeft = (width % SLOT_SIZE) / 2;
if (changed) {
this.overlapScanner.invalidate();
onGridChanged();
}
}
@@ -405,55 +408,42 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
}
public void refresh(GuiContainer gui) {
final int gridRenderingCacheMode = getGridRenderingCacheMode();
if (gridRenderingCacheMode <= 0 || screenCapture == null || screenCapture.needRefresh(gridRenderingCacheMode)) {
if (this.overlapScanner.shouldRefresh()) {
updateGuiOverlapSlots(gui);
}
shiftPage(0);
}
protected void updateGuiOverlapSlots(GuiContainer gui) {
final boolean[] oldSlotMap = invalidSlotMap;
final int oldRows = rows;
final int oldColumns = columns;
final boolean[] oldSlotMap = this.invalidSlotMap;
final int size = this.rows * this.columns;
final boolean[] slotMap = new boolean[size];
invalidSlotMap = new boolean[rows * columns];
perPage = columns * rows;
this.perPage = size;
if (gui != null) {
if (gui != null && size > 0) {
final INEIGuiHandler[] handlers = GuiInfo.getGuiHandlersSnapshot();
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
checkGuiOverlap(gui, handlers, 0, columns - 2, 1);
checkGuiOverlap(gui, handlers, columns - 1, 1, -1);
} else {
checkGuiOverlap(gui, handlers, 0, columns, 1);
}
final Rectangle4i origin = getSlotRect(0, 0);
this.perPage -= this.overlapScanner.scan(
rect -> GuiInfo.hideItemPanelSlot(gui, rect, handlers),
origin.x,
origin.y,
SLOT_SIZE,
this.rows,
this.columns,
origin.x + this.columns * SLOT_SIZE > gui.guiLeft,
origin.x < gui.guiLeft + gui.xSize,
slotMap);
}
if (oldRows != rows || oldColumns != columns || !Arrays.equals(oldSlotMap, invalidSlotMap)) {
this.invalidSlotMap = slotMap;
if (!Arrays.equals(oldSlotMap, slotMap)) {
onGridChanged();
}
}
private void checkGuiOverlap(GuiContainer gui, INEIGuiHandler[] handlers, int start, int end, int dir) {
boolean validColumn = false;
for (int c = start; c != end && (!NEIClientConfig.optimizeGuiOverlapComputation() || !validColumn); c += dir) {
validColumn = true;
for (int r = 0; r < rows; r++) {
final int idx = columns * r + c;
if (idx >= 0 && idx < invalidSlotMap.length
&& !invalidSlotMap[idx]
&& GuiInfo.hideItemPanelSlot(gui, getSlotRect(r, c), handlers)) {
invalidSlotMap[idx] = true;
validColumn = false;
perPage--;
}
}
}
}
public T getSlotMouseOver(int mousex, int mousey) {
if (!contains(mousex, mousey)) {
return null;
@@ -388,6 +388,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
public static void layout(GuiContainer gui) {
GridOverlapScanner.beginFrame(gui, GuiContainerManager.shouldShowTooltip(gui));
VisiblityData visiblity = new VisiblityData();
visiblity.showNEI = !isHidden();
visiblity.showBookmarkPanel = !isBookmarkPanelHidden();
@@ -821,6 +823,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (!isEnabled()) return;
GridOverlapScanner.requestScan();
AutoFocusWidget.instance.guiTick();
for (Widget widget : drawWidgets) widget.update();
@@ -498,10 +498,6 @@ public class NEIClientConfig {
tag.getTag("inventory.showItemQuantityWidget").setComment("Show Item Quantity Widget").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.showItemQuantityWidget", true));
tag.getTag("inventory.optimize_gui_overlap_computation").setComment("Optimize computation for GUI overlap")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.optimize_gui_overlap_computation", true));
tag.getTag("inventory.autocrafting").setComment("Autocrafting").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.autocrafting", true));
@@ -1160,10 +1156,6 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.bookmarks.craftingTreeZoomWithoutModifier");
}
public static boolean optimizeGuiOverlapComputation() {
return getBooleanSetting("inventory.optimize_gui_overlap_computation");
}
public static boolean showCycledIngredientsTooltip() {
return getBooleanSetting("inventory.guirecipe.cycledIngredientsTooltip");
}
+31 -20
View File
@@ -29,6 +29,9 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
protected T grid;
private int headerPaddingLeft;
private int headerPaddingRight;
public ArrayList<ItemStack> getItems() {
return this.grid.getItems();
}
@@ -105,26 +108,15 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
protected int resizeHeader(GuiContainer gui) {
final int BUTTON_SIZE = 16;
int paddingLeft = 0;
int paddingRight = 0;
while (paddingLeft < w && GuiInfo.hideItemPanelSlot(
gui,
new Rectangle4i(x + paddingLeft, y, ItemsGrid.SLOT_SIZE, ItemsGrid.SLOT_SIZE))) {
paddingLeft += ItemsGrid.SLOT_SIZE;
if (GridOverlapScanner.isScanFrame()) {
updateHeaderPadding(gui);
}
while (paddingRight < w && GuiInfo.hideItemPanelSlot(
gui,
new Rectangle4i(
x + w - paddingRight - ItemsGrid.SLOT_SIZE,
y,
ItemsGrid.SLOT_SIZE,
ItemsGrid.SLOT_SIZE))) {
paddingRight += ItemsGrid.SLOT_SIZE;
}
final int paddingLeft = this.headerPaddingLeft;
final int paddingRight = this.headerPaddingRight;
if (paddingLeft + paddingRight >= w) {
if (paddingLeft + paddingRight >= this.w) {
return 0;
}
@@ -132,16 +124,35 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
pagePrev.h = pageNext.h = BUTTON_SIZE;
pagePrev.y = pageNext.y = y;
pagePrev.x = x + paddingLeft;
pageNext.x = x + w - pageNext.w - paddingRight;
pagePrev.x = this.x + paddingLeft;
pageNext.x = this.x + this.w - pageNext.w - paddingRight;
pageLabel.x = x + paddingLeft + (w - paddingLeft - paddingRight) / 2;
pageLabel.y = y + 5;
pageLabel.x = this.x + paddingLeft + (this.w - paddingLeft - paddingRight) / 2;
pageLabel.y = this.y + 5;
pageLabel.text = getLabelText();
return BUTTON_SIZE + 2;
}
private void updateHeaderPadding(GuiContainer gui) {
final INEIGuiHandler[] handlers = GuiInfo.getGuiHandlersSnapshot();
final Rectangle4i slot = new Rectangle4i(this.x, this.y, ItemsGrid.SLOT_SIZE, ItemsGrid.SLOT_SIZE);
this.headerPaddingLeft = 0;
this.headerPaddingRight = 0;
while (this.headerPaddingLeft < this.w && GuiInfo.hideItemPanelSlot(gui, slot, handlers)) {
this.headerPaddingLeft += ItemsGrid.SLOT_SIZE;
slot.x += ItemsGrid.SLOT_SIZE;
}
slot.x = this.x + this.w - ItemsGrid.SLOT_SIZE;
while (this.headerPaddingRight < this.w && GuiInfo.hideItemPanelSlot(gui, slot, handlers)) {
this.headerPaddingRight += ItemsGrid.SLOT_SIZE;
slot.x -= ItemsGrid.SLOT_SIZE;
}
}
protected abstract int resizeFooter(GuiContainer gui);
public void setVisible() {
@@ -7,7 +7,6 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemSorter;
@@ -132,7 +131,7 @@ public class BookmarkGridGenerator {
itemIndex++;
}
} else if (group.crafting != null && group.crafting.itemToRecipe.values().contains(bookmarkItem.recipeId)) {
} else if (group.crafting != null && group.crafting.recipeToItems.containsKey(bookmarkItem.recipeId)) {
absoluteSlotIndex = generateCollapsedRecipe(prevBookmarkItem, itemIndex, absoluteSlotIndex, borderGrid);
prevBookmarkItem = bookmarkItem;
@@ -218,8 +217,7 @@ public class BookmarkGridGenerator {
}
private List<Integer> getShadows(BookmarkGroup group, RecipeId recipeId) {
return group.crafting.itemToRecipe.entrySet().stream().filter(entry -> recipeId.equals(entry.getValue()))
.map(entry -> entry.getKey()).collect(Collectors.toList());
return new ArrayList<>(group.crafting.recipeToItems.getOrDefault(recipeId, Collections.emptyList()));
}
private int nextSlotIndex(int index, BookmarkItem previousMeta, BookmarkItem meta, BookmarkViewMode viewMode) {
@@ -111,6 +111,7 @@ public class RecipeChainDetails {
public final Map<Integer, BookmarkChainItem> calculatedItems = new HashMap<>();
public final Map<Integer, RecipeId> itemToRecipe = new HashMap<>();
public final Map<RecipeId, List<Integer>> recipeToItems = new HashMap<>();
public final Set<RecipeId> outputRecipes = new HashSet<>();
public final Set<RecipeId> recipeInMiddle = new HashSet<>();
@@ -124,6 +125,7 @@ public class RecipeChainDetails {
}
this.itemToRecipe.clear();
this.recipeToItems.clear();
this.outputRecipes.clear();
this.recipeInMiddle.clear();
this.calculatedItems.clear();
@@ -180,6 +182,10 @@ public class RecipeChainDetails {
}
for (Map.Entry<Integer, RecipeId> entry : this.itemToRecipe.entrySet()) {
this.recipeToItems.computeIfAbsent(entry.getValue(), recipeId -> new ArrayList<>()).add(entry.getKey());
}
for (Map.Entry<Integer, BookmarkItem> entry : chainItems.entrySet()) {
final int itemIndex = entry.getKey();
if (itemIndex >= 0 && this.calculatedItems.containsKey(itemIndex)) {
@@ -37,8 +37,8 @@ public class SortableItem {
&& (group.viewMode == BookmarkViewMode.TODO_LIST || group.crafting != null);
this.crossGroup = !group.collapsed && group.viewMode == BookmarkViewMode.TODO_LIST
&& bookmarkItem.type != BookmarkItemType.INGREDIENT;
this.isCollapsedRecipe = group.crafting != null && group.crafting.itemToRecipe.values().stream()
.anyMatch(recipeId -> this.bookmarkItem.equalsRecipe(recipeId, this.bookmarkItem.groupId));
this.isCollapsedRecipe = group.crafting != null && this.bookmarkItem.recipeId != null
&& group.crafting.recipeToItems.containsKey(this.bookmarkItem.recipeId);
this.update();
}
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -16,7 +17,7 @@ import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidContainerItem;
import codechicken.nei.ClientHandler;
import codechicken.nei.ItemStackMap;
import codechicken.nei.ItemStackMap.StackMetaKey;
import codechicken.nei.LRUCache;
import codechicken.nei.api.IStackStringifyHandler;
import codechicken.nei.api.ItemInfo;
@@ -31,7 +32,7 @@ public class StackInfo {
private static final FluidStack NULL_FLUID = new FluidStack(FluidRegistry.WATER, 0);
public static final List<IStackStringifyHandler> stackStringifyHandlers = new ArrayList<>();
private static final Map<String, HashMap<String, String[]>> guidfilters = new HashMap<>();
private static final ItemStackMap<String> guidcache = new ItemStackMap<>();
private static final Map<Item, Map<StackMetaKey, String>> guidcache = new ConcurrentHashMap<>();
private static final LRUCache<ItemStackKey, FluidStack> fluidcache = new LRUCache<>(200);
private static boolean isPausedItemDamageSound = false;
@@ -182,7 +183,9 @@ public class StackInfo {
}
public static String getItemStackGUID(ItemStack stack) {
String guid = guidcache.get(stack);
final Item stackItem = stack.getItem();
final Map<StackMetaKey, String> itemGuids = stackItem != null ? guidcache.get(stackItem) : null;
String guid = itemGuids != null ? itemGuids.get(new StackMetaKey(stack)) : null;
if (guid != null) {
return guid;
@@ -190,7 +193,7 @@ public class StackInfo {
final NBTTagCompound nbTag = itemStackToNBT(stack, false);
if (nbTag == null) {
if (nbTag == null || stack.getItem() == null) {
return "unknown";
}
@@ -239,16 +242,15 @@ public class StackInfo {
}
});
synchronized (guidcache) {
guidcache.put(stack, keys.toString());
}
guid = keys.toString();
} else {
synchronized (guidcache) {
guidcache.put(stack, NBTHelper.toString(nbTag));
}
guid = NBTHelper.toString(nbTag);
}
return guidcache.get(stack);
guidcache.computeIfAbsent(stack.getItem(), item -> new ConcurrentHashMap<>())
.put(new StackMetaKey(stack.copy()), guid);
return guid;
}
public static void loadGuidFilters() {
@@ -10,6 +10,9 @@ import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import codechicken.nei.api.IStackStringifyHandler;
import codechicken.nei.item.ItemFluidDisplay;
import cpw.mods.fml.common.registry.GameRegistry;
@@ -22,6 +25,11 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
protected static Class<?> gtMetaGeneratedTool = null;
protected static Field playSound = null;
private static final Supplier<Item> AE2FC_FLUID_PACKET = Suppliers
.memoize(() -> GameRegistry.findItem("ae2fc", "fluid_packet"));
private static final Supplier<Item> AE2FC_FLUID_DROP = Suppliers
.memoize(() -> GameRegistry.findItem("ae2fc", "fluid_drop"));
static {
try {
final ClassLoader loader = GTFluidStackStringifyHandler.class.getClassLoader();
@@ -94,11 +102,11 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
return new FluidStack(fluid, 0);
}
} else if (item == GameRegistry.findItem("ae2fc", "fluid_packet")) {
} else if (item == AE2FC_FLUID_PACKET.get()) {
NBTTagCompound nbtTag = stack.getTagCompound();
return FluidStack.loadFluidStackFromNBT((NBTTagCompound) nbtTag.getTag("FluidStack"));
} else if (item == GameRegistry.findItem("ae2fc", "fluid_drop")) {
} else if (item == AE2FC_FLUID_DROP.get()) {
NBTTagCompound nbtTag = stack.getTagCompound();
Fluid fluid = FluidRegistry.getFluid(nbtTag.getString("Fluid").toLowerCase());
@@ -113,9 +121,9 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
@Override
public ItemStack normalizeRecipeQueryStack(ItemStack stack) {
final Item item = stack.getItem();
if (stack.getItem() == GameRegistry.findItem("ae2fc", "fluid_drop")
|| stack.getItem() == GameRegistry.findItem("ae2fc", "fluid_packet")) {
if (item == AE2FC_FLUID_DROP.get() || item == AE2FC_FLUID_PACKET.get()) {
final FluidStack fluidStack = getFluid(stack);
if (fluidStack != null) {
@@ -139,8 +147,7 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
@Override
public boolean isFluidDisplayItem(ItemStack stack) {
final Item item = stack.getItem();
return (itemFluidDisplay != null && itemFluidDisplay.isInstance(item))
|| item == GameRegistry.findItem("ae2fc", "fluid_packet");
return (itemFluidDisplay != null && itemFluidDisplay.isInstance(item)) || item == AE2FC_FLUID_PACKET.get();
}
}
@@ -26,6 +26,9 @@ public class FavoriteStorage {
protected final Map<RecipeId, Long> recipeIdToItemHash = new HashMap<>();
protected final Map<Long, ItemStack> itemHashToItemStack = new HashMap<>();
/** The key of the last looked up stack. Its NBT copies the whole stack, which is looked up every frame. */
private static volatile LookupKey lastLookupKey = null;
public void clear() {
this.itemStackToRecipeId.clear();
this.fluidToRecipeId.clear();
@@ -95,7 +98,7 @@ public class FavoriteStorage {
RecipeId recipeId = this.itemHashToRecipeId.get(getItemKey(stack));
if (recipeId == null) {
recipeId = this.itemStackToRecipeId.get(StackInfo.itemStackToNBT(stack, false));
recipeId = this.itemStackToRecipeId.get(getLookupKey(stack));
}
if (recipeId == null) {
@@ -105,6 +108,28 @@ public class FavoriteStorage {
return recipeId;
}
private static NBTTagCompound getLookupKey(ItemStack stack) {
LookupKey key = lastLookupKey;
if (key == null || !key.stack.isItemEqual(stack) || !ItemStack.areItemStackTagsEqual(key.stack, stack)) {
key = new LookupKey(stack.copy(), StackInfo.itemStackToNBT(stack, false));
lastLookupKey = key;
}
return key.nbt;
}
private static class LookupKey {
private final ItemStack stack;
private final NBTTagCompound nbt;
private LookupKey(ItemStack stack, NBTTagCompound nbt) {
this.stack = stack;
this.nbt = nbt;
}
}
public ItemStack getItemStack(RecipeId recipeId) {
NBTTagCompound itemStackNBT = this.recipeIdToItemStack.get(recipeId);
@@ -10,6 +10,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import net.minecraft.creativetab.CreativeTabs;
@@ -128,8 +129,8 @@ public class ItemUntranslator {
private static final String CONFIG_FILE = "untranslator.cfg";
private static final ItemUntranslator instance = new ItemUntranslator();
private final Map<String, String> secondNames = new HashMap<>();
private final Map<String, String> processedNames = new HashMap<>();
private final Map<String, String> secondNames = new ConcurrentHashMap<>();
private final Map<String, String> processedNames = new ConcurrentHashMap<>();
private ItemUntranslator() {}
@@ -241,14 +242,19 @@ public class ItemUntranslator {
return EnumChatFormatting.getTextWithoutFormattingCodes(name).trim();
}
public synchronized String getItemStackDisplayName(ItemStack stack) {
public String getItemStackDisplayName(ItemStack stack) {
if (stack == null || this.secondNames.isEmpty()) {
return "";
}
final String guidKey = StackInfo.getItemStackGUID(stack);
final String displayName = this.processedNames.get(guidKey);
return displayName != null ? displayName : processDisplayName(stack, guidKey);
}
private synchronized String processDisplayName(ItemStack stack, String guidKey) {
return this.processedNames.computeIfAbsent(guidKey, stackKey -> {
String displayName = this.secondNames.get(stackKey);
@@ -412,9 +412,6 @@ nei.options.inventory.search.subsetsSearchMode=Item Subsets Search
nei.options.inventory.search.subsetsSearchMode.0=Always
nei.options.inventory.search.subsetsSearchMode.1=Prefix: %s
nei.options.inventory.search.subsetsSearchMode.2=Never
nei.options.inventory.optimize_gui_overlap_computation=Optimize computation for GUI overlap
nei.options.inventory.optimize_gui_overlap_computation.true=Yes
nei.options.inventory.optimize_gui_overlap_computation.false=No
nei.options.inventory.autocrafting=Autocrafting
nei.options.inventory.autocrafting.true=Enabled
nei.options.inventory.autocrafting.false=Disabled
@@ -251,9 +251,6 @@ nei.options.inventory.search.subsetsSearchMode=Поиск по подмноже
nei.options.inventory.search.subsetsSearchMode.0=Всегда
nei.options.inventory.search.subsetsSearchMode.1=Префикс: %s
nei.options.inventory.search.subsetsSearchMode.2=Никогда
nei.options.inventory.optimize_gui_overlap_computation=Оптимизация вычислений при перекрытии GUI
nei.options.inventory.optimize_gui_overlap_computation.true=Да
nei.options.inventory.optimize_gui_overlap_computation.false=Нет
nei.options.inventory.guirecipe.shiftOverlayRecipe=Требовать удержание Shift для перемещения предметов при отображении рецепта
nei.options.inventory.guirecipe.shiftOverlayRecipe.true=Да
nei.options.inventory.guirecipe.shiftOverlayRecipe.false=Нет
@@ -359,9 +359,6 @@ nei.options.inventory.search.subsetsSearchMode=Пошук у підгрупах
nei.options.inventory.search.subsetsSearchMode.0=Завжди
nei.options.inventory.search.subsetsSearchMode.1=Префікс: %s
nei.options.inventory.search.subsetsSearchMode.2=Ніколи
nei.options.inventory.optimize_gui_overlap_computation=Оптимізувати обчислення перекриття інтерфейсів
nei.options.inventory.optimize_gui_overlap_computation.true=Так
nei.options.inventory.optimize_gui_overlap_computation.false=Ні
nei.options.inventory.autocrafting=Автокрафт
nei.options.inventory.autocrafting.true=Увімкнено
nei.options.inventory.autocrafting.false=Вимкнено
@@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.List;
@@ -16,7 +15,7 @@ import org.junit.jupiter.api.Test;
public class ItemsGridTest {
@Test
void synchronizesOverlapAndCaptureRefresh() {
void refreshesCaptureOnlyWhenGridChanged() {
TestGrid grid = new TestGrid();
ItemsGrid.ScreenCapture capture = mock(ItemsGrid.ScreenCapture.class);
grid.screenCapture = capture;
@@ -24,22 +23,48 @@ public class ItemsGridTest {
grid.setGridSize(1, 2, 18, 18);
grid.setGridSize(1, 2, 18, 18);
verify(capture, times(1)).refreshBuffer();
}
when(capture.needRefresh(1)).thenReturn(false, true);
grid.refresh(null);
@Test
void refreshesOverlapOnlyOnGridChangeOrScanFrame() {
TestGrid grid = new TestGrid();
GridOverlapScanner.requestScan();
GridOverlapScanner.beginFrame(null, true);
grid.setGridSize(1, 2, 18, 18);
grid.refresh(null);
assertEquals(1, grid.overlapRefreshes);
GridOverlapScanner.beginFrame(null, true);
grid.refresh(null);
assertEquals(1, grid.overlapRefreshes);
grid.setGridSize(1, 2, 36, 18);
grid.refresh(null);
assertEquals(2, grid.overlapRefreshes);
GridOverlapScanner.requestScan();
GridOverlapScanner.beginFrame(null, true);
grid.refresh(null);
assertEquals(3, grid.overlapRefreshes);
GridOverlapScanner.beginFrame(null, false);
grid.refresh(null);
assertEquals(4, grid.overlapRefreshes);
GridOverlapScanner.beginFrame(null, false);
grid.refresh(null);
assertEquals(4, grid.overlapRefreshes);
GridOverlapScanner.beginFrame(null, true);
grid.refresh(null);
assertEquals(5, grid.overlapRefreshes);
}
private static final class TestGrid extends ItemsGrid<ItemsGrid.ItemsGridSlot, ItemsGrid.MouseContext> {
private int overlapRefreshes;
@Override
protected int getGridRenderingCacheMode() {
return 1;
}
@Override
protected void updateGuiOverlapSlots(GuiContainer gui) {
overlapRefreshes++;