Skip to content

Commit d00d79a

Browse files
author
MagicTeaMC
committed
some more small fixes
1 parent 74d1a2c commit d00d79a

2 files changed

Lines changed: 56 additions & 102 deletions

File tree

src/main/java/org/milkteamc/autotreechop/events/BlockBreakListener.java

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public void onBlockBreak(BlockBreakEvent event) {
121121
return;
122122
}
123123

124-
// Limits cleared — now check for a pending confirmation.
124+
// Limits cleared — check for a pending confirmation first.
125125
ConfirmationManager confirmationManager = plugin.getConfirmationManager();
126126
ChopData pending = confirmationManager.consumePendingConfirmation(playerUUID);
127127

@@ -145,8 +145,8 @@ public void onBlockBreak(BlockBreakEvent event) {
145145
// here), then read them on an async thread (snapshots are immutable — thread-safe).
146146
Map<Long, ChunkSnapshot> snapshots = captureLeafCheckSnapshots(block, config);
147147

148-
// Clone location and tool now so we have stable values if the async path
149-
// later needs them (block reference is live world state — not safe async).
148+
// Clone location and tool now so we have stable values for the async path.
149+
// The block reference itself is a live world object — not safe to read off-thread.
150150
Location frozenLocation = location.clone();
151151
ItemStack frozenTool = tool.clone();
152152

@@ -193,15 +193,7 @@ void dispatchChop(
193193
EffectUtils.showChopEffect(player, block);
194194
}
195195

196-
ProtectionHooks hooks = new ProtectionHooks(
197-
plugin.isWorldGuardEnabled(),
198-
plugin.getWorldGuardHook(),
199-
plugin.isResidenceEnabled(),
200-
plugin.getResidenceHook(),
201-
plugin.isGriefPreventionEnabled(),
202-
plugin.getGriefPreventionHook(),
203-
plugin.isLandsEnabled(),
204-
plugin.getLandsHook());
196+
ProtectionHooks hooks = buildProtectionHooks();
205197

206198
plugin.getTreeChopUtils()
207199
.chopTree(
@@ -215,6 +207,24 @@ void dispatchChop(
215207
hooks);
216208
}
217209

210+
/**
211+
* Builds a {@link ProtectionHooks} snapshot from the plugin's current hook state.
212+
*
213+
* <p>Extracted from {@link #dispatchChop} so that the hook wiring lives in one
214+
* place and future hook additions only need to be made here.
215+
*/
216+
private ProtectionHooks buildProtectionHooks() {
217+
return new ProtectionHooks(
218+
plugin.isWorldGuardEnabled(),
219+
plugin.getWorldGuardHook(),
220+
plugin.isResidenceEnabled(),
221+
plugin.getResidenceHook(),
222+
plugin.isGriefPreventionEnabled(),
223+
plugin.getGriefPreventionHook(),
224+
plugin.isLandsEnabled(),
225+
plugin.getLandsHook());
226+
}
227+
218228
/**
219229
* Captures {@link ChunkSnapshot}s for all chunks within the leaf-detection radius.
220230
*
@@ -233,7 +243,7 @@ private Map<Long, ChunkSnapshot> captureLeafCheckSnapshots(Block log, Config con
233243
int chunkX = (cx + dx) >> 4;
234244
int chunkZ = (cz + dz) >> 4;
235245
if (!world.isChunkLoaded(chunkX, chunkZ)) continue;
236-
long key = ((long) chunkX << 32) | (chunkZ & 0xFFFFFFFFL);
246+
long key = chunkKey(chunkX, chunkZ);
237247
snapshots.computeIfAbsent(
238248
key, k -> world.getChunkAt(chunkX, chunkZ).getChunkSnapshot(false, false, false));
239249
}
@@ -266,7 +276,7 @@ private static boolean hasNearbyLeaves(Block log, Config config, Map<Long, Chunk
266276
int z = cz + dz;
267277
if (y < minY || y >= maxY) continue;
268278

269-
long key = ((long) (x >> 4) << 32) | ((z >> 4) & 0xFFFFFFFFL);
279+
long key = chunkKey(x >> 4, z >> 4);
270280
ChunkSnapshot snapshot = snapshots.get(key);
271281
if (snapshot == null) continue;
272282

@@ -278,4 +288,8 @@ private static boolean hasNearbyLeaves(Block log, Config config, Map<Long, Chunk
278288
}
279289
return false;
280290
}
291+
292+
private static long chunkKey(int chunkX, int chunkZ) {
293+
return ((long) chunkX << 32) | (chunkZ & 0xFFFFFFFFL);
294+
}
281295
}

src/main/java/org/milkteamc/autotreechop/utils/TreeChopUtils.java

Lines changed: 28 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,12 @@ private static boolean hasEnoughDurability(ItemStack tool, int blockCount, Confi
6666

6767
int unbreakingLevel = getUnbreakingLevel(tool);
6868

69+
int damagePerHit = config.isToolDamage() ? config.getToolDamageDecrease() : 1;
6970
int estimatedDamage;
7071
if (config.getRespectUnbreaking() && unbreakingLevel > 0) {
71-
estimatedDamage = blockCount / (unbreakingLevel + 1);
72+
estimatedDamage = (blockCount * damagePerHit) / (unbreakingLevel + 1);
7273
} else {
73-
estimatedDamage = blockCount * config.getToolDamageDecrease();
74+
estimatedDamage = blockCount * damagePerHit;
7475
}
7576

7677
return remainingDurability > estimatedDamage;
@@ -98,7 +99,7 @@ private static void applyToolDamage(ItemStack tool, Player player, int blocksBro
9899
int newDamage = currentDamage + damageToApply;
99100

100101
if (newDamage >= tool.getType().getMaxDurability()) {
101-
player.getInventory().removeItem(tool);
102+
player.getInventory().setItemInMainHand(null);
102103
} else {
103104
damageableMeta.setDamage(newDamage);
104105
tool.setItemMeta(damageableMeta);
@@ -116,7 +117,7 @@ private static boolean shouldApplyDurabilityLoss(int unbreakingLevel, Config con
116117
if (unbreakingLevel <= 0 || !config.getRespectUnbreaking()) {
117118
return true;
118119
}
119-
return random.nextInt(100) < (100.0 / (unbreakingLevel + 1));
120+
return random.nextInt(unbreakingLevel + 1) == 0;
120121
}
121122

122123
public static boolean isTool(Player player) {
@@ -140,10 +141,6 @@ public static boolean isTool(Player player) {
140141
return xMat == XMaterial.SHEARS || xMat == XMaterial.FISHING_ROD || xMat == XMaterial.FLINT_AND_STEEL;
141142
}
142143

143-
/**
144-
* Main entry point for tree chopping
145-
* PHASE 1: Synchronous snapshot creation
146-
*/
147144
public void chopTree(
148145
Block block,
149146
Player player,
@@ -180,14 +177,12 @@ public void chopTree(
180177
// Mark location as processing
181178
sessionManager.addTreeChopLocations(playerUUID, Collections.singleton(block.getLocation()));
182179

183-
// PHASE 1: Synchronous - Capture block snapshot
184180
try {
185181
BlockSnapshot treeSnapshot = BlockSnapshotCreator.captureTreeRegion(
186182
block, config, connectedBlocks, config.getMaxDiscoveryBlocks());
187183

188184
Location startLocation = block.getLocation().clone();
189185

190-
// PHASE 2: Asynchronous - Calculate tree structure
191186
Runnable asyncDiscovery = () -> {
192187
try {
193188
Set<Location> treeBlocks = BlockDiscoveryUtils.discoverTreeBFS(
@@ -215,10 +210,6 @@ public void chopTree(
215210
}
216211
}
217212

218-
/**
219-
* Validate tree and execute chopping
220-
* This runs synchronously on the region thread
221-
*/
222213
private void validateAndExecuteChop(
223214
Set<Location> treeBlocks,
224215
Block originalBlock,
@@ -235,7 +226,6 @@ private void validateAndExecuteChop(
235226
return;
236227
}
237228

238-
// Validation checks
239229
if (treeBlocks.isEmpty()) {
240230
sessionManager.clearTreeChopSession(playerUUID);
241231
return;
@@ -267,10 +257,6 @@ private void validateAndExecuteChop(
267257
executeTreeChop(treeBlocks, player, tool, config, playerConfig, hooks, originalBlock);
268258
}
269259

270-
/**
271-
* Execute tree chopping in batches
272-
* This runs synchronously with batch processing
273-
*/
274260
private void executeTreeChop(
275261
Set<Location> treeBlocks,
276262
Player player,
@@ -285,13 +271,10 @@ private void executeTreeChop(
285271
int totalBlocks = blockList.size();
286272
UUID playerUUID = player.getUniqueId();
287273

288-
// Track the LOWEST log of each type for replanting (Y coordinate)
274+
Location centerLocation = originalBlock.getLocation().clone();
289275
Map<Material, Location> logTypesForReplant = new HashMap<>();
290-
// Use thread-safe set for actuallyRemovedLogs since it's accessed across batches
291276
Set<Location> actuallyRemovedLogs = ConcurrentHashMap.newKeySet();
292277

293-
// CRITICAL: Capture leaf snapshot BEFORE removing logs
294-
// This ensures we can see which logs exist for proper leaf orphan detection
295278
BlockSnapshot leafSnapshot = null;
296279
if (config.isLeafRemovalEnabled()) {
297280
try {
@@ -311,7 +294,7 @@ private void executeTreeChop(
311294
(location, index) -> {
312295
Block block = location.getBlock();
313296

314-
// Re-check block type (may have changed)
297+
// Re-check block type (may have changed between phases)
315298
if (!BlockDiscoveryUtils.isLog(block.getType(), config)) {
316299
return;
317300
}
@@ -323,7 +306,7 @@ private void executeTreeChop(
323306

324307
Material originalLogType = block.getType();
325308

326-
// Track the lowest Y coordinate log for each type (for proper replanting)
309+
// Track the lowest-Y log of each type for replanting
327310
Location existingLoc = logTypesForReplant.get(originalLogType);
328311
if (existingLoc == null || location.getBlockY() < existingLoc.getBlockY()) {
329312
logTypesForReplant.put(originalLogType, location.clone());
@@ -355,20 +338,17 @@ private void executeTreeChop(
355338
// Handle leaf removal
356339
if (config.isLeafRemovalEnabled() && finalLeafSnapshot != null) {
357340
long delay = config.getLeafRemovalDelayTicks();
358-
Location leafProcessLocation = originalBlock.getLocation();
359341

360-
Runnable leafTask = () -> {
361-
processLeafRemovalWithPreCapturedSnapshot(
362-
finalLeafSnapshot,
363-
originalBlock.getLocation(),
364-
player,
365-
config,
366-
playerConfig,
367-
hooks,
368-
actuallyRemovedLogs);
369-
};
342+
Runnable leafTask = () -> processLeafRemovalWithPreCapturedSnapshot(
343+
finalLeafSnapshot,
344+
centerLocation,
345+
player,
346+
config,
347+
playerConfig,
348+
hooks,
349+
actuallyRemovedLogs);
370350

371-
scheduler.scheduleDelayed(leafProcessLocation, leafTask, delay);
351+
scheduler.scheduleDelayed(centerLocation, leafTask, delay);
372352
}
373353

374354
// Handle replanting
@@ -399,13 +379,6 @@ private void executeTreeChop(
399379
});
400380
}
401381

402-
/**
403-
* Process leaf removal with PRE-CAPTURED snapshot
404-
* The snapshot was taken BEFORE logs were removed
405-
* PHASE 1: Already done (snapshot captured before log removal)
406-
* PHASE 2: Async - Calculate leaves to remove
407-
* PHASE 3: Sync - Remove leaves in batches
408-
*/
409382
private void processLeafRemovalWithPreCapturedSnapshot(
410383
BlockSnapshot leafSnapshot,
411384
Location centerLocation,
@@ -425,36 +398,28 @@ private void processLeafRemovalWithPreCapturedSnapshot(
425398

426399
String playerKey = player.getUniqueId().toString();
427400

428-
// Check if player already has an active leaf removal session
429401
if (sessionManager.hasActiveLeafRemovalSession(playerKey)) {
430402
return;
431403
}
432404

433-
// Start a new session
434405
String sessionId = sessionManager.startLeafRemovalSession(playerKey);
435406
if (sessionId == null) {
436407
return;
437408
}
438409

439-
// PHASE 2: Asynchronous - Calculate leaves to remove
440410
Runnable asyncLeafCalculation = () -> {
441411
try {
442-
// Use the provided removedLogs directly
443-
// (already contains all actually removed logs from executeTreeChop)
444412
Set<Location> leavesToRemove;
445413
int radius = config.getLeafRemovalRadius();
446414

447-
// Choose discovery method based on radius and mode
448415
if ("smart".equalsIgnoreCase(config.getLeafRemovalMode())) {
449416
leavesToRemove = BlockDiscoveryUtils.discoverLeavesBFS(
450417
leafSnapshot, centerLocation, radius, config, removedLogs);
451418
} else {
452-
// For "aggressive" or "radius" mode, radial is faster
453419
leavesToRemove = BlockDiscoveryUtils.discoverLeavesRadial(
454420
leafSnapshot, centerLocation, radius, config, removedLogs);
455421
}
456422

457-
// PHASE 3: Back to sync for removal
458423
Runnable removalTask = () ->
459424
executeLeafRemoval(leavesToRemove, player, config, playerConfig, hooks, sessionId, playerKey);
460425

@@ -470,15 +435,10 @@ private void processLeafRemovalWithPreCapturedSnapshot(
470435
if (config.isLeafRemovalAsync()) {
471436
scheduler.runTaskAsync(asyncLeafCalculation);
472437
} else {
473-
// Run synchronously if async is disabled
474438
asyncLeafCalculation.run();
475439
}
476440
}
477441

478-
/**
479-
* Execute leaf removal in batches
480-
* This runs synchronously on the region thread
481-
*/
482442
private void executeLeafRemoval(
483443
Set<Location> leavesToRemove,
484444
Player player,
@@ -501,31 +461,20 @@ private void executeLeafRemoval(
501461
0,
502462
batchSize,
503463
(location, index) -> {
504-
// Check daily limit if counting towards limit
505464
if (config.getLeafRemovalCountsTowardsLimit()) {
506465
if (!PermissionUtils.hasVipBlock(player, playerConfig, config)
507466
&& playerConfig.getDailyBlocksBroken() >= config.getMaxBlocksPerDay()) {
508-
return false; // Stop processing - limit reached
467+
return false;
509468
}
510469
}
511470

512471
Block leafBlock = location.getBlock();
513-
514-
// Remove the leaf block with all checks
515472
removeLeafBlock(leafBlock, player, config, playerConfig, hooks);
516-
517-
return true; // Continue processing
473+
return true;
518474
},
519-
() -> {
520-
// Leaf removal complete - end session
521-
sessionManager.endLeafRemovalSession(sessionId, playerKey);
522-
});
475+
() -> sessionManager.endLeafRemovalSession(sessionId, playerKey));
523476
}
524477

525-
/**
526-
* Remove a single leaf block with all necessary checks
527-
* This runs synchronously on the region thread
528-
*/
529478
private boolean removeLeafBlock(
530479
Block leafBlock,
531480
Player player,
@@ -535,26 +484,19 @@ private boolean removeLeafBlock(
535484

536485
Location leafLocation = leafBlock.getLocation();
537486

538-
// Check if already processing this location
539-
if (processingLeafLocations.contains(leafLocation)) {
540-
return false;
541-
}
542-
543-
// Re-check if it's still a leaf
544-
if (!BlockDiscoveryUtils.isLeafBlock(leafBlock.getType(), config)) {
487+
if (!processingLeafLocations.add(leafLocation)) {
545488
return false;
546489
}
547490

548-
// Re-check protection at execution time
549-
if (!ProtectionCheckUtils.canModifyBlock(player, leafLocation, hooks)) {
550-
return false;
551-
}
491+
try {
492+
if (!BlockDiscoveryUtils.isLeafBlock(leafBlock.getType(), config)) {
493+
return false;
494+
}
552495

553-
// Mark as processing
554-
processingLeafLocations.add(leafLocation);
496+
if (!ProtectionCheckUtils.canModifyBlock(player, leafLocation, hooks)) {
497+
return false;
498+
}
555499

556-
try {
557-
// Call BlockBreakEvent if enabled
558500
if (config.isCallBlockBreakEvent()) {
559501
BlockBreakEvent breakEvent = new BlockBreakEvent(leafBlock, player);
560502
plugin.getServer().getPluginManager().callEvent(breakEvent);
@@ -573,15 +515,13 @@ private boolean removeLeafBlock(
573515
leafBlock.setType(XMaterial.AIR.get(), false);
574516
}
575517

576-
// Update daily blocks count if needed
577518
if (config.getLeafRemovalCountsTowardsLimit()) {
578519
playerConfig.incrementDailyBlocksBroken();
579520
}
580521

581522
return true;
582523

583524
} finally {
584-
// Always remove from processing set
585525
processingLeafLocations.remove(leafLocation);
586526
}
587527
}

0 commit comments

Comments
 (0)