diff --git a/src/main/scala/mrtjp/projectred/expansion/TileAutoCrafter.scala b/src/main/scala/mrtjp/projectred/expansion/TileAutoCrafter.scala index 7c1421194..989c6a586 100644 --- a/src/main/scala/mrtjp/projectred/expansion/TileAutoCrafter.scala +++ b/src/main/scala/mrtjp/projectred/expansion/TileAutoCrafter.scala @@ -171,9 +171,8 @@ class TileAutoCrafter def containsEnoughResource(item: ItemKey, amount: Int): Boolean = { val eq = new ItemEquality eq.matchMeta = !item.makeStack(0).isItemStackDamageable - eq.matchNBT = false - eq.matchOre = currentRecipe.isInstanceOf[ShapedOreRecipe] || currentRecipe - .isInstanceOf[ShapelessOreRecipe] + eq.matchNBT = true + eq.matchOre = false var found = 0 for (i <- 9 until 27) { @@ -201,9 +200,8 @@ class TileAutoCrafter def eatResource(item: ItemKey, amount: Int) { val eq = new ItemEquality eq.matchMeta = !item.makeStack(0).isItemStackDamageable - eq.matchNBT = false - eq.matchOre = currentRecipe.isInstanceOf[ShapedOreRecipe] || currentRecipe - .isInstanceOf[ShapelessOreRecipe] + eq.matchNBT = true + eq.matchOre = false var left = amount for (i <- 9 until 27) { @@ -349,15 +347,6 @@ class GuiAutoCrafter(tile: TileAutoCrafter, c: ContainerAutoCrafter) GuiDraw.drawString("Auto Crafting Bench", 8, 6, Colors.GREY.argb, false) GuiDraw.drawString("Inventory", 8, 120, Colors.GREY.argb, false) } - - override def drawFront_Impl(mouse: Point, rframe: Float) { - if ( - Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown( - Keyboard.KEY_RSHIFT - ) - ) - GuiProjectBench.drawPlanOutputOverlay(c.slots) - } } object GuiAutoCrafter extends TGuiBuilder { diff --git a/src/main/scala/mrtjp/projectred/expansion/TileProjectBench.scala b/src/main/scala/mrtjp/projectred/expansion/TileProjectBench.scala index 46ece47f6..64c60eda4 100644 --- a/src/main/scala/mrtjp/projectred/expansion/TileProjectBench.scala +++ b/src/main/scala/mrtjp/projectred/expansion/TileProjectBench.scala @@ -6,7 +6,6 @@ package mrtjp.projectred.expansion import java.util.{List => JList} - import codechicken.lib.data.MCDataInput import codechicken.lib.gui.GuiDraw import codechicken.lib.render.uv.{MultiIconTransformation, UVTransformation} @@ -36,7 +35,6 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.IIcon import net.minecraft.world.{IBlockAccess, World} import net.minecraftforge.oredict.{ShapedOreRecipe, ShapelessOreRecipe} -import org.lwjgl.input.Keyboard import scala.collection.JavaConversions._ @@ -200,15 +198,17 @@ class SlotProjectCrafting( tile.currentRecipe, tile.currentInputs, storage - ) + ) && tile.currentRecipe.matches(tile.invCrafting, tile.world) } // copied from super for obfuscation bug - canRemoveDelegate() + canRemoveDelegate() && tile.currentRecipe.matches( + tile.invCrafting, + tile.world + ) } override def onPickupFromSlot(player: EntityPlayer, stack: ItemStack) { - onCrafting(stack) val storage = ((9 until 27) ++ (0 until 9)).map { i => val s = tile.getStackInSlot(i) @@ -232,14 +232,75 @@ class SlotProjectCrafting( } } - val invCrafting = new InventoryCrafting(new NodeContainer, 3, 3) - for (i <- 0 until 9) - invCrafting.setInventorySlotContents(i, tile.currentInputs(i)) - FMLCommonHandler - .instance() - .firePlayerCraftingEvent(player, stack, invCrafting) + FMLCommonHandler.instance.firePlayerCraftingEvent( + player, + stack, + tile.invCrafting + ) + onCrafting(stack) + + for (i <- 0 until 9) { + val gridStack = tile.invCrafting.getStackInSlot( + i + ) // current real item in grid (maybe null or decreased) + val remainder = getRemaining(i, tile.invCrafting) + + if (remainder != null && gridStack != null) { + // Case 1: No plan active AND this grid slot is now empty → put remainder back in grid + if (!tile.isPlanRecipe && (gridStack.isItemEqual(remainder))) { + tile.setInventorySlotContents(i, remainder) + } + // Case 2: Try to merge remainder into storage slots (9-26) or player inventory + else if ( + !tryAddToStorageSlots(remainder) && + !player.inventory.addItemStackToInventory(remainder) + ) { + // If no space anywhere, drop it + player.dropPlayerItemWithRandomChoice(remainder, false) + } + } + } tile.updateRecipe() + + } + def tryAddToStorageSlots(stack: ItemStack): Boolean = { + // Try to merge into storage slots 9-26 + for (j <- 9 until 27) { + val slotStack = tile.getStackInSlot(j) + if ( + slotStack != null && slotStack.isItemEqual(stack) && + ItemStack.areItemStackTagsEqual(slotStack, stack) && + slotStack.stackSize < slotStack.getMaxStackSize + ) { + val space = slotStack.getMaxStackSize - slotStack.stackSize + val toAdd = Math.min(space, stack.stackSize) + slotStack.stackSize += toAdd + stack.stackSize -= toAdd + if (stack.stackSize <= 0) return true + } + } + + // Try to place in empty storage slot + for (j <- 9 until 27) { + if (tile.getStackInSlot(j) == null) { + tile.setInventorySlotContents(j, stack) + return true + } + } + + false + } + + def getRemaining(i: Int, invCrafting: InventoryCrafting): ItemStack = { + val stack = invCrafting.getStackInSlot(i) + + if (stack != null) { + val item = stack.getItem + if (item != null && item.hasContainerItem(stack)) { + item.getContainerItem(stack) + } else null + } else null } def searchFor( @@ -248,16 +309,16 @@ class SlotProjectCrafting( inputs: Array[ItemStack], storage: Array[ItemStack] ): Boolean = { - i = 0 - val invCrafting = new InventoryCrafting(new NodeContainer, 3, 3) + if (tile.isPlanRecipe) i = 0 else i = 17 for (i <- 0 until 9) { val item = inputs(i) if (item != null) { - if (!eatResource(recipe, item, storage)) return false - invCrafting.setInventorySlotContents(i, item) + val eatenItem = eatResource(recipe, item, storage) + if (eatenItem == null) return false + tile.invCrafting.setInventorySlotContents(i, eatenItem) } } - recipe.matches(invCrafting, world) + recipe.matches(tile.invCrafting, world) } private var i = 0 @@ -265,25 +326,24 @@ class SlotProjectCrafting( recipe: IRecipe, stack1: ItemStack, storage: Array[ItemStack] - ): Boolean = { + ): ItemStack = { def increment() = { i = (i + 1) % storage.length; i } - if (i < 18) i = 0 else increment() + if (!tile.isPlanRecipe) increment() val start = i do { val stack2 = storage(i) if (stack2 != null && ingredientMatch(recipe, stack1, stack2)) { - if (stack2.getItem.hasContainerItem(stack2)) { - val cStack = stack2.getItem.getContainerItem(stack2) - storage(i) = - if (cStack.getItemDamage < cStack.getMaxDamage) cStack else null - return true - } else if (stack2.stackSize >= 1) { - stack2.stackSize -= 1 - return true + stack2.stackSize -= 1; + if (stack2.stackSize <= 0) { + storage(i) = null; } + + val copy = stack2.copy(); + copy.stackSize = 1; + return copy; } } while (increment() != start) - false + null } private def ingredientMatch( @@ -291,11 +351,11 @@ class SlotProjectCrafting( stack1: ItemStack, stack2: ItemStack ) = { + val eq = new ItemEquality eq.matchMeta = !stack1.isItemStackDamageable - eq.matchNBT = false - eq.matchOre = recipe.isInstanceOf[ShapedOreRecipe] || recipe - .isInstanceOf[ShapelessOreRecipe] + eq.matchNBT = true + eq.matchOre = false eq.matches(ItemKey.get(stack1), ItemKey.get(stack2)) } @@ -337,15 +397,11 @@ class ContainerProjectBench(player: EntityPlayer, tile: TileProjectBench) detectAndSendChanges() } - override def slotClick( - id: Int, - mouse: Int, - shift: Int, - player: EntityPlayer - ) = { - var mode = shift - if (id == 28 && mode == 6) mode = 0 - super.slotClick(id, mouse, mode, player) + override def transferStackInSlot(player: EntityPlayer, i: Int): ItemStack = { + if (i == 28 && !getSlot(28).canTakeStack(player)) + null + else + super.transferStackInSlot(player, i) } override def doMerge(stack: ItemStack, from: Int): Boolean = { @@ -354,7 +410,7 @@ class ContainerProjectBench(player: EntityPlayer, tile: TileProjectBench) if (tryMergeItemStack(stack, 9, 27, false)) return true // merge to storage if (tryMergeItemStack(stack, 29, 65, false)) - return true // merge to inventory) + return true // merge to inventory } else if (9 until 27 contains from) // storage { if (stack.getItem.isInstanceOf[ItemPlan]) { @@ -375,7 +431,7 @@ class ContainerProjectBench(player: EntityPlayer, tile: TileProjectBench) if (tryMergeItemStack(stack, 9, 27, true)) return true // merge to storage if (tryMergeItemStack(stack, 29, 65, false)) - return true // merge to inventory) + return true // merge to inventory } else if (from == 28) // output slot { if (tryMergeItemStack(stack, 29, 65, true)) @@ -455,15 +511,6 @@ class GuiProjectBench(tile: TileProjectBench, c: ContainerProjectBench) GuiDraw.drawString("Project Bench", 8, 6, Colors.GREY.argb, false) GuiDraw.drawString("Inventory", 8, 116, Colors.GREY.argb, false) } - - override def drawFront_Impl(mouse: Point, rframe: Float) { - if ( - Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown( - Keyboard.KEY_RSHIFT - ) - ) - GuiProjectBench.drawPlanOutputOverlay(c.slots) - } } object GuiProjectBench extends TGuiBuilder { @@ -477,29 +524,6 @@ object GuiProjectBench extends TGuiBuilder { case _ => null } } - - def drawPlanOutputOverlay(slots: Iterable[TSlot3]) { - for (slot <- slots) if (slot.getHasStack) { - val stack = slot.getStack - if (ItemPlan.hasRecipeInside(stack)) { - val output = ItemPlan.loadPlanOutput(stack) - GuiDraw.drawRect( - slot.xDisplayPosition, - slot.yDisplayPosition, - 16, - 16, - Colors.LIGHT_BLUE.argb(0xcc) - ) - ItemDisplayNode.renderItem( - Point(slot.xDisplayPosition + 1, slot.yDisplayPosition + 1), - Size(14, 14), - 0, - true, - output - ) - } - } - } } object RenderProjectBench extends TCubeMapRender { diff --git a/src/main/scala/mrtjp/projectred/expansion/items.scala b/src/main/scala/mrtjp/projectred/expansion/items.scala index 5f801f41e..948f54d5d 100644 --- a/src/main/scala/mrtjp/projectred/expansion/items.scala +++ b/src/main/scala/mrtjp/projectred/expansion/items.scala @@ -6,7 +6,6 @@ package mrtjp.projectred.expansion import java.util.{List => JList} - import codechicken.lib.packet.PacketCustom import codechicken.lib.vec.{BlockCoord, Rotation, Translation, Vector3} import cpw.mods.fml.common.FMLCommonHandler @@ -20,11 +19,14 @@ import mrtjp.core.item.ItemCore import mrtjp.projectred.ProjectRedExpansion import mrtjp.projectred.api.IScrewdriver import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiScreen import net.minecraft.client.model.{ModelBiped, ModelRenderer} +import net.minecraft.client.renderer.RenderHelper +import net.minecraft.client.renderer.entity.RenderItem import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.enchantment.{ - EnchantmentHelper, Enchantment, + EnchantmentHelper, EnumEnchantmentType } import net.minecraft.entity.player.EntityPlayer @@ -35,8 +37,11 @@ import net.minecraft.item.{Item, ItemArmor, ItemStack} import net.minecraft.nbt.{NBTTagCompound, NBTTagList} import net.minecraft.util.{DamageSource, EnumChatFormatting, IIcon} import net.minecraft.world.World +import net.minecraftforge.client.{IItemRenderer, MinecraftForgeClient} import net.minecraftforge.common.ISpecialArmor import net.minecraftforge.common.ISpecialArmor.ArmorProperties +import org.lwjgl.input.Keyboard +import org.lwjgl.opengl.GL11 import scala.collection.mutable.{Set => MSet} @@ -179,12 +184,15 @@ class ItemElectronicScrewdriver class ItemPlan extends ItemCore("projectred.expansion.plan") { setCreativeTab(ProjectRedExpansion.tabExpansion) + if (FMLCommonHandler.instance().getEffectiveSide.isClient) + MinecraftForgeClient.registerItemRenderer(this, new ItemPlanRenderer) var iconBlank: IIcon = null var iconWritten: IIcon = null override def getIconIndex(stack: ItemStack) = - if (ItemPlan.hasRecipeInside(stack)) iconWritten else iconBlank + if (ItemPlan.hasRecipeInside(stack)) iconWritten + else iconBlank override def getIcon(stack: ItemStack, pass: Int) = getIconIndex(stack) @@ -200,13 +208,92 @@ class ItemPlan extends ItemCore("projectred.expansion.plan") { flag: Boolean ) { if (ItemPlan.hasRecipeInside(stack)) { - val s = - s"${EnumChatFormatting.BLUE}Output: ${EnumChatFormatting.GRAY + ItemPlan.loadPlanOutput(stack).getDisplayName}" - list.asInstanceOf[JList[String]].add(s) + val output = ItemPlan.loadPlanOutput(stack); + val inputs = ItemPlan.loadPlanInputs(stack); + + val tooltip = list.asInstanceOf[JList[String]] + + // Output line (with amount) + tooltip.add( + s"${EnumChatFormatting.BLUE}Output: " + + s"${EnumChatFormatting.GRAY}${output.stackSize}x ${output.getDisplayName}" + ) + + // Inputs header + tooltip.add( + s"${EnumChatFormatting.BLUE}Inputs:" + ) + + // Each input item + inputs.foreach { in => + if (in != null) { + tooltip.add( + s" ${EnumChatFormatting.DARK_GRAY}- " + + s"${EnumChatFormatting.GRAY}${in.getDisplayName}" + ) + } else { + tooltip.add( + s" ${EnumChatFormatting.DARK_GRAY}- " + + s"${EnumChatFormatting.GRAY}Empty" + ) + } + } } } } +class ItemPlanRenderer extends IItemRenderer { + final private val ri = new RenderItem + private var recursive = false + + override def handleRenderType( + item: ItemStack, + `type`: IItemRenderer.ItemRenderType + ): Boolean = { + val isShiftHeld = + Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown( + Keyboard.KEY_RSHIFT + ) + if ( + !this.recursive && (`type` eq IItemRenderer.ItemRenderType.INVENTORY) && isShiftHeld + ) { + if (ItemPlan.hasRecipeInside(item)) return true + } + false + } + + override def shouldUseRenderHelper( + `type`: IItemRenderer.ItemRenderType, + item: ItemStack, + helper: IItemRenderer.ItemRendererHelper + ) = false + + override def renderItem( + `type`: IItemRenderer.ItemRenderType, + item: ItemStack, + data: AnyRef* + ): Unit = { + this.recursive = true + + val is = ItemPlan.loadPlanOutput(item) + val mc = Minecraft.getMinecraft + GL11.glPushAttrib( + GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT + ) + RenderHelper.enableGUIStandardItemLighting() + this.ri.renderItemAndEffectIntoGUI( + mc.fontRenderer, + mc.getTextureManager, + is, + 0, + 0 + ) + RenderHelper.disableStandardItemLighting() + GL11.glPopAttrib() + this.recursive = false + } +} + object ItemPlan { private def assertStackTag(stack: ItemStack) { if (!stack.hasTagCompound)