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