package com.wasteofplastic.askyblock.listeners; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Animals; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Monster; import org.bukkit.entity.Player; import org.bukkit.entity.Slime; import org.bukkit.entity.Villager; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockMultiPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.hanging.HangingPlaceEvent; import org.bukkit.event.vehicle.VehicleCreateEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; import com.wasteofplastic.askyblock.ASkyBlock; import com.wasteofplastic.askyblock.Island; import com.wasteofplastic.askyblock.Island.SettingsFlag; import com.wasteofplastic.askyblock.Settings; import com.wasteofplastic.askyblock.util.Util; import com.wasteofplastic.askyblock.util.VaultHelper; public class EntityLimits implements Listener { private static final boolean DEBUG = false; private static final boolean DEBUG2 = false; private static final boolean DEBUG3 = false; private final ASkyBlock plugin; private YamlConfiguration entities; /** * Handles entity and natural limitations * @param plugin - ASkyBlock plugin object */ public EntityLimits(ASkyBlock plugin) { this.plugin = plugin; if (Settings.saveEntities) { entities = Util.loadYamlFile("entitylimits.yml"); } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onChunkLoad(ChunkLoadEvent event) { if (!Settings.saveEntities || !IslandGuard.inWorld(event.getWorld())) { return; } Arrays.asList(event.getChunk().getEntities()).forEach(entity -> { String loc = entities.getString(event.getWorld().getName() + "." + event.getChunk().getX() + "." + event.getChunk().getZ() + "." + entity.getUniqueId().toString(), ""); if (!loc.isEmpty()) { entity.setMetadata("spawnLoc", new FixedMetadataValue(plugin, loc )); } }); // Delete the chunk data entities.set(event.getWorld().getName() + "." + event.getChunk().getX() + "." + event.getChunk().getZ() , null); } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onChunkUnload(ChunkUnloadEvent event) { if (!Settings.saveEntities || !IslandGuard.inWorld(event.getWorld())) { return; } // Delete the chunk data entities.set(event.getWorld().getName() + "." + event.getChunk().getX() + "." + event.getChunk().getZ() , null); // Create new entry Arrays.stream(event.getChunk().getEntities()).filter(x -> x.hasMetadata("spawnLoc")).forEach(entity -> { // Get the meta data entity.getMetadata("spawnLoc").stream().filter(y -> y.getOwningPlugin().equals(plugin)).forEach(v -> { entities.set(event.getWorld().getName() + "." + event.getChunk().getX() + "." + event.getChunk().getZ() + "." + entity.getUniqueId().toString(), v.asString()); }); }); Util.saveYamlFile(entities, "entitylimits.yml", true); } public void disable() { if (!Settings.saveEntities) { return; } ASkyBlock.getIslandWorld().getEntities().stream().filter(x -> x.hasMetadata("spawnLoc")).forEach(entity -> { // Get the meta data entity.getMetadata("spawnLoc").stream().filter(y -> y.getOwningPlugin().equals(plugin)).forEach(v -> { entities.set(entity.getWorld().getName() + "." + entity.getLocation().getChunk().getX() + "." + entity.getLocation().getChunk().getZ() + "." + entity.getUniqueId().toString(), v.asString()); }); }); if (Settings.createNether && Settings.newNether && ASkyBlock.getNetherWorld() != null) { ASkyBlock.getNetherWorld().getEntities().stream().filter(x -> x.hasMetadata("spawnLoc")).forEach(entity -> { // Get the meta data entity.getMetadata("spawnLoc").stream().filter(y -> y.getOwningPlugin().equals(plugin)).forEach(v -> { entities.set(entity.getWorld().getName() + "." + entity.getLocation().getChunk().getX() + "." + entity.getLocation().getChunk().getZ() + "." + entity.getUniqueId().toString(), v.asString()); }); }); } Util.saveYamlFile(entities, "entitylimits.yml", false); } /** * Action allowed in this location * @param location * @param flag * @return true if allowed */ private boolean actionAllowed(Location location, SettingsFlag flag) { Island island = plugin.getGrid().getProtectedIslandAt(location); if (island != null && island.getIgsFlag(flag)){ return true; } return island == null && Settings.defaultWorldSettings.get(flag); } /** * Checks if action is allowed for player in location for flag * @param player * @param location * @param flag * @return true if allowed */ private boolean actionAllowed(Player player, Location location, SettingsFlag flag) { if (player == null) { return actionAllowed(location, flag); } // This permission bypasses protection if (player.isOp() || VaultHelper.checkPerm(player, Settings.PERMPREFIX + "mod.bypassprotect")) { return true; } Island island = plugin.getGrid().getProtectedIslandAt(location); if (island != null && (island.getIgsFlag(flag) || island.getMembers().contains(player.getUniqueId()))){ return true; } return island == null && Settings.defaultWorldSettings.get(flag); } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onAnimalSpawn(final CreatureSpawnEvent e) { // If not in the right world, return if (!IslandGuard.inWorld(e.getEntity())) { return; } // If not an animal if (!(e.getEntity() instanceof Animals) && !e.getEntityType().equals(EntityType.SQUID)) { return; } if (DEBUG2) { plugin.getLogger().info("Animal spawn event! " + e.getEventName()); plugin.getLogger().info(e.getSpawnReason().toString()); plugin.getLogger().info(e.getEntityType().toString()); } // If there's no limit - leave it if (Settings.breedingLimit <= 0) { if (DEBUG2) plugin.getLogger().info("No limit on breeding or spawning"); return; } // We only care about spawning and breeding if (e.getSpawnReason() != SpawnReason.SPAWNER && e.getSpawnReason() != SpawnReason.BREEDING && e.getSpawnReason() != SpawnReason.EGG && e.getSpawnReason() != SpawnReason.DISPENSE_EGG && e.getSpawnReason() != SpawnReason.SPAWNER_EGG && !e.getSpawnReason().name().contains("BABY")) { if (DEBUG2) plugin.getLogger().info("Not Spawner or breeding"); return; } LivingEntity animal = e.getEntity(); Island island = plugin.getGrid().getProtectedIslandAt(animal.getLocation()); if (island == null) { // Animal is spawning outside of an island so ignore if (DEBUG2) plugin.getLogger().info("Outside island, so spawning is okay"); return; } // Count how many animals are there and who is the most likely spawner if it was a player // This had to be reworked because the previous snowball approach doesn't work for large volumes List<Player> culprits = new ArrayList<Player>(); boolean overLimit = false; int animals = 0; for (int x = island.getMinProtectedX() /16; x <= (island.getMinProtectedX() + island.getProtectionSize() - 1)/16; x++) { for (int z = island.getMinProtectedZ() /16; z <= (island.getMinProtectedZ() + island.getProtectionSize() - 1)/16; z++) { for (Entity entity : ASkyBlock.getIslandWorld().getChunkAt(x, z).getEntities()) { if (entity instanceof Animals || entity.getType().equals(EntityType.SQUID)) { if (DEBUG2) plugin.getLogger().info("DEBUG: Animal count is " + animals); animals++; if (animals >= Settings.breedingLimit) { // Delete any extra animals overLimit = true; animal.remove(); if (DEBUG2) plugin.getLogger().info("Over limit! >=" + Settings.breedingLimit); e.setCancelled(true); } } else if (entity instanceof Player && e.getSpawnReason() != SpawnReason.SPAWNER && e.getSpawnReason() != SpawnReason.DISPENSE_EGG) { for (ItemStack itemInHand: Util.getPlayerInHandItems((Player) entity)) { if (itemInHand != null) { Material type = itemInHand.getType(); if (type == Material.EGG || type == Material.MONSTER_EGG || type == Material.WHEAT || type == Material.CARROT_ITEM || type == Material.SEEDS) { if (DEBUG2) plugin.getLogger().info("Player used egg or did breeding "); if (!culprits.contains((Player)entity)) { culprits.add(((Player) entity)); } } } } } } } } if (DEBUG2) plugin.getLogger().info("Counting nether"); // Nether check if (Settings.createNether && Settings.newNether && ASkyBlock.getNetherWorld() != null) { for (int x = island.getMinProtectedX() /16; x <= (island.getMinProtectedX() + island.getProtectionSize() - 1)/16; x++) { for (int z = island.getMinProtectedZ() /16; z <= (island.getMinProtectedZ() + island.getProtectionSize() - 1)/16; z++) { for (Entity entity : ASkyBlock.getNetherWorld().getChunkAt(x, z).getEntities()) { if (entity instanceof Animals || entity.getType().equals(EntityType.SQUID)) { if (DEBUG2) plugin.getLogger().info("DEBUG: Animal count is " + animals); animals++; if (animals >= Settings.breedingLimit) { // Delete any extra animals if (DEBUG2) plugin.getLogger().info("Over limit! >=" + Settings.breedingLimit); overLimit = true; animal.remove(); e.setCancelled(true); } } else if (entity instanceof Player && e.getSpawnReason() != SpawnReason.SPAWNER && e.getSpawnReason() != SpawnReason.DISPENSE_EGG) { for (ItemStack itemInHand : Util.getPlayerInHandItems(((Player) entity))) { Material type = itemInHand.getType(); if (type == Material.EGG || type == Material.MONSTER_EGG || type == Material.WHEAT || type == Material.CARROT_ITEM || type == Material.SEEDS) { if (!culprits.contains((Player)entity)) { culprits.add(((Player) entity)); } } } } } } } } if (overLimit) { if (e.getSpawnReason() != SpawnReason.SPAWNER) { plugin.getLogger().warning( "Island at " + island.getCenter().getBlockX() + "," + island.getCenter().getBlockZ() + " hit the island animal breeding limit of " + Settings.breedingLimit); for (Player player : culprits) { Util.sendMessage(player, ChatColor.RED + plugin.myLocale(player.getUniqueId()).moblimitsError.replace("[number]", String.valueOf(Settings.breedingLimit))); plugin.getLogger().warning(player.getName() + " was trying to use " + Util.getPlayerInHandItems(player).toString()); } } } // plugin.getLogger().info("DEBUG: Animal count is " + animals); } /** * Prevents mobs spawning naturally at spawn or in an island * * @param e - event */ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onNaturalMobSpawn(final CreatureSpawnEvent e) { // if grid is not loaded yet, return. if (plugin.getGrid() == null) { return; } // If not in the right world, return if (!IslandGuard.inWorld(e.getEntity())) { return; } // Deal with natural spawning if (e.getSpawnReason().equals(SpawnReason.NATURAL) || 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)) { if (e.getEntity() instanceof Monster || e.getEntity() instanceof Slime) { if (!actionAllowed(e.getLocation(), SettingsFlag.MONSTER_SPAWN)) { if (DEBUG3) plugin.getLogger().info("Natural monster spawn cancelled."); // Mobs not allowed to spawn e.setCancelled(true); return; } } else if (e.getEntity() instanceof Animals) { if (!actionAllowed(e.getLocation(), SettingsFlag.MOB_SPAWN)) { // Animals are not allowed to spawn if (DEBUG2) plugin.getLogger().info("Natural animal spawn cancelled."); e.setCancelled(true); return; } } } if (DEBUG2) { plugin.getLogger().info("Mob spawn allowed " + e.getEventName()); plugin.getLogger().info(e.getSpawnReason().toString()); plugin.getLogger().info(e.getEntityType().toString()); } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onPlayerBlockPlace(final BlockMultiPlaceEvent e) { if (DEBUG) { plugin.getLogger().info("DEBUG: " + e.getEventName()); if (e.getPlayer() == null) { plugin.getLogger().info("DEBUG: player is null"); } else { plugin.getLogger().info("DEBUG: block placed by " + e.getPlayer().getName()); } plugin.getLogger().info("DEBUG: Block is " + e.getBlock().toString()); } if (Settings.allowedFakePlayers.contains(e.getPlayer().getName())) return; // plugin.getLogger().info(e.getEventName()); if (IslandGuard.inWorld(e.getPlayer())) { // This permission bypasses protection if (e.getPlayer().isOp() || VaultHelper.checkPerm(e.getPlayer(), Settings.PERMPREFIX + "mod.bypassprotect")) { return; } Island island = plugin.getGrid().getProtectedIslandAt(e.getBlock().getLocation()); if (island == null) { if (!Settings.defaultWorldSettings.get(SettingsFlag.PLACE_BLOCKS)) { Util.sendMessage(e.getPlayer(), ChatColor.RED + plugin.myLocale(e.getPlayer().getUniqueId()).islandProtected); e.setCancelled(true); } return; } // Island exists if (island.getIgsFlag(SettingsFlag.PLACE_BLOCKS) || island.getMembers().contains(e.getPlayer().getUniqueId())) { // Check how many placed //plugin.getLogger().info("DEBUG: block placed " + e.getBlock().getType()); String type = e.getBlock().getType().toString(); if (!e.getBlock().getState().getClass().getName().endsWith("CraftBlockState") // Not all blocks have that type of class, so we have to do some explicit checking... || e.getBlock().getType().equals(Material.REDSTONE_COMPARATOR_OFF) || type.endsWith("BANNER") // Avoids V1.7 issues || e.getBlock().getType().equals(Material.ENDER_CHEST) || e.getBlock().getType().equals(Material.ENCHANTMENT_TABLE) || e.getBlock().getType().equals(Material.DAYLIGHT_DETECTOR) || e.getBlock().getType().equals(Material.FLOWER_POT)){ // tile entity placed if (Settings.limitedBlocks.containsKey(type) && Settings.limitedBlocks.get(type) > -1) { int count = island.getTileEntityCount(e.getBlock().getType(),e.getBlock().getWorld()); if (Settings.limitedBlocks.get(type) <= count) { Util.sendMessage(e.getPlayer(), ChatColor.RED + (plugin.myLocale(e.getPlayer().getUniqueId()).entityLimitReached.replace("[entity]", Util.prettifyText(type))).replace("[number]", String.valueOf(Settings.limitedBlocks.get(type)))); e.setCancelled(true); return; } } } return; } // Outside of protection area or visitor Util.sendMessage(e.getPlayer(), ChatColor.RED + plugin.myLocale(e.getPlayer().getUniqueId()).islandProtected); e.setCancelled(true); } } /** * Prevents placing of blocks * * @param e - event */ @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onPlayerBlockPlace(final BlockPlaceEvent e) { if (DEBUG) { plugin.getLogger().info("DEBUG: " + e.getEventName()); if (e.getPlayer() == null) { plugin.getLogger().info("DEBUG: player is null"); } else { plugin.getLogger().info("DEBUG: block placed by " + e.getPlayer().getName()); } plugin.getLogger().info("DEBUG: Block is " + e.getBlock().toString()); } if (Settings.allowedFakePlayers.contains(e.getPlayer().getName())) return; // plugin.getLogger().info(e.getEventName()); if (IslandGuard.inWorld(e.getPlayer())) { // This permission bypasses protection if (e.getPlayer().isOp() || VaultHelper.checkPerm(e.getPlayer(), Settings.PERMPREFIX + "mod.bypassprotect")) { return; } //plugin.getLogger().info("DEBUG: checking is inside protection area"); Island island = plugin.getGrid().getProtectedIslandAt(e.getBlock().getLocation()); // Outside of island protection zone if (island == null) { if (!Settings.defaultWorldSettings.get(SettingsFlag.PLACE_BLOCKS)) { Util.sendMessage(e.getPlayer(), ChatColor.RED + plugin.myLocale(e.getPlayer().getUniqueId()).islandProtected); e.setCancelled(true); } return; } if (actionAllowed(e.getPlayer(), e.getBlock().getLocation(), SettingsFlag.PLACE_BLOCKS)) { // Check how many placed //plugin.getLogger().info("DEBUG: block placed " + e.getBlock().getType()); String type = e.getBlock().getType().toString(); if (!e.getBlock().getState().getClass().getName().endsWith("CraftBlockState") // Not all blocks have that type of class, so we have to do some explicit checking... || e.getBlock().getType().equals(Material.REDSTONE_COMPARATOR_OFF) || type.endsWith("BANNER") // Avoids V1.7 issues || e.getBlock().getType().equals(Material.ENDER_CHEST) || e.getBlock().getType().equals(Material.ENCHANTMENT_TABLE) || e.getBlock().getType().equals(Material.DAYLIGHT_DETECTOR) || e.getBlock().getType().equals(Material.FLOWER_POT)){ // tile entity placed if (Settings.limitedBlocks.containsKey(type) && Settings.limitedBlocks.get(type) > -1) { int count = island.getTileEntityCount(e.getBlock().getType(),e.getBlock().getWorld()); //plugin.getLogger().info("DEBUG: count is "+ count); if (Settings.limitedBlocks.get(type) <= count) { Util.sendMessage(e.getPlayer(), ChatColor.RED + (plugin.myLocale(e.getPlayer().getUniqueId()).entityLimitReached.replace("[entity]", Util.prettifyText(type))).replace("[number]", String.valueOf(Settings.limitedBlocks.get(type)))); e.setCancelled(true); return; } } } } else { // Visitor Util.sendMessage(e.getPlayer(), ChatColor.RED + plugin.myLocale(e.getPlayer().getUniqueId()).islandProtected); e.setCancelled(true); } } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onPlayerBlockPlace(final HangingPlaceEvent e) { if (DEBUG) { plugin.getLogger().info(e.getEventName()); plugin.getLogger().info("DEBUG: block placed " + e.getBlock().getType()); plugin.getLogger().info("DEBUG: entity " + e.getEntity().getType()); } if (Settings.allowedFakePlayers.contains(e.getPlayer().getName())) return; // plugin.getLogger().info(e.getEventName()); if (IslandGuard.inWorld(e.getPlayer())) { // This permission bypasses protection if (e.getPlayer().isOp() || VaultHelper.checkPerm(e.getPlayer(), Settings.PERMPREFIX + "mod.bypassprotect")) { return; } Island island = plugin.getGrid().getProtectedIslandAt(e.getBlock().getLocation()); // Outside of island protection zone if (island == null) { if (!Settings.defaultWorldSettings.get(SettingsFlag.PLACE_BLOCKS)) { Util.sendMessage(e.getPlayer(), ChatColor.RED + plugin.myLocale(e.getPlayer().getUniqueId()).islandProtected); e.setCancelled(true); } return; } if (island.getIgsFlag(SettingsFlag.PLACE_BLOCKS) || island.getMembers().contains(e.getPlayer().getUniqueId())) { // Check how many placed String type = e.getEntity().getType().toString(); if (e.getEntity().getType().equals(EntityType.ITEM_FRAME) || e.getEntity().getType().equals(EntityType.PAINTING)) { // tile entity placed if (Settings.limitedBlocks.containsKey(type) && Settings.limitedBlocks.get(type) > -1) { // Convert from EntityType to Material via string - ugh int count = island.getTileEntityCount(Material.valueOf(type),e.getEntity().getWorld()); if (Settings.limitedBlocks.get(type) <= count) { Util.sendMessage(e.getPlayer(), ChatColor.RED + (plugin.myLocale(e.getPlayer().getUniqueId()).entityLimitReached.replace("[entity]", Util.prettifyText(type))).replace("[number]", String.valueOf(Settings.limitedBlocks.get(type)))); e.setCancelled(true); } } } } else { // Visitor Util.sendMessage(e.getPlayer(), ChatColor.RED + plugin.myLocale(e.getPlayer().getUniqueId()).islandProtected); e.setCancelled(true); } } } /** * Prevents trees from growing outside of the protected area. * * @param e - event */ @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onTreeGrow(final StructureGrowEvent e) { if (DEBUG) { plugin.getLogger().info(e.getEventName()); } // Check world if (!IslandGuard.inWorld(e.getLocation())) { return; } // Check if this is on an island Island island = plugin.getGrid().getIslandAt(e.getLocation()); if (island == null || island.isSpawn()) { return; } Iterator<BlockState> it = e.getBlocks().iterator(); while (it.hasNext()) { BlockState b = it.next(); if (b.getType() == Material.LOG || b.getType() == Material.LOG_2 || b.getType() == Material.LEAVES || b.getType() == Material.LEAVES_2) { if (!island.onIsland(b.getLocation())) { it.remove(); } } } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onVillagerSpawn(final CreatureSpawnEvent e) { // If not an villager if (!(e.getEntity() instanceof Villager)) { return; } if (DEBUG3) { plugin.getLogger().info("Villager spawn event! " + e.getEventName()); plugin.getLogger().info("Reason:" + e.getSpawnReason().toString()); plugin.getLogger().info("Entity:" + e.getEntityType().toString()); } // Only cover overworld if (!e.getEntity().getWorld().equals(ASkyBlock.getIslandWorld())) { return; } // If there's no limit - leave it if (Settings.villagerLimit <= 0) { return; } // We only care about villagers breeding, being cured or coming from a spawn egg, etc. if (e.getSpawnReason() != SpawnReason.SPAWNER && e.getSpawnReason() != SpawnReason.BREEDING && e.getSpawnReason() != SpawnReason.DISPENSE_EGG && e.getSpawnReason() != SpawnReason.SPAWNER_EGG && e.getSpawnReason() != SpawnReason.CURED) { return; } Island island = plugin.getGrid().getProtectedIslandAt(e.getLocation()); if (island == null || island.getOwner() == null || island.isSpawn()) { // No island, no limit return; } int limit = Settings.villagerLimit * Math.max(1,plugin.getPlayers().getMembers(island.getOwner()).size()); //plugin.getLogger().info("DEBUG: villager limit = " + limit); //long time = System.nanoTime(); int pop = island.getPopulation(); //plugin.getLogger().info("DEBUG: time = " + ((System.nanoTime() - time)*0.000000001)); if (pop >= limit) { plugin.getLogger().warning( "Island at " + island.getCenter().getBlockX() + "," + island.getCenter().getBlockZ() + " hit the island villager limit of " + limit); //plugin.getLogger().info("Stopped villager spawning on island " + island.getCenter()); // Get all players in the area List<Entity> players = e.getEntity().getNearbyEntities(10,10,10); for (Entity player: players) { if (player instanceof Player) { Player p = (Player) player; Util.sendMessage(p, ChatColor.RED + plugin.myLocale(island.getOwner()).villagerLimitError.replace("[number]", String.valueOf(limit))); } } plugin.getMessages().tellTeam(island.getOwner(), ChatColor.RED + plugin.myLocale(island.getOwner()).villagerLimitError.replace("[number]", String.valueOf(limit))); if (e.getSpawnReason().equals(SpawnReason.CURED)) { // Easter Egg. Or should I say Easter Apple? ItemStack goldenApple = new ItemStack(Material.GOLDEN_APPLE); // Nerfed //goldenApple.setDurability((short)1); e.getLocation().getWorld().dropItemNaturally(e.getLocation(), goldenApple); } e.setCancelled(true); } } /** * Handles minecart placing * @param e - event */ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onMinecart(VehicleCreateEvent e) { if (DEBUG) { plugin.getLogger().info("DEBUG: " + e.getEventName()); plugin.getLogger().info("DEBUG: Vehicle type = " + e.getVehicle().getType()); } if (!IslandGuard.inWorld(e.getVehicle())) { if (DEBUG) plugin.getLogger().info("DEBUG: Not in world"); return; } if (DEBUG) plugin.getLogger().info("DEBUG: Checking entity types"); if (Settings.entityLimits.containsKey(e.getVehicle().getType())) { // If someone in that area has the bypass permission, allow the spawning for (Entity entity : e.getVehicle().getLocation().getWorld().getNearbyEntities(e.getVehicle().getLocation(), 5, 5, 5)) { if (entity instanceof Player) { Player player = (Player)entity; Boolean bypass = false; if (player.isOp() || VaultHelper.checkPerm(player, Settings.PERMPREFIX + "mod.bypass")) { if (DEBUG) plugin.getLogger().info("DEBUG: op or bypass"); bypass = true; } // Check island Island island = plugin.getGrid().getProtectedIslandAt(e.getVehicle().getLocation()); if (island == null) { // Only count island entities if (DEBUG) plugin.getLogger().info("DEBUG: island is null"); return; } // Ignore spawn if (island.isSpawn()) { if (DEBUG) plugin.getLogger().info("DEBUG: ignore spawn"); return; } if (DEBUG) plugin.getLogger().info("DEBUG: Checking entity limits"); // Check if the player is at the limit if (atLimit(island, bypass, e.getVehicle())) { e.setCancelled(true); for (Entity ent : e.getVehicle().getLocation().getWorld().getNearbyEntities(e.getVehicle().getLocation(), 5, 5, 5)) { if (ent instanceof Player) { Util.sendMessage((Player)ent, ChatColor.RED + (plugin.myLocale(player.getUniqueId()).entityLimitReached.replace("[entity]", Util.prettifyText(e.getVehicle().getType().toString())) .replace("[number]", String.valueOf(Settings.entityLimits.get(e.getVehicle().getType()))))); } } } } } } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onCreatureSpawn(final CreatureSpawnEvent e) { if (DEBUG) plugin.getLogger().info("DEBUG: entity tracker " + e.getEventName()); // Check world if (!e.getLocation().getWorld().toString().contains(Settings.worldName)) { return; } if (!Settings.entityLimits.containsKey(e.getEntityType())) { // Unknown entity limit or unlimited return; } boolean bypass = false; if (DEBUG) plugin.getLogger().info("DEBUG: spawn reason = " + e.getSpawnReason()); // Check why it was spawned switch (e.getSpawnReason()) { // These reasons are due to a player being involved (usually) case BREEDING: case BUILD_IRONGOLEM: case BUILD_SNOWMAN: case BUILD_WITHER: case CURED: case EGG: case SPAWNER_EGG: // If someone in that area has the bypass permission, allow the spawning for (Entity entity : e.getLocation().getWorld().getNearbyEntities(e.getLocation(), 5, 5, 5)) { if (entity instanceof Player) { Player player = (Player)entity; if (player.isOp() || VaultHelper.checkPerm(player, Settings.PERMPREFIX + "mod.bypass")) { //plugin.getLogger().info("DEBUG: bypass"); bypass = true; break; } } } break; default: break; } // Tag the entity with the island spawn location Island island = plugin.getGrid().getIslandAt(e.getLocation()); if (island == null) { // Only count island entities return; } // Ignore spawn if (island.isSpawn()) { return; } if (DEBUG) plugin.getLogger().info("DEBUG: Checking entity limits"); // Check if the player is at the limit if (atLimit(island, bypass, e.getEntity())) { e.setCancelled(true); if (!e.getSpawnReason().equals(SpawnReason.SPAWNER)) { for (Entity ent : e.getLocation().getWorld().getNearbyEntities(e.getLocation(), 5, 5, 5)) { if (ent instanceof Player) { Player player = (Player)ent; Util.sendMessage(player, ChatColor.RED + (plugin.myLocale(player.getUniqueId()).entityLimitReached.replace("[entity]", Util.prettifyText(e.getEntityType().toString())) .replace("[number]", String.valueOf(Settings.entityLimits.get(e.getEntityType()))))); } } } } } /** * Checks if new entities can be added to island * @param island * @param bypass - true if this is being done by a player with authorization to bypass limits * @param ent - the entity * @return true if at the limit, false if not */ private boolean atLimit(Island island, boolean bypass, Entity ent) { int count = 0; checkLimits: if (bypass || Settings.entityLimits.get(ent.getType()) > 0) { // If bypass, just tag the creature. If not, then we need to count creatures if (!bypass) { // Run through all the current entities on this world for (Entity entity: ent.getWorld().getEntities()) { // If it is the right one if (entity.getType().equals(ent.getType())) { if (DEBUG) plugin.getLogger().info("DEBUG: " + entity.getType() + " found"); // Check spawn location if (entity.hasMetadata("spawnLoc")) { if (DEBUG) plugin.getLogger().info("DEBUG: has meta"); // Get the meta data List<MetadataValue> values = entity.getMetadata("spawnLoc"); for (MetadataValue v : values) { // There is a chance another plugin also uses the meta data spawnLoc if (v.getOwningPlugin().equals(plugin)) { // Get the island spawn location Location spawnLoc = Util.getLocationString(v.asString()); if (DEBUG) plugin.getLogger().info("DEBUG: entity spawnLoc = " + spawnLoc); if (spawnLoc != null && spawnLoc.equals(island.getCenter())) { // Entity is on this island count++; if (DEBUG) plugin.getLogger().info("DEBUG: entity is on island. Number = " + count); if (count >= Settings.entityLimits.get(ent.getType())) { // No more allowed! if (DEBUG) plugin.getLogger().info("DEBUG: no more allowed! >=" + count); break checkLimits; } } } } } } } } // Okay to spawn, but tag it ent.setMetadata("spawnLoc", new FixedMetadataValue(plugin, Util.getStringLocation(island.getCenter()))); if (DEBUG) plugin.getLogger().info("DEBUG: spawn okay"); return false; } // Cancel - no spawning - tell nearby players if (DEBUG) plugin.getLogger().info("DEBUG: spawn cancelled"); return true; } }