66package mrtjp .projectred .expansion
77
88import java .util .{List => JList }
9-
109import codechicken .lib .data .MCDataInput
1110import codechicken .lib .gui .GuiDraw
1211import codechicken .lib .render .uv .{MultiIconTransformation , UVTransformation }
@@ -24,7 +23,7 @@ import net.minecraft.client.renderer.texture.IIconRegister
2423import net .minecraft .client .resources .I18n
2524import net .minecraft .entity .player .EntityPlayer
2625import net .minecraft .inventory .{ICrafting , ISidedInventory , InventoryCrafting }
27- import net .minecraft .item .ItemStack
26+ import net .minecraft .item .{ Item , ItemStack }
2827import net .minecraft .item .crafting .{CraftingManager , IRecipe }
2928import net .minecraft .nbt .NBTTagCompound
3029import net .minecraft .util .IIcon
@@ -51,6 +50,11 @@ class TileAutoCrafter
5150 private var cycleTimer1 = getUnpoweredCycleTimer
5251 private var cycleTimer2 = getPoweredCycleTimer
5352
53+ private var recipeEquality : ItemEquality = _
54+ private val recipeCache = new java.util.HashMap [String , IRecipe ]()
55+ private lazy val allRecipes =
56+ CraftingManager .getInstance().getRecipeList.asInstanceOf [JList [IRecipe ]]
57+
5458 override def save (tag : NBTTagCompound ) {
5559 super .save(tag)
5660 saveInv(tag)
@@ -132,22 +136,38 @@ class TileAutoCrafter
132136 currentRecipe = null
133137 currentInputs.clear()
134138 currentOutput = null
139+ recipeEquality = null
135140
136141 val plan = getStackInSlot(planSlot)
137- if (plan != null && ItemPlan .hasRecipeInside(plan)) {
138- val inputs = ItemPlan .loadPlanInputs(plan)
139- for (i <- 0 until 9 ) invCrafting.setInventorySlotContents(i, inputs(i))
140- val recipes =
141- CraftingManager .getInstance().getRecipeList.asInstanceOf [JList [IRecipe ]]
142- currentRecipe = recipes.find(_.matches(invCrafting, world)).orNull
143- if (currentRecipe != null ) {
144- inputs
145- .map { ItemKey .getOrNull }
146- .filter(_ != null )
147- .foreach(currentInputs.add(_, 1 ))
148- currentOutput =
149- ItemKeyStack .getOrNull(currentRecipe.getCraftingResult(invCrafting))
150- }
142+ if (plan == null || ! ItemPlan .hasRecipeInside(plan)) return
143+
144+ val inputs = ItemPlan .loadPlanInputs(plan)
145+ for (i <- 0 until 9 ) invCrafting.setInventorySlotContents(i, inputs(i))
146+
147+ val key = planKey(inputs)
148+ currentRecipe = recipeCache.get(key)
149+
150+ if (currentRecipe == null ) {
151+ currentRecipe = allRecipes.find(_.matches(invCrafting, world)).orNull
152+ if (currentRecipe != null )
153+ recipeCache.put(key, currentRecipe)
154+ }
155+
156+ if (currentRecipe != null ) {
157+ inputs
158+ .map(ItemKey .getOrNull)
159+ .filter(_ != null )
160+ .foreach(currentInputs.add(_, 1 ))
161+
162+ currentOutput =
163+ ItemKeyStack .getOrNull(currentRecipe.getCraftingResult(invCrafting))
164+
165+ recipeEquality = new ItemEquality
166+ recipeEquality.matchNBT = true
167+ recipeEquality.matchMeta =
168+ ! currentOutput.key.makeStack(0 ).isItemStackDamageable
169+ recipeEquality.matchOre = currentRecipe.isInstanceOf [ShapedOreRecipe ] ||
170+ currentRecipe.isInstanceOf [ShapelessOreRecipe ]
151171 }
152172 }
153173
@@ -156,17 +176,34 @@ class TileAutoCrafter
156176 recipeNeedsRefresh = true
157177 }
158178
179+ private def buildStorageMap (): Map [ItemKey , Int ] = {
180+ val map = scala.collection.mutable.Map .empty[ItemKey , Int ]
181+ for (i <- 9 until 27 ) {
182+ val s = getStackInSlot(i)
183+ if (s != null ) {
184+ val k = ItemKey .get(s)
185+ map(k) = map.getOrElse(k, 0 ) + s.stackSize
186+ }
187+ }
188+ map.toMap
189+ }
190+
159191 def tryCraft (): Boolean = {
160- if (currentRecipe != null && checkSpaceForOutput)
161- if (
162- currentInputs.result.forall(p => containsEnoughResource(p._1, p._2))
163- ) {
164- for ((item, amount) <- currentInputs.result)
165- eatResource(item, amount)
166- produceOutput()
167- return true
192+ if (currentRecipe == null || ! checkSpaceForOutput)
193+ return false
194+
195+ val storage = buildStorageMap()
196+ if (
197+ ! currentInputs.result.forall { case (k, amt) =>
198+ storage.getOrElse(k, 0 ) >= amt
168199 }
169- false
200+ ) return false
201+
202+ for ((item, amount) <- currentInputs.result)
203+ eatResource(item, amount)
204+
205+ produceOutput()
206+ true
170207 }
171208
172209 def containsEnoughResource (item : ItemKey , amount : Int ): Boolean = {
@@ -200,16 +237,10 @@ class TileAutoCrafter
200237 }
201238
202239 def eatResource (item : ItemKey , amount : Int ) {
203- val eq = new ItemEquality
204- eq.matchMeta = ! item.makeStack(0 ).isItemStackDamageable
205- eq.matchNBT = true
206- eq.matchOre = currentRecipe.isInstanceOf [ShapedOreRecipe ] || currentRecipe
207- .isInstanceOf [ShapelessOreRecipe ]
208-
209240 var left = amount
210- for (i <- 9 until 27 ) {
241+ for (i <- 9 until 27 if left > 0 ) {
211242 val s = getStackInSlot(i)
212- if (s != null && eq .matches(item, ItemKey .get(s))) {
243+ if (s != null && recipeEquality .matches(item, ItemKey .get(s))) {
213244 if (s.getItem.hasContainerItem(s)) {
214245 val cStack = s.getItem.getContainerItem(s)
215246 setInventorySlotContents(i, cStack)
@@ -221,8 +252,6 @@ class TileAutoCrafter
221252 if (s.stackSize <= 0 ) setInventorySlotContents(i, null )
222253 else markDirty()
223254 }
224-
225- if (left <= 0 ) return
226255 }
227256 }
228257 }
@@ -238,6 +267,15 @@ class TileAutoCrafter
238267
239268 override def createContainer (player : EntityPlayer ) =
240269 new ContainerAutoCrafter (player, this )
270+
271+ def planKey (inputs : Array [ItemStack ]): String =
272+ inputs
273+ .map {
274+ case null => " null"
275+ case s => Item .getIdFromItem(s.getItem) + " :" + s.getItemDamage
276+ }
277+ .mkString(" |" )
278+
241279}
242280
243281class ContainerAutoCrafter (player : EntityPlayer , tile : TileAutoCrafter )
0 commit comments