diff --git a/Level/config.yml b/Level/config.yml new file mode 100644 index 0000000..15b3707 --- /dev/null +++ b/Level/config.yml @@ -0,0 +1,305 @@ +# This file lists the values for various blocks that are used to calculate the +# island level. Level = total of all blocks in island boundary / 100. +# Players with the permission askyblock.island.multiplier.# will have their blocks +# multiplied in value by that amount. + +# Underwater block multiplier +# If blocks are below sea-level, they can have a higher value. e.g. 2x +# Promotes under-water development if there is a sea. Value can be fractional. +underwater: 1.0 + +# Value of one island level. Default 100. Minimum value is 1. +levelcost: 100 + +# Cooldown between level requests in seconds +levelwait: 60 + +# Death penalty +# How many block values a player will lose per death. +# Default value of 100 means that for every death, the player will lose 1 level (if levelcost is 100) +# Set to zero to not use this feature +deathpenalty: 100 +# Sum team deaths - if true, all the teams deaths are summed +# If false, only the leader's deaths counts +sumteamdeaths: false +# Max deaths +# If player dies more than this, it doesn't count anymore +# Stops players from getting into an impossible situation +maxdeaths: 10 +# Reset deaths on island reset +islandresetdeathreset: true +# Reset deaths on team join +teamjoindeathreset: true + + +# This section lists the limits for any particular block. Blocks over this amount +# are not counted. +# Format: +# MATERIAL: limit or MATERIAL:DATA: limit. +# If DATA is used, there MUST be a corresponding block:data value in the blocks list. +# For example, if you limit Jungle Logs LOG:3, then there must be a value for LOG:3 +# in the blocks section. If there is not, then LOG:3 would have no value. +limits: + COBBLESTONE: 10000 + NETHERRACK: 1000 + #LOG:3: 10 + +# This section lists the value of a block. Value must be an integer. +# Any blocks not listed will have a value of zero. +# Format is MATERIAL: value or MATERIAL:DATA: value. + +blocks: + ACACIA_DOOR: 1 + ACACIA_STAIRS: 1 + ACACIA_FENCE: 1 + ACACIA_FENCE_GATE: 1 + ACACIA_STAIRS: 2 + ACTIVATOR_RAIL: 10 + AIR: 0 + ANVIL: 10 + ARMOR_STAND: 2 + BANNER: 2 + BEACON: 100 + BED_BLOCK: 1 + BEDROCK: 0 + BEETROOT_BLOCK: 1 + BIRCH_DOOR: 1 + BIRCH_FENCE: 1 + BIRCH_FENCE_GATE: 1 + BIRCH_WOOD_STAIRS: 1 + BLACK_GLAZED_TERRACOTTA: 1 + BLACK_SHULKER_BOX: 1 + BLUE_GLAZED_TERRACOTTA: 1 + BLUE_SHULKER_BOX: 1 + BOAT: 2 + BOAT_ACACIA: 2 + BOAT_BIRCH: 2 + BOAT_DARK_OAK: 2 + BOAT_JUNGLE: 2 + BOAT_SPRUCE: 2 + BONE_BLOCK: 1 + BOOKSHELF: 5 + BREWING_STAND: 20 + BRICK: 5 + BRICK_STAIRS: 5 + BROWN_GLAZED_TERRACOTTA: 1 + BROWN_SHULKER_BOX: 1 + BURNING_FURNACE: 10 + CACTUS: 1 + CAKE_BLOCK: 1 + CARPET: 1 + CAULDRON: 10 + CHEST: 2 + CHORUS_FLOWER: 1 + CHORUS_PLANT: 1 + CLAY: 2 + COAL_BLOCK: 9 + COAL_ORE: 0 + COBBLE_WALL: 1 + COBBLESTONE: 1 + COBBLESTONE_STAIRS: 1 + COCOA: 1 + CONCRETE: 1 + CONCRETE_POWDER: 1 + CYAN_GLAZED_TERRACOTTA: 1 + CYAN_SHULKER_BOX: 1 + DARK_OAK_DOOR: 1 + DARK_OAK_FENCE: 1 + DARK_OAK_FENCE_GATE: 1 + DARK_OAK_STAIRS: 1 + DAYLIGHT_DETECTOR: 10 + DAYLIGHT_DETECTOR_INVERTED: 10 + DEAD_BUSH: 1 + DETECTOR_RAIL: 10 + DIAMOND_BLOCK: 300 + DIODE: 5 + DIODE_BLOCK_OFF: 5 + DIODE_BLOCK_ON: 5 + DIRT: 2 + DISPENSER: 5 + DOUBLE_PLANT: 2 + DOUBLE_STEP: 1 + DOUBLE_STONE_SLAB2: 1 + DRAGON_EGG: 150 + DROPPER: 5 + EMERALD_BLOCK: 150 + EMERALD_ORE: 0 + ENCHANTMENT_TABLE: 150 + END_BRICKS: 2 + ENDER_CHEST: 150 + ENDER_PORTAL_FRAME: 0 + ENDER_PORTAL: 0 + ENDER_STONE: 2 + EXPLOSIVE_MINECART: 10 + FENCE: 1 + FENCE_GATE: 1 + FIRE: 0 + FLOWER_POT: 5 + FROSTED_ICE: 1 + FURNACE: 10 + GLASS: 2 + GLOWSTONE: 1 + GOLD_BLOCK: 150 + GOLD_ORE: 0 + GRASS: 5 + GRASS_PATH: 5 + GRAY_GLAZED_TERRACOTTA: 1 + GRAY_SHULKER_BOX: 1 + GRAVEL: 1 + GREEN_GLAZED_TERRACOTTA: 1 + GREEN_SHULKER_BOX: 1 + HARD_CLAY: 2 + HAY_BLOCK: 2 + HOPPER: 10 + HOPPER_MINECART: 20 + HUGE_MUSHROOM_1: 1 + HUGE_MUSHROOM_2: 1 + ICE: 5 + IRON_BLOCK: 10 + IRON_DOOR_BLOCK: 5 + IRON_FENCE: 5 + IRON_ORE: 0 + IRON_PLATE: 5 + IRON_TRAPDOOR: 1 + ITEM_FRAME: 2 + JACK_O_LANTERN: 1 + JUKEBOX: 10 + JUNGLE_DOOR: 1 + JUNGLE_FENCE: 1 + JUNGLE_FENCE_GATE: 1 + JUNGLE_WOOD_STAIRS: 1 + LADDER: 1 + LAPIS_BLOCK: 10 + LAPIS_ORE: 0 + LAVA: 0 + LEAVES_2: 1 + LEAVES: 1 + LEVER: 1 + LIGHT_BLUE_GLAZED_TERRACOTTA: 1 + LIGHT_BLUE_SHULKER_BOX: 1 + LIME_GLAZED_TERRACOTTA: 1 + LIME_SHULKER_BOX: 1 + LOG: 1 + #Other log types - examples + #LOG:3: 2 + LOG_2: 1 + LONG_GRASS: 1 + MAGENTA_GLAZED_TERRACOTTA: 1 + MAGENTA_SHULKER_BOX: 1 + MAGMA: 1 + MELON_BLOCK: 1 + MELON_STEM: 1 + MINECART: 10 + MOB_SPAWNER: 0 + MOSSY_COBBLESTONE: 2 + MYCEL: 5 + NETHER_BRICK: 2 + NETHER_BRICK_STAIRS: 2 + NETHER_FENCE: 2 + NETHER_STALK: 1 + NETHER_WART_BLOCK: 2 + NETHERRACK: 1 + NOTE_BLOCK: 10 + OBSERVER: 1 + OBSIDIAN: 10 + ORANGE_GLAZED_TERRACOTTA: 1 + ORANGE_SHULKER_BOX: 1 + PACKED_ICE: 5 + PAINTING: 2 + PINK_GLAZED_TERRACOTTA: 1 + PINK_SHULKER_BOX: 1 + PISTON_BASE: 2 + PISTON_STICKY_BASE: 2 + PORTAL: 0 + POWERED_MINECART: 10 + POWERED_RAIL: 10 + PRISMARINE: 10 + PUMPKIN_STEM: 1 + PUMPKIN: 1 + PURPLE_GLAZED_TERRACOTTA: 1 + PURPLE_SHULKER_BOX: 1 + PURPUR_BLOCK: 1 + PURPUR_DOUBLE_SLAB: 1 + PURPUR_PILLAR: 1 + PURPUR_SLAB: 1 + PURPUR_STAIRS: 1 + QUARTZ_BLOCK: 1 + QUARTZ_ORE: 0 + QUARTZ_STAIRS: 1 + QUARTZ: 1 + RAILS: 1 + RED_GLAZED_TERRACOTTA: 1 + RED_MUSHROOM: 1 + RED_NETHER_BRICK: 2 + RED_ROSE: 1 + RED_SANDSTONE: 1 + RED_SANDSTONE_STAIRS: 1 + RED_SHULKER_BOX: 1 + REDSTONE_BLOCK: 10 + REDSTONE_COMPARATOR_OFF: 10 + REDSTONE_COMPARATOR_ON: 10 + REDSTONE_COMPARATOR: 10 + REDSTONE_LAMP_OFF: 10 + REDSTONE_LAMP_ON: 10 + REDSTONE_ORE: 0 + REDSTONE_TORCH_OFF: 5 + REDSTONE_TORCH_ON: 5 + REDSTONE_WIRE: 1 + SAND: 1 + SANDSTONE: 1 + SANDSTONE_STAIRS: 1 + SEA_LANTERN: 1 + SIGN_POST: 1 + SILVER_GLAZED_TERRACOTTA: 1 + SILVER_SHULKER_BOX: 1 + SKULL: 10 + SLIME_BLOCK: 10 + SMOOTH_BRICK: 2 + SMOOTH_STAIRS: 2 + SNOW_BLOCK: 1 + SOIL: 2 + SOUL_SAND: 2 + SPONGE: 10 + SPRUCE_DOOR: 1 + SPRUCE_FENCE: 1 + SPRUCE_FENCE_GATE: 1 + SPRUCE_WOOD_STAIRS: 1 + STAINED_CLAY: 2 + STAINED_GLASS: 2 + STAINED_GLASS_PANE: 1 + STATIONARY_LAVA: 0 + STATIONARY_WATER: 0 + STEP: 1 + STONE: 1 + STONE_BUTTON: 1 + STONE_PLATE: 2 + STORAGE_MINECART: 10 + SUGAR_CANE_BLOCK: 1 + THIN_GLASS: 1 + TNT: 5 + TORCH: 2 + TRAP_DOOR: 5 + TRAPPED_CHEST: 10 + TRIPWIRE_HOOK: 2 + TRIPWIRE: 2 + VINE: 1 + WALL_SIGN: 1 + WATER_LILY: 5 + WEB: 10 + WHEAT: 1 + WHITE_GLAZED_TERRACOTTA: 1 + WHITE_SHULKER_BOX: 1 + WOOD: 1 + WOOD_BUTTON: 1 + WOOD_DOOR: 1 + WOOD_DOUBLE_STEP: 1 + WOOD_PLATE: 1 + WOOD_STAIRS: 1 + WOOD_STEP: 1 + WOODEN_DOOR: 1 + WOOL: 1 + WORKBENCH: 1 + YELLOW_FLOWER: 1 + YELLOW_GLAZED_TERRACOTTA: 1 + YELLOW_SHULKER_BOX: 1 + \ No newline at end of file diff --git a/Level/locales/bsb_en_US.yml b/Level/locales/bsb_en_US.yml new file mode 100755 index 0000000..8c3e1f0 --- /dev/null +++ b/Level/locales/bsb_en_US.yml @@ -0,0 +1,15 @@ +########################################################################################### +# This is a YML file. Be careful when editing. Check your edits in a YAML checker like # +# the one at http://yaml-online-parser.appspot.com # +########################################################################################### + +### Credits ### +# Tastybento: maintainer +# Poslovitch: maintainer +# +# This translation is adapted to version : [alpha-0.0.1] + +island: + islandLevelIs: "Island level is" + requiredPointsToNextLevel: "[points] points required until the next level" +levelDeaths: "([number] deaths)" \ No newline at end of file diff --git a/Level/pom.xml b/Level/pom.xml index da19790..e96246d 100644 --- a/Level/pom.xml +++ b/Level/pom.xml @@ -20,6 +20,14 @@ *.yml + + locales + false + ${basedir}/locales + + *.yml + + diff --git a/Level/src/bskyblock/addin/level/Level.java b/Level/src/bskyblock/addin/level/Level.java index 6a5fe19..075f604 100644 --- a/Level/src/bskyblock/addin/level/Level.java +++ b/Level/src/bskyblock/addin/level/Level.java @@ -1,20 +1,52 @@ package bskyblock.addin.level; +import java.util.Calendar; +import java.util.HashMap; import java.util.Set; +import java.util.UUID; +import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; +import bskyblock.addin.level.config.LocaleManager; +import bskyblock.addin.level.config.PluginConfig; import us.tastybento.bskyblock.BSkyBlock; import us.tastybento.bskyblock.api.commands.ArgumentHandler; import us.tastybento.bskyblock.api.commands.CanUseResp; +import us.tastybento.bskyblock.config.BSBLocale; +import us.tastybento.bskyblock.config.Settings; +import us.tastybento.bskyblock.util.Util; +import us.tastybento.bskyblock.util.VaultHelper; public class Level extends JavaPlugin { + + private BSkyBlock bSkyBlock; + + // Level calc cool down + private HashMap levelWaitTime = new HashMap(); + + // Level calc checker + BukkitTask checker = null; + + private int levelWait; + + private LocaleManager localeManager; + + private HashMap islandLevel; + @Override - public void onEnable(){ - BSkyBlock plugin = BSkyBlock.getPlugin(); - plugin.getIslandCommand().addSubCommand(new ArgumentHandler("island") { + public void onEnable() { + new PluginConfig(this); + bSkyBlock = BSkyBlock.getPlugin(); + islandLevel = new HashMap<>(); + new TopTen(this); + // Local locales + localeManager = new LocaleManager(this); + bSkyBlock.getIslandCommand().addSubCommand(new ArgumentHandler("island") { @Override public CanUseResp canUse(CommandSender sender) { @@ -23,7 +55,23 @@ public class Level extends JavaPlugin { @Override public void execute(CommandSender sender, String[] args) { - sender.sendMessage("Your island level is XXX"); + if (sender instanceof Player) { + Player player = (Player)sender; + UUID playerUUID = player.getUniqueId(); + + if (VaultHelper.hasPerm(player, Settings.PERMPREFIX + "island.info")) { + if (!bSkyBlock.getPlayers().inTeam(playerUUID) && !bSkyBlock.getPlayers().hasIsland(playerUUID)) { + Util.sendMessage(player, ChatColor.RED + bSkyBlock.getLocale(sender).get("error.noisland")); + return; + } else { + calculateIslandLevel(player, playerUUID); + return; + } + } else { + //Util.sendMessage(player, ChatColor.RED + bSkyBlock.myLocale(playerUUID).errorNoPermission); + return; + } + } } @Override @@ -45,4 +93,112 @@ public class Level extends JavaPlugin { } + /** + * Calculates the island level + * + * @param sender + * - Player object of player who is asking + * @param targetPlayer + * - UUID of the player's island that is being requested + * @return - true if successful. + */ + public boolean calculateIslandLevel(final CommandSender sender, final UUID targetPlayer) { + return calculateIslandLevel(sender, targetPlayer, false); + } + + /** + * Calculates the island level + * @param sender - asker of the level info + * @param targetPlayer + * @param report - if true, a detailed report will be provided + * @return - false if this is cannot be done + */ + public boolean calculateIslandLevel(final CommandSender sender, final UUID targetPlayer, boolean report) { + if (sender instanceof Player) { + Player asker = (Player)sender; + // Player asking for their own island calc + if (asker.getUniqueId().equals(targetPlayer) || asker.isOp() || VaultHelper.hasPerm(asker, Settings.PERMPREFIX + "mod.info")) { + // Newer better system - uses chunks + if (!onLevelWaitTime(asker) || levelWait <= 0 || asker.isOp() || VaultHelper.hasPerm(asker, Settings.PERMPREFIX + "mod.info")) { + Util.sendMessage(asker, ChatColor.GREEN + "Calculating level, please wait..."); + setLevelWaitTime(asker); + new LevelCalcByChunk(this, bSkyBlock, targetPlayer, asker, report); + } else { + Util.sendMessage(asker, ChatColor.YELLOW + String.valueOf(getLevelWaitTime(asker))); + } + + } else { + // Asking for the level of another player + //Util.sendMessage(asker, ChatColor.GREEN + bSkyBlock.myLocale(asker.getUniqueId()).islandislandLevelis.replace("[level]", String.valueOf(bSkyBlock.getIslands().getIslandLevel(targetPlayer)))); + } + } else { + // Console request + //Util.sendMessage(sender, ChatColor.GREEN + bSkyBlock.myLocale().levelCalculating); + new LevelCalcByChunk(this, bSkyBlock, targetPlayer, sender, report); + } + return true; + } + + /** + * Sets cool down for the level command + * + * @param player + */ + private void setLevelWaitTime(final Player player) { + levelWaitTime.put(player.getUniqueId(), Long.valueOf(Calendar.getInstance().getTimeInMillis() + levelWait * 1000)); + } + + public boolean onLevelWaitTime(final Player player) { + if (levelWaitTime.containsKey(player.getUniqueId())) { + if (levelWaitTime.get(player.getUniqueId()).longValue() > Calendar.getInstance().getTimeInMillis()) { + return true; + } + + return false; + } + + return false; + } + + private long getLevelWaitTime(final Player player) { + if (levelWaitTime.containsKey(player.getUniqueId())) { + if (levelWaitTime.get(player.getUniqueId()).longValue() > Calendar.getInstance().getTimeInMillis()) { + return (levelWaitTime.get(player.getUniqueId()).longValue() - Calendar.getInstance().getTimeInMillis()) / 1000; + } + + return 0L; + } + + return 0L; + } + + public long getIslandLevel(UUID targetPlayer) { + //getLogger().info("DEBUG: getting island level for " + bSkyBlock.getPlayers().getName(targetPlayer)); + if (islandLevel.containsKey(targetPlayer)) + return islandLevel.get(targetPlayer); + return 0; + } + + public void setIslandLevel(UUID targetPlayer, long level) { + //getLogger().info("DEBUG: set island level to " + level + " for " + bSkyBlock.getPlayers().getName(targetPlayer)); + islandLevel.put(targetPlayer, level); + + } + + /** + * @param sender + * @return Locale object for sender + */ + public BSBLocale getLocale(CommandSender sender) { + return localeManager.getLocale(sender); + } + + /** + * @param uuid + * @return Locale object for UUID + */ + public BSBLocale getLocale(UUID uuid) { + return localeManager.getLocale(uuid); + } + } diff --git a/Level/src/bskyblock/addin/level/LevelCalcByChunk.java b/Level/src/bskyblock/addin/level/LevelCalcByChunk.java new file mode 100644 index 0000000..f617dbf --- /dev/null +++ b/Level/src/bskyblock/addin/level/LevelCalcByChunk.java @@ -0,0 +1,496 @@ +package bskyblock.addin.level; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import org.apache.commons.lang.math.NumberUtils; +import org.bukkit.ChatColor; +import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.material.MaterialData; +import org.bukkit.permissions.PermissionAttachmentInfo; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.google.common.collect.Multiset.Entry; +import com.google.common.collect.Multisets; + +import bskyblock.addin.level.config.Settings; +import bskyblock.addin.level.event.IslandPostLevelEvent; +import bskyblock.addin.level.event.IslandPreLevelEvent; +import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.database.objects.Island; +import us.tastybento.bskyblock.util.Util; + +/** + * A class that calculates the level of an island very quickly by copying island + * chunks to a list and then processing asynchronously. + * + * @author tastybento + * + */ +public class LevelCalcByChunk { + private static final boolean DEBUG = false; + protected static final boolean LEVEL_LOGGING = false; + private List reportLines = new ArrayList(); + + public LevelCalcByChunk(Level plugin, BSkyBlock bSkyBlock, UUID targetPlayer, CommandSender asker) { + this(plugin, bSkyBlock, targetPlayer, asker, false); + } + + /** + * Calculates the level of an island + * @param bSkyBlock + * @param targetPlayer - UUID of island owner or team member + * @param sender - requester of the level calculation, if anyone + * @param report - provide a report to the asker + */ + public LevelCalcByChunk(final Level plugin, final BSkyBlock bSkyBlock, final UUID targetPlayer, final CommandSender sender, final boolean report) { + // Get player's island + final Island island = bSkyBlock.getIslands().getIsland(targetPlayer); + if (DEBUG) + plugin.getLogger().info("DEBUG: " + island); + if (island != null) { + // Get the permission multiplier if it is available + Player player = plugin.getServer().getPlayer(targetPlayer); + int multiplier = 1; + if (player != null) { + if (DEBUG) + plugin.getLogger().info("DEBUG: player is online"); + // Get permission multiplier + for (PermissionAttachmentInfo perms : player.getEffectivePermissions()) { + if (perms.getPermission().startsWith(Settings.PERMPREFIX + "island.multiplier.")) { + String spl[] = perms.getPermission().split(Settings.PERMPREFIX + "island.multiplier."); + if (spl.length > 1) { + if (!NumberUtils.isDigits(spl[1])) { + bSkyBlock.getLogger().severe("Player " + player.getName() + " has permission: " + perms.getPermission() + " <-- the last part MUST be a number! Ignoring..."); + } else { + // Get the max value should there be more than one + multiplier = Math.max(multiplier, Integer.valueOf(spl[1])); + } + } + } + // Do some sanity checking + if (multiplier < 1) { + multiplier = 1; + } + } + if (DEBUG) + plugin.getLogger().info("DEBUG: multiplier = " + multiplier); + } + final int levelMultiplier = multiplier; + // Get the handicap + final int levelHandicap = island.getLevelHandicap(); + if (DEBUG) + plugin.getLogger().info("DEBUG: island level handicap = " + levelHandicap); + // Get the death handicap + int deaths = bSkyBlock.getPlayers().getDeaths(targetPlayer); + if (DEBUG) + plugin.getLogger().info("DEBUG: deaths = " + deaths); + if (bSkyBlock.getPlayers().inTeam(targetPlayer)) { + if (DEBUG) + plugin.getLogger().info("DEBUG: player is in a team"); + // Get the team leader's deaths + deaths = bSkyBlock.getPlayers().getDeaths(bSkyBlock.getIslands().getTeamLeader(targetPlayer)); + if (Settings.sumTeamDeaths) { + deaths = 0; + //plugin.getLogger().info("DEBUG: player is in team"); + for (UUID member : bSkyBlock.getIslands().getMembers(targetPlayer)) { + deaths += bSkyBlock.getPlayers().getDeaths(member); + } + } + if (DEBUG) + plugin.getLogger().info("DEBUG: deaths is now = " + deaths); + } + final int deathHandicap = deaths; + // Check if player's island world is the nether or overworld and adjust accordingly + final World world = bSkyBlock.getIslands().getIslandLocation(targetPlayer).getWorld(); + // Get the chunks + if (DEBUG) + plugin.getLogger().info("DEBUG: Getting chunks. Protection range = " + island.getProtectionRange()); + //long nano = System.nanoTime(); + Set chunkSnapshot = new HashSet(); + for (int x = island.getMinProtectedX(); x < (island.getMinProtectedX() + (island.getProtectionRange() *2) + 16); x += 16) { + for (int z = island.getMinProtectedZ(); z < (island.getMinProtectedZ() + (island.getProtectionRange() * 2) + 16); z += 16) { + if (!world.isChunkLoaded((int)((double)x/16), (int)((double)z/16))) { + //plugin.getLogger().info("DEBUG: chunk is not loaded"); + // If the chunk isn't already generated, don't try and generate it + if (world.loadChunk((int)((double)x/16), (int)((double)z/16), false)) { + //plugin.getLogger().info("DEBUG: chunk loaded"); + Chunk chunk = world.getChunkAt((int)((double)x/16), (int)((double)z/16)); + chunkSnapshot.add(chunk.getChunkSnapshot()); + //plugin.getLogger().info("DEBUG: unload = " + chunk.unload(false)); + } + } else { + //plugin.getLogger().info("DEBUG: chunk is loaded"); + chunkSnapshot.add(world.getBlockAt(x, 0, z).getChunk().getChunkSnapshot()); + } + if (DEBUG) + plugin.getLogger().info("DEBUG: getting chunk at " + x + ", " + z); + } + } + //plugin.getLogger().info("DEBUG: time = " + (System.nanoTime() - nano) / 1000000 + " ms"); + if (DEBUG) + plugin.getLogger().info("DEBUG: size of chunk snapshot = " + chunkSnapshot.size()); + final Set finalChunk = chunkSnapshot; + final int worldHeight = world.getMaxHeight(); + //plugin.getLogger().info("DEBUG:world height = " +worldHeight); + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { + + @Override + public void run() { + // Logging + List mdLog = null; + List uwLog = null; + List noCountLog = null; + List overflowLog = null; + if (LEVEL_LOGGING || report) { + mdLog = new ArrayList(); + uwLog = new ArrayList(); + noCountLog = new ArrayList(); + overflowLog = new ArrayList(); + } + // Copy the limits hashmap + HashMap limitCount = new HashMap(Settings.blockLimits); + // Calculate the island score + long blockCount = 0; + long underWaterBlockCount = 0; + for (ChunkSnapshot chunk: finalChunk) { + for (int x = 0; x< 16; x++) { + // Check if the block coord is inside the protection zone and if not, don't count it + if (chunk.getX() * 16 + x < island.getMinProtectedX() || chunk.getX() * 16 + x >= island.getMinProtectedX() + (island.getProtectionRange() * 2)) { + if (DEBUG) + plugin.getLogger().info("Block is outside protected area - x = " + (chunk.getX() * 16 + x)); + continue; + } + for (int z = 0; z < 16; z++) { + // Check if the block coord is inside the protection zone and if not, don't count it + if (chunk.getZ() * 16 + z < island.getMinProtectedZ() || chunk.getZ() * 16 + z >= island.getMinProtectedZ() + (island.getProtectionRange() * 2)) { + if (DEBUG) + plugin.getLogger().info("Block is outside protected area - z = " + (chunk.getZ() * 16 + z)); + continue; + } + + for (int y = 0; y < worldHeight; y++) { + int type = chunk.getBlockTypeId(x, y, z); + int data = chunk.getBlockData(x, y, z); + MaterialData md = new MaterialData(type,(byte) data); + MaterialData generic = new MaterialData(type); + if (type != 0) { // AIR + if (DEBUG) + plugin.getLogger().info("Block is inside protected area " + (chunk.getX() * 16) + "," + (chunk.getZ() * 16 + z)); + if (DEBUG) + plugin.getLogger().info("Block is " + md + "[" + generic +"]"); + if (limitCount.containsKey(md) && Settings.blockValues.containsKey(md)) { + int count = limitCount.get(md); + if (DEBUG) + plugin.getLogger().info("DEBUG: Count for non-generic " + md + " is " + count); + if (count > 0) { + limitCount.put(md, --count); + if (Settings.seaHeight > 0 && y<=Settings.seaHeight) { + underWaterBlockCount += Settings.blockValues.get(md); + if (LEVEL_LOGGING || report) { + uwLog.add(md); + } + } else { + blockCount += Settings.blockValues.get(md); + if (LEVEL_LOGGING || report) { + mdLog.add(md); + } + } + } else if (LEVEL_LOGGING || report) { + overflowLog.add(md); + } + } else if (limitCount.containsKey(generic) && Settings.blockValues.containsKey(generic)) { + int count = limitCount.get(generic); + if (DEBUG) + plugin.getLogger().info("DEBUG: Count for generic " + generic + " is " + count); + if (count > 0) { + limitCount.put(generic, --count); + if (Settings.seaHeight > 0 && y<=Settings.seaHeight) { + underWaterBlockCount += Settings.blockValues.get(generic); + if (LEVEL_LOGGING || report) { + uwLog.add(md); + } + } else { + blockCount += Settings.blockValues.get(generic); + if (LEVEL_LOGGING || report) { + mdLog.add(md); + } + } + } else if (LEVEL_LOGGING || report) { + overflowLog.add(md); + } + } else if (Settings.blockValues.containsKey(md)) { + if (DEBUG) + plugin.getLogger().info("DEBUG: Adding " + md + " = " + Settings.blockValues.get(md)); + if (Settings.seaHeight > 0 && y<=Settings.seaHeight) { + underWaterBlockCount += Settings.blockValues.get(md); + if (LEVEL_LOGGING || report) { + uwLog.add(md); + } + } else { + blockCount += Settings.blockValues.get(md); + if (LEVEL_LOGGING || report) { + mdLog.add(md); + } + } + } else if (Settings.blockValues.containsKey(generic)) { + if (DEBUG) + plugin.getLogger().info("DEBUG: Adding " + generic + " = " + Settings.blockValues.get(generic)); + if (Settings.seaHeight > 0 && y<=Settings.seaHeight) { + underWaterBlockCount += Settings.blockValues.get(generic); + if (LEVEL_LOGGING || report) { + uwLog.add(md); + } + } else { + blockCount += Settings.blockValues.get(generic); + if (LEVEL_LOGGING || report) { + mdLog.add(md); + } + } + } else if (LEVEL_LOGGING || report) { + noCountLog.add(md); + } + } + } + } + } + } + + blockCount += (long)((double)underWaterBlockCount * Settings.underWaterMultiplier); + if (DEBUG) + plugin.getLogger().info("DEBUG: block count = "+blockCount); + + final long score = (((blockCount * levelMultiplier) - (deathHandicap * Settings.deathpenalty)) / Settings.levelCost) - levelHandicap; + // Logging or report + if (LEVEL_LOGGING || report) { + // provide counts + Multiset uwCount = HashMultiset.create(uwLog); + Multiset mdCount = HashMultiset.create(mdLog); + Multiset ncCount = HashMultiset.create(noCountLog); + Multiset ofCount = HashMultiset.create(overflowLog); + reportLines.add("Level Log for island at " + island.getCenter()); + if (sender instanceof Player) { + reportLines.add("Asker is " + sender.getName() + " (" + ((Player)sender).getUniqueId().toString() + ")"); + } else { + reportLines.add("Asker is console"); + } + reportLines.add("Target player UUID = " + targetPlayer.toString()); + reportLines.add("Total block value count = " + String.format("%,d",blockCount)); + reportLines.add("Level cost = " + Settings.levelCost); + reportLines.add("Level multiplier = " + levelMultiplier + " (Player must be online to get a permission multiplier)"); + reportLines.add("Schematic level handicap = " + levelHandicap + " (level is reduced by this amount)"); + reportLines.add("Deaths handicap = " + (deathHandicap * Settings.deathpenalty) + " (" + deathHandicap + " deaths)"); + reportLines.add("Level calculated = " + score); + reportLines.add("=================================="); + int total = 0; + if (!uwCount.isEmpty()) { + reportLines.add("Underwater block count (Multiplier = x" + Settings.underWaterMultiplier + ") value"); + reportLines.add("Total number of underwater blocks = " + String.format("%,d",uwCount.size())); + Iterable> entriesSortedByCount = + Multisets.copyHighestCountFirst(uwCount).entrySet(); + Iterator> it = entriesSortedByCount.iterator(); + while (it.hasNext()) { + Entry type = it.next(); + int value = 0; + if (Settings.blockValues.containsKey(type)) { + // Specific + value = Settings.blockValues.get(type); + } else if (Settings.blockValues.containsKey(new MaterialData(type.getElement().getItemType()))) { + // Generic + value = Settings.blockValues.get(new MaterialData(type.getElement().getItemType())); + } + if (value > 0) { + reportLines.add(type.getElement().toString() + ":" + + String.format("%,d",type.getCount()) + " blocks x " + value + " = " + (value * type.getCount())); + total += (value * type.getCount()); + } + } + reportLines.add("Subtotal = " + total); + reportLines.add("=================================="); + } + reportLines.add("Regular block count"); + reportLines.add("Total number of blocks = " + String.format("%,d",mdCount.size())); + //Iterable> entriesSortedByCount = + // Multisets.copyHighestCountFirst(mdCount).entrySet(); + Iterable> entriesSortedByCount = + mdCount.entrySet(); + Iterator> it = entriesSortedByCount.iterator(); + while (it.hasNext()) { + Entry type = it.next(); + int value = 0; + if (Settings.blockValues.containsKey(type)) { + // Specific + value = Settings.blockValues.get(type); + } else if (Settings.blockValues.containsKey(new MaterialData(type.getElement().getItemType()))) { + // Generic + value = Settings.blockValues.get(new MaterialData(type.getElement().getItemType())); + } + if (value > 0) { + reportLines.add(type.getElement().toString() + ":" + + String.format("%,d",type.getCount()) + " blocks x " + value + " = " + (value * type.getCount())); + total += (value * type.getCount()); + } + } + reportLines.add("Total = " + total); + reportLines.add("=================================="); + reportLines.add("Blocks not counted because they exceeded limits: " + String.format("%,d",ofCount.size())); + //entriesSortedByCount = Multisets.copyHighestCountFirst(ofCount).entrySet(); + entriesSortedByCount = ofCount.entrySet(); + it = entriesSortedByCount.iterator(); + while (it.hasNext()) { + Entry type = it.next(); + Integer limit = Settings.blockLimits.get(type.getElement()); + String explain = ")"; + if (limit == null) { + MaterialData generic = new MaterialData(type.getElement().getItemType()); + limit = Settings.blockLimits.get(generic); + explain = " - All types)"; + } + reportLines.add(type.getElement().toString() + ": " + String.format("%,d",type.getCount()) + " blocks (max " + limit + explain); + } + reportLines.add("=================================="); + reportLines.add("Blocks on island that are not in blockvalues.yml"); + reportLines.add("Total number = " + String.format("%,d",ncCount.size())); + //entriesSortedByCount = Multisets.copyHighestCountFirst(ncCount).entrySet(); + entriesSortedByCount = ncCount.entrySet(); + it = entriesSortedByCount.iterator(); + while (it.hasNext()) { + Entry type = it.next(); + reportLines.add(type.getElement().toString() + ": " + String.format("%,d",type.getCount()) + " blocks"); + } + reportLines.add("================================="); + } + + // Calculate how many points are required to get to the next level + long calculatePointsToNextLevel = (Settings.levelCost * (score + 1 + levelHandicap)) - ((blockCount * levelMultiplier) - (deathHandicap * Settings.deathpenalty)); + // Sometimes it will return 0, so calculate again to make sure it will display a good value + if(calculatePointsToNextLevel == 0) calculatePointsToNextLevel = (Settings.levelCost * (score + 2 + levelHandicap)) - ((blockCount * levelMultiplier) - (deathHandicap * Settings.deathpenalty)); + + final long pointsToNextLevel = calculatePointsToNextLevel; + + // Return to main thread + plugin.getServer().getScheduler().runTask(plugin, new Runnable() { + + @Override + public void run() { + // Fire the pre-level event + Island island = bSkyBlock.getIslands().getIsland(targetPlayer); + final IslandPreLevelEvent event = new IslandPreLevelEvent(targetPlayer, island, score); + event.setPointsToNextLevel(pointsToNextLevel); + plugin.getServer().getPluginManager().callEvent(event); + long oldLevel = plugin.getIslandLevel(targetPlayer); + if (!event.isCancelled()) { + if (DEBUG) + plugin.getLogger().info("DEBUG: updating player"); + + if (oldLevel != event.getLevel()) { + // Update player and team mates + plugin.setIslandLevel(targetPlayer, event.getLevel()); + if (DEBUG) + plugin.getLogger().info("DEBUG: set island level, now trying to save player"); + bSkyBlock.getPlayers().save(targetPlayer); + } + if (DEBUG) + plugin.getLogger().info("DEBUG: save player, now looking at team members"); + // Update any team members too + if (bSkyBlock.getPlayers().inTeam(targetPlayer)) { + //plugin.getLogger().info("DEBUG: player is in team"); + for (UUID member : bSkyBlock.getIslands().getMembers(targetPlayer)) { + //plugin.getLogger().info("DEBUG: updating team member level too"); + if (plugin.getIslandLevel(member) != event.getLevel()) { + plugin.setIslandLevel(member, event.getLevel()); + bSkyBlock.getPlayers().save(member); + } + } + } + if (DEBUG) { + plugin.getLogger().info("DEBUG: finished team member saving"); + plugin.getLogger().info("DEBUG: updating top ten"); + } + if (bSkyBlock.getPlayers().inTeam(targetPlayer)) { + UUID leader = bSkyBlock.getIslands().getTeamLeader(targetPlayer); + if (leader != null) { + TopTen.topTenAddEntry(leader, event.getLevel()); + } + } else { + TopTen.topTenAddEntry(targetPlayer, event.getLevel()); + } + } + + // Fire the island post level calculation event + final IslandPostLevelEvent event3 = new IslandPostLevelEvent(targetPlayer, island, event.getLevel(), event.getPointsToNextLevel()); + bSkyBlock.getServer().getPluginManager().callEvent(event3); + + if(!event3.isCancelled()){ + // Check that sender still is online + if (sender != null) { + // Check if console + if (!(sender instanceof Player)) { + // Console + if (!report) { + Util.sendMessage(sender, ChatColor.GREEN + plugin.getLocale(sender).get("island.islandLevelIs") + " " + ChatColor.WHITE + plugin.getIslandLevel(targetPlayer)); + } else { + for (String line: reportLines) { + Util.sendMessage(sender, line); + } + Util.sendMessage(sender, ChatColor.GREEN + plugin.getLocale(sender).get("island.islandLevelIs") + " " + ChatColor.WHITE + plugin.getIslandLevel(targetPlayer)); + if (event.getPointsToNextLevel() >= 0) { + String toNextLevel = ChatColor.GREEN + plugin.getLocale(sender).get("island.requiredPointsToNextLevel").replace("[points]", String.valueOf(event.getPointsToNextLevel())); + toNextLevel = toNextLevel.replace("[next]", String.valueOf(plugin.getIslandLevel(targetPlayer) + 1)); + Util.sendMessage(sender, toNextLevel); + } + } + } else { + // Player + if (!report) { + // Tell offline team members the island level changed + if (plugin.getIslandLevel(targetPlayer) != oldLevel) { + //plugin.getLogger().info("DEBUG: telling offline players"); + //bSkyBlock.getMessages().tellOfflineTeam(targetPlayer, ChatColor.GREEN + bSkyBlock.myLocale(targetPlayer).islandislandLevelis + " " + ChatColor.WHITE + // + plugin.getIslandLevel(targetPlayer)); + } + if (sender instanceof Player && ((Player)sender).isOnline()) { + String message = ChatColor.GREEN + plugin.getLocale(sender).get("island.islandLevelIs") + " " + ChatColor.WHITE + plugin.getIslandLevel(targetPlayer); + if (Settings.deathpenalty != 0) { + message += " " + plugin.getLocale(sender).get("levelDeaths").replace("[number]", String.valueOf(deathHandicap)); + } + Util.sendMessage(sender, message); + //Send player how many points are required to reach next island level + if (event.getPointsToNextLevel() >= 0) { + String toNextLevel = ChatColor.GREEN + plugin.getLocale(sender).get("island.requiredPointsToNextLevel").replace("[points]", String.valueOf(event.getPointsToNextLevel())); + toNextLevel = toNextLevel.replace("[next]", String.valueOf(plugin.getIslandLevel(targetPlayer) + 1)); + Util.sendMessage(sender, toNextLevel); + } + } + } else { + if (((Player)sender).isOnline()) { + for (String line: reportLines) { + Util.sendMessage(sender, line); + } + } + Util.sendMessage(sender, ChatColor.GREEN + plugin.getLocale(sender).get("island.islandLevelIs") + " " + ChatColor.WHITE + plugin.getIslandLevel(targetPlayer)); + if (event.getPointsToNextLevel() >= 0) { + String toNextLevel = ChatColor.GREEN + plugin.getLocale(sender).get("island.requiredPointsToNextLevel").replace("[points]", String.valueOf(event.getPointsToNextLevel())); + toNextLevel = toNextLevel.replace("[next]", String.valueOf(plugin.getIslandLevel(targetPlayer) + 1)); + Util.sendMessage(sender, toNextLevel); + } + } + } + } + } + }}); + }}); + } + } + +} diff --git a/Level/src/bskyblock/addin/level/MapUtil.java b/Level/src/bskyblock/addin/level/MapUtil.java new file mode 100644 index 0000000..0116a77 --- /dev/null +++ b/Level/src/bskyblock/addin/level/MapUtil.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * This file is part of ASkyBlock. + * + * ASkyBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ASkyBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASkyBlock. If not, see . + *******************************************************************************/ +package bskyblock.addin.level; + +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * @author tastybento + */ +public class MapUtil { + /** + * Sorts map in descending order + * + * @param map + * @return + */ + public static > LinkedHashMap sortByValue(Map map) { + List> list = new LinkedList>(map.entrySet()); + Collections.sort(list, new Comparator>() { + public int compare(Map.Entry o1, Map.Entry o2) { + // Switch these two if you want ascending + return (o2.getValue()).compareTo(o1.getValue()); + } + }); + + LinkedHashMap result = new LinkedHashMap(); + for (Map.Entry entry : list) { + result.put(entry.getKey(), entry.getValue()); + if (result.size() > 20) + break; + } + return result; + } +} diff --git a/Level/src/bskyblock/addin/level/TopTen.java b/Level/src/bskyblock/addin/level/TopTen.java new file mode 100644 index 0000000..597019f --- /dev/null +++ b/Level/src/bskyblock/addin/level/TopTen.java @@ -0,0 +1,284 @@ +/******************************************************************************* + * This file is part of ASkyBlock. + * + * ASkyBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ASkyBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASkyBlock. If not, see . + *******************************************************************************/ + +package bskyblock.addin.level; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; + +import bskyblock.addin.level.config.Settings; +import us.tastybento.bskyblock.BSkyBlock; + +/** + * Handles all Top Ten List functions + * + * @author tastybento + * + */ +public class TopTen implements Listener{ + private static Level plugin; + // Top ten list of players + private static Map topTenList = new HashMap(); + private static final int GUISIZE = 27; // Must be a multiple of 9 + private static final int[] SLOTS = new int[] {4, 12, 14, 19, 20, 21, 22, 23, 24, 25}; + private static final boolean DEBUG = false; + // Store this as a static because it's the same for everyone and saves memory cleanup + private static Inventory gui; + + public TopTen(Level plugin) { + TopTen.plugin = plugin; + } + + /** + * Adds a player to the top ten, if the level is good enough + * + * @param ownerUUID + * @param l + */ + public static void topTenAddEntry(UUID ownerUUID, long l) { + // Special case for removals. If a level of zero is given the player + // needs to be removed from the list + if (l < 1) { + if (topTenList.containsKey(ownerUUID)) { + topTenList.remove(ownerUUID); + } + return; + } + // Try and see if the player is online + Player player = plugin.getServer().getPlayer(ownerUUID); + if (player != null) { + // Online + if (!player.hasPermission(Settings.PERMPREFIX + "intopten")) { + topTenList.remove(ownerUUID); + return; + } + } + topTenList.put(ownerUUID, l); + topTenList = MapUtil.sortByValue(topTenList); + } + + /** + * Removes ownerUUID from the top ten list + * + * @param ownerUUID + */ + public static void topTenRemoveEntry(UUID ownerUUID) { + topTenList.remove(ownerUUID); + } + + /** + * Generates a sorted map of islands for the Top Ten list from all player + * files + */ + public static void topTenCreate() { + topTenCreate(null); + } + + /** + * Creates the top ten list from scratch. Does not get the level of each island. Just + * takes the level from the player's file. + * Runs asynchronously from the main thread. + * @param sender + */ + public static void topTenCreate(final CommandSender sender) { + // TODO + } + + public static void topTenSave() { + if (topTenList == null) { + return; + } + plugin.getLogger().info("Saving top ten list"); + // Make file + File topTenFile = new File(plugin.getDataFolder(), "topten.yml"); + // Make configuration + YamlConfiguration config = new YamlConfiguration(); + // Save config + + int rank = 0; + for (Map.Entry m : topTenList.entrySet()) { + if (rank++ == 10) { + break; + } + config.set("topten." + m.getKey().toString(), m.getValue()); + } + try { + config.save(topTenFile); + plugin.getLogger().info("Saved top ten list"); + } catch (Exception e) { + plugin.getLogger().severe("Could not save top ten list!"); + e.printStackTrace(); + } + } + + /** + * Loads the top ten from the file system topten.yml. If it does not exist + * then the top ten is created + */ + public static void topTenLoad() { + topTenList.clear(); + // TODO + } + + /** + * Displays the Top Ten list if it exists in chat + * + * @param player + * - the requesting player + * @return - true if successful, false if no Top Ten list exists + */ + public static boolean topTenShow(final Player player) { + + if (DEBUG) + plugin.getLogger().info("DEBUG: new GUI display"); + // New GUI display (shown by default) + if (topTenList == null) topTenCreate(); + topTenList = MapUtil.sortByValue(topTenList); + // Create the top ten GUI if it does not exist + if (gui == null) { + gui = Bukkit.createInventory(null, GUISIZE, plugin.getLocale(player.getUniqueId()).get("topTenGuiTitle")); + if (DEBUG) + plugin.getLogger().info("DEBUG: creating GUI for the first time"); + } + // Reset + gui.clear(); + int i = 1; + Iterator> it = topTenList.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry m = it.next(); + UUID playerUUID = m.getKey(); + if (DEBUG) + plugin.getLogger().info("DEBUG: " + i + ": " + playerUUID); + // Remove from TopTen if the player is online and has the permission + Player entry = plugin.getServer().getPlayer(playerUUID); + boolean show = true; + if (entry != null) { + if (!entry.hasPermission(Settings.PERMPREFIX + "intopten")) { + it.remove(); + show = false; + } + } else { + if (DEBUG) + plugin.getLogger().info("DEBUG: player not online, so no per check"); + + } + if (show) { + gui.setItem(SLOTS[i-1], getSkull(i, m.getValue(), playerUUID)); + if (i++ == 10) break; + } + } + + player.openInventory(gui); + + return true; + } + + static ItemStack getSkull(int rank, Long long1, UUID player){ + if (DEBUG) + plugin.getLogger().info("DEBUG: Getting the skull"); + String playerName = BSkyBlock.getPlugin().getPlayers().getName(player); + if (DEBUG) { + plugin.getLogger().info("DEBUG: playername = " + playerName); + + plugin.getLogger().info("DEBUG: second chance = " + BSkyBlock.getPlugin().getPlayers().getName(player)); + } + ItemStack playerSkull = new ItemStack(Material.SKULL_ITEM, 1, (short) 3); + if (playerName == null) return null; + SkullMeta meta = (SkullMeta) playerSkull.getItemMeta(); + meta.setOwner(playerName); + meta.setDisplayName((plugin.getLocale(player).get("topTenGuiHeading").replace("[name]", BSkyBlock.getPlugin().getIslands().getIslandName(player))).replace("[rank]", String.valueOf(rank))); + //meta.setDisplayName(ChatColor.YELLOW + "" + ChatColor.BOLD + " " + ChatColor.YELLOW + "Island: " + ChatColor.GOLD + ChatColor.UNDERLINE + plugin.getGrid().getIslandName(player) + ChatColor.GRAY + " (#" + rank + ")"); + List lore = new ArrayList(); + lore.add(ChatColor.YELLOW + plugin.getLocale(player).get("levelislandLevel") + " " + long1); + if (BSkyBlock.getPlugin().getPlayers().inTeam(player)) { + List memberList = new ArrayList<>(); + for (UUID members : BSkyBlock.getPlugin().getIslands().getMembers(player)) { + memberList.add(ChatColor.AQUA + BSkyBlock.getPlugin().getPlayers().getName(members)); + } + lore.addAll(memberList); + } + //else lore.add(ChatColor.AQUA + playerName); + + meta.setLore(lore); + playerSkull.setItemMeta(meta); + return playerSkull; + } + + static void remove(UUID owner) { + topTenList.remove(owner); + } + + @SuppressWarnings("deprecation") + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true) + public void onInventoryClick(InventoryClickEvent event) { + Inventory inventory = event.getInventory(); // The inventory that was clicked in + if (inventory.getName() == null) { + return; + } + // The player that clicked the item + Player player = (Player) event.getWhoClicked(); + if (!inventory.getTitle().equals(plugin.getLocale(player).get("topTenGuiTitle"))) { + return; + } + event.setCancelled(true); + player.updateInventory(); + if(event.getCurrentItem() != null && event.getCurrentItem().getType().equals(Material.SKULL_ITEM) && event.getCurrentItem().hasItemMeta()){ + // TODO warp + //Util.runCommand(player, "is warp " + ((SkullMeta)event.getCurrentItem().getItemMeta()).getOwner()); + player.closeInventory(); + return; + } + if (event.getSlotType().equals(SlotType.OUTSIDE)) { + player.closeInventory(); + return; + } + if (event.getClick().equals(ClickType.SHIFT_RIGHT)) { + player.closeInventory(); + return; + } + } + + /** + * Get a sorted descending map of the top players + * @return the topTenList - may be more or less than ten + */ + public static Map getTopTenList() { + return topTenList; + } +} diff --git a/Level/src/bskyblock/addin/level/config/LocaleManager.java b/Level/src/bskyblock/addin/level/config/LocaleManager.java new file mode 100644 index 0000000..c148e7b --- /dev/null +++ b/Level/src/bskyblock/addin/level/config/LocaleManager.java @@ -0,0 +1,28 @@ +package bskyblock.addin.level.config; + +import java.util.UUID; + +import bskyblock.addin.level.Level; +import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.config.AbstractLocaleManager; +import us.tastybento.bskyblock.config.BSBLocale; +import us.tastybento.bskyblock.config.Settings; + +public class LocaleManager extends AbstractLocaleManager { + + public LocaleManager(Level plugin) { + super(plugin); + } + + @Override + public BSBLocale getLocale(UUID player) { + //getLogger().info("DEBUG: " + player); + //getLogger().info("DEBUG: " + getPlayers() == null ? "Players is null":"Players in not null"); + //getLogger().info("DEBUG: " + getPlayers().getPlayer(player)); + //getLogger().info("DEBUG: " + getPlayers().getPlayer(player).getLocale()); + String locale = BSkyBlock.getPlugin().getPlayers().getPlayer(player).getLocale(); + if(locale.isEmpty() || !getLocales().containsKey(locale)) return getLocales().get(Settings.defaultLanguage); + + return getLocales().get(locale); + } +} diff --git a/Level/src/bskyblock/addin/level/config/PluginConfig.java b/Level/src/bskyblock/addin/level/config/PluginConfig.java new file mode 100644 index 0000000..ae70d30 --- /dev/null +++ b/Level/src/bskyblock/addin/level/config/PluginConfig.java @@ -0,0 +1,95 @@ +package bskyblock.addin.level.config; + +import java.util.HashMap; + +import org.apache.commons.lang.StringUtils; +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +import bskyblock.addin.level.Level; + +public class PluginConfig { + private static final boolean DEBUG = false; + + /** + * Loads the various settings from the config.yml file into the plugin + */ + public PluginConfig(Level plugin) { + plugin.saveDefaultConfig(); + + // Island level cool down time + Settings.levelWait = plugin.getConfig().getInt("levelwait", 60); + if (Settings.levelWait < 0) { + Settings.levelWait = 0; + } + + // Get the under water multiplier + Settings.deathpenalty = plugin.getConfig().getInt("deathpenalty", 0); + Settings.sumTeamDeaths = plugin.getConfig().getBoolean("sumteamdeaths"); + Settings.maxDeaths = plugin.getConfig().getInt("maxdeaths", 10); + Settings.islandResetDeathReset = plugin.getConfig().getBoolean("islandresetdeathreset", true); + Settings.teamJoinDeathReset = plugin.getConfig().getBoolean("teamjoindeathreset", true); + Settings.underWaterMultiplier = plugin.getConfig().getDouble("underwater", 1D); + Settings.levelCost = plugin.getConfig().getInt("levelcost", 100); + if (Settings.levelCost < 1) { + Settings.levelCost = 1; + plugin.getLogger().warning("levelcost in blockvalues.yml cannot be less than 1. Setting to 1."); + } + Settings.blockLimits = new HashMap(); + if (plugin.getConfig().isSet("limits")) { + for (String material : plugin.getConfig().getConfigurationSection("limits").getKeys(false)) { + try { + String[] split = material.split(":"); + byte data = 0; + if (split.length>1) { + data = Byte.valueOf(split[1]); + } + Material mat; + if (StringUtils.isNumeric(split[0])) { + mat = Material.getMaterial(Integer.parseInt(split[0])); + } else { + mat = Material.valueOf(split[0].toUpperCase()); + } + MaterialData materialData = new MaterialData(mat); + materialData.setData(data); + Settings.blockLimits.put(materialData, plugin.getConfig().getInt("limits." + material, 0)); + if (DEBUG) { + plugin.getLogger().info("Maximum number of " + materialData + " will be " + Settings.blockLimits.get(materialData)); + } + } catch (Exception e) { + plugin.getLogger().warning("Unknown material (" + material + ") in blockvalues.yml Limits section. Skipping..."); + } + } + } + Settings.blockValues = new HashMap(); + if (plugin.getConfig().isSet("blocks")) { + for (String material : plugin.getConfig().getConfigurationSection("blocks").getKeys(false)) { + try { + String[] split = material.split(":"); + byte data = 0; + if (split.length>1) { + data = Byte.valueOf(split[1]); + } + MaterialData materialData = null; + if (StringUtils.isNumeric(split[0])) { + materialData = new MaterialData(Integer.parseInt(split[0])); + } else { + materialData = new MaterialData(Material.valueOf(split[0].toUpperCase())); + } + + materialData.setData(data); + Settings.blockValues.put(materialData, plugin.getConfig().getInt("blocks." + material, 0)); + if (DEBUG) { + plugin.getLogger().info(materialData.toString() + " value = " + Settings.blockValues.get(materialData)); + } + } catch (Exception e) { + // e.printStackTrace(); + plugin.getLogger().warning("Unknown material (" + material + ") in blockvalues.yml blocks section. Skipping..."); + } + } + } else { + plugin.getLogger().severe("No block values in blockvalues.yml! All island levels will be zero!"); + } + // All done + } +} diff --git a/Level/src/bskyblock/addin/level/config/Settings.java b/Level/src/bskyblock/addin/level/config/Settings.java new file mode 100644 index 0000000..6d36216 --- /dev/null +++ b/Level/src/bskyblock/addin/level/config/Settings.java @@ -0,0 +1,23 @@ +package bskyblock.addin.level.config; + +import java.util.HashMap; + +import org.bukkit.material.MaterialData; + +public class Settings { + + public static String PERMPREFIX; + public static boolean sumTeamDeaths; + public static int seaHeight; + public static HashMap blockLimits; + public static HashMap blockValues; + public static double underWaterMultiplier; + public static int deathpenalty; + public static long levelCost; + public static Object defaultLanguage; + public static int levelWait; + public static int maxDeaths; + public static boolean islandResetDeathReset; + public static boolean teamJoinDeathReset; + +} diff --git a/Level/src/bskyblock/addin/level/event/IslandPostLevelEvent.java b/Level/src/bskyblock/addin/level/event/IslandPostLevelEvent.java new file mode 100644 index 0000000..6182cdb --- /dev/null +++ b/Level/src/bskyblock/addin/level/event/IslandPostLevelEvent.java @@ -0,0 +1,47 @@ +package bskyblock.addin.level.event; + +import java.util.UUID; + +import us.tastybento.bskyblock.api.events.IslandEvent; +import us.tastybento.bskyblock.database.objects.Island; + +/** + * This event is fired after ASkyBlock calculates an island level and when it sends notification to the player. + * Use getLevel() to see the level calculated and getPointsToNextLevel() to see how much points are needed to reach next level. + * Canceling this event will result in no notifications to the player. + * + * @author Poslovitch, tastybento + */ +public class IslandPostLevelEvent extends IslandEvent { + private long level; + private long pointsToNextLevel; + + /** + * @param player + * @param island + * @param l + */ + public IslandPostLevelEvent(UUID player, Island island, long l, long m) { + super(island); + this.level = l; + this.pointsToNextLevel = m; + } + + public long getLevel() { + return level; + } + + public void setLevel(long level) { + this.level = level; + } + + public long getPointsToNextLevel() { + return pointsToNextLevel; + } + + public void setPointsToNextLevel(long pointsToNextLevel) { + this.pointsToNextLevel = pointsToNextLevel; + } + + +} diff --git a/Level/src/bskyblock/addin/level/event/IslandPreLevelEvent.java b/Level/src/bskyblock/addin/level/event/IslandPreLevelEvent.java new file mode 100644 index 0000000..c818cf9 --- /dev/null +++ b/Level/src/bskyblock/addin/level/event/IslandPreLevelEvent.java @@ -0,0 +1,45 @@ +package bskyblock.addin.level.event; + +import java.util.UUID; + +import us.tastybento.bskyblock.api.events.IslandEvent; +import us.tastybento.bskyblock.database.objects.Island; + +public class IslandPreLevelEvent extends IslandEvent { + + private UUID targetPlayer; + private long level; + private long pointsToNextLevel; + + + public IslandPreLevelEvent(UUID targetPlayer, Island island, long level) { + super(island); + this.targetPlayer = targetPlayer; + this.level = level; + } + + public long getPointsToNextLevel() { + return pointsToNextLevel; + } + + public void setPointsToNextLevel(long pointsToNextLevel) { + this.pointsToNextLevel = pointsToNextLevel; + } + + public UUID getTargetPlayer() { + return targetPlayer; + } + + public void setTargetPlayer(UUID targetPlayer) { + this.targetPlayer = targetPlayer; + } + + public long getLevel() { + return level; + } + + public void setLevel(long level) { + this.level = level; + } + +}