Skip to content

Commit 63bdda3

Browse files
author
MagicTeaMC
committed
fix #85
1 parent 0b7e305 commit 63bdda3

2 files changed

Lines changed: 66 additions & 6 deletions

File tree

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,8 @@ private void executeTreeChop(
360360
hooks.lands,
361361
hooks.residence,
362362
hooks.griefPrevention,
363-
hooks.worldGuard);
363+
hooks.worldGuard,
364+
actuallyRemovedLogs);
364365
}
365366
}
366367

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

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package org.milkteamc.autotreechop.utils;
22

33
import com.cryptomorin.xseries.XMaterial;
4+
import java.util.Set;
45
import org.bukkit.Bukkit;
56
import org.bukkit.Location;
67
import org.bukkit.Material;
8+
import org.bukkit.World;
79
import org.bukkit.block.Block;
810
import org.bukkit.block.BlockFace;
911
import org.bukkit.entity.Player;
@@ -33,7 +35,8 @@ public static void scheduleReplant(
3335
LandsHook landsHook,
3436
ResidenceHook residenceHook,
3537
GriefPreventionHook griefPreventionHook,
36-
WorldGuardHook worldGuardHook) {
38+
WorldGuardHook worldGuardHook,
39+
Set<Location> choppedLogs) {
3740

3841
if (!config.isAutoReplantEnabled()) {
3942
return;
@@ -45,7 +48,7 @@ public static void scheduleReplant(
4548
}
4649

4750
Location originalLocation = brokenLogBlock.getLocation().clone();
48-
boolean needs2x2 = requires2x2Formation(originalLogType);
51+
boolean needs2x2 = isLikely2x2Tree(originalLogType, originalLocation, choppedLogs);
4952

5053
Runnable replantTask = () -> {
5154
if (needs2x2) {
@@ -110,11 +113,67 @@ public static void scheduleReplant(
110113
}
111114

112115
/**
113-
* Returns true for tree types that require a 2x2 sapling formation to grow.
116+
* Determines whether the chopped tree should be replanted as a 2x2 sapling
117+
* formation.
118+
*
119+
* <p>Dark Oak and Pale Oak are always 2x2. Spruce and Jungle are 2x2 only when
120+
* the base of the chopped tree contained four logs arranged in a 2x2 square —
121+
* detected by scanning the chopped-log set for a matching pattern at the Y
122+
* level of the lowest broken log. All other tree types are always single.
114123
*/
115-
private static boolean requires2x2Formation(Material logType) {
124+
private static boolean isLikely2x2Tree(Material logType, Location lowestLogLocation, Set<Location> choppedLogs) {
125+
116126
XMaterial xMat = XMaterial.matchXMaterial(logType);
117-
return xMat == XMaterial.DARK_OAK_LOG || xMat == XMaterial.PALE_OAK_LOG;
127+
128+
// Dark Oak and Pale Oak are always planted as 2x2
129+
if (xMat == XMaterial.DARK_OAK_LOG || xMat == XMaterial.PALE_OAK_LOG) {
130+
return true;
131+
}
132+
133+
// Only Spruce and Jungle can be big (2x2) trees — everything else is always single
134+
if (xMat != XMaterial.SPRUCE_LOG && xMat != XMaterial.JUNGLE_LOG) {
135+
return false;
136+
}
137+
138+
// Detect 2x2 by checking whether four logs of this type form a square at
139+
// the base Y level among the actually-chopped blocks.
140+
int baseY = lowestLogLocation.getBlockY();
141+
int baseX = lowestLogLocation.getBlockX();
142+
int baseZ = lowestLogLocation.getBlockZ();
143+
World world = lowestLogLocation.getWorld();
144+
145+
// Try all four possible 2x2 anchors that include the base-log position as a corner
146+
int[][] candidateAnchors = {{0, 0}, {-1, 0}, {0, -1}, {-1, -1}};
147+
for (int[] ao : candidateAnchors) {
148+
int ax = baseX + ao[0];
149+
int az = baseZ + ao[1];
150+
boolean all4Present = true;
151+
for (int[] offset : FORMATION_2X2) {
152+
if (!containsBlockLocation(choppedLogs, world, ax + offset[0], baseY, az + offset[1])) {
153+
all4Present = false;
154+
break;
155+
}
156+
}
157+
if (all4Present) {
158+
return true;
159+
}
160+
}
161+
162+
return false;
163+
}
164+
165+
/**
166+
* Returns {@code true} if {@code locations} contains a block-coordinate match
167+
* for the given world and integer coordinates. Uses integer comparison to avoid
168+
* floating-point or yaw/pitch equality issues.
169+
*/
170+
private static boolean containsBlockLocation(Set<Location> locations, World world, int x, int y, int z) {
171+
for (Location loc : locations) {
172+
if (loc.getWorld() == world && loc.getBlockX() == x && loc.getBlockY() == y && loc.getBlockZ() == z) {
173+
return true;
174+
}
175+
}
176+
return false;
118177
}
119178

120179
/**

0 commit comments

Comments
 (0)