Add event cancellation debug commands.

This commit is contained in:
sk89q 2014-12-30 20:05:42 -08:00
parent 18ec3db1bb
commit ce169461a3
14 changed files with 1051 additions and 0 deletions

View File

@ -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.");
}
}

View File

@ -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) {}
} }

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View 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";
}
}

View 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();
}

View 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.";
}
}
}

View File

@ -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.";
}
}
}