NEWS: Welcome to my new homepage! <3

Organized code and removed unused imports - poppy - A feature-rich Minecraft plugin which enhances gaming experience

poppy

A feature-rich Minecraft plugin which enhances gaming experience
git clone git://192.168.2.2/poppy
Log | Files | Refs | README

commit 2692f76dc26f4d02d7668e205da635987f37410a
parent f3f641aa7c315240672545c824c3524764dd71b7
Author: typable <contact@typable.dev>
Date:   Tue, 10 Jan 2023 16:55:54 +0100

Organized code and removed unused imports

Diffstat:
MREADME.md | 4++--
Ahook.sh | 9+++++++++
Mres/plugin.yml | 8++++----
Dsrc/de/typable/minecrafthub/Main.java | 301-------------------------------------------------------------------------------
Dsrc/de/typable/minecrafthub/config/Config.java | 86-------------------------------------------------------------------------------
Dsrc/de/typable/minecrafthub/constant/Constants.java | 19-------------------
Dsrc/de/typable/minecrafthub/event/AutoWorkbenchListener.java | 241-------------------------------------------------------------------------------
Dsrc/de/typable/minecrafthub/event/ChairListener.java | 215-------------------------------------------------------------------------------
Dsrc/de/typable/minecrafthub/event/DoubleDoorListener.java | 152-------------------------------------------------------------------------------
Dsrc/de/typable/minecrafthub/event/EventListener.java | 181-------------------------------------------------------------------------------
Dsrc/de/typable/minecrafthub/event/LeavesDecayListener.java | 124-------------------------------------------------------------------------------
Dsrc/de/typable/minecrafthub/util/Util.java | 239-------------------------------------------------------------------------------
Asrc/poppy/Config.java | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/poppy/Constants.java | 19+++++++++++++++++++
Asrc/poppy/Main.java | 301+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/poppy/Utils.java | 238+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/poppy/modules/AutoWorkbenchModule.java | 241+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/poppy/modules/ChairModule.java | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/poppy/modules/CommonModule.java | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/poppy/modules/DoubleDoorModule.java | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/poppy/modules/LeavesDecayModule.java | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21 files changed, 1572 insertions(+), 1564 deletions(-)

diff --git a/README.md b/README.md @@ -1,5 +1,5 @@ -# minecraft-hub -A Minecraft Server Management Plugin +# poppy +A Minecraft server management plugin ### Export as JAR file diff --git a/hook.sh b/hook.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +cd /home/andreas/git/poppy + +git --git-dir=../poppy/.git --work-tree=../poppy pull origin main + +/opt/gradle/gradle-7.6/bin/gradle build + +cp build/libs/poppy.jar /srv/minecraft/plugins/ diff --git a/res/plugin.yml b/res/plugin.yml @@ -1,7 +1,7 @@ -main: de.typable.minecrafthub.Main -name: MinecraftHub +main: poppy.Main +name: poppy version: 0.0.1 -author: typable +author: typable, chunksize api-version: 1.16 commands: head: @@ -10,7 +10,7 @@ commands: spawn: usage: /spawn invsee: - usage: /invsee <name> <enderchest> + usage: /invsee <name> sethome: home: setwarp: diff --git a/src/de/typable/minecrafthub/Main.java b/src/de/typable/minecrafthub/Main.java @@ -1,301 +0,0 @@ -package de.typable.minecrafthub; - -import java.io.File; -import java.io.IOException; -import java.net.BindException; -import java.net.ServerSocket; -import java.net.Socket; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.WorldCreator; -import org.bukkit.WorldType; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.SkullMeta; -import org.bukkit.inventory.meta.BookMeta; -import org.bukkit.material.Tree; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; - -import de.typable.minecrafthub.constant.Constants; -import de.typable.minecrafthub.event.AutoWorkbenchListener; -import de.typable.minecrafthub.event.ChairListener; -import de.typable.minecrafthub.event.DoubleDoorListener; -import de.typable.minecrafthub.event.EventListener; -import de.typable.minecrafthub.event.LeavesDecayListener; -import de.typable.minecrafthub.util.Util; -import de.typable.minecrafthub.config.Config; - - -public class Main extends JavaPlugin -{ - private PluginManager pluginManager; - private DoubleDoorListener doubleDoorListener; - private ChairListener chairListener; - private AutoWorkbenchListener autoWorkbenchListener; - private LeavesDecayListener leavesDecayListener; - private EventListener eventListener; - - private Plugin plugin; - private Config config; - - @Override - public void onEnable() - { - plugin = this; - config = new Config("config/minecraft-hub.yml"); - - pluginManager = Bukkit.getPluginManager(); - - doubleDoorListener = new DoubleDoorListener(); - pluginManager.registerEvents(doubleDoorListener, this); - - chairListener = new ChairListener(); - pluginManager.registerEvents(chairListener, this); - - autoWorkbenchListener = new AutoWorkbenchListener(); - pluginManager.registerEvents(autoWorkbenchListener, this); - - leavesDecayListener = new LeavesDecayListener(this); - pluginManager.registerEvents(leavesDecayListener, this); - - eventListener = new EventListener(); - pluginManager.registerEvents(eventListener, this); - } - - @Override - public void onDisable() - { - chairListener.onDisable(); - } - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) - { - if(sender instanceof Player) - { - Player player = (Player) sender; - - switch(label) - { - case "head": - return setItemAsHead(player, args); - case "skull": - return getSkullForName(player, args); - case "invsee": - return openInventoryForPlayer(player, args); - case "info": - return openInfoBook(player, args); - case "spawn": - return teleportToSpawn(player, args); - case "home": - return teleportToHome(player, args); - case "warp": - return teleportToWarppoint(player, args); - case "sethome": - return setHome(player, args); - case "setwarp": - return addWarppoint(player, args); - default: - return false; - } - } - - return true; - } - - private boolean setItemAsHead(final Player player, final String[] args) - { - final ItemStack item = player.getInventory().getItemInMainHand(); - final ItemStack head = player.getInventory().getHelmet(); - - player.getInventory().setHelmet(item); - player.getInventory().setItemInMainHand((new ItemStack(Material.AIR))); - - if(player.getGameMode() == GameMode.SURVIVAL) - { - if(head != null) - { - player.getInventory().addItem(head); - } - } - - return true; - } - - @SuppressWarnings("deprecation") - private boolean getSkullForName(final Player player, final String[] args) - { - if(!player.isOp()) - { - player.sendMessage(Constants.Messages.NOT_ENOUGH_PERMISSION); - return true; - } - - if(args.length != 1) - { - return false; - } - - final String name = args[0]; - final ItemStack skull = new ItemStack(Material.PLAYER_HEAD); - final SkullMeta meta = (SkullMeta) skull.getItemMeta(); - meta.setOwner(name); - skull.setItemMeta(meta); - - player.getInventory().addItem(skull); - - return true; - } - - private boolean openInventoryForPlayer(final Player player, final String[] args) - { - if(args.length == 0) - { - return false; - } - - if(!player.isOp()) - { - player.sendMessage(Constants.Messages.NOT_ENOUGH_PERMISSION); - return true; - } - - final Player target = Bukkit.getPlayer(args[0]); - - if(target == null) - { - player.sendMessage(ChatColor.RED + "Player not found!"); - return true; - } - - player.openInventory(target.getInventory()); - - return true; - } - - private boolean openInfoBook(final Player player, final String[] args) - { - final ItemStack book = new ItemStack(Material.WRITTEN_BOOK); - final BookMeta meta = (BookMeta) book.getItemMeta(); - meta.setTitle("Info"); - meta.setAuthor("Server"); - meta.setPages(config.getInfoPages()); - book.setItemMeta(meta); - - player.openBook(book); - - return true; - } - - private boolean teleportToSpawn(final Player player, final String[] args) - { - final Location location = Bukkit.getWorld("world").getSpawnLocation(); - - if(Util.travelTo(plugin, player, location)) - { - player.sendMessage(ChatColor.GRAY + "You've been teleported to spawn."); - } - - return true; - } - - private boolean teleportToHome(final Player player, final String[] args) - { - final Location location = config.getHome(player); - - if(location == null) - { - player.sendMessage(ChatColor.RED + "You've don't have a home point."); - return true; - } - - if(Util.travelTo(plugin, player, location)) - { - player.sendMessage(ChatColor.GRAY + "You've been teleported to your home."); - } - - return true; - } - - private boolean teleportToWarppoint(final Player player, final String[] args) - { - if(args.length != 1) - { - return false; - } - - final String name = args[0]; - final Location location = config.getWarp(name); - - if(location == null) - { - player.sendMessage(ChatColor.RED + "Warp point " + name + " doesn't exist!"); - return true; - } - - if(Util.travelTo(plugin, player, location)) - { - player.sendMessage(ChatColor.GRAY + "You've been teleported to warp point " + name + "."); - } - - return true; - } - - private boolean setHome(final Player player, final String[] args) - { - try - { - config.setHome(player); - player.sendMessage(ChatColor.YELLOW + "Home point set."); - } - catch(Exception ex) - { - player.sendMessage(Constants.Messages.FAILED_TO_SAVE_CONFIG_FILE); - } - - return true; - } - - private boolean addWarppoint(final Player player, final String[] args) - { - if(args.length != 1) - { - return false; - } - - final String name = args[0]; - - if(!Util.payFee(player, Material.COMPASS, 1)) - { - player.sendMessage(ChatColor.RED + "The fee for creating a warp point is 1 compass!"); - return true; - } - - try - { - if(!config.setWarp(name, player.getLocation())) - { - player.sendMessage(ChatColor.RED + "Warp point " + name + " already exists!"); - return true; - } - - player.sendMessage(ChatColor.YELLOW + "Warp point " + name + " set."); - } - catch(Exception ex) - { - player.sendMessage(Constants.Messages.FAILED_TO_SAVE_CONFIG_FILE); - } - - return true; - } - -} diff --git a/src/de/typable/minecrafthub/config/Config.java b/src/de/typable/minecrafthub/config/Config.java @@ -1,86 +0,0 @@ -package de.typable.minecrafthub.config; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.ArrayList; - -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.Location; - -import de.typable.minecrafthub.util.Util; - -public class Config -{ - private File file; - private FileConfiguration configuration; - - public Config(final String path) - { - this.file = new File(path); - this.configuration = YamlConfiguration.loadConfiguration(this.file); - } - - public void setHome(final Player player) throws IOException - { - final String path = "home." + player.getDisplayName(); - final Location location = Util.calcBlockCenter(player.getLocation()); - - this.configuration.set(path, location); - this.configuration.save(this.file); - } - - public Location getHome(final Player player) - { - final String path = "home." + player.getDisplayName(); - - return this.configuration.getLocation(path); - } - - public boolean setWarp(final String name, final Location location) throws IOException - { - final String path = "warp." + name; - - if(this.configuration.getLocation(path) != null) - { - return false; - } - - this.configuration.set(path, Util.calcBlockCenter(location)); - this.configuration.save(this.file); - - return true; - } - - public Location getWarp(final String name) - { - final String path = "warp." + name; - - return this.configuration.getLocation(path); - } - - public List<String> getInfoPages() - { - final String path = "info"; - List<String> pages = null; - - try - { - this.configuration.load(this.file); - pages = (List<String>) this.configuration.getList(path); - } - catch(Exception ex) - { - // ignore - } - - if(pages == null) - { - pages = new ArrayList<>(); - } - - return pages; - } -} diff --git a/src/de/typable/minecrafthub/constant/Constants.java b/src/de/typable/minecrafthub/constant/Constants.java @@ -1,19 +0,0 @@ -package de.typable.minecrafthub.constant; - -import org.bukkit.ChatColor; - - -public class Constants -{ - public static final long TICK = 20; - public static final int BLOCKS_PER_CHUNK = 16; - public static final int CHUNKS_PER_EMERALD = 25; - public static final int MIN_FEE = 1; - public static final int MAX_FEE = 64; - - public static final class Messages - { - public static final String NOT_ENOUGH_PERMISSION = ChatColor.RED + "You don't have enough Permission to perform this command!"; - public static final String FAILED_TO_SAVE_CONFIG_FILE = ChatColor.RED + "Failed to save changes!"; - } -} diff --git a/src/de/typable/minecrafthub/event/AutoWorkbenchListener.java b/src/de/typable/minecrafthub/event/AutoWorkbenchListener.java @@ -1,241 +0,0 @@ -package de.typable.minecrafthub.event; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; - -import org.bukkit.Bukkit; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.Dropper; -import org.bukkit.entity.Entity; -import org.bukkit.entity.ItemFrame; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryMoveItemEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.Recipe; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; - -import de.typable.minecrafthub.util.Util; - - -public class AutoWorkbenchListener implements Listener -{ - @EventHandler - public void onItemMove(InventoryMoveItemEvent event) - { - Inventory source = event.getSource(); - Inventory target = event.getDestination(); - - if(source.getHolder() instanceof Dropper) - { - Dropper dropper = (Dropper) source.getHolder(); - - ItemFrame frame = getItemFrame(dropper.getBlock()); - - if(frame == null) - { - return; - } - - ItemStack item = frame.getItem(); - - Recipe recipe = getCraftingRecipe(item, source, target); - - if(recipe != null) - { - if(recipe instanceof ShapelessRecipe) - { - ShapelessRecipe shapless = (ShapelessRecipe) recipe; - - target.addItem(shapless.getResult()); - } - - if(recipe instanceof ShapedRecipe) - { - ShapedRecipe shaped = (ShapedRecipe) recipe; - - target.addItem(shaped.getResult()); - } - } - - event.setCancelled(true); - } - } - - private Recipe getCraftingRecipe(ItemStack item, Inventory source, Inventory target) - { - if(Util.isEmpty(item)) - { - return null; - } - - Iterator<Recipe> iterator = Bukkit.recipeIterator(); - - while(iterator.hasNext()) - { - Recipe recipe = iterator.next(); - - if(Util.compare(item, recipe.getResult())) - { - List<ItemStack> ingredients = null; - - if(recipe instanceof ShapelessRecipe) - { - ShapelessRecipe shapless = (ShapelessRecipe) recipe; - - ingredients = shapless.getIngredientList(); - } - - if(recipe instanceof ShapedRecipe) - { - ShapedRecipe shaped = (ShapedRecipe) recipe; - - ingredients = new ArrayList<>(); - - for(ItemStack value : shaped.getIngredientMap().values()) - { - if(ingredients.isEmpty()) - { - if(!Util.isEmpty(value)) - { - ingredients.add(value); - } - } - else - { - appendUniqueIngredient(ingredients, value); - } - } - } - - if(ingredients == null) - { - continue; - } - - if(!hasIngredients(source, ingredients)) - { - continue; - } - - if(Util.isInventoryFull(target, recipe.getResult())) - { - return null; - } - - removeIngredients(ingredients, source); - - return recipe; - } - } - - return null; - } - - private void removeIngredients(List<ItemStack> ingredients, Inventory inventory) - { - for(ItemStack ingredient : ingredients) - { - if(Util.isEmpty(ingredient)) - { - continue; - } - - int amount = ingredient.getAmount(); - - ListIterator<ItemStack> iterator = inventory.iterator(); - - while(iterator.hasNext()) - { - ItemStack item = iterator.next(); - - if(Util.isEmpty(item)) - { - continue; - } - - if(Util.compare(item, ingredient)) - { - if(item.getAmount() > amount) - { - item.setAmount(item.getAmount() - amount); - amount = 0; - - break; - } - - if(item.getAmount() == amount) - { - amount = 0; - inventory.removeItem(item); - - break; - } - - if(item.getAmount() < amount) - { - amount -= item.getAmount(); - inventory.removeItem(item); - } - } - } - } - } - - private void appendUniqueIngredient(List<ItemStack> ingredients, ItemStack item) - { - for(ItemStack ingredient : ingredients) - { - if(Util.compare(item, ingredient)) - { - ingredient.setAmount(ingredient.getAmount() + item.getAmount()); - - return; - } - } - - if(!Util.isEmpty(item)) - { - ingredients.add(item); - } - } - - private boolean hasIngredients(Inventory inventory, List<ItemStack> ingredients) - { - for(ItemStack ingredient : ingredients) - { - if(ingredient != null && !Util.containsAtLeast(inventory, ingredient, ingredient.getAmount())) - { - return false; - } - } - - return true; - } - - private ItemFrame getItemFrame(Block block) - { - for(Entity entity : block.getWorld().getNearbyEntities(block.getLocation(), 2, 2, 2)) - { - if(entity instanceof ItemFrame) - { - ItemFrame frame = (ItemFrame) entity; - - if(frame.getFacing() == BlockFace.UP) - { - if(block.getLocation().add(0.5, 1.03125, 0.5).distance(frame.getLocation()) < 0.2D) - { - return frame; - } - } - } - } - - return null; - } -} diff --git a/src/de/typable/minecrafthub/event/ChairListener.java b/src/de/typable/minecrafthub/event/ChairListener.java @@ -1,215 +0,0 @@ -package de.typable.minecrafthub.event; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.data.Bisected.Half; -import org.bukkit.block.data.type.Stairs; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.util.Vector; -import org.spigotmc.event.entity.EntityDismountEvent; - -import de.typable.minecrafthub.util.Util; - - -public class ChairListener implements Listener -{ - private static final Material[] CHAIR_TYPE = new Material[] - { - Material.OAK_STAIRS, - Material.SPRUCE_STAIRS, - Material.BIRCH_STAIRS, - Material.JUNGLE_STAIRS, - Material.ACACIA_STAIRS, - Material.DARK_OAK_STAIRS, - Material.ACACIA_STAIRS, - Material.CRIMSON_STAIRS, - Material.WARPED_STAIRS - }; - - private Map<Block, ArmorStand> blockMap = new HashMap<>(); - - public void onDisable() - { - for(ArmorStand armorStand : blockMap.values()) - { - armorStand.eject(); - armorStand.remove(); - } - } - - @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) - { - Player player = event.getPlayer(); - - if(event.getAction() == Action.RIGHT_CLICK_BLOCK) - { - if(event.getClickedBlock() != null && !event.getPlayer().isSneaking()) - { - Block block = event.getClickedBlock(); - - if(isChair(block.getType())) - { - if(!isInRange(block, player)) - { - return; - } - - if(blockMap.containsKey(block)) - { - return; - } - - if(isCompatible(block)) - { - ArmorStand armorStand = createMountableChair(block, player); - - if(armorStand == null) - { - return; - } - - event.setCancelled(true); - - blockMap.put(block, armorStand); - } - } - } - } - } - - @EventHandler - public void onEntityDismount(EntityDismountEvent event) - { - if(event.getEntity() instanceof Player) - { - Entity entity = event.getDismounted(); - - if(entity != null && entity instanceof ArmorStand) - { - if(blockMap.containsValue(entity)) - { - for(Entry<Block, ArmorStand> entry : blockMap.entrySet()) - { - if(entry.getValue() == entity) - { - blockMap.remove(entry.getKey()); - - break; - } - } - } - - Location location = entity.getLocation(); - location.add(0, 1, 0); - - for(Entity passenger : entity.getPassengers()) { - location.setPitch(passenger.getLocation().getPitch()); - location.setYaw(passenger.getLocation().getYaw()); - passenger.teleport(location); - } - - entity.remove(); - } - } - } - - @EventHandler - public void onBlockBreak(BlockBreakEvent event) - { - Block block = event.getBlock(); - - if(blockMap.containsKey(block)) - { - ArmorStand armorStand = blockMap.get(block); - armorStand.eject(); - - blockMap.remove(block); - } - } - - private boolean isInRange(Block block, Player player) - { - return block.getLocation().add(0.5, 0.5, 0.5).distance(player.getLocation()) <= 2; - } - - private boolean isChair(Material material) - { - for(Material chair : CHAIR_TYPE) - { - if(material == chair) - { - return true; - } - } - - return false; - } - - private boolean isCompatible(Block block) - { - Block upperBlock = block.getWorld().getBlockAt(block.getLocation().add(0, 1, 0)); - - if(!Util.isAir(upperBlock.getType())) - { - return false; - } - - Stairs stairs = (Stairs) block.getState().getBlockData(); - - if(stairs.getHalf() != Half.BOTTOM) - { - return false; - } - - if(stairs.isWaterlogged()) - { - return false; - } - - if(stairs.getShape() == Stairs.Shape.INNER_RIGHT || stairs.getShape() == Stairs.Shape.INNER_LEFT) - { - return false; - } - - return true; - } - - @SuppressWarnings("deprecation") - private ArmorStand createMountableChair(Block block, Player player) - { - Stairs stairs = (Stairs) block.getState().getBlockData(); - - Float yaw = Util.convertFacingToYaw(stairs.getFacing()); - - if(yaw == null) - { - return null; - } - - Location location = block.getLocation().add(0.5, -0.4, 0.5); - location.setYaw(yaw); - - ArmorStand armorStand = (ArmorStand) block.getWorld().spawnEntity(location, EntityType.ARMOR_STAND); - armorStand.setPassenger((Entity) player); - armorStand.setSmall(true); - armorStand.setGravity(false); - armorStand.setInvulnerable(true); - armorStand.setVisible(false); - - return armorStand; - } -} diff --git a/src/de/typable/minecrafthub/event/DoubleDoorListener.java b/src/de/typable/minecrafthub/event/DoubleDoorListener.java @@ -1,152 +0,0 @@ -package de.typable.minecrafthub.event; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Sound; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.data.type.Door; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerInteractEvent; - -import de.typable.minecrafthub.util.Util; - - -public class DoubleDoorListener implements Listener -{ - private static final Material[] DOOR_TYPE = new Material[] { Material.OAK_DOOR, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR, Material.ACACIA_DOOR, Material.CRIMSON_DOOR, Material.WARPED_DOOR }; - - @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) - { - Player player = event.getPlayer(); - - if(event.getAction() == Action.RIGHT_CLICK_BLOCK) - { - if(event.getClickedBlock() != null) - { - Block block = event.getClickedBlock(); - - if(isDoor(block.getType())) - { - if(player.isSneaking()) - { - if(!Util.isEmpty(player.getInventory().getItemInMainHand())) - { - return; - } - - if(!Util.isEmpty(player.getInventory().getItemInOffHand())) - { - return; - } - } - - BlockState state = block.getState(); - Door door = (Door) state.getBlockData(); - - Location location = getOppositeDoor(door, block.getLocation()); - - if(location == null) - { - return; - } - - Block opposite = block.getWorld().getBlockAt(location); - - if(block.getType() != opposite.getType()) - { - return; - } - - BlockState stateOpposite = opposite.getState(); - Door doorOpposite = (Door) stateOpposite.getBlockData(); - - if(isCompatible(door, doorOpposite)) - { - if(door.isOpen() && doorOpposite.isOpen()) - { - doorOpposite.setOpen(false); - - stateOpposite.setBlockData(doorOpposite); - stateOpposite.update(); - - player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_DOOR_CLOSE, 1F, 1F); - } - - if(!door.isOpen() && !doorOpposite.isOpen()) - { - doorOpposite.setOpen(true); - - stateOpposite.setBlockData(doorOpposite); - stateOpposite.update(); - - player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_DOOR_OPEN, 1F, 1F); - } - } - } - } - } - } - - private boolean isDoor(Material material) - { - for(Material door : DOOR_TYPE) - { - if(material == door) - { - return true; - } - } - - return false; - } - - private Location getOppositeDoor(Door door, Location location) - { - int invert = door.getHinge() == Door.Hinge.LEFT ? 1 : -1; - - switch(door.getFacing()) - { - case NORTH: - location.add(1 * invert, 0, 0); - break; - case EAST: - location.add(0, 0, 1 * invert); - break; - case SOUTH: - location.add(-1 * invert, 0, 0); - break; - case WEST: - location.add(0, 0, -1 * invert); - break; - default: - return null; - } - - return location; - } - - private boolean isCompatible(Door door, Door doorItem) - { - if(door.getFacing() != doorItem.getFacing()) - { - return false; - } - - if(door.getHalf() != doorItem.getHalf()) - { - return false; - } - - if(door.getHinge() == doorItem.getHinge()) - { - return false; - } - - return true; - } -} diff --git a/src/de/typable/minecrafthub/event/EventListener.java b/src/de/typable/minecrafthub/event/EventListener.java @@ -1,180 +0,0 @@ -package de.typable.minecrafthub.event; - -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Directional; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.entity.Snowball; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.event.entity.EntityExplodeEvent; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.PlayerInteractAtEntityEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; - -import de.typable.minecrafthub.util.Util; - - -public class EventListener implements Listener -{ - @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) - { - - Player player = event.getPlayer(); - - if(event.getAction() == Action.PHYSICAL) - { - if(event.getClickedBlock() != null) - { - if(event.getClickedBlock().getType() == Material.FARMLAND) - { - event.setCancelled(true); - } - } - } - - EquipmentSlot equip = event.getHand(); - - if(equip.equals(EquipmentSlot.HAND)) - { - - if(event.getAction() == Action.RIGHT_CLICK_BLOCK) - { - Block block = event.getClickedBlock(); - - if(block == null) - { - return; - } - - Material material = block.getType(); - - if(player.isSneaking()) - { - return; - } - - BlockData blockdata = block.getBlockData(); - - if(blockdata instanceof Ageable) - { - - Ageable ageable = (Ageable) blockdata; - - if(Util.isFarmable(material) && ageable.getAge() == ageable.getMaximumAge()) - { - - event.setCancelled(true); - - if(blockdata instanceof Directional) - { - Directional directional = (Directional) blockdata; - BlockFace blockface = directional.getFacing(); - - block.breakNaturally(player.getItemInUse()); - block.setType(material); - directional = (Directional) blockdata; - ageable.setAge(0); - directional.setFacing(blockface); - block.setBlockData(blockdata); - } - else - { - - block.breakNaturally(player.getItemInUse()); - block.setType(material); - } - } - } - - if(material == Material.MELON && Util.hasStem(block) || material == Material.PUMPKIN && Util.hasStem(block)) - { - block.breakNaturally(player.getInventory().getItemInMainHand()); - } - } - } - } - - @EventHandler - public void onEntityExplode(EntityExplodeEvent event) - { - if(event.getEntityType() == EntityType.CREEPER) - { - event.blockList().clear(); - } - } - - @EventHandler - public void onChat(AsyncPlayerChatEvent event) - { - String message = ChatColor.GRAY + event.getMessage().replace("%", "%%"); - String format = ChatColor.WHITE + event.getPlayer().getName() + ": " + message; - event.setFormat(format); - } - - @EventHandler - public void onEntityHit(EntityDamageByEntityEvent event) - { - if(event.getDamager() instanceof Snowball) - { - Snowball snowball = (Snowball) event.getDamager(); - - if(snowball.getShooter() instanceof Player) - { - Player player = (Player) event.getEntity(); - - player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 2, 1)); - event.setDamage(1); - } - } - } - - @EventHandler - public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) - { - Player player = event.getPlayer(); - - if(event.getRightClicked().getType().equals(EntityType.ARMOR_STAND)) - { - ItemStack item = player.getInventory().getItemInMainHand(); - - if(item.getType() == Material.STICK && item.getAmount() > 1 && player.isSneaking()) - { - ArmorStand armorstand = (ArmorStand) event.getRightClicked(); - - armorstand.setArms(true); - item.setAmount(item.getAmount() - 2); - - event.setCancelled(true); - } - } - } - - @EventHandler - public void onArmorStandDestroy(EntityDeathEvent event) - { - if(event.getEntity() instanceof ArmorStand) - { - ArmorStand armorstand = (ArmorStand) event.getEntity(); - - if(armorstand.hasArms()) - { - event.getDrops().add(new ItemStack(Material.STICK, 2)); - } - } - } -} -\ No newline at end of file diff --git a/src/de/typable/minecrafthub/event/LeavesDecayListener.java b/src/de/typable/minecrafthub/event/LeavesDecayListener.java @@ -1,124 +0,0 @@ -package de.typable.minecrafthub.event; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import org.bukkit.Tag; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.data.type.Leaves; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.LeavesDecayEvent; -import org.bukkit.plugin.Plugin; - -public class LeavesDecayListener implements Listener -{ - private static final int DELAY = 25; - private static final List<BlockFace> NEIGHBORS = Arrays.asList( - BlockFace.UP, - BlockFace.NORTH, - BlockFace.EAST, - BlockFace.SOUTH, - BlockFace.WEST, - BlockFace.DOWN - ); - - private Plugin plugin; - private List<Block> scheduled = new ArrayList<>(); - - public LeavesDecayListener(Plugin plugin) - { - this.plugin = plugin; - } - - @EventHandler - public void onBlockBreak(BlockBreakEvent event) - { - onBlockRemove(event.getBlock()); - } - - @EventHandler - public void onLeavesDecay(LeavesDecayEvent event) - { - onBlockRemove(event.getBlock()); - } - - private void onBlockRemove(Block block) - { - if(!Tag.LOGS.isTagged(block.getType()) && !Tag.LEAVES.isTagged(block.getType())) - { - return; - } - - Collections.shuffle(NEIGHBORS); - - for(BlockFace face : NEIGHBORS) - { - final Block neighbor = block.getRelative(face); - - if(!Tag.LEAVES.isTagged(neighbor.getType())) - { - continue; - } - - Leaves leaves = (Leaves) neighbor.getBlockData(); - - if(leaves.isPersistent()) - { - continue; - } - - if(scheduled.contains(neighbor)) - { - continue; - } - - plugin.getServer().getScheduler().runTaskLater(plugin, () -> decay(neighbor), DELAY); - - scheduled.add(neighbor); - } - } - - private boolean decay(Block block) - { - scheduled.remove(block); - - if(!block.getWorld().isChunkLoaded(block.getX() >> 4, block.getZ() >> 4)) - { - return false; - } - - if(!Tag.LEAVES.isTagged(block.getType())) - { - return false; - } - - Leaves leaves = (Leaves) block.getBlockData(); - - if(leaves.isPersistent()) - { - return false; - } - - if(leaves.getDistance() < 7) - { - return false; - } - - LeavesDecayEvent event = new LeavesDecayEvent(block); - plugin.getServer().getPluginManager().callEvent(event); - - if(event.isCancelled()) - { - return false; - } - - block.breakNaturally(); - - return true; - } -} diff --git a/src/de/typable/minecrafthub/util/Util.java b/src/de/typable/minecrafthub/util/Util.java @@ -1,239 +0,0 @@ -package de.typable.minecrafthub.util; - -import javax.swing.text.Position; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Player; -import org.bukkit.entity.Entity; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; -import org.bukkit.Location; -import org.bukkit.GameMode; -import org.bukkit.plugin.Plugin; - -import de.typable.minecrafthub.constant.Constants; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; - - -public class Util -{ - public static boolean isEmpty(ItemStack item) - { - return item == null || item.getType() == Material.AIR; - } - - public static boolean isType(ItemStack item, Material type) - { - return !isEmpty(item) && item.getType() == type; - } - - public static boolean compare(ItemStack item, ItemStack item2) - { - if(item == null || item2 == null) - { - return false; - } - - if(item.getType() != item2.getType()) - { - return false; - } - - return true; - } - - public static boolean isInventoryFull(Inventory inventory, ItemStack result) - { - for(ItemStack item : inventory.getContents()) - { - if(Util.isEmpty(item)) - { - return false; - } - - if(result.isSimilar(item)) - { - if(result.getAmount() + item.getAmount() <= item.getMaxStackSize()) - { - return false; - } - } - } - - return true; - } - - public static boolean containsAtLeast(Inventory inventory, ItemStack item, int amount) - { - for(int i = 0; i < inventory.getSize(); i++) - { - ItemStack current = inventory.getItem(i); - - if(Util.compare(item, current)) - { - amount -= current.getAmount(); - - if(amount <= 0) - { - return true; - } - } - } - - return false; - } - - public static void sendActionMessage(Player player, String message) - { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); - } - - public static void sendCountdown(Plugin plugin, final String message, final int time, Runnable runnable) - { - Bukkit.getScheduler().runTaskTimer(plugin, new Runnable() - { - int count = time; - - @Override - public void run() - { - if(count == 0) - { - runnable.run(); - return; - } - - Bukkit.getServer().broadcastMessage(ChatColor.YELLOW + message + " " + count + " sec"); - - count--; - } - }, 0L, Constants.TICK); - } - - public static Float convertFacingToYaw(BlockFace face) - { - switch(face) - { - case NORTH: - return 0F; - case EAST: - return 90F; - case SOUTH: - return 180F; - case WEST: - return -90F; - default: - break; - } - - return null; - } - - public static boolean isAir(Material material) - { - return material == Material.AIR || material == Material.CAVE_AIR || material == Material.VOID_AIR; - } - - public static boolean isFarmable(Material material) - { - return material == Material.WHEAT || material == Material.CARROTS || material == Material.POTATOES || material == Material.BEETROOTS || material == Material.NETHER_WART || material == Material.COCOA; - } - - public static boolean isStem(Material material) - { - return material == Material.ATTACHED_PUMPKIN_STEM || material == Material.ATTACHED_MELON_STEM; - } - - public static boolean hasStem(Block block) - { - Location blockLocation = block.getLocation(); - Material blockNorth = blockLocation.clone().add(0, 0, -1).getBlock().getType(); - Material blockEast = blockLocation.clone().add(1, 0, 0).getBlock().getType(); - Material blockSouth = blockLocation.clone().add(0, 0, 1).getBlock().getType(); - Material blockWest = blockLocation.clone().add(-1, 0, 0).getBlock().getType(); - - return isStem(blockNorth) || isStem(blockEast) || isStem(blockSouth) || isStem(blockWest); - } - - public static Location calcBlockCenter(final Location location) - { - Location centered = location.clone(); - centered.setX(Location.locToBlock(location.getX()) + 0.5); - centered.setY(Location.locToBlock(location.getY())); - centered.setZ(Location.locToBlock(location.getZ()) + 0.5); - - return centered; - } - - public static int calcTravelFee(final Location from, final Location to) - { - final Double distance = from.distance(to); - int fee = (int) Math.floor(distance / (Constants.BLOCKS_PER_CHUNK * Constants.CHUNKS_PER_EMERALD)); - - if(fee < Constants.MIN_FEE) - { - fee = Constants.MIN_FEE; - } - - if(fee > Constants.MAX_FEE) - { - fee = Constants.MAX_FEE; - } - - return fee; - } - - public static boolean travelTo(final Plugin plugin, final Player player, final Location location) - { - final int fee = Util.calcTravelFee(player.getLocation(), location); - final String unit = fee == 1 ? "emerald" : "emeralds"; - - if(!payFee(player, Material.EMERALD, fee) && player.getGameMode() == GameMode.SURVIVAL) - { - player.sendMessage(ChatColor.RED + "Not enough emeralds to teleport! Travel fee: " + fee + " " + unit); - return false; - } - - if(player.getVehicle() != null) - { - Entity vehicle = player.getVehicle(); - vehicle.eject(); - player.teleport(location); - - Bukkit.getScheduler().runTaskLater(plugin, () -> { - vehicle.teleport(location); - }, 3); - - Bukkit.getScheduler().runTaskLater(plugin, () -> { - vehicle.addPassenger(player); - }, 6); - } - else - { - player.teleport(location); - } - - return true; - } - - public static boolean payFee(final Player player, final Material unit, final int amount) - { - final ItemStack item = player.getInventory().getItemInMainHand(); - - if(item.getType() != unit || item.getAmount() < amount) - { - return false; - } - - item.setAmount(item.getAmount() - amount); - - return true; - } -} diff --git a/src/poppy/Config.java b/src/poppy/Config.java @@ -0,0 +1,86 @@ +package poppy; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.ArrayList; + +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.Location; + +import poppy.Utils; + +public class Config +{ + private File file; + private FileConfiguration configuration; + + public Config(final String path) + { + this.file = new File(path); + this.configuration = YamlConfiguration.loadConfiguration(this.file); + } + + public void setHome(final Player player) throws IOException + { + final String path = "home." + player.getDisplayName(); + final Location location = Utils.calcBlockCenter(player.getLocation()); + + this.configuration.set(path, location); + this.configuration.save(this.file); + } + + public Location getHome(final Player player) + { + final String path = "home." + player.getDisplayName(); + + return this.configuration.getLocation(path); + } + + public boolean setWarp(final String name, final Location location) throws IOException + { + final String path = "warp." + name; + + if(this.configuration.getLocation(path) != null) + { + return false; + } + + this.configuration.set(path, Utils.calcBlockCenter(location)); + this.configuration.save(this.file); + + return true; + } + + public Location getWarp(final String name) + { + final String path = "warp." + name; + + return this.configuration.getLocation(path); + } + + public List<String> getInfoPages() + { + final String path = "info"; + List<String> pages = null; + + try + { + this.configuration.load(this.file); + pages = (List<String>) this.configuration.getList(path); + } + catch(Exception ex) + { + // ignore + } + + if(pages == null) + { + pages = new ArrayList<>(); + } + + return pages; + } +} diff --git a/src/poppy/Constants.java b/src/poppy/Constants.java @@ -0,0 +1,19 @@ +package poppy; + +import org.bukkit.ChatColor; + + +public class Constants +{ + public static final long TICK = 20; + public static final int BLOCKS_PER_CHUNK = 16; + public static final int CHUNKS_PER_EMERALD = 25; + public static final int MIN_FEE = 1; + public static final int MAX_FEE = 64; + + public static final class Messages + { + public static final String NOT_ENOUGH_PERMISSION = ChatColor.RED + "You don't have enough Permission to perform this command!"; + public static final String FAILED_TO_SAVE_CONFIG_FILE = ChatColor.RED + "Failed to save changes!"; + } +} diff --git a/src/poppy/Main.java b/src/poppy/Main.java @@ -0,0 +1,301 @@ +package poppy; + +import java.io.File; +import java.io.IOException; +import java.net.BindException; +import java.net.ServerSocket; +import java.net.Socket; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.WorldCreator; +import org.bukkit.WorldType; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.inventory.meta.BookMeta; +import org.bukkit.material.Tree; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + +import poppy.Constants; +import poppy.Config; +import poppy.Utils; +import poppy.modules.AutoWorkbenchModule; +import poppy.modules.ChairModule; +import poppy.modules.DoubleDoorModule; +import poppy.modules.CommonModule; +import poppy.modules.LeavesDecayModule; + + +public class Main extends JavaPlugin +{ + private Plugin plugin; + private Config config; + private PluginManager pluginManager; + + private DoubleDoorModule doubleDoorModule; + private ChairModule chairModule; + private AutoWorkbenchModule autoWorkbenchModule; + private LeavesDecayModule leavesDecayModule; + private CommonModule commonModule; + + @Override + public void onEnable() + { + plugin = this; + config = new Config("config/minecraft-hub.yml"); + + pluginManager = Bukkit.getPluginManager(); + + doubleDoorModule = new DoubleDoorModule(); + pluginManager.registerEvents(doubleDoorModule, this); + + chairModule = new ChairModule(); + pluginManager.registerEvents(chairModule, this); + + autoWorkbenchModule = new AutoWorkbenchModule(); + pluginManager.registerEvents(autoWorkbenchModule, this); + + leavesDecayModule = new LeavesDecayModule(this); + pluginManager.registerEvents(leavesDecayModule, this); + + commonModule = new CommonModule(); + pluginManager.registerEvents(commonModule, this); + } + + @Override + public void onDisable() + { + chairModule.onDisable(); + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) + { + if(sender instanceof Player) + { + Player player = (Player) sender; + + switch(label) + { + case "head": + return setItemAsHead(player, args); + case "skull": + return getSkullForName(player, args); + case "invsee": + return openInventoryForPlayer(player, args); + case "info": + return openInfoBook(player, args); + case "spawn": + return teleportToSpawn(player, args); + case "home": + return teleportToHome(player, args); + case "warp": + return teleportToWarppoint(player, args); + case "sethome": + return setHome(player, args); + case "setwarp": + return addWarppoint(player, args); + default: + return false; + } + } + + return true; + } + + private boolean setItemAsHead(final Player player, final String[] args) + { + final ItemStack item = player.getInventory().getItemInMainHand(); + final ItemStack head = player.getInventory().getHelmet(); + + player.getInventory().setHelmet(item); + player.getInventory().setItemInMainHand((new ItemStack(Material.AIR))); + + if(player.getGameMode() == GameMode.SURVIVAL) + { + if(head != null) + { + player.getInventory().addItem(head); + } + } + + return true; + } + + @SuppressWarnings("deprecation") + private boolean getSkullForName(final Player player, final String[] args) + { + if(!player.isOp()) + { + player.sendMessage(Constants.Messages.NOT_ENOUGH_PERMISSION); + return true; + } + + if(args.length != 1) + { + return false; + } + + final String name = args[0]; + final ItemStack skull = new ItemStack(Material.PLAYER_HEAD); + final SkullMeta meta = (SkullMeta) skull.getItemMeta(); + meta.setOwner(name); + skull.setItemMeta(meta); + + player.getInventory().addItem(skull); + + return true; + } + + private boolean openInventoryForPlayer(final Player player, final String[] args) + { + if(args.length == 0) + { + return false; + } + + if(!player.isOp()) + { + player.sendMessage(Constants.Messages.NOT_ENOUGH_PERMISSION); + return true; + } + + final Player target = Bukkit.getPlayer(args[0]); + + if(target == null) + { + player.sendMessage(ChatColor.RED + "Player not found!"); + return true; + } + + player.openInventory(target.getInventory()); + + return true; + } + + private boolean openInfoBook(final Player player, final String[] args) + { + final ItemStack book = new ItemStack(Material.WRITTEN_BOOK); + final BookMeta meta = (BookMeta) book.getItemMeta(); + meta.setTitle("Info"); + meta.setAuthor("Server"); + meta.setPages(config.getInfoPages()); + book.setItemMeta(meta); + + player.openBook(book); + + return true; + } + + private boolean teleportToSpawn(final Player player, final String[] args) + { + final Location location = Bukkit.getWorld("world").getSpawnLocation(); + + if(Utils.travelTo(plugin, player, location)) + { + player.sendMessage(ChatColor.GRAY + "You've been teleported to spawn."); + } + + return true; + } + + private boolean teleportToHome(final Player player, final String[] args) + { + final Location location = config.getHome(player); + + if(location == null) + { + player.sendMessage(ChatColor.RED + "You've don't have a home point."); + return true; + } + + if(Utils.travelTo(plugin, player, location)) + { + player.sendMessage(ChatColor.GRAY + "You've been teleported to your home."); + } + + return true; + } + + private boolean teleportToWarppoint(final Player player, final String[] args) + { + if(args.length != 1) + { + return false; + } + + final String name = args[0]; + final Location location = config.getWarp(name); + + if(location == null) + { + player.sendMessage(ChatColor.RED + "Warp point " + name + " doesn't exist!"); + return true; + } + + if(Utils.travelTo(plugin, player, location)) + { + player.sendMessage(ChatColor.GRAY + "You've been teleported to warp point " + name + "."); + } + + return true; + } + + private boolean setHome(final Player player, final String[] args) + { + try + { + config.setHome(player); + player.sendMessage(ChatColor.YELLOW + "Home point set."); + } + catch(Exception ex) + { + player.sendMessage(Constants.Messages.FAILED_TO_SAVE_CONFIG_FILE); + } + + return true; + } + + private boolean addWarppoint(final Player player, final String[] args) + { + if(args.length != 1) + { + return false; + } + + final String name = args[0]; + + if(!Utils.payFee(player, Material.COMPASS, 1)) + { + player.sendMessage(ChatColor.RED + "The fee for creating a warp point is 1 compass!"); + return true; + } + + try + { + if(!config.setWarp(name, player.getLocation())) + { + player.sendMessage(ChatColor.RED + "Warp point " + name + " already exists!"); + return true; + } + + player.sendMessage(ChatColor.YELLOW + "Warp point " + name + " set."); + } + catch(Exception ex) + { + player.sendMessage(Constants.Messages.FAILED_TO_SAVE_CONFIG_FILE); + } + + return true; + } + +} diff --git a/src/poppy/Utils.java b/src/poppy/Utils.java @@ -0,0 +1,238 @@ +package poppy; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.entity.Entity; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; +import org.bukkit.Location; +import org.bukkit.GameMode; +import org.bukkit.plugin.Plugin; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; + +import poppy.Constants; + + +public class Utils +{ + public static boolean isEmpty(ItemStack item) + { + return item == null || item.getType() == Material.AIR; + } + + public static boolean isType(ItemStack item, Material type) + { + return !isEmpty(item) && item.getType() == type; + } + + public static boolean compare(ItemStack item, ItemStack item2) + { + if(item == null || item2 == null) + { + return false; + } + + if(item.getType() != item2.getType()) + { + return false; + } + + return true; + } + + public static boolean isInventoryFull(Inventory inventory, ItemStack result) + { + for(ItemStack item : inventory.getContents()) + { + if(Utils.isEmpty(item)) + { + return false; + } + + if(result.isSimilar(item)) + { + if(result.getAmount() + item.getAmount() <= item.getMaxStackSize()) + { + return false; + } + } + } + + return true; + } + + public static boolean containsAtLeast(Inventory inventory, ItemStack item, int amount) + { + for(int i = 0; i < inventory.getSize(); i++) + { + ItemStack current = inventory.getItem(i); + + if(Utils.compare(item, current)) + { + amount -= current.getAmount(); + + if(amount <= 0) + { + return true; + } + } + } + + return false; + } + + public static void sendActionMessage(Player player, String message) + { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); + } + + public static void sendCountdown(Plugin plugin, final String message, final int time, Runnable runnable) + { + Bukkit.getScheduler().runTaskTimer(plugin, new Runnable() + { + int count = time; + + @Override + public void run() + { + if(count == 0) + { + runnable.run(); + return; + } + + Bukkit.getServer().broadcastMessage(ChatColor.YELLOW + message + " " + count + " sec"); + + count--; + } + }, 0L, Constants.TICK); + } + + public static Float convertFacingToYaw(BlockFace face) + { + switch(face) + { + case NORTH: + return 0F; + case EAST: + return 90F; + case SOUTH: + return 180F; + case WEST: + return -90F; + default: + break; + } + + return null; + } + + public static boolean isAir(Material material) + { + return material == Material.AIR || material == Material.CAVE_AIR || material == Material.VOID_AIR; + } + + public static boolean isFarmable(Material material) + { + return material == Material.WHEAT || material == Material.CARROTS || material == Material.POTATOES || material == Material.BEETROOTS || material == Material.NETHER_WART || material == Material.COCOA; + } + + public static boolean isStem(Material material) + { + return material == Material.ATTACHED_PUMPKIN_STEM || material == Material.ATTACHED_MELON_STEM; + } + + public static boolean hasStem(Block block) + { + Location blockLocation = block.getLocation(); + Material blockNorth = blockLocation.clone().add(0, 0, -1).getBlock().getType(); + Material blockEast = blockLocation.clone().add(1, 0, 0).getBlock().getType(); + Material blockSouth = blockLocation.clone().add(0, 0, 1).getBlock().getType(); + Material blockWest = blockLocation.clone().add(-1, 0, 0).getBlock().getType(); + + return isStem(blockNorth) || isStem(blockEast) || isStem(blockSouth) || isStem(blockWest); + } + + public static Location calcBlockCenter(final Location location) + { + Location centered = location.clone(); + centered.setX(Location.locToBlock(location.getX()) + 0.5); + centered.setY(Location.locToBlock(location.getY())); + centered.setZ(Location.locToBlock(location.getZ()) + 0.5); + + return centered; + } + + public static int calcTravelFee(final Location from, final Location to) + { + final Double distance = from.distance(to); + int fee = (int) Math.floor(distance / (Constants.BLOCKS_PER_CHUNK * Constants.CHUNKS_PER_EMERALD)); + + if(fee < Constants.MIN_FEE) + { + fee = Constants.MIN_FEE; + } + + if(fee > Constants.MAX_FEE) + { + fee = Constants.MAX_FEE; + } + + return fee; + } + + public static boolean travelTo(final Plugin plugin, final Player player, final Location location) + { + final int fee = Utils.calcTravelFee(player.getLocation(), location); + final String unit = fee == 1 ? "emerald" : "emeralds"; + + if(!payFee(player, Material.EMERALD, fee) && player.getGameMode() == GameMode.SURVIVAL) + { + player.sendMessage(ChatColor.RED + "Not enough emeralds to teleport! Travel fee: " + fee + " " + unit); + return false; + } + + if(player.getVehicle() != null) + { + Entity vehicle = player.getVehicle(); + vehicle.eject(); + player.teleport(location); + + Bukkit.getScheduler().runTaskLater(plugin, () -> { + vehicle.teleport(location); + }, 3); + + Bukkit.getScheduler().runTaskLater(plugin, () -> { + vehicle.addPassenger(player); + }, 6); + } + else + { + player.teleport(location); + } + + return true; + } + + public static boolean payFee(final Player player, final Material unit, final int amount) + { + final ItemStack item = player.getInventory().getItemInMainHand(); + + if(item.getType() != unit || item.getAmount() < amount) + { + return false; + } + + item.setAmount(item.getAmount() - amount); + + return true; + } +} diff --git a/src/poppy/modules/AutoWorkbenchModule.java b/src/poppy/modules/AutoWorkbenchModule.java @@ -0,0 +1,241 @@ +package poppy.modules; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Dropper; +import org.bukkit.entity.Entity; +import org.bukkit.entity.ItemFrame; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryMoveItemEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.ShapelessRecipe; + +import poppy.Utils; + + +public class AutoWorkbenchModule implements Listener +{ + @EventHandler + public void onItemMove(InventoryMoveItemEvent event) + { + Inventory source = event.getSource(); + Inventory target = event.getDestination(); + + if(source.getHolder() instanceof Dropper) + { + Dropper dropper = (Dropper) source.getHolder(); + + ItemFrame frame = getItemFrame(dropper.getBlock()); + + if(frame == null) + { + return; + } + + ItemStack item = frame.getItem(); + + Recipe recipe = getCraftingRecipe(item, source, target); + + if(recipe != null) + { + if(recipe instanceof ShapelessRecipe) + { + ShapelessRecipe shapless = (ShapelessRecipe) recipe; + + target.addItem(shapless.getResult()); + } + + if(recipe instanceof ShapedRecipe) + { + ShapedRecipe shaped = (ShapedRecipe) recipe; + + target.addItem(shaped.getResult()); + } + } + + event.setCancelled(true); + } + } + + private Recipe getCraftingRecipe(ItemStack item, Inventory source, Inventory target) + { + if(Utils.isEmpty(item)) + { + return null; + } + + Iterator<Recipe> iterator = Bukkit.recipeIterator(); + + while(iterator.hasNext()) + { + Recipe recipe = iterator.next(); + + if(Utils.compare(item, recipe.getResult())) + { + List<ItemStack> ingredients = null; + + if(recipe instanceof ShapelessRecipe) + { + ShapelessRecipe shapless = (ShapelessRecipe) recipe; + + ingredients = shapless.getIngredientList(); + } + + if(recipe instanceof ShapedRecipe) + { + ShapedRecipe shaped = (ShapedRecipe) recipe; + + ingredients = new ArrayList<>(); + + for(ItemStack value : shaped.getIngredientMap().values()) + { + if(ingredients.isEmpty()) + { + if(!Utils.isEmpty(value)) + { + ingredients.add(value); + } + } + else + { + appendUniqueIngredient(ingredients, value); + } + } + } + + if(ingredients == null) + { + continue; + } + + if(!hasIngredients(source, ingredients)) + { + continue; + } + + if(Utils.isInventoryFull(target, recipe.getResult())) + { + return null; + } + + removeIngredients(ingredients, source); + + return recipe; + } + } + + return null; + } + + private void removeIngredients(List<ItemStack> ingredients, Inventory inventory) + { + for(ItemStack ingredient : ingredients) + { + if(Utils.isEmpty(ingredient)) + { + continue; + } + + int amount = ingredient.getAmount(); + + ListIterator<ItemStack> iterator = inventory.iterator(); + + while(iterator.hasNext()) + { + ItemStack item = iterator.next(); + + if(Utils.isEmpty(item)) + { + continue; + } + + if(Utils.compare(item, ingredient)) + { + if(item.getAmount() > amount) + { + item.setAmount(item.getAmount() - amount); + amount = 0; + + break; + } + + if(item.getAmount() == amount) + { + amount = 0; + inventory.removeItem(item); + + break; + } + + if(item.getAmount() < amount) + { + amount -= item.getAmount(); + inventory.removeItem(item); + } + } + } + } + } + + private void appendUniqueIngredient(List<ItemStack> ingredients, ItemStack item) + { + for(ItemStack ingredient : ingredients) + { + if(Utils.compare(item, ingredient)) + { + ingredient.setAmount(ingredient.getAmount() + item.getAmount()); + + return; + } + } + + if(!Utils.isEmpty(item)) + { + ingredients.add(item); + } + } + + private boolean hasIngredients(Inventory inventory, List<ItemStack> ingredients) + { + for(ItemStack ingredient : ingredients) + { + if(ingredient != null && !Utils.containsAtLeast(inventory, ingredient, ingredient.getAmount())) + { + return false; + } + } + + return true; + } + + private ItemFrame getItemFrame(Block block) + { + for(Entity entity : block.getWorld().getNearbyEntities(block.getLocation(), 2, 2, 2)) + { + if(entity instanceof ItemFrame) + { + ItemFrame frame = (ItemFrame) entity; + + if(frame.getFacing() == BlockFace.UP) + { + if(block.getLocation().add(0.5, 1.03125, 0.5).distance(frame.getLocation()) < 0.2D) + { + return frame; + } + } + } + } + + return null; + } +} diff --git a/src/poppy/modules/ChairModule.java b/src/poppy/modules/ChairModule.java @@ -0,0 +1,215 @@ +package poppy.modules; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.Bisected.Half; +import org.bukkit.block.data.type.Stairs; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.util.Vector; +import org.spigotmc.event.entity.EntityDismountEvent; + +import poppy.Utils; + + +public class ChairModule implements Listener +{ + private static final Material[] CHAIR_TYPE = new Material[] + { + Material.OAK_STAIRS, + Material.SPRUCE_STAIRS, + Material.BIRCH_STAIRS, + Material.JUNGLE_STAIRS, + Material.ACACIA_STAIRS, + Material.DARK_OAK_STAIRS, + Material.ACACIA_STAIRS, + Material.CRIMSON_STAIRS, + Material.WARPED_STAIRS + }; + + private Map<Block, ArmorStand> blockMap = new HashMap<>(); + + public void onDisable() + { + for(ArmorStand armorStand : blockMap.values()) + { + armorStand.eject(); + armorStand.remove(); + } + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) + { + Player player = event.getPlayer(); + + if(event.getAction() == Action.RIGHT_CLICK_BLOCK) + { + if(event.getClickedBlock() != null && !event.getPlayer().isSneaking()) + { + Block block = event.getClickedBlock(); + + if(isChair(block.getType())) + { + if(!isInRange(block, player)) + { + return; + } + + if(blockMap.containsKey(block)) + { + return; + } + + if(isCompatible(block)) + { + ArmorStand armorStand = createMountableChair(block, player); + + if(armorStand == null) + { + return; + } + + event.setCancelled(true); + + blockMap.put(block, armorStand); + } + } + } + } + } + + @EventHandler + public void onEntityDismount(EntityDismountEvent event) + { + if(event.getEntity() instanceof Player) + { + Entity entity = event.getDismounted(); + + if(entity != null && entity instanceof ArmorStand) + { + if(blockMap.containsValue(entity)) + { + for(Entry<Block, ArmorStand> entry : blockMap.entrySet()) + { + if(entry.getValue() == entity) + { + blockMap.remove(entry.getKey()); + + break; + } + } + } + + Location location = entity.getLocation(); + location.add(0, 1, 0); + + for(Entity passenger : entity.getPassengers()) { + location.setPitch(passenger.getLocation().getPitch()); + location.setYaw(passenger.getLocation().getYaw()); + passenger.teleport(location); + } + + entity.remove(); + } + } + } + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) + { + Block block = event.getBlock(); + + if(blockMap.containsKey(block)) + { + ArmorStand armorStand = blockMap.get(block); + armorStand.eject(); + + blockMap.remove(block); + } + } + + private boolean isInRange(Block block, Player player) + { + return block.getLocation().add(0.5, 0.5, 0.5).distance(player.getLocation()) <= 2; + } + + private boolean isChair(Material material) + { + for(Material chair : CHAIR_TYPE) + { + if(material == chair) + { + return true; + } + } + + return false; + } + + private boolean isCompatible(Block block) + { + Block upperBlock = block.getWorld().getBlockAt(block.getLocation().add(0, 1, 0)); + + if(!Utils.isAir(upperBlock.getType())) + { + return false; + } + + Stairs stairs = (Stairs) block.getState().getBlockData(); + + if(stairs.getHalf() != Half.BOTTOM) + { + return false; + } + + if(stairs.isWaterlogged()) + { + return false; + } + + if(stairs.getShape() == Stairs.Shape.INNER_RIGHT || stairs.getShape() == Stairs.Shape.INNER_LEFT) + { + return false; + } + + return true; + } + + @SuppressWarnings("deprecation") + private ArmorStand createMountableChair(Block block, Player player) + { + Stairs stairs = (Stairs) block.getState().getBlockData(); + + Float yaw = Utils.convertFacingToYaw(stairs.getFacing()); + + if(yaw == null) + { + return null; + } + + Location location = block.getLocation().add(0.5, -0.4, 0.5); + location.setYaw(yaw); + + ArmorStand armorStand = (ArmorStand) block.getWorld().spawnEntity(location, EntityType.ARMOR_STAND); + armorStand.setPassenger((Entity) player); + armorStand.setSmall(true); + armorStand.setGravity(false); + armorStand.setInvulnerable(true); + armorStand.setVisible(false); + + return armorStand; + } +} diff --git a/src/poppy/modules/CommonModule.java b/src/poppy/modules/CommonModule.java @@ -0,0 +1,180 @@ +package poppy.modules; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.Snowball; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import poppy.Utils; + + +public class CommonModule implements Listener +{ + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) + { + + Player player = event.getPlayer(); + + if(event.getAction() == Action.PHYSICAL) + { + if(event.getClickedBlock() != null) + { + if(event.getClickedBlock().getType() == Material.FARMLAND) + { + event.setCancelled(true); + } + } + } + + EquipmentSlot equip = event.getHand(); + + if(equip.equals(EquipmentSlot.HAND)) + { + + if(event.getAction() == Action.RIGHT_CLICK_BLOCK) + { + Block block = event.getClickedBlock(); + + if(block == null) + { + return; + } + + Material material = block.getType(); + + if(player.isSneaking()) + { + return; + } + + BlockData blockdata = block.getBlockData(); + + if(blockdata instanceof Ageable) + { + + Ageable ageable = (Ageable) blockdata; + + if(Utils.isFarmable(material) && ageable.getAge() == ageable.getMaximumAge()) + { + + event.setCancelled(true); + + if(blockdata instanceof Directional) + { + Directional directional = (Directional) blockdata; + BlockFace blockface = directional.getFacing(); + + block.breakNaturally(player.getItemInUse()); + block.setType(material); + directional = (Directional) blockdata; + ageable.setAge(0); + directional.setFacing(blockface); + block.setBlockData(blockdata); + } + else + { + + block.breakNaturally(player.getItemInUse()); + block.setType(material); + } + } + } + + if(material == Material.MELON && Utils.hasStem(block) || material == Material.PUMPKIN && Utils.hasStem(block)) + { + block.breakNaturally(player.getInventory().getItemInMainHand()); + } + } + } + } + + @EventHandler + public void onEntityExplode(EntityExplodeEvent event) + { + if(event.getEntityType() == EntityType.CREEPER) + { + event.blockList().clear(); + } + } + + @EventHandler + public void onChat(AsyncPlayerChatEvent event) + { + String message = ChatColor.GRAY + event.getMessage().replace("%", "%%"); + String format = ChatColor.WHITE + event.getPlayer().getName() + ": " + message; + event.setFormat(format); + } + + @EventHandler + public void onEntityHit(EntityDamageByEntityEvent event) + { + if(event.getDamager() instanceof Snowball) + { + Snowball snowball = (Snowball) event.getDamager(); + + if(snowball.getShooter() instanceof Player) + { + Player player = (Player) event.getEntity(); + + player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 2, 1)); + event.setDamage(1); + } + } + } + + @EventHandler + public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) + { + Player player = event.getPlayer(); + + if(event.getRightClicked().getType().equals(EntityType.ARMOR_STAND)) + { + ItemStack item = player.getInventory().getItemInMainHand(); + + if(item.getType() == Material.STICK && item.getAmount() > 1 && player.isSneaking()) + { + ArmorStand armorstand = (ArmorStand) event.getRightClicked(); + + armorstand.setArms(true); + item.setAmount(item.getAmount() - 2); + + event.setCancelled(true); + } + } + } + + @EventHandler + public void onArmorStandDestroy(EntityDeathEvent event) + { + if(event.getEntity() instanceof ArmorStand) + { + ArmorStand armorstand = (ArmorStand) event.getEntity(); + + if(armorstand.hasArms()) + { + event.getDrops().add(new ItemStack(Material.STICK, 2)); + } + } + } +} +\ No newline at end of file diff --git a/src/poppy/modules/DoubleDoorModule.java b/src/poppy/modules/DoubleDoorModule.java @@ -0,0 +1,152 @@ +package poppy.modules; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.type.Door; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; + +import poppy.Utils; + + +public class DoubleDoorModule implements Listener +{ + private static final Material[] DOOR_TYPE = new Material[] { Material.OAK_DOOR, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR, Material.ACACIA_DOOR, Material.CRIMSON_DOOR, Material.WARPED_DOOR }; + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) + { + Player player = event.getPlayer(); + + if(event.getAction() == Action.RIGHT_CLICK_BLOCK) + { + if(event.getClickedBlock() != null) + { + Block block = event.getClickedBlock(); + + if(isDoor(block.getType())) + { + if(player.isSneaking()) + { + if(!Utils.isEmpty(player.getInventory().getItemInMainHand())) + { + return; + } + + if(!Utils.isEmpty(player.getInventory().getItemInOffHand())) + { + return; + } + } + + BlockState state = block.getState(); + Door door = (Door) state.getBlockData(); + + Location location = getOppositeDoor(door, block.getLocation()); + + if(location == null) + { + return; + } + + Block opposite = block.getWorld().getBlockAt(location); + + if(block.getType() != opposite.getType()) + { + return; + } + + BlockState stateOpposite = opposite.getState(); + Door doorOpposite = (Door) stateOpposite.getBlockData(); + + if(isCompatible(door, doorOpposite)) + { + if(door.isOpen() && doorOpposite.isOpen()) + { + doorOpposite.setOpen(false); + + stateOpposite.setBlockData(doorOpposite); + stateOpposite.update(); + + player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_DOOR_CLOSE, 1F, 1F); + } + + if(!door.isOpen() && !doorOpposite.isOpen()) + { + doorOpposite.setOpen(true); + + stateOpposite.setBlockData(doorOpposite); + stateOpposite.update(); + + player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_DOOR_OPEN, 1F, 1F); + } + } + } + } + } + } + + private boolean isDoor(Material material) + { + for(Material door : DOOR_TYPE) + { + if(material == door) + { + return true; + } + } + + return false; + } + + private Location getOppositeDoor(Door door, Location location) + { + int invert = door.getHinge() == Door.Hinge.LEFT ? 1 : -1; + + switch(door.getFacing()) + { + case NORTH: + location.add(1 * invert, 0, 0); + break; + case EAST: + location.add(0, 0, 1 * invert); + break; + case SOUTH: + location.add(-1 * invert, 0, 0); + break; + case WEST: + location.add(0, 0, -1 * invert); + break; + default: + return null; + } + + return location; + } + + private boolean isCompatible(Door door, Door doorItem) + { + if(door.getFacing() != doorItem.getFacing()) + { + return false; + } + + if(door.getHalf() != doorItem.getHalf()) + { + return false; + } + + if(door.getHinge() == doorItem.getHinge()) + { + return false; + } + + return true; + } +} diff --git a/src/poppy/modules/LeavesDecayModule.java b/src/poppy/modules/LeavesDecayModule.java @@ -0,0 +1,124 @@ +package poppy.modules; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.bukkit.Tag; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.type.Leaves; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.LeavesDecayEvent; +import org.bukkit.plugin.Plugin; + +public class LeavesDecayModule implements Listener +{ + private static final int DELAY = 25; + private static final List<BlockFace> NEIGHBORS = Arrays.asList( + BlockFace.UP, + BlockFace.NORTH, + BlockFace.EAST, + BlockFace.SOUTH, + BlockFace.WEST, + BlockFace.DOWN + ); + + private Plugin plugin; + private List<Block> scheduled = new ArrayList<>(); + + public LeavesDecayModule(Plugin plugin) + { + this.plugin = plugin; + } + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) + { + onBlockRemove(event.getBlock()); + } + + @EventHandler + public void onLeavesDecay(LeavesDecayEvent event) + { + onBlockRemove(event.getBlock()); + } + + private void onBlockRemove(Block block) + { + if(!Tag.LOGS.isTagged(block.getType()) && !Tag.LEAVES.isTagged(block.getType())) + { + return; + } + + Collections.shuffle(NEIGHBORS); + + for(BlockFace face : NEIGHBORS) + { + final Block neighbor = block.getRelative(face); + + if(!Tag.LEAVES.isTagged(neighbor.getType())) + { + continue; + } + + Leaves leaves = (Leaves) neighbor.getBlockData(); + + if(leaves.isPersistent()) + { + continue; + } + + if(scheduled.contains(neighbor)) + { + continue; + } + + plugin.getServer().getScheduler().runTaskLater(plugin, () -> decay(neighbor), DELAY); + + scheduled.add(neighbor); + } + } + + private boolean decay(Block block) + { + scheduled.remove(block); + + if(!block.getWorld().isChunkLoaded(block.getX() >> 4, block.getZ() >> 4)) + { + return false; + } + + if(!Tag.LEAVES.isTagged(block.getType())) + { + return false; + } + + Leaves leaves = (Leaves) block.getBlockData(); + + if(leaves.isPersistent()) + { + return false; + } + + if(leaves.getDistance() < 7) + { + return false; + } + + LeavesDecayEvent event = new LeavesDecayEvent(block); + plugin.getServer().getPluginManager().callEvent(event); + + if(event.isCancelled()) + { + return false; + } + + block.breakNaturally(); + + return true; + } +}