9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-30 04:19:30 +00:00

Enhance update suppression (#701)

* feat: enhance update suppression

* fix: fix nest exception, better print

* fix: bot update suppression catch

* chore: format

* feat: better performance

* fix: fix build err

* refactor

* fix: throw IAE when call not from net.minecraft

* format: use jbr annotation

* fix: fix comment pos

* chore: format

* fix: fix comment

* feat: add stacktrace to event
This commit is contained in:
MC_XiaoHei
2025-08-18 19:31:26 +08:00
committed by GitHub
parent 4b21a9687f
commit 0f40159c34
22 changed files with 328 additions and 133 deletions

View File

@@ -6,11 +6,13 @@ import net.minecraft.server.level.ServerPlayer;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesLogger;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.event.bot.BotActionExecuteEvent;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import org.leavesmc.leaves.util.UpdateSuppressionException;
import java.util.List;
import java.util.UUID;
@@ -86,7 +88,17 @@ public abstract class ServerBotAction<E extends ServerBotAction<E>> {
return;
}
if (this.doTick(bot)) {
boolean result = false;
try {
result = this.doTick(bot);
} catch (UpdateSuppressionException e) {
e.providePlayer(bot);
e.consume();
} catch (Exception e) {
LeavesLogger.LOGGER.severe("An error occurred while executing bot " + bot.displayName + ", action " + this.name, e);
}
if (result) {
if (this.numberRemaining > 0) {
this.numberRemaining--;
}

View File

@@ -1,32 +1,125 @@
package org.leavesmc.leaves.util;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.LeavesLogger;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.event.player.UpdateSuppressionEvent;
import java.util.ArrayList;
import java.util.List;
public class UpdateSuppressionException extends RuntimeException {
private @Nullable BlockPos pos;
private @Nullable Level level;
private @Nullable Block source;
private @Nullable ServerPlayer player;
private final @NotNull Throwable throwable;
private final BlockPos pos;
private final Block source;
public UpdateSuppressionException(BlockPos pos, Block source) {
super("Update suppression");
public UpdateSuppressionException(
@Nullable BlockPos pos,
@Nullable Level level,
@Nullable Block source,
@Nullable ServerPlayer player,
@NotNull Throwable throwable
) {
super("Update Suppression");
this.pos = pos;
this.level = level;
this.source = source;
this.player = player;
this.throwable = throwable;
}
public BlockPos getPos() {
return pos;
public void providePlayer(@NotNull ServerPlayer player) {
if (this.level == null) {
this.level = player.level();
}
this.player = player;
}
public Block getSource() {
return source;
}
public String getMessage() {
if (pos != null) {
return "An update suppression processed, form [%s] to [x:%d,y:%d,z:%d]".formatted(source.getName(), pos.getX(), pos.getY(), pos.getZ());
} else {
return "An update suppression processed, form [%s]".formatted(source.getName());
public void provideLevel(@NotNull Level level) {
if (this.level != null) {
this.level = level;
}
}
public void provideBlock(@NotNull Level level, @NotNull BlockPos pos, @NotNull Block source) {
provideLevel(level);
provideBlock(pos, source);
}
public void provideBlock(@NotNull BlockPos pos, @NotNull Block source) {
if (this.pos != null) {
this.pos = pos;
}
if (this.source != null) {
this.source = source;
}
}
public void consume() {
submitEvent();
LeavesLogger.LOGGER.info(getMessage());
}
private void submitEvent() {
Location location = null;
if (pos != null && level != null) {
location = new Location(level.getWorld(), pos.getX(), pos.getY(), pos.getZ());
}
Material material = null;
if (source != null) {
material = source.defaultBlockState().getBukkitMaterial();
}
Player bukkitPlayer = null;
if (player != null) {
bukkitPlayer = player.getBukkitEntity();
}
new UpdateSuppressionEvent(bukkitPlayer, location, material, throwable).callEvent();
}
@Override
public String getMessage() {
List<String> messages = new ArrayList<>();
messages.add("An %s update suppression was triggered".formatted(getTypeName()));
if (source != null) {
messages.add("from %s".formatted(source.defaultBlockState().getBukkitMaterial().name()));
}
if (pos != null) {
messages.add("at [x:%d,y:%d,z:%d]".formatted(pos.getX(), pos.getY(), pos.getZ()));
}
if (level != null) {
messages.add("in %s".formatted(level.dimension().location()));
}
if (player != null) {
if (player instanceof ServerBot) {
messages.add("by %s[bot]".formatted(player.displayName));
} else {
messages.add("by %s".formatted(player.displayName));
}
}
return String.join(" ", messages);
}
@Contract(pure = true)
private @NotNull String getTypeName() {
Class<? extends Throwable> type = throwable.getClass();
if (type == ClassCastException.class) {
return "CCE";
} else if (type == StackOverflowError.class) {
return "SOE";
} else if (type == IllegalArgumentException.class) {
return "IAE";
}
return type.getSimpleName();
}
}