From a1c842785067dbcc9512e241604735eef3b1b3f7 Mon Sep 17 00:00:00 2001 From: Steven Lawson Date: Sat, 3 Nov 2012 15:03:38 -0400 Subject: [PATCH] Added Protected Areas! Switched distance -> distanceSquared to eliminate square root computation, where possible. --- src/config.yml | 5 + .../Commands/Command_cartsit.java | 17 ++- .../Commands/Command_expel.java | 2 +- .../Commands/Command_protectarea.java | 103 +++++++++++++++ .../Commands/Command_setspawnworld.java | 6 + .../Listener/TFM_BlockListener.java | 36 ++++- .../Listener/TFM_PlayerListener.java | 10 +- .../TotalFreedomMod/SerializableLocation.java | 93 +++++++++++++ .../TotalFreedomMod/TFM_ProtectedArea.java | 125 ++++++++++++++++++ .../TotalFreedomMod/TotalFreedomMod.java | 13 ++ src/plugin.yml | 3 + 11 files changed, 395 insertions(+), 18 deletions(-) create mode 100644 src/me/StevenLawson/TotalFreedomMod/Commands/Command_protectarea.java create mode 100644 src/me/StevenLawson/TotalFreedomMod/SerializableLocation.java create mode 100644 src/me/StevenLawson/TotalFreedomMod/TFM_ProtectedArea.java diff --git a/src/config.yml b/src/config.yml index f7221417..3045e833 100644 --- a/src/config.yml +++ b/src/config.yml @@ -54,6 +54,11 @@ flatlands_generation_params: 16,stone,32,dirt,1,grass # Admin-Only Mode admin_only_mode: false +# Protected Areas - Protect areas so that only superadmins can directly modify blocks in those areas. WorldEdit and other such plugins might bypass this. +protected_areas_enabled: true +auto_protect_spawnpoints: true +auto_protect_radius: 25.0 + # SuperAwesomeAdmins - Because normal superadmin just isn't awesome enough. These users can do even more awesomey admin shit. super_awesome_admins: - markbyron diff --git a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_cartsit.java b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_cartsit.java index a73584e8..5cd00a44 100644 --- a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_cartsit.java +++ b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_cartsit.java @@ -49,16 +49,19 @@ public class Command_cartsit extends TFM_Command Minecart nearest_cart = null; for (Minecart cart : target_player.getWorld().getEntitiesByClass(Minecart.class)) { - if (nearest_cart == null) + if (cart.isEmpty()) { - nearest_cart = cart; - } - else - { - if (cart.getLocation().distance(target_player.getLocation()) < nearest_cart.getLocation().distance(target_player.getLocation())) + if (nearest_cart == null) { nearest_cart = cart; } + else + { + if (cart.getLocation().distanceSquared(target_player.getLocation()) < nearest_cart.getLocation().distanceSquared(target_player.getLocation())) + { + nearest_cart = cart; + } + } } } @@ -68,7 +71,7 @@ public class Command_cartsit extends TFM_Command } else { - sender.sendMessage("There are no minecarts in the target world."); + sender.sendMessage("There are no empty minecarts in the target world."); } } diff --git a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_expel.java b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_expel.java index b863bccf..7c090587 100644 --- a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_expel.java +++ b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_expel.java @@ -54,7 +54,7 @@ public class Command_expel extends TFM_Command boolean in_range = false; try { - in_range = target_pos.distance(sender_pos) < radius; + in_range = target_pos.distanceSquared(sender_pos) < (radius * radius); } catch (IllegalArgumentException ex) { diff --git a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_protectarea.java b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_protectarea.java new file mode 100644 index 00000000..142364f6 --- /dev/null +++ b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_protectarea.java @@ -0,0 +1,103 @@ +package me.StevenLawson.TotalFreedomMod.Commands; + +import me.StevenLawson.TotalFreedomMod.TFM_ProtectedArea; +import me.StevenLawson.TotalFreedomMod.TFM_Util; +import me.StevenLawson.TotalFreedomMod.TotalFreedomMod; +import org.apache.commons.lang.StringUtils; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class Command_protectarea extends TFM_Command +{ + @Override + public boolean run(CommandSender sender, Player sender_p, Command cmd, String commandLabel, String[] args, boolean senderIsConsole) + { + if (!TFM_Util.isUserSuperadmin(sender)) + { + sender.sendMessage(TotalFreedomMod.MSG_NO_PERMS); + return true; + } + + if (!TotalFreedomMod.protectedAreasEnabled) + { + sender.sendMessage("Protected areas are currently disabled in the TotalFreedomMod configuration."); + return true; + } + + if (args.length == 1) + { + if (args[0].equalsIgnoreCase("list")) + { + sender.sendMessage("Protected Areas: " + StringUtils.join(TFM_ProtectedArea.getProtectedAreaLabels(), ", ")); + } + else if (args[0].equalsIgnoreCase("clear")) + { + TFM_ProtectedArea.clearProtectedAreas(); + + sender.sendMessage("Protected Areas Cleared."); + } + else + { + return false; + } + + return true; + } + else if (args.length == 2) + { + if (args[0].equalsIgnoreCase("remove")) + { + TFM_ProtectedArea.removeProtectedArea(args[1]); + + sender.sendMessage("Area removed. Protected Areas: " + StringUtils.join(TFM_ProtectedArea.getProtectedAreaLabels(), ", ")); + } + else + { + return false; + } + + return true; + } + else if (args.length == 3) + { + if (args[0].equalsIgnoreCase("add")) + { + if (senderIsConsole) + { + sender.sendMessage("You must be in-game to set a protected area."); + return true; + } + + Double radius; + try + { + radius = Double.parseDouble(args[2]); + } + catch (NumberFormatException nfex) + { + sender.sendMessage("Invalid radius."); + return true; + } + + if (radius > TFM_ProtectedArea.MAX_RADIUS || radius < 0.0D) + { + sender.sendMessage("Invalid radius. Radius must be a positive value less than " + TFM_ProtectedArea.MAX_RADIUS + "."); + return true; + } + + TFM_ProtectedArea.addProtectedArea(args[1], sender_p.getLocation(), radius); + + sender.sendMessage("Area added. Protected Areas: " + StringUtils.join(TFM_ProtectedArea.getProtectedAreaLabels(), ", ")); + } + else + { + return false; + } + + return true; + } + + return false; + } +} diff --git a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_setspawnworld.java b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_setspawnworld.java index bb35f3e0..9a00fa9b 100644 --- a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_setspawnworld.java +++ b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_setspawnworld.java @@ -1,5 +1,6 @@ package me.StevenLawson.TotalFreedomMod.Commands; +import me.StevenLawson.TotalFreedomMod.TFM_ProtectedArea; import me.StevenLawson.TotalFreedomMod.TFM_Util; import me.StevenLawson.TotalFreedomMod.TotalFreedomMod; import org.bukkit.ChatColor; @@ -29,6 +30,11 @@ public class Command_setspawnworld extends TFM_Command sender_p.getWorld().setSpawnLocation(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); sender.sendMessage(ChatColor.GRAY + "Spawn location for this world set to: " + TFM_Util.formatLocation(sender_p.getWorld().getSpawnLocation())); + + if (TotalFreedomMod.protectedAreasEnabled && TotalFreedomMod.autoProtectSpawnpoints) + { + TFM_ProtectedArea.addProtectedArea("spawn_" + sender_p.getWorld().getName(), pos, TotalFreedomMod.autoProtectRadius); + } return true; } diff --git a/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_BlockListener.java b/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_BlockListener.java index 510d695a..3836fff6 100644 --- a/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_BlockListener.java +++ b/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_BlockListener.java @@ -1,6 +1,7 @@ package me.StevenLawson.TotalFreedomMod.Listener; import me.StevenLawson.TotalFreedomMod.TFM_Log; +import me.StevenLawson.TotalFreedomMod.TFM_ProtectedArea; import me.StevenLawson.TotalFreedomMod.TFM_UserInfo; import me.StevenLawson.TotalFreedomMod.TFM_Util; import me.StevenLawson.TotalFreedomMod.TotalFreedomMod; @@ -39,20 +40,21 @@ public class TFM_BlockListener implements Listener @EventHandler(priority = EventPriority.NORMAL) public void onBlockBreak(BlockBreakEvent event) { + Player p = event.getPlayer(); + Location block_pos = event.getBlock().getLocation(); + if (TotalFreedomMod.nukeMonitor) { - Player p = event.getPlayer(); TFM_UserInfo playerdata = TFM_UserInfo.getPlayerData(p); Location player_pos = p.getLocation(); - Location block_pos = event.getBlock().getLocation(); boolean out_of_range = false; if (!player_pos.getWorld().equals(block_pos.getWorld())) { out_of_range = true; } - else if (player_pos.distance(block_pos) > TotalFreedomMod.nukeMonitorRange) + else if (player_pos.distanceSquared(block_pos) > (TotalFreedomMod.nukeMonitorRange * TotalFreedomMod.nukeMonitorRange)) { out_of_range = true; } @@ -84,26 +86,38 @@ public class TFM_BlockListener implements Listener return; } } + + if (TotalFreedomMod.protectedAreasEnabled) + { + if (!TFM_Util.isUserSuperadmin(p)) + { + if (TFM_ProtectedArea.isInProtectedArea(block_pos)) + { + event.setCancelled(true); + return; + } + } + } } @EventHandler(priority = EventPriority.HIGH) public void onBlockPlace(BlockPlaceEvent event) { Player p = event.getPlayer(); + Location block_pos = event.getBlock().getLocation(); if (TotalFreedomMod.nukeMonitor) { TFM_UserInfo playerdata = TFM_UserInfo.getPlayerData(p); Location player_pos = p.getLocation(); - Location block_pos = event.getBlock().getLocation(); boolean out_of_range = false; if (!player_pos.getWorld().equals(block_pos.getWorld())) { out_of_range = true; } - else if (player_pos.distance(block_pos) > TotalFreedomMod.nukeMonitorRange) + else if (player_pos.distanceSquared(block_pos) > (TotalFreedomMod.nukeMonitorRange * TotalFreedomMod.nukeMonitorRange)) { out_of_range = true; } @@ -136,6 +150,18 @@ public class TFM_BlockListener implements Listener } } + if (TotalFreedomMod.protectedAreasEnabled) + { + if (!TFM_Util.isUserSuperadmin(p)) + { + if (TFM_ProtectedArea.isInProtectedArea(block_pos)) + { + event.setCancelled(true); + return; + } + } + } + ItemStack is = new ItemStack(event.getBlockPlaced().getType(), 1, (short) 0, event.getBlockPlaced().getData()); switch (is.getType()) { diff --git a/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_PlayerListener.java b/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_PlayerListener.java index f79fe90c..bb12034c 100644 --- a/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_PlayerListener.java +++ b/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_PlayerListener.java @@ -154,17 +154,17 @@ public class TFM_PlayerListener implements Listener Location mover_pos = p.getLocation(); Location fuckoff_pos = fuckoff_player.getLocation(); - double distance; + double distanceSquared; try { - distance = mover_pos.distance(fuckoff_pos); + distanceSquared = mover_pos.distanceSquared(fuckoff_pos); } catch (IllegalArgumentException ex) { continue; } - if (distance < fuckoff_range) + if (distanceSquared < (fuckoff_range * fuckoff_range)) { event.setTo(fuckoff_pos.clone().add(mover_pos.subtract(fuckoff_pos).toVector().normalize().multiply(fuckoff_range * 1.1))); break; @@ -210,7 +210,7 @@ public class TFM_PlayerListener implements Listener } else { - out_of_cage = target_pos.distance(playerdata.getCagePos()) > 2.5; + out_of_cage = target_pos.distanceSquared(playerdata.getCagePos()) > (2.5 * 2.5); } if (out_of_cage) @@ -249,7 +249,7 @@ public class TFM_PlayerListener implements Listener { if (p.getWorld().equals(landmine_pos.getWorld())) { - if (p.getLocation().distance(landmine_pos) <= landmine.radius) + if (p.getLocation().distanceSquared(landmine_pos) <= (landmine.radius * landmine.radius)) { landmine.landmine_pos.getBlock().setType(Material.AIR); diff --git a/src/me/StevenLawson/TotalFreedomMod/SerializableLocation.java b/src/me/StevenLawson/TotalFreedomMod/SerializableLocation.java new file mode 100644 index 00000000..f127b7c5 --- /dev/null +++ b/src/me/StevenLawson/TotalFreedomMod/SerializableLocation.java @@ -0,0 +1,93 @@ +package me.StevenLawson.TotalFreedomMod; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; + +// From: http://forums.bukkit.org/threads/location-serialized.105851/ +// By: gcflames5 + +public final class SerializableLocation implements Serializable +{ + private static final long serialVersionUID = 7498864812883577904L; + private final String world; + private final String uuid; + private final double x, y, z; + private final float yaw, pitch; + private transient Location loc; + + public SerializableLocation(Location l) + { + this.world = l.getWorld().getName(); + this.uuid = l.getWorld().getUID().toString(); + this.x = l.getX(); + this.y = l.getY(); + this.z = l.getZ(); + this.yaw = l.getYaw(); + this.pitch = l.getPitch(); + } + + public static Location returnLocation(SerializableLocation l) + { + float pitch = l.pitch; + float yaw = l.yaw; + double x = l.x; + double y = l.y; + double z = l.z; + World world = Bukkit.getWorld(l.world); + Location location = new Location(world, x, y, z, yaw, pitch); + return location; + } + + public static Location returnBlockLocation(SerializableLocation l) + { + double x = l.x; + double y = l.y; + double z = l.z; + World world = Bukkit.getWorld(l.world); + Location location = new Location(world, x, y, z); + return location; + } + + public SerializableLocation(Map map) + { + this.world = (String) map.get("world"); + this.uuid = (String) map.get("uuid"); + this.x = (Double) map.get("x"); + this.y = (Double) map.get("y"); + this.z = (Double) map.get("z"); + this.yaw = ((Float) map.get("yaw")).floatValue(); + this.pitch = ((Float) map.get("pitch")).floatValue(); + } + + public final Map serialize() + { + Map map = new HashMap(); + map.put("world", this.world); + map.put("uuid", this.uuid); + map.put("x", this.x); + map.put("y", this.y); + map.put("z", this.z); + map.put("yaw", this.yaw); + map.put("pitch", this.pitch); + return map; + } + + public final Location getLocation(Server server) + { + if (loc == null) + { + World world_l = server.getWorld(this.uuid); + if (world_l == null) + { + world_l = server.getWorld(this.world); + } + loc = new Location(world_l, x, y, z, yaw, pitch); + } + return loc; + } +} diff --git a/src/me/StevenLawson/TotalFreedomMod/TFM_ProtectedArea.java b/src/me/StevenLawson/TotalFreedomMod/TFM_ProtectedArea.java new file mode 100644 index 00000000..a49e6dcd --- /dev/null +++ b/src/me/StevenLawson/TotalFreedomMod/TFM_ProtectedArea.java @@ -0,0 +1,125 @@ +package me.StevenLawson.TotalFreedomMod; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; + +public class TFM_ProtectedArea implements Serializable +{ + public static final double MAX_RADIUS = 50.0D; + private static Map protectedAreas = new HashMap(); + private final SerializableLocation center_location; + private final double radius; + + private TFM_ProtectedArea(Location root_location, double radius) + { + this.center_location = new SerializableLocation(root_location); + this.radius = radius; + } + + public static boolean isInProtectedArea(Location check_location) + { + for (Map.Entry protected_area : TFM_ProtectedArea.protectedAreas.entrySet()) + { + Location protected_area_center = SerializableLocation.returnLocation(protected_area.getValue().center_location); + if (protected_area_center != null) + { + if (check_location.getWorld() == protected_area_center.getWorld()) + { + double protected_area_radius = protected_area.getValue().radius; + + if (check_location.distanceSquared(protected_area_center) <= (protected_area_radius * protected_area_radius)) + { + return true; + } + } + } + } + + return false; + } + + public static void addProtectedArea(String label, Location root_location, double radius) + { + TFM_ProtectedArea.protectedAreas.put(label.toLowerCase(), new TFM_ProtectedArea(root_location, radius)); + saveProtectedAreas(); + } + + public static void removeProtectedArea(String label) + { + TFM_ProtectedArea.protectedAreas.remove(label.toLowerCase()); + saveProtectedAreas(); + } + + public static void clearProtectedAreas() + { + TFM_ProtectedArea.protectedAreas.clear(); + autoAddSpawnpoints(); + saveProtectedAreas(); + } + + public static Set getProtectedAreaLabels() + { + return TFM_ProtectedArea.protectedAreas.keySet(); + } + + public static void saveProtectedAreas() + { + try + { + FileOutputStream fos = new FileOutputStream(new File(TotalFreedomMod.plugin.getDataFolder(), TotalFreedomMod.PROTECTED_AREA_FILE)); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(TFM_ProtectedArea.protectedAreas); + oos.close(); + fos.close(); + } + catch (Exception ex) + { + TFM_Log.severe(ex); + } + } + + @SuppressWarnings("unchecked") + public static void loadProtectedAreas() + { + try + { + File input_file = new File(TotalFreedomMod.plugin.getDataFolder(), TotalFreedomMod.PROTECTED_AREA_FILE); + if (input_file.exists()) + { + FileInputStream fis = new FileInputStream(input_file); + ObjectInputStream ois = new ObjectInputStream(fis); + TFM_ProtectedArea.protectedAreas = (HashMap) ois.readObject(); + ois.close(); + fis.close(); + } + } + catch (Exception ex) + { + File input_file = new File(TotalFreedomMod.plugin.getDataFolder(), TotalFreedomMod.PROTECTED_AREA_FILE); + input_file.delete(); + + TFM_Log.severe(ex); + } + } + + public static void autoAddSpawnpoints() + { + if (TotalFreedomMod.autoProtectSpawnpoints) + { + for (World world : Bukkit.getWorlds()) + { + TFM_ProtectedArea.addProtectedArea("spawn_" + world.getName(), world.getSpawnLocation(), TotalFreedomMod.autoProtectRadius); + } + } + } +} diff --git a/src/me/StevenLawson/TotalFreedomMod/TotalFreedomMod.java b/src/me/StevenLawson/TotalFreedomMod/TotalFreedomMod.java index a6c3430c..1a8b8cfc 100644 --- a/src/me/StevenLawson/TotalFreedomMod/TotalFreedomMod.java +++ b/src/me/StevenLawson/TotalFreedomMod/TotalFreedomMod.java @@ -30,6 +30,7 @@ public class TotalFreedomMod extends JavaPlugin public static final String CONFIG_FILE = "config.yml"; public static final String SUPERADMIN_FILE = "superadmin.yml"; public static final String PERMBAN_FILE = "permban.yml"; + public static final String PROTECTED_AREA_FILE = "protectedareas.dat"; public static final String COMMAND_PATH = "me.StevenLawson.TotalFreedomMod.Commands"; public static final String COMMAND_PREFIX = "Command_"; @@ -88,6 +89,12 @@ public class TotalFreedomMod extends JavaPlugin world.setThunderDuration(0); } } + + if (TotalFreedomMod.protectedAreasEnabled) + { + TFM_ProtectedArea.loadProtectedAreas(); + TFM_ProtectedArea.autoAddSpawnpoints(); + } } @Override @@ -186,6 +193,9 @@ public class TotalFreedomMod extends JavaPlugin public static boolean allowFliudSpread = false; public static boolean adminOnlyMode = false; public static List superAwesomeAdmins = Arrays.asList("markbyron", "mark", "madgeek1450", "madgeek", "darthsalamon", "darth"); + public static boolean protectedAreasEnabled = true; + public static boolean autoProtectSpawnpoints = true; + public static double autoProtectRadius = 25.0D; public void loadMainConfig() { @@ -224,6 +234,9 @@ public class TotalFreedomMod extends JavaPlugin allowFliudSpread = config.getBoolean("allow_fluid_spread", allowFliudSpread); adminOnlyMode = config.getBoolean("admin_only_mode", adminOnlyMode); superAwesomeAdmins = config.getStringList("super_awesome_admins"); + protectedAreasEnabled = config.getBoolean("protected_areas_enabled", protectedAreasEnabled); + autoProtectSpawnpoints = config.getBoolean("auto_protect_spawnpoints", autoProtectSpawnpoints); + autoProtectRadius = config.getDouble("auto_protect_radius", autoProtectRadius); } catch (Exception ex) { diff --git a/src/plugin.yml b/src/plugin.yml index 37b1f2f4..1fa88367 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -140,6 +140,9 @@ commands: prelog: description: Superadmin command - Enable/disable the command prelogger. When this is on, logs will be filled with many duplicate messages. usage: / + protectarea: + description: Superadmin command - Protect areas so that only superadmins can directly modify blocks in those areas. WorldEdit and other such plugins might bypass this. + usage: / | add