Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. Finishing checks the recipe and tool work before producing the furniture item. Players can inspect progress with the branding tool or deliberately cancel a project 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. 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
/** Result of a station action. Callers own player-facing messages. */
public enum StationFeedback {
SUCCESS,
CAPACITY,
WRONG_TYPE,
NONE,
LACKING_ITEMS,
LACKING_HITS,
RECIPE_MISMATCH,
NO_PROJECT
}
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,6 @@ private void handleRightClick(PlayerInteractEvent e) {
playWorkFx(existing.getLoc(), Material.OAK_LOG);
p.getWorld().playSound(existing.getLoc(), Sound.ITEM_AXE_WAX_OFF, 0.7f, 2f);
break;
case CAPACITY:
p.sendMessage("搂cYou already have the needed amount of this type");
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 0.5f);
break;
case WRONG_TYPE:
p.sendMessage("搂cThis item type is not needed for the project");
p.playSound(p.getLocation(), Sound.ENTITY_VILLAGER_NO, 1f, 1f);
Expand Down Expand Up @@ -329,20 +325,8 @@ private void handleLeftClick(PlayerInteractEvent e) {
p.getWorld().playSound(station.getLoc(), Sound.ITEM_SHIELD_BREAK, 0.4f, 1f);
return;
}
StationFeedback finish = station.canFinish();
if (finish == StationFeedback.LACKING_ITEMS) {
p.sendMessage("搂cYou have to add all the items before working");
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.RECIPE_MISMATCH) {
p.sendMessage("搂cThe materials do not match the recipe");
p.playSound(p.getLocation(), Sound.ENTITY_VILLAGER_NO, 1f, 1f);
if (station.canFinish() != StationFeedback.SUCCESS) {
failCraft(p, station);
return;
}
completeCraft(p, station);
Expand All @@ -366,22 +350,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);
break;
case NONE:
p.sendMessage("搂cThis tool is not needed for this project");
p.playSound(p.getLocation(), Sound.ENTITY_VILLAGER_NO, 1f, 1f);
break;
case CAPACITY:
p.sendMessage("搂cYou dont need more hits with this tool");
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 0.5f);
break;
default:
break;
}
Expand Down Expand Up @@ -427,6 +399,21 @@ private void completeCraft(Player p, WoodStation station) {
remove(station.getLoc());
}

/** A wrong recipe or hit mix destroys the work. Deposited materials are not refunded. */
// Keep the existing legacy text representation, formatting, and exact-string comparisons.
@SuppressWarnings("deprecation")
private void failCraft(Player p, WoodStation station) {
String name = station.getProject().getName();
station.cancel();
remove(station.getLoc());
p.sendTitle("搂cThe craft failed", "搂7" + name + " 搂7was ruined and the materials were lost", 5, 40, 10);
Location loc = station.getLoc().clone().add(0.5, 1, 0.5);
if (loc.getWorld() != null) {
loc.getWorld().playSound(loc, Sound.ENTITY_ITEM_BREAK, 1f, 0.8f);
loc.getWorld().spawnParticle(Particle.SMOKE, loc, 20, 0.2, 0.2, 0.2, 0.02);
}
}

private boolean isBranding(ItemStack item) {
return TLibs.getItemAPI().getChecker().checkItemWithPath(item, Cache.brandingTool);
}
Expand Down
54 changes: 12 additions & 42 deletions src/main/java/net/tfminecraft/woodworking/station/WoodStation.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ public void applySavedProgress(Map<String, Integer> materials, Map<String, Integ
if (material == null || e.getValue() == null) continue;
int amount = Math.max(0, e.getValue());
depositedByMaterial.put(material, amount);
IntCounter bucket = types.get(material.getType());
if (bucket != null) bucket.increaseCurrent(amount);
types.computeIfAbsent(material.getType(), k -> new IntCounter()).increaseCurrent(amount);
}
}
if (hitCounts != null) {
Expand All @@ -139,25 +138,23 @@ public void applySavedProgress(Map<String, Integer> materials, Map<String, Integ
for (Map.Entry<CraftingHit, IntCounter> e : hits.entrySet()) {
HitType type = e.getKey().getType();
if (type == null) continue;
IntCounter bucket = hitTypes.get(type);
if (bucket != null) bucket.increaseCurrent(e.getValue().getCurrent());
hitTypes.computeIfAbsent(type, k -> new IntCounter()).increaseCurrent(e.getValue().getCurrent());
}
}
if (savedDeposited != null) {
deposited.addAll(savedDeposited);
}
}

/**
* Accepts any woodworking material, even one the recipe does not use or past the needed
* amount. Only {@link #canFinish()} decides whether the result is correct.
*/
public StationFeedback addMaterial(WoodMaterial material, ItemStack stack) {
if (project == null) return StationFeedback.NO_PROJECT;
if (material == null) return StationFeedback.WRONG_TYPE;

String type = material.getType();
IntCounter bucket = types.get(type);
if (bucket == null) return StationFeedback.WRONG_TYPE;
if (bucket.isEqual()) return StationFeedback.CAPACITY;

bucket.increaseCurrent(1);
types.computeIfAbsent(material.getType(), k -> new IntCounter()).increaseCurrent(1);
depositedByMaterial.merge(material, 1, Integer::sum);
if (stack != null) {
ItemStack copy = stack.clone();
Expand All @@ -167,42 +164,16 @@ public StationFeedback addMaterial(WoodMaterial material, ItemStack stack) {
return StationFeedback.SUCCESS;
}

/** Accepts any hit, in any order and amount, like {@link #addMaterial(WoodMaterial, ItemStack)}. */
public StationFeedback hit(CraftingHit hit) {
if (project == null) return StationFeedback.NO_PROJECT;
if (!checkItems()) return StationFeedback.LACKING_ITEMS;
if (hit == null || hit.getType() == null) return StationFeedback.WRONG_TYPE;
if (!hitTypes.containsKey(hit.getType())) return StationFeedback.NONE;
if (hitTypes.get(hit.getType()).isEqual()) return StationFeedback.CAPACITY;

if (hits.containsKey(hit)) {
hits.get(hit).increaseCurrent(1);
} else {
IntCounter counter = new IntCounter();
counter.setCurrent(1);
hits.put(hit, counter);
}
hitTypes.get(hit.getType()).increaseCurrent(1);
hits.computeIfAbsent(hit, k -> new IntCounter()).increaseCurrent(1);
hitTypes.computeIfAbsent(hit.getType(), k -> new IntCounter()).increaseCurrent(1);
return StationFeedback.SUCCESS;
}

/** True when every material-type bucket is exactly filled. */
public boolean checkItems() {
if (project == null) return false;
for (IntCounter c : types.values()) {
if (!c.isEqual()) return false;
}
return true;
}

/** True when every hit-type bucket is exactly filled. */
public boolean checkHits() {
if (project == null) return false;
for (IntCounter c : hitTypes.values()) {
if (!c.isEqual()) 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;
Expand All @@ -228,11 +199,10 @@ public boolean checkExactRecipe() {
return true;
}

/** SUCCESS only when the deposited materials and the hits both match the project exactly. */
public StationFeedback canFinish() {
if (project == null) return StationFeedback.NO_PROJECT;
if (!checkItems()) return StationFeedback.LACKING_ITEMS;
if (!checkExactHits()) return StationFeedback.LACKING_HITS;
if (!checkExactRecipe()) return StationFeedback.RECIPE_MISMATCH;
if (!checkExactRecipe() || !checkExactHits()) return StationFeedback.RECIPE_MISMATCH;
return StationFeedback.SUCCESS;
}

Expand Down