WIP: Tracks why flag actions allowed or not

This idea is to add a "why" command for admins that will reveal why a
player can do something. I want admins to be able to understand this
better so that they can give us better bug reports or fix it themselves.

We have good error messages for players for when they can do something
via the Island Protected text, but it would be useful to have the
opposite too, i.e., an explanation for why a player was able to break
blocks.

The approach here is that an admin would do "/bsbadmin why <playername>"
to turn on tracking. Then when the player did something, it would be
reported in the console.

This commit just has enums set, but I'm going to work on a notification
system next.
This commit is contained in:
tastybento 2018-10-12 08:14:08 -07:00
parent a2c58b4c77
commit 0020cbf849

View File

@ -23,8 +23,29 @@ import world.bentobox.bentobox.managers.IslandsManager;
*/ */
public abstract class AbstractFlagListener implements Listener { public abstract class AbstractFlagListener implements Listener {
/**
* Reason for why flag was allowed or disallowed
* Used by admins for debugging player actions
*
*/
enum Why {
UNPROTECTED_WORLD,
OP,
BYPASS_EVERYWHERE,
BYPASS_ISLAND,
RANK_ALLOWED,
ALLOWED_IN_WORLD,
ALLOWED_ON_ISLAND,
NOT_ALLOWED_ON_ISLAND,
NOT_ALLOWED_IN_WORLD,
ERROR_NO_ASSOCIATED_USER,
NOT_SET
}
private BentoBox plugin = BentoBox.getInstance(); private BentoBox plugin = BentoBox.getInstance();
private User user = null; private User user = null;
private Why why;
/** /**
* @return the plugin * @return the plugin
@ -122,11 +143,13 @@ public abstract class AbstractFlagListener implements Listener {
* @return true if the check is okay, false if it was disallowed * @return true if the check is okay, false if it was disallowed
*/ */
public boolean checkIsland(Event e, Location loc, Flag flag, boolean silent) { public boolean checkIsland(Event e, Location loc, Flag flag, boolean silent) {
why = Why.NOT_SET;
// If this is not an Island World or a standard Nether or End, skip // If this is not an Island World or a standard Nether or End, skip
if (!plugin.getIWM().inWorld(loc) if (!plugin.getIWM().inWorld(loc)
|| (plugin.getIWM().isNether(loc.getWorld()) && !plugin.getIWM().isNetherIslands(loc.getWorld())) || (plugin.getIWM().isNether(loc.getWorld()) && !plugin.getIWM().isNetherIslands(loc.getWorld()))
|| (plugin.getIWM().isEnd(loc.getWorld()) && !plugin.getIWM().isEndIslands(loc.getWorld())) || (plugin.getIWM().isEnd(loc.getWorld()) && !plugin.getIWM().isEndIslands(loc.getWorld()))
) { ) {
why = Why.UNPROTECTED_WORLD;
return true; return true;
} }
// Get the island and if present // Get the island and if present
@ -134,6 +157,11 @@ public abstract class AbstractFlagListener implements Listener {
// Handle Settings Flag // Handle Settings Flag
if (flag.getType().equals(Flag.Type.SETTING)) { if (flag.getType().equals(Flag.Type.SETTING)) {
// If the island exists, return the setting, otherwise return the default setting for this flag // If the island exists, return the setting, otherwise return the default setting for this flag
if (island.isPresent()) {
why = island.map(x -> x.isAllowed(flag)).orElse(false) ? Why.ALLOWED_ON_ISLAND : Why.NOT_ALLOWED_ON_ISLAND;
} else {
why = flag.isSetForWorld(loc.getWorld()) ? Why.ALLOWED_IN_WORLD : Why.NOT_ALLOWED_IN_WORLD;
}
return island.map(x -> x.isAllowed(flag)).orElse(flag.isSetForWorld(loc.getWorld())); return island.map(x -> x.isAllowed(flag)).orElse(flag.isSetForWorld(loc.getWorld()));
} }
@ -144,12 +172,18 @@ public abstract class AbstractFlagListener implements Listener {
// TODO: is this the correct handling here? // TODO: is this the correct handling here?
if (user == null && !createEventUser(e)) { if (user == null && !createEventUser(e)) {
plugin.logError("Check island had no associated user! " + e.getEventName()); plugin.logError("Check island had no associated user! " + e.getEventName());
why = Why.ERROR_NO_ASSOCIATED_USER;
return false; return false;
} }
// Ops or "bypass everywhere" moderators can do anything // Ops or "bypass everywhere" moderators can do anything
if (user.isOp() || user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + ".mod.bypass." + flag.getID() + ".everywhere")) { if (user.isOp() || user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + ".mod.bypass." + flag.getID() + ".everywhere")) {
user = null; user = null;
if (user.isOp()) {
why = Why.OP;
} else {
why = Why.BYPASS_EVERYWHERE;
}
return true; return true;
} }
@ -158,24 +192,27 @@ public abstract class AbstractFlagListener implements Listener {
if (island.isPresent()) { if (island.isPresent()) {
// If it is not allowed on the island, "bypass island" moderators can do anything // If it is not allowed on the island, "bypass island" moderators can do anything
if (!island.get().isAllowed(user, flag) && !user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + ".mod.bypass." + flag.getID() + ".island")) { if (island.get().isAllowed(user, flag)) {
noGo(e, flag, silent); why = Why.RANK_ALLOWED;
}
if (user.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + ".mod.bypass." + flag.getID() + ".island")) {
why = Why.BYPASS_ISLAND;
}
// Clear the user for the next time // Clear the user for the next time
why = Why.NOT_ALLOWED_ON_ISLAND;
user = null; user = null;
return false; return false;
} else {
user = null;
return true;
}
} }
// The player is in the world, but not on an island, so general world settings apply // The player is in the world, but not on an island, so general world settings apply
if (!flag.isSetForWorld(loc.getWorld())) { if (flag.isSetForWorld(loc.getWorld())) {
why = Why.ALLOWED_IN_WORLD;
user = null;
return true;
} else {
why = Why.NOT_ALLOWED_IN_WORLD;
noGo(e, flag, silent); noGo(e, flag, silent);
user = null; user = null;
return false; return false;
} else {
user = null;
return true;
} }
} }
@ -203,4 +240,12 @@ public abstract class AbstractFlagListener implements Listener {
protected IslandWorldManager getIWM() { protected IslandWorldManager getIWM() {
return plugin.getIWM(); return plugin.getIWM();
} }
/**
* Get why the flag was allowed or not allowed
* @return the why - reason
*/
public Why getWhy() {
return why;
}
} }