From e0a3cab3173ab65f658dbe1cbcec6c2855475b99 Mon Sep 17 00:00:00 2001 From: loldudester Date: Sat, 24 Jan 2015 03:16:53 +0000 Subject: [PATCH 01/13] Fixed dark UI issue on newer versions of Forge On (at least) Forge 10.13.2.1230, the GUI for both crafting tables renders really dark. I added a GL line to fix this, into each GUI file. --- .../lepko/easycrafting/core/inventory/gui/GuiAutoCrafting.java | 3 +++ .../lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiAutoCrafting.java b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiAutoCrafting.java index e05ed0d..3800c60 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiAutoCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiAutoCrafting.java @@ -1,5 +1,7 @@ package net.lepko.easycrafting.core.inventory.gui; +import org.lwjgl.opengl.GL11; + import net.lepko.easycrafting.Ref; import net.lepko.easycrafting.core.block.TileEntityAutoCrafting; import net.lepko.easycrafting.core.inventory.ContainerAutoCrafting; @@ -30,6 +32,7 @@ public void initGui() { @Override protected void drawGuiContainerBackgroundLayer(float tickTime, int mouseX, int mouseY) { + GL11.glColor4f(1, 1, 1, 1); // Background mc.renderEngine.bindTexture(GUI_TEXTURE); drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java index b9ffbef..2840219 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java @@ -132,9 +132,11 @@ public void drawScreen(int mouseX, int mouseY, float time) { @Override protected void drawGuiContainerBackgroundLayer(float f, int i, int j) { + GL11.glColor4f(1, 1, 1, 1); // Background mc.renderEngine.bindTexture(GUI_TEXTURE); drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); + GL11.glColor4f(1, 1, 1, 1); // Tabs super.drawGuiContainerBackgroundLayer(f, i, j); From f9504293b16e02a3022cb7290afc50a7efe8ad22 Mon Sep 17 00:00:00 2001 From: Anon Date: Wed, 8 Apr 2015 21:32:22 -0500 Subject: [PATCH 02/13] Fix Exception when searching in search tab. Remove duplicate recipes --- .gitignore | 5 + build.properties | 2 +- .../core/inventory/gui/GuiEasyCrafting.java | 976 +++++++++--------- .../core/recipe/RecipeChecker.java | 236 ++--- .../core/recipe/RecipeHelper.java | 402 ++++---- .../core/recipe/RecipeManager.java | 212 ++-- .../core/recipe/WrappedRecipe.java | 228 ++-- .../core/util/InventoryUtils.java | 506 ++++----- 8 files changed, 1316 insertions(+), 1251 deletions(-) diff --git a/.gitignore b/.gitignore index 1cedfb4..0a6a8de 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,8 @@ Desktop.ini *.iml *.ipr *.iws +/bin/ +.classpath +/.gradle/ +.project +/.settings/ diff --git a/build.properties b/build.properties index b30163f..8faa337 100644 --- a/build.properties +++ b/build.properties @@ -4,7 +4,7 @@ filename=EasyCrafting version=2.0.1 version_mc=1.7.10 -version_forge=10.13.0.1208 +version_forge=10.13.2.1291 #ftp_location=ftp://localhost/maven/ ftp_location=ftp://lepko.net/domains/lepko.net/public_html/mods/maven/ diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java index b9ffbef..1f13cd2 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java @@ -1,7 +1,9 @@ package net.lepko.easycrafting.core.inventory.gui; import codechicken.nei.guihook.IContainerTooltipHandler; + import com.google.common.collect.ImmutableList; + import cpw.mods.fml.common.Optional; import net.lepko.easycrafting.Ref; import net.lepko.easycrafting.core.block.ModBlocks; @@ -31,6 +33,7 @@ import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; import net.minecraftforge.oredict.OreDictionary; + import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; @@ -43,484 +46,497 @@ @Optional.Interface(iface = "codechicken.nei.guihook.IContainerTooltipHandler", modid = "NotEnoughItems") public class GuiEasyCrafting extends GuiTabbed implements IContainerTooltipHandler { - private class TabEasyCrafting extends Tab { - public TabEasyCrafting(ItemStack iconStack, String tooltip) { - super(iconStack, tooltip); - } - - @Override - public void onTabSelected() { - updateSearch(true); - } - } - - private static final ResourceLocation GUI_TEXTURE = new ResourceLocation(Ref.RES_DOMAIN, "textures/gui/easycraftinggui.png"); - private static String LAST_SEARCH = ""; - private static boolean WORKER_LOCKED = false; - - public List shownRecipes; - public List craftableRecipes = ImmutableList.of(); - - private int currentRowOffset = 0; - private int maxRowOffset = 0; - private float currentScrollValue = 0; - private boolean wasClicking = false; - private boolean isDraggingScrollBar = false; - private boolean[] canCraftCache; - - private final IInventory tileInventory; - private GuiTextField searchField; - - public GuiEasyCrafting(InventoryPlayer playerInventory, TileEntityEasyCrafting tileInventory) { - super(new ContainerEasyCrafting(playerInventory, tileInventory)); - this.tileInventory = tileInventory; - ySize = 235; - } - - @Override - public void initGui() { - super.initGui(); - Keyboard.enableRepeatEvents(true); - searchField = new GuiTextField(fontRendererObj, guiLeft + 82, guiTop + 6, 89, fontRendererObj.FONT_HEIGHT); - searchField.setMaxStringLength(32); - searchField.setEnableBackgroundDrawing(false); - searchField.setVisible(true); - searchField.setTextColor(0xFFFFFF); - searchField.setCanLoseFocus(false); - searchField.setFocused(true); - searchField.setText(LAST_SEARCH); - } - - @Override - public void initTabs() { - tabGroup.addTab(new TabEasyCrafting(new ItemStack(ModBlocks.table), "Available")); - tabGroup.addTab(new TabEasyCrafting(new ItemStack(Items.compass), "Search")); - } - - @Override - public void onGuiClosed() { - super.onGuiClosed(); - Keyboard.enableRepeatEvents(false); - } - - @Override - public void drawScreen(int mouseX, int mouseY, float time) { - // XXX: Check lock on worker thread - WORKER_LOCKED = !RecipeChecker.INSTANCE.done; - - // Handle scrollbar dragging - boolean leftMouseDown = Mouse.isButtonDown(0); - int left = guiLeft + 155; - int top = guiTop + 18; - int right = left + 14; - int bottom = top + 89; - - if (!wasClicking && leftMouseDown && mouseX >= left && mouseY >= top && mouseX < right && mouseY < bottom) { - isDraggingScrollBar = maxRowOffset > 0; - } else if (!leftMouseDown) { - isDraggingScrollBar = false; - } - - wasClicking = leftMouseDown; - - if (isDraggingScrollBar) { - setScrollValue((mouseY - top - 7.5F) / (bottom - top - 15.0F)); - } - - super.drawScreen(mouseX, mouseY, time); - } - - @Override - protected void drawGuiContainerBackgroundLayer(float f, int i, int j) { - // Background - mc.renderEngine.bindTexture(GUI_TEXTURE); - drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); - - // Tabs - super.drawGuiContainerBackgroundLayer(f, i, j); - - // Scrollbar - int scrollTextureX = maxRowOffset == 0 ? 12 : 0; - drawTexturedModalRect(guiLeft + 156, guiTop + 17 + (int) (currentScrollValue * 73.0F), scrollTextureX, 240, 12, 16); - - // Search - int searchTextureX = xSize - 90 - 7; - drawTexturedModalRect(guiLeft + searchTextureX, guiTop + 4, searchTextureX, 256 - 12, 90, 12); - searchField.drawTextBox(); - - // Output slot backgrounds - if (canCraftCache != null && currentTab != 0) { - int offset = currentRowOffset * 8; - for (int k = 0; k < 40 && k + offset < canCraftCache.length; k++) { - drawSlotBackground(inventorySlots.getSlot(k), canCraftCache[k + offset]); - } - } - - // Storage slots background - for (int l = 0; l < 18; l++) { - drawSlotBackground(inventorySlots.getSlot(l + 40), false); - } - } - - @Override - protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { - String title = "Easy Crafting"; - if (WORKER_LOCKED) { - title = "Searching..."; - } - fontRendererObj.drawString(title, 7, 6, 0x404040); - - super.drawGuiContainerForegroundLayer(mouseX, mouseY); - } - - @Override - protected void keyTyped(char par1, int par2) { - if (!checkHotbarKeys(par2)) { - if (searchField.textboxKeyTyped(par1, par2)) { - updateSearch(true); - } else { - super.keyTyped(par1, par2); - } - } - } - - @Override - public void handleMouseInput() { - int mouseScroll = Mouse.getEventDWheel(); - if (mouseScroll == 0) { // Bypass NEI fast transfer manager - super.handleMouseInput(); - } else { - setRowOffset(currentRowOffset + (mouseScroll > 0 ? -1 : 1)); - } - } - - // button: - // 0 -> left mouse - // 1 -> action=0 or 1 -> right mouse - // _____action=5 -> left click dragged over - // 2 -> middle mouse - // 5 -> action=5 -> right click dragged over - // - // action: - // 0 -> click - // 1 -> shift click - // 2 -> swap with slot in hotbar (button is 0-8) - // 3 -> pick block - // 4 -> drop block - // 5 -> dragged stack - // 6 -> double click - @Override - protected void handleMouseClick(Slot slot, int slotIndex, int button, int action) { - if (slotIndex >= 0 && slotIndex < 40) { - onCraftingSlotClick(slot, slotIndex, button, action); - } else { - super.handleMouseClick(slot, slotIndex, button, action); - } - } - - private void onCraftingSlotClick(Slot slot, int slotIndex, int button, int action) { - Ref.LOGGER.trace("Clicked: " + slot.getClass().getSimpleName() + "@" + slotIndex + ", button=" + button + ", action=" + action + ", stack=" + slot.getStack()); - - if (action > 1 || button > 1 || !slot.getHasStack()) { - return; - } - - ItemStack heldStack = mc.thePlayer.inventory.getItemStack(); - ItemStack slotStack = slot.getStack(); - - WrappedRecipe recipe = null; - int recipeIndex = slotIndex + currentRowOffset * 8; - if (recipeIndex >= 0 && shownRecipes != null && recipeIndex < shownRecipes.size()) { - WrappedRecipe r = shownRecipes.get(recipeIndex); - if (StackUtils.areEqualNoSizeNoNBT(r.getOutput(), slotStack) && craftableRecipes != null && craftableRecipes.contains(r)) { - recipe = r; - } - } - if (recipe == null) { - return; - } - - // slotStack already has a stack from recipe.handler.getCraftingResult() - ItemStack finalStack = slotStack.copy(); - int finalStackSize = 0; - - if (heldStack == null) { - finalStackSize = finalStack.stackSize; - } else if (StackUtils.canStack(slotStack, heldStack) == 0) { - finalStackSize = finalStack.stackSize + heldStack.stackSize; - } - - if (finalStackSize > 0) { - boolean isRightClick = button == 1; - boolean isShiftClick = action == 1; - - PacketHandler.INSTANCE.sendToServer(new MessageEasyCrafting(recipe, isRightClick, isShiftClick)); - - if (isRightClick) { // Right click; craft until max stack - int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, heldStack); - int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); - if (timesCrafted > 0) { - finalStack.stackSize = finalStackSize + (timesCrafted - 1) * finalStack.stackSize; - mc.thePlayer.inventory.setItemStack(finalStack); - } - } else if (isShiftClick) { - int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, null); - int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); - if (timesCrafted > 0) { - finalStack.stackSize *= timesCrafted; //ignore finalStackSize; it might contain heldStack size - InventoryUtils.addItemToInventory(mc.thePlayer.inventory, finalStack); - } - } else { // Left click; craft once - finalStack.stackSize = finalStackSize; - mc.thePlayer.inventory.setItemStack(finalStack); - } - } - } - - private void drawSlotBackground(Slot slot, boolean canCraft) { - int x = guiLeft + slot.xDisplayPosition; - int y = guiTop + slot.yDisplayPosition; - int color = canCraft ? 0x8000A000 : 0x80A00000; - Gui.drawRect(x, y, x + 16, y + 16, color); - } - - @SuppressWarnings("unchecked") - private void updateSearch(boolean scrollToTop) { - List all = currentTab == 0 ? craftableRecipes : RecipeManager.getAllRecipes(); - List list = new ArrayList(); - if (all == null || searchField == null) { - return; - } - LAST_SEARCH = searchField.getText().toLowerCase(); - if (!LAST_SEARCH.trim().isEmpty()) { - for (WrappedRecipe recipe : all) { - List tips = recipe.getOutput().getTooltip(mc.thePlayer, mc.gameSettings.advancedItemTooltips); - for (String tip : tips) { - if (tip.toLowerCase().contains(LAST_SEARCH)) { - list.add(recipe); - break; - } - } - } - shownRecipes = list; - } else { - shownRecipes = all; - } - - maxRowOffset = (int) (Math.ceil(shownRecipes.size() / 8.0D) - 5); - maxRowOffset = maxRowOffset < 0 ? 0 : maxRowOffset; - - rebuildCanCraftCache(); - setRowOffset(scrollToTop ? 0 : currentRowOffset); - } - - public void refreshCraftingOutput() { - craftableRecipes = ImmutableList.copyOf(RecipeChecker.INSTANCE.recipes); - updateSearch(false); - } - - private void rebuildCanCraftCache() { - canCraftCache = new boolean[shownRecipes.size()]; - for (int i = 0; i < shownRecipes.size(); i++) { - canCraftCache[i] = craftableRecipes.contains(shownRecipes.get(i)); - } - } - - private void setRowOffset(int rowOffset) { - currentRowOffset = MathHelper.clamp_int(rowOffset, 0, maxRowOffset); - currentScrollValue = MathHelper.clamp_float(currentRowOffset / (float) maxRowOffset, 0F, 1F); - setSlots(); - } - - private void setScrollValue(float scrollValue) { - currentScrollValue = MathHelper.clamp_float(scrollValue, 0F, 1F); - currentRowOffset = MathHelper.clamp_int((int) (currentScrollValue * maxRowOffset + 0.5F), 0, maxRowOffset); - setSlots(); - } - - private void setSlots() { - if (shownRecipes != null) { - int offset = currentRowOffset * 8; - for (int i = 0; i < 40; i++) { - if (i + offset >= shownRecipes.size() || i + offset < 0) { - tileInventory.setInventorySlotContents(i, null); - } else { - WrappedRecipe recipe = shownRecipes.get(i + offset); - ItemStack is = recipe.handler.getCraftingResult(recipe, recipe.usedIngredients); - tileInventory.setInventorySlotContents(i, is); - } - } - } - } - - // START NEI - @Override - public List handleTooltip(GuiContainer gui, int mouseX, int mouseY, List currentTip) { - return currentTip; - } - - @Override - public List handleItemDisplayName(GuiContainer gui, ItemStack stack, List currentTip) { - return currentTip; - } - - @Override - public List handleItemTooltip(GuiContainer gui, ItemStack stack, int mouseX, int mouseY, List currentTip) { - if (!drawCustomTooltip(stack, mouseX, mouseY, currentTip)) { - return currentTip; - } - // Hack to always return empty list - return new LinkedList() { - @Override - public int size() { - return 0; - } - }; - } - // END NEI - - @SuppressWarnings("unchecked") - @Override - protected void renderToolTip(ItemStack stack, int mouseX, int mouseY) { - if (!drawCustomTooltip(stack, mouseX, mouseY, (List) stack.getTooltip(mc.thePlayer, mc.gameSettings.advancedItemTooltips))) { - super.renderToolTip(stack, mouseX, mouseY); - } - } - - private boolean drawCustomTooltip(ItemStack stack, int mouseX, int mouseY, List currentTip) { - if (isCtrlKeyDown() && currentTip != null && !currentTip.isEmpty()) { - for (int j = 0; j < 40; j++) { - Slot slot = inventorySlots.getSlot(j); - //isPointInRegion - if (func_146978_c(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, mouseX, mouseY)) { - FontRenderer font = stack.getItem().getFontRenderer(stack); - String itemName = currentTip.get(0); - List list = ImmutableList.of(stack.getRarity().rarityColor + itemName); - drawHoveringText(list, mouseX, mouseY, font == null ? fontRendererObj : font); - - boolean leftSide = mouseX + 12 + fontRendererObj.getStringWidth(itemName) > width; - drawIngredientTooltip(j, mouseX, mouseY, leftSide); - return true; - } - } - } - return false; - } - - private void drawIngredientTooltip(int slotIndex, int mouseX, int mouseY, boolean leftSide) { - - WrappedRecipe recipe = null; - - int recipe_index = slotIndex + currentRowOffset * 8; - if (recipe_index >= 0 && shownRecipes != null && recipe_index < shownRecipes.size()) { - WrappedRecipe r = shownRecipes.get(recipe_index); - if (StackUtils.areCraftingEquivalent(r.getOutput(), inventorySlots.getSlot(slotIndex).getStack())) { - recipe = r; - } - } - - if (recipe == null) { - return; - } - - boolean canCraft = canCraftCache[recipe_index]; - List ingredientList = canCraft && !recipe.usedIngredients.isEmpty() ? StackUtils.collateStacks(recipe.usedIngredients) : recipe.collatedInputs; - - if (ingredientList != null && !ingredientList.isEmpty()) { - int width = 16; - int height = 16; - int xPos = mouseX + 12; - int yPos = mouseY - 12 + 14; - - if (ingredientList.size() > 1) { - width += (ingredientList.size() - 1) * (width + 2); - } - - if (leftSide) { - xPos -= 28 + width; - } - - // red: 0x50FF0000;// green: 0x5000A700;// vanilla purple: 0x505000FF; - int bgColor = 0xF0100010; - int borderColor = canCraft ? 0x5000A700 : 0x50FF0000; - int borderColorDark = (borderColor & 0xFEFEFE) >> 1 | borderColor & 0xFF000000; - - zLevel += 500.0F; - itemRender.zLevel += 500.0F; - - RenderHelper.disableStandardItemLighting(); - GL11.glDisable(GL11.GL_LIGHTING); - GL11.glDisable(GL11.GL_DEPTH_TEST); - GL11.glDisable(GL12.GL_RESCALE_NORMAL); - - drawGradientRect(xPos - 3, yPos - 4, xPos + width + 3, yPos - 3, bgColor, bgColor); - drawGradientRect(xPos - 3, yPos + height + 3, xPos + width + 3, yPos + height + 4, bgColor, bgColor); - drawGradientRect(xPos - 3, yPos - 3, xPos + width + 3, yPos + height + 3, bgColor, bgColor); - drawGradientRect(xPos - 4, yPos - 3, xPos - 3, yPos + height + 3, bgColor, bgColor); - drawGradientRect(xPos + width + 3, yPos - 3, xPos + width + 4, yPos + height + 3, bgColor, bgColor); - - drawGradientRect(xPos - 3, yPos - 3 + 1, xPos - 3 + 1, yPos + height + 3 - 1, borderColor, borderColorDark); - drawGradientRect(xPos + width + 2, yPos - 3 + 1, xPos + width + 3, yPos + height + 3 - 1, borderColor, borderColorDark); - drawGradientRect(xPos - 3, yPos - 3, xPos + width + 3, yPos - 3 + 1, borderColor, borderColor); - drawGradientRect(xPos - 3, yPos + height + 2, xPos + width + 3, yPos + height + 3, borderColorDark, borderColorDark); - - RenderHelper.enableGUIStandardItemLighting(); - GL11.glEnable(GL11.GL_LIGHTING); - GL11.glEnable(GL11.GL_DEPTH_TEST); - GL11.glEnable(GL12.GL_RESCALE_NORMAL); - - for (WrappedStack ws : ingredientList) { - renderItem(xPos, yPos, ws); - xPos += 18; - } - - GL11.glDisable(GL12.GL_RESCALE_NORMAL); - GL11.glDisable(GL11.GL_DEPTH_TEST); - GL11.glDisable(GL11.GL_LIGHTING); - - zLevel -= 500.0F; - itemRender.zLevel -= 500.0F; - } - } - - private void renderItem(int xPos, int yPos, WrappedStack ws) { - ItemStack is = null; - - int count = 0; - for (ItemStack stack : ws.stacks) { - if (stack.getItemDamage() == OreDictionary.WILDCARD_VALUE && stack.getHasSubtypes()) { - count += ItemMap.get(stack.getItem()).size(); - } else { - count++; - } - } - - int num = (int) ((mc.theWorld.getTotalWorldTime() / 10) % count); - - count = 0; - for (ItemStack stack : ws.stacks) { - if (stack.getItemDamage() == OreDictionary.WILDCARD_VALUE && stack.getHasSubtypes()) { - List all = ItemMap.get(stack.getItem()); - if (num >= count && num < count + all.size()) { - is = StackUtils.copyStack(all.get(num - count), ws.size); - break; - } - count += all.size(); - } else { - if (num == count) { - is = StackUtils.copyStack(stack, ws.size); - break; - } - count++; - } - } - - // - if (is != null) { - itemRender.renderItemAndEffectIntoGUI(fontRendererObj, mc.renderEngine, is, xPos, yPos); - itemRender.renderItemOverlayIntoGUI(fontRendererObj, mc.renderEngine, is, xPos, yPos); - } else { - Ref.LOGGER.warn("Error rendering stack in recipe tooltip: is == null"); - } - } + private class TabEasyCrafting extends Tab { + public TabEasyCrafting(ItemStack iconStack, String tooltip) { + super(iconStack, tooltip); + } + + @Override + public void onTabSelected() { + updateSearch(true); + } + } + + private static final ResourceLocation GUI_TEXTURE = new ResourceLocation(Ref.RES_DOMAIN, "textures/gui/easycraftinggui.png"); + private static String LAST_SEARCH = ""; + private static boolean WORKER_LOCKED = false; + + public List shownRecipes; + public List craftableRecipes = ImmutableList.of(); + + private int currentRowOffset = 0; + private int maxRowOffset = 0; + private float currentScrollValue = 0; + private boolean wasClicking = false; + private boolean isDraggingScrollBar = false; + private boolean[] canCraftCache; + + private final IInventory tileInventory; + private GuiTextField searchField; + + public GuiEasyCrafting(InventoryPlayer playerInventory, TileEntityEasyCrafting tileInventory) { + super(new ContainerEasyCrafting(playerInventory, tileInventory)); + this.tileInventory = tileInventory; + ySize = 235; + } + + @Override + public void initGui() { + super.initGui(); + Keyboard.enableRepeatEvents(true); + searchField = new GuiTextField(fontRendererObj, guiLeft + 82, guiTop + 6, 89, fontRendererObj.FONT_HEIGHT); + searchField.setMaxStringLength(32); + searchField.setEnableBackgroundDrawing(false); + searchField.setVisible(true); + searchField.setTextColor(0xFFFFFF); + searchField.setCanLoseFocus(false); + searchField.setFocused(true); + searchField.setText(LAST_SEARCH); + } + + @Override + public void initTabs() { + tabGroup.addTab(new TabEasyCrafting(new ItemStack(ModBlocks.table), "Available")); + tabGroup.addTab(new TabEasyCrafting(new ItemStack(Items.compass), "Search")); + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + Keyboard.enableRepeatEvents(false); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float time) { + // XXX: Check lock on worker thread + WORKER_LOCKED = !RecipeChecker.INSTANCE.done; + + // Handle scrollbar dragging + boolean leftMouseDown = Mouse.isButtonDown(0); + int left = guiLeft + 155; + int top = guiTop + 18; + int right = left + 14; + int bottom = top + 89; + + if (!wasClicking && leftMouseDown && mouseX >= left && mouseY >= top && mouseX < right && mouseY < bottom) { + isDraggingScrollBar = maxRowOffset > 0; + } else if (!leftMouseDown) { + isDraggingScrollBar = false; + } + + wasClicking = leftMouseDown; + + if (isDraggingScrollBar) { + setScrollValue((mouseY - top - 7.5F) / (bottom - top - 15.0F)); + } + + super.drawScreen(mouseX, mouseY, time); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float f, int i, int j) { + // Background + mc.renderEngine.bindTexture(GUI_TEXTURE); + drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); + + // Tabs + super.drawGuiContainerBackgroundLayer(f, i, j); + + // Scrollbar + int scrollTextureX = maxRowOffset == 0 ? 12 : 0; + drawTexturedModalRect(guiLeft + 156, guiTop + 17 + (int) (currentScrollValue * 73.0F), scrollTextureX, 240, 12, 16); + + // Search + int searchTextureX = xSize - 90 - 7; + drawTexturedModalRect(guiLeft + searchTextureX, guiTop + 4, searchTextureX, 256 - 12, 90, 12); + searchField.drawTextBox(); + + // Output slot backgrounds + if (canCraftCache != null && currentTab != 0) { + int offset = currentRowOffset * 8; + for (int k = 0; k < 40 && k + offset < canCraftCache.length; k++) { + drawSlotBackground(inventorySlots.getSlot(k), canCraftCache[k + offset]); + } + } + + // Storage slots background + for (int l = 0; l < 18; l++) { + drawSlotBackground(inventorySlots.getSlot(l + 40), false); + } + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + String title = "Easy Crafting"; + if (WORKER_LOCKED) { + title = "Searching..."; + } + fontRendererObj.drawString(title, 7, 6, 0x404040); + + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + } + + @Override + protected void keyTyped(char par1, int par2) { + if (!checkHotbarKeys(par2)) { + if (searchField.textboxKeyTyped(par1, par2)) { + updateSearch(true); + } else { + super.keyTyped(par1, par2); + } + } + } + + @Override + public void handleMouseInput() { + int mouseScroll = Mouse.getEventDWheel(); + if (mouseScroll == 0) { // Bypass NEI fast transfer manager + super.handleMouseInput(); + } else { + setRowOffset(currentRowOffset + (mouseScroll > 0 ? -1 : 1)); + } + } + + // button: + // 0 -> left mouse + // 1 -> action=0 or 1 -> right mouse + // _____action=5 -> left click dragged over + // 2 -> middle mouse + // 5 -> action=5 -> right click dragged over + // + // action: + // 0 -> click + // 1 -> shift click + // 2 -> swap with slot in hotbar (button is 0-8) + // 3 -> pick block + // 4 -> drop block + // 5 -> dragged stack + // 6 -> double click + @Override + protected void handleMouseClick(Slot slot, int slotIndex, int button, int action) { + if (slotIndex >= 0 && slotIndex < 40) { + onCraftingSlotClick(slot, slotIndex, button, action); + } else { + super.handleMouseClick(slot, slotIndex, button, action); + } + } + + private void onCraftingSlotClick(Slot slot, int slotIndex, int button, int action) { + Ref.LOGGER.trace("Clicked: " + slot.getClass().getSimpleName() + "@" + slotIndex + ", button=" + button + ", action=" + action + ", stack=" + slot.getStack()); + + if (action > 1 || button > 1 || !slot.getHasStack()) { + return; + } + + ItemStack heldStack = mc.thePlayer.inventory.getItemStack(); + ItemStack slotStack = slot.getStack(); + + WrappedRecipe recipe = null; + int recipeIndex = slotIndex + currentRowOffset * 8; + if (recipeIndex >= 0 && shownRecipes != null && recipeIndex < shownRecipes.size()) { + WrappedRecipe r = shownRecipes.get(recipeIndex); + if (StackUtils.areEqualNoSizeNoNBT(r.getOutput(), slotStack) && craftableRecipes != null && craftableRecipes.contains(r)) { + recipe = r; + } + } + if (recipe == null) { + return; + } + + // slotStack already has a stack from recipe.handler.getCraftingResult() + ItemStack finalStack = slotStack.copy(); + int finalStackSize = 0; + + if (heldStack == null) { + finalStackSize = finalStack.stackSize; + } else if (StackUtils.canStack(slotStack, heldStack) == 0) { + finalStackSize = finalStack.stackSize + heldStack.stackSize; + } + + if (finalStackSize > 0) { + boolean isRightClick = button == 1; + boolean isShiftClick = false; + + PacketHandler.INSTANCE.sendToServer(new MessageEasyCrafting(recipe, isRightClick, isShiftClick)); + + if (isRightClick) { // Right click; craft until max stack + int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, heldStack); + int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); + if (timesCrafted > 0) { + finalStack.stackSize = finalStackSize + (timesCrafted - 1) * finalStack.stackSize; + mc.thePlayer.inventory.setItemStack(finalStack); + } + } + else if (isShiftClick) { + finalStack.stackSize = finalStackSize; + mc.thePlayer.inventory.setItemStack(finalStack); + //int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, null); + //int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); + //if (timesCrafted > 0) { + // finalStack.stackSize *= timesCrafted; //ignore finalStackSize; it might contain heldStack size + // InventoryUtils.addItemToInventory(mc.thePlayer.inventory, finalStack); + //} + } + else { // Left click; craft once + finalStack.stackSize = finalStackSize; + mc.thePlayer.inventory.setItemStack(finalStack); + } + } + } + + private void drawSlotBackground(Slot slot, boolean canCraft) { + int x = guiLeft + slot.xDisplayPosition; + int y = guiTop + slot.yDisplayPosition; + int color = canCraft ? 0x8000A000 : 0x80A00000; + Gui.drawRect(x, y, x + 16, y + 16, color); + } + + @SuppressWarnings("unchecked") + private void updateSearch(boolean scrollToTop) { + List all = currentTab == 0 ? craftableRecipes : RecipeManager.getAllRecipes(); + List list = new ArrayList(); + if (all == null || searchField == null) { + return; + } + + LAST_SEARCH = searchField.getText().toLowerCase(); + if (!LAST_SEARCH.trim().isEmpty()) { + for (WrappedRecipe recipe : all) { + try { + List tips = recipe.getOutput().getTooltip(mc.thePlayer, mc.gameSettings.advancedItemTooltips); + for (String tip : tips) { + if (tip.toLowerCase().contains(LAST_SEARCH)) { + list.add(recipe); + break; + } + } + } + catch(NullPointerException ex) + { + Ref.LOGGER.info("Exception on Update Search. Continuing with search" + recipe.getOutput().toString()); + } + } + shownRecipes = list; + } else { + shownRecipes = all; + } + + maxRowOffset = (int) (Math.ceil(shownRecipes.size() / 8.0D) - 5); + maxRowOffset = maxRowOffset < 0 ? 0 : maxRowOffset; + + rebuildCanCraftCache(); + setRowOffset(scrollToTop ? 0 : currentRowOffset); + + } + + + public void refreshCraftingOutput() { + craftableRecipes = ImmutableList.copyOf(RecipeChecker.INSTANCE.recipes); + updateSearch(false); + } + + private void rebuildCanCraftCache() { + canCraftCache = new boolean[shownRecipes.size()]; + for (int i = 0; i < shownRecipes.size(); i++) { + canCraftCache[i] = craftableRecipes.contains(shownRecipes.get(i)); + } + } + + private void setRowOffset(int rowOffset) { + currentRowOffset = MathHelper.clamp_int(rowOffset, 0, maxRowOffset); + currentScrollValue = MathHelper.clamp_float(currentRowOffset / (float) maxRowOffset, 0F, 1F); + setSlots(); + } + + private void setScrollValue(float scrollValue) { + currentScrollValue = MathHelper.clamp_float(scrollValue, 0F, 1F); + currentRowOffset = MathHelper.clamp_int((int) (currentScrollValue * maxRowOffset + 0.5F), 0, maxRowOffset); + setSlots(); + } + + private void setSlots() { + if (shownRecipes != null) { + int offset = currentRowOffset * 8; + for (int i = 0; i < 40; i++) { + if (i + offset >= shownRecipes.size() || i + offset < 0) { + tileInventory.setInventorySlotContents(i, null); + } else { + WrappedRecipe recipe = shownRecipes.get(i + offset); + ItemStack is = recipe.handler.getCraftingResult(recipe, recipe.usedIngredients); + tileInventory.setInventorySlotContents(i, is); + } + } + } + } + + // START NEI + @Override + public List handleTooltip(GuiContainer gui, int mouseX, int mouseY, List currentTip) { + return currentTip; + } + + @Override + public List handleItemDisplayName(GuiContainer gui, ItemStack stack, List currentTip) { + return currentTip; + } + + @Override + public List handleItemTooltip(GuiContainer gui, ItemStack stack, int mouseX, int mouseY, List currentTip) { + if (!drawCustomTooltip(stack, mouseX, mouseY, currentTip)) { + return currentTip; + } + // Hack to always return empty list + return new LinkedList() { + @Override + public int size() { + return 0; + } + }; + } + // END NEI + + @SuppressWarnings("unchecked") + @Override + protected void renderToolTip(ItemStack stack, int mouseX, int mouseY) { + if (!drawCustomTooltip(stack, mouseX, mouseY, (List) stack.getTooltip(mc.thePlayer, mc.gameSettings.advancedItemTooltips))) { + super.renderToolTip(stack, mouseX, mouseY); + } + } + + private boolean drawCustomTooltip(ItemStack stack, int mouseX, int mouseY, List currentTip) { + if (isCtrlKeyDown() && currentTip != null && !currentTip.isEmpty()) { + for (int j = 0; j < 40; j++) { + Slot slot = inventorySlots.getSlot(j); + //isPointInRegion + if (func_146978_c(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, mouseX, mouseY)) { + FontRenderer font = stack.getItem().getFontRenderer(stack); + String itemName = currentTip.get(0); + List list = ImmutableList.of(stack.getRarity().rarityColor + itemName); + drawHoveringText(list, mouseX, mouseY, font == null ? fontRendererObj : font); + + boolean leftSide = mouseX + 12 + fontRendererObj.getStringWidth(itemName) > width; + drawIngredientTooltip(j, mouseX, mouseY, leftSide); + return true; + } + } + } + return false; + } + + private void drawIngredientTooltip(int slotIndex, int mouseX, int mouseY, boolean leftSide) { + + WrappedRecipe recipe = null; + + int recipe_index = slotIndex + currentRowOffset * 8; + if (recipe_index >= 0 && shownRecipes != null && recipe_index < shownRecipes.size()) { + WrappedRecipe r = shownRecipes.get(recipe_index); + if (StackUtils.areCraftingEquivalent(r.getOutput(), inventorySlots.getSlot(slotIndex).getStack())) { + recipe = r; + } + } + + if (recipe == null) { + return; + } + + boolean canCraft = canCraftCache[recipe_index]; + List ingredientList = canCraft && !recipe.usedIngredients.isEmpty() ? StackUtils.collateStacks(recipe.usedIngredients) : recipe.collatedInputs; + + if (ingredientList != null && !ingredientList.isEmpty()) { + int width = 16; + int height = 16; + int xPos = mouseX + 12; + int yPos = mouseY - 12 + 14; + + if (ingredientList.size() > 1) { + width += (ingredientList.size() - 1) * (width + 2); + } + + if (leftSide) { + xPos -= 28 + width; + } + + // red: 0x50FF0000;// green: 0x5000A700;// vanilla purple: 0x505000FF; + int bgColor = 0xF0100010; + int borderColor = canCraft ? 0x5000A700 : 0x50FF0000; + int borderColorDark = (borderColor & 0xFEFEFE) >> 1 | borderColor & 0xFF000000; + + zLevel += 500.0F; + itemRender.zLevel += 500.0F; + + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + + drawGradientRect(xPos - 3, yPos - 4, xPos + width + 3, yPos - 3, bgColor, bgColor); + drawGradientRect(xPos - 3, yPos + height + 3, xPos + width + 3, yPos + height + 4, bgColor, bgColor); + drawGradientRect(xPos - 3, yPos - 3, xPos + width + 3, yPos + height + 3, bgColor, bgColor); + drawGradientRect(xPos - 4, yPos - 3, xPos - 3, yPos + height + 3, bgColor, bgColor); + drawGradientRect(xPos + width + 3, yPos - 3, xPos + width + 4, yPos + height + 3, bgColor, bgColor); + + drawGradientRect(xPos - 3, yPos - 3 + 1, xPos - 3 + 1, yPos + height + 3 - 1, borderColor, borderColorDark); + drawGradientRect(xPos + width + 2, yPos - 3 + 1, xPos + width + 3, yPos + height + 3 - 1, borderColor, borderColorDark); + drawGradientRect(xPos - 3, yPos - 3, xPos + width + 3, yPos - 3 + 1, borderColor, borderColor); + drawGradientRect(xPos - 3, yPos + height + 2, xPos + width + 3, yPos + height + 3, borderColorDark, borderColorDark); + + RenderHelper.enableGUIStandardItemLighting(); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + + for (WrappedStack ws : ingredientList) { + renderItem(xPos, yPos, ws); + xPos += 18; + } + + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glDisable(GL11.GL_LIGHTING); + + zLevel -= 500.0F; + itemRender.zLevel -= 500.0F; + } + } + + private void renderItem(int xPos, int yPos, WrappedStack ws) { + ItemStack is = null; + + int count = 0; + for (ItemStack stack : ws.stacks) { + if (stack.getItemDamage() == OreDictionary.WILDCARD_VALUE && stack.getHasSubtypes()) { + count += ItemMap.get(stack.getItem()).size(); + } else { + count++; + } + } + + int num = (int) ((mc.theWorld.getTotalWorldTime() / 10) % count); + + count = 0; + for (ItemStack stack : ws.stacks) { + if (stack.getItemDamage() == OreDictionary.WILDCARD_VALUE && stack.getHasSubtypes()) { + List all = ItemMap.get(stack.getItem()); + if (num >= count && num < count + all.size()) { + is = StackUtils.copyStack(all.get(num - count), ws.size); + break; + } + count += all.size(); + } else { + if (num == count) { + is = StackUtils.copyStack(stack, ws.size); + break; + } + count++; + } + } + + // + if (is != null) { + itemRender.renderItemAndEffectIntoGUI(fontRendererObj, mc.renderEngine, is, xPos, yPos); + itemRender.renderItemOverlayIntoGUI(fontRendererObj, mc.renderEngine, is, xPos, yPos); + } else { + Ref.LOGGER.warn("Error rendering stack in recipe tooltip: is == null"); + } + } } \ No newline at end of file diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java index 5416a5f..7dabaca 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java @@ -19,122 +19,122 @@ @SideOnly(Side.CLIENT) public enum RecipeChecker { - INSTANCE; - - private Minecraft mc = FMLClientHandler.instance().getClient(); - - public volatile boolean requested = false; - private volatile boolean displayed = true; - private volatile boolean suspended = false; - public volatile boolean done = false; - - public volatile List recipes = ImmutableList.of(); - - private Thread worker = null; - - @SubscribeEvent - public void tickEnd(TickEvent.ClientTickEvent event) { - if (event.phase == TickEvent.Phase.END && mc.theWorld != null) { - if (worker == null || !worker.isAlive()) { - worker = new Thread(new CraftabilityChecker(), Ref.MOD_ID + "-" + CraftabilityChecker.class.getSimpleName()); - worker.setDaemon(true); - worker.start(); - Ref.LOGGER.info("Worker thread spawned."); - } - if (!displayed && !requested && done) { - if (mc.currentScreen instanceof GuiEasyCrafting) { - GuiEasyCrafting gec = (GuiEasyCrafting) mc.currentScreen; - gec.refreshCraftingOutput(); - displayed = true; - } - } - } - } - - private class CraftabilityChecker implements Runnable { - - @Override - public void run() { - while (true) { - if (requested) { - requested = false; - displayed = false; - suspended = false; - done = false; - - setCraftableRecipes(); - } - - try { - Thread.sleep(50L); - } catch (InterruptedException ignored) { - } - } - } - - private void setCraftableRecipes() { - InventoryPlayer inventory = mc.thePlayer.inventory; - recipes = getCraftableRecipes(inventory, ConfigHandler.MAX_RECURSION, ConfigHandler.MAX_TIME, RecipeManager.getAllRecipes()); - done = !suspended; - } - - private List getCraftableRecipes(IInventory inventory, int maxRecursion, long maxTime, List recipesToCheck) { - long startTime = System.currentTimeMillis(); - - List craftable = new LinkedList(); - List tmpAll = new LinkedList(recipesToCheck); - - // TODO: timeout - // TODO: on gui when you press shift calc all the base ingredients from the inventory you need for all crafting - // steps not just the last recipe (also color overlay the slots you take from) - - for (WrappedRecipe wr : tmpAll) { - if (requested) { - suspended = true; - return ImmutableList.of(); - } - if (RecipeHelper.canCraft(wr, inventory)) { - craftable.add(wr); - } - } - tmpAll.removeAll(craftable); - - if (!craftable.isEmpty()) { - for (int recursion = 0; recursion < maxRecursion; recursion++) { - if (requested) { - suspended = true; - return ImmutableList.of(); - } - if (tmpAll.isEmpty()) { - break; - } - - List tmpCraftable = new LinkedList(craftable); - for (WrappedRecipe wr : tmpAll) { - if (requested) { - suspended = true; - return ImmutableList.of(); - } - if (RecipeHelper.canCraft(wr, inventory, tmpCraftable, maxRecursion)) { - craftable.add(wr); - } - } - tmpAll.removeAll(craftable); - - if (tmpCraftable.size() == craftable.size()) { - break; - } - } - } - - if (requested) { - suspended = true; - return ImmutableList.of(); - } - - Collections.sort(craftable, WrappedRecipe.Sorter.INSTANCE); - Ref.LOGGER.info(String.format("%d/%d craftable | %.4f seconds", craftable.size(), recipesToCheck.size(), (System.currentTimeMillis() - startTime) / 1000.0D)); - return craftable; - } - } + INSTANCE; + + private Minecraft mc = FMLClientHandler.instance().getClient(); + + public volatile boolean requested = false; + private volatile boolean displayed = true; + private volatile boolean suspended = false; + public volatile boolean done = false; + + public volatile List recipes = ImmutableList.of(); + + private Thread worker = null; + + @SubscribeEvent + public void tickEnd(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END && mc.theWorld != null) { + if (worker == null || !worker.isAlive()) { + worker = new Thread(new CraftabilityChecker(), Ref.MOD_ID + "-" + CraftabilityChecker.class.getSimpleName()); + worker.setDaemon(true); + worker.start(); + Ref.LOGGER.info("Worker thread spawned."); + } + if (!displayed && !requested && done) { + if (mc.currentScreen instanceof GuiEasyCrafting) { + GuiEasyCrafting gec = (GuiEasyCrafting) mc.currentScreen; + gec.refreshCraftingOutput(); + displayed = true; + } + } + } + } + + private class CraftabilityChecker implements Runnable { + + @Override + public void run() { + while (true) { + if (requested) { + requested = false; + displayed = false; + suspended = false; + done = false; + + setCraftableRecipes(); + } + + try { + Thread.sleep(50L); + } catch (InterruptedException ignored) { + } + } + } + + private void setCraftableRecipes() { + InventoryPlayer inventory = mc.thePlayer.inventory; + recipes = getCraftableRecipes(inventory, ConfigHandler.MAX_RECURSION, ConfigHandler.MAX_TIME, RecipeManager.getAllRecipes()); + done = !suspended; + } + + private List getCraftableRecipes(IInventory inventory, int maxRecursion, long maxTime, List recipesToCheck) { + long startTime = System.currentTimeMillis(); + + List craftable = new LinkedList(); + List tmpAll = new LinkedList(recipesToCheck); + + // TODO: timeout + // TODO: on gui when you press shift calc all the base ingredients from the inventory you need for all crafting + // steps not just the last recipe (also color overlay the slots you take from) + + for (WrappedRecipe wr : tmpAll) { + if (requested) { + suspended = true; + return ImmutableList.of(); + } + if (RecipeHelper.canCraft(wr, inventory)) { + craftable.add(wr); + } + } + tmpAll.removeAll(craftable); + + if (!craftable.isEmpty()) { + for (int recursion = 0; recursion < maxRecursion; recursion++) { + if (requested) { + suspended = true; + return ImmutableList.of(); + } + if (tmpAll.isEmpty()) { + break; + } + + List tmpCraftable = new LinkedList(craftable); + for (WrappedRecipe wr : tmpAll) { + if (requested) { + suspended = true; + return ImmutableList.of(); + } + if (RecipeHelper.canCraft(wr, inventory, tmpCraftable, maxRecursion)) { + craftable.add(wr); + } + } + tmpAll.removeAll(craftable); + + if (tmpCraftable.size() == craftable.size()) { + break; + } + } + } + + if (requested) { + suspended = true; + return ImmutableList.of(); + } + + Collections.sort(craftable, WrappedRecipe.Sorter.INSTANCE); + Ref.LOGGER.info(String.format("%d/%d craftable | %.4f seconds", craftable.size(), recipesToCheck.size(), (System.currentTimeMillis() - startTime) / 1000.0D)); + return craftable; + } + } } diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java index 0287fc8..0e5dca1 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java @@ -1,5 +1,6 @@ package net.lepko.easycrafting.core.recipe; +import net.lepko.easycrafting.Ref; import net.lepko.easycrafting.core.util.InventoryUtils; import net.lepko.easycrafting.core.util.StackUtils; import net.minecraft.inventory.IInventory; @@ -12,204 +13,205 @@ public class RecipeHelper { - /** - * Check if a recipe can be crafted with the ingredients from the inventory. - */ - public static boolean canCraft(WrappedRecipe recipe, IInventory inventory) { - return canCraft(recipe, inventory, null, false, 1, 0) > 0; - } - - /** - * Check if a recipe can be crafted with the ingredients from the inventory. If an ingredient is missing try to craft it from a list of recipes. - */ - public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, List recipesToCheck, int recursion) { - return canCraft(recipe, inventory, recipesToCheck, false, 1, recursion) > 0; - } - - /** - * Check if a recipe can be crafted with the ingredients from the inventory. If an ingredient is missing try to craft it from a list of recipes. - * - * @param recipe - recipe to check - * @param inventory - inventory to use the ingredients from - * @param recipesToCheck - a list of recipes to try and craft from if an ingredient is missing - * @param take - whether or not to take the ingredients from the inventory - * @param recursion - how deep to recurse while trying to craft an ingredient (must be nonnegative) - */ - public static int canCraft(WrappedRecipe recipe, IInventory inventory, List recipesToCheck, boolean take, int maxTimes, int recursion) { - if (recursion < 0) { - return 0; - } - - recipe.usedIngredients.clear(); - - int invSize = InventoryUtils.getMainInventorySize(inventory); - InventoryBasic tmp = new InventoryBasic("tmp", true, invSize); - InventoryBasic tmp2 = new InventoryBasic("tmp2", true, invSize); - InventoryUtils.setContents(tmp, inventory); - - int timesCrafted = 0; - timesLoop: - while (timesCrafted < maxTimes) { - iiLoop: - for (int ii = 0; ii < recipe.inputs.size(); ii++) { - if (recipe.inputs.get(ii) instanceof ItemStack) { - ItemStack ingredient = (ItemStack) recipe.inputs.get(ii); - int inventoryIndex = isItemInInventory(ingredient, recipe, tmp); - if (inventoryIndex != -1 && InventoryUtils.consumeItemForCrafting(tmp, inventoryIndex, recipe.usedIngredients)) { - continue iiLoop; - } - // ingredient is not in inventory, can we craft it? - if (recipesToCheck != null && recursion > 0) { - List list = getRecipesForItemFromList(ingredient, recipe, recipesToCheck); - for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, recipesToCheck, true, 1, recursion - 1) > 0) { - ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); - is.stackSize--; - if (is.stackSize > 0 && !InventoryUtils.addItemToInventory(tmp, is)) { - break timesLoop; - } - ItemStack usedItemStack = is.copy(); - usedItemStack.stackSize = 1; - recipe.usedIngredients.add(usedItemStack); - continue iiLoop; - } - } - } - // ingredient is not in inventory and we can't craft it! - break timesLoop; - } else if (recipe.inputs.get(ii) instanceof List) { - @SuppressWarnings("unchecked") - List ingredients = (List) recipe.inputs.get(ii); - int inventoryIndex = isItemInInventory(ingredients, recipe, tmp); - if (inventoryIndex != -1 && InventoryUtils.consumeItemForCrafting(tmp, inventoryIndex, recipe.usedIngredients)) { - continue iiLoop; - } - // ingredient is not in inventory, can we craft it? - if (recipesToCheck != null && recursion > 0) { - List list = getRecipesForItemFromList(ingredients, recipe, recipesToCheck); - for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, recipesToCheck, true, 1, recursion - 1) > 0) { - ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); - is.stackSize--; - if (is.stackSize > 0 && !InventoryUtils.addItemToInventory(tmp, is)) { - break timesLoop; - } - ItemStack usedItemStack = is.copy(); - usedItemStack.stackSize = 1; - recipe.usedIngredients.add(usedItemStack); - continue iiLoop; - } - } - } - // - break timesLoop; - } - } - - timesCrafted++; - InventoryUtils.setContents(tmp2, tmp); - } - - if (timesCrafted > 0) { - if (take) { - InventoryUtils.setContents(inventory, tmp2); - } - } - return timesCrafted; - } - - private static int isItemInInventory(ItemStack is, WrappedRecipe recipe, IInventory inv) { - int size = InventoryUtils.getMainInventorySize(inv); - for (int i = 0; i < size; i++) { - ItemStack candidate = inv.getStackInSlot(i); - if (candidate != null && recipe.handler.matchItem(is, candidate, recipe)) { - return i; - } - } - return -1; - } - - private static int isItemInInventory(List ing, WrappedRecipe recipe, IInventory inv) { - for (ItemStack is : ing) { - int slot = isItemInInventory(is, recipe, inv); - if (slot != -1) { - return slot; - } - } - return -1; - } - - private static List getRecipesForItemFromList(ItemStack ingredient, WrappedRecipe recipe, List recipesToCheck) { - List list = new LinkedList(); - for (WrappedRecipe wr : recipesToCheck) { - if (recipe.handler.matchItem(ingredient, wr.getOutput(), recipe)) { - list.add(wr); - } - } - return list; - } - - private static List getRecipesForItemFromList(List ingredients, WrappedRecipe recipe, List recipesToCheck) { - List list = new LinkedList(); - for (ItemStack is : ingredients) { - list.addAll(getRecipesForItemFromList(is, recipe, recipesToCheck)); - } - return list; - } - - /** - * Get the recipe that matches provided result and ingredients. - */ - public static WrappedRecipe getValidRecipe(ItemStack result, ItemStack[] ingredients) { - List all = RecipeManager.getAllRecipes(); - allLoop: - for (WrappedRecipe wr : all) { - if (StackUtils.areEqualNoSizeNoNBT(wr.getOutput(), result) && wr.inputs.size() == ingredients.length) { - ingLoop: - for (int i = 0; i < ingredients.length; i++) { - if (wr.inputs.get(i) instanceof ItemStack) { - ItemStack is = (ItemStack) wr.inputs.get(i); - if (!StackUtils.areCraftingEquivalent(is, ingredients[i])) { - continue allLoop; - } - } else if (wr.inputs.get(i) instanceof List) { - if (ingredients[i].getItem() == null) { - return null; - } - @SuppressWarnings("unchecked") - List ingList = (List) wr.inputs.get(i); - if (ingList.isEmpty()) { - return null; - } - for (ItemStack is : ingList) { - if (StackUtils.areCraftingEquivalent(is, ingredients[i])) { - continue ingLoop; - } - } - continue allLoop; - } - } - return wr; - } - } - return null; - } - - /** - * How many times can we fit the resulting itemstack in players hand. - * - * @param result itemstack we are trying to fit - * @param inHand itemstack currently in hand - */ - public static int calculateCraftingMultiplierUntilMaxStack(ItemStack result, ItemStack inHand) { - int maxTimes = MathHelper.floor_double(result.getMaxStackSize() / (double) result.stackSize); - if (inHand != null) { - int diff = result.getMaxStackSize() - (maxTimes * result.stackSize); - while (inHand.stackSize > diff) { - maxTimes--; - diff += result.stackSize; - } - } - return maxTimes; - } + /** + * Check if a recipe can be crafted with the ingredients from the inventory. + */ + public static boolean canCraft(WrappedRecipe recipe, IInventory inventory) { + return canCraft(recipe, inventory, null, false, 1, 0) > 0; + } + + /** + * Check if a recipe can be crafted with the ingredients from the inventory. If an ingredient is missing try to craft it from a list of recipes. + */ + public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, List recipesToCheck, int recursion) { + return canCraft(recipe, inventory, recipesToCheck, false, 1, recursion) > 0; + } + + /** + * Check if a recipe can be crafted with the ingredients from the inventory. If an ingredient is missing try to craft it from a list of recipes. + * + * @param recipe - recipe to check + * @param inventory - inventory to use the ingredients from + * @param recipesToCheck - a list of recipes to try and craft from if an ingredient is missing + * @param take - whether or not to take the ingredients from the inventory + * @param recursion - how deep to recurse while trying to craft an ingredient (must be nonnegative) + */ + public static int canCraft(WrappedRecipe recipe, IInventory inventory, List recipesToCheck, boolean take, int maxTimes, int recursion) { + if (recursion < 0) { + return 0; + } + + recipe.usedIngredients.clear(); + + int invSize = InventoryUtils.getMainInventorySize(inventory); + InventoryBasic tmp = new InventoryBasic("tmp", true, invSize); + InventoryBasic tmp2 = new InventoryBasic("tmp2", true, invSize); + InventoryUtils.setContents(tmp, inventory); + + + int timesCrafted = 0; + timesLoop: + while (timesCrafted < maxTimes) { + iiLoop: + for (int ii = 0; ii < recipe.inputs.size(); ii++) { + if (recipe.inputs.get(ii) instanceof ItemStack) { + ItemStack ingredient = (ItemStack) recipe.inputs.get(ii); + int inventoryIndex = isItemInInventory(ingredient, recipe, tmp); + if (inventoryIndex != -1 && InventoryUtils.consumeItemForCrafting(tmp, inventoryIndex, recipe.usedIngredients)) { + continue iiLoop; + } + // ingredient is not in inventory, can we craft it? + if (recipesToCheck != null && recursion > 0) { + List list = getRecipesForItemFromList(ingredient, recipe, recipesToCheck); + for (WrappedRecipe wr : list) { + if (canCraft(wr, tmp, recipesToCheck, true, 1, recursion - 1) > 0) { + ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); + is.stackSize--; + if (is.stackSize > 0 && !InventoryUtils.addItemToInventory(tmp, is)) { + break timesLoop; + } + ItemStack usedItemStack = is.copy(); + usedItemStack.stackSize = 1; + recipe.usedIngredients.add(usedItemStack); + continue iiLoop; + } + } + } + // ingredient is not in inventory and we can't craft it! + break timesLoop; + } else if (recipe.inputs.get(ii) instanceof List) { + @SuppressWarnings("unchecked") + List ingredients = (List) recipe.inputs.get(ii); + int inventoryIndex = isItemInInventory(ingredients, recipe, tmp); + if (inventoryIndex != -1 && InventoryUtils.consumeItemForCrafting(tmp, inventoryIndex, recipe.usedIngredients)) { + continue iiLoop; + } + // ingredient is not in inventory, can we craft it? + if (recipesToCheck != null && recursion > 0) { + List list = getRecipesForItemFromList(ingredients, recipe, recipesToCheck); + for (WrappedRecipe wr : list) { + if (canCraft(wr, tmp, recipesToCheck, true, 1, recursion - 1) > 0) { + ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); + is.stackSize--; + if (is.stackSize > 0 && !InventoryUtils.addItemToInventory(tmp, is)) { + break timesLoop; + } + ItemStack usedItemStack = is.copy(); + usedItemStack.stackSize = 1; + recipe.usedIngredients.add(usedItemStack); + continue iiLoop; + } + } + } + // + break timesLoop; + } + } + + timesCrafted++; + InventoryUtils.setContents(tmp2, tmp); + } + + if (timesCrafted > 0) { + if (take) { + InventoryUtils.setContents(inventory, tmp2); + } + } + return timesCrafted; + } + + private static int isItemInInventory(ItemStack is, WrappedRecipe recipe, IInventory inv) { + int size = InventoryUtils.getMainInventorySize(inv); + for (int i = 0; i < size; i++) { + ItemStack candidate = inv.getStackInSlot(i); + if (candidate != null && recipe.handler.matchItem(is, candidate, recipe)) { + return i; + } + } + return -1; + } + + private static int isItemInInventory(List ing, WrappedRecipe recipe, IInventory inv) { + for (ItemStack is : ing) { + int slot = isItemInInventory(is, recipe, inv); + if (slot != -1) { + return slot; + } + } + return -1; + } + + private static List getRecipesForItemFromList(ItemStack ingredient, WrappedRecipe recipe, List recipesToCheck) { + List list = new LinkedList(); + for (WrappedRecipe wr : recipesToCheck) { + if (recipe.handler.matchItem(ingredient, wr.getOutput(), recipe)) { + list.add(wr); + } + } + return list; + } + + private static List getRecipesForItemFromList(List ingredients, WrappedRecipe recipe, List recipesToCheck) { + List list = new LinkedList(); + for (ItemStack is : ingredients) { + list.addAll(getRecipesForItemFromList(is, recipe, recipesToCheck)); + } + return list; + } + + /** + * Get the recipe that matches provided result and ingredients. + */ + public static WrappedRecipe getValidRecipe(ItemStack result, ItemStack[] ingredients) { + List all = RecipeManager.getAllRecipes(); + allLoop: + for (WrappedRecipe wr : all) { + if (StackUtils.areEqualNoSizeNoNBT(wr.getOutput(), result) && wr.inputs.size() == ingredients.length) { + ingLoop: + for (int i = 0; i < ingredients.length; i++) { + if (wr.inputs.get(i) instanceof ItemStack) { + ItemStack is = (ItemStack) wr.inputs.get(i); + if (!StackUtils.areCraftingEquivalent(is, ingredients[i])) { + continue allLoop; + } + } else if (wr.inputs.get(i) instanceof List) { + if (ingredients[i].getItem() == null) { + return null; + } + @SuppressWarnings("unchecked") + List ingList = (List) wr.inputs.get(i); + if (ingList.isEmpty()) { + return null; + } + for (ItemStack is : ingList) { + if (StackUtils.areCraftingEquivalent(is, ingredients[i])) { + continue ingLoop; + } + } + continue allLoop; + } + } + return wr; + } + } + return null; + } + + /** + * How many times can we fit the resulting itemstack in players hand. + * + * @param result itemstack we are trying to fit + * @param inHand itemstack currently in hand + */ + public static int calculateCraftingMultiplierUntilMaxStack(ItemStack result, ItemStack inHand) { + int maxTimes = MathHelper.floor_double(result.getMaxStackSize() / (double) result.stackSize); + if (inHand != null) { + int diff = result.getMaxStackSize() - (maxTimes * result.stackSize); + while (inHand.stackSize > diff) { + maxTimes--; + diff += result.stackSize; + } + } + return maxTimes; + } } diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java index c63047d..f4acd99 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java @@ -1,6 +1,7 @@ package net.lepko.easycrafting.core.recipe; import com.google.common.collect.ImmutableList; + import net.lepko.easycrafting.Ref; import net.lepko.easycrafting.core.recipe.handler.*; import net.minecraft.entity.player.EntityPlayer; @@ -10,96 +11,137 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.IRecipe; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityClientPlayerMP; +import net.minecraft.client.gui.inventory.GuiContainer; + + + + + import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; public class RecipeManager { - public static final List HANDLERS = new LinkedList(); - - static { - // Mod recipe classes could extend vanilla classes so scan them first - HANDLERS.add(new IC2RecipeHandler()); - HANDLERS.add(new ForestryRecipeHandler()); - HANDLERS.add(new MekanismRecipeHandler()); - - // At the end scan vanilla and forge - HANDLERS.add(new VanillaRecipeHandler()); - HANDLERS.add(new ForgeRecipeHandler()); - } - - private static final List allRecipes = new LinkedList(); - private static int prevListSize = 0; - private static IRecipe prevLastElement = null; - - private static boolean shouldScan(List recipes) { - if (allRecipes.isEmpty()) { - return true; - } - // XXX: Investigate issues with mods adding recipes too late at some point in the future. - if (prevListSize != recipes.size() || (!recipes.isEmpty() && prevLastElement != recipes.get(recipes.size() - 1))) { - Ref.LOGGER.warn("|~| A MOD IS ADDING RECIPES TOO LATE |~| Class=" + recipes.get(recipes.size() - 1).getClass().getCanonicalName()); - return true; - } - return false; - } - - public static void scanRecipes() { - @SuppressWarnings("unchecked") - List recipes = CraftingManager.getInstance().getRecipeList(); - if (!shouldScan(recipes)) { - return; - } - prevListSize = recipes.size(); - prevLastElement = recipes.get(recipes.size() - 1); - - allRecipes.clear(); - - long startTime = System.nanoTime(); - int fails = 0; - - for (IRecipe r : recipes) { - WrappedRecipe wr = WrappedRecipe.of(r); - if (wr != null) { - allRecipes.add(wr); - } else { - fails++; - } - } - - Collections.sort(allRecipes, WrappedRecipe.Sorter.INSTANCE); - - Ref.LOGGER.info(String.format("Scanned %d recipes (%d failed) in %.8f seconds", recipes.size(), fails, (System.nanoTime() - startTime) / 1000000000.0D)); - } - - public static List getAllRecipes() { - return ImmutableList.copyOf(allRecipes); - } - - /** - * Only use the inventory that is returned from this method if IRecipe.getCraftingResult() does not check for validity of pattern in crafting inventory slots. - */ - public static InventoryCrafting getCraftingInventory(List usedIngredients) { - InventoryCrafting ic = new InventoryCrafting(new Container() { - @Override - public boolean canInteractWith(EntityPlayer p_75145_1_) { - return false; - } - - @Override - public void onCraftMatrixChanged(IInventory p_75130_1_) { - //NO-OP - } - }, 3, 3); - for (int i = 0; i < 9; i++) { - if (i < usedIngredients.size()) { - ic.setInventorySlotContents(i, usedIngredients.get(i)); - } else { - ic.setInventorySlotContents(i, null); - } - } - return ic; - } + public static final List HANDLERS = new LinkedList(); + + static { + // Mod recipe classes could extend vanilla classes so scan them first + HANDLERS.add(new IC2RecipeHandler()); + HANDLERS.add(new ForestryRecipeHandler()); + HANDLERS.add(new MekanismRecipeHandler()); + + // At the end scan vanilla and forge + HANDLERS.add(new VanillaRecipeHandler()); + HANDLERS.add(new ForgeRecipeHandler()); + } + private static final List allRecipes = new LinkedList(); + private static int prevListSize = 0; + private static IRecipe prevLastElement = null; + + private static boolean shouldScan(List recipes) { + if (allRecipes.isEmpty()) { + return true; + } + // XXX: Investigate issues with mods adding recipes too late at some + // point in the future. + if (prevListSize != recipes.size() + || (!recipes.isEmpty() && prevLastElement != recipes + .get(recipes.size() - 1))) { + Ref.LOGGER.warn("|~| A MOD IS ADDING RECIPES TOO LATE |~| Class=" + + recipes.get(recipes.size() - 1).getClass() + .getCanonicalName()); + return true; + } + return false; + } + + public static void scanRecipes() { + @SuppressWarnings("unchecked") + List recipes = CraftingManager.getInstance().getRecipeList(); + if (!shouldScan(recipes)) { + return; + } + prevListSize = recipes.size(); + prevLastElement = recipes.get(recipes.size() - 1); + + allRecipes.clear(); + + long startTime = System.nanoTime(); + int fails = 0; + HashMap recipeExists = new HashMap(); + for (IRecipe r : recipes) { + WrappedRecipe wr = WrappedRecipe.of(r); + if (wr != null && !CheckIfRecipeAlreadyExists(allRecipes, wr,recipeExists)) + { + allRecipes.add(wr); + } else { + fails++; + } + } + + Collections.sort(allRecipes, WrappedRecipe.Sorter.INSTANCE); + + + Ref.LOGGER.info(String.format( + "Scanned %d recipes (%d failed) in %.8f seconds", + recipes.size(), fails, + (System.nanoTime() - startTime) / 1000000000.0D)); + } + + public static List getAllRecipes() { + return ImmutableList.copyOf(allRecipes); + } + + /** + * Only use the inventory that is returned from this method if + * IRecipe.getCraftingResult() does not check for validity of pattern in + * crafting inventory slots. + */ + public static InventoryCrafting getCraftingInventory( + List usedIngredients) { + InventoryCrafting ic = new InventoryCrafting(new Container() { + @Override + public boolean canInteractWith(EntityPlayer p_75145_1_) { + return false; + } + + @Override + public void onCraftMatrixChanged(IInventory p_75130_1_) { + // NO-OP + } + }, 3, 3); + for (int i = 0; i < 9; i++) { + if (i < usedIngredients.size()) { + ic.setInventorySlotContents(i, usedIngredients.get(i)); + } else { + ic.setInventorySlotContents(i, null); + } + } + return ic; + } + + public static boolean CheckIfRecipeAlreadyExists(List wr, WrappedRecipe newrecipe,HashMap recipeExists) + { + try { + if (wr.size() > 0) + { + String i = newrecipe.getOutput().toString(); + if (recipeExists.get(i) != null) + { + return true; + } + recipeExists.put(i, ""); + } + return false; + } + catch (NullPointerException ex) + { + return true; + } + } } diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java b/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java index 0c59b10..1dded76 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java @@ -15,125 +15,125 @@ public class WrappedRecipe { - public final IRecipe recipe; - public final List inputs; - public final List collatedInputs; - private final WrappedStack output; - public final IRecipeHandler handler; - public final List usedIngredients; + public final IRecipe recipe; + public final List inputs; + public final List collatedInputs; + public final WrappedStack output; + public final IRecipeHandler handler; + public final List usedIngredients; - private WrappedRecipe(IRecipe recipe, List inputs, WrappedStack output, IRecipeHandler handler) { - this.recipe = recipe; - this.inputs = inputs; - this.collatedInputs = StackUtils.collateStacks(inputs); - this.output = output; - this.handler = handler; - this.usedIngredients = new ArrayList(9); - } + private WrappedRecipe(IRecipe recipe, List inputs, WrappedStack output, IRecipeHandler handler) { + this.recipe = recipe; + this.inputs = inputs; + this.collatedInputs = StackUtils.collateStacks(inputs); + this.output = output; + this.handler = handler; + this.usedIngredients = new ArrayList(9); + } - public ItemStack getOutput() { - return StackUtils.copyStack(output.stacks.get(0), output.size); - } + public ItemStack getOutput() { + return StackUtils.copyStack(output.stacks.get(0), output.size); + } - /** - * If recipe is valid, adds the recipe to the list and returns the WrappedRecipe instance. - */ - public static WrappedRecipe of(IRecipe recipe) { - if (recipe == null) { - warn("recipe is null"); - return null; - } - if (recipe.getRecipeOutput() == null) { - warn("recipe output is null", recipe); - return null; - } - if (recipe.getRecipeOutput().getItem() == null) { - warn("recipe output item is null [id=" + recipe.getRecipeOutput().getItem() + "]", recipe); - return null; - } - List inputs = null; - IRecipeHandler handler = null; - for (IRecipeHandler h : RecipeManager.HANDLERS) { - inputs = h.getInputs(recipe); - if (inputs != null) { - handler = h; - break; - } - } + /** + * If recipe is valid, adds the recipe to the list and returns the WrappedRecipe instance. + */ + public static WrappedRecipe of(IRecipe recipe) { + if (recipe == null) { + warn("recipe is null"); + return null; + } + if (recipe.getRecipeOutput() == null) { + warn("recipe output is null", recipe); + return null; + } + if (recipe.getRecipeOutput().getItem() == null) { + warn("recipe output item is null [id=" + recipe.getRecipeOutput().getItem() + "]", recipe); + return null; + } + List inputs = null; + IRecipeHandler handler = null; + for (IRecipeHandler h : RecipeManager.HANDLERS) { + inputs = h.getInputs(recipe); + if (inputs != null) { + handler = h; + break; + } + } - if (inputs == null) { - warn("failed to get recipe input list", recipe); - return null; - } - inputs.removeAll(Collections.singleton(null)); - if (inputs.isEmpty()) { - warn("recipe input list is empty", recipe); - return null; - } - for (Object o : inputs) { - if (o instanceof List) { - List list = (List) o; - if (list.isEmpty()) { - warn("one of recipe inputs is an empty list", recipe); - return null; - } else { - for (Object p : list) { - if (p instanceof ItemStack) { - ItemStack stack = (ItemStack) p; - if (stack.getItem() == null) { - warn("one of recipe input items is null [id=" + stack.getItem() + "]", recipe); - return null; - } - stack.stackSize = 1; - } else { - warn("one of recipe inputs is unknown", o, recipe); - return null; - } - } - } - } else { - if (o instanceof ItemStack) { - ItemStack stack = (ItemStack) o; - if (stack.getItem() == null) { - warn("one of recipe input items is null [id=" + stack.getItem() + "]", recipe); - return null; - } - stack.stackSize = 1; - } else { - warn("one of recipe inputs is unknown", o, recipe); - return null; - } - } - } - return new WrappedRecipe(recipe, inputs, new WrappedStack(recipe.getRecipeOutput()), handler); - } + if (inputs == null) { + warn("failed to get recipe input list", recipe); + return null; + } + inputs.removeAll(Collections.singleton(null)); + if (inputs.isEmpty()) { + warn("recipe input list is empty", recipe); + return null; + } + for (Object o : inputs) { + if (o instanceof List) { + List list = (List) o; + if (list.isEmpty()) { + warn("one of recipe inputs is an empty list", recipe); + return null; + } else { + for (Object p : list) { + if (p instanceof ItemStack) { + ItemStack stack = (ItemStack) p; + if (stack.getItem() == null) { + warn("one of recipe input items is null [id=" + stack.getItem() + "]", recipe); + return null; + } + stack.stackSize = 1; + } else { + warn("one of recipe inputs is unknown", o, recipe); + return null; + } + } + } + } else { + if (o instanceof ItemStack) { + ItemStack stack = (ItemStack) o; + if (stack.getItem() == null) { + warn("one of recipe input items is null [id=" + stack.getItem() + "]", recipe); + return null; + } + stack.stackSize = 1; + } else { + warn("one of recipe inputs is unknown", o, recipe); + return null; + } + } + } + return new WrappedRecipe(recipe, inputs, new WrappedStack(recipe.getRecipeOutput()), handler); + } - private static void warn(String msg, Object... objs) { - String s = "[WrappedRecipe] " + msg; - for (Object o : objs) { - s += " (" + o.getClass().getCanonicalName() + ")"; - } - Ref.LOGGER.warn(s); - } + private static void warn(String msg, Object... objs) { + String s = "[WrappedRecipe] " + msg; + for (Object o : objs) { + s += " (" + o.getClass().getCanonicalName() + ")"; + } + Ref.LOGGER.warn(s); + } - public static enum Sorter implements Comparator { - INSTANCE; + public static enum Sorter implements Comparator { + INSTANCE; - @Override - public int compare(WrappedRecipe first, WrappedRecipe second) { - ItemStack is1 = first.getOutput(); - ItemStack is2 = second.getOutput(); - int compareName = is1.getItem().getUnlocalizedName(is1).compareTo(is2.getItem().getUnlocalizedName(is2)); - if (compareName != 0) { - return compareName; - } else { - int compareDamage = Ints.compare(is1.getItemDamage(), is2.getItemDamage()); - if (compareDamage != 0) { - return compareDamage; - } else { - return Ints.compare(is1.stackSize, is2.stackSize) * -1; - } - } - } - } + @Override + public int compare(WrappedRecipe first, WrappedRecipe second) { + ItemStack is1 = first.getOutput(); + ItemStack is2 = second.getOutput(); + int compareName = is1.getItem().getUnlocalizedName(is1).compareTo(is2.getItem().getUnlocalizedName(is2)); + if (compareName != 0) { + return compareName; + } else { + int compareDamage = Ints.compare(is1.getItemDamage(), is2.getItemDamage()); + if (compareDamage != 0) { + return compareDamage; + } else { + return Ints.compare(is1.stackSize, is2.stackSize) * -1; + } + } + } + } } diff --git a/src/main/java/net/lepko/easycrafting/core/util/InventoryUtils.java b/src/main/java/net/lepko/easycrafting/core/util/InventoryUtils.java index 5f857b5..43a63b2 100644 --- a/src/main/java/net/lepko/easycrafting/core/util/InventoryUtils.java +++ b/src/main/java/net/lepko/easycrafting/core/util/InventoryUtils.java @@ -16,275 +16,275 @@ public class InventoryUtils { - private static final Random RNG = new Random(); - private static final int PLAYER_INVENTORY_SIZE = 36; + private static final Random RNG = new Random(); + private static final int PLAYER_INVENTORY_SIZE = 36; - /** - * Get the size of the main inventory, without armor slots. - * - * @param inv - the inventory to check - * @return size of the inventory, or in case of {@link InventoryPlayer} PLAYER_INVENTORY_SIZE - */ - public static int getMainInventorySize(IInventory inv) { - if (inv instanceof InventoryPlayer) { - return PLAYER_INVENTORY_SIZE; - } - return inv.getSizeInventory(); - } + /** + * Get the size of the main inventory, without armor slots. + * + * @param inv - the inventory to check + * @return size of the inventory, or in case of {@link InventoryPlayer} PLAYER_INVENTORY_SIZE + */ + public static int getMainInventorySize(IInventory inv) { + if (inv instanceof InventoryPlayer) { + return PLAYER_INVENTORY_SIZE; + } + return inv.getSizeInventory(); + } - /** - * Get the first empty slot in the inventory. - * - * @param inventory - inventory to check - * @return slot index of the first empty slot, -1 if none found - */ - public static int getEmptySlot(IInventory inventory) { - int invSize = getMainInventorySize(inventory); - return getEmptySlot(inventory, 0, invSize); - } + /** + * Get the first empty slot in the inventory. + * + * @param inventory - inventory to check + * @return slot index of the first empty slot, -1 if none found + */ + public static int getEmptySlot(IInventory inventory) { + int invSize = getMainInventorySize(inventory); + return getEmptySlot(inventory, 0, invSize); + } - /** - * Get the first empty slot in the inventory inside the provided slot index range. - * - * @param inventory - inventory to check - * @param start - first slot index (inclusive) - * @param end - last slot index (exclusive) - * @return slot index of the first empty slot, -1 if none found - */ - public static int getEmptySlot(IInventory inventory, int start, int end) { - for (int i = start; i < end; i++) { - if (inventory.getStackInSlot(i) == null) { - return i; - } - } - return -1; - } + /** + * Get the first empty slot in the inventory inside the provided slot index range. + * + * @param inventory - inventory to check + * @param start - first slot index (inclusive) + * @param end - last slot index (exclusive) + * @return slot index of the first empty slot, -1 if none found + */ + public static int getEmptySlot(IInventory inventory, int start, int end) { + for (int i = start; i < end; i++) { + if (inventory.getStackInSlot(i) == null) { + return i; + } + } + return -1; + } - /** - * Store the contents of an inventory in a list. - * - * @param inventory - inventory to store - */ - public static List storeContents(IInventory inventory) { - List copy = new ArrayList(inventory.getSizeInventory()); - for (int i = 0; i < inventory.getSizeInventory(); i++) { - copy.add(i, ItemStack.copyItemStack(inventory.getStackInSlot(i))); - } - return copy; - } + /** + * Store the contents of an inventory in a list. + * + * @param inventory - inventory to store + */ + public static List storeContents(IInventory inventory) { + List copy = new ArrayList(inventory.getSizeInventory()); + for (int i = 0; i < inventory.getSizeInventory(); i++) { + copy.add(i, ItemStack.copyItemStack(inventory.getStackInSlot(i))); + } + return copy; + } - /** - * Replace the contents of an inventory with the ones of the list. List and inventory sizes must be the same! - * - * @param inventory - inventory to replace - * @param list - list of itemstacks - */ - public static void setContents(IInventory inventory, List list) { - if (inventory.getSizeInventory() != list.size()) { - Ref.LOGGER.warn("Tried to set inventory contents from a list that is not the same size as the inventory; Aborted!"); - return; - } - for (int i = 0; i < list.size(); i++) { - inventory.setInventorySlotContents(i, ItemStack.copyItemStack(list.get(i))); - } - } + /** + * Replace the contents of an inventory with the ones of the list. List and inventory sizes must be the same! + * + * @param inventory - inventory to replace + * @param list - list of itemstacks + */ + public static void setContents(IInventory inventory, List list) { + if (inventory.getSizeInventory() != list.size()) { + Ref.LOGGER.warn("Tried to set inventory contents from a list that is not the same size as the inventory; Aborted!"); + return; + } + for (int i = 0; i < list.size(); i++) { + inventory.setInventorySlotContents(i, ItemStack.copyItemStack(list.get(i))); + } + } - /** - * Replace the contents of an inventory with the contents of another inventory. - * - * @param to - inventory to set contents to - * @param from - inventory to read contents from - */ - public static void setContents(IInventory to, IInventory from) { - int invSize = Math.min(to.getSizeInventory(), from.getSizeInventory()); - for (int i = 0; i < invSize; i++) { - to.setInventorySlotContents(i, ItemStack.copyItemStack(from.getStackInSlot(i))); - } - } + /** + * Replace the contents of an inventory with the contents of another inventory. + * + * @param to - inventory to set contents to + * @param from - inventory to read contents from + */ + public static void setContents(IInventory to, IInventory from) { + int invSize = Math.min(to.getSizeInventory(), from.getSizeInventory()); + for (int i = 0; i < invSize; i++) { + to.setInventorySlotContents(i, ItemStack.copyItemStack(from.getStackInSlot(i))); + } + } - /** - * Add the specified itemstack to inventory. Try stacking it with existing stacks first. If that fails try to put it in an empty slot. - * - * @param inventory - inventory to add to - * @param itemstack - item to add - * @return whether or not the itemstack was added to the inventory - */ - public static boolean addItemToInventory(IInventory inventory, ItemStack itemstack) { - int invSize = getMainInventorySize(inventory); - return addItemToInventory(inventory, itemstack, 0, invSize); - } + /** + * Add the specified itemstack to inventory. Try stacking it with existing stacks first. If that fails try to put it in an empty slot. + * + * @param inventory - inventory to add to + * @param itemstack - item to add + * @return whether or not the itemstack was added to the inventory + */ + public static boolean addItemToInventory(IInventory inventory, ItemStack itemstack) { + int invSize = getMainInventorySize(inventory); + return addItemToInventory(inventory, itemstack, 0, invSize); + } - /** - * Add the specified itemstack to inventory. Try stacking it with existing stacks first. If that fails try to put it in an empty slot. Constrain - * to the provided slot index range. - * - * @param inventory - inventory to add to - * @param itemstack - item to add - * @param start - first slot index (inclusive) - * @param end - last slot index (exclusive) - * @return whether or not the itemstack was added to the inventory - */ - public static boolean addItemToInventory(IInventory inventory, ItemStack itemstack, int start, int end) { - List contents = InventoryUtils.storeContents(inventory); - int maxStack = Math.min(inventory.getInventoryStackLimit(), itemstack.getMaxStackSize()); - for (int i = start; i < end; i++) { - if (StackUtils.areEqualNoSize(itemstack, inventory.getStackInSlot(i))) { - ItemStack is = inventory.getStackInSlot(i); - if (is.stackSize >= maxStack) { - continue; - } - if (is.stackSize + itemstack.stackSize <= maxStack) { - is.stackSize += itemstack.stackSize; - inventory.markDirty(); - return true; - } else { - itemstack.stackSize -= maxStack - is.stackSize; - is.stackSize = maxStack; - } - } - } - while (true) { - int slot = InventoryUtils.getEmptySlot(inventory, start, end); - if (slot != -1) { - if (itemstack.stackSize <= maxStack) { - inventory.setInventorySlotContents(slot, itemstack.copy()); - inventory.markDirty(); - return true; - } else { - ItemStack is = itemstack.copy(); - itemstack.stackSize -= maxStack; - is.stackSize = maxStack; - inventory.setInventorySlotContents(slot, is); - } - } else { - break; - } - } - InventoryUtils.setContents(inventory, contents); - return false; - } + /** + * Add the specified itemstack to inventory. Try stacking it with existing stacks first. If that fails try to put it in an empty slot. Constrain + * to the provided slot index range. + * + * @param inventory - inventory to add to + * @param itemstack - item to add + * @param start - first slot index (inclusive) + * @param end - last slot index (exclusive) + * @return whether or not the itemstack was added to the inventory + */ + public static boolean addItemToInventory(IInventory inventory, ItemStack itemstack, int start, int end) { + List contents = InventoryUtils.storeContents(inventory); + int maxStack = Math.min(inventory.getInventoryStackLimit(), itemstack.getMaxStackSize()); + for (int i = start; i < end; i++) { + if (StackUtils.areEqualNoSize(itemstack, inventory.getStackInSlot(i))) { + ItemStack is = inventory.getStackInSlot(i); + if (is.stackSize >= maxStack) { + continue; + } + if (is.stackSize + itemstack.stackSize <= maxStack) { + is.stackSize += itemstack.stackSize; + inventory.markDirty(); + return true; + } else { + itemstack.stackSize -= maxStack - is.stackSize; + is.stackSize = maxStack; + } + } + } + while (true) { + int slot = InventoryUtils.getEmptySlot(inventory, start, end); + if (slot != -1) { + if (itemstack.stackSize <= maxStack) { + inventory.setInventorySlotContents(slot, itemstack.copy()); + inventory.markDirty(); + return true; + } else { + ItemStack is = itemstack.copy(); + itemstack.stackSize -= maxStack; + is.stackSize = maxStack; + inventory.setInventorySlotContents(slot, is); + } + } else { + break; + } + } + InventoryUtils.setContents(inventory, contents); + return false; + } - /** - * Decreases the stack size in the inventoryIndex slot in the inventory by 1 and gives back any container items (bucket, etc.). Also adds the - * consumed item to the usedIngredients list. - * - * @param inventory - inventory to take from - * @param inventoryIndex - slot index to take from - * @param usedIngredients - a list to which the consumed ingredient will be added - * @return true if successful, false if there is no space for container items or cannot take from stack - */ - public static boolean consumeItemForCrafting(IInventory inventory, int inventoryIndex, List usedIngredients) { - ItemStack stack = inventory.decrStackSize(inventoryIndex, 1); - if (stack != null) { - if (stack.getItem().hasContainerItem(stack)) { - ItemStack containerStack = stack.getItem().getContainerItem(stack); - if (containerStack.isItemStackDamageable() && containerStack.getItemDamage() > containerStack.getMaxDamage()) { - containerStack = null; - } - if (containerStack != null && !addItemToInventory(inventory, containerStack)) { - if (inventory.getStackInSlot(inventoryIndex) != null) { - inventory.getStackInSlot(inventoryIndex).stackSize++; - } else { - inventory.setInventorySlotContents(inventoryIndex, stack); - } - return false; - } - } - usedIngredients.add(stack); - inventory.markDirty(); - return true; - } - return false; - } + /** + * Decreases the stack size in the inventoryIndex slot in the inventory by 1 and gives back any container items (bucket, etc.). Also adds the + * consumed item to the usedIngredients list. + * + * @param inventory - inventory to take from + * @param inventoryIndex - slot index to take from + * @param usedIngredients - a list to which the consumed ingredient will be added + * @return true if successful, false if there is no space for container items or cannot take from stack + */ + public static boolean consumeItemForCrafting(IInventory inventory, int inventoryIndex, List usedIngredients) { + ItemStack stack = inventory.decrStackSize(inventoryIndex, 1); + if (stack != null) { + if (stack.getItem().hasContainerItem(stack)) { + ItemStack containerStack = stack.getItem().getContainerItem(stack); + if (containerStack.isItemStackDamageable() && containerStack.getItemDamage() > containerStack.getMaxDamage()) { + containerStack = null; + } + if (containerStack != null && !addItemToInventory(inventory, containerStack)) { + if (inventory.getStackInSlot(inventoryIndex) != null) { + inventory.getStackInSlot(inventoryIndex).stackSize++; + } else { + inventory.setInventorySlotContents(inventoryIndex, stack); + } + return false; + } + } + usedIngredients.add(stack); + inventory.markDirty(); + return true; + } + return false; + } - public static void readStacksFromNBT(ItemStack[] stacks, NBTTagList nbt) { - for (int i = 0; i < nbt.tagCount(); i++) { - NBTTagCompound tag = nbt.getCompoundTagAt(i); - byte slot = tag.getByte("Slot"); - if (slot >= 0 && slot < stacks.length) { - stacks[slot] = ItemStack.loadItemStackFromNBT(tag); - } - } - } + public static void readStacksFromNBT(ItemStack[] stacks, NBTTagList nbt) { + for (int i = 0; i < nbt.tagCount(); i++) { + NBTTagCompound tag = nbt.getCompoundTagAt(i); + byte slot = tag.getByte("Slot"); + if (slot >= 0 && slot < stacks.length) { + stacks[slot] = ItemStack.loadItemStackFromNBT(tag); + } + } + } - public static NBTTagList writeStacksToNBT(ItemStack[] stacks) { - NBTTagList itemList = new NBTTagList(); - for (int i = 0; i < stacks.length; i++) { - ItemStack stack = stacks[i]; - if (stack != null) { - NBTTagCompound tag = new NBTTagCompound(); - tag.setByte("Slot", (byte) i); - stack.writeToNBT(tag); - itemList.appendTag(tag); - } - } - return itemList; - } + public static NBTTagList writeStacksToNBT(ItemStack[] stacks) { + NBTTagList itemList = new NBTTagList(); + for (int i = 0; i < stacks.length; i++) { + ItemStack stack = stacks[i]; + if (stack != null) { + NBTTagCompound tag = new NBTTagCompound(); + tag.setByte("Slot", (byte) i); + stack.writeToNBT(tag); + itemList.appendTag(tag); + } + } + return itemList; + } - public static void dropItems(TileEntity te) { - if (te instanceof IInventory) { - dropItems(te, createSlotArray(0, ((IInventory) te).getSizeInventory())); - } - } + public static void dropItems(TileEntity te) { + if (te instanceof IInventory) { + dropItems(te, createSlotArray(0, ((IInventory) te).getSizeInventory())); + } + } - public static void dropItems(TileEntity te, int[] slots) { - if (te instanceof IInventory) { - double x = te.xCoord + 0.5; - double y = te.yCoord + 0.5; - double z = te.zCoord + 0.5; - IInventory inv = (IInventory) te; + public static void dropItems(TileEntity te, int[] slots) { + if (te instanceof IInventory) { + double x = te.xCoord + 0.5; + double y = te.yCoord + 0.5; + double z = te.zCoord + 0.5; + IInventory inv = (IInventory) te; - for (int slot : slots) { - dropItem(te.getWorldObj(), x, y, z, inv.getStackInSlot(slot)); - } - } - } + for (int slot : slots) { + dropItem(te.getWorldObj(), x, y, z, inv.getStackInSlot(slot)); + } + } + } - public static void dropItem(World world, double x, double y, double z, ItemStack stack) { - if (stack != null) { - EntityItem drop = new EntityItem(world, x, y, z, stack.copy()); - float speed = 0.05F; - drop.motionX = (float) RNG.nextGaussian() * speed; - drop.motionY = (float) RNG.nextGaussian() * speed + 0.2F; - drop.motionZ = (float) RNG.nextGaussian() * speed; - world.spawnEntityInWorld(drop); - } - } + public static void dropItem(World world, double x, double y, double z, ItemStack stack) { + if (stack != null) { + EntityItem drop = new EntityItem(world, x, y, z, stack.copy()); + float speed = 0.05F; + drop.motionX = (float) RNG.nextGaussian() * speed; + drop.motionY = (float) RNG.nextGaussian() * speed + 0.2F; + drop.motionZ = (float) RNG.nextGaussian() * speed; + world.spawnEntityInWorld(drop); + } + } - public static ItemStack decreaseStackSize(IInventory inv, int slotIndex, int amount) { - ItemStack stack = inv.getStackInSlot(slotIndex); - if (stack != null) { - if (stack.stackSize <= amount) { - inv.setInventorySlotContents(slotIndex, null); - } else { - ItemStack is = stack.splitStack(amount); - if (stack.stackSize == 0) { - inv.setInventorySlotContents(slotIndex, null); - } else { - inv.markDirty(); - } - inv.markDirty(); - return is; - } - inv.markDirty(); - } - return stack; - } + public static ItemStack decreaseStackSize(IInventory inv, int slotIndex, int amount) { + ItemStack stack = inv.getStackInSlot(slotIndex); + if (stack != null) { + if (stack.stackSize <= amount) { + inv.setInventorySlotContents(slotIndex, null); + } else { + ItemStack is = stack.splitStack(amount); + if (stack.stackSize == 0) { + inv.setInventorySlotContents(slotIndex, null); + } else { + inv.markDirty(); + } + inv.markDirty(); + return is; + } + inv.markDirty(); + } + return stack; + } - public static ItemStack getStackInSlotOnClosing(IInventory inv, int slotIndex) { - ItemStack stack = inv.getStackInSlot(slotIndex); - inv.setInventorySlotContents(slotIndex, null); - return stack; - } + public static ItemStack getStackInSlotOnClosing(IInventory inv, int slotIndex) { + ItemStack stack = inv.getStackInSlot(slotIndex); + inv.setInventorySlotContents(slotIndex, null); + return stack; + } - /** - * Create an array of slot indices (int[]) for use with ISidedInventory. First slot index is inclusive, last index is exclusive. - */ - public static int[] createSlotArray(int first, int last) { - int[] slots = new int[last - first]; - for (int i = first; i < last; i++) { - slots[i - first] = i; - } - return slots; - } + /** + * Create an array of slot indices (int[]) for use with ISidedInventory. First slot index is inclusive, last index is exclusive. + */ + public static int[] createSlotArray(int first, int last) { + int[] slots = new int[last - first]; + for (int i = first; i < last; i++) { + slots[i - first] = i; + } + return slots; + } } From 2d39d74ca26cba82741fb5bc8624dec02e7418b7 Mon Sep 17 00:00:00 2001 From: Anon Date: Sat, 11 Apr 2015 10:57:01 -0500 Subject: [PATCH 03/13] a --- .../core/inventory/gui/GuiEasyCrafting.java | 17 +- .../network/message/MessageEasyCrafting.java | 247 ++++++----- .../core/recipe/RecipeHelper.java | 382 ++++++++++++------ 3 files changed, 394 insertions(+), 252 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java index 1f13cd2..4dece57 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java @@ -255,7 +255,7 @@ private void onCraftingSlotClick(Slot slot, int slotIndex, int button, int actio if (finalStackSize > 0) { boolean isRightClick = button == 1; - boolean isShiftClick = false; + boolean isShiftClick = action == 1; PacketHandler.INSTANCE.sendToServer(new MessageEasyCrafting(recipe, isRightClick, isShiftClick)); @@ -268,14 +268,13 @@ private void onCraftingSlotClick(Slot slot, int slotIndex, int button, int actio } } else if (isShiftClick) { - finalStack.stackSize = finalStackSize; - mc.thePlayer.inventory.setItemStack(finalStack); - //int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, null); - //int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); - //if (timesCrafted > 0) { - // finalStack.stackSize *= timesCrafted; //ignore finalStackSize; it might contain heldStack size - // InventoryUtils.addItemToInventory(mc.thePlayer.inventory, finalStack); - //} + int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, null); + int timesCrafted = RecipeHelper.canCraftWithComponents(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); + if (timesCrafted > 0) { + finalStack.stackSize *= timesCrafted; //ignore finalStackSize; it might contain heldStack size + RecipeHelper.canCraftWithComponents(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), true, timesCrafted, ConfigHandler.MAX_RECURSION); + InventoryUtils.addItemToInventory(mc.thePlayer.inventory, finalStack); + } } else { // Left click; craft once finalStack.stackSize = finalStackSize; diff --git a/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java index 32b6471..8960ab7 100644 --- a/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java @@ -17,128 +17,127 @@ public class MessageEasyCrafting extends AbstractMessage { - private ItemStack result; - private ItemStack[] ingredients; - private boolean isRightClick = false; - private boolean isShiftClick = false; - - public MessageEasyCrafting() {} - - public MessageEasyCrafting(WrappedRecipe recipe, boolean isRightClick, boolean isShiftClick) { - setRecipe(recipe); - this.isRightClick = isRightClick; - this.isShiftClick = isShiftClick; - } - - private void setRecipe(WrappedRecipe recipe) { - result = recipe.getOutput(); - ingredients = new ItemStack[recipe.inputs.size()]; - - for (int i = 0; i < recipe.inputs.size(); i++) { - if (recipe.inputs.get(i) instanceof ItemStack) { - ingredients[i] = ((ItemStack) recipe.inputs.get(i)).copy(); - } else if (recipe.inputs.get(i) instanceof List) { - @SuppressWarnings("unchecked") - List ingList = (List) recipe.inputs.get(i); - ingredients[i] = ingList.get(0).copy(); - } - } - } - - @Override - public void write(ByteBuf target) { - target.writeBoolean(isRightClick); - - target.writeShort(Item.getIdFromItem(result.getItem())); - target.writeInt(result.getItemDamage()); - target.writeByte(result.stackSize); - - target.writeByte(ingredients.length); - - for (ItemStack is : ingredients) { - target.writeShort(Item.getIdFromItem(is.getItem())); - target.writeInt(is.getItemDamage()); - target.writeByte(is.stackSize); - } - - target.writeBoolean(isShiftClick); - } - - @Override - public void read(ByteBuf source) { - isRightClick = source.readBoolean(); - - int id = source.readShort(); - int damage = source.readInt(); - int size = source.readByte(); - - result = new ItemStack(Item.getItemById(id), size, damage); - - int length = source.readByte(); - - ingredients = new ItemStack[length]; - - for (int i = 0; i < length; i++) { - int _id = source.readShort(); - int _damage = source.readInt(); - int _size = source.readByte(); - - ingredients[i] = new ItemStack(Item.getItemById(_id), _size, _damage); - } - - isShiftClick = source.readBoolean(); - } - - @Override - public void run(EntityPlayer player, Side side) { - Ref.LOGGER.trace("Message: " + this.getClass().getName() + " Side: " + side); - - WrappedRecipe recipe = RecipeHelper.getValidRecipe(result, ingredients); - if (recipe == null) { - return; - } - - ItemStack stack_in_hand = player.inventory.getItemStack(); - - // We need this call to canCraft() to populate the output in getCraftingResult() with NBT - if (RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), false, 1, ConfigHandler.MAX_RECURSION) == 0) { - return; - } - - ItemStack return_stack = recipe.handler.getCraftingResult(recipe, recipe.usedIngredients); - int return_size = 0; - - if (stack_in_hand == null) { - return_size = return_stack.stackSize; - } else if (StackUtils.canStack(stack_in_hand, return_stack) == 0) { - return_size = return_stack.stackSize + stack_in_hand.stackSize; - } - - if (return_size > 0) { - if (!isRightClick) { - if (isShiftClick) { - int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(return_stack, null); - int timesCrafted = RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); - if (timesCrafted > 0) { - return_stack.stackSize *= timesCrafted; - if (InventoryUtils.addItemToInventory(player.inventory, return_stack)) { - RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), true, maxTimes, ConfigHandler.MAX_RECURSION); - } - } - } else { - if (RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), true, 1, ConfigHandler.MAX_RECURSION) > 0) { - return_stack.stackSize = return_size; - player.inventory.setItemStack(return_stack); - } - } - } else { - int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(return_stack, stack_in_hand); - int timesCrafted = RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), true, maxTimes, ConfigHandler.MAX_RECURSION); - if (timesCrafted > 0) { - return_stack.stackSize = return_size + (timesCrafted - 1) * return_stack.stackSize; - player.inventory.setItemStack(return_stack); - } - } - } - } + private ItemStack result; + private ItemStack[] ingredients; + private boolean isRightClick = false; + private boolean isShiftClick = false; + + public MessageEasyCrafting() {} + + public MessageEasyCrafting(WrappedRecipe recipe, boolean isRightClick, boolean isShiftClick) { + setRecipe(recipe); + this.isRightClick = isRightClick; + this.isShiftClick = isShiftClick; + } + + private void setRecipe(WrappedRecipe recipe) { + result = recipe.getOutput(); + ingredients = new ItemStack[recipe.inputs.size()]; + + for (int i = 0; i < recipe.inputs.size(); i++) { + if (recipe.inputs.get(i) instanceof ItemStack) { + ingredients[i] = ((ItemStack) recipe.inputs.get(i)).copy(); + } else if (recipe.inputs.get(i) instanceof List) { + @SuppressWarnings("unchecked") + List ingList = (List) recipe.inputs.get(i); + ingredients[i] = ingList.get(0).copy(); + } + } + } + + @Override + public void write(ByteBuf target) { + target.writeBoolean(isRightClick); + + target.writeShort(Item.getIdFromItem(result.getItem())); + target.writeInt(result.getItemDamage()); + target.writeByte(result.stackSize); + + target.writeByte(ingredients.length); + + for (ItemStack is : ingredients) { + target.writeShort(Item.getIdFromItem(is.getItem())); + target.writeInt(is.getItemDamage()); + target.writeByte(is.stackSize); + } + + target.writeBoolean(isShiftClick); + } + + @Override + public void read(ByteBuf source) { + isRightClick = source.readBoolean(); + + int id = source.readShort(); + int damage = source.readInt(); + int size = source.readByte(); + + result = new ItemStack(Item.getItemById(id), size, damage); + + int length = source.readByte(); + + ingredients = new ItemStack[length]; + + for (int i = 0; i < length; i++) { + int _id = source.readShort(); + int _damage = source.readInt(); + int _size = source.readByte(); + + ingredients[i] = new ItemStack(Item.getItemById(_id), _size, _damage); + } + + isShiftClick = source.readBoolean(); + } + + @Override + public void run(EntityPlayer player, Side side) { + Ref.LOGGER.trace("Message: " + this.getClass().getName() + " Side: " + side); + + WrappedRecipe recipe = RecipeHelper.getValidRecipe(result, ingredients); + if (recipe == null) { + return; + } + + ItemStack stack_in_hand = player.inventory.getItemStack(); + + // We need this call to canCraft() to populate the output in getCraftingResult() with NBT + if (RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), false, 1, ConfigHandler.MAX_RECURSION) == 0) { + return; + } + + ItemStack return_stack = recipe.handler.getCraftingResult(recipe, recipe.usedIngredients); + int return_size = 0; + + if (stack_in_hand == null) { + return_size = return_stack.stackSize; + } else if (StackUtils.canStack(stack_in_hand, return_stack) == 0) { + return_size = return_stack.stackSize + stack_in_hand.stackSize; + } + + if (return_size > 0) { + if (!isRightClick) { + if (isShiftClick) { + int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(return_stack, null); + int timesCrafted = RecipeHelper.canCraftWithComponents(recipe, player.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); + if (timesCrafted > 0) { + return_stack.stackSize *= timesCrafted; + RecipeHelper.canCraftWithComponents(recipe, player.inventory, RecipeManager.getAllRecipes(), true, timesCrafted, ConfigHandler.MAX_RECURSION); + InventoryUtils.addItemToInventory(player.inventory, return_stack); + } + } else { + if (RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), true, 1, ConfigHandler.MAX_RECURSION) > 0) { + return_stack.stackSize = return_size; + player.inventory.setItemStack(return_stack); + } + } + } else { + int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(return_stack, stack_in_hand); + int timesCrafted = RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), true, maxTimes, ConfigHandler.MAX_RECURSION); + if (timesCrafted > 0) { + return_stack.stackSize = return_size + (timesCrafted - 1) * return_stack.stackSize; + player.inventory.setItemStack(return_stack); + } + } + } + } } diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java index 0e5dca1..181c387 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java @@ -21,97 +21,227 @@ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory) { } /** - * Check if a recipe can be crafted with the ingredients from the inventory. If an ingredient is missing try to craft it from a list of recipes. + * Check if a recipe can be crafted with the ingredients from the inventory. + * If an ingredient is missing try to craft it from a list of recipes. */ - public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, List recipesToCheck, int recursion) { + public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, + List recipesToCheck, int recursion) { return canCraft(recipe, inventory, recipesToCheck, false, 1, recursion) > 0; } /** - * Check if a recipe can be crafted with the ingredients from the inventory. If an ingredient is missing try to craft it from a list of recipes. + * Check if a recipe can be crafted with the ingredients from the inventory. + * If an ingredient is missing try to craft it from a list of recipes. * - * @param recipe - recipe to check - * @param inventory - inventory to use the ingredients from - * @param recipesToCheck - a list of recipes to try and craft from if an ingredient is missing - * @param take - whether or not to take the ingredients from the inventory - * @param recursion - how deep to recurse while trying to craft an ingredient (must be nonnegative) + * @param recipe + * - recipe to check + * @param inventory + * - inventory to use the ingredients from + * @param recipesToCheck + * - a list of recipes to try and craft from if an ingredient is + * missing + * @param take + * - whether or not to take the ingredients from the inventory + * @param recursion + * - how deep to recurse while trying to craft an ingredient + * (must be nonnegative) */ - public static int canCraft(WrappedRecipe recipe, IInventory inventory, List recipesToCheck, boolean take, int maxTimes, int recursion) { + public static int canCraft(WrappedRecipe recipe, IInventory inventory, + List recipesToCheck, boolean take, int maxTimes, + int recursion) { if (recursion < 0) { return 0; } recipe.usedIngredients.clear(); - int invSize = InventoryUtils.getMainInventorySize(inventory); InventoryBasic tmp = new InventoryBasic("tmp", true, invSize); InventoryBasic tmp2 = new InventoryBasic("tmp2", true, invSize); InventoryUtils.setContents(tmp, inventory); - int timesCrafted = 0; - timesLoop: - while (timesCrafted < maxTimes) { - iiLoop: - for (int ii = 0; ii < recipe.inputs.size(); ii++) { - if (recipe.inputs.get(ii) instanceof ItemStack) { - ItemStack ingredient = (ItemStack) recipe.inputs.get(ii); - int inventoryIndex = isItemInInventory(ingredient, recipe, tmp); - if (inventoryIndex != -1 && InventoryUtils.consumeItemForCrafting(tmp, inventoryIndex, recipe.usedIngredients)) { + timesLoop: while (timesCrafted < maxTimes) { + iiLoop: for (int ii = 0; ii < recipe.inputs.size(); ii++) { + if (recipe.inputs.get(ii) instanceof ItemStack) { + ItemStack ingredient = (ItemStack) recipe.inputs.get(ii); + int inventoryIndex = isItemInInventory(ingredient, recipe, + tmp); + if (inventoryIndex != -1 + && InventoryUtils.consumeItemForCrafting(tmp, + inventoryIndex, recipe.usedIngredients)) { + continue iiLoop; + } + // ingredient is not in inventory, can we craft it? + if (recipesToCheck != null && recursion > 0) { + List list = getRecipesForItemFromList( + ingredient, recipe, recipesToCheck); + for (WrappedRecipe wr : list) { + if (canCraft(wr, tmp, recipesToCheck, true, 1, + recursion - 1) > 0) { + ItemStack is = wr.handler.getCraftingResult(wr, + wr.usedIngredients); + is.stackSize--; + if (is.stackSize > 0 + && !InventoryUtils.addItemToInventory( + tmp, is)) { + break timesLoop; + } + ItemStack usedItemStack = is.copy(); + usedItemStack.stackSize = 1; + recipe.usedIngredients.add(usedItemStack); continue iiLoop; } - // ingredient is not in inventory, can we craft it? - if (recipesToCheck != null && recursion > 0) { - List list = getRecipesForItemFromList(ingredient, recipe, recipesToCheck); - for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, recipesToCheck, true, 1, recursion - 1) > 0) { - ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); - is.stackSize--; - if (is.stackSize > 0 && !InventoryUtils.addItemToInventory(tmp, is)) { - break timesLoop; - } - ItemStack usedItemStack = is.copy(); - usedItemStack.stackSize = 1; - recipe.usedIngredients.add(usedItemStack); - continue iiLoop; - } - } - } - // ingredient is not in inventory and we can't craft it! + } + } + // ingredient is not in inventory and we can't craft it! + break timesLoop; + } else if (recipe.inputs.get(ii) instanceof List) { + @SuppressWarnings("unchecked") + List ingredients = (List) recipe.inputs + .get(ii); + int inventoryIndex = isItemInInventory(ingredients, recipe, + tmp); + if (inventoryIndex != -1 + && InventoryUtils.consumeItemForCrafting(tmp, + inventoryIndex, recipe.usedIngredients)) { + continue iiLoop; + } + // ingredient is not in inventory, can we craft it? + if (recipesToCheck != null && recursion > 0) { + List list = getRecipesForItemFromList( + ingredients, recipe, recipesToCheck); + for (WrappedRecipe wr : list) { + if (canCraft(wr, tmp, recipesToCheck, true, 1, + recursion - 1) > 0) { + ItemStack is = wr.handler.getCraftingResult(wr, + wr.usedIngredients); + is.stackSize--; + if (is.stackSize > 0 + && !InventoryUtils.addItemToInventory( + tmp, is)) { + break timesLoop; + } + ItemStack usedItemStack = is.copy(); + usedItemStack.stackSize = 1; + recipe.usedIngredients.add(usedItemStack); + continue iiLoop; + } + } + } + // + break timesLoop; + } + } + + timesCrafted++; + InventoryUtils.setContents(tmp2, tmp); + + } + if (timesCrafted > 0) { + if (take) { + InventoryUtils.setContents(inventory, tmp2); + } + } + return timesCrafted; + } + + // / Checks inventory size and sees if all crafted components + recipe + // output can fit in the inventory. Used for shift-click crafting + public static int canCraftWithComponents(WrappedRecipe recipe, + IInventory inventory, List recipesToCheck, + boolean take, int maxTimes, int recursion) { + if (recursion < 0) { + return 0; + } + + recipe.usedIngredients.clear(); + int invSize = InventoryUtils.getMainInventorySize(inventory); + InventoryBasic tmp = new InventoryBasic("tmp", true, invSize); + InventoryBasic tmp2 = new InventoryBasic("tmp2", true, invSize); + InventoryUtils.setContents(tmp, inventory); + + int timesCrafted = 0; + timesLoop: while (timesCrafted < maxTimes) { + iiLoop: for (int ii = 0; ii < recipe.inputs.size(); ii++) { + if (recipe.inputs.get(ii) instanceof ItemStack) { + ItemStack ingredient = (ItemStack) recipe.inputs.get(ii); + int inventoryIndex = isItemInInventory(ingredient, recipe, + tmp); + if (inventoryIndex != -1 + && InventoryUtils.consumeItemForCrafting(tmp, + inventoryIndex, recipe.usedIngredients)) { + continue iiLoop; + } + // ingredient is not in inventory, can we craft it? + if (recipesToCheck != null && recursion > 0) { + List list = getRecipesForItemFromList( + ingredient, recipe, recipesToCheck); + for (WrappedRecipe wr : list) { + if (canCraft(wr, tmp, recipesToCheck, true, 1, + recursion - 1) > 0) { + ItemStack is = wr.handler.getCraftingResult(wr, + wr.usedIngredients); + is.stackSize--; + if (is.stackSize > 0 + && !InventoryUtils.addItemToInventory( + tmp, is)) { break timesLoop; - } else if (recipe.inputs.get(ii) instanceof List) { - @SuppressWarnings("unchecked") - List ingredients = (List) recipe.inputs.get(ii); - int inventoryIndex = isItemInInventory(ingredients, recipe, tmp); - if (inventoryIndex != -1 && InventoryUtils.consumeItemForCrafting(tmp, inventoryIndex, recipe.usedIngredients)) { + } + ItemStack usedItemStack = is.copy(); + usedItemStack.stackSize = 1; + recipe.usedIngredients.add(usedItemStack); continue iiLoop; } - // ingredient is not in inventory, can we craft it? - if (recipesToCheck != null && recursion > 0) { - List list = getRecipesForItemFromList(ingredients, recipe, recipesToCheck); - for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, recipesToCheck, true, 1, recursion - 1) > 0) { - ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); - is.stackSize--; - if (is.stackSize > 0 && !InventoryUtils.addItemToInventory(tmp, is)) { - break timesLoop; - } - ItemStack usedItemStack = is.copy(); - usedItemStack.stackSize = 1; - recipe.usedIngredients.add(usedItemStack); - continue iiLoop; - } + } + } + // ingredient is not in inventory and we can't craft it! + break timesLoop; + } else if (recipe.inputs.get(ii) instanceof List) { + @SuppressWarnings("unchecked") + List ingredients = (List) recipe.inputs + .get(ii); + int inventoryIndex = isItemInInventory(ingredients, recipe, + tmp); + if (inventoryIndex != -1 + && InventoryUtils.consumeItemForCrafting(tmp, + inventoryIndex, recipe.usedIngredients)) { + continue iiLoop; + } + // ingredient is not in inventory, can we craft it? + if (recipesToCheck != null && recursion > 0) { + List list = getRecipesForItemFromList( + ingredients, recipe, recipesToCheck); + for (WrappedRecipe wr : list) { + if (canCraft(wr, tmp, recipesToCheck, true, 1, + recursion - 1) > 0) { + ItemStack is = wr.handler.getCraftingResult(wr, + wr.usedIngredients); + is.stackSize--; + if (is.stackSize > 0 + && !InventoryUtils.addItemToInventory( + tmp, is)) { + break timesLoop; } + ItemStack usedItemStack = is.copy(); + usedItemStack.stackSize = 1; + recipe.usedIngredients.add(usedItemStack); + continue iiLoop; } - // - break timesLoop; } } - - timesCrafted++; - InventoryUtils.setContents(tmp2, tmp); + // + break timesLoop; + } } + timesCrafted++; + InventoryUtils.setContents(tmp2, tmp); + + } + ItemStack result = recipe.getOutput(); + if (!InventoryUtils.addItemToInventory(tmp, result)) { + timesCrafted = 0; + } if (timesCrafted > 0) { if (take) { InventoryUtils.setContents(inventory, tmp2); @@ -120,18 +250,21 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, List ing, WrappedRecipe recipe, IInventory inv) { + private static int isItemInInventory(List ing, + WrappedRecipe recipe, IInventory inv) { for (ItemStack is : ing) { int slot = isItemInInventory(is, recipe, inv); if (slot != -1) { @@ -141,7 +274,9 @@ private static int isItemInInventory(List ing, WrappedRecipe recipe, return -1; } - private static List getRecipesForItemFromList(ItemStack ingredient, WrappedRecipe recipe, List recipesToCheck) { + private static List getRecipesForItemFromList( + ItemStack ingredient, WrappedRecipe recipe, + List recipesToCheck) { List list = new LinkedList(); for (WrappedRecipe wr : recipesToCheck) { if (recipe.handler.matchItem(ingredient, wr.getOutput(), recipe)) { @@ -151,7 +286,9 @@ private static List getRecipesForItemFromList(ItemStack ingredien return list; } - private static List getRecipesForItemFromList(List ingredients, WrappedRecipe recipe, List recipesToCheck) { + private static List getRecipesForItemFromList( + List ingredients, WrappedRecipe recipe, + List recipesToCheck) { List list = new LinkedList(); for (ItemStack is : ingredients) { list.addAll(getRecipesForItemFromList(is, recipe, recipesToCheck)); @@ -162,56 +299,63 @@ private static List getRecipesForItemFromList(List ing /** * Get the recipe that matches provided result and ingredients. */ - public static WrappedRecipe getValidRecipe(ItemStack result, ItemStack[] ingredients) { - List all = RecipeManager.getAllRecipes(); - allLoop: - for (WrappedRecipe wr : all) { - if (StackUtils.areEqualNoSizeNoNBT(wr.getOutput(), result) && wr.inputs.size() == ingredients.length) { - ingLoop: - for (int i = 0; i < ingredients.length; i++) { - if (wr.inputs.get(i) instanceof ItemStack) { - ItemStack is = (ItemStack) wr.inputs.get(i); - if (!StackUtils.areCraftingEquivalent(is, ingredients[i])) { - continue allLoop; - } - } else if (wr.inputs.get(i) instanceof List) { - if (ingredients[i].getItem() == null) { - return null; - } - @SuppressWarnings("unchecked") - List ingList = (List) wr.inputs.get(i); - if (ingList.isEmpty()) { - return null; - } - for (ItemStack is : ingList) { - if (StackUtils.areCraftingEquivalent(is, ingredients[i])) { - continue ingLoop; - } - } - continue allLoop; - } - } - return wr; - } - } - return null; - } - - /** - * How many times can we fit the resulting itemstack in players hand. - * - * @param result itemstack we are trying to fit - * @param inHand itemstack currently in hand - */ - public static int calculateCraftingMultiplierUntilMaxStack(ItemStack result, ItemStack inHand) { - int maxTimes = MathHelper.floor_double(result.getMaxStackSize() / (double) result.stackSize); - if (inHand != null) { - int diff = result.getMaxStackSize() - (maxTimes * result.stackSize); - while (inHand.stackSize > diff) { - maxTimes--; - diff += result.stackSize; - } - } - return maxTimes; - } + public static WrappedRecipe getValidRecipe(ItemStack result, + ItemStack[] ingredients) { + List all = RecipeManager.getAllRecipes(); + allLoop: for (WrappedRecipe wr : all) { + if (StackUtils.areEqualNoSizeNoNBT(wr.getOutput(), result) + && wr.inputs.size() == ingredients.length) { + ingLoop: for (int i = 0; i < ingredients.length; i++) { + if (wr.inputs.get(i) instanceof ItemStack) { + ItemStack is = (ItemStack) wr.inputs.get(i); + if (!StackUtils.areCraftingEquivalent(is, + ingredients[i])) { + continue allLoop; + } + } else if (wr.inputs.get(i) instanceof List) { + if (ingredients[i].getItem() == null) { + return null; + } + @SuppressWarnings("unchecked") + List ingList = (List) wr.inputs + .get(i); + if (ingList.isEmpty()) { + return null; + } + for (ItemStack is : ingList) { + if (StackUtils.areCraftingEquivalent(is, + ingredients[i])) { + continue ingLoop; + } + } + continue allLoop; + } + } + return wr; + } + } + return null; + } + + /** + * How many times can we fit the resulting itemstack in players hand. + * + * @param result + * itemstack we are trying to fit + * @param inHand + * itemstack currently in hand + */ + public static int calculateCraftingMultiplierUntilMaxStack( + ItemStack result, ItemStack inHand) { + int maxTimes = MathHelper.floor_double(result.getMaxStackSize() + / (double) result.stackSize); + if (inHand != null) { + int diff = result.getMaxStackSize() - (maxTimes * result.stackSize); + while (inHand.stackSize > diff) { + maxTimes--; + diff += result.stackSize; + } + } + return maxTimes; + } } From 82debdea49dcba03e04e8377634b122aaccdf53d Mon Sep 17 00:00:00 2001 From: planetguy32 Date: Mon, 11 May 2015 20:57:19 -0700 Subject: [PATCH 04/13] Major optimizations to recipe tree traversal - new code takes .336 sec whereas old code took 17.022 sec for the same inventory. --- .../core/inventory/gui/GuiEasyCrafting.java | 6 +- .../core/inventory/slot/SlotInterceptor.java | 2 +- .../network/message/MessageEasyCrafting.java | 11 ++-- .../core/recipe/RecipeChecker.java | 11 +++- .../core/recipe/RecipeHelper.java | 64 +++++++++---------- .../core/recipe/RecipeManager.java | 37 ++++++++++- .../core/recipe/handler/IRecipeHandler.java | 1 + 7 files changed, 84 insertions(+), 48 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java index 4dece57..64c3b65 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java @@ -261,7 +261,7 @@ private void onCraftingSlotClick(Slot slot, int slotIndex, int button, int actio if (isRightClick) { // Right click; craft until max stack int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, heldStack); - int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); + int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, false, maxTimes, ConfigHandler.MAX_RECURSION); if (timesCrafted > 0) { finalStack.stackSize = finalStackSize + (timesCrafted - 1) * finalStack.stackSize; mc.thePlayer.inventory.setItemStack(finalStack); @@ -269,10 +269,10 @@ private void onCraftingSlotClick(Slot slot, int slotIndex, int button, int actio } else if (isShiftClick) { int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, null); - int timesCrafted = RecipeHelper.canCraftWithComponents(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); + int timesCrafted = RecipeHelper.canCraftWithComponents(recipe, mc.thePlayer.inventory, false, maxTimes, ConfigHandler.MAX_RECURSION); if (timesCrafted > 0) { finalStack.stackSize *= timesCrafted; //ignore finalStackSize; it might contain heldStack size - RecipeHelper.canCraftWithComponents(recipe, mc.thePlayer.inventory, RecipeManager.getAllRecipes(), true, timesCrafted, ConfigHandler.MAX_RECURSION); + RecipeHelper.canCraftWithComponents(recipe, mc.thePlayer.inventory, true, timesCrafted, ConfigHandler.MAX_RECURSION); InventoryUtils.addItemToInventory(mc.thePlayer.inventory, finalStack); } } diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/slot/SlotInterceptor.java b/src/main/java/net/lepko/easycrafting/core/inventory/slot/SlotInterceptor.java index a944be3..cca00b4 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/slot/SlotInterceptor.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/slot/SlotInterceptor.java @@ -23,6 +23,6 @@ public void onSlotChanged() { @SideOnly(Side.CLIENT) private void onSlotChangedClient() { - RecipeChecker.INSTANCE.requested = true; + RecipeChecker.INSTANCE.setRequested(true); } } diff --git a/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java index 8960ab7..3f38cc6 100644 --- a/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java @@ -5,7 +5,6 @@ import net.lepko.easycrafting.Ref; import net.lepko.easycrafting.core.config.ConfigHandler; import net.lepko.easycrafting.core.recipe.RecipeHelper; -import net.lepko.easycrafting.core.recipe.RecipeManager; import net.lepko.easycrafting.core.recipe.WrappedRecipe; import net.lepko.easycrafting.core.util.InventoryUtils; import net.lepko.easycrafting.core.util.StackUtils; @@ -101,7 +100,7 @@ public void run(EntityPlayer player, Side side) { ItemStack stack_in_hand = player.inventory.getItemStack(); // We need this call to canCraft() to populate the output in getCraftingResult() with NBT - if (RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), false, 1, ConfigHandler.MAX_RECURSION) == 0) { + if (RecipeHelper.canCraft(recipe, player.inventory, false, 1, ConfigHandler.MAX_RECURSION) == 0) { return; } @@ -118,21 +117,21 @@ public void run(EntityPlayer player, Side side) { if (!isRightClick) { if (isShiftClick) { int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(return_stack, null); - int timesCrafted = RecipeHelper.canCraftWithComponents(recipe, player.inventory, RecipeManager.getAllRecipes(), false, maxTimes, ConfigHandler.MAX_RECURSION); + int timesCrafted = RecipeHelper.canCraftWithComponents(recipe, player.inventory, false, maxTimes, ConfigHandler.MAX_RECURSION); if (timesCrafted > 0) { return_stack.stackSize *= timesCrafted; - RecipeHelper.canCraftWithComponents(recipe, player.inventory, RecipeManager.getAllRecipes(), true, timesCrafted, ConfigHandler.MAX_RECURSION); + RecipeHelper.canCraftWithComponents(recipe, player.inventory, true, timesCrafted, ConfigHandler.MAX_RECURSION); InventoryUtils.addItemToInventory(player.inventory, return_stack); } } else { - if (RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), true, 1, ConfigHandler.MAX_RECURSION) > 0) { + if (RecipeHelper.canCraft(recipe, player.inventory, true, 1, ConfigHandler.MAX_RECURSION) > 0) { return_stack.stackSize = return_size; player.inventory.setItemStack(return_stack); } } } else { int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(return_stack, stack_in_hand); - int timesCrafted = RecipeHelper.canCraft(recipe, player.inventory, RecipeManager.getAllRecipes(), true, maxTimes, ConfigHandler.MAX_RECURSION); + int timesCrafted = RecipeHelper.canCraft(recipe, player.inventory, true, maxTimes, ConfigHandler.MAX_RECURSION); if (timesCrafted > 0) { return_stack.stackSize = return_size + (timesCrafted - 1) * return_stack.stackSize; player.inventory.setItemStack(return_stack); diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java index 7dabaca..4fb0399 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java @@ -50,6 +50,15 @@ public void tickEnd(TickEvent.ClientTickEvent event) { } } } + + public boolean isRequested() { + return requested; + } + + public void setRequested(boolean requested) { + this.requested = requested; + } + private class CraftabilityChecker implements Runnable { @@ -71,7 +80,7 @@ public void run() { } } } - + private void setCraftableRecipes() { InventoryPlayer inventory = mc.thePlayer.inventory; recipes = getCraftableRecipes(inventory, ConfigHandler.MAX_RECURSION, ConfigHandler.MAX_TIME, RecipeManager.getAllRecipes()); diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java index 181c387..165c29c 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java @@ -5,9 +5,11 @@ import net.lepko.easycrafting.core.util.StackUtils; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryBasic; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.MathHelper; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -17,7 +19,7 @@ public class RecipeHelper { * Check if a recipe can be crafted with the ingredients from the inventory. */ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory) { - return canCraft(recipe, inventory, null, false, 1, 0) > 0; + return canCraft(recipe, inventory, false, 1, 0) > 0; } /** @@ -26,7 +28,7 @@ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory) { */ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, List recipesToCheck, int recursion) { - return canCraft(recipe, inventory, recipesToCheck, false, 1, recursion) > 0; + return canCraft(recipe, inventory, false, 1, recursion) > 0; } /** @@ -37,9 +39,6 @@ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, * - recipe to check * @param inventory * - inventory to use the ingredients from - * @param recipesToCheck - * - a list of recipes to try and craft from if an ingredient is - * missing * @param take * - whether or not to take the ingredients from the inventory * @param recursion @@ -47,8 +46,7 @@ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, * (must be nonnegative) */ public static int canCraft(WrappedRecipe recipe, IInventory inventory, - List recipesToCheck, boolean take, int maxTimes, - int recursion) { + boolean take, int maxTimes, int recursion) { if (recursion < 0) { return 0; } @@ -72,12 +70,11 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, continue iiLoop; } // ingredient is not in inventory, can we craft it? - if (recipesToCheck != null && recursion > 0) { + if (recursion > 0) { List list = getRecipesForItemFromList( - ingredient, recipe, recipesToCheck); + ingredient, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, recipesToCheck, true, 1, - recursion - 1) > 0) { + if (canCraft(wr, tmp, true, 1, recursion - 1) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; @@ -107,12 +104,11 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, continue iiLoop; } // ingredient is not in inventory, can we craft it? - if (recipesToCheck != null && recursion > 0) { + if (recursion > 0) { List list = getRecipesForItemFromList( - ingredients, recipe, recipesToCheck); + ingredients, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, recipesToCheck, true, 1, - recursion - 1) > 0) { + if (canCraft(wr, tmp, true, 1, recursion - 1) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; @@ -148,8 +144,8 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, // / Checks inventory size and sees if all crafted components + recipe // output can fit in the inventory. Used for shift-click crafting public static int canCraftWithComponents(WrappedRecipe recipe, - IInventory inventory, List recipesToCheck, - boolean take, int maxTimes, int recursion) { + IInventory inventory, boolean take, + int maxTimes, int recursion) { if (recursion < 0) { return 0; } @@ -173,11 +169,11 @@ public static int canCraftWithComponents(WrappedRecipe recipe, continue iiLoop; } // ingredient is not in inventory, can we craft it? - if (recipesToCheck != null && recursion > 0) { + if (recursion > 0) { List list = getRecipesForItemFromList( - ingredient, recipe, recipesToCheck); + ingredient, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, recipesToCheck, true, 1, + if (canCraft(wr, tmp, true, 1, recursion - 1) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); @@ -208,12 +204,11 @@ public static int canCraftWithComponents(WrappedRecipe recipe, continue iiLoop; } // ingredient is not in inventory, can we craft it? - if (recipesToCheck != null && recursion > 0) { + if (recursion > 0) { List list = getRecipesForItemFromList( - ingredients, recipe, recipesToCheck); + ingredients, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, recipesToCheck, true, 1, - recursion - 1) > 0) { + if (canCraft(wr, tmp, true, 1, recursion - 1) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; @@ -275,23 +270,24 @@ private static int isItemInInventory(List ing, } private static List getRecipesForItemFromList( - ItemStack ingredient, WrappedRecipe recipe, - List recipesToCheck) { - List list = new LinkedList(); - for (WrappedRecipe wr : recipesToCheck) { - if (recipe.handler.matchItem(ingredient, wr.getOutput(), recipe)) { - list.add(wr); - } + ItemStack ingredient, WrappedRecipe recipe) { + List list = new ArrayList(); + if(ingredient != null && ingredient.getItem() != null){ + List recipes=RecipeManager.getProducers(ingredient.getItem()); + if(recipes!=null) + for (WrappedRecipe wr : recipes) + if (recipe.handler.matchItem(ingredient, wr.getOutput(), recipe)) + list.add(wr); } return list; } + private static List getRecipesForItemFromList( - List ingredients, WrappedRecipe recipe, - List recipesToCheck) { + List ingredients, WrappedRecipe recipe) { List list = new LinkedList(); for (ItemStack is : ingredients) { - list.addAll(getRecipesForItemFromList(is, recipe, recipesToCheck)); + list.addAll(getRecipesForItemFromList(is, recipe)); } return list; } diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java index f4acd99..8b82ff2 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java @@ -8,9 +8,11 @@ import net.minecraft.inventory.Container; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.ShapedRecipes; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityClientPlayerMP; import net.minecraft.client.gui.inventory.GuiContainer; @@ -20,6 +22,10 @@ + + + +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; @@ -39,7 +45,8 @@ public class RecipeManager { HANDLERS.add(new VanillaRecipeHandler()); HANDLERS.add(new ForgeRecipeHandler()); } - private static final List allRecipes = new LinkedList(); + private static final List allRecipes = new ArrayList(); + private static HashMap> producers=new HashMap(), consumers=new HashMap(); private static int prevListSize = 0; private static IRecipe prevLastElement = null; @@ -76,8 +83,13 @@ public static void scanRecipes() { HashMap recipeExists = new HashMap(); for (IRecipe r : recipes) { WrappedRecipe wr = WrappedRecipe.of(r); - if (wr != null && !CheckIfRecipeAlreadyExists(allRecipes, wr,recipeExists)) - { + if (wr != null && !CheckIfRecipeAlreadyExists(allRecipes, wr,recipeExists)){ + addItem(wr, wr.getOutput().getItem(), producers); + for(Object o:wr.inputs){ + if(o instanceof ItemStack){ + addItem(wr, ((ItemStack) o).getItem(), consumers); + } + } allRecipes.add(wr); } else { fails++; @@ -144,4 +156,23 @@ public static boolean CheckIfRecipeAlreadyExists(List wr, Wrapped return true; } } + + private static void addItem(WrappedRecipe sr, Item out, HashMap> r){ + if(r.containsKey(out)){ + r.get(out).add(sr); + }else{ + ArrayList ls=new ArrayList(); + ls.add(sr); + r.put(out, ls); + } + } + + public static List getProducers(Item i){ + return producers.get(i); + } + + public static List getConsumers(Item i){ + return producers.get(i); + } + } diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/handler/IRecipeHandler.java b/src/main/java/net/lepko/easycrafting/core/recipe/handler/IRecipeHandler.java index 58c8210..a4181eb 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/handler/IRecipeHandler.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/handler/IRecipeHandler.java @@ -13,4 +13,5 @@ public interface IRecipeHandler { public boolean matchItem(ItemStack target, ItemStack candidate, WrappedRecipe recipe); public ItemStack getCraftingResult(WrappedRecipe recipe, List usedIngredients); + } From f24a56f2589cff62c9854baa1115418c86b24b57 Mon Sep 17 00:00:00 2001 From: planetguy32 Date: Mon, 11 May 2015 21:13:44 -0700 Subject: [PATCH 05/13] Fixed foreach in actually crafting things. ++responsiveness --- .../net/lepko/easycrafting/core/recipe/RecipeHelper.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java index 165c29c..65dc519 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java @@ -297,10 +297,11 @@ private static List getRecipesForItemFromList( */ public static WrappedRecipe getValidRecipe(ItemStack result, ItemStack[] ingredients) { - List all = RecipeManager.getAllRecipes(); + if(result==null)return null; + List all = RecipeManager.getConsumers(result.getItem()); + if(all==null)return null; allLoop: for (WrappedRecipe wr : all) { - if (StackUtils.areEqualNoSizeNoNBT(wr.getOutput(), result) - && wr.inputs.size() == ingredients.length) { + if (wr.inputs.size() == ingredients.length) { ingLoop: for (int i = 0; i < ingredients.length; i++) { if (wr.inputs.get(i) instanceof ItemStack) { ItemStack is = (ItemStack) wr.inputs.get(i); From 70c2a81b5bc9d566825254dbd31be0411e0d01ff Mon Sep 17 00:00:00 2001 From: planetguy32 Date: Wed, 13 May 2015 18:42:46 -0700 Subject: [PATCH 06/13] Added a means to stop infinite loops caused by recursive recipes. --- .../core/inventory/gui/GuiEasyCrafting.java | 2 +- .../network/message/MessageEasyCrafting.java | 6 +-- .../core/recipe/RecipeHelper.java | 24 +++++++---- .../core/recipe/RecipeManager.java | 40 ++++++++++++++++++- .../core/recipe/WrappedRecipe.java | 36 +++++++++++++++++ 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java index 583f14f..c01a054 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java @@ -263,7 +263,7 @@ private void onCraftingSlotClick(Slot slot, int slotIndex, int button, int actio if (isRightClick) { // Right click; craft until max stack int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, heldStack); - int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, false, maxTimes, ConfigHandler.MAX_RECURSION); + int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, false, maxTimes, ConfigHandler.MAX_RECURSION, false); if (timesCrafted > 0) { finalStack.stackSize = finalStackSize + (timesCrafted - 1) * finalStack.stackSize; mc.thePlayer.inventory.setItemStack(finalStack); diff --git a/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java index 3f38cc6..02d44d5 100644 --- a/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java @@ -100,7 +100,7 @@ public void run(EntityPlayer player, Side side) { ItemStack stack_in_hand = player.inventory.getItemStack(); // We need this call to canCraft() to populate the output in getCraftingResult() with NBT - if (RecipeHelper.canCraft(recipe, player.inventory, false, 1, ConfigHandler.MAX_RECURSION) == 0) { + if (RecipeHelper.canCraft(recipe, player.inventory, false, 1, ConfigHandler.MAX_RECURSION, false) == 0) { return; } @@ -124,14 +124,14 @@ public void run(EntityPlayer player, Side side) { InventoryUtils.addItemToInventory(player.inventory, return_stack); } } else { - if (RecipeHelper.canCraft(recipe, player.inventory, true, 1, ConfigHandler.MAX_RECURSION) > 0) { + if (RecipeHelper.canCraft(recipe, player.inventory, true, 1, ConfigHandler.MAX_RECURSION, false) > 0) { return_stack.stackSize = return_size; player.inventory.setItemStack(return_stack); } } } else { int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(return_stack, stack_in_hand); - int timesCrafted = RecipeHelper.canCraft(recipe, player.inventory, true, maxTimes, ConfigHandler.MAX_RECURSION); + int timesCrafted = RecipeHelper.canCraft(recipe, player.inventory, true, maxTimes, ConfigHandler.MAX_RECURSION, false); if (timesCrafted > 0) { return_stack.stackSize = return_size + (timesCrafted - 1) * return_stack.stackSize; player.inventory.setItemStack(return_stack); diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java index 65dc519..66f2892 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java @@ -19,7 +19,7 @@ public class RecipeHelper { * Check if a recipe can be crafted with the ingredients from the inventory. */ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory) { - return canCraft(recipe, inventory, false, 1, 0) > 0; + return canCraft(recipe, inventory, false, 1, 0, false) > 0; } /** @@ -28,7 +28,7 @@ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory) { */ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, List recipesToCheck, int recursion) { - return canCraft(recipe, inventory, false, 1, recursion) > 0; + return canCraft(recipe, inventory, false, 1, recursion, false) > 0; } /** @@ -44,13 +44,21 @@ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, * @param recursion * - how deep to recurse while trying to craft an ingredient * (must be nonnegative) + * @param strictRecursion If this is set to true, will not recurse through + * - another recipe that causes pathological recursion. */ public static int canCraft(WrappedRecipe recipe, IInventory inventory, - boolean take, int maxTimes, int recursion) { + boolean take, int maxTimes, int recursion, boolean strictRecursion) { if (recursion < 0) { return 0; } - + + if(recipe.knownToCauseRecursionProblems){ + if(strictRecursion) + return 0; + strictRecursion=true; + } + recipe.usedIngredients.clear(); int invSize = InventoryUtils.getMainInventorySize(inventory); InventoryBasic tmp = new InventoryBasic("tmp", true, invSize); @@ -74,7 +82,7 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, List list = getRecipesForItemFromList( ingredient, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, true, 1, recursion - 1) > 0) { + if (canCraft(wr, tmp, true, 1, recursion - 1, strictRecursion) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; @@ -108,7 +116,7 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, List list = getRecipesForItemFromList( ingredients, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, true, 1, recursion - 1) > 0) { + if (canCraft(wr, tmp, true, 1, recursion - 1, strictRecursion) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; @@ -174,7 +182,7 @@ public static int canCraftWithComponents(WrappedRecipe recipe, ingredient, recipe); for (WrappedRecipe wr : list) { if (canCraft(wr, tmp, true, 1, - recursion - 1) > 0) { + recursion - 1, false) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; @@ -208,7 +216,7 @@ public static int canCraftWithComponents(WrappedRecipe recipe, List list = getRecipesForItemFromList( ingredients, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, true, 1, recursion - 1) > 0) { + if (canCraft(wr, tmp, true, 1, recursion - 1, false) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java index 8b82ff2..04005f5 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java @@ -77,6 +77,8 @@ public static void scanRecipes() { prevLastElement = recipes.get(recipes.size() - 1); allRecipes.clear(); + producers.clear(); + consumers.clear(); long startTime = System.nanoTime(); int fails = 0; @@ -98,7 +100,6 @@ public static void scanRecipes() { Collections.sort(allRecipes, WrappedRecipe.Sorter.INSTANCE); - Ref.LOGGER.info(String.format( "Scanned %d recipes (%d failed) in %.8f seconds", recipes.size(), fails, @@ -176,3 +177,40 @@ public static List getConsumers(Item i){ } } + +/* Infinite loop: + +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed +[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemReed@7083ef3d +*/ \ No newline at end of file diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java b/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java index 1dded76..f4b30c1 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java @@ -1,10 +1,12 @@ package net.lepko.easycrafting.core.recipe; import com.google.common.primitives.Ints; + import net.lepko.easycrafting.Ref; import net.lepko.easycrafting.core.recipe.handler.IRecipeHandler; import net.lepko.easycrafting.core.util.StackUtils; import net.lepko.easycrafting.core.util.WrappedStack; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; @@ -14,6 +16,18 @@ import java.util.List; public class WrappedRecipe { + + private static Class[] problemItemClasses; + + static{ + List classes=new ArrayList(); + try { //make one try/catch block per set of classes that might be independently installed + classes.add(Class.forName("tconstruct.world.itemblocks.WoolSlab1Item")); + classes.add(Class.forName("tconstruct.world.itemblocks.WoolSlab2Item")); + } catch (ClassNotFoundException e) { + } + problemItemClasses=classes.toArray(new Class[0]); + } public final IRecipe recipe; public final List inputs; @@ -21,6 +35,7 @@ public class WrappedRecipe { public final WrappedStack output; public final IRecipeHandler handler; public final List usedIngredients; + public final boolean knownToCauseRecursionProblems; private WrappedRecipe(IRecipe recipe, List inputs, WrappedStack output, IRecipeHandler handler) { this.recipe = recipe; @@ -29,6 +44,23 @@ private WrappedRecipe(IRecipe recipe, List inputs, WrappedStack output, this.output = output; this.handler = handler; this.usedIngredients = new ArrayList(9); + knownToCauseRecursionProblems=checkKnownRecursionProblems(); + } + + private boolean checkKnownRecursionProblems() { + for(WrappedStack stk:collatedInputs){ + if(output.stacks.get(0).getItem()==stk.stacks.get(0).getItem()) + return true; + } + Item i=output.stacks.get(0).getItem(); + if(i != null){ + for(Class c:problemItemClasses){ + if(c.isAssignableFrom(i.getClass())){ + return true; + } + } + } + return false; } public ItemStack getOutput() { @@ -136,4 +168,8 @@ public int compare(WrappedRecipe first, WrappedRecipe second) { } } } + + public String toString(){ + return collatedInputs + "->" + output; + } } From 634f7b2b6fc0f93d69bbb020098dc012c06fec25 Mon Sep 17 00:00:00 2001 From: planetguy32 Date: Thu, 14 May 2015 06:45:02 -0700 Subject: [PATCH 07/13] Keep recursion check minimal - wool slab check is unnecessary --- .../core/recipe/WrappedRecipe.java | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java b/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java index f4b30c1..b51146a 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java @@ -17,18 +17,6 @@ public class WrappedRecipe { - private static Class[] problemItemClasses; - - static{ - List classes=new ArrayList(); - try { //make one try/catch block per set of classes that might be independently installed - classes.add(Class.forName("tconstruct.world.itemblocks.WoolSlab1Item")); - classes.add(Class.forName("tconstruct.world.itemblocks.WoolSlab2Item")); - } catch (ClassNotFoundException e) { - } - problemItemClasses=classes.toArray(new Class[0]); - } - public final IRecipe recipe; public final List inputs; public final List collatedInputs; @@ -52,14 +40,6 @@ private boolean checkKnownRecursionProblems() { if(output.stacks.get(0).getItem()==stk.stacks.get(0).getItem()) return true; } - Item i=output.stacks.get(0).getItem(); - if(i != null){ - for(Class c:problemItemClasses){ - if(c.isAssignableFrom(i.getClass())){ - return true; - } - } - } return false; } @@ -172,4 +152,5 @@ public int compare(WrappedRecipe first, WrappedRecipe second) { public String toString(){ return collatedInputs + "->" + output; } + } From 59c56eecdedfc3dd252485c3162c6154b735860c Mon Sep 17 00:00:00 2001 From: Anon Date: Fri, 15 May 2015 17:39:15 -0500 Subject: [PATCH 08/13] Change focus on search field No longer locked onto focus field. Really annoying. --- .../easycrafting/core/inventory/gui/GuiEasyCrafting.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java index 4dece57..f38b8f7 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java @@ -89,8 +89,8 @@ public void initGui() { searchField.setEnableBackgroundDrawing(false); searchField.setVisible(true); searchField.setTextColor(0xFFFFFF); - searchField.setCanLoseFocus(false); - searchField.setFocused(true); + searchField.setCanLoseFocus(true); + searchField.setFocused(false); searchField.setText(LAST_SEARCH); } From a84ce02438bf8c934ee2143e469f79e995c6f4e4 Mon Sep 17 00:00:00 2001 From: Anon Date: Sun, 17 May 2015 14:41:25 -0500 Subject: [PATCH 09/13] Revert Searchfield changes. Fix getConsumers Revert searchfield changes cause they weren't working anyways. Getconsumers was using producers list. --- .../core/inventory/gui/GuiEasyCrafting.java | 4 +- .../core/recipe/RecipeHelper.java | 15 ++---- .../core/recipe/RecipeManager.java | 48 ++++--------------- 3 files changed, 15 insertions(+), 52 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java index 9d1f101..c01a054 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java @@ -89,8 +89,8 @@ public void initGui() { searchField.setEnableBackgroundDrawing(false); searchField.setVisible(true); searchField.setTextColor(0xFFFFFF); - searchField.setCanLoseFocus(true); - searchField.setFocused(false); + searchField.setCanLoseFocus(false); + searchField.setFocused(true); searchField.setText(LAST_SEARCH); } diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java index 66f2892..029e792 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java @@ -1,11 +1,9 @@ package net.lepko.easycrafting.core.recipe; -import net.lepko.easycrafting.Ref; import net.lepko.easycrafting.core.util.InventoryUtils; import net.lepko.easycrafting.core.util.StackUtils; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryBasic; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.MathHelper; @@ -83,12 +81,10 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, ingredient, recipe); for (WrappedRecipe wr : list) { if (canCraft(wr, tmp, true, 1, recursion - 1, strictRecursion) > 0) { - ItemStack is = wr.handler.getCraftingResult(wr, - wr.usedIngredients); + ItemStack is = wr.handler.getCraftingResult(wr,wr.usedIngredients); is.stackSize--; if (is.stackSize > 0 - && !InventoryUtils.addItemToInventory( - tmp, is)) { + && !InventoryUtils.addItemToInventory(tmp, is)) { break timesLoop; } ItemStack usedItemStack = is.copy(); @@ -277,8 +273,7 @@ private static int isItemInInventory(List ing, return -1; } - private static List getRecipesForItemFromList( - ItemStack ingredient, WrappedRecipe recipe) { + private static List getRecipesForItemFromList(ItemStack ingredient, WrappedRecipe recipe) { List list = new ArrayList(); if(ingredient != null && ingredient.getItem() != null){ List recipes=RecipeManager.getProducers(ingredient.getItem()); @@ -290,9 +285,7 @@ private static List getRecipesForItemFromList( return list; } - - private static List getRecipesForItemFromList( - List ingredients, WrappedRecipe recipe) { + private static List getRecipesForItemFromList(List ingredients, WrappedRecipe recipe) { List list = new LinkedList(); for (ItemStack is : ingredients) { list.addAll(getRecipesForItemFromList(is, recipe)); diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java index 04005f5..75b15b1 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeManager.java @@ -66,7 +66,7 @@ private static boolean shouldScan(List recipes) { } return false; } - + @SuppressWarnings("unchecked") public static void scanRecipes() { @SuppressWarnings("unchecked") List recipes = CraftingManager.getInstance().getRecipeList(); @@ -91,6 +91,13 @@ public static void scanRecipes() { if(o instanceof ItemStack){ addItem(wr, ((ItemStack) o).getItem(), consumers); } + else if(o instanceof List){ + ArrayList ar = (ArrayList)o; + for (ItemStack is : ar) + { + addItem(wr, is.getItem(), consumers); + } + } } allRecipes.add(wr); } else { @@ -173,44 +180,7 @@ public static List getProducers(Item i){ } public static List getConsumers(Item i){ - return producers.get(i); + return consumers.get(i); } } - -/* Infinite loop: - -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab1Item@e5c3248 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for tconstruct.world.itemblocks.WoolSlab2Item@31660f49 -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemCloth@474cc5ed -[17:46:37] [EasyCrafting-CraftabilityChecker/INFO] [EasyCrafting/]: Call for net.minecraft.item.ItemReed@7083ef3d -*/ \ No newline at end of file From 0c045baa824d32677017642ffd77bc35528302c4 Mon Sep 17 00:00:00 2001 From: planetguy32 Date: Fri, 5 Jun 2015 19:58:35 -0700 Subject: [PATCH 10/13] Replaced old recipe loop check with a more comprehensive (but slightly slower) version --- .../core/inventory/gui/GuiEasyCrafting.java | 2 +- .../network/message/MessageEasyCrafting.java | 6 +-- .../core/recipe/RecipeHelper.java | 51 ++++++++++++------- .../core/recipe/WrappedRecipe.java | 10 ---- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java index c01a054..583f14f 100644 --- a/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/inventory/gui/GuiEasyCrafting.java @@ -263,7 +263,7 @@ private void onCraftingSlotClick(Slot slot, int slotIndex, int button, int actio if (isRightClick) { // Right click; craft until max stack int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(slotStack, heldStack); - int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, false, maxTimes, ConfigHandler.MAX_RECURSION, false); + int timesCrafted = RecipeHelper.canCraft(recipe, mc.thePlayer.inventory, false, maxTimes, ConfigHandler.MAX_RECURSION); if (timesCrafted > 0) { finalStack.stackSize = finalStackSize + (timesCrafted - 1) * finalStack.stackSize; mc.thePlayer.inventory.setItemStack(finalStack); diff --git a/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java b/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java index 02d44d5..3f38cc6 100644 --- a/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/network/message/MessageEasyCrafting.java @@ -100,7 +100,7 @@ public void run(EntityPlayer player, Side side) { ItemStack stack_in_hand = player.inventory.getItemStack(); // We need this call to canCraft() to populate the output in getCraftingResult() with NBT - if (RecipeHelper.canCraft(recipe, player.inventory, false, 1, ConfigHandler.MAX_RECURSION, false) == 0) { + if (RecipeHelper.canCraft(recipe, player.inventory, false, 1, ConfigHandler.MAX_RECURSION) == 0) { return; } @@ -124,14 +124,14 @@ public void run(EntityPlayer player, Side side) { InventoryUtils.addItemToInventory(player.inventory, return_stack); } } else { - if (RecipeHelper.canCraft(recipe, player.inventory, true, 1, ConfigHandler.MAX_RECURSION, false) > 0) { + if (RecipeHelper.canCraft(recipe, player.inventory, true, 1, ConfigHandler.MAX_RECURSION) > 0) { return_stack.stackSize = return_size; player.inventory.setItemStack(return_stack); } } } else { int maxTimes = RecipeHelper.calculateCraftingMultiplierUntilMaxStack(return_stack, stack_in_hand); - int timesCrafted = RecipeHelper.canCraft(recipe, player.inventory, true, maxTimes, ConfigHandler.MAX_RECURSION, false); + int timesCrafted = RecipeHelper.canCraft(recipe, player.inventory, true, maxTimes, ConfigHandler.MAX_RECURSION); if (timesCrafted > 0) { return_stack.stackSize = return_size + (timesCrafted - 1) * return_stack.stackSize; player.inventory.setItemStack(return_stack); diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java index 029e792..3200cbe 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java @@ -2,12 +2,15 @@ import net.lepko.easycrafting.core.util.InventoryUtils; import net.lepko.easycrafting.core.util.StackUtils; +import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryBasic; import net.minecraft.item.ItemStack; import net.minecraft.util.MathHelper; +import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Deque; import java.util.LinkedList; import java.util.List; @@ -17,7 +20,7 @@ public class RecipeHelper { * Check if a recipe can be crafted with the ingredients from the inventory. */ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory) { - return canCraft(recipe, inventory, false, 1, 0, false) > 0; + return canCraft(recipe, inventory, false, 1, 0, new ArrayDeque()) > 0; } /** @@ -26,9 +29,9 @@ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory) { */ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, List recipesToCheck, int recursion) { - return canCraft(recipe, inventory, false, 1, recursion, false) > 0; + return canCraft(recipe, inventory, false, 1, recursion, new ArrayDeque()) > 0; } - + /** * Check if a recipe can be crafted with the ingredients from the inventory. * If an ingredient is missing try to craft it from a list of recipes. @@ -42,21 +45,25 @@ public static boolean canCraft(WrappedRecipe recipe, IInventory inventory, * @param recursion * - how deep to recurse while trying to craft an ingredient * (must be nonnegative) - * @param strictRecursion If this is set to true, will not recurse through - * - another recipe that causes pathological recursion. */ + public static int canCraft(WrappedRecipe recipe, IInventory inventory, - boolean take, int maxTimes, int recursion, boolean strictRecursion) { + boolean take, int maxTimes, int recursion) { + return canCraft(recipe, inventory, take, maxTimes, recursion, new ArrayDeque()); + } + + private static int canCraft(WrappedRecipe recipe, IInventory inventory, + boolean take, int maxTimes, int recursion, Deque checkedRecipeOutputs) { if (recursion < 0) { return 0; } - if(recipe.knownToCauseRecursionProblems){ - if(strictRecursion) - return 0; - strictRecursion=true; + if(checkedRecipeOutputs.contains(recipe.output.stacks.get(0).getItem())){ + return 0; } + checkedRecipeOutputs.addFirst(recipe.output.stacks.get(0).getItem()); + recipe.usedIngredients.clear(); int invSize = InventoryUtils.getMainInventorySize(inventory); InventoryBasic tmp = new InventoryBasic("tmp", true, invSize); @@ -80,7 +87,7 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, List list = getRecipesForItemFromList( ingredient, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, true, 1, recursion - 1, strictRecursion) > 0) { + if (canCraft(wr, tmp, true, 1, recursion - 1, checkedRecipeOutputs) > 0) { ItemStack is = wr.handler.getCraftingResult(wr,wr.usedIngredients); is.stackSize--; if (is.stackSize > 0 @@ -112,7 +119,7 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, List list = getRecipesForItemFromList( ingredients, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, true, 1, recursion - 1, strictRecursion) > 0) { + if (canCraft(wr, tmp, true, 1, recursion - 1, checkedRecipeOutputs) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; @@ -142,14 +149,23 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, InventoryUtils.setContents(inventory, tmp2); } } + + checkedRecipeOutputs.removeFirst(); + return timesCrafted; } + + public static int canCraftWithComponents(WrappedRecipe recipe, + InventoryPlayer inventory, boolean b, int maxTimes, + int maxRecursion) { + return canCraftWithComponents(recipe, inventory, b, maxTimes, maxRecursion, new ArrayDeque()); + } // / Checks inventory size and sees if all crafted components + recipe // output can fit in the inventory. Used for shift-click crafting - public static int canCraftWithComponents(WrappedRecipe recipe, + private static int canCraftWithComponents(WrappedRecipe recipe, IInventory inventory, boolean take, - int maxTimes, int recursion) { + int maxTimes, int recursion, Deque checkedRecipes) { if (recursion < 0) { return 0; } @@ -178,7 +194,7 @@ public static int canCraftWithComponents(WrappedRecipe recipe, ingredient, recipe); for (WrappedRecipe wr : list) { if (canCraft(wr, tmp, true, 1, - recursion - 1, false) > 0) { + recursion - 1, checkedRecipes) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; @@ -212,7 +228,7 @@ public static int canCraftWithComponents(WrappedRecipe recipe, List list = getRecipesForItemFromList( ingredients, recipe); for (WrappedRecipe wr : list) { - if (canCraft(wr, tmp, true, 1, recursion - 1, false) > 0) { + if (canCraft(wr, tmp, true, 1, recursion - 1, checkedRecipes) > 0) { ItemStack is = wr.handler.getCraftingResult(wr, wr.usedIngredients); is.stackSize--; @@ -299,7 +315,7 @@ private static List getRecipesForItemFromList(List ing public static WrappedRecipe getValidRecipe(ItemStack result, ItemStack[] ingredients) { if(result==null)return null; - List all = RecipeManager.getConsumers(result.getItem()); + List all = RecipeManager.getProducers(result.getItem()); if(all==null)return null; allLoop: for (WrappedRecipe wr : all) { if (wr.inputs.size() == ingredients.length) { @@ -356,4 +372,5 @@ public static int calculateCraftingMultiplierUntilMaxStack( } return maxTimes; } + } diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java b/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java index b51146a..0863eaf 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/WrappedRecipe.java @@ -23,7 +23,6 @@ public class WrappedRecipe { public final WrappedStack output; public final IRecipeHandler handler; public final List usedIngredients; - public final boolean knownToCauseRecursionProblems; private WrappedRecipe(IRecipe recipe, List inputs, WrappedStack output, IRecipeHandler handler) { this.recipe = recipe; @@ -32,17 +31,8 @@ private WrappedRecipe(IRecipe recipe, List inputs, WrappedStack output, this.output = output; this.handler = handler; this.usedIngredients = new ArrayList(9); - knownToCauseRecursionProblems=checkKnownRecursionProblems(); } - private boolean checkKnownRecursionProblems() { - for(WrappedStack stk:collatedInputs){ - if(output.stacks.get(0).getItem()==stk.stacks.get(0).getItem()) - return true; - } - return false; - } - public ItemStack getOutput() { return StackUtils.copyStack(output.stacks.get(0), output.size); } From ff3318b43b2fbf4150af57f58ef7410e7ef946cf Mon Sep 17 00:00:00 2001 From: SergeyCherepanov Date: Sun, 7 Jun 2015 20:39:56 +0400 Subject: [PATCH 11/13] fix inventory update event --- .../lepko/easycrafting/core/block/TileEntityAutoCrafting.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/lepko/easycrafting/core/block/TileEntityAutoCrafting.java b/src/main/java/net/lepko/easycrafting/core/block/TileEntityAutoCrafting.java index 5fcc98c..9c107f1 100644 --- a/src/main/java/net/lepko/easycrafting/core/block/TileEntityAutoCrafting.java +++ b/src/main/java/net/lepko/easycrafting/core/block/TileEntityAutoCrafting.java @@ -300,6 +300,7 @@ public ItemStack getStackInSlotOnClosing(int slotIndex) { @Override public void setInventorySlotContents(int slotIndex, ItemStack stack) { + inventoryChanged = true; inventory[slotIndex] = stack; } From 05ff543d9518af89fce13190a32c803dede9a9ee Mon Sep 17 00:00:00 2001 From: planetguy32 Date: Sun, 7 Jun 2015 10:40:34 -0700 Subject: [PATCH 12/13] Added timeout to help find recipe loops --- .../core/recipe/RecipeChecker.java | 36 +++++++++++++++---- .../core/recipe/RecipeHelper.java | 4 +++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java index 4fb0399..e265890 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeChecker.java @@ -1,6 +1,7 @@ package net.lepko.easycrafting.core.recipe; import com.google.common.collect.ImmutableList; + import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.TickEvent; @@ -16,6 +17,8 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; @SideOnly(Side.CLIENT) public enum RecipeChecker { @@ -59,7 +62,32 @@ public void setRequested(boolean requested) { this.requested = requested; } - + //Timeout code for craftability check - mostly for debugging purposes + + static final ExecutorService timekeeperThread=Executors.newFixedThreadPool(1); + + static Runnable timekeeperTask() { + return new Runnable(){ + public void run() { + try { + Thread.sleep(500L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + while(!RecipeHelper.state.isEmpty()) { + if(!RecipeHelper.state.isEmpty()){ + Ref.LOGGER.info("Long operation in recipe chain "+RecipeHelper.state); + } + try { + Thread.sleep(500L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }; + } + private class CraftabilityChecker implements Runnable { @Override @@ -73,15 +101,11 @@ public void run() { setCraftableRecipes(); } - - try { - Thread.sleep(50L); - } catch (InterruptedException ignored) { - } } } private void setCraftableRecipes() { + timekeeperThread.submit(timekeeperTask()); InventoryPlayer inventory = mc.thePlayer.inventory; recipes = getCraftableRecipes(inventory, ConfigHandler.MAX_RECURSION, ConfigHandler.MAX_TIME, RecipeManager.getAllRecipes()); done = !suspended; diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java index 3200cbe..014512e 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java @@ -15,6 +15,8 @@ import java.util.List; public class RecipeHelper { + + public static Deque state; /** * Check if a recipe can be crafted with the ingredients from the inventory. @@ -58,6 +60,8 @@ private static int canCraft(WrappedRecipe recipe, IInventory inventory, return 0; } + state=checkedRecipeOutputs; + if(checkedRecipeOutputs.contains(recipe.output.stacks.get(0).getItem())){ return 0; } From e557c215f9210a235181eb0b26b4d7616d0dcf0e Mon Sep 17 00:00:00 2001 From: planetguy32 Date: Sun, 7 Jun 2015 12:53:12 -0700 Subject: [PATCH 13/13] Ore-dictionary-based item removal filter --- .../core/recipe/RecipeHelper.java | 71 +++++++++++++++++-- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java index 014512e..a0d5f01 100644 --- a/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java +++ b/src/main/java/net/lepko/easycrafting/core/recipe/RecipeHelper.java @@ -7,12 +7,15 @@ import net.minecraft.inventory.InventoryBasic; import net.minecraft.item.ItemStack; import net.minecraft.util.MathHelper; +import net.minecraftforge.oredict.OreDictionary; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Set; public class RecipeHelper { @@ -53,21 +56,17 @@ public static int canCraft(WrappedRecipe recipe, IInventory inventory, boolean take, int maxTimes, int recursion) { return canCraft(recipe, inventory, take, maxTimes, recursion, new ArrayDeque()); } - + private static int canCraft(WrappedRecipe recipe, IInventory inventory, boolean take, int maxTimes, int recursion, Deque checkedRecipeOutputs) { if (recursion < 0) { return 0; } - state=checkedRecipeOutputs; - - if(checkedRecipeOutputs.contains(recipe.output.stacks.get(0).getItem())){ + if(!canRecurse(checkedRecipeOutputs, recipe.getOutput())){ return 0; } - checkedRecipeOutputs.addFirst(recipe.output.stacks.get(0).getItem()); - recipe.usedIngredients.clear(); int invSize = InventoryUtils.getMainInventorySize(inventory); InventoryBasic tmp = new InventoryBasic("tmp", true, invSize); @@ -376,5 +375,65 @@ public static int calculateCraftingMultiplierUntilMaxStack( } return maxTimes; } + + /** + * Checks if we already know how to make the given item. + */ + private static boolean canRecurse(Deque checkedRecipeOutputs, ItemStack outputStack){ + state=checkedRecipeOutputs; + + boolean useOreDict=false; + + OreDictionaryCheck odc=new OreDictionaryCheck(); + + for(int i: OreDictionary.getOreIDs(outputStack)) { + odc.addInt(i); + useOreDict=true; + } + + Object key=useOreDict ? odc : outputStack.getItem(); + + if(checkedRecipeOutputs.contains(key)) + return false; + else + checkedRecipeOutputs.addFirst(key); + + return true; + } + + /** + * Utility class for comparing things by ore dictionary + * @author planetguy + * + */ + private static class OreDictionaryCheck { + + private Set set=new HashSet(); + + public void addInt(int i){ + set.add(i); + } + + public boolean bigEnough(){ + return set.size() != 0; + } + + public boolean equals(Object o){ + if(o instanceof OreDictionaryCheck) + return equals((OreDictionaryCheck) o); + else + return false; + } + + //Abuses equals() a bit + public boolean equals(OreDictionaryCheck c){ + for(Integer i:set){ + if(c.set.contains(i)) + return true; + } + return false; + } + + } }