Add ClaimPermissionCheckEvent (#1006)

Also contains a bit of refactoring on internal logic. Modifies (secondary) siege mechanics.

* Un-couple siege from core claim functions

* UUID overload, documentation, naming clarity

* Add internal special message override support

* Fix permission calculation issues in subclaims

* Migrate egg handling to new methods

* Use suppliers for denial message

In many use cases addons don't care why a denial occurred, only that it did. On-demand calculation is vastly preferable to reduce server impact.
This commit is contained in:
Adam 2021-06-24 04:28:59 -04:00 committed by GitHub
parent fbf4c7c45b
commit bbb1e5d58c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 664 additions and 351 deletions

View File

@ -76,6 +76,7 @@ import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.function.BiPredicate;
import java.util.function.Supplier;
//event handlers related to blocks
public class BlockEventHandler implements Listener
@ -271,12 +272,12 @@ public class BlockEventHandler implements Listener
if (claim != null)
{
playerData.lastClaim = claim;
String noContainerReason = claim.allowContainers(player);
Supplier<String> noContainerReason = claim.checkPermission(player, ClaimPermission.Inventory, placeEvent);
if (noContainerReason == null)
return;
placeEvent.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noContainerReason);
GriefPrevention.sendMessage(player, TextMode.Err, noContainerReason.get());
return;
}
}
@ -304,7 +305,7 @@ public class BlockEventHandler implements Listener
}
//if the player has permission for the claim and he's placing UNDER the claim
if (block.getY() <= claim.lesserBoundaryCorner.getBlockY() && claim.allowBuild(player, block.getType()) == null)
if (block.getY() <= claim.lesserBoundaryCorner.getBlockY() && claim.checkPermission(player, ClaimPermission.Build, placeEvent) == null)
{
//extend the claim downward
this.dataStore.extendClaim(claim, block.getY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance);
@ -755,7 +756,7 @@ public class BlockEventHandler implements Listener
ProjectileSource shooter = ((Projectile) igniteEvent.getIgnitingEntity()).getShooter();
// Allow ignition if arrow was shot by a player with build permission.
if (shooter instanceof Player && claim.allowBuild((Player) shooter, Material.TNT) == null) return;
if (shooter instanceof Player && claim.checkPermission((Player) shooter, ClaimPermission.Build, igniteEvent) == null) return;
// Allow ignition if arrow was shot by a dispenser in the same claim.
if (shooter instanceof BlockProjectileSource &&
@ -945,13 +946,13 @@ public class BlockEventHandler implements Listener
return;
}
String allowContainer = claim.allowContainers(shooter);
Supplier<String> allowContainer = claim.checkPermission(shooter, ClaimPermission.Inventory, event);
if (allowContainer != null)
{
event.getHitBlock().setType(Material.AIR);
Bukkit.getScheduler().runTask(GriefPrevention.instance, () -> event.getHitBlock().setBlockData(block.getBlockData()));
GriefPrevention.sendMessage(shooter, TextMode.Err, allowContainer);
GriefPrevention.sendMessage(shooter, TextMode.Err, allowContainer.get());
return;
}
}

View File

@ -19,6 +19,8 @@
package me.ryanhamshire.GriefPrevention;
import me.ryanhamshire.GriefPrevention.util.BoundingBox;
import me.ryanhamshire.GriefPrevention.events.ClaimPermissionCheckEvent;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
@ -28,6 +30,11 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import java.util.ArrayList;
import java.util.Calendar;
@ -39,6 +46,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;
//represents a player claim
//creating an instance doesn't make an effective claim
@ -95,9 +103,7 @@ public class Claim
//administrative claims are created and maintained by players with the griefprevention.adminclaims permission.
public boolean isAdminClaim()
{
if (this.parent != null) return this.parent.isAdminClaim();
return (this.ownerID == null);
return this.getOwnerID() == null;
}
//accessor for ID
@ -119,7 +125,7 @@ public class Claim
{
if (this.isAdminClaim()) return false;
if (this.allowAccess(defender) != null) return false;
if (this.checkPermission(defender, ClaimPermission.Access, null) != null) return false;
return true;
}
@ -310,50 +316,15 @@ public class Claim
return claim.contains(location, false, true);
}
//permissions. note administrative "public" claims have different rules than other claims
//all of these return NULL when a player has permission, or a String error message when the player doesn't have permission
/**
* @deprecated Check {@link ClaimPermission#Edit} with {@link #checkPermission(Player, ClaimPermission, Event)}.
* @param player the Player
* @return the denial message, or null if the action is allowed
*/
@Deprecated
public String allowEdit(Player player)
{
//if we don't know who's asking, always say no (i've been told some mods can make this happen somehow)
if (player == null) return "";
//special cases...
//admin claims need adminclaims permission only.
if (this.isAdminClaim())
{
if (player.hasPermission("griefprevention.adminclaims")) return null;
}
//anyone with deleteclaims permission can modify non-admin claims at any time
else
{
if (player.hasPermission("griefprevention.deleteclaims")) return null;
}
//no resizing, deleting, and so forth while under siege
if (player.getUniqueId().equals(this.ownerID))
{
if (this.siegeData != null)
{
return GriefPrevention.instance.dataStore.getMessage(Messages.NoModifyDuringSiege);
}
//otherwise, owners can do whatever
return null;
}
//permission inheritance for subdivisions
if (this.parent != null)
{
if (player.getUniqueId().equals(this.parent.ownerID))
return null;
if (!inheritNothing)
return this.parent.allowEdit(player);
}
//error message if all else fails
return GriefPrevention.instance.dataStore.getMessage(Messages.OnlyOwnersModifyClaims, this.getOwnerName());
return checkPermission(player, ClaimPermission.Edit, null).get();
}
private static final Set<Material> PLACEABLE_FARMING_BLOCKS = EnumSet.of(
@ -371,73 +342,53 @@ public class Claim
return PLACEABLE_FARMING_BLOCKS.contains(material);
}
/**
* @deprecated Check {@link ClaimPermission#Build} with {@link #checkPermission(Player, ClaimPermission, Event)}.
* @param player the Player
* @return the denial message, or null if the action is allowed
*/
@Deprecated
//build permission check
public String allowBuild(Player player, Material material)
{
//if we don't know who's asking, always say no (i've been told some mods can make this happen somehow)
if (player == null) return "";
return checkPermission(player, ClaimPermission.Build, new CompatBuildBreakEvent(material, false)).get();
}
//when a player tries to build in a claim, if he's under siege, the siege may extend to include the new claim
GriefPrevention.instance.dataStore.tryExtendSiege(player, this);
public static class CompatBuildBreakEvent extends Event
{
private final Material material;
private final boolean isBreak;
//admin claims can always be modified by admins, no exceptions
if (this.isAdminClaim())
private CompatBuildBreakEvent(Material material, boolean isBreak)
{
if (player.hasPermission("griefprevention.adminclaims")) return null;
this.material = material;
this.isBreak = isBreak;
}
//no building while under siege
if (this.siegeData != null)
public Material getMaterial()
{
return GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildUnderSiege, this.siegeData.attacker.getName());
return material;
}
//no building while in pvp combat
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId());
if (playerData.inPvpCombat())
public boolean isBreak()
{
return GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildPvP);
return isBreak;
}
//owners can make changes, or admins with ignore claims mode enabled
if (player.getUniqueId().equals(this.ownerID) || GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).ignoreClaims)
return null;
//anyone with explicit build permission can make changes
if (this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
//also everyone is a member of the "public", so check for public permission
if (ClaimPermission.Build.isGrantedBy(this.playerIDToClaimPermissionMap.get("public"))) return null;
//allow for farming with /containertrust permission
if (this.allowContainers(player) == null)
@Override
public HandlerList getHandlers()
{
//do allow for farming, if player has /containertrust permission
if (placeableForFarming(material))
{
return null;
}
return new HandlerList();
}
//subdivision permission inheritance
if (this.parent != null)
{
if (player.getUniqueId().equals(this.parent.ownerID))
return null;
if (!inheritNothing)
return this.parent.allowBuild(player, material);
}
//failure message for all other cases
String reason = GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildPermission, this.getOwnerName());
if (player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
}
public boolean hasExplicitPermission(UUID uuid, ClaimPermission level)
{
if (uuid.equals(this.getOwnerID())) return true;
if (level == ClaimPermission.Manage) return this.managers.contains(uuid.toString());
return level.isGrantedBy(this.playerIDToClaimPermissionMap.get(uuid.toString()));
}
@ -446,185 +397,224 @@ public class Claim
// Check explicit ClaimPermission for UUID
if (this.hasExplicitPermission(player.getUniqueId(), level)) return true;
// Special case managers - a separate list is used.
if (level == ClaimPermission.Manage)
{
for (String node : this.managers)
{
// Ensure valid permission format for permissions - [permission.node]
if (node.length() < 3 || node.charAt(0) != '[' || node.charAt(node.length() - 1) != ']') continue;
// Check if player has node
if (player.hasPermission(node.substring(1, node.length() - 1))) return true;
}
return false;
}
// Check permission-based ClaimPermission
for (Map.Entry<String, ClaimPermission> stringToPermission : this.playerIDToClaimPermissionMap.entrySet())
{
String node = stringToPermission.getKey();
// Ensure valid permission format for permissions - [permission.node]
if (node.length() < 3 || node.charAt(0) != '[' || node.charAt(node.length() - 1) != ']')
{
continue;
}
if (node.length() < 3 || node.charAt(0) != '[' || node.charAt(node.length() - 1) != ']') continue;
// Check if level is high enough and player has node
if (level.isGrantedBy(stringToPermission.getValue())
&& player.hasPermission(node.substring(1, node.length() - 1)))
{
return true;
}
}
return false;
}
//break permission check
/**
* Check whether or not a Player has a certain level of trust.
*
* @param player the Player being checked for permissions
* @param permission the ClaimPermission level required
* @param event the Event triggering the permission check
* @return the denial message or null if permission is granted
*/
public Supplier<String> checkPermission(Player player, ClaimPermission permission, Event event)
{
return checkPermission(player, permission, event, null);
}
/**
* Check whether or not a Player has a certain level of trust. For internal use; allows changing default message.
*
* @param player the Player being checked for permissions
* @param permission the ClaimPermission level required
* @param event the Event triggering the permission check
* @param denialOverride a message overriding the default denial for clarity
* @return the denial message or null if permission is granted
*/
Supplier<String> checkPermission(Player player, ClaimPermission permission, Event event, Supplier<String> denialOverride)
{
return callPermissionCheck(new ClaimPermissionCheckEvent(player, this, permission, event), denialOverride);
}
/**
* Check whether or not a UUID has a certain level of trust.
*
* @param uuid the UUID being checked for permissions
* @param permission the ClaimPermission level required
* @param event the Event triggering the permission check
* @return the denial reason or null if permission is granted
*/
public Supplier<String> checkPermission(UUID uuid, ClaimPermission permission, Event event)
{
return callPermissionCheck(new ClaimPermissionCheckEvent(uuid, this, permission, event), null);
}
/**
* Helper method for calling a ClaimPermissionCheckEvent.
*
* @param event the ClaimPermissionCheckEvent to call
* @param denialOverride a message overriding the default denial for clarity
* @return the denial reason or null if permission is granted
*/
private Supplier<String> callPermissionCheck(ClaimPermissionCheckEvent event, Supplier<String> denialOverride)
{
// Set denial message (if any) using default behavior.
Supplier<String> defaultDenial = getDefaultDenial(event.getCheckedPlayer(), event.getCheckedUUID(),
event.getRequiredPermission(), event.getTriggeringEvent());
// If permission is denied and a clarifying override is provided, use override.
if (defaultDenial != null && denialOverride != null) {
defaultDenial = denialOverride;
}
event.setDenialReason(defaultDenial);
Bukkit.getPluginManager().callEvent(event);
return event.getDenialReason();
}
/**
* Get the default reason for denial of a ClaimPermission.
*
* @param player the Player being checked for permissions
* @param uuid the UUID being checked for permissions
* @param permission the ClaimPermission required
* @param event the Event triggering the permission check
* @return the denial reason or null if permission is granted
*/
private Supplier<String> getDefaultDenial(Player player, UUID uuid, ClaimPermission permission, Event event)
{
if (player != null)
{
// Admin claims need adminclaims permission only.
if (this.isAdminClaim())
{
if (player.hasPermission("griefprevention.adminclaims")) return null;
}
// Anyone with deleteclaims permission can edit non-admin claims at any time.
else if (permission == ClaimPermission.Edit && player.hasPermission("griefprevention.deleteclaims"))
return null;
}
// Claim owner and admins in ignoreclaims mode have access.
if (uuid.equals(this.getOwnerID()) || GriefPrevention.instance.dataStore.getPlayerData(uuid).ignoreClaims)
return null;
// Look for explicit individual permission.
if (player != null)
{
if (this.hasExplicitPermission(player, permission)) return null;
}
else
{
if (this.hasExplicitPermission(uuid, permission)) return null;
}
// Check for public permission.
if (permission.isGrantedBy(this.playerIDToClaimPermissionMap.get("public"))) return null;
// Special building-only rules.
if (permission == ClaimPermission.Build)
{
// No building while in PVP.
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(uuid);
if (playerData.inPvpCombat())
{
return () -> GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildPvP);
}
// Allow farming crops with container trust.
Material material = null;
if (event instanceof BlockBreakEvent || event instanceof BlockPlaceEvent)
material = ((BlockEvent) event).getBlock().getType();
if (material != null && placeableForFarming(material)
&& this.getDefaultDenial(player, uuid, ClaimPermission.Inventory, event) == null)
return null;
}
// Permission inheritance for subdivisions.
if (this.parent != null)
{
if (!inheritNothing)
return this.parent.getDefaultDenial(player, uuid, permission, event);
}
// Catch-all error message for all other cases.
return () ->
{
String reason = GriefPrevention.instance.dataStore.getMessage(permission.getDenialMessage(), this.getOwnerName());
if (player != null && player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
};
}
/**
* @deprecated Check {@link ClaimPermission#Build} with {@link #checkPermission(Player, ClaimPermission, Event)}.
* @param player the Player
* @return the denial message, or null if the action is allowed
*/
@Deprecated
public String allowBreak(Player player, Material material)
{
//if under siege, some blocks will be breakable
if (this.siegeData != null || this.doorsOpen)
{
//search for block type in list of breakable blocks
boolean breakable = GriefPrevention.instance.config_siege_blocks.contains(material);
//custom error messages for siege mode
if (!breakable)
{
return GriefPrevention.instance.dataStore.getMessage(Messages.NonSiegeMaterial);
}
else if (player.getUniqueId().equals(this.ownerID))
{
return GriefPrevention.instance.dataStore.getMessage(Messages.NoOwnerBuildUnderSiege);
}
else
{
return null;
}
}
//if not under siege, build rules apply
return this.allowBuild(player, material);
return checkPermission(player, ClaimPermission.Build, new CompatBuildBreakEvent(material, true)).get();
}
//access permission check
/**
* @deprecated Check {@link ClaimPermission#Access} with {@link #checkPermission(Player, ClaimPermission, Event)}.
* @param player the Player
* @return the denial message, or null if the action is allowed
*/
@Deprecated
public String allowAccess(Player player)
{
//following a siege where the defender lost, the claim will allow everyone access for a time
if (this.doorsOpen) return null;
//admin claims need adminclaims permission only.
if (this.isAdminClaim())
{
if (player.hasPermission("griefprevention.adminclaims")) return null;
}
//claim owner and admins in ignoreclaims mode have access
if (player.getUniqueId().equals(this.ownerID) || GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).ignoreClaims)
return null;
//look for explicit individual access, inventory, or build permission
if (this.hasExplicitPermission(player, ClaimPermission.Access)) return null;
//also check for public permission
if (ClaimPermission.Access.isGrantedBy(this.playerIDToClaimPermissionMap.get("public"))) return null;
//permission inheritance for subdivisions
if (this.parent != null)
{
if (player.getUniqueId().equals(this.parent.ownerID))
return null;
if (!inheritNothing)
return this.parent.allowAccess(player);
}
//catch-all error message for all other cases
String reason = GriefPrevention.instance.dataStore.getMessage(Messages.NoAccessPermission, this.getOwnerName());
if (player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
return checkPermission(player, ClaimPermission.Access, null).get();
}
//inventory permission check
/**
* @deprecated Check {@link ClaimPermission#Inventory} with {@link #checkPermission(Player, ClaimPermission, Event)}.
* @param player the Player
* @return the denial message, or null if the action is allowed
*/
@Deprecated
public String allowContainers(Player player)
{
//if we don't know who's asking, always say no (i've been told some mods can make this happen somehow)
if (player == null) return "";
//trying to access inventory in a claim may extend an existing siege to include this claim
GriefPrevention.instance.dataStore.tryExtendSiege(player, this);
//if under siege, nobody accesses containers
if (this.siegeData != null)
{
return GriefPrevention.instance.dataStore.getMessage(Messages.NoContainersSiege, siegeData.attacker.getName());
}
//owner and administrators in ignoreclaims mode have access
if (player.getUniqueId().equals(this.ownerID) || GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).ignoreClaims)
return null;
//admin claims need adminclaims permission only.
if (this.isAdminClaim())
{
if (player.hasPermission("griefprevention.adminclaims")) return null;
}
//check for explicit individual container or build permission
if (this.hasExplicitPermission(player, ClaimPermission.Inventory)) return null;
//check for public container or build permission
if (ClaimPermission.Inventory.isGrantedBy(this.playerIDToClaimPermissionMap.get("public"))) return null;
//permission inheritance for subdivisions
if (this.parent != null)
{
if (player.getUniqueId().equals(this.parent.ownerID))
return null;
if (!inheritNothing)
return this.parent.allowContainers(player);
}
//error message for all other cases
String reason = GriefPrevention.instance.dataStore.getMessage(Messages.NoContainersPermission, this.getOwnerName());
if (player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
return checkPermission(player, ClaimPermission.Inventory, null).get();
}
//grant permission check, relatively simple
/**
* @deprecated Check {@link ClaimPermission#Manage} with {@link #checkPermission(Player, ClaimPermission, Event)}.
* @param player the Player
* @return the denial message, or null if the action is allowed
*/
@Deprecated
public String allowGrantPermission(Player player)
{
//if we don't know who's asking, always say no (i've been told some mods can make this happen somehow)
if (player == null) return "";
//anyone who can modify the claim can do this
if (this.allowEdit(player) == null) return null;
//anyone who's in the managers (/PermissionTrust) list can do this
for (String managerID : this.managers)
{
if (managerID == null) continue;
if (player.getUniqueId().toString().equals(managerID)) return null;
else if (managerID.startsWith("[") && managerID.endsWith("]"))
{
managerID = managerID.substring(1, managerID.length() - 1);
if (managerID.isEmpty()) continue;
if (player.hasPermission(managerID)) return null;
}
}
//permission inheritance for subdivisions
if (this.parent != null)
{
if (player.getUniqueId().equals(this.parent.ownerID))
return null;
if (!inheritNothing)
return this.parent.allowGrantPermission(player);
}
//generic error message
String reason = GriefPrevention.instance.dataStore.getMessage(Messages.NoPermissionTrust, this.getOwnerName());
if (player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
return checkPermission(player, ClaimPermission.Manage, null).get();
}
public ClaimPermission getPermission(String playerID)
{
if (playerID == null || playerID.isEmpty())
{
return null;
}
if (playerID == null || playerID.isEmpty()) return null;
return this.playerIDToClaimPermissionMap.get(playerID.toLowerCase());
}
@ -632,18 +622,22 @@ public class Claim
//grants a permission for a player or the public
public void setPermission(String playerID, ClaimPermission permissionLevel)
{
if (playerID == null || playerID.isEmpty())
{
return;
}
if (permissionLevel == ClaimPermission.Edit) throw new IllegalArgumentException("Cannot add editors!");
this.playerIDToClaimPermissionMap.put(playerID.toLowerCase(), permissionLevel);
if (playerID == null || playerID.isEmpty()) return;
if (permissionLevel == ClaimPermission.Manage)
this.managers.add(playerID.toLowerCase());
else
this.playerIDToClaimPermissionMap.put(playerID.toLowerCase(), permissionLevel);
}
//revokes a permission for a player or the public
public void dropPermission(String playerID)
{
this.playerIDToClaimPermissionMap.remove(playerID.toLowerCase());
playerID = playerID.toLowerCase();
this.playerIDToClaimPermissionMap.remove(playerID);
this.managers.remove(playerID);
for (Claim child : this.children)
{

View File

@ -18,12 +18,47 @@
package me.ryanhamshire.GriefPrevention;
//basic enum stuff
/**
* Enum representing the permissions available in a {@link Claim}.
*/
public enum ClaimPermission
{
Build,
Inventory,
Access;
/**
* ClaimPermission used for owner-based checks. Cannot be granted and grants all other permissions.
*/
Edit(Messages.OnlyOwnersModifyClaims),
/**
* ClaimPermission used for building checks. Grants {@link #Inventory} and {@link #Access}.
*/
Build(Messages.NoBuildPermission),
/**
* ClaimPermission used for inventory management checks. Grants {@link #Access}.
*/
Inventory(Messages.NoContainersPermission),
/**
* ClaimPermission used for basic access.
*/
Access(Messages.NoAccessPermission),
/**
* ClaimPermission that allows users to grant ClaimPermissions. Uses a separate track from normal
* permissions and does not grant any other permissions.
*/
Manage(Messages.NoPermissionTrust);
private final Messages denialMessage;
ClaimPermission(Messages messages)
{
this.denialMessage = messages;
}
/**
* @return the {@link Messages Message} used when alerting a user that they lack the ClaimPermission
*/
public Messages getDenialMessage()
{
return denialMessage;
}
/**
* Check if a ClaimPermission is granted by another ClaimPermission.
@ -33,7 +68,8 @@ public enum ClaimPermission
*/
public boolean isGrantedBy(ClaimPermission other)
{
// As this uses declaration order to compare, if trust levels are reordered this method must be rewritten.
if (other == Manage || this == Manage) return other == this || other == Edit;
// This uses declaration order to compare! If trust levels are reordered this method must be rewritten.
return other != null && other.ordinal() <= this.ordinal();
}

View File

@ -1285,7 +1285,12 @@ public abstract class DataStore
if (claim.isAdminClaim()) return;
//player must have some level of permission to be sieged in a claim
if (claim.allowAccess(player) != null) return;
Claim currentClaim = claim;
while (!currentClaim.hasExplicitPermission(player, ClaimPermission.Access))
{
if (currentClaim.parent == null) return;
currentClaim = currentClaim.parent;
}
//otherwise extend the siege
playerData.siegeData.claims.add(claim);

View File

@ -102,6 +102,7 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import java.util.function.Supplier;
//handles events related to entities
public class EntityEventHandler implements Listener
@ -998,12 +999,12 @@ public class EntityEventHandler implements Listener
}
//otherwise player must have container trust in the claim
String failureReason = claim.allowBuild(attacker, Material.AIR);
Supplier<String> failureReason = claim.checkPermission(attacker, ClaimPermission.Build, event);
if (failureReason != null)
{
event.setCancelled(true);
if (sendErrorMessagesToPlayers)
GriefPrevention.sendMessage(attacker, TextMode.Err, failureReason);
GriefPrevention.sendMessage(attacker, TextMode.Err, failureReason.get());
return;
}
}
@ -1135,7 +1136,19 @@ public class EntityEventHandler implements Listener
//otherwise the player damaging the entity must have permission, unless it's a dog in a pvp world
else if (!(event.getEntity().getWorld().getPVP() && event.getEntity().getType() == EntityType.WOLF))
{
String noContainersReason = claim.allowContainers(attacker);
Supplier<String> override = null;
if (sendErrorMessagesToPlayers)
{
final Player finalAttacker = attacker;
override = () ->
{
String message = GriefPrevention.instance.dataStore.getMessage(Messages.NoDamageClaimedEntity, claim.getOwnerName());
if (finalAttacker.hasPermission("griefprevention.ignoreclaims"))
message += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return message;
};
}
Supplier<String> noContainersReason = claim.checkPermission(attacker, ClaimPermission.Inventory, event, override);
if (noContainersReason != null)
{
event.setCancelled(true);
@ -1147,10 +1160,7 @@ public class EntityEventHandler implements Listener
if (sendErrorMessagesToPlayers)
{
String message = GriefPrevention.instance.dataStore.getMessage(Messages.NoDamageClaimedEntity, claim.getOwnerName());
if (attacker.hasPermission("griefprevention.ignoreclaims"))
message += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
GriefPrevention.sendMessage(attacker, TextMode.Err, message);
GriefPrevention.sendMessage(attacker, TextMode.Err, noContainersReason.get());
}
event.setCancelled(true);
}
@ -1349,15 +1359,19 @@ public class EntityEventHandler implements Listener
//otherwise the player damaging the entity must have permission
else
{
String noContainersReason = claim.allowContainers(attacker);
final Player finalAttacker = attacker;
Supplier<String> override = () ->
{
String message = GriefPrevention.instance.dataStore.getMessage(Messages.NoDamageClaimedEntity, claim.getOwnerName());
if (finalAttacker.hasPermission("griefprevention.ignoreclaims"))
message += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return message;
};
Supplier<String> noContainersReason = claim.checkPermission(attacker, ClaimPermission.Inventory, event, override);
if (noContainersReason != null)
{
event.setCancelled(true);
String message = GriefPrevention.instance.dataStore.getMessage(Messages.NoDamageClaimedEntity, claim.getOwnerName());
if (attacker.hasPermission("griefprevention.ignoreclaims"))
message += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
GriefPrevention.sendMessage(attacker, TextMode.Err, message);
event.setCancelled(true);
GriefPrevention.sendMessage(attacker, TextMode.Err, noContainersReason.get());
}
//cache claim for later
@ -1399,10 +1413,12 @@ public class EntityEventHandler implements Listener
if (claim != null)
{
cachedClaim = claim;
if (thrower == null || claim.allowContainers(thrower) != null)
Supplier<String> override = () -> instance.dataStore.getMessage(Messages.NoDamageClaimedEntity, claim.getOwnerName());
final Supplier<String> noContainersReason = claim.checkPermission(thrower, ClaimPermission.Inventory, event, override);
if (thrower == null || noContainersReason != null)
{
event.setIntensity(effected, 0);
GriefPrevention.sendMessage(thrower, TextMode.Err, Messages.NoDamageClaimedEntity, claim.getOwnerName());
GriefPrevention.sendMessage(thrower, TextMode.Err, noContainersReason.get());
return;
}
}

View File

@ -70,7 +70,7 @@ class EquipShovelProcessingTask implements Runnable
//if standing in a claim owned by the player, visualize it
Claim claim = GriefPrevention.instance.dataStore.getClaimAt(player.getLocation(), true, playerData.lastClaim);
if (claim != null && claim.allowEdit(player) == null)
if (claim != null && claim.checkPermission(player, ClaimPermission.Edit, null) == null)
{
playerData.lastClaim = claim;
Visualization.Apply(player, Visualization.FromClaim(claim, player.getEyeLocation().getBlockY(), VisualizationType.Claim, player.getLocation()));

View File

@ -45,6 +45,7 @@ import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
@ -64,6 +65,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -359,6 +361,10 @@ public class GriefPrevention extends JavaPlugin
EntityEventHandler entityEventHandler = new EntityEventHandler(this.dataStore, this);
pluginManager.registerEvents(entityEventHandler, this);
//siege events
SiegeEventHandler siegeEventHandler = new SiegeEventHandler();
pluginManager.registerEvents(siegeEventHandler, this);
//vault-based economy integration
economyHandler = new EconomyHandler(this);
pluginManager.registerEvents(economyHandler, this);
@ -1153,7 +1159,7 @@ public class GriefPrevention extends JavaPlugin
}
//must have permission to edit the land claim you're in
String errorMessage = claim.allowEdit(player);
Supplier<String> errorMessage = claim.checkPermission(player, ClaimPermission.Edit, null);
if (errorMessage != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotYourClaim);
@ -1436,10 +1442,10 @@ public class GriefPrevention extends JavaPlugin
}
//if no permission to manage permissions, error message
String errorMessage = claim.allowGrantPermission(player);
Supplier<String> errorMessage = claim.checkPermission(player, ClaimPermission.Manage, null);
if (errorMessage != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, errorMessage);
GriefPrevention.sendMessage(player, TextMode.Err, errorMessage.get());
return true;
}
@ -1528,7 +1534,7 @@ public class GriefPrevention extends JavaPlugin
OfflinePlayer otherPlayer = null;
if (args[0].equals("all"))
{
if (claim == null || claim.allowEdit(player) == null)
if (claim == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null)
{
clearPermissions = true;
}
@ -1616,7 +1622,7 @@ public class GriefPrevention extends JavaPlugin
}
//otherwise, apply changes to only this claim
else if (claim.allowGrantPermission(player) != null)
else if (claim.checkPermission(player, ClaimPermission.Manage, null) != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoPermissionTrust, claim.getOwnerName());
return true;
@ -1627,7 +1633,7 @@ public class GriefPrevention extends JavaPlugin
if (clearPermissions)
{
//requires owner
if (claim.allowEdit(player) != null)
if (claim.checkPermission(player, ClaimPermission.Edit, null) != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.UntrustAllOwnerOnly);
return true;
@ -1655,7 +1661,7 @@ public class GriefPrevention extends JavaPlugin
idToDrop = otherPlayer.getUniqueId().toString();
}
boolean targetIsManager = claim.managers.contains(idToDrop);
if (targetIsManager && claim.allowEdit(player) != null) //only claim owners can untrust managers
if (targetIsManager && claim.checkPermission(player, ClaimPermission.Edit, null) != null) //only claim owners can untrust managers
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.ManagersDontUntrustManagers, claim.getOwnerName());
return true;
@ -2014,10 +2020,10 @@ public class GriefPrevention extends JavaPlugin
}
else
{
String noBuildReason = claim.allowBuild(player, Material.STONE);
Supplier<String> noBuildReason = claim.checkPermission(player, ClaimPermission.Build, null);
if (noBuildReason != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason);
GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get());
return true;
}
@ -2423,7 +2429,7 @@ public class GriefPrevention extends JavaPlugin
}
//if the player isn't in a claim or has permission to build, tell him to man up
if (claim == null || claim.allowBuild(player, Material.AIR) == null)
if (claim == null || claim.checkPermission(player, ClaimPermission.Build, null) == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotTrappedHere);
return true;
@ -2547,7 +2553,7 @@ public class GriefPrevention extends JavaPlugin
Claim defenderClaim = this.dataStore.getClaimAt(defender.getLocation(), false, null);
//defender must have some level of permission there to be protected
if (defenderClaim == null || defenderClaim.allowAccess(defender) != null)
if (defenderClaim == null || defenderClaim.checkPermission(defender, ClaimPermission.Access, null) != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotSiegableThere);
return true;
@ -2876,7 +2882,7 @@ public class GriefPrevention extends JavaPlugin
}
//verify ownership
else if (claim.allowEdit(player) != null)
else if (claim.checkPermission(player, ClaimPermission.Edit, null) != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotYourClaim);
}
@ -2974,39 +2980,29 @@ public class GriefPrevention extends JavaPlugin
else
{
//check permission here
if (claim.allowGrantPermission(player) != null)
if (claim.checkPermission(player, ClaimPermission.Manage, null) != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoPermissionTrust, claim.getOwnerName());
return;
}
//see if the player has the level of permission he's trying to grant
String errorMessage = null;
Supplier<String> errorMessage;
//permission level null indicates granting permission trust
if (permissionLevel == null)
{
errorMessage = claim.allowEdit(player);
errorMessage = claim.checkPermission(player, ClaimPermission.Edit, null);
if (errorMessage != null)
{
errorMessage = "Only " + claim.getOwnerName() + " can grant /PermissionTrust here.";
errorMessage = () -> "Only " + claim.getOwnerName() + " can grant /PermissionTrust here.";
}
}
//otherwise just use the ClaimPermission enum values
else
{
switch (permissionLevel)
{
case Access:
errorMessage = claim.allowAccess(player);
break;
case Inventory:
errorMessage = claim.allowContainers(player);
break;
default:
errorMessage = claim.allowBuild(player, Material.AIR);
}
errorMessage = claim.checkPermission(player, permissionLevel, null);
}
//error message for trying to grant a permission the player doesn't have
@ -3385,6 +3381,7 @@ public class GriefPrevention extends JavaPlugin
public String allowBuild(Player player, Location location)
{
// TODO check all derivatives and rework API
return this.allowBuild(player, location, location.getBlock().getType());
}
@ -3431,20 +3428,27 @@ public class GriefPrevention extends JavaPlugin
{
//cache the claim for later reference
playerData.lastClaim = claim;
return claim.allowBuild(player, material);
Block block = location.getBlock();
Supplier<String> supplier = claim.checkPermission(player, ClaimPermission.Build, new BlockPlaceEvent(block, block.getState(), block, new ItemStack(material), player, true, EquipmentSlot.HAND));
if (supplier == null) return null;
return supplier.get();
}
}
public String allowBreak(Player player, Block block, Location location)
{
return this.allowBreak(player, block, location, null);
}
public String allowBreak(Player player, Block block, Location location, BlockBreakEvent breakEvent) {
return this.allowBreak(player, block.getType(), location, breakEvent);
return this.allowBreak(player, block, location, new BlockBreakEvent(block, player));
}
public String allowBreak(Player player, Material material, Location location, BlockBreakEvent breakEvent)
{
return this.allowBreak(player, location.getBlock(), location, breakEvent);
}
public String allowBreak(Player player, Block block, Location location, BlockBreakEvent breakEvent)
{
if (!GriefPrevention.instance.claimsEnabledForWorld(location.getWorld())) return null;
@ -3479,7 +3483,7 @@ public class GriefPrevention extends JavaPlugin
playerData.lastClaim = claim;
//if not in the wilderness, then apply claim rules (permissions, etc)
String cancel = claim.allowBreak(player, material);
Supplier<String> cancel = claim.checkPermission(player, ClaimPermission.Build, breakEvent);
if (cancel != null && breakEvent != null)
{
PreventBlockBreakEvent preventionEvent = new PreventBlockBreakEvent(breakEvent);
@ -3490,7 +3494,9 @@ public class GriefPrevention extends JavaPlugin
}
}
return cancel;
if (cancel == null) return null;
return cancel.get();
}
}

View File

@ -106,6 +106,7 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.regex.Pattern;
class PlayerEventHandler implements Listener
@ -530,10 +531,10 @@ class PlayerEventHandler implements Listener
if (claim != null)
{
playerData.lastClaim = claim;
String reason = claim.allowAccess(player);
Supplier<String> reason = claim.checkPermission(player, ClaimPermission.Access, event);
if (reason != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, reason);
GriefPrevention.sendMessage(player, TextMode.Err, reason.get());
event.setCancelled(true);
}
}
@ -1091,10 +1092,10 @@ class PlayerEventHandler implements Listener
if (toClaim != null)
{
playerData.lastClaim = toClaim;
String noAccessReason = toClaim.allowAccess(player);
Supplier<String> noAccessReason = toClaim.checkPermission(player, ClaimPermission.Access, event);
if (noAccessReason != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, noAccessReason);
GriefPrevention.sendMessage(player, TextMode.Err, noAccessReason.get());
event.setCancelled(true);
if (cause == TeleportCause.ENDER_PEARL)
player.getInventory().addItem(new ItemStack(Material.ENDER_PEARL));
@ -1142,12 +1143,12 @@ class PlayerEventHandler implements Listener
Player player = event.getPlayer();
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
Claim toClaim = this.dataStore.getClaimAt(player.getLocation(), false, playerData.lastClaim);
if (toClaim == null)
Claim claim = this.dataStore.getClaimAt(player.getLocation(), false, playerData.lastClaim);
if (claim == null)
return;
playerData.lastClaim = toClaim;
if (toClaim.allowBuild(player, Material.AIR) == null)
playerData.lastClaim = claim;
if (claim.checkPermission(player, ClaimPermission.Build, event) == null)
return;
event.setCancelled(true);
@ -1291,10 +1292,10 @@ class PlayerEventHandler implements Listener
//for storage entities, apply container rules (this is a potential theft)
if (entity instanceof InventoryHolder)
{
String noContainersReason = claim.allowContainers(player);
Supplier<String> noContainersReason = claim.checkPermission(player, ClaimPermission.Inventory, event);
if (noContainersReason != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, noContainersReason);
GriefPrevention.sendMessage(player, TextMode.Err, noContainersReason.get());
event.setCancelled(true);
return;
}
@ -1309,12 +1310,18 @@ class PlayerEventHandler implements Listener
Claim claim = this.dataStore.getClaimAt(entity.getLocation(), false, null);
if (claim != null)
{
if (claim.allowContainers(player) != null)
Supplier<String> override = () ->
{
String message = instance.dataStore.getMessage(Messages.NoDamageClaimedEntity, claim.getOwnerName());
if (player.hasPermission("griefprevention.ignoreclaims"))
message += " " + instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
GriefPrevention.sendMessage(player, TextMode.Err, message);
return message;
};
final Supplier<String> noContainersReason = claim.checkPermission(player, ClaimPermission.Inventory, event, override);
if (noContainersReason != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, noContainersReason.get());
event.setCancelled(true);
return;
}
@ -1329,11 +1336,11 @@ class PlayerEventHandler implements Listener
Claim claim = this.dataStore.getClaimAt(entity.getLocation(), false, playerData.lastClaim);
if (claim != null)
{
String failureReason = claim.allowContainers(player);
Supplier<String> failureReason = claim.checkPermission(player, ClaimPermission.Inventory, event);
if (failureReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, failureReason);
GriefPrevention.sendMessage(player, TextMode.Err, failureReason.get());
return;
}
}
@ -1362,18 +1369,18 @@ class PlayerEventHandler implements Listener
Claim claim = this.dataStore.getClaimAt(event.getEgg().getLocation(), false, playerData.lastClaim);
//allow throw egg if player is in ignore claims mode
if (playerData.ignoreClaims) return;
if (playerData.ignoreClaims || claim == null) return;
if (claim != null && claim.allowContainers(player) != null)
Supplier<String> failureReason = claim.checkPermission(player, ClaimPermission.Inventory, event);
if (failureReason != null)
{
String message = this.instance.dataStore.getMessage(Messages.NoContainersPermission, claim.getOwnerName());
String reason = failureReason.get();
if (player.hasPermission("griefprevention.ignoreclaims"))
{
message += " " + instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
reason += " " + instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
}
GriefPrevention.sendMessage(player, TextMode.Err, message);
GriefPrevention.sendMessage(player, TextMode.Err, reason);
//cancel the event by preventing hatching
event.setHatching(false);
@ -1402,7 +1409,7 @@ class PlayerEventHandler implements Listener
if (claim != null)
{
//if no permission, cancel
String errorMessage = claim.allowContainers(player);
Supplier<String> errorMessage = claim.checkPermission(player, ClaimPermission.Inventory, event);
if (errorMessage != null)
{
event.setCancelled(true);
@ -1676,7 +1683,7 @@ class PlayerEventHandler implements Listener
{
playerData.lastClaim = claim;
String noAccessReason = claim.allowBreak(player, clickedBlockType);
Supplier<String> noAccessReason = claim.checkPermission(player, ClaimPermission.Build, event);
if (noAccessReason != null)
{
event.setCancelled(true);
@ -1701,11 +1708,11 @@ class PlayerEventHandler implements Listener
{
playerData.lastClaim = claim;
String noBuildReason = claim.allowBuild(player, Material.AIR);
Supplier<String> noBuildReason = claim.checkPermission(player, ClaimPermission.Build, event);
if (noBuildReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason);
GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get());
player.sendBlockChange(adjacentBlock.getLocation(), adjacentBlock.getType(), adjacentBlock.getData());
return;
}
@ -1766,11 +1773,11 @@ class PlayerEventHandler implements Listener
{
playerData.lastClaim = claim;
String noContainersReason = claim.allowContainers(player);
Supplier<String> noContainersReason = claim.checkPermission(player, ClaimPermission.Inventory, event);
if (noContainersReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noContainersReason);
GriefPrevention.sendMessage(player, TextMode.Err, noContainersReason.get());
return;
}
}
@ -1803,11 +1810,11 @@ class PlayerEventHandler implements Listener
{
playerData.lastClaim = claim;
String noAccessReason = claim.allowAccess(player);
Supplier<String> noAccessReason = claim.checkPermission(player, ClaimPermission.Access, event);
if (noAccessReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noAccessReason);
GriefPrevention.sendMessage(player, TextMode.Err, noAccessReason.get());
return;
}
}
@ -1822,11 +1829,11 @@ class PlayerEventHandler implements Listener
{
playerData.lastClaim = claim;
String noAccessReason = claim.allowAccess(player);
Supplier<String> noAccessReason = claim.checkPermission(player, ClaimPermission.Access, event);
if (noAccessReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noAccessReason);
GriefPrevention.sendMessage(player, TextMode.Err, noAccessReason.get());
return;
}
}
@ -1841,11 +1848,11 @@ class PlayerEventHandler implements Listener
{
playerData.lastClaim = claim;
String noContainerReason = claim.allowAccess(player);
Supplier<String> noContainerReason = claim.checkPermission(player, ClaimPermission.Access, event);
if (noContainerReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noContainerReason);
GriefPrevention.sendMessage(player, TextMode.Err, noContainerReason.get());
return;
}
}
@ -1867,11 +1874,11 @@ class PlayerEventHandler implements Listener
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim);
if (claim != null)
{
String noBuildReason = claim.allowBuild(player, clickedBlockType);
Supplier<String> noBuildReason = claim.checkPermission(player, ClaimPermission.Build, event);
if (noBuildReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason);
GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get());
return;
}
}
@ -1927,10 +1934,10 @@ class PlayerEventHandler implements Listener
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim);
if (claim != null)
{
String reason = claim.allowContainers(player);
Supplier<String> reason = claim.checkPermission(player, ClaimPermission.Inventory, event);
if (reason != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, reason);
GriefPrevention.sendMessage(player, TextMode.Err, reason.get());
event.setCancelled(true);
}
}
@ -1951,10 +1958,10 @@ class PlayerEventHandler implements Listener
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim);
if (claim != null)
{
String reason = claim.allowContainers(player);
Supplier<String> reason = claim.checkPermission(player, ClaimPermission.Inventory, event);
if (reason != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, reason);
GriefPrevention.sendMessage(player, TextMode.Err, reason.get());
event.setCancelled(true);
}
}
@ -2380,7 +2387,7 @@ class PlayerEventHandler implements Listener
if (claim != null)
{
//if the player has permission to edit the claim or subdivision
String noEditReason = claim.allowEdit(player);
Supplier<String> noEditReason = claim.checkPermission(player, ClaimPermission.Edit, event, () -> instance.dataStore.getMessage(Messages.CreateClaimFailOverlapOtherPlayer, claim.getOwnerName()));
if (noEditReason == null)
{
//if he clicked on a corner, start resizing it
@ -2481,7 +2488,7 @@ class PlayerEventHandler implements Listener
//otherwise tell the player he can't claim here because it's someone else's claim, and show him the claim
else
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlapOtherPlayer, claim.getOwnerName());
GriefPrevention.sendMessage(player, TextMode.Err, noEditReason.get());
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.ErrorClaim, player.getLocation());
// alert plugins of a visualization
@ -2659,12 +2666,12 @@ class PlayerEventHandler implements Listener
if (claim != null)
{
playerData.lastClaim = claim;
String noContainerReason = claim.allowContainers(player);
Supplier<String> noContainerReason = claim.checkPermission(player, ClaimPermission.Inventory, event);
if (noContainerReason != null)
{
event.setCancelled(true);
player.closeInventory();
GriefPrevention.sendMessage(player, TextMode.Err, noContainerReason);
GriefPrevention.sendMessage(player, TextMode.Err, noContainerReason.get());
}
}
}

View File

@ -47,7 +47,7 @@ class SecureClaimTask implements Runnable
Collection<Player> onlinePlayers = (Collection<Player>) GriefPrevention.instance.getServer().getOnlinePlayers();
for (Player player : onlinePlayers)
{
if (claim.contains(player.getLocation(), false, false) && claim.allowAccess(player) != null)
if (claim.contains(player.getLocation(), false, false) && claim.checkPermission(player, ClaimPermission.Access, null) != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeDoorsLockedEjection);
GriefPrevention.instance.ejectPlayer(player);

View File

@ -20,6 +20,8 @@ package me.ryanhamshire.GriefPrevention;
import org.bukkit.entity.Player;
import java.util.function.Supplier;
//checks to see whether or not a siege should end based on the locations of the players
//for example, defender escaped or attacker gave up and left
class SiegeCheckupTask implements Runnable
@ -44,7 +46,7 @@ class SiegeCheckupTask implements Runnable
//if this is a new claim and he has some permission there, extend the siege to include it
if (defenderClaim != null)
{
String noAccessReason = defenderClaim.allowAccess(defender);
Supplier<String> noAccessReason = defenderClaim.checkPermission(defender, ClaimPermission.Access, null);
if (defenderClaim.canSiege(defender) && noAccessReason == null)
{
this.siegeData.claims.add(defenderClaim);

View File

@ -0,0 +1,100 @@
package me.ryanhamshire.GriefPrevention;
import me.ryanhamshire.GriefPrevention.events.ClaimPermissionCheckEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerInteractEvent;
public class SiegeEventHandler implements Listener
{
@EventHandler(priority = EventPriority.LOWEST)
public void onClaimPermissionCheck(ClaimPermissionCheckEvent event)
{
if (event.getRequiredPermission() == ClaimPermission.Manage) return;
Player player = event.getCheckedPlayer();
// Player must be online to use siege features.
if (player == null) return;
Claim claim = event.getClaim();
// Admin claims cannot be sieged.
if (claim.isAdminClaim()) return;
// Claim modification during siege is not allowed.
if (event.getRequiredPermission() == ClaimPermission.Edit)
{
if (claim.siegeData != null)
event.setDenialReason(() -> GriefPrevention.instance.dataStore.getMessage(Messages.NoModifyDuringSiege));
return;
}
// Following a siege where the defender lost, the claim will allow everyone access for a time.
if (event.getRequiredPermission() == ClaimPermission.Access)
{
if (claim.doorsOpen)
event.setDenialReason(null);
return;
}
// If under siege, nobody accesses containers.
if (event.getRequiredPermission() == ClaimPermission.Inventory)
{
// Trying to access inventory in a claim may extend an existing siege to include this claim.
GriefPrevention.instance.dataStore.tryExtendSiege(player, claim);
if (claim.siegeData != null)
event.setDenialReason(() -> GriefPrevention.instance.dataStore.getMessage(Messages.NoContainersSiege, claim.siegeData.attacker.getName()));
return;
}
// When a player tries to build in a claim, if he's under siege, the siege may extend to include the new claim.
GriefPrevention.instance.dataStore.tryExtendSiege(player, claim);
// If claim is not under siege and doors are not open, use default behavior.
if (claim.siegeData == null && !claim.doorsOpen)
return;
// If under siege, some blocks will be breakable.
Material broken = null;
if (event.getTriggeringEvent() instanceof BlockBreakEvent)
broken = ((BlockBreakEvent) event.getTriggeringEvent()).getBlock().getType();
else if (event.getTriggeringEvent() instanceof Claim.CompatBuildBreakEvent)
{
Claim.CompatBuildBreakEvent triggeringEvent = (Claim.CompatBuildBreakEvent) event.getTriggeringEvent();
if (triggeringEvent.isBreak())
broken = triggeringEvent.getMaterial();
}
else if (event.getTriggeringEvent() instanceof PlayerInteractEvent)
{
PlayerInteractEvent triggeringEvent = (PlayerInteractEvent) event.getTriggeringEvent();
if (triggeringEvent.getAction() == Action.PHYSICAL && triggeringEvent.getClickedBlock() != null
&& triggeringEvent.getClickedBlock().getType() == Material.TURTLE_EGG)
broken = Material.TURTLE_EGG;
}
if (broken != null)
{
// Error messages for siege mode.
if (!GriefPrevention.instance.config_siege_blocks.contains(broken))
event.setDenialReason(() -> GriefPrevention.instance.dataStore.getMessage(Messages.NonSiegeMaterial));
else if (player.getUniqueId().equals(claim.ownerID))
event.setDenialReason(() -> GriefPrevention.instance.dataStore.getMessage(Messages.NoOwnerBuildUnderSiege));
return;
}
// No building while under siege.
if (claim.siegeData != null)
event.setDenialReason(() -> GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildUnderSiege, claim.siegeData.attacker.getName()));
}
}

View File

@ -0,0 +1,146 @@
package me.ryanhamshire.GriefPrevention.events;
import me.ryanhamshire.GriefPrevention.Claim;
import me.ryanhamshire.GriefPrevention.ClaimPermission;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.util.UUID;
import java.util.function.Supplier;
/**
* This event is called when a {@link Claim} requires a specific level of trust.
* If the denial reason is null, the trust requirements are met and the action is allowed.
*/
public class ClaimPermissionCheckEvent extends Event
{
private static final HandlerList handlers = new HandlerList();
private final Player checkedPlayer;
private final UUID checkedUUID;
private final Claim claim;
private final ClaimPermission requiredPermission;
private final Event triggeringEvent;
private Supplier<String> denial;
/**
* Constructor for a ClaimPermissionCheckEvent.
*
* @param checked the Player being checked for permissions
* @param claim the Claim in which permissions are being checked
* @param required the ClaimPermission level required
* @param triggeringEvent the Event triggering the permission check
*/
public ClaimPermissionCheckEvent(Player checked, Claim claim, ClaimPermission required, Event triggeringEvent)
{
this(checked, checked.getUniqueId(), claim, required, triggeringEvent);
}
/**
* Constructor for a ClaimPermissionCheckEvent.
*
* @param checked the UUID being checked for permissions
* @param claim the Claim in which permissions are being checked
* @param required the ClaimPermission level required
* @param triggeringEvent the Event triggering the permission check
*/
public ClaimPermissionCheckEvent(UUID checked, Claim claim, ClaimPermission required, Event triggeringEvent)
{
this(Bukkit.getPlayer(checked), checked, claim, required, triggeringEvent);
}
private ClaimPermissionCheckEvent(Player checkedPlayer, UUID checkedUUID, Claim claim, ClaimPermission required, Event triggeringEvent)
{
this.checkedPlayer = checkedPlayer;
this.checkedUUID = checkedUUID;
this.claim = claim;
this.requiredPermission = required;
this.triggeringEvent = triggeringEvent;
}
/**
* Returns the Player being checked for permission if online.
*
* @return the Player being checked or null if offline
*/
public Player getCheckedPlayer()
{
return checkedPlayer;
}
/**
* Returns the UUID being checked for permission.
*
* @return the UUID being checked for permission
*/
public UUID getCheckedUUID()
{
return checkedUUID;
}
/**
* Returns the Claim in which permission is being checked.
*
* @return the Claim in which permission is being checked
*/
public Claim getClaim()
{
return claim;
}
/**
* Returns the ClaimPermission being checked for.
*
* @return the ClaimPermission being checked for
*/
public ClaimPermission getRequiredPermission()
{
return requiredPermission;
}
/**
* Returns the Event causing this event to fire.
*
* @return the Event triggering this event or null if none was provided
*/
public Event getTriggeringEvent()
{
return triggeringEvent;
}
/**
* Returns the reason the ClaimPermission check failed.
* If the check did not fail, the message will be null.
*
* @return the denial reason or null if permission is granted
*/
public Supplier<String> getDenialReason()
{
return denial;
}
/**
* Sets the reason for denial.
*
* @param denial the denial reason
*/
public void setDenialReason(Supplier<String> denial)
{
this.denial = denial;
}
@Override
public HandlerList getHandlers()
{
return handlers;
}
public static HandlerList getHandlerList()
{
return handlers;
}
}