prevent simulateBlockBreak from calling itself fixes #5188

This commit is contained in:
nossr50
2025-07-04 12:13:37 -07:00
parent 87277a0d6f
commit e6199c0a7a

View File

@@ -64,6 +64,13 @@ import org.jetbrains.annotations.NotNull;
*/
public final class EventUtils {
/**
* True when the current thread is already executing simulateBlockBreak().
* Thread-local so parallel Folia regions / async tasks are isolated.
*/
private static final ThreadLocal<Boolean> IN_FAKE_BREAK =
ThreadLocal.withInitial(() -> false);
/**
* This is a static utility class, therefore we don't want any instances of this class. Making
* the constructor private prevents accidents like that.
@@ -366,22 +373,31 @@ public final class EventUtils {
* @param eventType The type of event to signal to other plugins
* @return true if the event wasn't cancelled, false otherwise
*/
public static boolean simulateBlockBreak(Block block, Player player,
private static boolean simulateBlockBreak(Block block, Player player,
FakeBlockBreakEventType eventType) {
PluginManager pluginManager = mcMMO.p.getServer().getPluginManager();
FakeBlockDamageEvent damageEvent = new FakeBlockDamageEvent(player, block,
player.getInventory().getItemInMainHand(), true);
pluginManager.callEvent(damageEvent);
BlockBreakEvent fakeBlockBreakEvent = null;
switch (eventType) {
case FAKE -> fakeBlockBreakEvent = new FakeBlockBreakEvent(block, player);
case TREE_FELLER -> fakeBlockBreakEvent = new TreeFellerBlockBreakEvent(block, player);
if (IN_FAKE_BREAK.get()) {
return true;
}
IN_FAKE_BREAK.set(true);
try {
final PluginManager pluginManager = mcMMO.p.getServer().getPluginManager();
final FakeBlockDamageEvent damageEvent = new FakeBlockDamageEvent(player, block,
player.getInventory().getItemInMainHand(), true);
pluginManager.callEvent(damageEvent);
final BlockBreakEvent fakeBlockBreakEvent = switch (eventType) {
case FAKE -> new FakeBlockBreakEvent(block, player);
case TREE_FELLER -> new TreeFellerBlockBreakEvent(block, player);
};
pluginManager.callEvent(fakeBlockBreakEvent);
return !damageEvent.isCancelled() && !fakeBlockBreakEvent.isCancelled();
} finally {
// always clear the flag
IN_FAKE_BREAK.set(false);
}
pluginManager.callEvent(fakeBlockBreakEvent);
return !damageEvent.isCancelled() && !fakeBlockBreakEvent.isCancelled();
}
public static void handlePartyTeleportEvent(Player teleportingPlayer, Player targetPlayer) {