44import java .util .List ;
55import java .util .Map ;
66import java .util .Optional ;
7+ import java .util .stream .Collectors ;
78
89import com .tcm .MineTale .MineTale ;
10+ import com .tcm .MineTale .block .workbenches .entity .AbstractWorkbenchEntity ;
11+ import com .tcm .MineTale .block .workbenches .menu .AbstractWorkbenchContainerMenu ;
912import com .tcm .MineTale .block .workbenches .menu .WorkbenchWorkbenchMenu ;
1013import com .tcm .MineTale .mixin .client .ClientRecipeBookAccessor ;
1114import com .tcm .MineTale .mixin .client .RecipeBookComponentAccessor ;
1215import com .tcm .MineTale .network .CraftRequestPayload ;
1316import com .tcm .MineTale .recipe .MineTaleRecipeBookComponent ;
17+ import com .tcm .MineTale .recipe .WorkbenchRecipe ;
1418import com .tcm .MineTale .registry .ModBlocks ;
1519import com .tcm .MineTale .registry .ModRecipeDisplay ;
1620import com .tcm .MineTale .registry .ModRecipes ;
2428import net .minecraft .client .gui .screens .recipebook .RecipeBookComponent ;
2529import net .minecraft .client .gui .screens .recipebook .RecipeCollection ;
2630import net .minecraft .client .renderer .RenderPipelines ;
31+ import net .minecraft .core .HolderSet ;
2732import net .minecraft .resources .Identifier ;
33+ import net .minecraft .server .level .ServerPlayer ;
2834import net .minecraft .world .entity .player .Inventory ;
2935import net .minecraft .world .entity .player .Player ;
36+ import net .minecraft .world .item .Item ;
3037import net .minecraft .world .item .ItemStack ;
3138import net .minecraft .world .item .crafting .Ingredient ;
3239import net .minecraft .world .item .crafting .display .RecipeDisplayEntry ;
@@ -89,7 +96,7 @@ private static MineTaleRecipeBookComponent createRecipeBookComponent(WorkbenchWo
8996 *
9097 * Sets the layout size (imageWidth = 176, imageHeight = 166), delegates remaining
9198 * layout initialization to the superclass, and creates the three craft buttons
92- * ("1", "30 ", "All") wired to their respective handlers.
99+ * ("1", "10 ", "All") wired to their respective handlers.
93100 */
94101 @ Override
95102 protected void init () {
@@ -107,7 +114,7 @@ protected void init() {
107114 }).bounds (defaultLeft , defaultTop , 75 , 20 ).build ());
108115
109116 this .craftTenBtn = addRenderableWidget (Button .builder (Component .literal ("x10" ), (button ) -> {
110- handleCraftRequest (30 );
117+ handleCraftRequest (10 );
111118 }).bounds (defaultLeft , defaultTop + 22 , 35 , 20 ).build ());
112119
113120 this .craftAllBtn = addRenderableWidget (Button .builder (Component .literal ("All" ), (button ) -> {
@@ -189,11 +196,12 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
189196 if (selectedEntry != null ) {
190197 // We use the entry directly. It contains the 15 ingredients needed!
191198 boolean canCraftOne = canCraft (this .minecraft .player , selectedEntry , 1 );
199+ boolean canCraftMoreThanOne = canCraft (this .minecraft .player , selectedEntry , 2 );
192200 boolean canCraftTen = canCraft (this .minecraft .player , selectedEntry , 10 );
193201
194202 this .craftOneBtn .active = canCraftOne ;
195203 this .craftTenBtn .active = canCraftTen ;
196- this .craftAllBtn .active = canCraftOne ;
204+ this .craftAllBtn .active = canCraftMoreThanOne ;
197205 } else {
198206 this .craftOneBtn .active = false ;
199207 this .craftTenBtn .active = false ;
@@ -206,48 +214,74 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
206214 private boolean canCraft (Player player , RecipeDisplayEntry entry , int craftCount ) {
207215 if (player == null || entry == null ) return false ;
208216
209- // craftingRequirements() provides the list of all items (the 15 items for your chest)
210217 Optional <List <Ingredient >> reqs = entry .craftingRequirements ();
211218 if (reqs .isEmpty ()) return false ;
212219
213- // 1. Group duplicate ingredients (e.g., 5 Log entries become 1 Log entry with a value of 5)
214- Map <Ingredient , Integer > aggregatedRequirements = new HashMap <>();
220+ // 1. Group ingredients by their underlying Item HolderSet.
221+ // Since Ingredient doesn't override hashCode, we use the values field directly
222+ // or use a List of Holders as the key for stable hashing.
223+ Map <HolderSet <Item >, Integer > aggregatedRequirements = new HashMap <>();
224+
225+ // Helper map to get back to an Ingredient object for the final check
226+ Map <HolderSet <Item >, Ingredient > holderToIngredient = new HashMap <>();
227+
215228 for (Ingredient ing : reqs .get ()) {
216- aggregatedRequirements .put (ing , aggregatedRequirements .getOrDefault (ing , 0 ) + 1 );
229+ // Accessing the 'values' via a custom accessor or reflection if private,
230+ // but based on your source, we can use the Ingredient object itself
231+ // IF we use a helper that handles the hashing correctly.
232+
233+ // Strategy: Use the stream of holders as a List key (Lists have stable hashcodes)
234+ HolderSet <Item > key = ing .items ().collect (Collectors .collectingAndThen (Collectors .toList (), HolderSet ::direct ));
235+
236+ aggregatedRequirements .put (key , aggregatedRequirements .getOrDefault (key , 0 ) + 1 );
237+ holderToIngredient .putIfAbsent (key , ing );
217238 }
218239
219- // 2. Check the player's inventory against the totals
240+ // 2. Check the player's inventory
220241 Inventory inv = player .getInventory ();
221- for (Map .Entry <Ingredient , Integer > entryReq : aggregatedRequirements .entrySet ()) {
222- // totalNeeded = (Amount in 1 recipe) * (Number of crafts, e.g. 1 or 30)
242+ for (Map .Entry <HolderSet <Item >, Integer > entryReq : aggregatedRequirements .entrySet ()) {
223243 int totalNeeded = entryReq .getValue () * craftCount ;
244+ Ingredient originalIng = holderToIngredient .get (entryReq .getKey ());
224245
225- if (!hasIngredientAmount (inv , entryReq . getKey () , totalNeeded )) {
226- return false ; // Player doesn't have enough of this specific ingredient
246+ if (!hasIngredientAmount (inv , originalIng , totalNeeded )) {
247+ return false ;
227248 }
228249 }
229250
230251 return true ;
231252 }
232253
233254 private boolean hasIngredientAmount (Inventory inventory , Ingredient ingredient , int totalRequired ) {
234- System .out .println ("DEBUG: Searching inventory for " + totalRequired + " of an ingredient ..." );
255+ System .out .println ("DEBUG: Searching inventory + nearby for " + totalRequired + "..." );
235256 if (totalRequired <= 0 ) return true ;
236257
237258 int found = 0 ;
259+
260+ // 1. Check Player Inventory
238261 for (int i = 0 ; i < inventory .getContainerSize (); i ++) {
239262 ItemStack stack = inventory .getItem (i );
240263 if (!stack .isEmpty () && ingredient .test (stack )) {
241264 found += stack .getCount ();
242- System .out .println ("DEBUG: Found " + stack .getCount () + " in slot " + i + ". Total found: " + found );
243265 }
244- if (found >= totalRequired ) {
245- System .out .println ("DEBUG: Ingredient requirement MET" );
246- return true ;
266+ }
267+
268+ // 2. CHECK THE NETWORKED ITEMS FROM CHESTS
269+ // This is the list we sent via the packet!
270+ if (this .menu instanceof AbstractWorkbenchContainerMenu workbenchMenu ) {
271+ for (ItemStack stack : workbenchMenu .getNetworkedNearbyItems ()) {
272+ if (!stack .isEmpty () && ingredient .test (stack )) {
273+ found += stack .getCount ();
274+ System .out .println ("DEBUG: Found " + stack .getCount () + " in nearby networked list. Total: " + found );
275+ }
247276 }
248277 }
249278
250- System .out .println ("DEBUG: Ingredient requirement FAILED. Only found: " + found + "/" + totalRequired );
279+ if (found >= totalRequired ) {
280+ System .out .println ("DEBUG: Requirement MET with " + found + "/" + totalRequired );
281+ return true ;
282+ }
283+
284+ System .out .println ("DEBUG: FAILED. Only found: " + found + "/" + totalRequired );
251285 return false ;
252286 }
253287
0 commit comments