Skip to content

Commit 5105790

Browse files
fix: pull from chests works for workbench workbench entity
1 parent d47ff42 commit 5105790

9 files changed

Lines changed: 758 additions & 175 deletions

File tree

src/client/java/com/tcm/MineTale/MineTaleClient.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@
22

33
import com.tcm.MineTale.block.workbenches.screen.FurnaceWorkbenchScreen;
44
import com.tcm.MineTale.block.workbenches.screen.WorkbenchWorkbenchScreen;
5+
import com.tcm.MineTale.network.ClientboundNearbyInventorySyncPacket;
6+
7+
import java.util.List;
8+
9+
import com.tcm.MineTale.block.workbenches.menu.AbstractWorkbenchContainerMenu;
510
import com.tcm.MineTale.block.workbenches.screen.CampfireWorkbenchScreen;
611
import com.tcm.MineTale.registry.ModMenuTypes;
712

813
import net.fabricmc.api.ClientModInitializer;
14+
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
915
import net.minecraft.client.gui.screens.MenuScreens;
16+
import net.minecraft.client.gui.screens.Screen;
17+
import net.minecraft.client.gui.screens.recipebook.RecipeUpdateListener;
18+
import net.minecraft.world.item.ItemStack;
1019

1120
public class MineTaleClient implements ClientModInitializer {
1221
/**
@@ -22,5 +31,36 @@ public void onInitializeClient() {
2231
MenuScreens.register(ModMenuTypes.FURNACE_WORKBENCH_MENU, FurnaceWorkbenchScreen::new);
2332
MenuScreens.register(ModMenuTypes.CAMPFIRE_WORKBENCH_MENU, CampfireWorkbenchScreen::new);
2433
MenuScreens.register(ModMenuTypes.WORKBENCH_WORKBENCH_MENU, WorkbenchWorkbenchScreen::new);
34+
35+
ClientPlayNetworking.registerGlobalReceiver(ClientboundNearbyInventorySyncPacket.TYPE, (payload, context) -> {
36+
List<ItemStack> items = payload.items();
37+
38+
// We create a task that can re-run itself if the menu isn't ready yet
39+
context.client().execute(new Runnable() {
40+
int retries = 0;
41+
42+
@Override
43+
public void run() {
44+
if (context.client().player.containerMenu instanceof AbstractWorkbenchContainerMenu menu) {
45+
applyItemsToMenu(menu, items, context.client().screen);
46+
} else if (retries < 10) { // Try for up to 10 frames (~0.5 seconds)
47+
retries++;
48+
// Re-submit to the next tick
49+
context.client().execute(this);
50+
} else {
51+
System.out.println("CLIENT: Failed to sync nearby items after 10 retries.");
52+
}
53+
}
54+
});
55+
});
56+
}
57+
58+
// Helper method to keep things clean
59+
private static void applyItemsToMenu(AbstractWorkbenchContainerMenu menu, List<ItemStack> items, Screen screen) {
60+
System.out.println("CLIENT: Successfully applied " + items.size() + " stacks to the Workbench Menu.");
61+
menu.setNetworkedNearbyItems(items);
62+
if (screen instanceof RecipeUpdateListener listener) {
63+
listener.recipesUpdated();
64+
}
2565
}
2666
}

src/client/java/com/tcm/MineTale/block/workbenches/screen/WorkbenchWorkbenchScreen.java

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
import java.util.List;
55
import java.util.Map;
66
import java.util.Optional;
7+
import java.util.stream.Collectors;
78

89
import com.tcm.MineTale.MineTale;
10+
import com.tcm.MineTale.block.workbenches.entity.AbstractWorkbenchEntity;
11+
import com.tcm.MineTale.block.workbenches.menu.AbstractWorkbenchContainerMenu;
912
import com.tcm.MineTale.block.workbenches.menu.WorkbenchWorkbenchMenu;
1013
import com.tcm.MineTale.mixin.client.ClientRecipeBookAccessor;
1114
import com.tcm.MineTale.mixin.client.RecipeBookComponentAccessor;
1215
import com.tcm.MineTale.network.CraftRequestPayload;
1316
import com.tcm.MineTale.recipe.MineTaleRecipeBookComponent;
17+
import com.tcm.MineTale.recipe.WorkbenchRecipe;
1418
import com.tcm.MineTale.registry.ModBlocks;
1519
import com.tcm.MineTale.registry.ModRecipeDisplay;
1620
import com.tcm.MineTale.registry.ModRecipes;
@@ -24,9 +28,12 @@
2428
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
2529
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
2630
import net.minecraft.client.renderer.RenderPipelines;
31+
import net.minecraft.core.HolderSet;
2732
import net.minecraft.resources.Identifier;
33+
import net.minecraft.server.level.ServerPlayer;
2834
import net.minecraft.world.entity.player.Inventory;
2935
import net.minecraft.world.entity.player.Player;
36+
import net.minecraft.world.item.Item;
3037
import net.minecraft.world.item.ItemStack;
3138
import net.minecraft.world.item.crafting.Ingredient;
3239
import 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

Comments
 (0)