diff --git a/addon.yml b/addon.yml new file mode 100755 index 0000000..ba829db --- /dev/null +++ b/addon.yml @@ -0,0 +1,37 @@ +name: BSkyBlock-Level +main: bskyblock.addon.level.Level +version: 0.1 + +authors: tastybento + +permissions: + bskyblock.intopten: + description: Player is in the top ten. + default: true + bskyblock.island.level: + description: Player can use level command + default: true + bskyblock.island.top: + description: Player can use top ten command + default: true + bskyblock.admin.level: + description: Player can use admin level command + default: true + bskyblock.admin.topten: + description: Player can use admin top ten command + default: true + acidisland.intopten: + description: Player is in the top ten. + default: true + acidisland.island.level: + description: Player can use level command + default: true + acidisland.island.top: + description: Player can use top ten command + default: true + acidisland.admin.level: + description: Player can use admin level command + default: true + acidisland.admin.topten: + description: Player can use admin top ten command + default: true \ No newline at end of file diff --git a/config.yml b/config.yml index 15b3707..c5955fe 100644 --- a/config.yml +++ b/config.yml @@ -35,271 +35,613 @@ 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. +# MATERIAL: limit 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. +# Any blocks not listed will have a value of 1. AIR is always zero. +# Format is MATERIAL: value blocks: + ACACIA_BUTTON: 1 ACACIA_DOOR: 1 - ACACIA_STAIRS: 1 - ACACIA_FENCE: 1 + ACACIA_FENCE: 2 ACACIA_FENCE_GATE: 1 + ACACIA_LEAVES: 0 + ACACIA_LOG: 0 + ACACIA_PLANKS: 1 + ACACIA_PRESSURE_PLATE: 1 + ACACIA_SAPLING: 1 + ACACIA_SLAB: 1 ACACIA_STAIRS: 2 - ACTIVATOR_RAIL: 10 - AIR: 0 + ACACIA_TRAPDOOR: 1 + ACACIA_WOOD: 1 + ACTIVATOR_RAIL: 1 + ALLIUM: 1 + ANDESITE: 1 ANVIL: 10 - ARMOR_STAND: 2 - BANNER: 2 - BEACON: 100 - BED_BLOCK: 1 + ATTACHED_MELON_STEM: 1 + ATTACHED_PUMPKIN_STEM: 1 + AZURE_BLUET: 1 + BARRIER: 0 + BEACON: 500 BEDROCK: 0 - BEETROOT_BLOCK: 1 + BEETROOTS: 1 + BIRCH_BUTTON: 1 BIRCH_DOOR: 1 - BIRCH_FENCE: 1 + BIRCH_FENCE: 2 BIRCH_FENCE_GATE: 1 - BIRCH_WOOD_STAIRS: 1 + BIRCH_LEAVES: 0 + BIRCH_LOG: 0 + BIRCH_PLANKS: 1 + BIRCH_PRESSURE_PLATE: 1 + BIRCH_SAPLING: 1 + BIRCH_SLAB: 1 + BIRCH_STAIRS: 2 + BIRCH_TRAPDOOR: 1 + BIRCH_WOOD: 1 + BLACK_BANNER: 2 + BLACK_BED: 2 + BLACK_CARPET: 1 + BLACK_CONCRETE: 1 + BLACK_CONCRETE_POWDER: 1 BLACK_GLAZED_TERRACOTTA: 1 BLACK_SHULKER_BOX: 1 + BLACK_STAINED_GLASS: 2 + BLACK_STAINED_GLASS_PANE: 1 + BLACK_TERRACOTTA: 1 + BLACK_WALL_BANNER: 2 + BLACK_WOOL: 1 + BLUE_BANNER: 2 + BLUE_BED: 2 + BLUE_CARPET: 1 + BLUE_CONCRETE: 1 + BLUE_CONCRETE_POWDER: 1 BLUE_GLAZED_TERRACOTTA: 1 + BLUE_ICE: 1 + BLUE_ORCHID: 1 BLUE_SHULKER_BOX: 1 - BOAT: 2 - BOAT_ACACIA: 2 - BOAT_BIRCH: 2 - BOAT_DARK_OAK: 2 - BOAT_JUNGLE: 2 - BOAT_SPRUCE: 2 + BLUE_STAINED_GLASS: 2 + BLUE_STAINED_GLASS_PANE: 1 + BLUE_TERRACOTTA: 1 + BLUE_WALL_BANNER: 2 + BLUE_WOOL: 1 BONE_BLOCK: 1 BOOKSHELF: 5 + BRAIN_CORAL: 1 + BRAIN_CORAL_BLOCK: 1 + BRAIN_CORAL_FAN: 1 + BRAIN_CORAL_WALL_FAN: 1 BREWING_STAND: 20 - BRICK: 5 + BRICKS: 5 + BRICK_SLAB: 3 BRICK_STAIRS: 5 + BROWN_BANNER: 2 + BROWN_BED: 2 + BROWN_CARPET: 1 + BROWN_CONCRETE: 1 + BROWN_CONCRETE_POWDER: 1 BROWN_GLAZED_TERRACOTTA: 1 + BROWN_MUSHROOM: 1 + BROWN_MUSHROOM_BLOCK: 1 BROWN_SHULKER_BOX: 1 - BURNING_FURNACE: 10 + BROWN_STAINED_GLASS: 2 + BROWN_STAINED_GLASS_PANE: 1 + BROWN_TERRACOTTA: 1 + BROWN_WALL_BANNER: 2 + BROWN_WOOL: 1 + BUBBLE_COLUMN: 1 + BUBBLE_CORAL: 1 + BUBBLE_CORAL_BLOCK: 1 + BUBBLE_CORAL_FAN: 1 + BUBBLE_CORAL_WALL_FAN: 1 CACTUS: 1 - CAKE_BLOCK: 1 - CARPET: 1 + CAKE: 1 + CARROTS: 1 + CARVED_PUMPKIN: 1 CAULDRON: 10 + CAVE_AIR: 1 + CHAIN_COMMAND_BLOCK: 1 CHEST: 2 + CHIPPED_ANVIL: 9 + CHISELED_QUARTZ_BLOCK: 1 + CHISELED_RED_SANDSTONE: 1 + CHISELED_SANDSTONE: 1 + CHISELED_STONE_BRICKS: 2 CHORUS_FLOWER: 1 CHORUS_PLANT: 1 CLAY: 2 COAL_BLOCK: 9 - COAL_ORE: 0 - COBBLE_WALL: 1 + COAL_ORE: 1 + COARSE_DIRT: 1 COBBLESTONE: 1 - COBBLESTONE_STAIRS: 1 + COBBLESTONE_SLAB: 1 + COBBLESTONE_STAIRS: 2 + COBBLESTONE_WALL: 1 + COBWEB: 10 COCOA: 1 - CONCRETE: 1 - CONCRETE_POWDER: 1 + COMMAND_BLOCK: 1 + COMPARATOR: 10 + CONDUIT: 1 + CRACKED_STONE_BRICKS: 2 + CRAFTING_TABLE: 1 + CREEPER_HEAD: 1 + CREEPER_WALL_HEAD: 1 + CUT_RED_SANDSTONE: 1 + CUT_SANDSTONE: 1 + CYAN_BANNER: 2 + CYAN_BED: 2 + CYAN_CARPET: 1 + CYAN_CONCRETE: 1 + CYAN_CONCRETE_POWDER: 1 CYAN_GLAZED_TERRACOTTA: 1 CYAN_SHULKER_BOX: 1 + CYAN_STAINED_GLASS: 2 + CYAN_STAINED_GLASS_PANE: 1 + CYAN_TERRACOTTA: 1 + CYAN_WALL_BANNER: 2 + CYAN_WOOL: 1 + DAMAGED_ANVIL: 5 + DANDELION: 1 + DARK_OAK_BUTTON: 1 DARK_OAK_DOOR: 1 - DARK_OAK_FENCE: 1 + DARK_OAK_FENCE: 2 DARK_OAK_FENCE_GATE: 1 - DARK_OAK_STAIRS: 1 + DARK_OAK_LEAVES: 0 + DARK_OAK_LOG: 0 + DARK_OAK_PLANKS: 1 + DARK_OAK_PRESSURE_PLATE: 1 + DARK_OAK_SAPLING: 1 + DARK_OAK_SLAB: 1 + DARK_OAK_STAIRS: 2 + DARK_OAK_TRAPDOOR: 1 + DARK_OAK_WOOD: 1 + DARK_PRISMARINE: 1 + DARK_PRISMARINE_SLAB: 1 + DARK_PRISMARINE_STAIRS: 2 DAYLIGHT_DETECTOR: 10 - DAYLIGHT_DETECTOR_INVERTED: 10 + DEAD_BRAIN_CORAL_BLOCK: 1 + DEAD_BRAIN_CORAL_FAN: 1 + DEAD_BRAIN_CORAL_WALL_FAN: 1 + DEAD_BUBBLE_CORAL_BLOCK: 1 + DEAD_BUBBLE_CORAL_FAN: 1 + DEAD_BUBBLE_CORAL_WALL_FAN: 1 DEAD_BUSH: 1 + DEAD_FIRE_CORAL_BLOCK: 1 + DEAD_FIRE_CORAL_FAN: 1 + DEAD_FIRE_CORAL_WALL_FAN: 1 + DEAD_HORN_CORAL_BLOCK: 1 + DEAD_HORN_CORAL_FAN: 1 + DEAD_HORN_CORAL_WALL_FAN: 1 + DEAD_TUBE_CORAL_BLOCK: 1 + DEAD_TUBE_CORAL_FAN: 1 + DEAD_TUBE_CORAL_WALL_FAN: 1 DETECTOR_RAIL: 10 DIAMOND_BLOCK: 300 - DIODE: 5 - DIODE_BLOCK_OFF: 5 - DIODE_BLOCK_ON: 5 - DIRT: 2 + DIAMOND_ORE: 1 + DIORITE: 1 + DIRT: 1 DISPENSER: 5 - DOUBLE_PLANT: 2 - DOUBLE_STEP: 1 - DOUBLE_STONE_SLAB2: 1 DRAGON_EGG: 150 + DRAGON_HEAD: 1 + DRAGON_WALL_HEAD: 1 + DRIED_KELP_BLOCK: 1 DROPPER: 5 EMERALD_BLOCK: 150 - EMERALD_ORE: 0 - ENCHANTMENT_TABLE: 150 - END_BRICKS: 2 + EMERALD_ORE: 1 + ENCHANTING_TABLE: 150 ENDER_CHEST: 150 - ENDER_PORTAL_FRAME: 0 - ENDER_PORTAL: 0 - ENDER_STONE: 2 - EXPLOSIVE_MINECART: 10 - FENCE: 1 - FENCE_GATE: 1 + END_GATEWAY: 0 + END_PORTAL: 0 + END_PORTAL_FRAME: 0 + END_ROD: 1 + END_STONE: 1 + END_STONE_BRICKS: 2 + FARMLAND: 1 + FERN: 1 FIRE: 0 - FLOWER_POT: 5 + FIRE_CORAL: 1 + FIRE_CORAL_BLOCK: 1 + FIRE_CORAL_FAN: 1 + FIRE_CORAL_WALL_FAN: 1 + FLOWER_POT: 1 FROSTED_ICE: 1 - FURNACE: 10 + FURNACE: 8 GLASS: 2 + GLASS_PANE: 1 GLOWSTONE: 1 GOLD_BLOCK: 150 - GOLD_ORE: 0 - GRASS: 5 - GRASS_PATH: 5 + GOLD_ORE: 1 + GRANITE: 1 + GRASS: 1 + GRASS_BLOCK: 1 + GRASS_PATH: 1 + GRAVEL: 1 + GRAY_BANNER: 2 + GRAY_BED: 2 + GRAY_CARPET: 1 + GRAY_CONCRETE: 1 + GRAY_CONCRETE_POWDER: 1 GRAY_GLAZED_TERRACOTTA: 1 GRAY_SHULKER_BOX: 1 - GRAVEL: 1 + GRAY_STAINED_GLASS: 2 + GRAY_STAINED_GLASS_PANE: 1 + GRAY_TERRACOTTA: 1 + GRAY_WALL_BANNER: 2 + GRAY_WOOL: 1 + GREEN_BANNER: 2 + GREEN_BED: 2 + GREEN_CARPET: 1 + GREEN_CONCRETE: 1 + GREEN_CONCRETE_POWDER: 1 GREEN_GLAZED_TERRACOTTA: 1 GREEN_SHULKER_BOX: 1 - HARD_CLAY: 2 + GREEN_STAINED_GLASS: 2 + GREEN_STAINED_GLASS_PANE: 1 + GREEN_TERRACOTTA: 1 + GREEN_WALL_BANNER: 2 + GREEN_WOOL: 1 HAY_BLOCK: 2 - HOPPER: 10 - HOPPER_MINECART: 20 - HUGE_MUSHROOM_1: 1 - HUGE_MUSHROOM_2: 1 + HEAVY_WEIGHTED_PRESSURE_PLATE: 1 + HOPPER: -10 + HORN_CORAL: 1 + HORN_CORAL_BLOCK: 1 + HORN_CORAL_FAN: 1 + HORN_CORAL_WALL_FAN: 1 ICE: 5 + INFESTED_CHISELED_STONE_BRICKS: 2 + INFESTED_COBBLESTONE: 1 + INFESTED_CRACKED_STONE_BRICKS: 2 + INFESTED_MOSSY_STONE_BRICKS: 2 + INFESTED_STONE: 1 + INFESTED_STONE_BRICKS: 2 + IRON_BARS: 1 IRON_BLOCK: 10 - IRON_DOOR_BLOCK: 5 - IRON_FENCE: 5 - IRON_ORE: 0 - IRON_PLATE: 5 + IRON_DOOR: 5 + IRON_ORE: 1 IRON_TRAPDOOR: 1 - ITEM_FRAME: 2 JACK_O_LANTERN: 1 JUKEBOX: 10 + JUNGLE_BUTTON: 1 JUNGLE_DOOR: 1 - JUNGLE_FENCE: 1 + JUNGLE_FENCE: 2 JUNGLE_FENCE_GATE: 1 - JUNGLE_WOOD_STAIRS: 1 + JUNGLE_LEAVES: 0 + JUNGLE_LOG: 0 + JUNGLE_PLANKS: 1 + JUNGLE_PRESSURE_PLATE: 1 + JUNGLE_SAPLING: 1 + JUNGLE_SLAB: 1 + JUNGLE_STAIRS: 2 + JUNGLE_TRAPDOOR: 1 + JUNGLE_WOOD: 1 + KELP: 1 + KELP_PLANT: 1 LADDER: 1 LAPIS_BLOCK: 10 - LAPIS_ORE: 0 + LAPIS_ORE: 1 + LARGE_FERN: 1 LAVA: 0 - LEAVES_2: 1 - LEAVES: 1 LEVER: 1 + LIGHT_BLUE_BANNER: 2 + LIGHT_BLUE_BED: 2 + LIGHT_BLUE_CARPET: 1 + LIGHT_BLUE_CONCRETE: 1 + LIGHT_BLUE_CONCRETE_POWDER: 1 LIGHT_BLUE_GLAZED_TERRACOTTA: 1 LIGHT_BLUE_SHULKER_BOX: 1 + LIGHT_BLUE_STAINED_GLASS: 2 + LIGHT_BLUE_STAINED_GLASS_PANE: 1 + LIGHT_BLUE_TERRACOTTA: 1 + LIGHT_BLUE_WALL_BANNER: 2 + LIGHT_BLUE_WOOL: 1 + LIGHT_GRAY_BANNER: 2 + LIGHT_GRAY_BED: 2 + LIGHT_GRAY_CARPET: 1 + LIGHT_GRAY_CONCRETE: 1 + LIGHT_GRAY_CONCRETE_POWDER: 1 + LIGHT_GRAY_GLAZED_TERRACOTTA: 1 + LIGHT_GRAY_SHULKER_BOX: 1 + LIGHT_GRAY_STAINED_GLASS: 2 + LIGHT_GRAY_STAINED_GLASS_PANE: 1 + LIGHT_GRAY_TERRACOTTA: 1 + LIGHT_GRAY_WALL_BANNER: 2 + LIGHT_GRAY_WOOL: 1 + LIGHT_WEIGHTED_PRESSURE_PLATE: 1 + LILAC: 1 + LILY_PAD: 5 + LIME_BANNER: 2 + LIME_BED: 2 + LIME_CARPET: 1 + LIME_CONCRETE: 1 + LIME_CONCRETE_POWDER: 1 LIME_GLAZED_TERRACOTTA: 1 LIME_SHULKER_BOX: 1 - LOG: 1 - #Other log types - examples - #LOG:3: 2 - LOG_2: 1 - LONG_GRASS: 1 + LIME_STAINED_GLASS: 2 + LIME_STAINED_GLASS_PANE: 1 + LIME_TERRACOTTA: 1 + LIME_WALL_BANNER: 2 + LIME_WOOL: 1 + MAGENTA_BANNER: 2 + MAGENTA_BED: 2 + MAGENTA_CARPET: 1 + MAGENTA_CONCRETE: 1 + MAGENTA_CONCRETE_POWDER: 1 MAGENTA_GLAZED_TERRACOTTA: 1 MAGENTA_SHULKER_BOX: 1 - MAGMA: 1 - MELON_BLOCK: 1 + MAGENTA_STAINED_GLASS: 2 + MAGENTA_STAINED_GLASS_PANE: 1 + MAGENTA_TERRACOTTA: 1 + MAGENTA_WALL_BANNER: 2 + MAGENTA_WOOL: 1 + MAGMA_BLOCK: 1 + MELON: 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 + MOSSY_COBBLESTONE: 1 + MOSSY_COBBLESTONE_WALL: 1 + MOSSY_STONE_BRICKS: 2 + MOVING_PISTON: 1 + MUSHROOM_STEM: 1 + MYCELIUM: 5 NETHERRACK: 1 + NETHER_BRICKS: 2 + NETHER_BRICK_FENCE: 2 + NETHER_BRICK_SLAB: 1 + NETHER_BRICK_STAIRS: 2 + NETHER_PORTAL: 1 + NETHER_QUARTZ_ORE: 1 + NETHER_WART: 1 + NETHER_WART_BLOCK: 2 NOTE_BLOCK: 10 + OAK_BUTTON: 1 + OAK_DOOR: 1 + OAK_FENCE: 2 + OAK_FENCE_GATE: 1 + OAK_LEAVES: 0 + OAK_LOG: 0 + OAK_PLANKS: 1 + OAK_PRESSURE_PLATE: 1 + OAK_SAPLING: 1 + OAK_SLAB: 1 + OAK_STAIRS: 2 + OAK_TRAPDOOR: 1 + OAK_WOOD: 1 OBSERVER: 1 OBSIDIAN: 10 + ORANGE_BANNER: 2 + ORANGE_BED: 2 + ORANGE_CARPET: 1 + ORANGE_CONCRETE: 1 + ORANGE_CONCRETE_POWDER: 1 ORANGE_GLAZED_TERRACOTTA: 1 ORANGE_SHULKER_BOX: 1 + ORANGE_STAINED_GLASS: 2 + ORANGE_STAINED_GLASS_PANE: 1 + ORANGE_TERRACOTTA: 1 + ORANGE_TULIP: 1 + ORANGE_WALL_BANNER: 2 + ORANGE_WOOL: 1 + OXEYE_DAISY: 1 PACKED_ICE: 5 - PAINTING: 2 + PEONY: 1 + PETRIFIED_OAK_SLAB: 1 + PINK_BANNER: 2 + PINK_BED: 2 + PINK_CARPET: 1 + PINK_CONCRETE: 1 + PINK_CONCRETE_POWDER: 1 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 + PINK_STAINED_GLASS: 2 + PINK_STAINED_GLASS_PANE: 1 + PINK_TERRACOTTA: 1 + PINK_TULIP: 1 + PINK_WALL_BANNER: 2 + PINK_WOOL: 1 + PISTON: 2 + PISTON_HEAD: 1 + PLAYER_HEAD: 1 + PLAYER_WALL_HEAD: 1 + PODZOL: 1 + POLISHED_ANDESITE: 1 + POLISHED_DIORITE: 1 + POLISHED_GRANITE: 1 + POPPY: 1 + POTATOES: 1 + POTTED_ACACIA_SAPLING: 1 + POTTED_ALLIUM: 1 + POTTED_AZURE_BLUET: 1 + POTTED_BIRCH_SAPLING: 1 + POTTED_BLUE_ORCHID: 1 + POTTED_BROWN_MUSHROOM: 1 + POTTED_CACTUS: 1 + POTTED_DANDELION: 1 + POTTED_DARK_OAK_SAPLING: 1 + POTTED_DEAD_BUSH: 1 + POTTED_FERN: 1 + POTTED_JUNGLE_SAPLING: 1 + POTTED_OAK_SAPLING: 1 + POTTED_ORANGE_TULIP: 1 + POTTED_OXEYE_DAISY: 1 + POTTED_PINK_TULIP: 1 + POTTED_POPPY: 1 + POTTED_RED_MUSHROOM: 1 + POTTED_RED_TULIP: 1 + POTTED_SPRUCE_SAPLING: 1 + POTTED_WHITE_TULIP: 1 + POWERED_RAIL: 1 + PRISMARINE: 1 + PRISMARINE_BRICKS: 2 + PRISMARINE_BRICK_SLAB: 1 + PRISMARINE_BRICK_STAIRS: 2 + PRISMARINE_SLAB: 1 + PRISMARINE_STAIRS: 2 PUMPKIN: 1 + PUMPKIN_STEM: 1 + PURPLE_BANNER: 2 + PURPLE_BED: 2 + PURPLE_CARPET: 1 + PURPLE_CONCRETE: 1 + PURPLE_CONCRETE_POWDER: 1 PURPLE_GLAZED_TERRACOTTA: 1 PURPLE_SHULKER_BOX: 1 + PURPLE_STAINED_GLASS: 2 + PURPLE_STAINED_GLASS_PANE: 1 + PURPLE_TERRACOTTA: 1 + PURPLE_WALL_BANNER: 2 + PURPLE_WOOL: 1 PURPUR_BLOCK: 1 - PURPUR_DOUBLE_SLAB: 1 PURPUR_PILLAR: 1 PURPUR_SLAB: 1 - PURPUR_STAIRS: 1 + PURPUR_STAIRS: 2 QUARTZ_BLOCK: 1 - QUARTZ_ORE: 0 - QUARTZ_STAIRS: 1 - QUARTZ: 1 - RAILS: 1 + QUARTZ_PILLAR: 1 + QUARTZ_SLAB: 1 + QUARTZ_STAIRS: 2 + RAIL: 1 + REDSTONE_BLOCK: 10 + REDSTONE_LAMP: 10 + REDSTONE_ORE: 1 + REDSTONE_TORCH: 5 + REDSTONE_WALL_TORCH: 5 + REDSTONE_WIRE: 1 + RED_BED: 2 + RED_CARPET: 1 + RED_CONCRETE: 1 + RED_CONCRETE_POWDER: 1 RED_GLAZED_TERRACOTTA: 1 RED_MUSHROOM: 1 - RED_NETHER_BRICK: 2 - RED_ROSE: 1 + RED_MUSHROOM_BLOCK: 1 + RED_NETHER_BRICKS: 2 + RED_SAND: 1 RED_SANDSTONE: 1 - RED_SANDSTONE_STAIRS: 1 + RED_SANDSTONE_SLAB: 1 + RED_SANDSTONE_STAIRS: 2 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 + RED_STAINED_GLASS: 2 + RED_STAINED_GLASS_PANE: 1 + RED_TERRACOTTA: 1 + RED_TULIP: 1 + RED_WALL_BANNER: 2 + RED_WOOL: 1 + REPEATER: 1 + REPEATING_COMMAND_BLOCK: 1 + ROSE_BUSH: 1 SAND: 1 SANDSTONE: 1 - SANDSTONE_STAIRS: 1 + SANDSTONE_SLAB: 1 + SANDSTONE_STAIRS: 2 + SEAGRASS: 1 SEA_LANTERN: 1 - SIGN_POST: 1 - SILVER_GLAZED_TERRACOTTA: 1 - SILVER_SHULKER_BOX: 1 - SKULL: 10 + SEA_PICKLE: 1 + SHULKER_BOX: 1 + SIGN: 1 + SKELETON_SKULL: 10 + SKELETON_WALL_SKULL: 100 SLIME_BLOCK: 10 - SMOOTH_BRICK: 2 - SMOOTH_STAIRS: 2 + SMOOTH_QUARTZ: 1 + SMOOTH_RED_SANDSTONE: 1 + SMOOTH_SANDSTONE: 1 + SMOOTH_STONE: 1 + SNOW: 1 SNOW_BLOCK: 1 - SOIL: 2 SOUL_SAND: 2 + SPAWNER: 1 SPONGE: 10 + SPRUCE_BUTTON: 1 SPRUCE_DOOR: 1 - SPRUCE_FENCE: 1 + SPRUCE_FENCE: 2 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 + SPRUCE_LEAVES: 0 + SPRUCE_LOG: 0 + SPRUCE_PLANKS: 1 + SPRUCE_PRESSURE_PLATE: 1 + SPRUCE_SAPLING: 1 + SPRUCE_SLAB: 1 + SPRUCE_STAIRS: 2 + SPRUCE_TRAPDOOR: 1 + SPRUCE_WOOD: 1 + STICKY_PISTON: 1 STONE: 1 + STONE_BRICKS: 2 + STONE_BRICK_SLAB: 1 + STONE_BRICK_STAIRS: 2 STONE_BUTTON: 1 - STONE_PLATE: 2 - STORAGE_MINECART: 10 - SUGAR_CANE_BLOCK: 1 - THIN_GLASS: 1 + STONE_PRESSURE_PLATE: 1 + STONE_SLAB: 1 + STRIPPED_ACACIA_LOG: 0 + STRIPPED_ACACIA_WOOD: 1 + STRIPPED_BIRCH_LOG: 0 + STRIPPED_BIRCH_WOOD: 1 + STRIPPED_DARK_OAK_LOG: 0 + STRIPPED_DARK_OAK_WOOD: 1 + STRIPPED_JUNGLE_LOG: 0 + STRIPPED_JUNGLE_WOOD: 1 + STRIPPED_OAK_LOG: 0 + STRIPPED_OAK_WOOD: 1 + STRIPPED_SPRUCE_LOG: 0 + STRIPPED_SPRUCE_WOOD: 1 + SUGAR_CANE: 1 + SUNFLOWER: 1 + TALL_GRASS: 1 + TALL_SEAGRASS: 1 + TERRACOTTA: 1 TNT: 5 - TORCH: 2 - TRAP_DOOR: 5 - TRAPPED_CHEST: 10 - TRIPWIRE_HOOK: 2 + TORCH: 1 + TRAPPED_CHEST: 5 TRIPWIRE: 2 + TRIPWIRE_HOOK: 2 + TUBE_CORAL: 1 + TUBE_CORAL_BLOCK: 1 + TUBE_CORAL_FAN: 1 + TUBE_CORAL_WALL_FAN: 1 + TURTLE_EGG: 1 VINE: 1 + VOID_AIR: 1 WALL_SIGN: 1 - WATER_LILY: 5 - WEB: 10 + WALL_TORCH: 1 + WATER: 0 + WET_SPONGE: 10 WHEAT: 1 + WHITE_BANNER: 2 + WHITE_BED: 2 + WHITE_CARPET: 1 + WHITE_CONCRETE: 1 + WHITE_CONCRETE_POWDER: 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 + WHITE_STAINED_GLASS: 2 + WHITE_STAINED_GLASS_PANE: 1 + WHITE_TERRACOTTA: 1 + WHITE_TULIP: 1 + WHITE_WALL_BANNER: 2 + WHITE_WOOL: 1 + WITHER_SKELETON_SKULL: 10 + WITHER_SKELETON_WALL_SKULL: 10 + YELLOW_BANNER: 2 + YELLOW_BED: 2 + YELLOW_CARPET: 1 + YELLOW_CONCRETE: 1 + YELLOW_CONCRETE_POWDER: 1 YELLOW_GLAZED_TERRACOTTA: 1 YELLOW_SHULKER_BOX: 1 + YELLOW_STAINED_GLASS: 2 + YELLOW_STAINED_GLASS_PANE: 1 + YELLOW_TERRACOTTA: 1 + YELLOW_WALL_BANNER: 2 + YELLOW_WOOL: 1 + ZOMBIE_HEAD: 1 + ZOMBIE_WALL_HEAD: 1 + +# World differences +# List any blocks that have a different value in a specific world +# If a block is not listed, the default value will be used +# Prefix with world name +worlds: + AcidIsland_world: + SAND: 0 + SANDSTONE: 0 + ICE: 0 \ No newline at end of file diff --git a/locales/bsb_en_US.yml b/locales/bsb_en_US.yml deleted file mode 100755 index 4a8eba7..0000000 --- a/locales/bsb_en_US.yml +++ /dev/null @@ -1,20 +0,0 @@ -########################################################################################### -# 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)" -topten: - guiTitle: "Top Ten" - guiHeading: "[name]:[rank]" - islandLevel: "Level [level]" - \ No newline at end of file diff --git a/locales/en-US.yml b/locales/en-US.yml new file mode 100755 index 0000000..adf49e6 --- /dev/null +++ b/locales/en-US.yml @@ -0,0 +1,30 @@ +########################################################################################### +# 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 # +########################################################################################### + +admin: + level: + parameters: "" + description: "calculate the island level for player" + top: + description: "show the top ten list" + unknown-world: "&cUnknown world!" + +island: + level: + parameters: "[player]" + description: "calculate your island level or show the level of [player]" + calculating: "&aCalculating level..." + island-level-is: "&aIsland level is &b[level]" + required-points-to-next-level: "&a[points] points required until the next level" + deaths: "&c([number] deaths)" + cooldown: "&cYou must wait &b[time] &cseconds until you can do that again" + + top: + description: "show the Top Ten" + gui-title: "&aTop Ten" + gui-heading: "&6[name]: &B[rank]" + island-level: "&BLevel [level]" + warp-to: "&AWarping to [name]'s island" + \ No newline at end of file diff --git a/plugin.yml b/plugin.yml deleted file mode 100755 index f2bbac8..0000000 --- a/plugin.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: BSkyBlock-Level -main: bskyblock.addin.level.Level -version: 0.1 - -authors: [tastybento] - -depend: [BSkyBlock] - -permissions: - bskyblock.intopten: - description: Player is in the top ten. - default: true - bskyblock.island.level: - description: Player can use level command - default: true - bskyblock.island.topten: - description: Player can use top ten command - default: true - bskyblock.admin.level: - description: Player can use admin level command - default: true - bskyblock.admin.topten: - description: Player can use admin top ten command - default: true \ No newline at end of file diff --git a/pom.xml b/pom.xml index f06d4ce..f64aecb 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,6 @@ 4.0.0 - Level Level 0.0.1-SNAPSHOT jar @@ -41,16 +40,23 @@ + + org.spigotmc + spigot-api + 1.13-R0.1-SNAPSHOT + provided + - org.bukkit - bukkit - 1.12.2-R0.1-SNAPSHOT + world.bentobox + bentobox + LATEST provided - us.tastybento - bskyblock - LATEST + bskyblock.addon + WelcomeWarpSigns + 0.0.1-SNAPSHOT + provided @@ -59,4 +65,5 @@ https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + bskyblock.addon \ No newline at end of file diff --git a/src/bskyblock/addin/level/ChunkScanner.java b/src/bskyblock/addin/level/ChunkScanner.java deleted file mode 100644 index 65e282b..0000000 --- a/src/bskyblock/addin/level/ChunkScanner.java +++ /dev/null @@ -1,342 +0,0 @@ -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.Optional; -import java.util.Set; - -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.material.MaterialData; - -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 us.tastybento.bskyblock.BSkyBlock; -import us.tastybento.bskyblock.api.commands.User; -import us.tastybento.bskyblock.database.objects.Island; - -/** - * 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 ChunkScanner { - private static final boolean DEBUG = false; - protected static final boolean LEVEL_LOGGING = false; - private final Level plugin; - private final Set finalChunk; - private final Results result; - private final Optional asker; - - - public ChunkScanner(Level plugin, Island island) { - this.plugin = plugin; - // Get the chunks to scan - finalChunk = getIslandChunks(island); - this.asker = Optional.empty(); - // Create new level result - result = new Results(); - runAsyncCount(island); - } - - /** - * Calculates the level of an island - * @param plugin - * @param island - island that is being calculated - * @param asker - the user who wants the report - */ - public ChunkScanner(Level plugin, Island island, User asker) { - this.plugin = plugin; - // Get the chunks to scan - finalChunk = getIslandChunks(island); - this.asker = Optional.of(asker); - // Create new level result - result = new Results(); - runAsyncCount(island); - } - - private void runAsyncCount(Island island) { - // Run AsyncTask to count blocks in the chunk snapshots - plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() { - - @SuppressWarnings("deprecation") - @Override - public void run() { - // Copy the limits hashmap - HashMap limitCount = new HashMap(Settings.blockLimits); - // Calculate the island score - 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 < island.getWorld().getMaxHeight(); y++) { - Material type = chunk.getBlockType(x, y, z); - // Currently, there is no alternative to using block data (Dec 2017) - MaterialData md = new MaterialData(type, (byte) chunk.getBlockData(x, y, z)); - MaterialData generic = new MaterialData(type); - if (!type.equals(Material.AIR)) { // 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) { - result.underWaterBlockCount += Settings.blockValues.get(md); - result.uwCount.add(md); - } else { - result.rawBlockCount += Settings.blockValues.get(md); - result.mdCount.add(md); - } - } else { - result.ofCount.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) { - result.underWaterBlockCount += Settings.blockValues.get(generic); - result.uwCount.add(md); - } else { - result.rawBlockCount += Settings.blockValues.get(generic); - result.mdCount.add(md); - } - } else { - result.ofCount.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) { - result.underWaterBlockCount += Settings.blockValues.get(md); - result.uwCount.add(md); - } else { - result.rawBlockCount += Settings.blockValues.get(md); - result.mdCount.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) { - result.underWaterBlockCount += Settings.blockValues.get(generic); - result.uwCount.add(md); - } else { - result.rawBlockCount += Settings.blockValues.get(generic); - result.mdCount.add(md); - } - } else { - result.ncCount.add(md); - } - } - } - } - } - } - - result.rawBlockCount += (long)((double)result.underWaterBlockCount * Settings.underWaterMultiplier); - if (DEBUG) - plugin.getLogger().info("DEBUG: block count = "+result.rawBlockCount); - // Set the death penalty - result.deathHandicap = BSkyBlock.getPlugin().getPlayers().getDeaths(island.getOwner()) * Settings.deathpenalty; - // Set final score - result.score = (result.rawBlockCount / Settings.levelCost) - result.deathHandicap; - - // Return to main thread - plugin.getServer().getScheduler().runTask(plugin, new Runnable() { - - @Override - public void run() { - // Run any modifications - - // All done. - if (asker.isPresent()) { - // Tell the asker the result - if (asker.get().isPlayer() && asker.get().isOnline()) { - asker.get().sendLegacyMessage("Your level is " + result.score); - } else { - // Console - sendConsoleReport(asker); - } - } - } - - private void sendConsoleReport(Optional asker) { - List reportLines = new ArrayList<>(); - // provide counts - reportLines.add("Level Log for island at " + island.getCenter()); - reportLines.add("Island owner UUID = " + island.getOwner()); - reportLines.add("Total block value count = " + String.format("%,d",result.rawBlockCount)); - 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 = " + result.deathHandicap); - reportLines.add("Level calculated = " + result.score); - reportLines.add("=================================="); - int total = 0; - if (!result.uwCount.isEmpty()) { - reportLines.add("Underwater block count (Multiplier = x" + Settings.underWaterMultiplier + ") value"); - reportLines.add("Total number of underwater blocks = " + String.format("%,d",result.uwCount.size())); - Iterable> entriesSortedByCount = - Multisets.copyHighestCountFirst(result.uwCount).entrySet(); - Iterator> it = entriesSortedByCount.iterator(); - while (it.hasNext()) { - Entry en = it.next(); - MaterialData type = en.getElement(); - - int value = 0; - if (Settings.blockValues.containsKey(type)) { - // Specific - value = Settings.blockValues.get(type); - } else if (Settings.blockValues.containsKey(new MaterialData(type.getItemType()))) { - // Generic - value = Settings.blockValues.get(new MaterialData(type.getItemType())); - } - if (value > 0) { - reportLines.add(type.toString() + ":" - + String.format("%,d",en.getCount()) + " blocks x " + value + " = " + (value * en.getCount())); - total += (value * en.getCount()); - } - } - reportLines.add("Subtotal = " + total); - reportLines.add("=================================="); - } - reportLines.add("Regular block count"); - reportLines.add("Total number of blocks = " + String.format("%,d",result.mdCount.size())); - //Iterable> entriesSortedByCount = - // Multisets.copyHighestCountFirst(mdCount).entrySet(); - Iterable> entriesSortedByCount = - result.mdCount.entrySet(); - Iterator> it = entriesSortedByCount.iterator(); - while (it.hasNext()) { - Entry en = it.next(); - MaterialData type = en.getElement(); - int value = 0; - if (Settings.blockValues.containsKey(type)) { - // Specific - value = Settings.blockValues.get(type); - } else if (Settings.blockValues.containsKey(new MaterialData(type.getItemType()))) { - // Generic - value = Settings.blockValues.get(new MaterialData(type.getItemType())); - } - if (value > 0) { - reportLines.add(type.toString() + ":" - + String.format("%,d",en.getCount()) + " blocks x " + value + " = " + (value * en.getCount())); - total += (value * en.getCount()); - } - } - reportLines.add("Total = " + total); - reportLines.add("=================================="); - reportLines.add("Blocks not counted because they exceeded limits: " + String.format("%,d",result.ofCount.size())); - //entriesSortedByCount = Multisets.copyHighestCountFirst(ofCount).entrySet(); - entriesSortedByCount = result.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 config.yml"); - reportLines.add("Total number = " + String.format("%,d",result.ncCount.size())); - //entriesSortedByCount = Multisets.copyHighestCountFirst(ncCount).entrySet(); - entriesSortedByCount = result.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("================================="); - - for (String line : reportLines) { - asker.get().sendLegacyMessage(line); - } - } - - }); - - } - - }); - - - } - - private Set getIslandChunks(Island island) { - // Check if player's island world is the nether or overworld and adjust accordingly - final World world = island.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))) { - // If the chunk isn't already generated, load it but don't try and generate it - world.loadChunk((int)((double)x/16), (int)((double)z/16), false); - } - // chunk is loaded - chunkSnapshot.add(world.getBlockAt(x, 0, z).getChunk().getChunkSnapshot()); - - if (DEBUG) - plugin.getLogger().info("DEBUG: getting chunk at " + x + ", " + z); - } - } - if (DEBUG) - plugin.getLogger().info("DEBUG: size of chunk snapshot = " + chunkSnapshot.size()); - return chunkSnapshot; - } - - /** - * Results class - * @author ben - * - */ - public class Results { - Multiset mdCount = HashMultiset.create(); - Multiset uwCount = HashMultiset.create(); - Multiset ncCount = HashMultiset.create(); - Multiset ofCount = HashMultiset.create(); - long rawBlockCount; - Island island; - long underWaterBlockCount = 0; - long score; - int deathHandicap; - } -} diff --git a/src/bskyblock/addin/level/Level.java b/src/bskyblock/addin/level/Level.java deleted file mode 100644 index 50b3f25..0000000 --- a/src/bskyblock/addin/level/Level.java +++ /dev/null @@ -1,179 +0,0 @@ -package bskyblock.addin.level; - -import java.beans.IntrospectionException; -import java.lang.reflect.InvocationTargetException; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map.Entry; -import java.util.UUID; - -import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitTask; - -import bskyblock.addin.level.commands.AdminLevel; -import bskyblock.addin.level.commands.AdminTop; -import bskyblock.addin.level.commands.IslandLevel; -import bskyblock.addin.level.commands.IslandTop; -import bskyblock.addin.level.config.PluginConfig; -import bskyblock.addin.level.database.object.Levels; -import us.tastybento.bskyblock.BSkyBlock; -import us.tastybento.bskyblock.api.commands.CompositeCommand; -import us.tastybento.bskyblock.api.commands.User; -import us.tastybento.bskyblock.config.Settings; -import us.tastybento.bskyblock.database.BSBDatabase; -import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler; - -/** - * Addin to BSkyBlock that enables island level scoring and top ten functionality - * @author tastybento - * - */ -public class Level extends JavaPlugin { - - - // The BSkyBlock plugin instance. - private BSkyBlock bSkyBlock; - - // Level calc checker - BukkitTask checker = null; - - // Database handler for level data - private AbstractDatabaseHandler handler; - - // The BSkyBlock database object - private BSBDatabase database; - - // A cache of island levels. Island levels are not kept in memory unless required. - // The cache is saved when the server shuts down and the plugin is disabled. - // TODO: Save regularly to avoid crash issues. - private HashMap levelsCache; - - // The Top Ten object - private TopTen topTen; - - // Level calculator - private LevelPresenter levelCalc; - - @SuppressWarnings("unchecked") - @Override - public void onEnable() { - // Load the plugin's config - new PluginConfig(this); - // Get the BSkyBlock plugin. This will be available because this plugin depends on it in plugin.yml. - bSkyBlock = BSkyBlock.getPlugin(); - // Check if it is enabled - it might be loaded, but not enabled. - if (!bSkyBlock.isEnabled()) { - this.setEnabled(false); - return; - } - // Get the BSkyBlock database - database = BSBDatabase.getDatabase(); - // Set up the database handler to store and retrieve Island classes - // Note that these are saved by the BSkyBlock database - handler = (AbstractDatabaseHandler) database.getHandler(bSkyBlock, Levels.class); - // Initialize the cache - levelsCache = new HashMap<>(); - // Load the calculator - levelCalc = new LevelPresenter(this); - // Start the top ten and register it for clicks - topTen = new TopTen(this); - getServer().getPluginManager().registerEvents(topTen, this); - // Local locales - //localeManager = new LocaleManager(this); - // Register commands - CompositeCommand bsbIslandCmd = (CompositeCommand) BSkyBlock.getPlugin().getCommandsManager().getCommand(Settings.ISLANDCOMMAND); - new IslandLevel(this, bsbIslandCmd); - new IslandTop(this, bsbIslandCmd); - CompositeCommand bsbAdminCmd = (CompositeCommand) BSkyBlock.getPlugin().getCommandsManager().getCommand(Settings.ADMINCOMMAND); - new AdminLevel(this, bsbAdminCmd); - new AdminTop(this, bsbAdminCmd); - // Done - } - - @Override - public void onDisable(){ - // Save the cache - if (levelsCache != null) { - save(false); - } - } - - /** - * Save the levels to the database - * @param async - if true, saving will be done async - */ - public void save(boolean async){ - Runnable save = () -> { - try { - for (Entry en : levelsCache.entrySet()) { - Levels lv = new Levels(); - lv.setLevel(en.getValue()); - lv.setUniqueId(en.getKey().toString()); - handler.saveObject(lv); - } - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException - | InstantiationException | NoSuchMethodException | IntrospectionException | SQLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - }; - if(async){ - getServer().getScheduler().runTaskAsynchronously(this, save); - } else { - save.run(); - } - } - - /** - * Get level from cache for a player - * @param targetPlayer - * @return Level of player - */ - public long getIslandLevel(UUID targetPlayer) { - //getLogger().info("DEBUG: getting island level for " + bSkyBlock.getPlayers().getName(targetPlayer)); - if (levelsCache.containsKey(targetPlayer)) { - return levelsCache.get(targetPlayer); - } - // Get from database - Levels level; - try { - level = handler.loadObject(targetPlayer.toString()); - if (level == null) { - // We do not know this player, set to zero - return 0; - } - levelsCache.put(targetPlayer, level.getLevel()); - return level.getLevel(); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException - | SecurityException | ClassNotFoundException | IntrospectionException | SQLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return 0; - } - - /** - * Save the player's level - * @param targetPlayer - * @param level - */ - public void setIslandLevel(UUID targetPlayer, long level) { - //getLogger().info("DEBUG: set island level to " + level + " for " + bSkyBlock.getPlayers().getName(targetPlayer)); - // Add to cache - levelsCache.put(targetPlayer, level); - topTen.addEntry(targetPlayer, level); - } - - public AbstractDatabaseHandler getHandler() { - return handler; - } - - public TopTen getTopTen() { - return topTen; - } - - public void calculateIslandLevel(User user, UUID playerUUID, boolean b) { - levelCalc.calculateIslandLevel(user, playerUUID, b); - } - -} diff --git a/src/bskyblock/addin/level/LevelPlugin.java b/src/bskyblock/addin/level/LevelPlugin.java deleted file mode 100644 index 9bb3ab3..0000000 --- a/src/bskyblock/addin/level/LevelPlugin.java +++ /dev/null @@ -1,25 +0,0 @@ -package bskyblock.addin.level; - -import java.util.logging.Logger; - -import us.tastybento.bskyblock.BSkyBlock; - -/** - * Makes code look nicer - * @author ben - * - */ -public abstract class LevelPlugin { - protected final Level plugin; - protected final BSkyBlock bSkyBlock; - - public LevelPlugin(Level plugin) { - this.plugin = plugin; - this.bSkyBlock = BSkyBlock.getPlugin(); - } - - public final Logger getLogger() { - return plugin.getLogger(); - } - -} diff --git a/src/bskyblock/addin/level/LevelPresenter.java b/src/bskyblock/addin/level/LevelPresenter.java deleted file mode 100644 index 0ee0481..0000000 --- a/src/bskyblock/addin/level/LevelPresenter.java +++ /dev/null @@ -1,98 +0,0 @@ -package bskyblock.addin.level; - -import java.util.Calendar; -import java.util.HashMap; -import java.util.UUID; - -import org.bukkit.ChatColor; - -import us.tastybento.bskyblock.api.commands.User; -import us.tastybento.bskyblock.config.Settings; - -public class LevelPresenter extends LevelPlugin { - - private int levelWait; - // Level calc cool down - private HashMap levelWaitTime = new HashMap(); - - public LevelPresenter(Level plugin) { - super(plugin); - } - - /** - * 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 User 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 User sender, final UUID targetPlayer, boolean report) { - // Check if sender has island - if (!bSkyBlock.getIslands().hasIsland(targetPlayer)) { - sender.sendLegacyMessage("Target does not have an island"); - return false; - } - // Player asking for their own island calc - if (!sender.isPlayer() || sender.getUniqueId().equals(targetPlayer) || sender.isOp() || sender.hasPermission(Settings.PERMPREFIX + "mod.info")) { - // Newer better system - uses chunks - if (!onLevelWaitTime(sender) || levelWait <= 0 || sender.isOp() || sender.hasPermission(Settings.PERMPREFIX + "mod.info")) { - sender.sendLegacyMessage(ChatColor.GREEN + "Calculating level, please wait..."); - setLevelWaitTime(sender); - new ChunkScanner(plugin, bSkyBlock.getIslands().getIsland(targetPlayer), sender); - } else { - sender.sendLegacyMessage( ChatColor.YELLOW + String.valueOf(getLevelWaitTime(sender))); - } - - } else { - // Asking for the level of another player - sender.sendMessage("island.islandLevelIs","[level]", String.valueOf(plugin.getIslandLevel(targetPlayer))); - } - return true; - } - - /** - * Sets cool down for the level command - * - * @param player - */ - private void setLevelWaitTime(final User player) { - levelWaitTime.put(player.getUniqueId(), Long.valueOf(Calendar.getInstance().getTimeInMillis() + levelWait * 1000)); - } - - private boolean onLevelWaitTime(final User sender) { - if (levelWaitTime.containsKey(sender.getUniqueId())) { - if (levelWaitTime.get(sender.getUniqueId()).longValue() > Calendar.getInstance().getTimeInMillis()) { - return true; - } - - return false; - } - - return false; - } - - private long getLevelWaitTime(final User sender) { - if (levelWaitTime.containsKey(sender.getUniqueId())) { - if (levelWaitTime.get(sender.getUniqueId()).longValue() > Calendar.getInstance().getTimeInMillis()) { - return (levelWaitTime.get(sender.getUniqueId()).longValue() - Calendar.getInstance().getTimeInMillis()) / 1000; - } - - return 0L; - } - - return 0L; - } -} diff --git a/src/bskyblock/addin/level/TopTen.java b/src/bskyblock/addin/level/TopTen.java deleted file mode 100644 index f958a30..0000000 --- a/src/bskyblock/addin/level/TopTen.java +++ /dev/null @@ -1,289 +0,0 @@ -/******************************************************************************* - * 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.beans.IntrospectionException; -import java.lang.reflect.InvocationTargetException; -import java.sql.SQLException; -import java.util.ArrayList; -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.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.database.object.Levels; -import bskyblock.addin.level.database.object.TopTenList; -import bskyblock.addin.level.event.TopTenClick; -import us.tastybento.bskyblock.BSkyBlock; -import us.tastybento.bskyblock.api.commands.User; -import us.tastybento.bskyblock.config.Settings; -import us.tastybento.bskyblock.database.BSBDatabase; -import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler; - -/** - * Handles all Top Ten List functions - * - * @author tastybento - * - */ -public class TopTen implements Listener { - private Level plugin; - // Top ten list of players - private TopTenList topTenList; - private final int GUISIZE = 27; // Must be a multiple of 9 - private final int[] SLOTS = new int[] {4, 12, 14, 19, 20, 21, 22, 23, 24, 25}; - private final boolean DEBUG = false; - // Store this as a because it's the same for everyone and saves memory cleanup - private Inventory gui; - private BSBDatabase database; - private AbstractDatabaseHandler handler; - - @SuppressWarnings("unchecked") - public TopTen(Level plugin) { - this.plugin = plugin; - // Set up database - database = BSBDatabase.getDatabase(); - // Set up the database handler to store and retrieve the TopTenList class - // Note that these are saved in the BSkyBlock database - handler = (AbstractDatabaseHandler) database.getHandler(BSkyBlock.getPlugin(), TopTenList.class); - loadTopTen(); - } - - /** - * Adds a player to the top ten, if the level is good enough - * - * @param ownerUUID - * @param l - */ - public void addEntry(UUID ownerUUID, long l) { - // 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.addLevel(ownerUUID, l); - saveTopTen(); - } - - /** - * 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. - */ - public void create() { - // Obtain all the levels for each known player - AbstractDatabaseHandler levelHandler = plugin.getHandler(); - try { - long index = 0; - for (Levels lv : levelHandler.loadObjects()) { - if (index++ % 1000 == 0) { - plugin.getLogger().info("Processed " + index + " players for top ten"); - } - // Convert to UUID - UUID playerUUID = UUID.fromString(lv.getUniqueId()); - // Check if the player is an owner or team leader - if (BSkyBlock.getPlugin().getIslands().isOwner(playerUUID)) { - topTenList.addLevel(playerUUID, lv.getLevel()); - } - } - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException - | SecurityException | ClassNotFoundException | IntrospectionException | SQLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - saveTopTen(); - } - - /** - * 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 boolean getGUI(final Player player) { - if (DEBUG) - plugin.getLogger().info("DEBUG: GUI display"); - // New GUI display (shown by default) - if (topTenList == null) create(); - // Create the top ten GUI if it does not exist - if (gui == null) { - gui = Bukkit.createInventory(null, GUISIZE, "topten.guiTitle"); - if (DEBUG) - plugin.getLogger().info("DEBUG: creating GUI for the first time"); - } - // Reset - gui.clear(); - int i = 1; - Iterator> it = topTenList.getTopTen().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); - player.updateInventory(); - - return true; - } - - private 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.setOwningPlayer(plugin.getServer().getOfflinePlayer(player)); - meta.setOwner(playerName); - meta.setDisplayName(("topten.guiHeading".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 + "topten.islandLevel".replace("[level]", String.valueOf(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; - } - - public TopTenList getTopTenList() { - return topTenList; - } - - /** - * Loads the top ten from the database - */ - public void loadTopTen() { - try { - topTenList = handler.loadObject("topten"); - if (topTenList == null) { - topTenList = new TopTenList(); - } - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException - | SecurityException | ClassNotFoundException | IntrospectionException | SQLException e) { - e.printStackTrace(); - } - } - - @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("topten.guiTitle")) { - return; - } - event.setCancelled(true); - player.updateInventory(); - if(event.getCurrentItem() != null && event.getCurrentItem().getType().equals(Material.SKULL_ITEM) && event.getCurrentItem().hasItemMeta()){ - player.closeInventory(); - // Fire click event - TopTenClick clickEvent = new TopTenClick(((SkullMeta)event.getCurrentItem().getItemMeta()).getOwningPlayer().getName()); - plugin.getServer().getPluginManager().callEvent(clickEvent); - return; - } - if (event.getSlotType().equals(SlotType.OUTSIDE)) { - player.closeInventory(); - return; - } - if (event.getClick().equals(ClickType.SHIFT_RIGHT)) { - player.closeInventory(); - return; - } - } - - /** - * Removes ownerUUID from the top ten list - * - * @param ownerUUID - */ - public void removeEntry(UUID ownerUUID) { - topTenList.remove(ownerUUID); - } - - public void saveTopTen() { - //plugin.getLogger().info("Saving top ten list"); - if (topTenList == null) { - //plugin.getLogger().info("DEBUG: toptenlist = null!"); - return; - } - try { - handler.saveObject(topTenList); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException - | InstantiationException | NoSuchMethodException | IntrospectionException | SQLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - -} diff --git a/src/bskyblock/addin/level/commands/AdminLevel.java b/src/bskyblock/addin/level/commands/AdminLevel.java deleted file mode 100644 index 689480e..0000000 --- a/src/bskyblock/addin/level/commands/AdminLevel.java +++ /dev/null @@ -1,44 +0,0 @@ -package bskyblock.addin.level.commands; - -import java.util.List; -import java.util.UUID; - -import bskyblock.addin.level.Level; -import us.tastybento.bskyblock.api.commands.CompositeCommand; -import us.tastybento.bskyblock.api.commands.User; -import us.tastybento.bskyblock.config.Settings; - -public class AdminLevel extends CompositeCommand { - - private final Level levelPlugin; - - public AdminLevel(Level levelPlugin, CompositeCommand parent) { - super(parent, "level"); - this.levelPlugin = levelPlugin; - this.setPermission(Settings.PERMPREFIX + "admin.level"); - this.setOnlyPlayer(false); - this.setUsage("admin.level.usage"); - } - - @Override - public boolean execute(User user, List args) { - if (!args.isEmpty()) { - // Asking for another player's level? - // Convert name to a UUID - final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0), true); - //getLogger().info("DEBUG: console player info UUID = " + playerUUID); - if (playerUUID == null) { - user.sendMessage("error.UnknownPlayer"); - return true; - } else { - if (user.isPlayer()) { - levelPlugin.calculateIslandLevel(user, playerUUID, false); - } else { - levelPlugin.calculateIslandLevel(user, playerUUID, true); - } - } - } - return true; - } - -} diff --git a/src/bskyblock/addin/level/commands/AdminTop.java b/src/bskyblock/addin/level/commands/AdminTop.java deleted file mode 100644 index d81c647..0000000 --- a/src/bskyblock/addin/level/commands/AdminTop.java +++ /dev/null @@ -1,39 +0,0 @@ -package bskyblock.addin.level.commands; - -import java.util.List; -import java.util.Map.Entry; -import java.util.UUID; - -import bskyblock.addin.level.Level; -import us.tastybento.bskyblock.BSkyBlock; -import us.tastybento.bskyblock.api.commands.CompositeCommand; -import us.tastybento.bskyblock.api.commands.User; -import us.tastybento.bskyblock.config.Settings; - -public class AdminTop extends CompositeCommand { - - private final Level levelPlugin; - - public AdminTop(Level levelPlugin, CompositeCommand parent) { - super(parent, "top", "topten"); - this.levelPlugin = levelPlugin; - this.setPermission(Settings.PERMPREFIX + "admin.top"); - this.setOnlyPlayer(false); - this.setUsage("admin.top.usage"); - } - - @Override - public boolean execute(User user, List args) { - int rank = 0; - for (Entry topTen : levelPlugin.getTopTen().getTopTenList().getTopTen().entrySet()) { - UUID player = topTen.getKey(); - rank++; - String item = String.valueOf(rank) + ":" + BSkyBlock.getPlugin().getIslands().getIslandName(player) + " " - + "topten.islandLevel" + String.valueOf(topTen.getValue()); - user.sendLegacyMessage(item); - } - - return true; - } - -} diff --git a/src/bskyblock/addin/level/commands/IslandTop.java b/src/bskyblock/addin/level/commands/IslandTop.java deleted file mode 100644 index 4ca37b9..0000000 --- a/src/bskyblock/addin/level/commands/IslandTop.java +++ /dev/null @@ -1,27 +0,0 @@ -package bskyblock.addin.level.commands; - -import java.util.List; - -import bskyblock.addin.level.Level; -import us.tastybento.bskyblock.api.commands.CompositeCommand; -import us.tastybento.bskyblock.api.commands.User; -import us.tastybento.bskyblock.config.Settings; - -public class IslandTop extends CompositeCommand { - - private final Level plugin; - - public IslandTop(Level plugin, CompositeCommand parent) { - super(parent, "top", "topten"); - this.plugin = plugin; - this.setPermission(Settings.PERMPREFIX + "island.top"); - this.setUsage("island.top.usage"); - } - - @Override - public boolean execute(User user, List list) { - plugin.getTopTen().getGUI(user.getPlayer()); - return false; - } - -} diff --git a/src/bskyblock/addin/level/config/PluginConfig.java b/src/bskyblock/addin/level/config/PluginConfig.java deleted file mode 100644 index ae70d30..0000000 --- a/src/bskyblock/addin/level/config/PluginConfig.java +++ /dev/null @@ -1,95 +0,0 @@ -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/src/bskyblock/addin/level/config/Settings.java b/src/bskyblock/addin/level/config/Settings.java deleted file mode 100644 index d01dfea..0000000 --- a/src/bskyblock/addin/level/config/Settings.java +++ /dev/null @@ -1,22 +0,0 @@ -package bskyblock.addin.level.config; - -import java.util.HashMap; - -import org.bukkit.material.MaterialData; - -public class Settings { - - 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/src/bskyblock/addin/level/database/object/Levels.java b/src/bskyblock/addin/level/database/object/Levels.java deleted file mode 100644 index 08d969c..0000000 --- a/src/bskyblock/addin/level/database/object/Levels.java +++ /dev/null @@ -1,28 +0,0 @@ -package bskyblock.addin.level.database.object; - -import us.tastybento.bskyblock.database.objects.DataObject; - -public class Levels extends DataObject { - - private String uniqueId = ""; - private long level = 0; - - @Override - public String getUniqueId() { - return uniqueId; - } - - @Override - public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId; - } - - public long getLevel() { - return level; - } - - public void setLevel(long level) { - this.level = level; - } - -} diff --git a/src/bskyblock/addin/level/event/IslandPostLevelEvent.java b/src/bskyblock/addin/level/event/IslandPostLevelEvent.java deleted file mode 100644 index 478bd5b..0000000 --- a/src/bskyblock/addin/level/event/IslandPostLevelEvent.java +++ /dev/null @@ -1,47 +0,0 @@ -package bskyblock.addin.level.event; - -import java.util.UUID; - -import us.tastybento.bskyblock.api.events.IslandBaseEvent; -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 IslandBaseEvent { - 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/src/bskyblock/addin/level/event/IslandPreLevelEvent.java b/src/bskyblock/addin/level/event/IslandPreLevelEvent.java deleted file mode 100644 index f3d8bd0..0000000 --- a/src/bskyblock/addin/level/event/IslandPreLevelEvent.java +++ /dev/null @@ -1,45 +0,0 @@ -package bskyblock.addin.level.event; - -import java.util.UUID; - -import us.tastybento.bskyblock.api.events.IslandBaseEvent; -import us.tastybento.bskyblock.database.objects.Island; - -public class IslandPreLevelEvent extends IslandBaseEvent { - - 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; - } - -} diff --git a/src/main/java/bskyblock/addon/level/Level.java b/src/main/java/bskyblock/addon/level/Level.java new file mode 100644 index 0000000..b2b14c1 --- /dev/null +++ b/src/main/java/bskyblock/addon/level/Level.java @@ -0,0 +1,191 @@ +package bskyblock.addon.level; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.World; + +import bskyblock.addon.level.commands.AdminLevel; +import bskyblock.addon.level.commands.AdminTop; +import bskyblock.addon.level.commands.IslandLevel; +import bskyblock.addon.level.commands.IslandTop; +import bskyblock.addon.level.config.Settings; +import bskyblock.addon.level.database.object.LevelsData; +import bskyblock.addon.level.listeners.NewIslandListener; +import world.bentobox.bentobox.api.addons.Addon; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.BSBDatabase; +import world.bentobox.bentobox.database.objects.Island; + + +/** + * Addon to BSkyBlock that enables island level scoring and top ten functionality + * @author tastybento + * + */ +public class Level extends Addon { + + // Settings + private Settings settings; + + // Database handler for level data + private BSBDatabase handler; + + // A cache of island levels. + private Map levelsCache; + + // The Top Ten object + private TopTen topTen; + + // Level calculator + private LevelPresenter levelCalc; + + /** + * Calculates a user's island + * @param world - the world where this island is + * @param user - the user who is asking, or null if none + * @param playerUUID - the target island member's UUID + */ + public void calculateIslandLevel(World world, User user, UUID playerUUID) { + levelCalc.calculateIslandLevel(world, user, playerUUID); + } + + /** + * Get level from cache for a player + * @param targetPlayer + * @return Level of player + */ + public long getIslandLevel(World world, UUID targetPlayer) { + LevelsData ld = getLevelsData(targetPlayer); + return ld == null ? 0L : ld.getLevel(world); + } + + private LevelsData getLevelsData(UUID targetPlayer) { + // Load player + return levelsCache.getOrDefault(targetPlayer, handler.loadObject(targetPlayer.toString())); + } + + /** + * @return the settings + */ + public final Settings getSettings() { + return settings; + } + + public TopTen getTopTen() { + return topTen; + } + + @Override + public void onDisable(){ + // Save the cache + if (levelsCache != null) { + save(false); + } + if (topTen != null) { + topTen.saveTopTen(); + } + } + + @Override + public void onEnable() { + // Check if it is enabled - it might be loaded, but not enabled. + if (getPlugin() == null || !getPlugin().isEnabled()) { + getLogger().severe("BSkyBlock does not exist or is not enabled. Stopping."); + this.setEnabled(false); + return; + } + // Load the plugin's config + settings = new Settings(this); + // Get the BSkyBlock database + // Set up the database handler to store and retrieve Island classes + // Note that these are saved by the BSkyBlock database + handler = new BSBDatabase<>(this, LevelsData.class); + // Initialize the cache + levelsCache = new HashMap<>(); + // Load the calculator + levelCalc = new LevelPresenter(this, this.getPlugin()); + // Start the top ten and register it for clicks + topTen = new TopTen(this); + registerListener(topTen); + // Register commands - run one tick later to allow all addons to load + // AcidIsland hook in + getServer().getScheduler().runTask(getPlugin(), () -> { + this.getPlugin().getAddonsManager().getAddonByName("AcidIsland").ifPresent(a -> { + CompositeCommand acidIslandCmd = getPlugin().getCommandsManager().getCommand("ai"); + if (acidIslandCmd != null) { + new IslandLevel(this, acidIslandCmd); + new IslandTop(this, acidIslandCmd); + CompositeCommand acidCmd = getPlugin().getCommandsManager().getCommand("acid"); + new AdminLevel(this, acidCmd); + new AdminTop(this, acidCmd); + } + }); + // BSkyBlock hook in + this.getPlugin().getAddonsManager().getAddonByName("BSkyBlock").ifPresent(a -> { + CompositeCommand bsbIslandCmd = getPlugin().getCommandsManager().getCommand("island"); + if (bsbIslandCmd != null) { + new IslandLevel(this, bsbIslandCmd); + new IslandTop(this, bsbIslandCmd); + CompositeCommand bsbAdminCmd = getPlugin().getCommandsManager().getCommand("bsbadmin"); + new AdminLevel(this, bsbAdminCmd); + new AdminTop(this, bsbAdminCmd); + } + }); + }); + + // Register new island listener + registerListener(new NewIslandListener(this)); + // Done + + } + + /** + * Save the levels to the database + * @param async - if true, saving will be done async + */ + public void save(boolean async){ + Runnable save = () -> levelsCache.values().forEach(handler::saveObject); + if(async){ + getServer().getScheduler().runTaskAsynchronously(getPlugin(), save); + } else { + save.run(); + } + } + + /** + * Sets the player's level to a value + * @param world + * @param targetPlayer + * @param level + */ + public void setIslandLevel(World world, UUID targetPlayer, long level) { + LevelsData ld = getLevelsData(targetPlayer); + if (ld == null) { + ld = new LevelsData(targetPlayer, level, world); + } else { + ld.setLevel(world, level); + } + // Add to cache + levelsCache.put(targetPlayer, ld); + topTen.addEntry(world, targetPlayer, getIslandLevel(world, targetPlayer)); + } + + /** + * Sets the initial island level + * @param island - island + * @param level - initial calculated island level + */ + public void setInitialIslandLevel(Island island, long level) { + setIslandLevel(island.getWorld(), island.getOwner(), level); + levelsCache.get(island.getOwner()).setInitialIslandLevel(level); + } + + + public BSBDatabase getHandler() { + return handler; + } + +} diff --git a/src/main/java/bskyblock/addon/level/LevelPresenter.java b/src/main/java/bskyblock/addon/level/LevelPresenter.java new file mode 100644 index 0000000..8998fa0 --- /dev/null +++ b/src/main/java/bskyblock/addon/level/LevelPresenter.java @@ -0,0 +1,100 @@ +package bskyblock.addon.level; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.UUID; + +import org.bukkit.World; + +import bskyblock.addon.level.calculators.PlayerLevel; +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.user.User; + +public class LevelPresenter { + + private int levelWait; + private final Level addon; + private final BentoBox plugin; + + // Level calc cool down + private HashMap levelWaitTime = new HashMap(); + + public LevelPresenter(Level addon, BentoBox plugin) { + this.addon = addon; + this.plugin = plugin; + } + + /** + * Calculates the island level + * @param world - world to check + * @param sender - asker of the level info + * @param targetPlayer + * @return - false if this is cannot be done + */ + public boolean calculateIslandLevel(World world, final User sender, UUID targetPlayer) { + // Get permission prefix for this world + String permPrefix = plugin.getIWM().getPermissionPrefix(world); + // Check if target has island + boolean inTeam = false; + if (!plugin.getIslands().hasIsland(world, targetPlayer)) { + // Player may be in a team + if (plugin.getIslands().inTeam(world, targetPlayer)) { + targetPlayer = plugin.getIslands().getTeamLeader(world, targetPlayer); + inTeam = true; + } else { + sender.sendMessage("general.errors.player-has-no-island"); + return false; + } + } + // Player asking for their own island calc + if (inTeam || !sender.isPlayer() || sender.getUniqueId().equals(targetPlayer) || sender.isOp() || sender.hasPermission(permPrefix + "mod.info")) { + // Newer better system - uses chunks + if (!onLevelWaitTime(sender) || levelWait <= 0 || sender.isOp() || sender.hasPermission(permPrefix + "mod.info")) { + sender.sendMessage("island.level.calculating"); + setLevelWaitTime(sender); + new PlayerLevel(addon, plugin.getIslands().getIsland(world, targetPlayer), targetPlayer, sender); + } else { + // Cooldown + sender.sendMessage("island.level.cooldown", "[time]", String.valueOf(getLevelWaitTime(sender))); + } + + } else { + // Asking for the level of another player + sender.sendMessage("island.level.island-level-is","[level]", String.valueOf(addon.getIslandLevel(world, targetPlayer))); + } + return true; + } + + /** + * Sets cool down for the level command + * + * @param player + */ + private void setLevelWaitTime(final User player) { + levelWaitTime.put(player.getUniqueId(), Long.valueOf(Calendar.getInstance().getTimeInMillis() + levelWait * 1000)); + } + + private boolean onLevelWaitTime(final User sender) { + if (levelWaitTime.containsKey(sender.getUniqueId())) { + if (levelWaitTime.get(sender.getUniqueId()).longValue() > Calendar.getInstance().getTimeInMillis()) { + return true; + } + + return false; + } + + return false; + } + + private long getLevelWaitTime(final User sender) { + if (levelWaitTime.containsKey(sender.getUniqueId())) { + if (levelWaitTime.get(sender.getUniqueId()).longValue() > Calendar.getInstance().getTimeInMillis()) { + return (levelWaitTime.get(sender.getUniqueId()).longValue() - Calendar.getInstance().getTimeInMillis()) / 1000; + } + + return 0L; + } + + return 0L; + } +} diff --git a/src/main/java/bskyblock/addon/level/TopTen.java b/src/main/java/bskyblock/addon/level/TopTen.java new file mode 100644 index 0000000..a0aa8de --- /dev/null +++ b/src/main/java/bskyblock/addon/level/TopTen.java @@ -0,0 +1,216 @@ +package bskyblock.addon.level; + +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.World; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; + +import bskyblock.addon.level.database.object.LevelsData; +import bskyblock.addon.level.database.object.TopTenData; +import world.bentobox.bentobox.api.panels.PanelItem; +import world.bentobox.bentobox.api.panels.builders.PanelBuilder; +import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.BSBDatabase; + +/** + * Handles all Top Ten List functions + * + * @author tastybento + * + */ +public class TopTen implements Listener { + private Level addon; + // Top ten list of players + private Map topTenList; + private final int[] SLOTS = new int[] {4, 12, 14, 19, 20, 21, 22, 23, 24, 25}; + private final boolean DEBUG = false; + private BSBDatabase handler; + + public TopTen(Level addon) { + this.addon = addon; + // Set up the database handler to store and retrieve the TopTenList class + // Note that these are saved in the BSkyBlock database + handler = new BSBDatabase<>(addon, TopTenData.class); + loadTopTen(); + } + + /** + * Adds a player to the top ten, if the level is good enough + * + * @param ownerUUID + * @param l + */ + public void addEntry(World world, UUID ownerUUID, long l) { + // Check if player is an island owner or not + if (!addon.getIslands().isOwner(world, ownerUUID)) { + return; + } + // Set up world data + topTenList.putIfAbsent(world, new TopTenData()); + topTenList.get(world).setUniqueId(world.getName()); + + // Try and see if the player is online + Player player = addon.getServer().getPlayer(ownerUUID); + if (player != null) { + // Online + if (!player.hasPermission(addon.getPlugin().getIWM().getPermissionPrefix(world) + ".intopten")) { + topTenList.get(world).remove(ownerUUID); + return; + } + } + topTenList.get(world).addLevel(ownerUUID, l); + } + + /** + * 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. + */ + public void create(String permPrefix) { + // Obtain all the levels for each known player + BSBDatabase levelHandler = addon.getHandler(); + long index = 0; + for (LevelsData lv : levelHandler.loadObjects()) { + if (index++ % 1000 == 0) { + addon.getLogger().info("Processed " + index + " players for top ten"); + } + // Convert to UUID + UUID playerUUID = UUID.fromString(lv.getUniqueId()); + // Get the world + lv.getLevels().forEach((k,v) -> addEntry(Bukkit.getWorld(k), playerUUID, v)); + } + saveTopTen(); + } + + /** + * Displays the Top Ten list + * @param world + * + * @param user + * - the requesting player + * @return - true if successful, false if no Top Ten list exists + */ + public boolean getGUI(World world, final User user, String permPrefix) { + // Check world + topTenList.putIfAbsent(world, new TopTenData()); + topTenList.get(world).setUniqueId(world.getName()); + if (DEBUG) + addon.getLogger().info("DEBUG: GUI display"); + + PanelBuilder panel = new PanelBuilder() + .name(user.getTranslation("island.top.gui-title")) + .user(user); + + int i = 1; + Iterator> it = topTenList.get(world).getTopTen().entrySet().iterator(); + while (it.hasNext()) { + Map.Entry m = it.next(); + UUID topTenUUID = m.getKey(); + if (DEBUG) + addon.getLogger().info("DEBUG: " + i + ": " + topTenUUID); + // Remove from TopTen if the player is online and has the permission + Player entry = addon.getServer().getPlayer(topTenUUID); + boolean show = true; + if (entry != null) { + if (DEBUG) + addon.getLogger().info("DEBUG: removing from topten"); + if (!entry.hasPermission(permPrefix + "intopten")) { + it.remove(); + show = false; + } + } else { + if (DEBUG) + addon.getLogger().info("DEBUG: player not online, so no per check"); + + } + if (show) { + panel.item(SLOTS[i-1], getHead(i, m.getValue(), topTenUUID, user, world)); + if (i++ == 10) break; + } + } + panel.build(); + return true; + } + + /** + * Get the head panel item + * @param rank - the top ten rank of this player/team. Can be used in the name of the island for vanity. + * @param level - the level of the island + * @param playerUUID - the UUID of the top ten player + * @param asker - the asker of the top ten + * @return PanelItem + */ + private PanelItem getHead(int rank, Long level, UUID playerUUID, User asker, World world) { + final String name = addon.getPlayers().getName(playerUUID); + List description = new ArrayList<>(); + if (name != null) { + description.add(asker.getTranslation("island.top.gui-heading", "[name]", name, "[rank]", String.valueOf(rank))); + description.add(asker.getTranslation("island.top.island-level","[level]", String.valueOf(level))); + if (addon.getIslands().inTeam(world, playerUUID)) { + List memberList = new ArrayList<>(); + for (UUID members : addon.getIslands().getMembers(world, playerUUID)) { + memberList.add(ChatColor.AQUA + addon.getPlayers().getName(members)); + } + description.addAll(memberList); + } + } + PanelItemBuilder builder = new PanelItemBuilder() + .icon(name) + .name(name) + .description(description); + + // If welcome warps is present then add warping + /* + addon.getAddonByName("BSkyBlock-WelcomeWarps").ifPresent(warp -> { + + if (((Warp)warp).getWarpSignsManager().hasWarp(world, playerUUID)) { + builder.clickHandler((panel, user, click, slot) -> { + if (click.equals(ClickType.LEFT)) { + user.sendMessage("island.top.warp-to", "[name]", name); + ((Warp)warp).getWarpSignsManager().warpPlayer(world, user, playerUUID); + } + return true; + }); + } + });*/ + return builder.build(); + } + + public TopTenData getTopTenList(World world) { + return topTenList.get(world); + } + + /** + * Loads all the top tens from the database + */ + public void loadTopTen() { + topTenList = new HashMap<>(); + handler.loadObjects().forEach(tt -> topTenList.put(Bukkit.getWorld(tt.getUniqueId()), tt)); + } + + /** + * Removes ownerUUID from the top ten list + * + * @param ownerUUID + */ + public void removeEntry(World world, UUID ownerUUID) { + topTenList.putIfAbsent(world, new TopTenData()); + topTenList.get(world).setUniqueId(world.getName()); + topTenList.get(world).remove(ownerUUID); + } + + public void saveTopTen() { + topTenList.values().forEach(handler::saveObject); + } + +} diff --git a/src/main/java/bskyblock/addon/level/calculators/CalcIslandLevel.java b/src/main/java/bskyblock/addon/level/calculators/CalcIslandLevel.java new file mode 100644 index 0000000..919d98b --- /dev/null +++ b/src/main/java/bskyblock/addon/level/calculators/CalcIslandLevel.java @@ -0,0 +1,364 @@ +package bskyblock.addon.level.calculators; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.scheduler.BukkitTask; + +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.addon.level.Level; +import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.util.Pair; +import world.bentobox.bentobox.util.Util; + + +public class CalcIslandLevel { + + private static final int MAX_CHUNKS = 200; + private static final long SPEED = 1; + private boolean checking = true; + private BukkitTask task; + + private Level addon; + + private Set> chunksToScan; + private Island island; + private World world; + private Results result; + private Runnable onExit; + + // Copy the limits hashmap + HashMap limitCount; + + + /** + * Calculate the island's level + * Results are available in {@link CalcIslandLevel.Results} + * @param addon - Level addon + * @param island - island to be calculated + * @param onExit - what to run when done + */ + public CalcIslandLevel(final Level addon, final Island island, final Runnable onExit) { + this.addon = addon; + this.island = island; + this.world = island != null ? island.getCenter().getWorld() : null; + this.limitCount = new HashMap<>(addon.getSettings().getBlockLimits()); + this.onExit = onExit; + + // Results go here + result = new Results(); + + // Get chunks to scan + chunksToScan = getChunksToScan(island); + + // Start checking + checking = true; + + // Start a recurring task until done or cancelled + task = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> { + Set chunkSnapshot = new HashSet<>(); + if (checking) { + Iterator> it = chunksToScan.iterator(); + if (!it.hasNext()) { + // Nothing left + tidyUp(); + return; + } + // Add chunk snapshots to the list + while (it.hasNext() && chunkSnapshot.size() < MAX_CHUNKS) { + Pair pair = it.next(); + if (!world.isChunkLoaded(pair.x, pair.z)) { + world.loadChunk(pair.x, pair.z); + chunkSnapshot.add(world.getChunkAt(pair.x, pair.z).getChunkSnapshot()); + world.unloadChunk(pair.x, pair.z); + } else { + chunkSnapshot.add(world.getChunkAt(pair.x, pair.z).getChunkSnapshot()); + } + it.remove(); + } + // Move to next step + checking = false; + checkChunksAsync(chunkSnapshot); + } + }, 0L, SPEED); + } + + private void checkChunksAsync(final Set chunkSnapshot) { + // Run async task to scan chunks + addon.getServer().getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { + for (ChunkSnapshot chunk: chunkSnapshot) { + scanChunk(chunk); + } + // Nothing happened, change state + checking = true; + }); + + } + + private void scanChunk(ChunkSnapshot chunk) { + 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) { + 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) { + continue; + } + + for (int y = 0; y < island.getCenter().getWorld().getMaxHeight(); y++) { + Material blockData = chunk.getBlockType(x, y, z); + boolean belowSeaLevel = (addon.getSettings().getSeaHeight() > 0 && y<=addon.getSettings().getSeaHeight()) ? true : false; + // Air is free + if (!blockData.equals(Material.AIR)) { + checkBlock(blockData, belowSeaLevel); + } + } + } + } + } + + private void checkBlock(Material md, boolean belowSeaLevel) { + int count = limitCount(md); + if (belowSeaLevel) { + result.underWaterBlockCount += count; + result.uwCount.add(md); + } else { + result.rawBlockCount += count; + result.mdCount.add(md); + } + } + + /** + * Checks if a block has been limited or not and whether a block has any value or not + * @param md + * @return value of the block if can be counted + */ + private int limitCount(Material md) { + if (limitCount.containsKey(md)) { + int count = limitCount.get(md); + if (count > 0) { + limitCount.put(md, --count); + return getValue(md); + } else { + result.ofCount.add(md); + return 0; + } + } else if (addon.getSettings().getBlockValues().containsKey(md)) { + return getValue(md); + } else { + result.ncCount.add(md); + return 0; + } + } + + /** + * Get value of a material + * World blocks trump regular block values + * @param md + * @return value of a material + */ + private int getValue(Material md) { + if (addon.getSettings().getWorldBlockValues().containsKey(world) && addon.getSettings().getWorldBlockValues().get(world).containsKey(md)) { + return addon.getSettings().getWorldBlockValues().get(world).get(md); + } + return addon.getSettings().getBlockValues().getOrDefault(md, 0); + } + + /** + * Get a set of all the chunks in island + * @param island + * @return + */ + private Set> getChunksToScan(Island island) { + 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) { + Pair pair = new Pair<>(world.getBlockAt(x, 0, z).getChunk().getX(), world.getBlockAt(x, 0, z).getChunk().getZ()); + chunkSnapshot.add(pair); + } + } + return chunkSnapshot; + } + + private void tidyUp() { + // Cancel + task.cancel(); + // Finalize calculations + result.rawBlockCount += (long)(result.underWaterBlockCount * addon.getSettings().getUnderWaterMultiplier()); + // Set the death penalty + result.deathHandicap = addon.getPlayers().getDeaths(world, island.getOwner()); + // Set final score + result.level = (result.rawBlockCount / addon.getSettings().getLevelCost()) - result.deathHandicap - island.getLevelHandicap(); + // Calculate how many points are required to get to the next level + result.pointsToNextLevel = (addon.getSettings().getLevelCost() * (result.level + 1 + island.getLevelHandicap())) - (result.rawBlockCount - (result.deathHandicap * addon.getSettings().getDeathPenalty())); + // Sometimes it will return 0, so calculate again to make sure it will display a good value + if(result.pointsToNextLevel == 0) result.pointsToNextLevel = (addon.getSettings().getLevelCost() * (result.level + 2 + island.getLevelHandicap()) - (result.rawBlockCount - (result.deathHandicap * addon.getSettings().getDeathPenalty()))); + // Report + result.report = getReport(); + // All done. + if (onExit != null) { + Bukkit.getScheduler().runTask(addon.getPlugin(), onExit); + } + } + + + private List getReport() { + List reportLines = new ArrayList<>(); + // provide counts + reportLines.add("Level Log for island in " + addon.getPlugin().getIWM().getFriendlyName(island.getWorld()) + " at " + Util.xyz(island.getCenter().toVector())); + reportLines.add("Island owner UUID = " + island.getOwner()); + reportLines.add("Total block value count = " + String.format("%,d",result.rawBlockCount)); + reportLines.add("Level cost = " + addon.getSettings().getLevelCost()); + reportLines.add("Deaths handicap = " + result.deathHandicap); + reportLines.add("Level calculated = " + result.level); + reportLines.add("=================================="); + int total = 0; + if (!result.uwCount.isEmpty()) { + reportLines.add("Underwater block count (Multiplier = x" + addon.getSettings().getUnderWaterMultiplier() + ") value"); + reportLines.add("Total number of underwater blocks = " + String.format("%,d",result.uwCount.size())); + reportLines.addAll(sortedReport(total, result.uwCount)); + } + reportLines.add("Regular block count"); + reportLines.add("Total number of blocks = " + String.format("%,d",result.mdCount.size())); + reportLines.addAll(sortedReport(total, result.mdCount)); + + reportLines.add("Blocks not counted because they exceeded limits: " + String.format("%,d",result.ofCount.size())); + //entriesSortedByCount = Multisets.copyHighestCountFirst(ofCount).entrySet(); + Iterable> entriesSortedByCount = result.ofCount.entrySet(); + Iterator> it = entriesSortedByCount.iterator(); + while (it.hasNext()) { + Entry type = it.next(); + Integer limit = addon.getSettings().getBlockLimits().get(type.getElement()); + String explain = ")"; + if (limit == null) { + Material generic = type.getElement(); + limit = addon.getSettings().getBlockLimits().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 config.yml"); + reportLines.add("Total number = " + String.format("%,d",result.ncCount.size())); + //entriesSortedByCount = Multisets.copyHighestCountFirst(ncCount).entrySet(); + entriesSortedByCount = result.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("================================="); + + return reportLines; + } + + private Collection sortedReport(int total, Multiset MaterialCount) { + Collection result = new ArrayList<>(); + Iterable> entriesSortedByCount = Multisets.copyHighestCountFirst(MaterialCount).entrySet(); + Iterator> it = entriesSortedByCount.iterator(); + while (it.hasNext()) { + Entry en = it.next(); + Material type = en.getElement(); + + int value = 0; + if (addon.getSettings().getBlockValues().containsKey(type)) { + // Specific + value = addon.getSettings().getBlockValues().get(type); + } + result.add(type.toString() + ":" + + String.format("%,d",en.getCount()) + " blocks x " + value + " = " + (value * en.getCount())); + total += (value * en.getCount()); + } + result.add("Subtotal = " + total); + result.add("=================================="); + return result; + } + + /** + * @return the result + */ + public Results getResult() { + return result; + } + + /** + * Results class + * + */ + public class Results { + private List report; + private Multiset mdCount = HashMultiset.create(); + private Multiset uwCount = HashMultiset.create(); + private Multiset ncCount = HashMultiset.create(); + private Multiset ofCount = HashMultiset.create(); + private long rawBlockCount = 0; + private long underWaterBlockCount = 0; + private long level = 0; + private int deathHandicap = 0; + private long pointsToNextLevel = 0; + /** + * @return the deathHandicap + */ + public int getDeathHandicap() { + return deathHandicap; + } + /** + * @param deathHandicap the deathHandicap to set + */ + public void setDeathHandicap(int deathHandicap) { + this.deathHandicap = deathHandicap; + } + /** + * @return the report + */ + public List getReport() { + return report; + } + /** + * @return the level + */ + public long getLevel() { + return level; + } + /** + * @return the pointsToNextLevel + */ + public long getPointsToNextLevel() { + return pointsToNextLevel; + } + /** + * @param report the report to set + */ + public void setReport(List report) { + this.report = report; + } + /** + * @param level the level to set + */ + public void setLevel(long level) { + this.level = level; + } + /** + * @param pointsToNextLevel the pointsToNextLevel to set + */ + public void setPointsToNextLevel(long pointsToNextLevel) { + this.pointsToNextLevel = pointsToNextLevel; + } + + } +} diff --git a/src/main/java/bskyblock/addon/level/calculators/PlayerLevel.java b/src/main/java/bskyblock/addon/level/calculators/PlayerLevel.java new file mode 100644 index 0000000..f9c0f1d --- /dev/null +++ b/src/main/java/bskyblock/addon/level/calculators/PlayerLevel.java @@ -0,0 +1,88 @@ +package bskyblock.addon.level.calculators; + +import java.util.UUID; + +import org.bukkit.World; + +import bskyblock.addon.level.Level; +import bskyblock.addon.level.calculators.CalcIslandLevel.Results; +import bskyblock.addon.level.event.IslandLevelCalculatedEvent; +import bskyblock.addon.level.event.IslandPreLevelEvent; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.objects.Island; + + +/** + * Gets the player's island level. For admin or players + * @author tastybento + * + */ +public class PlayerLevel { + + private Level addon; + + private Island island; + private World world; + private User asker; + private UUID targetPlayer; + + private long oldLevel; + + private CalcIslandLevel calc; + + + public PlayerLevel(final Level addon, final Island island, final UUID targetPlayer, final User asker) { + this.addon = addon; + this.island = island; + this.world = island != null ? island.getCenter().getWorld() : null; + this.asker = asker; + this.targetPlayer = targetPlayer; + this.oldLevel = addon.getIslandLevel(world, targetPlayer); + + // Fire pre-level calc event + IslandPreLevelEvent e = new IslandPreLevelEvent(targetPlayer, island); + addon.getServer().getPluginManager().callEvent(e); + if (!e.isCancelled()) { + // Calculate if not cancelled + calc = new CalcIslandLevel(addon, island, ()-> informPlayers()); + } + } + + + private void informPlayers() { + // Fire post calculation event + IslandLevelCalculatedEvent ilce = new IslandLevelCalculatedEvent(targetPlayer, island, calc.getResult()); + addon.getServer().getPluginManager().callEvent(ilce); + Results results = ilce.getResults(); + // Save the results + island.getMemberSet().forEach(m -> addon.setIslandLevel(world, m, results.getLevel())); + // Display result + if (!ilce.isCancelled()) { + // Tell the asker + asker.sendMessage("island.level.island-level-is", "[level]", String.valueOf(addon.getIslandLevel(world, targetPlayer))); + // Console + if (!asker.isPlayer()) { + results.getReport().forEach(asker::sendRawMessage); + return; + } + // Player + if (addon.getSettings().getDeathPenalty() != 0) { + asker.sendMessage("island.level.deaths", "[number]", String.valueOf(results.getDeathHandicap())); + } + // Send player how many points are required to reach next island level + if (results.getPointsToNextLevel() >= 0) { + asker.sendMessage("island.level.required-points-to-next-level", "[points]", String.valueOf(addon.getIslandLevel(world, targetPlayer))); + } + // Tell other team members + if (addon.getIslandLevel(world, targetPlayer) != oldLevel) { + for (UUID member : island.getMemberSet()) { + if (!member.equals(asker.getUniqueId())) { + User.getInstance(member).sendMessage("island.level.island-level-is", "[level]", String.valueOf(addon.getIslandLevel(world, targetPlayer))); + } + } + } + } + } + + +} diff --git a/src/main/java/bskyblock/addon/level/commands/AdminLevel.java b/src/main/java/bskyblock/addon/level/commands/AdminLevel.java new file mode 100644 index 0000000..87308fa --- /dev/null +++ b/src/main/java/bskyblock/addon/level/commands/AdminLevel.java @@ -0,0 +1,48 @@ +package bskyblock.addon.level.commands; + +import java.util.List; +import java.util.UUID; + +import bskyblock.addon.level.Level; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.user.User; + +public class AdminLevel extends CompositeCommand { + + private final Level levelPlugin; + + public AdminLevel(Level levelPlugin, CompositeCommand parent) { + super(parent, "level"); + this.levelPlugin = levelPlugin; + } + + @Override + public boolean execute(User user, String label, List args) { + if (args.size() == 1) { + // Asking for another player's level? + // Convert name to a UUID + final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0)); + //getLogger().info("DEBUG: console player info UUID = " + playerUUID); + if (playerUUID == null) { + user.sendMessage("general.errors.unknown-player"); + return true; + } else { + levelPlugin.calculateIslandLevel(getWorld(), user, playerUUID); + } + return true; + } else { + showHelp(this, user); + return false; + } + } + + @Override + public void setup() { + this.setPermission("admin.level"); + this.setOnlyPlayer(false); + this.setParameters("admin.level.parameters"); + this.setDescription("admin.level.description"); + + } + +} diff --git a/src/main/java/bskyblock/addon/level/commands/AdminTop.java b/src/main/java/bskyblock/addon/level/commands/AdminTop.java new file mode 100644 index 0000000..c0add98 --- /dev/null +++ b/src/main/java/bskyblock/addon/level/commands/AdminTop.java @@ -0,0 +1,64 @@ +package bskyblock.addon.level.commands; + +import java.util.List; +import java.util.Map.Entry; +import java.util.UUID; + +import org.bukkit.World; + +import bskyblock.addon.level.Level; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.objects.Island; + +public class AdminTop extends CompositeCommand { + + private final Level levelPlugin; + + public AdminTop(Level levelPlugin, CompositeCommand parent) { + super(parent, "top", "topten"); + this.levelPlugin = levelPlugin; + } + + @Override + public boolean execute(User user, String label, List args) { + // Get world + World world = null; + if (args.isEmpty()) { + if (getPlugin().getIWM().getOverWorlds().size() == 1) { + world = getPlugin().getIWM().getOverWorlds().get(0); + } else { + showHelp(this, user); + return false; + } + } else { + if (getPlugin().getIWM().isOverWorld(args.get(0))) { + world = getPlugin().getIWM().getIslandWorld(args.get(0)); + } else { + user.sendMessage("commands.admin.top.unknown-world"); + return false; + } + + } + int rank = 0; + for (Entry topTen : levelPlugin.getTopTen().getTopTenList(world).getTopTen().entrySet()) { + Island island = getPlugin().getIslands().getIsland(world, topTen.getKey()); + if (island != null) { + rank++; + String item = String.valueOf(rank) + ":" + island.getName() + " " + + user.getTranslation("topten.islandLevel", "[level]", String.valueOf(topTen.getValue())); + user.sendRawMessage(item); + } + } + + return true; + } + + @Override + public void setup() { + this.setPermission("admin.top"); + this.setOnlyPlayer(false); + this.setDescription("admin.top.description"); + } + +} diff --git a/src/bskyblock/addin/level/commands/IslandLevel.java b/src/main/java/bskyblock/addon/level/commands/IslandLevel.java similarity index 50% rename from src/bskyblock/addin/level/commands/IslandLevel.java rename to src/main/java/bskyblock/addon/level/commands/IslandLevel.java index dbcaa04..8e98a0b 100644 --- a/src/bskyblock/addin/level/commands/IslandLevel.java +++ b/src/main/java/bskyblock/addon/level/commands/IslandLevel.java @@ -1,48 +1,51 @@ -package bskyblock.addin.level.commands; +package bskyblock.addon.level.commands; import java.util.List; import java.util.UUID; -import bskyblock.addin.level.Level; -import us.tastybento.bskyblock.api.commands.CompositeCommand; -import us.tastybento.bskyblock.api.commands.User; -import us.tastybento.bskyblock.config.Settings; +import bskyblock.addon.level.Level; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.user.User; public class IslandLevel extends CompositeCommand { - + private final Level levelPlugin; - + public IslandLevel(Level levelPlugin, CompositeCommand parent) { super(parent, "level"); this.levelPlugin = levelPlugin; - this.setPermission(Settings.PERMPREFIX + "island.level"); - this.setUsage("island.level.usage"); - this.setOnlyPlayer(true); } @Override - public boolean execute(User user, List args) { + public boolean execute(User user, String label, List args) { if (!args.isEmpty()) { // Asking for another player's level? // Convert name to a UUID - final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0), true); + final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0)); //getLogger().info("DEBUG: console player info UUID = " + playerUUID); if (playerUUID == null) { - user.sendMessage("error.UnknownPlayer"); + user.sendMessage("general.errors.unknown-player"); return true; } else if (user.getUniqueId().equals(playerUUID) ) { // Self level request - levelPlugin.calculateIslandLevel(user, user.getUniqueId(), false); + levelPlugin.calculateIslandLevel(getWorld(), user, user.getUniqueId()); } else { - user.sendMessage("addon.level.level-is", "[level]", String.valueOf(levelPlugin.getIslandLevel(playerUUID))); - user.sendLegacyMessage("Level = " + String.valueOf(levelPlugin.getIslandLevel(playerUUID))); + user.sendMessage("island.level.island-level-is", "[level]", String.valueOf(levelPlugin.getIslandLevel(getWorld(), playerUUID))); return true; } } else { // Self level request - levelPlugin.calculateIslandLevel(user, user.getUniqueId(), false); + levelPlugin.calculateIslandLevel(getWorld(), user, user.getUniqueId()); } return false; } + @Override + public void setup() { + this.setPermission("island.level"); + this.setParameters("island.level.parameters"); + this.setDescription("island.level.description"); + this.setOnlyPlayer(true); + } + } diff --git a/src/main/java/bskyblock/addon/level/commands/IslandTop.java b/src/main/java/bskyblock/addon/level/commands/IslandTop.java new file mode 100644 index 0000000..1bd0a19 --- /dev/null +++ b/src/main/java/bskyblock/addon/level/commands/IslandTop.java @@ -0,0 +1,32 @@ +package bskyblock.addon.level.commands; + +import java.util.List; + +import bskyblock.addon.level.Level; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.user.User; + +public class IslandTop extends CompositeCommand { + + private final Level plugin; + + public IslandTop(Level plugin, CompositeCommand parent) { + super(parent, "top", "topten"); + this.plugin = plugin; + } + + @Override + public boolean execute(User user, String label, List list) { + plugin.getTopTen().getGUI(getWorld(), user, getPermissionPrefix()); + return true; + } + + @Override + public void setup() { + this.setPermission("island.top"); + this.setDescription("island.top.description"); + + + } + +} diff --git a/src/main/java/bskyblock/addon/level/config/Settings.java b/src/main/java/bskyblock/addon/level/config/Settings.java new file mode 100644 index 0000000..4e1d5b6 --- /dev/null +++ b/src/main/java/bskyblock/addon/level/config/Settings.java @@ -0,0 +1,250 @@ +package bskyblock.addon.level.config; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.configuration.ConfigurationSection; + +import bskyblock.addon.level.Level; + +public class Settings { + + private boolean sumTeamDeaths; + private int seaHeight; + private Map blockLimits = new HashMap<>(); + private Map blockValues = new HashMap<>(); + private Map> worldBlockValues = new HashMap<>(); + private double underWaterMultiplier; + private int deathpenalty; + private long levelCost; + private Object defaultLanguage; + private int levelWait; + private int maxDeaths; + private boolean islandResetDeathReset; + private boolean teamJoinDeathReset; + + public Settings(Level level) { + + level.saveDefaultConfig(); + + setLevelWait(level.getConfig().getInt("levelwait", 60)); + if (getLevelWait() < 0) { + setLevelWait(0); + } + setDeathpenalty(level.getConfig().getInt("deathpenalty", 0)); + setSumTeamDeaths(level.getConfig().getBoolean("sumteamdeaths")); + setMaxDeaths(level.getConfig().getInt("maxdeaths", 10)); + setIslandResetDeathReset(level.getConfig().getBoolean("islandresetdeathreset", true)); + setTeamJoinDeathReset(level.getConfig().getBoolean("teamjoindeathreset", true)); + setUnderWaterMultiplier(level.getConfig().getDouble("underwater", 1D)); + setLevelCost(level.getConfig().getInt("levelcost", 100)); + if (getLevelCost() < 1) { + setLevelCost(1); + level.getLogger().warning("levelcost in blockvalues.yml cannot be less than 1. Setting to 1."); + } + + if (level.getConfig().isSet("limits")) { + HashMap blockLimits = new HashMap<>(); + for (String material : level.getConfig().getConfigurationSection("limits").getKeys(false)) { + try { + Material mat = Material.valueOf(material); + blockLimits.put(mat, level.getConfig().getInt("limits." + material, 0)); + } catch (Exception e) { + level.getLogger().warning("Unknown material (" + material + ") in blockvalues.yml Limits section. Skipping..."); + } + } + setBlockLimits(blockLimits); + } + if (level.getConfig().isSet("blocks")) { + Map blockValues = new HashMap<>(); + for (String material : level.getConfig().getConfigurationSection("blocks").getKeys(false)) { + + try { + Material mat = Material.valueOf(material); + blockValues.put(mat, level.getConfig().getInt("blocks." + material, 0)); + } catch (Exception e) { + // e.printStackTrace(); + level.getLogger().warning("Unknown material (" + material + ") in config.yml blocks section. Skipping..."); + } + } + setBlockValues(blockValues); + } else { + level.getLogger().severe("No block values in config.yml! All island levels will be zero!"); + } + // Worlds + if (level.getConfig().isSet("worlds")) { + ConfigurationSection worlds = level.getConfig().getConfigurationSection("worlds"); + for (String world : worlds.getKeys(false)) { + World bWorld = Bukkit.getWorld(world); + if (bWorld != null) { + ConfigurationSection worldValues = worlds.getConfigurationSection(world); + for (String material : worldValues.getKeys(false)) { + Material mat = Material.valueOf(material); + Map values = worldBlockValues.getOrDefault(bWorld, new HashMap<>()); + values.put(mat, worldValues.getInt("blocks." + material, 0)); + worldBlockValues.put(bWorld, values); + } + } else { + level.getLogger().severe("Level Addon: No such world : " + world); + } + } + } + // All done + } + + /** + * @return the sumTeamDeaths + */ + public final boolean isSumTeamDeaths() { + return sumTeamDeaths; + } + /** + * @param sumTeamDeaths the sumTeamDeaths to set + */ + public final void setSumTeamDeaths(boolean sumTeamDeaths) { + this.sumTeamDeaths = sumTeamDeaths; + } + /** + * @return the seaHeight + */ + public final int getSeaHeight() { + return seaHeight; + } + /** + * @param seaHeight the seaHeight to set + */ + public final void setSeaHeight(int seaHeight) { + this.seaHeight = seaHeight; + } + /** + * @return the blockLimits + */ + public final Map getBlockLimits() { + return blockLimits; + } + /** + * @param blockLimits2 the blockLimits to set + */ + public final void setBlockLimits(HashMap blockLimits2) { + this.blockLimits = blockLimits2; + } + /** + * @return the blockValues + */ + public final Map getBlockValues() { + return blockValues; + } + /** + * @param blockValues2 the blockValues to set + */ + public final void setBlockValues(Map blockValues2) { + this.blockValues = blockValues2; + } + /** + * @return the underWaterMultiplier + */ + public final double getUnderWaterMultiplier() { + return underWaterMultiplier; + } + /** + * @param underWaterMultiplier the underWaterMultiplier to set + */ + public final void setUnderWaterMultiplier(double underWaterMultiplier) { + this.underWaterMultiplier = underWaterMultiplier; + } + /** + * @return the deathpenalty + */ + public final int getDeathPenalty() { + return deathpenalty; + } + /** + * @param deathpenalty the deathpenalty to set + */ + public final void setDeathpenalty(int deathpenalty) { + this.deathpenalty = deathpenalty; + } + /** + * @return the levelCost + */ + public final long getLevelCost() { + return levelCost; + } + /** + * @param levelCost the levelCost to set + */ + public final void setLevelCost(long levelCost) { + this.levelCost = levelCost; + } + /** + * @return the defaultLanguage + */ + public final Object getDefaultLanguage() { + return defaultLanguage; + } + /** + * @param defaultLanguage the defaultLanguage to set + */ + public final void setDefaultLanguage(Object defaultLanguage) { + this.defaultLanguage = defaultLanguage; + } + /** + * @return the levelWait + */ + public final int getLevelWait() { + return levelWait; + } + /** + * @param levelWait the levelWait to set + */ + public final void setLevelWait(int levelWait) { + this.levelWait = levelWait; + } + /** + * @return the maxDeaths + */ + public final int getMaxDeaths() { + return maxDeaths; + } + /** + * @param maxDeaths the maxDeaths to set + */ + public final void setMaxDeaths(int maxDeaths) { + this.maxDeaths = maxDeaths; + } + /** + * @return the islandResetDeathReset + */ + public final boolean isIslandResetDeathReset() { + return islandResetDeathReset; + } + /** + * @param islandResetDeathReset the islandResetDeathReset to set + */ + public final void setIslandResetDeathReset(boolean islandResetDeathReset) { + this.islandResetDeathReset = islandResetDeathReset; + } + /** + * @return the teamJoinDeathReset + */ + public final boolean isTeamJoinDeathReset() { + return teamJoinDeathReset; + } + /** + * @param teamJoinDeathReset the teamJoinDeathReset to set + */ + public final void setTeamJoinDeathReset(boolean teamJoinDeathReset) { + this.teamJoinDeathReset = teamJoinDeathReset; + } + + /** + * @return the worldBlockValues + */ + public Map> getWorldBlockValues() { + return worldBlockValues; + } + +} diff --git a/src/main/java/bskyblock/addon/level/database/object/LevelsData.java b/src/main/java/bskyblock/addon/level/database/object/LevelsData.java new file mode 100644 index 0000000..81f3b5b --- /dev/null +++ b/src/main/java/bskyblock/addon/level/database/object/LevelsData.java @@ -0,0 +1,94 @@ +package bskyblock.addon.level.database.object; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.World; + +import com.google.gson.annotations.Expose; + +import world.bentobox.bentobox.database.objects.DataObject; + +public class LevelsData implements DataObject { + + // uniqueId is the player's UUID + @Expose + private String uniqueId = ""; + + // Map - world name, level + @Expose + private Map levels = new HashMap<>(); + @Expose + private long initialIslandLevel = 0; + + public LevelsData() {} // For Bean loading + + /** + * Create a level entry for target player + * @param targetPlayer + * @param level + * @param world + */ + public LevelsData(UUID targetPlayer, long level, World world) { + uniqueId = targetPlayer.toString(); + levels.put(world.getName(), level); + } + + /* (non-Javadoc) + * @see world.bentobox.bbox.database.objects.DataObject#getUniqueId() + */ + @Override + public String getUniqueId() { + return uniqueId; + } + + /* (non-Javadoc) + * @see world.bentobox.bbox.database.objects.DataObject#setUniqueId(java.lang.String) + */ + @Override + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + /** + * Get the island level for this world + * @param world - world + * @return island level, less the initialIslandLevel + */ + public Long getLevel(World world) { + return world == null ? -initialIslandLevel : levels.getOrDefault(world.getName(), 0L) - initialIslandLevel; + } + + /** + * @return the levels + */ + public Map getLevels() { + return levels; + } + + /** + * @param levels the levels to set + */ + public void setLevels(Map levels) { + this.levels = levels; + } + + public void setLevel(World world, Long lv) { + levels.put(world.getName(),lv); + } + + /** + * @return the initialIslandLevel + */ + public long getInitialIslandLevel() { + return initialIslandLevel; + } + + /** + * @param initialIslandLevel the initialIslandLevel to set + */ + public void setInitialIslandLevel(long initialIslandLevel) { + this.initialIslandLevel = initialIslandLevel; + } +} diff --git a/src/bskyblock/addin/level/database/object/TopTenList.java b/src/main/java/bskyblock/addon/level/database/object/TopTenData.java similarity index 58% rename from src/bskyblock/addin/level/database/object/TopTenList.java rename to src/main/java/bskyblock/addon/level/database/object/TopTenData.java index f2a22f8..b114212 100644 --- a/src/bskyblock/addin/level/database/object/TopTenList.java +++ b/src/main/java/bskyblock/addon/level/database/object/TopTenData.java @@ -1,28 +1,38 @@ -package bskyblock.addin.level.database.object; +package bskyblock.addon.level.database.object; -import java.util.Comparator; -import java.util.HashMap; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; -import us.tastybento.bskyblock.database.objects.DataObject; +import com.google.gson.annotations.Expose; + +import world.bentobox.bentobox.database.objects.DataObject; /** * This class stores and sorts the top ten. * @author ben * */ -public class TopTenList extends DataObject { +public class TopTenData implements DataObject { - private String uniqueId = "topten"; - private HashMap topTen = new HashMap<>(); + // UniqueId is the world name + @Expose + private String uniqueId = ""; + @Expose + private Map topTen = new LinkedHashMap<>(); + + public TopTenData() {} - public HashMap getTopTen() { - return topTen; + public Map getTopTen() { + return topTen.entrySet().stream() + .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).limit(10) + .collect(Collectors.toMap( + Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); } - public void setTopTen(HashMap topTen) { + public void setTopTen(Map topTen) { this.topTen = topTen; } @@ -43,7 +53,6 @@ public class TopTenList extends DataObject { */ public void addLevel(UUID uuid, Long level) { this.topTen.put(uuid, level); - sortTopTen(); } /** @@ -65,13 +74,4 @@ public class TopTenList extends DataObject { this.topTen.remove(ownerUUID); } - /** - * Sorts the top ten and limits it to 10 entries - */ - void sortTopTen() { - topTen = (HashMap) topTen.entrySet().stream() - .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())) - .limit(10) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } } diff --git a/src/main/java/bskyblock/addon/level/event/IslandLevelCalculatedEvent.java b/src/main/java/bskyblock/addon/level/event/IslandLevelCalculatedEvent.java new file mode 100644 index 0000000..56b89af --- /dev/null +++ b/src/main/java/bskyblock/addon/level/event/IslandLevelCalculatedEvent.java @@ -0,0 +1,59 @@ +package bskyblock.addon.level.event; + +import java.util.UUID; + +import bskyblock.addon.level.calculators.CalcIslandLevel.Results; +import world.bentobox.bentobox.api.events.IslandBaseEvent; +import world.bentobox.bentobox.database.objects.Island; + +/** + * This event is fired after the island level is calculated and before the results are saved. + * If this event is cancelled, results will saved, but not communicated. i.e., the result will be silent. + * + * @author tastybento + */ +public class IslandLevelCalculatedEvent extends IslandBaseEvent { + private Results results; + + private UUID targetPlayer; + + /** + * @param targetPlayer + * @param island + * @param results + */ + public IslandLevelCalculatedEvent(UUID targetPlayer, Island island, Results results) { + super(island); + this.targetPlayer = targetPlayer; + this.results = results; + } + + /** + * @return the results + */ + public Results getResults() { + return results; + } + + /** + * @return the targetPlayer + */ + public UUID getTargetPlayer() { + return targetPlayer; + } + /** + * @param results the results to set + */ + public void setResults(Results results) { + this.results = results; + } + + /** + * @param targetPlayer the targetPlayer to set + */ + public void setTargetPlayer(UUID targetPlayer) { + this.targetPlayer = targetPlayer; + } + + +} diff --git a/src/main/java/bskyblock/addon/level/event/IslandPreLevelEvent.java b/src/main/java/bskyblock/addon/level/event/IslandPreLevelEvent.java new file mode 100644 index 0000000..6229178 --- /dev/null +++ b/src/main/java/bskyblock/addon/level/event/IslandPreLevelEvent.java @@ -0,0 +1,32 @@ +package bskyblock.addon.level.event; + +import java.util.UUID; + +import world.bentobox.bentobox.api.events.IslandBaseEvent; +import world.bentobox.bentobox.database.objects.Island; + +/** + * Called when an island level is going to be calculated + * @author tastybento + * + */ +public class IslandPreLevelEvent extends IslandBaseEvent { + + private UUID targetPlayer; + + + /** + * Called when an island level is going to be calculated + * @param targetPlayer - the player who is being tagetted (owner or team member) + * @param island - the island + */ + public IslandPreLevelEvent(UUID targetPlayer, Island island) { + super(island); + this.targetPlayer = targetPlayer; + } + + public UUID getTargetPlayer() { + return targetPlayer; + } + +} diff --git a/src/bskyblock/addin/level/event/TopTenClick.java b/src/main/java/bskyblock/addon/level/event/TopTenClick.java similarity index 96% rename from src/bskyblock/addin/level/event/TopTenClick.java rename to src/main/java/bskyblock/addon/level/event/TopTenClick.java index e7672b8..8159fc4 100644 --- a/src/bskyblock/addin/level/event/TopTenClick.java +++ b/src/main/java/bskyblock/addon/level/event/TopTenClick.java @@ -1,4 +1,4 @@ -package bskyblock.addin.level.event; +package bskyblock.addon.level.event; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; diff --git a/src/main/java/bskyblock/addon/level/listeners/NewIslandListener.java b/src/main/java/bskyblock/addon/level/listeners/NewIslandListener.java new file mode 100644 index 0000000..efcda94 --- /dev/null +++ b/src/main/java/bskyblock/addon/level/listeners/NewIslandListener.java @@ -0,0 +1,50 @@ +package bskyblock.addon.level.listeners; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; + +import bskyblock.addon.level.Level; +import bskyblock.addon.level.calculators.CalcIslandLevel; +import world.bentobox.bentobox.api.events.island.IslandEvent.IslandCreatedEvent; +import world.bentobox.bentobox.api.events.island.IslandEvent.IslandResettedEvent; +import world.bentobox.bentobox.database.objects.Island; + +/** + * Listens for new islands and sets the level to zero automatically + * @author tastybento + * + */ +public class NewIslandListener implements Listener { + + private Level addon; + private Map cil; + + /** + * @param addon + */ + public NewIslandListener(Level addon) { + this.addon = addon; + cil = new HashMap<>(); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onNewIsland(IslandCreatedEvent e) { + cil.putIfAbsent(e.getIsland(), new CalcIslandLevel(addon, e.getIsland(), () -> zeroLevel(e.getIsland()))); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onNewIsland(IslandResettedEvent e) { + cil.putIfAbsent(e.getIsland(), new CalcIslandLevel(addon, e.getIsland(), () -> zeroLevel(e.getIsland()))); + } + + private void zeroLevel(Island island) { + if (cil.containsKey(island)) { + addon.setInitialIslandLevel(island, cil.get(island).getResult().getLevel()); + cil.remove(island); + } + } +}