From 65f0d1e5932e7610a83fa30f174f60e2619bd792 Mon Sep 17 00:00:00 2001 From: XxFran10xX <318299142+XxFran10xX@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:36:53 +0200 Subject: [PATCH] fix: block early finishes and hits before materials Finishing with the branding tool now waits until every material and hit group has at least the amount the project menu lists. Before that it only shows a message and the project is kept. Past that point the exact-match check still decides between the furniture and a failed craft. Hits are refused until every material group has at least its listed amount. Co-Authored-By: Claude Opus 5.5 (1M context) --- README.md | 2 +- .../woodworking/station/StationFeedback.java | 2 ++ .../woodworking/station/StationManager.java | 17 +++++++++- .../woodworking/station/WoodStation.java | 31 +++++++++++++++++-- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 88b3e28..9c55965 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Woodworking turns furniture production into a practical workshop activity. Playe ## From materials to furniture -Each workbench holds a project while its materials and required actions are completed. The bench accepts any woodworking material and any tool action, so players have to know the design. Finishing produces the furniture only when the materials, their amounts and the tool actions all match the recipe exactly. Any other finish ruins the project and the deposited materials are lost. Players can inspect progress with the branding tool or deliberately cancel a project, with a full refund, when changing plans. +Each workbench holds a project while its materials and required actions are completed. The bench accepts any woodworking material and any tool action, so players have to know the design. Tool work starts once every material group has at least the amount the project lists, and finishing waits until every hit group has too. From there, finishing produces the furniture only when the materials, their amounts and the tool actions all match the recipe exactly. Any other finish ruins the project and the deposited materials are lost. Players can inspect progress with the branding tool or deliberately cancel a project, with a full refund, when changing plans. ## Documentation diff --git a/src/main/java/net/tfminecraft/woodworking/station/StationFeedback.java b/src/main/java/net/tfminecraft/woodworking/station/StationFeedback.java index b1e570a..0a8ca4e 100644 --- a/src/main/java/net/tfminecraft/woodworking/station/StationFeedback.java +++ b/src/main/java/net/tfminecraft/woodworking/station/StationFeedback.java @@ -4,6 +4,8 @@ public enum StationFeedback { SUCCESS, WRONG_TYPE, + LACKING_ITEMS, + LACKING_HITS, RECIPE_MISMATCH, NO_PROJECT } diff --git a/src/main/java/net/tfminecraft/woodworking/station/StationManager.java b/src/main/java/net/tfminecraft/woodworking/station/StationManager.java index 1f1a2e3..b0a544c 100644 --- a/src/main/java/net/tfminecraft/woodworking/station/StationManager.java +++ b/src/main/java/net/tfminecraft/woodworking/station/StationManager.java @@ -325,7 +325,18 @@ private void handleLeftClick(PlayerInteractEvent e) { p.getWorld().playSound(station.getLoc(), Sound.ITEM_SHIELD_BREAK, 0.4f, 1f); return; } - if (station.canFinish() != StationFeedback.SUCCESS) { + StationFeedback finish = station.canFinish(); + if (finish == StationFeedback.LACKING_ITEMS) { + p.sendMessage("§cYou have to add all the items before finishing"); + p.playSound(p.getLocation(), Sound.ENTITY_VILLAGER_NO, 1f, 1f); + return; + } + if (finish == StationFeedback.LACKING_HITS) { + p.sendMessage("§cYou need to complete all the hits before finishing"); + p.playSound(p.getLocation(), Sound.ENTITY_VILLAGER_NO, 1f, 1f); + return; + } + if (finish != StationFeedback.SUCCESS) { failCraft(p, station); return; } @@ -350,6 +361,10 @@ private void handleLeftClick(PlayerInteractEvent e) { playWorkFx(station.getLoc(), Material.OAK_PLANKS); p.getWorld().playSound(station.getLoc(), Sound.BLOCK_ANVIL_USE, 0.4f, 1f); break; + case LACKING_ITEMS: + p.sendMessage("§cYou have to add all the items before working"); + p.playSound(p.getLocation(), Sound.ENTITY_VILLAGER_NO, 1f, 1f); + break; case WRONG_TYPE: p.sendMessage("§cThis item cannot be used for woodworking hits"); p.playSound(p.getLocation(), Sound.ENTITY_VILLAGER_NO, 1f, 1f); diff --git a/src/main/java/net/tfminecraft/woodworking/station/WoodStation.java b/src/main/java/net/tfminecraft/woodworking/station/WoodStation.java index 08f72ac..133e9e8 100644 --- a/src/main/java/net/tfminecraft/woodworking/station/WoodStation.java +++ b/src/main/java/net/tfminecraft/woodworking/station/WoodStation.java @@ -164,9 +164,13 @@ public StationFeedback addMaterial(WoodMaterial material, ItemStack stack) { return StationFeedback.SUCCESS; } - /** Accepts any hit, in any order and amount, like {@link #addMaterial(WoodMaterial, ItemStack)}. */ + /** + * Accepts any hit, in any order and amount, once every material bucket has at least the + * amount the project menu lists. + */ public StationFeedback hit(CraftingHit hit) { if (project == null) return StationFeedback.NO_PROJECT; + if (!materialsAdded()) return StationFeedback.LACKING_ITEMS; if (hit == null || hit.getType() == null) return StationFeedback.WRONG_TYPE; hits.computeIfAbsent(hit, k -> new IntCounter()).increaseCurrent(1); @@ -174,6 +178,24 @@ public StationFeedback hit(CraftingHit hit) { return StationFeedback.SUCCESS; } + /** True when every material bucket holds at least its needed amount. Extra input still counts. */ + public boolean materialsAdded() { + return reachedNeeded(types); + } + + /** True when every hit bucket holds at least its needed amount. Extra hits still count. */ + public boolean hitsDone() { + return reachedNeeded(hitTypes); + } + + private boolean reachedNeeded(Map buckets) { + if (project == null) return false; + for (IntCounter c : buckets.values()) { + if (c.getCurrent() < c.getNeeded()) return false; + } + return true; + } + /** True when every required hit count matches and there are no extra leftover hits. */ public boolean checkExactHits() { if (project == null) return false; @@ -199,9 +221,14 @@ public boolean checkExactRecipe() { return true; } - /** SUCCESS only when the deposited materials and the hits both match the project exactly. */ + /** + * LACKING_* while a bucket is short of the listed amount, so finishing early changes nothing. + * Past that, SUCCESS only when the materials and the hits both match the project exactly. + */ public StationFeedback canFinish() { if (project == null) return StationFeedback.NO_PROJECT; + if (!materialsAdded()) return StationFeedback.LACKING_ITEMS; + if (!hitsDone()) return StationFeedback.LACKING_HITS; if (!checkExactRecipe() || !checkExactHits()) return StationFeedback.RECIPE_MISMATCH; return StationFeedback.SUCCESS; }