mirror of
https://github.com/EngineHub/WorldGuard.git
synced 2024-12-24 18:19:03 +01:00
Add event cancellation debug commands.
This commit is contained in:
parent
18ec3db1bb
commit
ce169461a3
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.commands;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.bukkit.event.debug.*;
|
||||
import com.sk89q.worldguard.util.report.CancelReport;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
import org.bukkit.util.BlockIterator;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class DebuggingCommands {
|
||||
|
||||
private static final Logger log = Logger.getLogger(DebuggingCommands.class.getCanonicalName());
|
||||
private static final int MAX_TRACE_DISTANCE = 20;
|
||||
|
||||
private final WorldGuardPlugin plugin;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param plugin The plugin instance
|
||||
*/
|
||||
public DebuggingCommands(WorldGuardPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Command(aliases = {"testbreak"}, usage = "[player]", desc = "Simulate a block break", min = 1, max = 1, flags = "t")
|
||||
@CommandPermissions("worldguard.debug.event")
|
||||
public void fireBreakEvent(CommandContext args, final CommandSender sender) throws CommandException {
|
||||
Player target = plugin.matchSinglePlayer(sender, args.getString(0));
|
||||
Block block = traceBlock(sender, target, args.hasFlag('t'));
|
||||
sender.sendMessage(ChatColor.AQUA + "Testing BLOCK BREAK at " + ChatColor.DARK_AQUA + block);
|
||||
LoggingBlockBreakEvent event = new LoggingBlockBreakEvent(block, target);
|
||||
testEvent(sender, target, event);
|
||||
}
|
||||
|
||||
|
||||
@Command(aliases = {"testplace"}, usage = "[player]", desc = "Simulate a block place", min = 1, max = 1, flags = "t")
|
||||
@CommandPermissions("worldguard.debug.event")
|
||||
public void firePlaceEvent(CommandContext args, final CommandSender sender) throws CommandException {
|
||||
Player target = plugin.matchSinglePlayer(sender, args.getString(0));
|
||||
Block block = traceBlock(sender, target, args.hasFlag('t'));
|
||||
sender.sendMessage(ChatColor.AQUA + "Testing BLOCK PLACE at " + ChatColor.DARK_AQUA + block);
|
||||
LoggingBlockPlaceEvent event = new LoggingBlockPlaceEvent(block, block.getState(), block.getRelative(BlockFace.DOWN), target.getItemInHand(), target, true);
|
||||
testEvent(sender, target, event);
|
||||
}
|
||||
|
||||
@Command(aliases = {"testinteract"}, usage = "[player]", desc = "Simulate a block interact", min = 1, max = 1, flags = "t")
|
||||
@CommandPermissions("worldguard.debug.event")
|
||||
public void fireInteractEvent(CommandContext args, final CommandSender sender) throws CommandException {
|
||||
Player target = plugin.matchSinglePlayer(sender, args.getString(0));
|
||||
Block block = traceBlock(sender, target, args.hasFlag('t'));
|
||||
sender.sendMessage(ChatColor.AQUA + "Testing BLOCK INTERACT at " + ChatColor.DARK_AQUA + block);
|
||||
LoggingPlayerInteractEvent event = new LoggingPlayerInteractEvent(target, Action.RIGHT_CLICK_BLOCK, target.getItemInHand(), block, BlockFace.SOUTH);
|
||||
testEvent(sender, target, event);
|
||||
}
|
||||
|
||||
@Command(aliases = {"testdamage"}, usage = "[player]", desc = "Simulate an entity damage", min = 1, max = 1, flags = "t")
|
||||
@CommandPermissions("worldguard.debug.event")
|
||||
public void fireDamageEvent(CommandContext args, final CommandSender sender) throws CommandException {
|
||||
Player target = plugin.matchSinglePlayer(sender, args.getString(0));
|
||||
Entity entity = traceEntity(sender, target, args.hasFlag('t'));
|
||||
sender.sendMessage(ChatColor.AQUA + "Testing ENTITY DAMAGE on " + ChatColor.DARK_AQUA + entity);
|
||||
LoggingEntityDamageByEntityEvent event = new LoggingEntityDamageByEntityEvent(target, entity, DamageCause.ENTITY_ATTACK, 1);
|
||||
testEvent(sender, target, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate an event and print its report.
|
||||
*
|
||||
* @param receiver The receiver of the messages
|
||||
* @param target The target
|
||||
* @param event THe event
|
||||
* @param <T> The type of event
|
||||
*/
|
||||
private <T extends Event & CancelLogging> void testEvent(CommandSender receiver, Player target, T event) {
|
||||
boolean isConsole = receiver instanceof ConsoleCommandSender;
|
||||
|
||||
if (!receiver.equals(target)) {
|
||||
if (!isConsole) {
|
||||
log.info(receiver.getName() + " is simulating an event on " + target.getName());
|
||||
}
|
||||
|
||||
target.sendMessage(
|
||||
ChatColor.RED + "(Please ignore any messages that may immediately follow.)");
|
||||
}
|
||||
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
int start = new Exception().getStackTrace().length;
|
||||
CancelReport report = new CancelReport(event, event.getCancels(), start);
|
||||
String result = report.toString();
|
||||
receiver.sendMessage(result.replaceAll("(?m)^", ChatColor.AQUA.toString()));
|
||||
|
||||
if (result.length() >= 500 && !isConsole) {
|
||||
receiver.sendMessage(ChatColor.GRAY + "The report was also printed to console.");
|
||||
log.info("Event report for " + receiver.getName() + ":\n\n" + result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source of the test.
|
||||
*
|
||||
* @param sender The message sender
|
||||
* @param target The provided target
|
||||
* @param fromTarget Whether the source should be the target
|
||||
* @return The source
|
||||
* @throws CommandException Thrown if a condition is not met
|
||||
*/
|
||||
private Player getSource(CommandSender sender, Player target, boolean fromTarget) throws CommandException {
|
||||
if (fromTarget) {
|
||||
return target;
|
||||
} else {
|
||||
if (sender instanceof Player) {
|
||||
return (Player) sender;
|
||||
} else {
|
||||
throw new CommandException(
|
||||
"If this command is not to be used in-game, use -t to run the test from the viewpoint of the given player rather than yourself.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first non-air block in a ray trace.
|
||||
*
|
||||
* @param sender The sender
|
||||
* @param target The target
|
||||
* @param fromTarget Whether the trace should originate from the target
|
||||
* @return The block found
|
||||
* @throws CommandException Throw on an incorrect parameter
|
||||
*/
|
||||
private Block traceBlock(CommandSender sender, Player target, boolean fromTarget) throws CommandException {
|
||||
Player source = getSource(sender, target, fromTarget);
|
||||
|
||||
BlockIterator it = new BlockIterator(source);
|
||||
int i = 0;
|
||||
while (it.hasNext() && i < MAX_TRACE_DISTANCE) {
|
||||
Block block = it.next();
|
||||
if (block.getType() != Material.AIR) {
|
||||
return block;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
throw new CommandException("Not currently looking at a block that is close enough.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first nearby entity in a ray trace.
|
||||
*
|
||||
* @param sender The sender
|
||||
* @param target The target
|
||||
* @param fromTarget Whether the trace should originate from the target
|
||||
* @return The entity found
|
||||
* @throws CommandException Throw on an incorrect parameter
|
||||
*/
|
||||
private Entity traceEntity(CommandSender sender, Player target, boolean fromTarget) throws CommandException {
|
||||
Player source = getSource(sender, target, fromTarget);
|
||||
|
||||
BlockIterator it = new BlockIterator(source);
|
||||
int i = 0;
|
||||
while (it.hasNext() && i < MAX_TRACE_DISTANCE) {
|
||||
Block block = it.next();
|
||||
|
||||
// A very in-accurate and slow search
|
||||
Entity[] entities = block.getChunk().getEntities();
|
||||
for (Entity entity : entities) {
|
||||
if (!entity.equals(target) && entity.getLocation().distanceSquared(block.getLocation()) < 10) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
throw new CommandException("Not currently looking at an entity that is close enough.");
|
||||
}
|
||||
|
||||
}
|
@ -180,4 +180,8 @@ public void listRunningTasks(CommandContext args, CommandSender sender) throws C
|
||||
}
|
||||
}
|
||||
|
||||
@Command(aliases = {"debug"}, desc = "Debugging commands")
|
||||
@NestedCommand({DebuggingCommands.class})
|
||||
public void debug(CommandContext args, CommandSender sender) {}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.event.debug;
|
||||
|
||||
import org.bukkit.event.Cancellable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Represents call to {@link Cancellable#setCancelled(boolean)}.
|
||||
*/
|
||||
public class CancelAttempt {
|
||||
|
||||
private final boolean before;
|
||||
private final boolean after;
|
||||
private final StackTraceElement[] stackTrace;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param before The cancellation flag before the call
|
||||
* @param after The cancellation flag after the call
|
||||
* @param stackTrace The stack trace
|
||||
*/
|
||||
public CancelAttempt(boolean before, boolean after, StackTraceElement[] stackTrace) {
|
||||
checkNotNull(stackTrace, "stackTrace");
|
||||
this.before = before;
|
||||
this.after = after;
|
||||
this.stackTrace = stackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cancellation state before the call.
|
||||
*
|
||||
* @return Whether the event was cancelled before
|
||||
*/
|
||||
public boolean getBefore() {
|
||||
return before;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cancellation state after the call.
|
||||
*
|
||||
* @return The new cancellation state
|
||||
*/
|
||||
public boolean getAfter() {
|
||||
return after;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stack trace.
|
||||
*
|
||||
* @return The stack trace
|
||||
*/
|
||||
public StackTraceElement[] getStackTrace() {
|
||||
return stackTrace;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.event.debug;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Logs attempts at cancellation.
|
||||
*/
|
||||
public class CancelLogger {
|
||||
|
||||
private List<CancelAttempt> entries = new ArrayList<CancelAttempt>();
|
||||
|
||||
/**
|
||||
* Log a call.
|
||||
*
|
||||
* @param before The cancellation flag before the call
|
||||
* @param after The cancellation flag after the call
|
||||
* @param stackTrace The stack trace
|
||||
*/
|
||||
public void log(boolean before, boolean after, StackTraceElement[] stackTrace) {
|
||||
entries.add(new CancelAttempt(before, after, stackTrace));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an immutable list of cancels.
|
||||
*
|
||||
* @return An immutable list
|
||||
*/
|
||||
public List<CancelAttempt> getCancels() {
|
||||
return ImmutableList.copyOf(entries);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.event.debug;
|
||||
|
||||
import org.bukkit.event.Cancellable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CancelLogging extends Cancellable {
|
||||
|
||||
/**
|
||||
* Get an immutable list of cancels.
|
||||
*
|
||||
* @return An immutable list
|
||||
*/
|
||||
List<CancelAttempt> getCancels();
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.event.debug;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LoggingBlockBreakEvent extends BlockBreakEvent implements CancelLogging {
|
||||
|
||||
private final CancelLogger logger = new CancelLogger();
|
||||
|
||||
public LoggingBlockBreakEvent(Block block, Player player) {
|
||||
super(block, player);
|
||||
}
|
||||
|
||||
public List<CancelAttempt> getCancels() {
|
||||
return logger.getCancels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.logger.log(isCancelled(), cancel, new Exception().getStackTrace());
|
||||
super.setCancelled(cancel);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.event.debug;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LoggingBlockPlaceEvent extends BlockPlaceEvent implements CancelLogging {
|
||||
|
||||
private final CancelLogger logger = new CancelLogger();
|
||||
|
||||
public LoggingBlockPlaceEvent(Block placedBlock, BlockState replacedBlockState, Block placedAgainst, ItemStack itemInHand, Player thePlayer, boolean canBuild) {
|
||||
super(placedBlock, replacedBlockState, placedAgainst, itemInHand, thePlayer, canBuild);
|
||||
}
|
||||
|
||||
public List<CancelAttempt> getCancels() {
|
||||
return logger.getCancels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.logger.log(isCancelled(), cancel, new Exception().getStackTrace());
|
||||
super.setCancelled(cancel);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.event.debug;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LoggingEntityDamageByEntityEvent extends EntityDamageByEntityEvent implements CancelLogging {
|
||||
|
||||
private final CancelLogger logger = new CancelLogger();
|
||||
|
||||
public LoggingEntityDamageByEntityEvent(Entity damager, Entity damagee, DamageCause cause, double damage) {
|
||||
super(damager, damagee, cause, damage);
|
||||
}
|
||||
|
||||
public List<CancelAttempt> getCancels() {
|
||||
return logger.getCancels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.logger.log(isCancelled(), cancel, new Exception().getStackTrace());
|
||||
super.setCancelled(cancel);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.event.debug;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LoggingPlayerInteractEvent extends PlayerInteractEvent implements CancelLogging {
|
||||
|
||||
private final CancelLogger logger = new CancelLogger();
|
||||
|
||||
public LoggingPlayerInteractEvent(Player who, Action action, ItemStack item, Block clickedBlock, BlockFace clickedFace) {
|
||||
super(who, action, item, clickedBlock, clickedFace);
|
||||
}
|
||||
|
||||
public List<CancelAttempt> getCancels() {
|
||||
return logger.getCancels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.logger.log(isCancelled(), cancel, new Exception().getStackTrace());
|
||||
super.setCancelled(cancel);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.util;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Traces the owner of a handler.
|
||||
*/
|
||||
public class HandlerTracer {
|
||||
|
||||
private final List<Handler> handlers;
|
||||
|
||||
public HandlerTracer(Event event) {
|
||||
this.handlers = getHandlers(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to detect the cause of an event that was fired.
|
||||
*
|
||||
* @param elements The stack trace
|
||||
* @return The plugin, if found
|
||||
*/
|
||||
@Nullable
|
||||
public Plugin detectPlugin(StackTraceElement[] elements) {
|
||||
for (int i = elements.length - 1; i >= 0; i--) {
|
||||
StackTraceElement element = elements[i];
|
||||
|
||||
for (Handler handler : handlers) {
|
||||
if (element.getClassName().equals(handler.className)) {
|
||||
return handler.plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a cache of listeners registered for an event.
|
||||
*
|
||||
* @param event The event
|
||||
* @return A list of handlers
|
||||
*/
|
||||
private static List<Handler> getHandlers(Event event) {
|
||||
List<Handler> handlers = Lists.newArrayList();
|
||||
|
||||
for (RegisteredListener listener : event.getHandlers().getRegisteredListeners()) {
|
||||
handlers.add(new Handler(listener.getListener().getClass().getName(), listener.getPlugin()));
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
private static class Handler {
|
||||
private final String className;
|
||||
private final Plugin plugin;
|
||||
|
||||
private Handler(String className, Plugin plugin) {
|
||||
this.className = className;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
}
|
||||
}
|
111
src/main/java/com/sk89q/worldguard/util/report/CancelReport.java
Normal file
111
src/main/java/com/sk89q/worldguard/util/report/CancelReport.java
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.util.report;
|
||||
|
||||
import com.sk89q.worldguard.bukkit.event.debug.CancelAttempt;
|
||||
import com.sk89q.worldguard.bukkit.util.HandlerTracer;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class CancelReport implements Report {
|
||||
|
||||
private final Event event;
|
||||
private final Cancellable cancellable;
|
||||
private final List<CancelAttempt> cancels;
|
||||
private final HandlerTracer tracer;
|
||||
private final int stackTruncateLength;
|
||||
|
||||
public <T extends Event & Cancellable> CancelReport(T event, List<CancelAttempt> cancels, int stackTruncateLength) {
|
||||
checkNotNull(event, "event");
|
||||
checkNotNull(cancels, "cancels");
|
||||
this.event = event;
|
||||
this.cancellable = event;
|
||||
this.cancels = cancels;
|
||||
this.tracer = new HandlerTracer(event);
|
||||
this.stackTruncateLength = stackTruncateLength;
|
||||
}
|
||||
|
||||
private StackTraceElement[] truncateStackTrace(StackTraceElement[] elements) {
|
||||
int newLength = elements.length - stackTruncateLength;
|
||||
if (newLength <= 0) {
|
||||
return new StackTraceElement[0];
|
||||
} else {
|
||||
return Arrays.copyOf(elements, newLength);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!cancels.isEmpty()) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("Was the action blocked? ").append(cancellable.isCancelled() ? "YES" : "NO").append("\n");
|
||||
|
||||
if (cancels.size() != 1) {
|
||||
builder.append("Entry #1 had the last word.\n");
|
||||
}
|
||||
|
||||
for (int i = cancels.size() - 1; i >= 0; i--) {
|
||||
CancelAttempt cancel = cancels.get(i);
|
||||
int index = cancels.size() - i;
|
||||
|
||||
StackTraceElement[] stackTrace = truncateStackTrace(cancel.getStackTrace());
|
||||
Plugin cause = tracer.detectPlugin(stackTrace);
|
||||
|
||||
builder.append("#").append(index).append(" ");
|
||||
builder.append(getCancelText(cancel.getAfter()));
|
||||
builder.append(" by ");
|
||||
|
||||
if (cause != null) {
|
||||
builder.append(cause.getName());
|
||||
} else {
|
||||
builder.append(" (NOT KNOWN - use the stack trace below)");
|
||||
builder.append("\n");
|
||||
builder.append(new StackTraceReport(stackTrace).toString().replaceAll("(?m)^", "\t"));
|
||||
}
|
||||
|
||||
builder.append("\n");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
} else {
|
||||
return "No plugins cancelled the event. Other causes for cancellation: " +
|
||||
"(1) Bukkit may be using a different event for the action " +
|
||||
" (example: buckets have their own bucket events); or " +
|
||||
"(2) Minecraft's spawn protection has not been disabled.";
|
||||
}
|
||||
}
|
||||
|
||||
private static String getCancelText(boolean flag) {
|
||||
return flag ? "BLOCKED" : "ALLOWED";
|
||||
}
|
||||
|
||||
}
|
26
src/main/java/com/sk89q/worldguard/util/report/Report.java
Normal file
26
src/main/java/com/sk89q/worldguard/util/report/Report.java
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.util.report;
|
||||
|
||||
public interface Report {
|
||||
|
||||
String getTitle();
|
||||
|
||||
}
|
194
src/main/java/com/sk89q/worldguard/util/report/ReportList.java
Normal file
194
src/main/java/com/sk89q/worldguard/util/report/ReportList.java
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.util.report;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class ReportList implements Report, List<Report> {
|
||||
|
||||
private final String title;
|
||||
private final List<Report> reports = Lists.newArrayList();
|
||||
|
||||
public ReportList(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return reports.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return reports.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return reports.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Report> iterator() {
|
||||
return reports.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return reports.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return reports.toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Report report) {
|
||||
return reports.add(report);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return reports.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return reports.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Report> c) {
|
||||
return reports.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends Report> c) {
|
||||
return reports.addAll(index, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return reports.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return reports.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(UnaryOperator<Report> operator) {
|
||||
reports.replaceAll(operator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(Comparator<? super Report> c) {
|
||||
reports.sort(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
reports.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return reports.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return reports.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Report get(int index) {
|
||||
return reports.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Report set(int index, Report element) {
|
||||
return reports.set(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Report element) {
|
||||
reports.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Report remove(int index) {
|
||||
return reports.remove(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
return reports.indexOf(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
return reports.lastIndexOf(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<Report> listIterator() {
|
||||
return reports.listIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<Report> listIterator(int index) {
|
||||
return reports.listIterator(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Report> subList(int fromIndex, int toIndex) {
|
||||
return reports.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!reports.isEmpty()) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Report report : reports) {
|
||||
builder.append("================================")
|
||||
.append(report.getTitle())
|
||||
.append("================================")
|
||||
.append("\n\n")
|
||||
.append(report.toString())
|
||||
.append("\n\n");
|
||||
}
|
||||
return builder.toString();
|
||||
} else {
|
||||
return "No reports.";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.util.report;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class StackTraceReport implements Report {
|
||||
|
||||
private final StackTraceElement[] stackTrace;
|
||||
|
||||
public StackTraceReport(StackTraceElement[] stackTrace) {
|
||||
checkNotNull(stackTrace, "stackTrace");
|
||||
this.stackTrace = stackTrace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Stack Trace";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (stackTrace.length > 0) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (StackTraceElement element : stackTrace) {
|
||||
if (!first) {
|
||||
builder.append("\n");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
builder.append(element.getClassName())
|
||||
.append(".")
|
||||
.append(element.getMethodName())
|
||||
.append("() (")
|
||||
.append(element.getFileName())
|
||||
.append(":")
|
||||
.append(element.getLineNumber())
|
||||
.append(")");
|
||||
}
|
||||
return builder.toString();
|
||||
} else {
|
||||
return "No stack trace available.";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user