diff --git a/src/main/java/us/tastybento/bskyblock/BSkyBlock.java b/src/main/java/us/tastybento/bskyblock/BSkyBlock.java index 6ff4ce516..1830f204d 100755 --- a/src/main/java/us/tastybento/bskyblock/BSkyBlock.java +++ b/src/main/java/us/tastybento/bskyblock/BSkyBlock.java @@ -19,7 +19,7 @@ import us.tastybento.bskyblock.managers.RanksManager; /** * Main BSkyBlock class - provides an island minigame in the sky - * @author Tastybento + * @author tastybento * @author Poslovitch */ public class BSkyBlock extends JavaPlugin { @@ -83,57 +83,34 @@ public class BSkyBlock extends JavaPlugin { // These items have to be loaded when the server has done 1 tick. // Note Worlds are not loaded this early, so any Locations or World reference will be null // at this point. Therefore, the 1 tick scheduler is required. - getServer().getScheduler().runTask(this, new Runnable() { + getServer().getScheduler().runTask(this, () -> { + // Create the world if it does not exist + islandWorldManager = new IslandWorld(plugin); - @Override - public void run() { - // Create the world if it does not exist - islandWorldManager = new IslandWorld(plugin); + getServer().getScheduler().runTask(plugin, () -> { + // Load islands from database + islandsManager.load(); - getServer().getScheduler().runTask(plugin, new Runnable() { + localesManager = new LocalesManager(plugin); + //TODO localesManager.registerLocales(plugin); - @Override - public void run() { - // Load islands from database - islandsManager.load(); + // Register Listeners + registerListeners(); - localesManager = new LocalesManager(plugin); - //TODO localesManager.registerLocales(plugin); + // Load Flags + flagsManager = new FlagsManager(plugin); - // Register Listeners - registerListeners(); + // Load addons + addonsManager = new AddonsManager(plugin); + addonsManager.enableAddons(); - // Load Flags - flagsManager = new FlagsManager(plugin); - - // Load addons - addonsManager = new AddonsManager(plugin); - addonsManager.enableAddons(); - - /* - *DEBUG CODE - Island loadedIsland = islandsManager.getIsland(owner); - getLogger().info("Island name = " + loadedIsland.getName()); - getLogger().info("Island locked = " + loadedIsland.getLocked()); - //getLogger().info("Random set = " + randomSet); - getLogger().info("Island coops = " + loadedIsland.getCoops()); - for (Entry flag: loadedIsland.getFlags().entrySet()) { - getLogger().info("Flag " + flag.getKey().name() + " = " + flag.getValue()); - } - */ - // Save islands & players data asynchronously every X minutes - getSettings().setDatabaseBackupPeriod(10 * 60 * 20); - plugin.getServer().getScheduler().runTaskTimer(plugin, new Runnable() { - - @Override - public void run() { - playersManager.save(true); - islandsManager.save(true); - } - }, getSettings().getDatabaseBackupPeriod(), getSettings().getDatabaseBackupPeriod()); - } - }); - } + // Save islands & players data asynchronously every X minutes + getSettings().setDatabaseBackupPeriod(10 * 60 * 20); + plugin.getServer().getScheduler().runTaskTimer(plugin, () -> { + playersManager.save(true); + islandsManager.save(true); + }, getSettings().getDatabaseBackupPeriod(), getSettings().getDatabaseBackupPeriod()); + }); }); } diff --git a/src/main/java/us/tastybento/bskyblock/api/events/island/IslandEvent.java b/src/main/java/us/tastybento/bskyblock/api/events/island/IslandEvent.java index e7b937310..2d8cd423e 100644 --- a/src/main/java/us/tastybento/bskyblock/api/events/island/IslandEvent.java +++ b/src/main/java/us/tastybento/bskyblock/api/events/island/IslandEvent.java @@ -2,7 +2,6 @@ package us.tastybento.bskyblock.api.events.island; import java.util.UUID; -import org.bukkit.Bukkit; import org.bukkit.Location; import us.tastybento.bskyblock.BSkyBlock; diff --git a/src/main/java/us/tastybento/bskyblock/api/panels/PanelItem.java b/src/main/java/us/tastybento/bskyblock/api/panels/PanelItem.java index f31a04ffd..ba1c7ea94 100644 --- a/src/main/java/us/tastybento/bskyblock/api/panels/PanelItem.java +++ b/src/main/java/us/tastybento/bskyblock/api/panels/PanelItem.java @@ -3,7 +3,6 @@ package us.tastybento.bskyblock.api.panels; import java.util.List; import java.util.Optional; -import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; diff --git a/src/main/java/us/tastybento/bskyblock/api/panels/builders/PanelItemBuilder.java b/src/main/java/us/tastybento/bskyblock/api/panels/builders/PanelItemBuilder.java index b53496cd7..cf86fec50 100644 --- a/src/main/java/us/tastybento/bskyblock/api/panels/builders/PanelItemBuilder.java +++ b/src/main/java/us/tastybento/bskyblock/api/panels/builders/PanelItemBuilder.java @@ -3,7 +3,6 @@ package us.tastybento.bskyblock.api.panels.builders; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Optional; import org.bukkit.Bukkit; import org.bukkit.Material; diff --git a/src/main/java/us/tastybento/bskyblock/database/objects/Island.java b/src/main/java/us/tastybento/bskyblock/database/objects/Island.java index 02562f2a7..539d4ac25 100755 --- a/src/main/java/us/tastybento/bskyblock/database/objects/Island.java +++ b/src/main/java/us/tastybento/bskyblock/database/objects/Island.java @@ -377,7 +377,7 @@ public class Island implements DataObject { /** * Set the Island Guard flag rank * @param flag - * @param value + * @param value - rank value. If the flag applies to the island, a positive number = true, negative = false */ public void setFlag(Flag flag, int value){ flags.put(flag, value); @@ -655,4 +655,14 @@ public class Island implements DataObject { public boolean isAllowed(User user, Flag flag) { return (this.getRank(user) >= this.getFlag(flag)) ? true : false; } + + /** + * Check if the flag is allowed or not + * For flags that are for the island in general and not related to rank + * @param flag + * @return true if allowed, false if not + */ + public boolean isAllowed(Flag flag) { + return this.getFlag(flag) >= 0 ? true : false; + } } \ No newline at end of file diff --git a/src/main/java/us/tastybento/bskyblock/listeners/JoinLeaveListener.java b/src/main/java/us/tastybento/bskyblock/listeners/JoinLeaveListener.java index 90c313771..e3618927b 100644 --- a/src/main/java/us/tastybento/bskyblock/listeners/JoinLeaveListener.java +++ b/src/main/java/us/tastybento/bskyblock/listeners/JoinLeaveListener.java @@ -1,6 +1,5 @@ package us.tastybento.bskyblock.listeners; -import java.util.Optional; import java.util.UUID; import org.bukkit.event.EventHandler; diff --git a/src/main/java/us/tastybento/bskyblock/listeners/FlagListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/AbstractFlagListener.java similarity index 72% rename from src/main/java/us/tastybento/bskyblock/listeners/FlagListener.java rename to src/main/java/us/tastybento/bskyblock/listeners/flags/AbstractFlagListener.java index dedf42541..f8aeb8601 100644 --- a/src/main/java/us/tastybento/bskyblock/listeners/FlagListener.java +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/AbstractFlagListener.java @@ -1,7 +1,7 @@ /** * */ -package us.tastybento.bskyblock.listeners; +package us.tastybento.bskyblock.listeners.flags; import java.util.Optional; @@ -18,18 +18,18 @@ import us.tastybento.bskyblock.api.flags.Flag; import us.tastybento.bskyblock.database.objects.Island; /** - * Abstract class for flag listeners to inherit. Provides some common code. - * @author ben + * Abstract class for flag listeners. Provides common code. + * @author tastybento * */ -public abstract class FlagListener implements Listener { +public abstract class AbstractFlagListener implements Listener { - protected BSkyBlock plugin; + public BSkyBlock plugin; private User user = null; - public FlagListener(BSkyBlock plugin) { + public AbstractFlagListener() { super(); - this.plugin = plugin; + this.plugin = BSkyBlock.getInstance(); } /** @@ -38,7 +38,7 @@ public abstract class FlagListener implements Listener { * @param e - the event * @return user or empty */ - protected Optional getEventUser(Event e) { + private Optional createEventUser(Event e) { // Set the user if (e instanceof PlayerEvent) { user = User.getInstance(((PlayerEvent)e).getPlayer()); @@ -52,41 +52,33 @@ public abstract class FlagListener implements Listener { * Explicitly set the user * @param user */ - protected void setUser(User user) { + public void setUser(User user) { this.user = user; } - /** - * Get the user associated with this event - * @return User or null - */ - protected User getUser() { - return user; - } - /* * The following methods cover the cancellable events and enable a simple noGo(e) to be used to cancel and send the error message */ /** - * Cancels the event and sends the island protected message to user + * Cancels the event and sends the island public message to user * @param e Event */ - protected void noGo(Event e) { + public void noGo(Event e) { noGo(e, false); } /** - * Cancels the event and sends the island protected message to user unless silent is true + * Cancels the event and sends the island public message to user unless silent is true * @param e Event * @param silent - if true, message is not sent */ - protected void noGo(Event e, boolean silent) { + public void noGo(Event e, boolean silent) { if (e instanceof Cancellable) ((Cancellable)e).setCancelled(true); if (user != null) { if (!silent) - user.sendMessage("protection.protected"); + user.sendMessage("protection.public"); user.updateInventory(); } } @@ -96,7 +88,7 @@ public abstract class FlagListener implements Listener { * @param loc * @return true if the location is in the island worlds */ - protected boolean inWorld(Location loc) { + public boolean inWorld(Location loc) { return (loc.getWorld().equals(plugin.getIslandWorldManager().getIslandWorld()) || loc.getWorld().equals(plugin.getIslandWorldManager().getNetherWorld()) || loc.getWorld().equals(plugin.getIslandWorldManager().getEndWorld())) ? true : false; @@ -107,7 +99,7 @@ public abstract class FlagListener implements Listener { * @param entity - the entity * @return true if in world */ - protected boolean inWorld(Entity entity) { + public boolean inWorld(Entity entity) { return inWorld(entity.getLocation()); } @@ -116,7 +108,7 @@ public abstract class FlagListener implements Listener { * @param user - a user * @return true if in world */ - protected boolean inWorld(User user) { + public boolean inWorld(User user) { return inWorld(user.getLocation()); } @@ -126,7 +118,7 @@ public abstract class FlagListener implements Listener { * @param loc * @return true if the check is okay, false if it was disallowed */ - protected boolean checkIsland(Event e, Location loc, Flag flag) { + public boolean checkIsland(Event e, Location loc, Flag flag) { return checkIsland(e, loc, flag, false); } @@ -139,20 +131,20 @@ public abstract class FlagListener implements Listener { * @param silent - if true, no attempt is made to tell the user * @return true if the check is okay, false if it was disallowed */ - protected boolean checkIsland(Event e, Location loc, Flag flag, boolean silent) { + public boolean checkIsland(Event e, Location loc, Flag flag, boolean silent) { // If the user is not set, try to get it from the event - if (getUser() == null) { + if (user == null) { // Set the user associated with this event - if (!getEventUser(e).isPresent()) return true; + if (!createEventUser(e).isPresent()) return true; } // If this is not an Island World, skip - if (!inWorld(getUser())) return true; + if (!inWorld(user)) return true; // Get the island and if present, check the flag, react if required and return Optional island = plugin.getIslands().getIslandAt(loc); if (island.isPresent()) { - if (!island.get().isAllowed(getUser(), flag)) { + if (!island.get().isAllowed(user, flag)) { noGo(e, silent); return false; } else { diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/AnvilListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/AnvilListener.java deleted file mode 100644 index 0a662e69e..000000000 --- a/src/main/java/us/tastybento/bskyblock/listeners/flags/AnvilListener.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * - */ -package us.tastybento.bskyblock.listeners.flags; - -import org.bukkit.Material; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerInteractEvent; - -import us.tastybento.bskyblock.BSkyBlock; -import us.tastybento.bskyblock.listeners.FlagListener; -import us.tastybento.bskyblock.lists.Flags; - -/** - * @author ben - * - */ -public class AnvilListener extends FlagListener { - - public AnvilListener() { - super(BSkyBlock.getInstance()); - } - - /** - * Handle placing of Anvils - * @param e - */ - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerInteract(final PlayerInteractEvent e) { - if (!e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { - return; - } - if (e.getClickedBlock().getType().equals(Material.ANVIL)) { - checkIsland(e, getUser().getLocation(), Flags.ANVIL); - } - } -} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/BlockInteractionListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/BlockInteractionListener.java new file mode 100644 index 000000000..c63130cc5 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/BlockInteractionListener.java @@ -0,0 +1,138 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * @author ben + * + */ +public class BlockInteractionListener extends AbstractFlagListener { + + /** + * Handle interaction with blocks + * @param e + */ + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + public void onPlayerInteract(final PlayerInteractEvent e) { + if (!e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { + return; + } + switch (e.getClickedBlock().getType()) { + case ANVIL: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.ANVIL); + break; + case BEACON: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.BEACON); + break; + case BED_BLOCK: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.BED); + break; + case BREWING_STAND: + case CAULDRON: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.BREWING); + break; + case CHEST: + case STORAGE_MINECART: + case TRAPPED_CHEST: + case BLACK_SHULKER_BOX: + case BLUE_SHULKER_BOX: + case BROWN_SHULKER_BOX: + case CYAN_SHULKER_BOX: + case GRAY_SHULKER_BOX: + case GREEN_SHULKER_BOX: + case LIGHT_BLUE_SHULKER_BOX: + case LIME_SHULKER_BOX: + case PINK_SHULKER_BOX: + case MAGENTA_SHULKER_BOX: + case ORANGE_SHULKER_BOX: + case PURPLE_SHULKER_BOX: + case RED_SHULKER_BOX: + case SILVER_SHULKER_BOX: + case WHITE_SHULKER_BOX: + case YELLOW_SHULKER_BOX: + case DISPENSER: + case DROPPER: + case HOPPER: + case HOPPER_MINECART: + + checkIsland(e, e.getClickedBlock().getLocation(), Flags.CHEST); + break; + + case ACACIA_DOOR: + case BIRCH_DOOR: + case DARK_OAK_DOOR: + case IRON_DOOR: + case IRON_DOOR_BLOCK: + case IRON_TRAPDOOR: + case JUNGLE_DOOR: + case SPRUCE_DOOR: + case TRAP_DOOR: + case WOODEN_DOOR: + case WOOD_DOOR: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.DOOR); + break; + case ACACIA_FENCE_GATE: + case BIRCH_FENCE_GATE: + case DARK_OAK_FENCE_GATE: + case FENCE_GATE: + case JUNGLE_FENCE_GATE: + case SPRUCE_FENCE_GATE: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.GATE); + break; + + case BURNING_FURNACE: + case FURNACE: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.FURNACE); + break; + case ENCHANTMENT_TABLE: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.ENCHANTING); + break; + case ENDER_CHEST: + break; + case JUKEBOX: + case NOTE_BLOCK: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.MUSIC); + break; + case WORKBENCH: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.CRAFTING); + break; + case STONE_BUTTON: + case WOOD_BUTTON: + case LEVER: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.LEVER_BUTTON); + break; + case DIODE: + case DIODE_BLOCK_OFF: + case DIODE_BLOCK_ON: + case REDSTONE_COMPARATOR_ON: + case REDSTONE_COMPARATOR_OFF: + case DAYLIGHT_DETECTOR: + case DAYLIGHT_DETECTOR_INVERTED: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.REDSTONE); + break; + default: + break; + } + // Now check for in-hand items + if (e.getItem() != null) { + switch (e.getItem().getType()) { + case ENDER_PEARL: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.ENDER_PEARL); + break; + case MONSTER_EGG: + checkIsland(e, e.getClickedBlock().getLocation(), Flags.SPAWN_EGGS); + default: + break; + + } + } + } +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/BreakBlocksListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/BreakBlocksListener.java index d86e41742..3dfc9277c 100644 --- a/src/main/java/us/tastybento/bskyblock/listeners/flags/BreakBlocksListener.java +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/BreakBlocksListener.java @@ -3,6 +3,7 @@ package us.tastybento.bskyblock.listeners.flags; import org.bukkit.Material; import org.bukkit.World.Environment; import org.bukkit.block.Block; +import org.bukkit.entity.ArmorStand; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; @@ -16,16 +17,10 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.vehicle.VehicleDamageEvent; import org.bukkit.util.BlockIterator; -import us.tastybento.bskyblock.BSkyBlock; import us.tastybento.bskyblock.api.commands.User; -import us.tastybento.bskyblock.listeners.FlagListener; import us.tastybento.bskyblock.lists.Flags; -public class BreakBlocksListener extends FlagListener { - - public BreakBlocksListener() { - super(BSkyBlock.getInstance()); - } +public class BreakBlocksListener extends AbstractFlagListener { /** * Prevents blocks from being broken @@ -36,7 +31,7 @@ public class BreakBlocksListener extends FlagListener { public void onBlockBreak(final BlockBreakEvent e) { checkIsland(e, e.getBlock().getLocation(), Flags.BREAK_BLOCKS); } - + /** * Prevents the breakage of hanging items * @@ -59,7 +54,7 @@ public class BreakBlocksListener extends FlagListener { public void onPlayerInteract(final PlayerInteractEvent e) { // Only handle hitting things if (!e.getAction().equals(Action.LEFT_CLICK_BLOCK)) return; - + // Look along player's sight line to see if any blocks are skulls try { BlockIterator iter = new BlockIterator(e.getPlayer(), 10); @@ -72,7 +67,7 @@ public class BreakBlocksListener extends FlagListener { } } } catch (Exception ex) {} - + switch (e.getClickedBlock().getType()) { case CAKE_BLOCK: case DRAGON_EGG: @@ -100,7 +95,7 @@ public class BreakBlocksListener extends FlagListener { User user = User.getInstance((Player) e.getAttacker()); // Get the island and if present, check the flag, react if required and return plugin.getIslands().getIslandAt(e.getVehicle().getLocation()).ifPresent(x -> { - if (!x.isAllowed(getUser(), Flags.BREAK_BLOCKS)) { + if (!x.isAllowed(user, Flags.BREAK_BLOCKS)) { e.setCancelled(true); user.sendMessage("protection.protected"); } @@ -121,8 +116,8 @@ public class BreakBlocksListener extends FlagListener { */ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onEntityDamage(EntityDamageByEntityEvent e) { - // Only handle item frames - if (!(e.getEntity() instanceof ItemFrame) && !e.getEntityType().toString().endsWith("STAND")) return; + // Only handle item frames and armor stands + if (!(e.getEntity() instanceof ItemFrame) && !(e.getEntity() instanceof ArmorStand)) return; // Get the attacker if (e.getDamager() instanceof Player) { @@ -141,5 +136,4 @@ public class BreakBlocksListener extends FlagListener { } } - } diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/BreedingListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/BreedingListener.java new file mode 100644 index 000000000..c26b4d997 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/BreedingListener.java @@ -0,0 +1,51 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.entity.Animals; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles breeding protection + * Note - animal protection is done elsewhere. + * @author tastybento + * + */ +public class BreedingListener extends AbstractFlagListener { + + /** + * A list of items that cause breeding if a player has them in their hand and they click an animal + * This list may need to be extended with future versions of Minecraft. + */ + private final static List BREEDING_ITEMS = Arrays.asList( + Material.EGG, + Material.WHEAT, + Material.CARROT_ITEM, + Material.SEEDS); + + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true) + public void onPlayerInteract(final PlayerInteractAtEntityEvent e) { + if (e.getRightClicked() != null && e.getRightClicked() instanceof Animals) { + ItemStack inHand = e.getPlayer().getInventory().getItemInMainHand(); + if (e.getHand().equals(EquipmentSlot.OFF_HAND)) { + inHand = e.getPlayer().getInventory().getItemInOffHand(); + } + if (inHand != null && BREEDING_ITEMS.contains(inHand.getType())) { + checkIsland(e, e.getRightClicked().getLocation(), Flags.BREEDING); + } + } + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/BucketListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/BucketListener.java new file mode 100644 index 000000000..a6accff38 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/BucketListener.java @@ -0,0 +1,56 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerBucketFillEvent; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles interaction with beds + * Note - bed protection from breaking or placing is done elsewhere. + * @author tastybento + * + */ +public class BucketListener extends AbstractFlagListener { + + /** + * Prevents emptying of buckets + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onBucketEmpty(final PlayerBucketEmptyEvent e) { + if (e.getBlockClicked() != null) { + // This is where the water or lava actually will be dumped + Block dumpBlock = e.getBlockClicked().getRelative(e.getBlockFace()); + checkIsland(e, dumpBlock.getLocation(), Flags.BUCKET); + } + } + + /** + * Prevents collecting of lava, water, milk. If bucket use is denied in general, it is blocked. + * @param e + */ + @EventHandler(priority = EventPriority.LOW) + public void onBucketFill(final PlayerBucketFillEvent e) { + // Check filling of various liquids + if (e.getItemStack().getType().equals(Material.LAVA_BUCKET)) { + if (!checkIsland(e, e.getBlockClicked().getLocation(), Flags.COLLECT_LAVA)) return; + } + if (e.getItemStack().getType().equals(Material.WATER_BUCKET)) { + if (!checkIsland(e, e.getBlockClicked().getLocation(), Flags.COLLECT_WATER)) return; + } + if (e.getItemStack().getType().equals(Material.MILK_BUCKET)) { + if (!checkIsland(e, e.getBlockClicked().getLocation(), Flags.MILKING)) return; + } + // Check general bucket use + checkIsland(e, e.getBlockClicked().getLocation(), Flags.BUCKET); + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/EggListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/EggListener.java new file mode 100644 index 000000000..ceb297d27 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/EggListener.java @@ -0,0 +1,30 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerEggThrowEvent; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles throwing regular eggs (not spawn eggs) + * @author tastybento + * + */ +public class EggListener extends AbstractFlagListener { + + /** + * Handle visitor chicken egg throwing + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onEggThrow(PlayerEggThrowEvent e) { + if (!checkIsland(e, e.getEgg().getLocation(), Flags.EGGS)) { + e.setHatching(false); + } + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/EntityInteractListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/EntityInteractListener.java new file mode 100644 index 000000000..382958aab --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/EntityInteractListener.java @@ -0,0 +1,43 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.entity.Animals; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles interaction with entities like armor stands + * Note - armor stand protection from breaking or placing is done elsewhere. + * @author tastybento + * + */ +public class EntityInteractListener extends AbstractFlagListener { + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true) + public void onPlayerInteract(final PlayerInteractAtEntityEvent e) { + if (e.getRightClicked() instanceof ArmorStand) { + checkIsland(e, e.getRightClicked().getLocation(), Flags.ARMOR_STAND); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerHitEntity(PlayerInteractEntityEvent e) { + // Animal riding + if (e.getRightClicked() instanceof Vehicle && e.getRightClicked() instanceof Animals) { + checkIsland(e, e.getRightClicked().getLocation(), Flags.RIDING); + } + // Villager trading + if (e.getRightClicked().getType().equals(EntityType.VILLAGER)) { + checkIsland(e, e.getRightClicked().getLocation(), Flags.TRADING); + } + } +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/FireListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/FireListener.java new file mode 100644 index 000000000..8d7c524bd --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/FireListener.java @@ -0,0 +1,165 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import java.util.Optional; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockSpreadEvent; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.util.BlockIterator; + +import us.tastybento.bskyblock.api.commands.User; +import us.tastybento.bskyblock.database.objects.Island; +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles fire + * @author tastybento + * + */ +public class FireListener extends AbstractFlagListener { + + /** + * Prevents fire spread + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onBlockBurn(BlockBurnEvent e) { + if (!inWorld(e.getBlock().getLocation())) { + return; + } + // Check if the island exists and if fire is allowed + Optional island = plugin.getIslands().getIslandAt(e.getBlock().getLocation()); + island.ifPresent(x -> { + if (!x.isAllowed(Flags.FIRE_SPREAD)) e.setCancelled(true); + }); + // If not on an island, check the default setting + if (!island.isPresent() && !Flags.FIRE_SPREAD.isAllowed()) e.setCancelled(true); + } + + /** + * Prevent fire spread + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onBlockSpread(BlockSpreadEvent e) { + if (e.getSource().getType().equals(Material.FIRE)) { + if (!inWorld(e.getBlock().getLocation())) { + return; + } + // Check if the island exists and if fire is allowed + Optional island = plugin.getIslands().getIslandAt(e.getBlock().getLocation()); + island.ifPresent(x -> { + if (!x.isAllowed(Flags.FIRE_SPREAD)) e.setCancelled(true); + }); + // If not on an island, check the default setting + if (!island.isPresent() && !Flags.FIRE_SPREAD.isAllowed()) e.setCancelled(true); + } + } + + /** + * Igniting fires + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onBlockIgnite(BlockIgniteEvent e) { + if (!inWorld(e.getBlock().getLocation())) { + return; + } + // Check if this is a portal lighting - that is allowed any time + if (e.getBlock().getType().equals(Material.OBSIDIAN)) { + return; + } + // Check if the island exists and if fire is allowed + Optional island = plugin.getIslands().getIslandAt(e.getBlock().getLocation()); + island.ifPresent(x -> { + if (!x.isAllowed(Flags.FIRE)) e.setCancelled(true); + }); + // If not on an island, check the default setting + if (!island.isPresent() && !Flags.FIRE.isAllowed()) e.setCancelled(true); + + } + + /** + * Flint & Steel and Extinguishing fire + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerInteract(PlayerInteractEvent e) { + if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK) && e.getMaterial() != null && e.getMaterial().equals(Material.FLINT_AND_STEEL)) { + checkIsland(e, e.getClickedBlock().getLocation(), Flags.FIRE); + } + // Look along player's sight line to see if any blocks are fire. Players can hit fire out quite a long way away. + try { + BlockIterator iter = new BlockIterator(e.getPlayer(), 10); + Block lastBlock = iter.next(); + while (iter.hasNext()) { + lastBlock = iter.next(); + if (lastBlock.equals(e.getClickedBlock())) { + break; + } + if (lastBlock.getType().equals(Material.FIRE)) { + checkIsland(e, lastBlock.getLocation(), Flags.FIRE_EXTINGUISH); + } + } + } catch (Exception ex) { + // To catch at block iterator exceptions that can happen in the void or at the very top of blocks + } + } + + /** + * Protect TNT. + * Note that allowing TNT to explode is governed by the Break Blocks flag. + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onTNTPrimed(EntityChangeBlockEvent e) { + // Check world + if (!inWorld(e.getBlock().getLocation())) { + return; + } + // Check for TNT + if (!e.getBlock().getType().equals(Material.TNT)) { + //plugin.getLogger().info("DEBUG: not tnt"); + return; + } + // Check if the island exists and if fire is allowed + Optional island = plugin.getIslands().getIslandAt(e.getBlock().getLocation()); + island.ifPresent(x -> { + if (!x.isAllowed(Flags.FIRE)) e.setCancelled(true); + }); + // If not on an island, check the default setting + if (!island.isPresent() && !Flags.FIRE.isAllowed()) e.setCancelled(true); + + // If either of these canceled the event, return + if (e.isCancelled()) return; + + // Stop TNT from being damaged if it is being caused by a visitor with a flaming arrow + if (e.getEntity() instanceof Projectile) { + Projectile projectile = (Projectile) e.getEntity(); + // Find out who fired it + if (projectile.getShooter() instanceof Player) { + if (projectile.getFireTicks() > 0) { + Player shooter = (Player)projectile.getShooter(); + setUser(User.getInstance(shooter)); + if (checkIsland(e, e.getBlock().getLocation(), Flags.BREAK_BLOCKS)) { + // Remove the arrow + projectile.remove(); + } + } + } + } + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/HurtingListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/HurtingListener.java new file mode 100644 index 000000000..c5aff48d1 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/HurtingListener.java @@ -0,0 +1,207 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import java.util.HashMap; +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.entity.Animals; +import org.bukkit.entity.Entity; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Snowman; +import org.bukkit.entity.Squid; +import org.bukkit.entity.Villager; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.LingeringPotionSplashEvent; +import org.bukkit.event.entity.PotionSplashEvent; +import org.bukkit.event.player.PlayerFishEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.potion.PotionEffect; + +import us.tastybento.bskyblock.api.commands.User; +import us.tastybento.bskyblock.api.flags.Flag; +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles hurting of monsters and animals directly and indirectly + * @author tastybento + * + */ +public class HurtingListener extends AbstractFlagListener { + + private HashMap thrownPotions = new HashMap<>(); + + + /** + * Handles mob and monster protection + * + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onEntityDamage(final EntityDamageByEntityEvent e) { + // Mobs being hurt + if (e.getEntity() instanceof Animals || e.getEntity() instanceof IronGolem || e.getEntity() instanceof Snowman + || e.getEntity() instanceof Villager) { + respond(e, e.getDamager(), Flags.HURT_MOBS); + } else if (e.getEntity() instanceof Monster || e.getEntity() instanceof Squid || e.getEntity() instanceof Slime) { + respond(e, e.getDamager(), Flags.HURT_MONSTERS); + } + } + + /** + * Finds the true attacker, even if the attack was via a projectile + * @param event + * @param damager + * @param flag + */ + private void respond(Event event, Entity damager, Flag flag) { + // Get the attacker + if (damager instanceof Player) { + setUser(User.getInstance(damager)); + checkIsland(event, damager.getLocation(), flag); + } else if (damager instanceof Projectile) { + // Find out who fired the projectile + Projectile p = (Projectile) damager; + if (p.getShooter() instanceof Player) { + setUser(User.getInstance((Player)p.getShooter())); + if (!checkIsland(event, damager.getLocation(), flag)) { + damager.setFireTicks(0); + damager.remove(); + } + } + } + + } + + /** + * Handle attacks with a fishing rod + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onFishing(PlayerFishEvent e) { + if (e.getCaught() == null) + return; + + if (e.getCaught() instanceof Animals || e.getCaught() instanceof IronGolem || e.getCaught() instanceof Snowman + || e.getCaught() instanceof Villager) { + if (checkIsland(e, e.getCaught().getLocation(), Flags.HURT_MONSTERS)) { + e.getHook().remove(); + return; + } + } else if (e.getCaught() instanceof Monster || e.getCaught() instanceof Squid || e.getCaught() instanceof Slime) { + if (checkIsland(e, e.getCaught().getLocation(), Flags.HURT_MONSTERS)) { + e.getHook().remove(); + return; + } + } + } + + + /** + * Handles feeding cookies to animals, which may hurt them + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerHitEntity(PlayerInteractEntityEvent e) { + if (e.getRightClicked() instanceof Animals) { + if ((e.getHand().equals(EquipmentSlot.HAND) && e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.COOKIE)) + || (e.getHand().equals(EquipmentSlot.OFF_HAND) && e.getPlayer().getInventory().getItemInOffHand().getType().equals(Material.COOKIE))) { + checkIsland(e, e.getRightClicked().getLocation(), Flags.HURT_MOBS); + } + } + } + + /** + * Checks for splash damage. Remove damage if it should not affect. + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true) + public void onSplashPotionSplash(final PotionSplashEvent e) { + // Try to get the shooter + Projectile projectile = (Projectile) e.getEntity(); + if (projectile.getShooter() != null && projectile.getShooter() instanceof Player) { + Player attacker = (Player)projectile.getShooter(); + setUser(User.getInstance(attacker)); + // Run through all the affected entities + for (LivingEntity entity: e.getAffectedEntities()) { + // Self damage + if (attacker.equals(entity)) { + continue; + } + // Monsters being hurt + if (entity instanceof Monster || entity instanceof Slime || entity instanceof Squid) { + if (!checkIsland(e, entity.getLocation(), Flags.HURT_MONSTERS)) { + for (PotionEffect effect : e.getPotion().getEffects()) { + entity.removePotionEffect(effect.getType()); + } + } + } + + // Mobs being hurt + if (entity instanceof Animals || entity instanceof IronGolem || entity instanceof Snowman + || entity instanceof Villager) { + if (!checkIsland(e, entity.getLocation(), Flags.HURT_MONSTERS)) { + for (PotionEffect effect : e.getPotion().getEffects()) { + entity.removePotionEffect(effect.getType()); + } + } + } + } + } + } + + /** + * Handle lingering potions. This tracks when a potion has been initially splashed. + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true) + public void onLingeringPotionSplash(final LingeringPotionSplashEvent e) { + // Try to get the shooter + Projectile projectile = (Projectile) e.getEntity(); + if (projectile.getShooter() != null && projectile.getShooter() instanceof Player) { + UUID uuid = ((Player)projectile.getShooter()).getUniqueId(); + // Store it and remove it when the effect is gone + thrownPotions.put(e.getAreaEffectCloud().getEntityId(), uuid); + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + thrownPotions.remove(e.getAreaEffectCloud().getEntityId()); + }, e.getAreaEffectCloud().getDuration()); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true) + public void onLingeringPotionDamage(final EntityDamageByEntityEvent e) { + if (e.getEntity() == null || e.getEntity().getUniqueId() == null) { + return; + } + + if (e.getCause().equals(DamageCause.ENTITY_ATTACK) && thrownPotions.containsKey(e.getDamager().getEntityId())) { + UUID attacker = thrownPotions.get(e.getDamager().getEntityId()); + // Self damage + if (attacker.equals(e.getEntity().getUniqueId())) { + return; + } + Entity entity = e.getEntity(); + // Monsters being hurt + if (entity instanceof Monster || entity instanceof Slime || entity instanceof Squid) { + checkIsland(e, entity.getLocation(), Flags.HURT_MONSTERS); + } + // Mobs being hurt + else if (entity instanceof Animals || entity instanceof IronGolem || entity instanceof Snowman + || entity instanceof Villager) { + checkIsland(e, entity.getLocation(), Flags.HURT_MONSTERS); + } + } + } +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/InventoryListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/InventoryListener.java new file mode 100644 index 000000000..00d004ba0 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/InventoryListener.java @@ -0,0 +1,59 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.block.Beacon; +import org.bukkit.block.BrewingStand; +import org.bukkit.block.Chest; +import org.bukkit.block.Dispenser; +import org.bukkit.block.Dropper; +import org.bukkit.block.Furnace; +import org.bukkit.block.Hopper; +import org.bukkit.block.ShulkerBox; +import org.bukkit.entity.Animals; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.inventory.InventoryClickEvent; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles inventory protection + * @author tastybento + * + */ +public class InventoryListener extends AbstractFlagListener { + + /** + * Prevents visitors picking items from inventories + * @param event + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true) + public void onMountInventoryClick(InventoryClickEvent event) { + if (event.getInventory().getHolder() == null) { + return; + } + if (event.getInventory().getHolder() instanceof Animals) { + checkIsland(event, event.getInventory().getLocation(), Flags.MOUNT_INVENTORY); + } + else if (event.getInventory().getHolder() instanceof Chest + || event.getInventory().getHolder() instanceof Dispenser + || event.getInventory().getHolder() instanceof Hopper + || event.getInventory().getHolder() instanceof Dropper + || event.getInventory().getHolder() instanceof ShulkerBox) { + checkIsland(event, event.getInventory().getLocation(), Flags.CHEST); + } + else if (event.getInventory().getHolder() instanceof Furnace) { + checkIsland(event, event.getInventory().getLocation(), Flags.FURNACE); + } + else if (event.getInventory().getHolder() instanceof BrewingStand) { + checkIsland(event, event.getInventory().getLocation(), Flags.BREWING); + } + else if (event.getInventory().getHolder() instanceof Beacon) { + checkIsland(event, event.getInventory().getLocation(), Flags.BEACON); + } + } + + +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/ItemDropPickUpListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/ItemDropPickUpListener.java new file mode 100644 index 000000000..b73e2f4b3 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/ItemDropPickUpListener.java @@ -0,0 +1,39 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityPickupItemEvent; +import org.bukkit.event.player.PlayerDropItemEvent; + +import us.tastybento.bskyblock.api.commands.User; +import us.tastybento.bskyblock.lists.Flags; + +/** + * @author tastybento + * + */ +public class ItemDropPickUpListener extends AbstractFlagListener { + + /* + * Handle item drop by visitors + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onVisitorDrop(PlayerDropItemEvent e) { + checkIsland(e, e.getItemDrop().getLocation(), Flags.VISITOR_ITEM_DROP); + } + + /* + * Handle item pickup by visitors + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onVisitorDrop(EntityPickupItemEvent e) { + if (e.getEntity() instanceof Player) { + setUser(User.getInstance(e.getEntity())); + checkIsland(e, e.getItem().getLocation(), Flags.VISITOR_ITEM_PICKUP); + } + } +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/LeashListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/LeashListener.java new file mode 100644 index 000000000..0899842b1 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/LeashListener.java @@ -0,0 +1,53 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.PlayerLeashEntityEvent; +import org.bukkit.event.hanging.HangingPlaceEvent; +import org.bukkit.event.player.PlayerUnleashEntityEvent; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * @author tastybento + * + */ +public class LeashListener extends AbstractFlagListener { + + /** + * Prevents leashing + * + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onLeashUse(PlayerLeashEntityEvent e) { + checkIsland(e, e.getEntity().getLocation(),Flags.LEASH); + } + + + /** + * Prevents unleashing + * + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onLeashUse(PlayerUnleashEntityEvent e) { + checkIsland(e, e.getEntity().getLocation(),Flags.LEASH); + } + + /** + * Prevents hitching + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerLeashHitch(final HangingPlaceEvent e) { + if (e.getEntity() != null && e.getEntity().getType().equals(EntityType.LEASH_HITCH)) { + checkIsland(e, e.getEntity().getLocation(),Flags.LEASH); + } + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/MobSpawnListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/MobSpawnListener.java new file mode 100644 index 000000000..2dded771b --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/MobSpawnListener.java @@ -0,0 +1,79 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import java.util.Optional; + +import org.bukkit.entity.Animals; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Slime; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; + +import us.tastybento.bskyblock.database.objects.Island; +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles natural mob spawning. + * @author tastybento + * + */ +public class MobSpawnListener extends AbstractFlagListener { + + /** + * Prevents mobs spawning naturally + * + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onNaturalMobSpawn(final CreatureSpawnEvent e) { + // If not in the right world, return + if (!inWorld(e.getEntity())) { + return; + } + // Deal with natural spawning + if (e.getSpawnReason().equals(SpawnReason.NATURAL) + || e.getSpawnReason().equals(SpawnReason.JOCKEY) + || e.getSpawnReason().equals(SpawnReason.CHUNK_GEN) + || e.getSpawnReason().equals(SpawnReason.DEFAULT) + || e.getSpawnReason().equals(SpawnReason.MOUNT) + || e.getSpawnReason().equals(SpawnReason.JOCKEY) + || e.getSpawnReason().equals(SpawnReason.NETHER_PORTAL)) { + Optional island = plugin.getIslands().getIslandAt(e.getLocation()); + if (island.isPresent()) { + if (e.getEntity() instanceof Monster || e.getEntity() instanceof Slime) { + if (!island.get().isAllowed(Flags.MOB_SPAWN)) { + // Mobs not allowed to spawn + e.setCancelled(true); + return; + } + } else if (e.getEntity() instanceof Animals) { + if (!island.get().isAllowed(Flags.MONSTER_SPAWN)) { + // Mobs not allowed to spawn + e.setCancelled(true); + return; + } + } + } else { + // Outside of the island + if (e.getEntity() instanceof Monster || e.getEntity() instanceof Slime) { + if (!Flags.MOB_SPAWN.isAllowed()) { + // Mobs not allowed to spawn + e.setCancelled(true); + return; + } + } else if (e.getEntity() instanceof Animals) { + if (!Flags.MONSTER_SPAWN.isAllowed()) { + // Mobs not allowed to spawn + e.setCancelled(true); + return; + } + } + } + } + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/PVPListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/PVPListener.java new file mode 100644 index 000000000..428b193f5 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/PVPListener.java @@ -0,0 +1,157 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import java.util.HashMap; +import java.util.UUID; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.LingeringPotionSplashEvent; +import org.bukkit.event.entity.PotionSplashEvent; +import org.bukkit.event.player.PlayerFishEvent; +import org.bukkit.potion.PotionEffect; + +import us.tastybento.bskyblock.api.commands.User; +import us.tastybento.bskyblock.api.flags.Flag; +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles PVP + * @author tastybento + * + */ +public class PVPListener extends AbstractFlagListener { + + private HashMap thrownPotions = new HashMap<>(); + + + /** + * This method protects players from PVP if it is not allowed and from + * arrows fired by other players + * + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onEntityDamage(final EntityDamageByEntityEvent e) { + if (e.getEntity() instanceof Player) { + Flag flag = Flags.PVP; + if (e.getEntity().getWorld().equals(plugin.getIslandWorldManager().getNetherWorld())) flag = Flags.NETHER_PVP; + else if (e.getEntity().getWorld().equals(plugin.getIslandWorldManager().getEndWorld())) flag = Flags.END_PVP; + respond(e, e.getDamager(), flag); + } + } + + private void respond(Event event, Entity damager, Flag flag) { + // Get the attacker + if (damager instanceof Player) { + setUser(User.getInstance(damager)); + checkIsland(event, damager.getLocation(), flag); + } else if (damager instanceof Projectile) { + // Find out who fired the arrow + Projectile p = (Projectile) damager; + if (p.getShooter() instanceof Player) { + setUser(User.getInstance((Player)p.getShooter())); + if (!checkIsland(event, damager.getLocation(), flag)) { + damager.setFireTicks(0); + damager.remove(); + } + } + } + + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onFishing(PlayerFishEvent e) { + if (e.getCaught() != null && e.getCaught() instanceof Player) { + Flag flag = Flags.PVP; + if (e.getCaught().getWorld().equals(plugin.getIslandWorldManager().getNetherWorld())) flag = Flags.NETHER_PVP; + else if (e.getCaught().getWorld().equals(plugin.getIslandWorldManager().getEndWorld())) flag = Flags.END_PVP; + if (checkIsland(e, e.getCaught().getLocation(), flag)) { + e.getHook().remove(); + return; + } + } + } + + /** + * Checks for splash damage. Remove damage if it should not affect. + * @param e + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true) + public void onSplashPotionSplash(final PotionSplashEvent e) { + // Deduce the world + Flag flag = Flags.PVP; + if (e.getPotion().getWorld().equals(plugin.getIslandWorldManager().getNetherWorld())) flag = Flags.NETHER_PVP; + else if (e.getPotion().getWorld().equals(plugin.getIslandWorldManager().getEndWorld())) flag = Flags.END_PVP; + + // Try to get the thrower + Projectile projectile = (Projectile) e.getEntity(); + if (projectile.getShooter() != null && projectile.getShooter() instanceof Player) { + Player attacker = (Player)projectile.getShooter(); + setUser(User.getInstance(attacker)); + // Run through all the affected entities + for (LivingEntity entity: e.getAffectedEntities()) { + // Self damage + if (attacker.equals(entity)) { + continue; + } + // PVP? + if (entity instanceof Player) { + if (!checkIsland(e, entity.getLocation(), flag)) { + for (PotionEffect effect : e.getPotion().getEffects()) { + entity.removePotionEffect(effect.getType()); + } + } + } + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true) + public void onLingeringPotionSplash(final LingeringPotionSplashEvent e) { + // Try to get the shooter + Projectile projectile = (Projectile) e.getEntity(); + if (projectile.getShooter() != null && projectile.getShooter() instanceof Player) { + UUID uuid = ((Player)projectile.getShooter()).getUniqueId(); + // Store it and remove it when the effect is gone + thrownPotions.put(e.getAreaEffectCloud().getEntityId(), uuid); + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + thrownPotions.remove(e.getAreaEffectCloud().getEntityId()); + }, e.getAreaEffectCloud().getDuration()); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true) + public void onLingeringPotionDamage(final EntityDamageByEntityEvent e) { + if (e.getEntity() == null || e.getEntity().getUniqueId() == null) { + return; + } + + if (e.getCause().equals(DamageCause.ENTITY_ATTACK) && thrownPotions.containsKey(e.getDamager().getEntityId())) { + // Deduce the world + Flag flag = Flags.PVP; + if (e.getEntity().getWorld().equals(plugin.getIslandWorldManager().getNetherWorld())) flag = Flags.NETHER_PVP; + else if (e.getEntity().getWorld().equals(plugin.getIslandWorldManager().getEndWorld())) flag = Flags.END_PVP; + + UUID attacker = thrownPotions.get(e.getDamager().getEntityId()); + // Self damage + if (attacker.equals(e.getEntity().getUniqueId())) { + return; + } + Entity entity = e.getEntity(); + // PVP? + if (entity instanceof Player) { + checkIsland(e, entity.getLocation(), flag); + } + } + } +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/PhysicalInteractionListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/PhysicalInteractionListener.java new file mode 100644 index 000000000..77a594f74 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/PhysicalInteractionListener.java @@ -0,0 +1,46 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * @author ben + * + */ +public class PhysicalInteractionListener extends AbstractFlagListener { + + /** + * Handle physical interaction with blocks + * Crop trample, pressure plates, triggering redstone, tripwires + * @param e + */ + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + public void onPlayerInteract(final PlayerInteractEvent e) { + if (!e.getAction().equals(Action.PHYSICAL)) { + return; + } + switch (e.getClickedBlock().getType()) { + case SOIL: + // Crop trample + checkIsland(e, e.getPlayer().getLocation(), Flags.CROP_TRAMPLE); + break; + case WOOD_PLATE: + case STONE_PLATE: + case GOLD_PLATE: + case IRON_PLATE: + // Pressure plates + checkIsland(e, e.getPlayer().getLocation(), Flags.PRESSURE_PLATE); + break; + default: + break; + + } + } +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/PlaceBlocksListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/PlaceBlocksListener.java index a1b212721..83c4d0413 100644 --- a/src/main/java/us/tastybento/bskyblock/listeners/flags/PlaceBlocksListener.java +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/PlaceBlocksListener.java @@ -10,16 +10,9 @@ import org.bukkit.event.block.EntityBlockFormEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; -import us.tastybento.bskyblock.BSkyBlock; -import us.tastybento.bskyblock.listeners.FlagListener; import us.tastybento.bskyblock.lists.Flags; -public class PlaceBlocksListener extends FlagListener { - - public PlaceBlocksListener() { - super(BSkyBlock.getInstance()); - } - +public class PlaceBlocksListener extends AbstractFlagListener { /** * Check blocks being placed in general @@ -73,7 +66,7 @@ public class PlaceBlocksListener extends FlagListener { if (e.getMaterial().equals(Material.END_CRYSTAL) || e.getMaterial() == Material.WOOD_DOOR || e.getMaterial() == Material.CHEST || e.getMaterial() == Material.TRAPPED_CHEST || e.getMaterial() == Material.IRON_DOOR || (e.getMaterial().name().contains("BOAT") && !e.getClickedBlock().isLiquid())) { - checkIsland(e, getUser().getLocation(), Flags.PLACE_BLOCKS); + checkIsland(e, e.getPlayer().getLocation(), Flags.PLACE_BLOCKS); } } } @@ -87,7 +80,7 @@ public class PlaceBlocksListener extends FlagListener { public void onBlockForm(EntityBlockFormEvent e) { if (e.getNewState().getType().equals(Material.FROSTED_ICE)) { // Silently check - checkIsland(e, getUser().getLocation(), Flags.PLACE_BLOCKS, true); + checkIsland(e, e.getBlock().getLocation(), Flags.PLACE_BLOCKS, true); } } diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/PortalListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/PortalListener.java new file mode 100644 index 000000000..e32d870c6 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/PortalListener.java @@ -0,0 +1,23 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerPortalEvent; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles portal protection + * @author tastybento + * + */ +public class PortalListener extends AbstractFlagListener { + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerPortal(PlayerPortalEvent e) { + checkIsland(e, e.getFrom(), Flags.PORTAL); + } +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/ShearingListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/ShearingListener.java new file mode 100644 index 000000000..2b404a5cc --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/ShearingListener.java @@ -0,0 +1,25 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerShearEntityEvent; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles shearing + * @author tastybento + * + */ +public class ShearingListener extends AbstractFlagListener { + + // Protect sheep + @EventHandler(priority = EventPriority.LOW) + public void onShear(final PlayerShearEntityEvent e) { + checkIsland(e, e.getEntity().getLocation(), Flags.SHEARING); + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/listeners/flags/TeleportationListener.java b/src/main/java/us/tastybento/bskyblock/listeners/flags/TeleportationListener.java new file mode 100644 index 000000000..cbb5cd6e6 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/listeners/flags/TeleportationListener.java @@ -0,0 +1,37 @@ +/** + * + */ +package us.tastybento.bskyblock.listeners.flags; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + +import us.tastybento.bskyblock.lists.Flags; + +/** + * Handles interaction with entities like armor stands + * Note - armor stand protection from breaking or placing is done elsewhere. + * @author tastybento + * + */ +public class TeleportationListener extends AbstractFlagListener { + + /** + * Ender pearl and chorus fruit teleport checks + * + * @param e + */ + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onPlayerTeleport(final PlayerTeleportEvent e) { + + if (e.getCause() != null) { + if (e.getCause().equals(TeleportCause.ENDER_PEARL)) { + checkIsland(e, e.getTo(), Flags.ENDER_PEARL); + } else if (e.getCause().equals(TeleportCause.CHORUS_FRUIT)) { + checkIsland(e, e.getTo(), Flags.CHORUS_FRUIT); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/us/tastybento/bskyblock/lists/Flags.java b/src/main/java/us/tastybento/bskyblock/lists/Flags.java index 66edc3c7c..62ec5cb48 100644 --- a/src/main/java/us/tastybento/bskyblock/lists/Flags.java +++ b/src/main/java/us/tastybento/bskyblock/lists/Flags.java @@ -1,56 +1,121 @@ package us.tastybento.bskyblock.lists; import org.bukkit.Material; + import us.tastybento.bskyblock.api.flags.Flag; import us.tastybento.bskyblock.api.flags.FlagBuilder; -import us.tastybento.bskyblock.listeners.flags.*; +import us.tastybento.bskyblock.listeners.flags.BlockInteractionListener; +import us.tastybento.bskyblock.listeners.flags.BreakBlocksListener; +import us.tastybento.bskyblock.listeners.flags.BreedingListener; +import us.tastybento.bskyblock.listeners.flags.BucketListener; +import us.tastybento.bskyblock.listeners.flags.EggListener; +import us.tastybento.bskyblock.listeners.flags.EntityInteractListener; +import us.tastybento.bskyblock.listeners.flags.FireListener; +import us.tastybento.bskyblock.listeners.flags.HurtingListener; +import us.tastybento.bskyblock.listeners.flags.InventoryListener; +import us.tastybento.bskyblock.listeners.flags.LeashListener; +import us.tastybento.bskyblock.listeners.flags.PVPListener; +import us.tastybento.bskyblock.listeners.flags.PhysicalInteractionListener; +import us.tastybento.bskyblock.listeners.flags.PlaceBlocksListener; +import us.tastybento.bskyblock.listeners.flags.PortalListener; +import us.tastybento.bskyblock.listeners.flags.ShearingListener; +import us.tastybento.bskyblock.listeners.flags.TeleportationListener; public class Flags { + /* + * Protection Flags + */ + + // Break and place blocks public static final Flag BREAK_BLOCKS = new FlagBuilder().id("BREAK_BLOCKS").icon(Material.STONE).listener(new BreakBlocksListener()).build(); public static final Flag PLACE_BLOCKS = new FlagBuilder().id("PLACE_BLOCKS").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag ANVIL = new FlagBuilder().id("ANVIL").icon(Material.DIRT).listener(new AnvilListener()).build(); - public static final Flag ARMOR_STAND = new FlagBuilder().id("ARMOR_STAND").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag BEACON = new FlagBuilder().id("BEACON").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag BED = new FlagBuilder().id("BED").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag BREEDING = new FlagBuilder().id("BREEDING").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag BREWING = new FlagBuilder().id("BREWING").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag BUCKET = new FlagBuilder().id("BUCKET").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag COLLECT_LAVA = new FlagBuilder().id("COLLECT_LAVA").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag COLLECT_WATER = new FlagBuilder().id("COLLECT_WATER").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag CHEST = new FlagBuilder().id("CHEST").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag CHORUS_FRUIT = new FlagBuilder().id("CHORUS_FRUIT").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag CRAFTING = new FlagBuilder().id("CRAFTING").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag CROP_TRAMPLE = new FlagBuilder().id("CROP_TRAMPLE").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag DOOR = new FlagBuilder().id("DOOR").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag EGGS = new FlagBuilder().id("EGGS").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag ENCHANTING = new FlagBuilder().id("ENCHANTING").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag ENDER_PEARL = new FlagBuilder().id("ENDER_PEARL").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag ENTER_EXIT_MESSAGES = new FlagBuilder().id("ENTER_EXIT_MESSAGES").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag FIRE = new FlagBuilder().id("FIRE").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag FIRE_EXTINGUISH = new FlagBuilder().id("FIRE_EXTINGUISH").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag FIRE_SPREAD = new FlagBuilder().id("FIRE_SPREAD").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag FURNACE = new FlagBuilder().id("FURNACE").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag GATE = new FlagBuilder().id("GATE").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag MOUNT_INVENTORY = new FlagBuilder().id("MOUNT_INVENTORY").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag RIDING = new FlagBuilder().id("RIDING").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag HURT_MOBS = new FlagBuilder().id("HURT_MOBS").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag LEASH = new FlagBuilder().id("LEASH").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag LEVER_BUTTON = new FlagBuilder().id("LEVER_BUTTON").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag MOB_SPAWN = new FlagBuilder().id("MOB_SPAWN").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag MUSIC = new FlagBuilder().id("MUSIC").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag PORTAL = new FlagBuilder().id("PORTAL").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag PRESSURE_PLATE = new FlagBuilder().id("PRESSURE_PLATE").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag PVP = new FlagBuilder().id("PVP").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag MILKING = new FlagBuilder().id("MILKING").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag NETHER_PVP = new FlagBuilder().id("NETHER_PVP").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag END_PVP = new FlagBuilder().id("END_PVP").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag REDSTONE = new FlagBuilder().id("REDSTONE").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag SPAWN_EGGS = new FlagBuilder().id("SPAWN_EGGS").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag SHEARING = new FlagBuilder().id("SHEARING").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); - public static final Flag TRADING = new FlagBuilder().id("TRADING").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); + + // Block interactions - all use BlockInteractionListener() + public static final Flag ANVIL = new FlagBuilder().id("ANVIL").icon(Material.ANVIL).listener(new BlockInteractionListener()).build(); + public static final Flag BEACON = new FlagBuilder().id("BEACON").icon(Material.BEACON).build(); + public static final Flag BED = new FlagBuilder().id("BED").icon(Material.BED).build(); + public static final Flag BREWING = new FlagBuilder().id("BREWING").icon(Material.BREWING_STAND_ITEM).build(); + public static final Flag CHEST = new FlagBuilder().id("CHEST").icon(Material.CHEST).build(); + public static final Flag DOOR = new FlagBuilder().id("DOOR").allowedByDefault(true).icon(Material.WOODEN_DOOR).build(); + public static final Flag CRAFTING = new FlagBuilder().id("CRAFTING").allowedByDefault(true).icon(Material.WORKBENCH).build(); + public static final Flag ENCHANTING = new FlagBuilder().id("ENCHANTING").allowedByDefault(true).icon(Material.ENCHANTMENT_TABLE).build(); + public static final Flag FURNACE = new FlagBuilder().id("FURNACE").icon(Material.FURNACE).build(); + public static final Flag GATE = new FlagBuilder().id("GATE").allowedByDefault(true).icon(Material.FENCE_GATE).build(); + public static final Flag MUSIC = new FlagBuilder().id("MUSIC").icon(Material.JUKEBOX).build(); + public static final Flag LEVER_BUTTON = new FlagBuilder().id("LEVER_BUTTON").icon(Material.LEVER).build(); + public static final Flag REDSTONE = new FlagBuilder().id("REDSTONE").icon(Material.REDSTONE).listener(new PlaceBlocksListener()).build(); + public static final Flag SPAWN_EGGS = new FlagBuilder().id("SPAWN_EGGS").icon(Material.MONSTER_EGG).listener(new PlaceBlocksListener()).build(); + + // Entity interactions + public static final Flag ARMOR_STAND = new FlagBuilder().id("ARMOR_STAND").icon(Material.ARMOR_STAND).listener(new EntityInteractListener()).build(); + public static final Flag RIDING = new FlagBuilder().id("RIDING").icon(Material.GOLD_BARDING).build(); + public static final Flag TRADING = new FlagBuilder().id("TRADING").allowedByDefault(true).icon(Material.EMERALD).build(); + + // Breeding + public static final Flag BREEDING = new FlagBuilder().id("BREEDING").icon(Material.CARROT).listener(new BreedingListener()).build(); + + // Buckets. All bucket use is covered by one listener + public static final Flag BUCKET = new FlagBuilder().id("BUCKET").icon(Material.BUCKET).listener(new BucketListener()).build(); + public static final Flag COLLECT_LAVA = new FlagBuilder().id("COLLECT_LAVA").icon(Material.LAVA_BUCKET).build(); + public static final Flag COLLECT_WATER = new FlagBuilder().id("COLLECT_WATER").icon(Material.WATER_BUCKET).build(); + public static final Flag MILKING = new FlagBuilder().id("MILKING").icon(Material.MILK_BUCKET).build(); + + // Chorus Fruit and Enderpearls + public static final Flag CHORUS_FRUIT = new FlagBuilder().id("CHORUS_FRUIT").icon(Material.CHORUS_FRUIT).listener(new TeleportationListener()).build(); + public static final Flag ENDER_PEARL = new FlagBuilder().id("ENDER_PEARL").icon(Material.ENDER_PEARL).build(); + + // Physical interactions + public static final Flag CROP_TRAMPLE = new FlagBuilder().id("CROP_TRAMPLE").icon(Material.WHEAT).listener(new PhysicalInteractionListener()).build(); + public static final Flag PRESSURE_PLATE = new FlagBuilder().id("PRESSURE_PLATE").icon(Material.GOLD_PLATE).build(); + + // Egg throwing + public static final Flag EGGS = new FlagBuilder().id("EGGS").icon(Material.EGG).listener(new EggListener()).build(); + + /* + * Fire + * I'll take you to burn. + * Fire + * I'll take you to learn. + * You gonna burn, burn, burn + * Fire + * I'll take you to burn + * - The Crazy World of Arthur Brown + */ + public static final Flag FIRE = new FlagBuilder().id("FIRE").icon(Material.FLINT_AND_STEEL).listener(new FireListener()).build(); + public static final Flag FIRE_EXTINGUISH = new FlagBuilder().id("FIRE_EXTINGUISH").icon(Material.POTION).build(); + public static final Flag FIRE_SPREAD = new FlagBuilder().id("FIRE_SPREAD").icon(Material.FIREWORK_CHARGE).build(); + + // Inventories + public static final Flag MOUNT_INVENTORY = new FlagBuilder().id("MOUNT_INVENTORY").icon(Material.IRON_BARDING).listener(new InventoryListener()).build(); + + // Hurting things + public static final Flag HURT_MOBS = new FlagBuilder().id("HURT_MOBS").icon(Material.STONE_SWORD).listener(new HurtingListener()).build(); + public static final Flag HURT_MONSTERS = new FlagBuilder().id("HURT_MONSTERS").icon(Material.WOOD_SWORD).build(); + + // Leashes + public static final Flag LEASH = new FlagBuilder().id("LEASH").icon(Material.LEASH).listener(new LeashListener()).build(); + + // Portal use protection + public static final Flag PORTAL = new FlagBuilder().id("PORTAL").icon(Material.OBSIDIAN).listener(new PortalListener()).build(); + + // PVP + public static final Flag PVP = new FlagBuilder().id("PVP").icon(Material.ARROW).listener(new PVPListener()).build(); + public static final Flag NETHER_PVP = new FlagBuilder().id("NETHER_PVP").icon(Material.IRON_AXE).build(); + public static final Flag END_PVP = new FlagBuilder().id("END_PVP").icon(Material.END_CRYSTAL).build(); + + // Shearing + public static final Flag SHEARING = new FlagBuilder().id("SHEARING").icon(Material.SHEARS).listener(new ShearingListener()).build(); + + // Visitor item pickup or drop public static final Flag VISITOR_ITEM_DROP = new FlagBuilder().id("VISITOR_ITEM_DROP").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); public static final Flag VISITOR_ITEM_PICKUP = new FlagBuilder().id("VISITOR_ITEM_PICKUP").icon(Material.DIRT).listener(new PlaceBlocksListener()).build(); + /* + * Non-protection flags + */ + public static final Flag ENTER_EXIT_MESSAGES = new FlagBuilder().id("ENTER_EXIT_MESSAGES").icon(Material.DIRT).allowedByDefault(true).listener(new PlaceBlocksListener()).build(); + public static final Flag MOB_SPAWN = new FlagBuilder().id("MOB_SPAWN").icon(Material.APPLE).allowedByDefault(true).listener(new PlaceBlocksListener()).build(); + public static final Flag MONSTER_SPAWN = new FlagBuilder().id("MONSTER_SPAWN").icon(Material.MOB_SPAWNER).allowedByDefault(true).listener(new PlaceBlocksListener()).build(); } diff --git a/src/main/java/us/tastybento/bskyblock/managers/FlagsManager.java b/src/main/java/us/tastybento/bskyblock/managers/FlagsManager.java index 68c1ddb16..960f83478 100644 --- a/src/main/java/us/tastybento/bskyblock/managers/FlagsManager.java +++ b/src/main/java/us/tastybento/bskyblock/managers/FlagsManager.java @@ -3,8 +3,6 @@ package us.tastybento.bskyblock.managers; import java.util.ArrayList; import java.util.List; -import org.bukkit.Bukkit; - import us.tastybento.bskyblock.BSkyBlock; import us.tastybento.bskyblock.api.flags.Flag; import us.tastybento.bskyblock.api.panels.PanelItem; diff --git a/src/main/java/us/tastybento/bskyblock/util/SafeSpotTeleport.java b/src/main/java/us/tastybento/bskyblock/util/SafeSpotTeleport.java index edf7af39d..c2790efef 100644 --- a/src/main/java/us/tastybento/bskyblock/util/SafeSpotTeleport.java +++ b/src/main/java/us/tastybento/bskyblock/util/SafeSpotTeleport.java @@ -98,203 +98,174 @@ public class SafeSpotTeleport { } final int worldHeight = maxHeight; //plugin.getLogger().info("DEBUG:world height = " + worldHeight); - plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { - - @Override - public void run() { - // Find a safe spot, defined as a solid block, with 2 air spaces above it - //long time = System.nanoTime(); - int x = 0; - int y = 0; - int z = 0; - ChunkSnapshot safeChunk = null; - ChunkSnapshot portalChunk = null; - boolean safeSpotFound = false; - Vector safeSpotInChunk = null; - Vector portalPart = null; - double distance = 0D; - double safeDistance = 0D; - for (ChunkSnapshot chunk: finalChunk) { - for (x = 0; x< 16; x++) { - for (z = 0; z < 16; z++) { - // Work down from the entry point up - for (y = Math.min(chunk.getHighestBlockYAt(x, z), worldHeight); y >= 0; y--) { - //System.out.println("Trying " + (16 * chunk.getX() + x) + " " + y + " " + (16 * chunk.getZ() + z)); - // Check for portal - only if this is not a safe home search - if (!setHome && chunk.getBlockType(x, y, z).equals(Material.PORTAL)) { - if (portalPart == null || (distance > islandLoc.toVector().distanceSquared(new Vector(x,y,z)))) { - // First one found or a closer one, save the chunk the position and the distance - portalChunk = chunk; - portalPart = new Vector(x,y,z); - distance = portalPart.distanceSquared(islandLoc.toVector()); - } - } - // Check for safe spot, but only if it is closer than one we have found already - if (!safeSpotFound || (safeDistance > islandLoc.toVector().distanceSquared(new Vector(x,y,z)))) { - // No safe spot yet, or closer distance - if (checkBlock(chunk,x,y,z, worldHeight)) { - safeChunk = chunk; - safeSpotFound = true; - safeSpotInChunk = new Vector(x,y,z); - safeDistance = islandLoc.toVector().distanceSquared(safeSpotInChunk); - } + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + // Find a safe spot, defined as a solid block, with 2 air spaces above it + //long time = System.nanoTime(); + int x = 0; + int y = 0; + int z = 0; + ChunkSnapshot safeChunk = null; + ChunkSnapshot portalChunk = null; + boolean safeSpotFound = false; + Vector safeSpotInChunk = null; + Vector portalPart = null; + double distance = 0D; + double safeDistance = 0D; + for (ChunkSnapshot chunk: finalChunk) { + for (x = 0; x< 16; x++) { + for (z = 0; z < 16; z++) { + // Work down from the entry point up + for (y = Math.min(chunk.getHighestBlockYAt(x, z), worldHeight); y >= 0; y--) { + //System.out.println("Trying " + (16 * chunk.getX() + x) + " " + y + " " + (16 * chunk.getZ() + z)); + // Check for portal - only if this is not a safe home search + if (!setHome && chunk.getBlockType(x, y, z).equals(Material.PORTAL)) { + if (portalPart == null || (distance > islandLoc.toVector().distanceSquared(new Vector(x,y,z)))) { + // First one found or a closer one, save the chunk the position and the distance + portalChunk = chunk; + portalPart = new Vector(x,y,z); + distance = portalPart.distanceSquared(islandLoc.toVector()); } } - } //end z - } // end x - //if (safeSpotFound) { - //System.out.print("DEBUG: safe spot found " + safeSpotInChunk.toString()); - //break search; - //} - } - // End search - // Check if the portal is safe (it should be) - if (portalPart != null) { - //System.out.print("DEBUG: Portal found"); - // There is a portal available, but is it safe? - // Get the lowest portal spot - x = portalPart.getBlockX(); - y = portalPart.getBlockY(); - z = portalPart.getBlockZ(); - while (portalChunk.getBlockType(x,y,z).equals(Material.PORTAL)) { - y--; - } - //System.out.print("DEBUG: Portal teleport loc = " + (16 * portalChunk.getX() + x) + "," + (y) + "," + (16 * portalChunk.getZ() + z)); - // Now check if this is a safe location - if (checkBlock(portalChunk,x,y,z, worldHeight)) { - // Yes, so use this instead of the highest location - //System.out.print("DEBUG: Portal is safe"); - safeSpotFound = true; - safeSpotInChunk = new Vector(x,y,z); - safeChunk = portalChunk; - // TODO: Add safe portal spot to island - } - } - //System.out.print("Seconds = " + ((System.nanoTime() - time) * 0.000000001)); - if (safeChunk != null && safeSpotFound) { - //final Vector spot = new Vector((16 *currentChunk.getX()) + x + 0.5D, y +1, (16 * currentChunk.getZ()) + z + 0.5D) - final Vector spot = new Vector((16 *safeChunk.getX()) + 0.5D, 1, (16 * safeChunk.getZ()) + 0.5D).add(safeSpotInChunk); - // Return to main thread and teleport the player - plugin.getServer().getScheduler().runTask(plugin, new Runnable() { - - @Override - public void run() { - Location destination = spot.toLocation(islandLoc.getWorld()); - //plugin.getLogger().info("DEBUG: safe spot found = " + destination); - - // Create a portal - // TODO Add if statement here - //Block b = player.getLocation().getBlock(); - //if (b.getType() != Material.PORTAL) { - /* - if (world.equals(BSkyBlock.getNetherWorld())) { - for (int x = -1; x < 3; x++) { - for (int y = -1; y< 4; y++) { - Location l = new Location(islandLoc.getWorld(), destination.getBlockX() + x, destination.getBlockY() + y, destination.getBlockZ() -1); - if (x == -1 || x == 2 || y == -1 || y == 3) { - //nms.setBlockSuperFast(l.getBlock(), Material.OBSIDIAN.getId(), (byte)0, false); - //l.getBlock().setType(Material.OBSIDIAN); - //plugin.getLogger().info("DEBUG: obsidian at "+ l); - } else { - //plugin.getLogger().info("DEBUG: Portal at "+ l); - nms.setBlockSuperFast(l.getBlock(), Material.PORTAL.getId(), (byte)0, false); - //l.getBlock().setType(Material.PORTAL); - } - } - } - }*/ - if (setHome && entity instanceof Player) { - plugin.getPlayers().setHomeLocation(entity.getUniqueId(), destination, homeNumber); - } - Vector velocity = entity.getVelocity(); - entity.teleport(destination); - entity.setVelocity(velocity); - // Exit spectator mode if in it - if (entity instanceof Player) { - Player player = (Player)entity; - if (player.getGameMode().equals(GameMode.SPECTATOR)) { - player.setGameMode(GameMode.SURVIVAL); + // Check for safe spot, but only if it is closer than one we have found already + if (!safeSpotFound || (safeDistance > islandLoc.toVector().distanceSquared(new Vector(x,y,z)))) { + // No safe spot yet, or closer distance + if (checkBlock(chunk,x,y,z, worldHeight)) { + safeChunk = chunk; + safeSpotFound = true; + safeSpotInChunk = new Vector(x,y,z); + safeDistance = islandLoc.toVector().distanceSquared(safeSpotInChunk); } } - }}); - } else { - // We did not find a spot - plugin.getServer().getScheduler().runTask(plugin, () -> { - //plugin.getLogger().info("DEBUG: safe spot not found"); - if (entity instanceof Player) { - if (!failureMessage.isEmpty()) { - entity.sendMessage(failureMessage); - } else { - entity.sendMessage("Warp not safe"); - } } - }); + } //end z + } // end x + //if (safeSpotFound) { + //System.out.print("DEBUG: safe spot found " + safeSpotInChunk.toString()); + //break search; + //} + } + // End search + // Check if the portal is safe (it should be) + if (portalPart != null) { + //System.out.print("DEBUG: Portal found"); + // There is a portal available, but is it safe? + // Get the lowest portal spot + x = portalPart.getBlockX(); + y = portalPart.getBlockY(); + z = portalPart.getBlockZ(); + while (portalChunk.getBlockType(x,y,z).equals(Material.PORTAL)) { + y--; + } + //System.out.print("DEBUG: Portal teleport loc = " + (16 * portalChunk.getX() + x) + "," + (y) + "," + (16 * portalChunk.getZ() + z)); + // Now check if this is a safe location + if (checkBlock(portalChunk,x,y,z, worldHeight)) { + // Yes, so use this instead of the highest location + //System.out.print("DEBUG: Portal is safe"); + safeSpotFound = true; + safeSpotInChunk = new Vector(x,y,z); + safeChunk = portalChunk; + // TODO: Add safe portal spot to island } } - - /** - * Returns true if the location is a safe one. - * @param chunk - * @param x - * @param y - * @param z - * @param worldHeight - * @return - */ - @SuppressWarnings("deprecation") - private boolean checkBlock(ChunkSnapshot chunk, int x, int y, int z, int worldHeight) { - int type = chunk.getBlockTypeId(x, y, z); - if (type != 0) { // AIR - int space1 = chunk.getBlockTypeId(x, Math.min(y + 1, worldHeight), z); - int space2 = chunk.getBlockTypeId(x, Math.min(y + 2, worldHeight), z); - if ((space1 == 0 && space2 == 0) || (space1 == Material.PORTAL.getId() || space2 == Material.PORTAL.getId())) { - // Now there is a chance that this is a safe spot - // Check for safe ground - Material mat = Material.getMaterial(type); - if (!mat.toString().contains("FENCE") - && !mat.toString().contains("DOOR") - && !mat.toString().contains("GATE") - && !mat.toString().contains("PLATE")) { - switch (mat) { - // Unsafe - case ANVIL: - case BARRIER: - case BOAT: - case CACTUS: - case DOUBLE_PLANT: - case ENDER_PORTAL: - case FIRE: - case FLOWER_POT: - case LADDER: - case LAVA: - case LEVER: - case LONG_GRASS: - case PISTON_EXTENSION: - case PISTON_MOVING_PIECE: - case PORTAL: - case SIGN_POST: - case SKULL: - case STANDING_BANNER: - case STATIONARY_LAVA: - case STATIONARY_WATER: - case STONE_BUTTON: - case TORCH: - case TRIPWIRE: - case WATER: - case WEB: - case WOOD_BUTTON: - //System.out.println("Block is dangerous " + mat.toString()); - break; - default: - // Safe - // System.out.println("Block is safe " + mat.toString()); - return true; - } + //System.out.print("Seconds = " + ((System.nanoTime() - time) * 0.000000001)); + if (safeChunk != null && safeSpotFound) { + //final Vector spot = new Vector((16 *currentChunk.getX()) + x + 0.5D, y +1, (16 * currentChunk.getZ()) + z + 0.5D) + final Vector spot = new Vector((16 *safeChunk.getX()) + 0.5D, 1, (16 * safeChunk.getZ()) + 0.5D).add(safeSpotInChunk); + // Return to main thread and teleport the player + plugin.getServer().getScheduler().runTask(plugin, () -> { + Location destination = spot.toLocation(islandLoc.getWorld()); + if (setHome && entity instanceof Player) { + plugin.getPlayers().setHomeLocation(entity.getUniqueId(), destination, homeNumber); + } + Vector velocity = entity.getVelocity(); + entity.teleport(destination); + entity.setVelocity(velocity); + // Exit spectator mode if in it + if (entity instanceof Player) { + Player player = (Player)entity; + if (player.getGameMode().equals(GameMode.SPECTATOR)) { + player.setGameMode(GameMode.SURVIVAL); } } - } - return false; - }}); + }); + } else { + // We did not find a spot + plugin.getServer().getScheduler().runTask(plugin, () -> { + //plugin.getLogger().info("DEBUG: safe spot not found"); + if (entity instanceof Player) { + if (!failureMessage.isEmpty()) { + entity.sendMessage(failureMessage); + } else { + entity.sendMessage("Warp not safe"); + } + } + }); + } + }); } } + + /** + * Returns true if the location is a safe one. + * @param chunk + * @param x + * @param y + * @param z + * @param worldHeight + * @return + */ + @SuppressWarnings("deprecation") + private boolean checkBlock(ChunkSnapshot chunk, int x, int y, int z, int worldHeight) { + int type = chunk.getBlockTypeId(x, y, z); + if (type != 0) { // AIR + int space1 = chunk.getBlockTypeId(x, Math.min(y + 1, worldHeight), z); + int space2 = chunk.getBlockTypeId(x, Math.min(y + 2, worldHeight), z); + if ((space1 == 0 && space2 == 0) || (space1 == Material.PORTAL.getId() || space2 == Material.PORTAL.getId())) { + // Now there is a chance that this is a safe spot + // Check for safe ground + Material mat = Material.getMaterial(type); + if (!mat.toString().contains("FENCE") + && !mat.toString().contains("DOOR") + && !mat.toString().contains("GATE") + && !mat.toString().contains("PLATE")) { + switch (mat) { + // Unsafe + case ANVIL: + case BARRIER: + case BOAT: + case CACTUS: + case DOUBLE_PLANT: + case ENDER_PORTAL: + case FIRE: + case FLOWER_POT: + case LADDER: + case LAVA: + case LEVER: + case LONG_GRASS: + case PISTON_EXTENSION: + case PISTON_MOVING_PIECE: + case PORTAL: + case SIGN_POST: + case SKULL: + case STANDING_BANNER: + case STATIONARY_LAVA: + case STATIONARY_WATER: + case STONE_BUTTON: + case TORCH: + case TRIPWIRE: + case WATER: + case WEB: + case WOOD_BUTTON: + //System.out.println("Block is dangerous " + mat.toString()); + break; + default: + // Safe + // System.out.println("Block is safe " + mat.toString()); + return true; + } + } + } + } + return false; + } } \ No newline at end of file