From 61823e98fb4df0e6ebfaeab7f66cafffd2301067 Mon Sep 17 00:00:00 2001 From: Len <40720638+destro174@users.noreply.github.com> Date: Sun, 1 May 2022 18:31:27 +0200 Subject: [PATCH] Do not allow to claim near admin claims --- .../ryanhamshire/GriefPrevention/Claim.java | 1555 +++++++++-------- .../GriefPrevention/DataStore.java | 6 +- .../GriefPrevention/alttd/config/Config.java | 412 ++--- 3 files changed, 987 insertions(+), 986 deletions(-) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/Claim.java b/src/main/java/me/ryanhamshire/GriefPrevention/Claim.java index dcd9bb6..6d64af9 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/Claim.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/Claim.java @@ -1,777 +1,778 @@ -/* - GriefPrevention Server Plugin for Minecraft - Copyright (C) 2012 Ryan Hamshire - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -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; -import org.bukkit.World; -import org.bukkit.World.Environment; -import org.bukkit.WorldBorder; -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; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -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 -//only claims which have been added to the datastore have any effect -public class Claim -{ - //two locations, which together define the boundaries of the claim - //note that the upper Y value is always ignored, because claims ALWAYS extend up to the sky - Location lesserBoundaryCorner; - Location greaterBoundaryCorner; - - //modification date. this comes from the file timestamp during load, and is updated with runtime changes - public Date modifiedDate; - - //id number. unique to this claim, never changes. - Long id = null; - - //ownerID. for admin claims, this is NULL - //use getOwnerName() to get a friendly name (will be "an administrator" for admin claims) - public UUID ownerID; - - //list of players who (beyond the claim owner) have permission to grant permissions in this claim - public ArrayList managers = new ArrayList<>(); - - //permissions for this claim, see ClaimPermission class - private HashMap playerIDToClaimPermissionMap = new HashMap<>(); - - //whether or not this claim is in the data store - //if a claim instance isn't in the data store, it isn't "active" - players can't interract with it - //why keep this? so that claims which have been removed from the data store can be correctly - //ignored even though they may have references floating around - public boolean inDataStore = false; - - public boolean areExplosivesAllowed = false; - - //parent claim - //only used for claim subdivisions. top level claims have null here - public Claim parent = null; - - // intended for subclaims - they inherit no permissions - private boolean inheritNothing = false; - - //children (subdivisions) - //note subdivisions themselves never have children - public ArrayList children = new ArrayList<>(); - - //following a siege, buttons/levers are unlocked temporarily. this represents that state - public boolean doorsOpen = false; - - //whether or not this is an administrative claim - //administrative claims are created and maintained by players with the griefprevention.adminclaims permission. - public boolean isAdminClaim() - { - return this.getOwnerID() == null; - } - - //accessor for ID - public Long getID() - { - return this.id; - } - - //basic constructor, just notes the creation time - //see above declarations for other defaults - Claim() - { - this.modifiedDate = Calendar.getInstance().getTime(); - } - - //main constructor. note that only creating a claim instance does nothing - a claim must be added to the data store to be effective - Claim(Location lesserBoundaryCorner, Location greaterBoundaryCorner, UUID ownerID, List builderIDs, List containerIDs, List accessorIDs, List managerIDs, boolean inheritNothing, Long id) - { - //modification date - this.modifiedDate = Calendar.getInstance().getTime(); - - //id - this.id = id; - - //store corners - this.lesserBoundaryCorner = lesserBoundaryCorner; - this.greaterBoundaryCorner = greaterBoundaryCorner; - - //owner - this.ownerID = ownerID; - - //other permissions - for (String builderID : builderIDs) - { - this.setPermission(builderID, ClaimPermission.Build); - } - - for (String containerID : containerIDs) - { - this.setPermission(containerID, ClaimPermission.Inventory); - } - - for (String accessorID : accessorIDs) - { - this.setPermission(accessorID, ClaimPermission.Access); - } - - for (String managerID : managerIDs) - { - if (managerID != null && !managerID.isEmpty()) - { - this.managers.add(managerID); - } - } - - this.inheritNothing = inheritNothing; - } - - Claim(Location lesserBoundaryCorner, Location greaterBoundaryCorner, UUID ownerID, List builderIDs, List containerIDs, List accessorIDs, List managerIDs, Long id) - { - this(lesserBoundaryCorner, greaterBoundaryCorner, ownerID, builderIDs, containerIDs, accessorIDs, managerIDs, false, id); - } - - //produces a copy of a claim. - public Claim(Claim claim) { - this.modifiedDate = claim.modifiedDate; - this.lesserBoundaryCorner = claim.greaterBoundaryCorner.clone(); - this.greaterBoundaryCorner = claim.greaterBoundaryCorner.clone(); - this.id = claim.id; - this.ownerID = claim.ownerID; - this.managers = new ArrayList<>(claim.managers); - this.playerIDToClaimPermissionMap = new HashMap<>(claim.playerIDToClaimPermissionMap); - this.inDataStore = false; //since it's a copy of a claim, not in datastore! - this.areExplosivesAllowed = claim.areExplosivesAllowed; - this.parent = claim.parent; - this.inheritNothing = claim.inheritNothing; - this.children = new ArrayList<>(claim.children); - this.doorsOpen = claim.doorsOpen; - } - - //measurements. all measurements are in blocks - public int getArea() - { - int claimWidth = this.greaterBoundaryCorner.getBlockX() - this.lesserBoundaryCorner.getBlockX() + 1; - int claimHeight = this.greaterBoundaryCorner.getBlockZ() - this.lesserBoundaryCorner.getBlockZ() + 1; - - return claimWidth * claimHeight; - } - - public int getWidth() - { - return this.greaterBoundaryCorner.getBlockX() - this.lesserBoundaryCorner.getBlockX() + 1; - } - - public int getHeight() - { - return this.greaterBoundaryCorner.getBlockZ() - this.lesserBoundaryCorner.getBlockZ() + 1; - } - - public boolean getSubclaimRestrictions() - { - return inheritNothing; - } - - public void setSubclaimRestrictions(boolean inheritNothing) - { - this.inheritNothing = inheritNothing; - } - - //distance check for claims, distance in this case is a band around the outside of the claim rather then euclidean distance - public boolean isNear(Location location, int howNear) - { - Claim claim = new Claim - (new Location(this.lesserBoundaryCorner.getWorld(), this.lesserBoundaryCorner.getBlockX() - howNear, this.lesserBoundaryCorner.getBlockY(), this.lesserBoundaryCorner.getBlockZ() - howNear), - new Location(this.greaterBoundaryCorner.getWorld(), this.greaterBoundaryCorner.getBlockX() + howNear, this.greaterBoundaryCorner.getBlockY(), this.greaterBoundaryCorner.getBlockZ() + howNear), - null, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), null); - - return claim.contains(location, false, true); - } - - /** - * @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) - { - Supplier supplier = checkPermission(player, ClaimPermission.Edit, null); - return supplier != null ? supplier.get() : null; - } - - private static final Set PLACEABLE_FARMING_BLOCKS = EnumSet.of( - Material.PUMPKIN_STEM, - Material.WHEAT, - Material.MELON_STEM, - Material.CARROTS, - Material.POTATOES, - Material.NETHER_WART, - Material.BEETROOTS, - Material.COCOA, - Material.MELON, - Material.PUMPKIN, - Material.GLOW_BERRIES//, -// Material.CAVE_VINES, -// Material.CAVE_VINES_PLANT); - ); - - private static boolean placeableForFarming(Material material) - { - 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) - { - Supplier supplier = checkPermission(player, ClaimPermission.Build, new CompatBuildBreakEvent(material, false)); - return supplier != null ? supplier.get() : null; - } - - public static class CompatBuildBreakEvent extends Event - { - private final Material material; - private final boolean isBreak; - - private CompatBuildBreakEvent(Material material, boolean isBreak) - { - this.material = material; - this.isBreak = isBreak; - } - - public Material getMaterial() - { - return material; - } - - public boolean isBreak() - { - return isBreak; - } - - @Override - public HandlerList getHandlers() - { - return new HandlerList(); - } - - } - - 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())); - } - - public boolean hasExplicitPermission(Player player, ClaimPermission level) - { - // 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 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; - - // 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; - } - - /** - * 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 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 checkPermission(Player player, ClaimPermission permission, Event event, Supplier 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 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 callPermissionCheck(ClaimPermissionCheckEvent event, Supplier denialOverride) - { - // Set denial message (if any) using default behavior. - Supplier 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 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) - { - Supplier supplier = checkPermission(player, ClaimPermission.Build, new CompatBuildBreakEvent(material, true)); - return supplier != null ? supplier.get() : null; - } - - /** - * @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) - { - Supplier supplier = checkPermission(player, ClaimPermission.Access, null); - return supplier != null ? supplier.get() : null; - } - - /** - * @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) - { - Supplier supplier = checkPermission(player, ClaimPermission.Inventory, null); - return supplier != null ? supplier.get() : null; - } - - /** - * @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) - { - Supplier supplier = checkPermission(player, ClaimPermission.Manage, null); - return supplier != null ? supplier.get() : null; - } - - public ClaimPermission getPermission(String playerID) - { - if (playerID == null || playerID.isEmpty()) return null; - - return this.playerIDToClaimPermissionMap.get(playerID.toLowerCase()); - } - - //grants a permission for a player or the public - public void setPermission(String playerID, ClaimPermission permissionLevel) - { - if (permissionLevel == ClaimPermission.Edit) throw new IllegalArgumentException("Cannot add editors!"); - - 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) - { - playerID = playerID.toLowerCase(); - this.playerIDToClaimPermissionMap.remove(playerID); - this.managers.remove(playerID); - - for (Claim child : this.children) - { - child.dropPermission(playerID); - } - } - - //clears all permissions (except owner of course) - public void clearPermissions() - { - this.playerIDToClaimPermissionMap.clear(); - this.managers.clear(); - - for (Claim child : this.children) - { - child.clearPermissions(); - } - } - - //gets ALL permissions - //useful for making copies of permissions during a claim resize and listing all permissions in a claim - public void getPermissions(ArrayList builders, ArrayList containers, ArrayList accessors, ArrayList managers) - { - //loop through all the entries in the hash map - for (Map.Entry entry : this.playerIDToClaimPermissionMap.entrySet()) - { - //build up a list for each permission level - if (entry.getValue() == ClaimPermission.Build) - { - builders.add(entry.getKey()); - } - else if (entry.getValue() == ClaimPermission.Inventory) - { - containers.add(entry.getKey()); - } - else if (entry.getValue() == ClaimPermission.Access) - { - accessors.add(entry.getKey()); - } - } - - //managers are handled a little differently - managers.addAll(this.managers); - } - - public void getClaimNearbyPermission(ArrayList permissions) - { - //loop through all the entries in the hash map - for (Map.Entry entry : this.playerIDToClaimPermissionMap.entrySet()) - { - //build up a list for each permission level - if (entry.getValue() == ClaimPermission.Claim) - { - permissions.add(entry.getKey()); - } - } - } - //returns a copy of the location representing lower x, y, z limits - public Location getLesserBoundaryCorner() - { - return this.lesserBoundaryCorner.clone(); - } - - //returns a copy of the location representing upper x, y, z limits - //NOTE: remember upper Y will always be ignored, all claims always extend to the sky - public Location getGreaterBoundaryCorner() - { - return this.greaterBoundaryCorner.clone(); - } - - //returns a friendly owner name (for admin claims, returns "an administrator" as the owner) - public String getOwnerName() - { - if (this.parent != null) - return this.parent.getOwnerName(); - - if (this.ownerID == null) - return GriefPrevention.instance.dataStore.getMessage(Messages.OwnerNameForAdminClaims); - - return GriefPrevention.lookupPlayerName(this.ownerID); - } - - public UUID getOwnerID() - { - if (this.parent != null) - { - return this.parent.ownerID; - } - return this.ownerID; - } - - //whether or not a location is in a claim - //ignoreHeight = true means location UNDER the claim will return TRUE - //excludeSubdivisions = true means that locations inside subdivisions of the claim will return FALSE - public boolean contains(Location location, boolean ignoreHeight, boolean excludeSubdivisions) - { - //not in the same world implies false - if (!Objects.equals(location.getWorld(), this.lesserBoundaryCorner.getWorld())) return false; - - BoundingBox boundingBox = new BoundingBox(this); - int x = location.getBlockX(); - int z = location.getBlockZ(); - - // If we're ignoring height, use 2D containment check. - if (ignoreHeight && !boundingBox.contains2d(x, z)) - { - return false; - } - // Otherwise use full containment check. - else if (!ignoreHeight && !boundingBox.contains(x, location.getBlockY(), z)) - { - return false; - } - - //additional check for subdivisions - //you're only in a subdivision when you're also in its parent claim - //NOTE: if a player creates subdivions then resizes the parent claim, it's possible that - //a subdivision can reach outside of its parent's boundaries. so this check is important! - if (this.parent != null) - { - return this.parent.contains(location, ignoreHeight, false); - } - - //code to exclude subdivisions in this check - else if (excludeSubdivisions) - { - //search all subdivisions to see if the location is in any of them - for (Claim child : this.children) - { - //if we find such a subdivision, return false - if (child.contains(location, ignoreHeight, true)) - { - return false; - } - } - } - - //otherwise yes - return true; - } - - //whether or not two claims overlap - //used internally to prevent overlaps when creating claims - boolean overlaps(Claim otherClaim) - { - if (!Objects.equals(this.lesserBoundaryCorner.getWorld(), otherClaim.getLesserBoundaryCorner().getWorld())) return false; - - return new BoundingBox(this).intersects(new BoundingBox(otherClaim)); - } - - //implements a strict ordering of claims, used to keep the claims collection sorted for faster searching - boolean greaterThan(Claim otherClaim) - { - Location thisCorner = this.getLesserBoundaryCorner(); - Location otherCorner = otherClaim.getLesserBoundaryCorner(); - - if (thisCorner.getBlockX() > otherCorner.getBlockX()) return true; - - if (thisCorner.getBlockX() < otherCorner.getBlockX()) return false; - - if (thisCorner.getBlockZ() > otherCorner.getBlockZ()) return true; - - if (thisCorner.getBlockZ() < otherCorner.getBlockZ()) return false; - - return thisCorner.getWorld().getName().compareTo(otherCorner.getWorld().getName()) < 0; - } - - public ArrayList getChunks() - { - ArrayList chunks = new ArrayList<>(); - - World world = this.getLesserBoundaryCorner().getWorld(); - Chunk lesserChunk = this.getLesserBoundaryCorner().getChunk(); - Chunk greaterChunk = this.getGreaterBoundaryCorner().getChunk(); - - for (int x = lesserChunk.getX(); x <= greaterChunk.getX(); x++) - { - for (int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); z++) - { - chunks.add(world.getChunkAt(x, z)); - } - } - - return chunks; - } - - ArrayList getChunkHashes() - { - return DataStore.getChunkHashes(this); - } - - public boolean canCleaimNear(Player player, int howNear) { - Location location = player.getLocation(); - Claim claim = new Claim - (new Location(this.lesserBoundaryCorner.getWorld(), this.lesserBoundaryCorner.getBlockX() - howNear, this.lesserBoundaryCorner.getBlockY(), this.lesserBoundaryCorner.getBlockZ() - howNear), - new Location(this.greaterBoundaryCorner.getWorld(), this.greaterBoundaryCorner.getBlockX() + howNear, this.greaterBoundaryCorner.getBlockY(), this.greaterBoundaryCorner.getBlockZ() + howNear), - null, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), null); - -// if(!claim.contains(location, false, true)) return true; - ArrayList claims = GriefPrevention.instance.dataStore.claims; - for (Claim claim2 : claims) { - if(claim2.parent != null) continue; - if(!claim2.overlaps(claim)) continue; - - Supplier canClaimTrust = claim2.checkPermission(player, ClaimPermission.Claim, null); - if (canClaimTrust == null) continue; - - player.sendMiniMessage("You can't claim this close to " + claim2.getOwnerName() + "'s claim.", null); // TODO MINIMESSAG + CONFIG - return false; - } - return true; - } - - public boolean isInsideBorder() { - WorldBorder worldBorder = this.getLesserBoundaryCorner().getWorld().getWorldBorder(); - return worldBorder.isInside(this.lesserBoundaryCorner) && worldBorder.isInside(this.greaterBoundaryCorner); - } - -} +/* + GriefPrevention Server Plugin for Minecraft + Copyright (C) 2012 Ryan Hamshire + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +package me.ryanhamshire.GriefPrevention; + +import me.ryanhamshire.GriefPrevention.alttd.config.Config; +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; +import org.bukkit.World; +import org.bukkit.WorldBorder; +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; +import java.util.Date; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +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 +//only claims which have been added to the datastore have any effect +public class Claim +{ + //two locations, which together define the boundaries of the claim + //note that the upper Y value is always ignored, because claims ALWAYS extend up to the sky + Location lesserBoundaryCorner; + Location greaterBoundaryCorner; + + //modification date. this comes from the file timestamp during load, and is updated with runtime changes + public Date modifiedDate; + + //id number. unique to this claim, never changes. + Long id = null; + + //ownerID. for admin claims, this is NULL + //use getOwnerName() to get a friendly name (will be "an administrator" for admin claims) + public UUID ownerID; + + //list of players who (beyond the claim owner) have permission to grant permissions in this claim + public ArrayList managers = new ArrayList<>(); + + //permissions for this claim, see ClaimPermission class + private HashMap playerIDToClaimPermissionMap = new HashMap<>(); + + //whether or not this claim is in the data store + //if a claim instance isn't in the data store, it isn't "active" - players can't interract with it + //why keep this? so that claims which have been removed from the data store can be correctly + //ignored even though they may have references floating around + public boolean inDataStore = false; + + public boolean areExplosivesAllowed = false; + + //parent claim + //only used for claim subdivisions. top level claims have null here + public Claim parent = null; + + // intended for subclaims - they inherit no permissions + private boolean inheritNothing = false; + + //children (subdivisions) + //note subdivisions themselves never have children + public ArrayList children = new ArrayList<>(); + + //following a siege, buttons/levers are unlocked temporarily. this represents that state + public boolean doorsOpen = false; + + //whether or not this is an administrative claim + //administrative claims are created and maintained by players with the griefprevention.adminclaims permission. + public boolean isAdminClaim() + { + return this.getOwnerID() == null; + } + + //accessor for ID + public Long getID() + { + return this.id; + } + + //basic constructor, just notes the creation time + //see above declarations for other defaults + Claim() + { + this.modifiedDate = Calendar.getInstance().getTime(); + } + + //main constructor. note that only creating a claim instance does nothing - a claim must be added to the data store to be effective + Claim(Location lesserBoundaryCorner, Location greaterBoundaryCorner, UUID ownerID, List builderIDs, List containerIDs, List accessorIDs, List managerIDs, boolean inheritNothing, Long id) + { + //modification date + this.modifiedDate = Calendar.getInstance().getTime(); + + //id + this.id = id; + + //store corners + this.lesserBoundaryCorner = lesserBoundaryCorner; + this.greaterBoundaryCorner = greaterBoundaryCorner; + + //owner + this.ownerID = ownerID; + + //other permissions + for (String builderID : builderIDs) + { + this.setPermission(builderID, ClaimPermission.Build); + } + + for (String containerID : containerIDs) + { + this.setPermission(containerID, ClaimPermission.Inventory); + } + + for (String accessorID : accessorIDs) + { + this.setPermission(accessorID, ClaimPermission.Access); + } + + for (String managerID : managerIDs) + { + if (managerID != null && !managerID.isEmpty()) + { + this.managers.add(managerID); + } + } + + this.inheritNothing = inheritNothing; + } + + Claim(Location lesserBoundaryCorner, Location greaterBoundaryCorner, UUID ownerID, List builderIDs, List containerIDs, List accessorIDs, List managerIDs, Long id) + { + this(lesserBoundaryCorner, greaterBoundaryCorner, ownerID, builderIDs, containerIDs, accessorIDs, managerIDs, false, id); + } + + //produces a copy of a claim. + public Claim(Claim claim) { + this.modifiedDate = claim.modifiedDate; + this.lesserBoundaryCorner = claim.greaterBoundaryCorner.clone(); + this.greaterBoundaryCorner = claim.greaterBoundaryCorner.clone(); + this.id = claim.id; + this.ownerID = claim.ownerID; + this.managers = new ArrayList<>(claim.managers); + this.playerIDToClaimPermissionMap = new HashMap<>(claim.playerIDToClaimPermissionMap); + this.inDataStore = false; //since it's a copy of a claim, not in datastore! + this.areExplosivesAllowed = claim.areExplosivesAllowed; + this.parent = claim.parent; + this.inheritNothing = claim.inheritNothing; + this.children = new ArrayList<>(claim.children); + this.doorsOpen = claim.doorsOpen; + } + + //measurements. all measurements are in blocks + public int getArea() + { + int claimWidth = this.greaterBoundaryCorner.getBlockX() - this.lesserBoundaryCorner.getBlockX() + 1; + int claimHeight = this.greaterBoundaryCorner.getBlockZ() - this.lesserBoundaryCorner.getBlockZ() + 1; + + return claimWidth * claimHeight; + } + + public int getWidth() + { + return this.greaterBoundaryCorner.getBlockX() - this.lesserBoundaryCorner.getBlockX() + 1; + } + + public int getHeight() + { + return this.greaterBoundaryCorner.getBlockZ() - this.lesserBoundaryCorner.getBlockZ() + 1; + } + + public boolean getSubclaimRestrictions() + { + return inheritNothing; + } + + public void setSubclaimRestrictions(boolean inheritNothing) + { + this.inheritNothing = inheritNothing; + } + + //distance check for claims, distance in this case is a band around the outside of the claim rather then euclidean distance + public boolean isNear(Location location, int howNear) + { + Claim claim = new Claim + (new Location(this.lesserBoundaryCorner.getWorld(), this.lesserBoundaryCorner.getBlockX() - howNear, this.lesserBoundaryCorner.getBlockY(), this.lesserBoundaryCorner.getBlockZ() - howNear), + new Location(this.greaterBoundaryCorner.getWorld(), this.greaterBoundaryCorner.getBlockX() + howNear, this.greaterBoundaryCorner.getBlockY(), this.greaterBoundaryCorner.getBlockZ() + howNear), + null, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), null); + + return claim.contains(location, false, true); + } + + /** + * @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) + { + Supplier supplier = checkPermission(player, ClaimPermission.Edit, null); + return supplier != null ? supplier.get() : null; + } + + private static final Set PLACEABLE_FARMING_BLOCKS = EnumSet.of( + Material.PUMPKIN_STEM, + Material.WHEAT, + Material.MELON_STEM, + Material.CARROTS, + Material.POTATOES, + Material.NETHER_WART, + Material.BEETROOTS, + Material.COCOA, + Material.MELON, + Material.PUMPKIN, + Material.GLOW_BERRIES//, +// Material.CAVE_VINES, +// Material.CAVE_VINES_PLANT); + ); + + private static boolean placeableForFarming(Material material) + { + 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) + { + Supplier supplier = checkPermission(player, ClaimPermission.Build, new CompatBuildBreakEvent(material, false)); + return supplier != null ? supplier.get() : null; + } + + public static class CompatBuildBreakEvent extends Event + { + private final Material material; + private final boolean isBreak; + + private CompatBuildBreakEvent(Material material, boolean isBreak) + { + this.material = material; + this.isBreak = isBreak; + } + + public Material getMaterial() + { + return material; + } + + public boolean isBreak() + { + return isBreak; + } + + @Override + public HandlerList getHandlers() + { + return new HandlerList(); + } + + } + + 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())); + } + + public boolean hasExplicitPermission(Player player, ClaimPermission level) + { + // 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 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; + + // 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; + } + + /** + * 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 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 checkPermission(Player player, ClaimPermission permission, Event event, Supplier 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 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 callPermissionCheck(ClaimPermissionCheckEvent event, Supplier denialOverride) + { + // Set denial message (if any) using default behavior. + Supplier 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 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) + { + Supplier supplier = checkPermission(player, ClaimPermission.Build, new CompatBuildBreakEvent(material, true)); + return supplier != null ? supplier.get() : null; + } + + /** + * @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) + { + Supplier supplier = checkPermission(player, ClaimPermission.Access, null); + return supplier != null ? supplier.get() : null; + } + + /** + * @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) + { + Supplier supplier = checkPermission(player, ClaimPermission.Inventory, null); + return supplier != null ? supplier.get() : null; + } + + /** + * @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) + { + Supplier supplier = checkPermission(player, ClaimPermission.Manage, null); + return supplier != null ? supplier.get() : null; + } + + public ClaimPermission getPermission(String playerID) + { + if (playerID == null || playerID.isEmpty()) return null; + + return this.playerIDToClaimPermissionMap.get(playerID.toLowerCase()); + } + + //grants a permission for a player or the public + public void setPermission(String playerID, ClaimPermission permissionLevel) + { + if (permissionLevel == ClaimPermission.Edit) throw new IllegalArgumentException("Cannot add editors!"); + + 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) + { + playerID = playerID.toLowerCase(); + this.playerIDToClaimPermissionMap.remove(playerID); + this.managers.remove(playerID); + + for (Claim child : this.children) + { + child.dropPermission(playerID); + } + } + + //clears all permissions (except owner of course) + public void clearPermissions() + { + this.playerIDToClaimPermissionMap.clear(); + this.managers.clear(); + + for (Claim child : this.children) + { + child.clearPermissions(); + } + } + + //gets ALL permissions + //useful for making copies of permissions during a claim resize and listing all permissions in a claim + public void getPermissions(ArrayList builders, ArrayList containers, ArrayList accessors, ArrayList managers) + { + //loop through all the entries in the hash map + for (Map.Entry entry : this.playerIDToClaimPermissionMap.entrySet()) + { + //build up a list for each permission level + if (entry.getValue() == ClaimPermission.Build) + { + builders.add(entry.getKey()); + } + else if (entry.getValue() == ClaimPermission.Inventory) + { + containers.add(entry.getKey()); + } + else if (entry.getValue() == ClaimPermission.Access) + { + accessors.add(entry.getKey()); + } + } + + //managers are handled a little differently + managers.addAll(this.managers); + } + + public void getClaimNearbyPermission(ArrayList permissions) + { + //loop through all the entries in the hash map + for (Map.Entry entry : this.playerIDToClaimPermissionMap.entrySet()) + { + //build up a list for each permission level + if (entry.getValue() == ClaimPermission.Claim) + { + permissions.add(entry.getKey()); + } + } + } + //returns a copy of the location representing lower x, y, z limits + public Location getLesserBoundaryCorner() + { + return this.lesserBoundaryCorner.clone(); + } + + //returns a copy of the location representing upper x, y, z limits + //NOTE: remember upper Y will always be ignored, all claims always extend to the sky + public Location getGreaterBoundaryCorner() + { + return this.greaterBoundaryCorner.clone(); + } + + //returns a friendly owner name (for admin claims, returns "an administrator" as the owner) + public String getOwnerName() + { + if (this.parent != null) + return this.parent.getOwnerName(); + + if (this.ownerID == null) + return GriefPrevention.instance.dataStore.getMessage(Messages.OwnerNameForAdminClaims); + + return GriefPrevention.lookupPlayerName(this.ownerID); + } + + public UUID getOwnerID() + { + if (this.parent != null) + { + return this.parent.ownerID; + } + return this.ownerID; + } + + //whether or not a location is in a claim + //ignoreHeight = true means location UNDER the claim will return TRUE + //excludeSubdivisions = true means that locations inside subdivisions of the claim will return FALSE + public boolean contains(Location location, boolean ignoreHeight, boolean excludeSubdivisions) + { + //not in the same world implies false + if (!Objects.equals(location.getWorld(), this.lesserBoundaryCorner.getWorld())) return false; + + BoundingBox boundingBox = new BoundingBox(this); + int x = location.getBlockX(); + int z = location.getBlockZ(); + + // If we're ignoring height, use 2D containment check. + if (ignoreHeight && !boundingBox.contains2d(x, z)) + { + return false; + } + // Otherwise use full containment check. + else if (!ignoreHeight && !boundingBox.contains(x, location.getBlockY(), z)) + { + return false; + } + + //additional check for subdivisions + //you're only in a subdivision when you're also in its parent claim + //NOTE: if a player creates subdivions then resizes the parent claim, it's possible that + //a subdivision can reach outside of its parent's boundaries. so this check is important! + if (this.parent != null) + { + return this.parent.contains(location, ignoreHeight, false); + } + + //code to exclude subdivisions in this check + else if (excludeSubdivisions) + { + //search all subdivisions to see if the location is in any of them + for (Claim child : this.children) + { + //if we find such a subdivision, return false + if (child.contains(location, ignoreHeight, true)) + { + return false; + } + } + } + + //otherwise yes + return true; + } + + //whether or not two claims overlap + //used internally to prevent overlaps when creating claims + boolean overlaps(Claim otherClaim) + { + if (!Objects.equals(this.lesserBoundaryCorner.getWorld(), otherClaim.getLesserBoundaryCorner().getWorld())) return false; + + return new BoundingBox(this).intersects(new BoundingBox(otherClaim)); + } + + //implements a strict ordering of claims, used to keep the claims collection sorted for faster searching + boolean greaterThan(Claim otherClaim) + { + Location thisCorner = this.getLesserBoundaryCorner(); + Location otherCorner = otherClaim.getLesserBoundaryCorner(); + + if (thisCorner.getBlockX() > otherCorner.getBlockX()) return true; + + if (thisCorner.getBlockX() < otherCorner.getBlockX()) return false; + + if (thisCorner.getBlockZ() > otherCorner.getBlockZ()) return true; + + if (thisCorner.getBlockZ() < otherCorner.getBlockZ()) return false; + + return thisCorner.getWorld().getName().compareTo(otherCorner.getWorld().getName()) < 0; + } + + public ArrayList getChunks() + { + ArrayList chunks = new ArrayList<>(); + + World world = this.getLesserBoundaryCorner().getWorld(); + Chunk lesserChunk = this.getLesserBoundaryCorner().getChunk(); + Chunk greaterChunk = this.getGreaterBoundaryCorner().getChunk(); + + for (int x = lesserChunk.getX(); x <= greaterChunk.getX(); x++) + { + for (int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); z++) + { + chunks.add(world.getChunkAt(x, z)); + } + } + + return chunks; + } + + ArrayList getChunkHashes() + { + return DataStore.getChunkHashes(this); + } + + public boolean canClaimNear(Player player, int howNear) { + Location location = player.getLocation(); + Claim claim = new Claim + (new Location(this.lesserBoundaryCorner.getWorld(), this.lesserBoundaryCorner.getBlockX() - howNear, this.lesserBoundaryCorner.getBlockY(), this.lesserBoundaryCorner.getBlockZ() - howNear), + new Location(this.greaterBoundaryCorner.getWorld(), this.greaterBoundaryCorner.getBlockX() + howNear, this.greaterBoundaryCorner.getBlockY(), this.greaterBoundaryCorner.getBlockZ() + howNear), + null, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), null); + +// if(!claim.contains(location, false, true)) return true; + ArrayList claims = GriefPrevention.instance.dataStore.claims; + for (Claim claim2 : claims) { + if (claim2.isAdminClaim()) { + player.sendMiniMessage(Config.claimNearAdminClaim, null); + return false; + } + if(claim2.parent != null) continue; + if(!claim2.overlaps(claim)) continue; + + Supplier canClaimTrust = claim2.checkPermission(player, ClaimPermission.Claim, null); + if (canClaimTrust == null) continue; + + player.sendMiniMessage("You can't claim this close to " + claim2.getOwnerName() + "'s claim.", null); // TODO placeholders + return false; + } + return true; + } + + public boolean isInsideBorder() { + WorldBorder worldBorder = this.getLesserBoundaryCorner().getWorld().getWorldBorder(); + return worldBorder.isInside(this.lesserBoundaryCorner) && worldBorder.isInside(this.greaterBoundaryCorner); + } + +} diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java b/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java index 387381b..fec095e 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java @@ -26,10 +26,8 @@ import me.ryanhamshire.GriefPrevention.events.ClaimDeletedEvent; import me.ryanhamshire.GriefPrevention.events.ClaimExtendEvent; import me.ryanhamshire.GriefPrevention.events.ClaimTransferEvent; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.Chunk; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.configuration.file.FileConfiguration; @@ -39,7 +37,6 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Tameable; import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -49,7 +46,6 @@ import java.io.FileWriter; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; -import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -975,7 +971,7 @@ public abstract class DataStore } } - if (creatingPlayer != null && !newClaim.canCleaimNear(creatingPlayer, 100) && newClaim.parent == null) { + if (creatingPlayer != null && !newClaim.canClaimNear(creatingPlayer, 100) && newClaim.parent == null) { result.succeeded = false; result.claim = null; return result; diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/alttd/config/Config.java b/src/main/java/me/ryanhamshire/GriefPrevention/alttd/config/Config.java index 3e008ed..ef46e2a 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/alttd/config/Config.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/alttd/config/Config.java @@ -1,204 +1,208 @@ -package me.ryanhamshire.GriefPrevention.alttd.config; - -import me.ryanhamshire.GriefPrevention.alttd.util.Logger; - -import java.awt.*; -import java.io.IOException; -import java.util.HashMap; -import java.util.concurrent.TimeUnit; - -@SuppressWarnings("unused") -public class Config extends AbstractConfig { - - private Config() { - super("alttdconfig.yml"); - } - - static Config config; - static int version; - - public static void reload() { - config = new Config(); - - version = config.getInt("config-version", 1); - config.set("config-version", 1); - - config.readConfig(Config.class, null); - } - - public static boolean DEBUG_MODE = false; - public static boolean alternativeClaimExpiring = false; - public static int alternativeClaimExpireDays = 1; - public static int adminClaimExpireCheckRate = 1200; - public static int playerClaimExpireCheckRate = 1200; - public static HashMap expiringClaims = new HashMap<>(); - private static void settings() { - String node = "alternative-claim-expiring"; - DEBUG_MODE = config.getBoolean("debug-mode", DEBUG_MODE); - alternativeClaimExpiring = config.getBoolean(node + ".enabled", alternativeClaimExpiring); - alternativeClaimExpireDays = config.getInt(node + ".days", alternativeClaimExpireDays); - adminClaimExpireCheckRate = config.getInt(node + ".admin-claim-expire-check-rate", adminClaimExpireCheckRate); - playerClaimExpireCheckRate = config.getInt(node + ".player-claim-expire-check-rate", playerClaimExpireCheckRate); - // todo create an alternative way of loading these in - expiringClaims.clear(); - config.getMap(node + ".claims", new HashMap()) - .forEach((key, value) -> { - try { - expiringClaims.put(Long.parseLong(key), value); - } catch (NumberFormatException ignored) {} - }); - } - - public static void addExpiringClaim(Long id) { - expiringClaims.put(id, System.currentTimeMillis() + TimeUnit.DAYS.toMillis(alternativeClaimExpireDays)); - config.set("alternative-claim-expiring.claims", expiringClaims); - try { - config.yaml.save(config.file); - } catch (IOException ex) { - Logger.severe("Could not save " + config.file.getName()); - ex.printStackTrace(); - } - } - - public static String CONTROL_LABEL = "GriefPrevention"; - public static boolean CONTROL_SHOW = true; - public static boolean CONTROL_HIDE = false; - public static String GRID_CONTROL_LABEL = "Gridlines"; - public static boolean GRID_CONTROL_SHOW = true; - public static boolean GRID_CONTROL_HIDE = true; - public static int UPDATE_INTERVAL = 300; - public static Color STROKE_COLOR = Color.GREEN; - public static int STROKE_WEIGHT = 1; - public static double STROKE_OPACITY = 1.0D; - public static Color FILL_COLOR = Color.GREEN; - public static double FILL_OPACITY = 0.2D; - - public static Color ADMIN_STROKE_COLOR = Color.BLUE; - public static int ADMIN_STROKE_WEIGHT = 1; - public static double ADMIN_STROKE_OPACITY = 1.0D; - public static Color ADMIN_FILL_COLOR = Color.BLUE; - public static double ADMIN_FILL_OPACITY = 0.2D; - - public static Color EXPIRING_STROKE_COLOR = Color.PINK; - public static int EXPIRING_STROKE_WEIGHT = 1; - public static double EXPIRING_STROKE_OPACITY = 1.0D; - public static Color EXPIRING_FILL_COLOR = Color.PINK; - public static double EXPIRING_FILL_OPACITY = 0.2D; - - public static String STRINGS_PUBLIC = "Public"; - public static String CLAIM_TOOLTIP = "Claim Owner: {owner}
" + - "Permission Trust: {managers}
" + - "Trust: {builders}
" + - "Container Trust: {containers}
" + - "Access Trust: {accessors}"; - public static String ADMIN_CLAIM_TOOLTIP = "Administrator Claim
" + - "Permission Trust: {managers}
" + - "Trust: {builders}
" + - "Container Trust: {containers}
" + - "Access Trust: {accessors}"; - public static String EXPIRING_CLAIM_TOOLTIP = "Temporary Claim
" + - "Permission Trust: {managers}
" + - "Trust: {builders}
" + - "Container Trust: {containers}
" + - "Access Trust: {accessors}
" + - "Expires: {expiretime}" ; - private static void mapSettings() { - CONTROL_LABEL = config.getString("settings.control.label", CONTROL_LABEL); - CONTROL_SHOW = config.getBoolean("settings.control.show", CONTROL_SHOW); - CONTROL_HIDE = config.getBoolean("settings.control.hide-by-default", CONTROL_HIDE); - GRID_CONTROL_LABEL = config.getString("settings.grid.label", GRID_CONTROL_LABEL); - GRID_CONTROL_SHOW = config.getBoolean("settings.grid.show", GRID_CONTROL_SHOW); - GRID_CONTROL_HIDE = config.getBoolean("settings.grid.hide-by-default", GRID_CONTROL_HIDE); - UPDATE_INTERVAL = config.getInt("settings.update-interval", UPDATE_INTERVAL); - - STROKE_COLOR = config.getColor("settings.style.regular-claim.stroke.color", STROKE_COLOR); - STROKE_WEIGHT = config.getInt("settings.style.regular-claim.stroke.weight", STROKE_WEIGHT); - STROKE_OPACITY = config.getDouble("settings.regular-claim.style.stroke.opacity", STROKE_OPACITY); - FILL_COLOR = config.getColor("settings.style.regular-claim.fill.color", FILL_COLOR); - FILL_OPACITY = config.getDouble("settings.style.regular-claim.fill.opacity", FILL_OPACITY); - - ADMIN_STROKE_COLOR = config.getColor("settings.style.admin-claim.stroke.color", ADMIN_STROKE_COLOR); - ADMIN_STROKE_WEIGHT = config.getInt("settings.style.admin-claim.stroke.weight", ADMIN_STROKE_WEIGHT); - ADMIN_STROKE_OPACITY = config.getDouble("settings.admin-claim.style.stroke.opacity", ADMIN_STROKE_OPACITY); - ADMIN_FILL_COLOR = config.getColor("settings.style.admin-claim.fill.color", ADMIN_FILL_COLOR); - ADMIN_FILL_OPACITY = config.getDouble("settings.style.admin-claim.fill.opacity", ADMIN_FILL_OPACITY); - - EXPIRING_STROKE_COLOR = config.getColor("settings.style.expiring-claim.stroke.color", EXPIRING_STROKE_COLOR); - EXPIRING_STROKE_WEIGHT = config.getInt("settings.style.expiring-claim.stroke.weight", EXPIRING_STROKE_WEIGHT); - EXPIRING_STROKE_OPACITY = config.getDouble("settings.expiring-claim.style.stroke.opacity", EXPIRING_STROKE_OPACITY); - EXPIRING_FILL_COLOR = config.getColor("settings.style.expiring-claim.fill.color", EXPIRING_FILL_COLOR); - EXPIRING_FILL_OPACITY = config.getDouble("settings.style.expiring-claim.fill.opacity", EXPIRING_FILL_OPACITY); - - STRINGS_PUBLIC = config.getString("settings.strings.public", STRINGS_PUBLIC); - CLAIM_TOOLTIP = config.getString("settings.region.tooltip.regular-claim", CLAIM_TOOLTIP); - ADMIN_CLAIM_TOOLTIP = config.getString("settings.region.tooltip.admin-claim", ADMIN_CLAIM_TOOLTIP); - EXPIRING_CLAIM_TOOLTIP = config.getString("settings.region.tooltip.expiring-claim", EXPIRING_CLAIM_TOOLTIP); - } - - public static int ignoreClaimWarningDelay = 20 * 600; - public static String ignoreClaimWarningMessage = " has had ignore claims on for