diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java index f6877cd..139831f 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -25,6 +25,7 @@ import me.ryanhamshire.GriefPrevention.alttd.hook.Pl3xMapHook; import me.ryanhamshire.GriefPrevention.alttd.listeners.AltitudeListener; import me.ryanhamshire.GriefPrevention.alttd.tasks.AdminClaimExpireTask; import me.ryanhamshire.GriefPrevention.alttd.tasks.IgnoreClaimWarningTask; +import me.ryanhamshire.GriefPrevention.alttd.util.SafeZone; import me.ryanhamshire.GriefPrevention.events.PreventBlockBreakEvent; import me.ryanhamshire.GriefPrevention.events.SaveTrappedPlayerEvent; import me.ryanhamshire.GriefPrevention.events.TrustChangedEvent; @@ -55,6 +56,7 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; @@ -2460,6 +2462,49 @@ public class GriefPrevention extends JavaPlugin return true; } + // kickfromclaim + else if (cmd.getName().equalsIgnoreCase("kickfromclaim") && player != null) + { + if (args.length < 1) { + player.sendMiniMessage(Config.PlayerNotSpecified, null); // todo placeholders. + return true; + } + Player target = Bukkit.getPlayer(args[0]); + if (target == null) { + player.sendMiniMessage(Config.PlayerOffline, null); // todo placeholders. + return true; + } + if (player.equals(target)) { + player.sendMiniMessage(Config.CannotKickSelf, null); // todo placeholders. + return true; + } + Claim claim = this.dataStore.getClaimAt(target.getLocation(), true, null); + if (claim == null || (claim.checkPermission(player, ClaimPermission.Manage, null) != null)) { + player.sendMiniMessage(Config.TargetNotInClaim, null); // todo placeholders. + return true; + } + SafeZone zone = new SafeZone(claim); + if ((target.hasPermission("griefprevention.adminclaims") && claim.isAdminClaim()) || zone + .hasTrust(target.getUniqueId())) { + player.sendMiniMessage(Config.CannotKickTrustedTarget, null); // todo placeholders. + return true; + } + if (target.hasPermission("griefprevention.kickfromclaimexempt")) { + player.sendMiniMessage(Config.CannotKickExemptTarget, null); // todo placeholders. + return true; + } + zone.testForSafeSpot(); + Location safe = zone.getSafeArea(); + if (safe == null) { + player.sendMiniMessage(Config.NoSafeLocation, null); // todo placeholders. + } else { + target.teleport(safe); + Bukkit.getPluginManager().callEvent(new PlayerTeleportEvent(target, safe, safe)); + player.sendMiniMessage(Config.KickSuccess, null); // todo placeholders. + target.sendMiniMessage(Config.KickedFromClaim, null); // todo placeholders. + } + return true; + } return false; } 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 e9f3fec..de3e2f7 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/alttd/config/Config.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/alttd/config/Config.java @@ -175,4 +175,25 @@ public class Config extends AbstractConfig { PASSWORD = config.getString("database.password", PASSWORD); } + public static String PlayerNotSpecified = "&cYou must specify a player. &7/{COMMAND} "; + public static String PlayerOffline = "&cThere isn't anyone online with &f\"{INPUT}\" &cin their name!"; + public static String CannotKickSelf = "&cYou cannot kick yourself!"; + public static String TargetNotInClaim = "&c{TARGET} is not inside of any claims that you control!"; + public static String CannotKickTrustedTarget = "&c{TARGET} has trust in the claims they're in, therefore they cannot be kicked!"; + public static String CannotKickExemptTarget = "&c{TARGET} cannot be kicked from claims."; + public static String KickSuccess = "&a{TARGET} was successfully kicked from the claim!"; + public static String NoSafeLocation = "&cKick Unsuccessful... No Safe Location Available!"; // send to spawn? + public static String KickedFromClaim = "{PLAYER} &ehas kicked you out of {CLAIM_OWNER}'s claim!"; + private static void kickFromClaimMessages() { + PlayerNotSpecified = config.getString("kickfromclaim.PlayerNotSpecified", PlayerNotSpecified); + PlayerOffline = config.getString("kickfromclaim.PlayerOffline", PlayerOffline); + CannotKickSelf = config.getString("kickfromclaim.CannotKickSelf", CannotKickSelf); + TargetNotInClaim = config.getString("kickfromclaim.TargetNotInClaim", TargetNotInClaim); + CannotKickTrustedTarget = config.getString("kickfromclaim.CannotKickTrustedTarget", CannotKickTrustedTarget); + CannotKickExemptTarget = config.getString("kickfromclaim.CannotKickExemptTarget", CannotKickExemptTarget); + KickSuccess = config.getString("kickfromclaim.KickSuccess", KickSuccess); + NoSafeLocation = config.getString("kickfromclaim.NoSafeLocation", NoSafeLocation); + KickedFromClaim = config.getString("kickfromclaim.KickedFromClaim", KickedFromClaim); + } + } diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/alttd/util/SafeZone.java b/src/main/java/me/ryanhamshire/GriefPrevention/alttd/util/SafeZone.java new file mode 100644 index 0000000..b068d7d --- /dev/null +++ b/src/main/java/me/ryanhamshire/GriefPrevention/alttd/util/SafeZone.java @@ -0,0 +1,133 @@ +package me.ryanhamshire.GriefPrevention.alttd.util; + +import java.util.ArrayList; +import java.util.UUID; +import me.ryanhamshire.GriefPrevention.Claim; +import me.ryanhamshire.GriefPrevention.DataStore; +import me.ryanhamshire.GriefPrevention.GriefPrevention; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.WorldBorder; + +public class SafeZone +{ + private static final DataStore ds = GriefPrevention.instance.dataStore; + + private static final int MARGIN = 75; + + private final Claim base; + + private Location safeSpot = null; + + public SafeZone(Claim claim) + { + this.base = claim; + } + + public void testForSafeSpot() + { + this.safeSpot = null; + Location lesser = this.base.getLesserBoundaryCorner(), greater = this.base.getGreaterBoundaryCorner(); + World world = greater.getWorld(); + int minx = lesser.getBlockX(), minz = lesser.getBlockZ(); + int maxx = greater.getBlockX(), maxz = greater.getBlockZ(); + WorldBorder worldBorder = world.getWorldBorder(); + for (int x = minx - MARGIN; x < maxx + MARGIN; x++) + { + for (int z = minz - MARGIN; z < maxz + MARGIN; z++) + { + if (!inside(x, z, minx, minz, maxx, maxz)) + { + int y = world.getMaxHeight() - 2; + Location loc = new Location(world, x, y, z); + if (worldBorder.isInside(loc)) + while (y > 0) { + Material type = world.getBlockAt(x, y - 1, z).getType(); + if (!isSolid(type) || + !hasAir(world, x, y, z) || + !safeSurrounds(world, x, y, z)) + { + loc.setY(y--); + continue; + } + this.safeSpot = loc.add(0.5D, 0.0D, 0.5D); + return; + } + } + } + } + } + + private boolean safeSurrounds(World world, int xcoord, int ycoord, int zcoord) + { + int xmin = xcoord - 1, xmax = xcoord + 1, zmin = zcoord - 1, zmax = zcoord + 1; + for (int y = ycoord - 1; y <= ycoord + 2; y++) + { + for (int x = xmin; x <= xmax; x++) + { + for (int z = zmin; z <= zmax; z++) + { + if (x != xcoord || z != zcoord) + { + Material type = world.getBlockAt(x, y, z).getType(); + switch (type) { + case LAVA: + case WATER: + case SWEET_BERRY_BUSH: + case CAMPFIRE: + case MAGMA_BLOCK: + case FIRE: + case FIRE_CHARGE: + case CACTUS: + return false; + } + } + } + } + } + return true; + } + + private boolean isSolid(Material type) { + if (!type.isSolid()) + return false; + switch (type) { + case CAMPFIRE: + case MAGMA_BLOCK: + case CACTUS: + return false; + } + return true; + } + + private boolean hasAir(World world, int x, int y, int z) { + for (int i = 0; i <= 2; ) { + if (world.getBlockAt(x, y + i, z).getType() != Material.AIR) + return false; + i++; + } + return true; + } + + private boolean inside(int x, int z, int minx, int minz, int maxx, int maxz) { + return (x >= minx && x <= maxx && z >= minz && z <= maxz); + } + + public Location getSafeArea() { + return this.safeSpot; + } + + public boolean hasTrust(UUID uniqueId) { + if ((ds.getPlayerData(uniqueId)).ignoreClaims) + return true; + if (!this.base.isAdminClaim()) { + UUID ownerID = (this.base.parent != null) ? this.base.parent.ownerID : this.base.ownerID; + if (ownerID.equals(uniqueId)) + return true; + } + ArrayList perms = new ArrayList<>(); + this.base.getPermissions(perms, perms, perms, perms); + return perms.contains(uniqueId.toString()); + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 7f332b0..cd0ce07 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -201,14 +201,19 @@ commands: description: Gives a player a manual about claiming land. usage: /ClaimBook permission: griefprevention.claimbook + kickfromclaim: + description: Kick players out of your claim! + usage: / + aliases: [kfc] + permission: griefprevention.kickfromclaim permissions: - griefprevention.createclaims: + griefprevention.createclaims: description: Grants permission to create claims. default: true griefprevention.admin.*: description: Grants all administrative functionality. children: - griefprevention.restorenature: true + griefprevention.restorenature: true griefprevention.restorenatureaggressive: true griefprevention.ignoreclaims: true griefprevention.adminclaims: true @@ -234,7 +239,10 @@ permissions: griefprevention.siegeteleport: true griefprevention.unlockothersdrops: true griefprevention.seeclaimsize: true - griefprevention.siegeimmune: + griefprevention.kickfromclaim: true + griefprevention.kickfromclaimexempt: true + griefprevention.petkick: true + griefprevention.siegeimmune: description: Makes a player immune to /Siege. default: op griefprevention.givepet: @@ -333,3 +341,12 @@ permissions: griefprevention.siegeteleport: description: Players with this permission can teleport into and out of besieged areas. default: op + griefprevention.kickfromclaim: + default: op + description: Allows the use of /kickfromclaim + griefprevention.kickfromclaimexempt: + default: op + description: Players with this perm cannot be kicked out of claims. + griefprevention.petkick: + default: op + description: Grants access to /petkick