11package com .tcm .MineTale .block .workbenches .screen ;
22
3+ import java .util .HashMap ;
34import java .util .List ;
5+ import java .util .Map ;
6+ import java .util .Optional ;
47
58import com .tcm .MineTale .MineTale ;
69import com .tcm .MineTale .block .workbenches .menu .WorkbenchWorkbenchMenu ;
10+ import com .tcm .MineTale .mixin .client .ClientRecipeBookAccessor ;
711import com .tcm .MineTale .mixin .client .RecipeBookComponentAccessor ;
812import com .tcm .MineTale .network .CraftRequestPayload ;
913import com .tcm .MineTale .recipe .MineTaleRecipeBookComponent ;
1216import com .tcm .MineTale .registry .ModRecipes ;
1317
1418import net .fabricmc .fabric .api .client .networking .v1 .ClientPlayNetworking ;
19+ import net .minecraft .client .ClientRecipeBook ;
1520import net .minecraft .client .gui .GuiGraphics ;
1621import net .minecraft .client .gui .components .Button ;
1722import net .minecraft .client .gui .navigation .ScreenPosition ;
2126import net .minecraft .client .renderer .RenderPipelines ;
2227import net .minecraft .resources .Identifier ;
2328import net .minecraft .world .entity .player .Inventory ;
29+ import net .minecraft .world .entity .player .Player ;
2430import net .minecraft .world .item .ItemStack ;
31+ import net .minecraft .world .item .crafting .Ingredient ;
2532import net .minecraft .world .item .crafting .display .RecipeDisplayEntry ;
2633import net .minecraft .world .item .crafting .display .RecipeDisplayId ;
2734import net .minecraft .world .item .crafting .display .SlotDisplayContext ;
@@ -34,7 +41,7 @@ public class WorkbenchWorkbenchScreen extends AbstractRecipeBookScreen<Workbench
3441 private final MineTaleRecipeBookComponent mineTaleRecipeBook ;
3542
3643 private Button craftOneBtn ;
37- private Button craftThirtyBtn ;
44+ private Button craftTenBtn ;
3845 private Button craftAllBtn ;
3946
4047 /**
@@ -92,17 +99,20 @@ protected void init() {
9299
93100 super .init ();
94101
95- this .craftOneBtn = addRenderableWidget (Button .builder (Component .literal ("1" ), (button ) -> {
102+ int defaultLeft = this .leftPos + 90 ;
103+ int defaultTop = this .topPos + 25 ;
104+
105+ this .craftOneBtn = addRenderableWidget (Button .builder (Component .literal ("Craft" ), (button ) -> {
96106 handleCraftRequest (1 );
97- }).bounds (this . leftPos + 80 , this . topPos + 20 , 30 , 20 ).build ());
107+ }).bounds (defaultLeft , defaultTop , 75 , 20 ).build ());
98108
99- this .craftThirtyBtn = addRenderableWidget (Button .builder (Component .literal ("30 " ), (button ) -> {
109+ this .craftTenBtn = addRenderableWidget (Button .builder (Component .literal ("x10 " ), (button ) -> {
100110 handleCraftRequest (30 );
101- }).bounds (this . leftPos + 112 , this . topPos + 20 , 30 , 20 ).build ());
111+ }).bounds (defaultLeft , defaultTop + 22 , 35 , 20 ).build ());
102112
103113 this .craftAllBtn = addRenderableWidget (Button .builder (Component .literal ("All" ), (button ) -> {
104114 handleCraftRequest (-1 ); // -1 represents "All" logic
105- }).bounds (this . leftPos + 144 , this . topPos + 20 , 30 , 20 ).build ());
115+ }).bounds (defaultLeft + 40 , defaultTop + 22 , 35 , 20 ).build ());
106116 }
107117
108118 /**
@@ -159,30 +169,88 @@ protected void renderBg(GuiGraphics guiGraphics, float f, int i, int j) {
159169 guiGraphics .blit (RenderPipelines .GUI_TEXTURED , TEXTURE , k , l , 0.0F , 0.0F , this .imageWidth , this .imageHeight , 256 , 256 );
160170 }
161171
162- /**
163- * Renders the workbench screen including the background tint, GUI elements, and tooltips.
164- *
165- * @param graphics the graphics context
166- * @param mouseX the current mouse x-coordinate
167- * @param mouseY the current mouse y-coordinate
168- * @param delta the partial tick delta for frame interpolation
169- */
170172 @ Override
171173 public void render (GuiGraphics graphics , int mouseX , int mouseY , float delta ) {
172- // 1. Always render the dark background tint first
173174 renderBackground (graphics , mouseX , mouseY , delta );
174-
175- // 3. Call super (this draws your slots and items)
176175 super .render (graphics , mouseX , mouseY , delta );
177176
178- boolean hasSelection = this .mineTaleRecipeBook .getSelectedRecipeId () != null ;
179- this .craftOneBtn .active = hasSelection ;
180- this .craftThirtyBtn .active = hasSelection ;
181- this .craftAllBtn .active = hasSelection ;
177+ // Get the ID of the recipe clicked in the ghost-book
178+ RecipeDisplayId displayId = this .mineTaleRecipeBook .getSelectedRecipeId ();
179+ RecipeDisplayEntry selectedEntry = null ;
180+
181+ if (displayId != null && this .minecraft .level != null ) {
182+ ClientRecipeBook book = this .minecraft .player .getRecipeBook ();
183+ // Accessing the known recipes via your Accessor
184+ Map <RecipeDisplayId , RecipeDisplayEntry > knownRecipes = ((ClientRecipeBookAccessor ) book ).getKnown ();
185+ selectedEntry = knownRecipes .get (displayId );
186+ }
187+
188+ // 2. Button Activation Logic
189+ if (selectedEntry != null ) {
190+ // We use the entry directly. It contains the 15 ingredients needed!
191+ boolean canCraftOne = canCraft (this .minecraft .player , selectedEntry , 1 );
192+ boolean canCraftTen = canCraft (this .minecraft .player , selectedEntry , 10 );
193+
194+ this .craftOneBtn .active = canCraftOne ;
195+ this .craftTenBtn .active = canCraftTen ;
196+ this .craftAllBtn .active = canCraftOne ;
197+ } else {
198+ this .craftOneBtn .active = false ;
199+ this .craftTenBtn .active = false ;
200+ this .craftAllBtn .active = false ;
201+ }
182202
183203 renderTooltip (graphics , mouseX , mouseY );
184204 }
185205
206+ private boolean canCraft (Player player , RecipeDisplayEntry entry , int craftCount ) {
207+ if (player == null || entry == null ) return false ;
208+
209+ // craftingRequirements() provides the list of all items (the 15 items for your chest)
210+ Optional <List <Ingredient >> reqs = entry .craftingRequirements ();
211+ if (reqs .isEmpty ()) return false ;
212+
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 <>();
215+ for (Ingredient ing : reqs .get ()) {
216+ aggregatedRequirements .put (ing , aggregatedRequirements .getOrDefault (ing , 0 ) + 1 );
217+ }
218+
219+ // 2. Check the player's inventory against the totals
220+ 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)
223+ int totalNeeded = entryReq .getValue () * craftCount ;
224+
225+ if (!hasIngredientAmount (inv , entryReq .getKey (), totalNeeded )) {
226+ return false ; // Player doesn't have enough of this specific ingredient
227+ }
228+ }
229+
230+ return true ;
231+ }
232+
233+ private boolean hasIngredientAmount (Inventory inventory , Ingredient ingredient , int totalRequired ) {
234+ System .out .println ("DEBUG: Searching inventory for " + totalRequired + " of an ingredient..." );
235+ if (totalRequired <= 0 ) return true ;
236+
237+ int found = 0 ;
238+ for (int i = 0 ; i < inventory .getContainerSize (); i ++) {
239+ ItemStack stack = inventory .getItem (i );
240+ if (!stack .isEmpty () && ingredient .test (stack )) {
241+ found += stack .getCount ();
242+ System .out .println ("DEBUG: Found " + stack .getCount () + " in slot " + i + ". Total found: " + found );
243+ }
244+ if (found >= totalRequired ) {
245+ System .out .println ("DEBUG: Ingredient requirement MET" );
246+ return true ;
247+ }
248+ }
249+
250+ System .out .println ("DEBUG: Ingredient requirement FAILED. Only found: " + found + "/" + totalRequired );
251+ return false ;
252+ }
253+
186254 /**
187255 * Computes the on-screen position for the recipe book toggle button for this GUI.
188256 *
0 commit comments