A feature-rich Minecraft plugin which enhances gaming experience
git clone git://soophie.de/poppy
1
# minecraft-hub2
A Minecraft Server Management Plugin1
# poppy2
A Minecraft server management plugin4
### Export as JAR file
1
#!/bin/bash3
cd /home/andreas/git/poppy5
git --git-dir=../poppy/.git --work-tree=../poppy pull origin main7
/opt/gradle/gradle-7.6/bin/gradle build9
cp build/libs/poppy.jar /srv/minecraft/plugins/
1
main: de.typable.minecrafthub.Main2
name: MinecraftHub1
main: poppy.Main2
name: poppy3
version: 0.0.14
author: typable4
author: typable, chunksize5
api-version: 1.166
commands:7
head:
10
spawn:11
usage: /spawn12
invsee:13
usage: /invsee <name> <enderchest>13
usage: /invsee <name>14
sethome:15
home:16
setwarp:
1
package de.typable.minecrafthub;3
import java.io.File;4
import java.io.IOException;5
import java.net.BindException;6
import java.net.ServerSocket;7
import java.net.Socket;9
import org.bukkit.Bukkit;10
import org.bukkit.ChatColor;11
import org.bukkit.GameMode;12
import org.bukkit.Location;13
import org.bukkit.Material;14
import org.bukkit.World;15
import org.bukkit.WorldCreator;16
import org.bukkit.WorldType;17
import org.bukkit.command.Command;18
import org.bukkit.command.CommandSender;19
import org.bukkit.entity.Player;20
import org.bukkit.inventory.ItemStack;21
import org.bukkit.inventory.meta.SkullMeta;22
import org.bukkit.inventory.meta.BookMeta;23
import org.bukkit.material.Tree;24
import org.bukkit.plugin.Plugin;25
import org.bukkit.plugin.PluginManager;26
import org.bukkit.plugin.java.JavaPlugin;28
import de.typable.minecrafthub.constant.Constants;29
import de.typable.minecrafthub.event.AutoWorkbenchListener;30
import de.typable.minecrafthub.event.ChairListener;31
import de.typable.minecrafthub.event.DoubleDoorListener;32
import de.typable.minecrafthub.event.EventListener;33
import de.typable.minecrafthub.event.LeavesDecayListener;34
import de.typable.minecrafthub.util.Util;35
import de.typable.minecrafthub.config.Config;38
public class Main extends JavaPlugin39
{40
private PluginManager pluginManager;41
private DoubleDoorListener doubleDoorListener;42
private ChairListener chairListener;43
private AutoWorkbenchListener autoWorkbenchListener;44
private LeavesDecayListener leavesDecayListener;45
private EventListener eventListener;47
private Plugin plugin;48
private Config config;50
@Override51
public void onEnable()52
{53
plugin = this;54
config = new Config("config/minecraft-hub.yml");56
pluginManager = Bukkit.getPluginManager();58
doubleDoorListener = new DoubleDoorListener();59
pluginManager.registerEvents(doubleDoorListener, this);61
chairListener = new ChairListener();62
pluginManager.registerEvents(chairListener, this);64
autoWorkbenchListener = new AutoWorkbenchListener();65
pluginManager.registerEvents(autoWorkbenchListener, this);67
leavesDecayListener = new LeavesDecayListener(this);68
pluginManager.registerEvents(leavesDecayListener, this);70
eventListener = new EventListener();71
pluginManager.registerEvents(eventListener, this);72
}74
@Override75
public void onDisable()76
{77
chairListener.onDisable();78
}80
@Override81
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)82
{83
if(sender instanceof Player)84
{85
Player player = (Player) sender;87
switch(label)88
{89
case "head":90
return setItemAsHead(player, args);91
case "skull":92
return getSkullForName(player, args);93
case "invsee":94
return openInventoryForPlayer(player, args);95
case "info":96
return openInfoBook(player, args);97
case "spawn":98
return teleportToSpawn(player, args);99
case "home":100
return teleportToHome(player, args);101
case "warp":102
return teleportToWarppoint(player, args);103
case "sethome":104
return setHome(player, args);105
case "setwarp":106
return addWarppoint(player, args);107
default:108
return false;109
}110
}112
return true;113
}115
private boolean setItemAsHead(final Player player, final String[] args)116
{117
final ItemStack item = player.getInventory().getItemInMainHand();118
final ItemStack head = player.getInventory().getHelmet();120
player.getInventory().setHelmet(item);121
player.getInventory().setItemInMainHand((new ItemStack(Material.AIR)));123
if(player.getGameMode() == GameMode.SURVIVAL)124
{125
if(head != null)126
{127
player.getInventory().addItem(head);128
}129
}131
return true;132
}134
@SuppressWarnings("deprecation")135
private boolean getSkullForName(final Player player, final String[] args)136
{137
if(!player.isOp())138
{139
player.sendMessage(Constants.Messages.NOT_ENOUGH_PERMISSION);140
return true;141
}143
if(args.length != 1)144
{145
return false;146
}148
final String name = args[0];149
final ItemStack skull = new ItemStack(Material.PLAYER_HEAD);150
final SkullMeta meta = (SkullMeta) skull.getItemMeta();151
meta.setOwner(name);152
skull.setItemMeta(meta);154
player.getInventory().addItem(skull);156
return true;157
}159
private boolean openInventoryForPlayer(final Player player, final String[] args)160
{161
if(args.length == 0)162
{163
return false;164
}166
if(!player.isOp())167
{168
player.sendMessage(Constants.Messages.NOT_ENOUGH_PERMISSION);169
return true;170
}172
final Player target = Bukkit.getPlayer(args[0]);174
if(target == null)175
{176
player.sendMessage(ChatColor.RED + "Player not found!");177
return true;178
}180
player.openInventory(target.getInventory());182
return true;183
}185
private boolean openInfoBook(final Player player, final String[] args)186
{187
final ItemStack book = new ItemStack(Material.WRITTEN_BOOK);188
final BookMeta meta = (BookMeta) book.getItemMeta();189
meta.setTitle("Info");190
meta.setAuthor("Server");191
meta.setPages(config.getInfoPages());192
book.setItemMeta(meta);194
player.openBook(book);196
return true;197
}199
private boolean teleportToSpawn(final Player player, final String[] args)200
{201
final Location location = Bukkit.getWorld("world").getSpawnLocation();203
if(Util.travelTo(plugin, player, location))204
{205
player.sendMessage(ChatColor.GRAY + "You've been teleported to spawn.");206
}208
return true;209
}211
private boolean teleportToHome(final Player player, final String[] args)212
{213
final Location location = config.getHome(player);215
if(location == null)216
{217
player.sendMessage(ChatColor.RED + "You've don't have a home point.");218
return true;219
}221
if(Util.travelTo(plugin, player, location))222
{223
player.sendMessage(ChatColor.GRAY + "You've been teleported to your home.");224
}226
return true;227
}229
private boolean teleportToWarppoint(final Player player, final String[] args)230
{231
if(args.length != 1)232
{233
return false;234
}236
final String name = args[0];237
final Location location = config.getWarp(name);239
if(location == null)240
{241
player.sendMessage(ChatColor.RED + "Warp point " + name + " doesn't exist!");242
return true;243
}245
if(Util.travelTo(plugin, player, location))246
{247
player.sendMessage(ChatColor.GRAY + "You've been teleported to warp point " + name + ".");248
}250
return true;251
}253
private boolean setHome(final Player player, final String[] args)254
{255
try256
{257
config.setHome(player);258
player.sendMessage(ChatColor.YELLOW + "Home point set.");259
}260
catch(Exception ex)261
{262
player.sendMessage(Constants.Messages.FAILED_TO_SAVE_CONFIG_FILE);263
}265
return true;266
}268
private boolean addWarppoint(final Player player, final String[] args)269
{270
if(args.length != 1)271
{272
return false;273
}275
final String name = args[0];277
if(!Util.payFee(player, Material.COMPASS, 1))278
{279
player.sendMessage(ChatColor.RED + "The fee for creating a warp point is 1 compass!");280
return true;281
}283
try284
{285
if(!config.setWarp(name, player.getLocation()))286
{287
player.sendMessage(ChatColor.RED + "Warp point " + name + " already exists!");288
return true;289
}291
player.sendMessage(ChatColor.YELLOW + "Warp point " + name + " set.");292
}293
catch(Exception ex)294
{295
player.sendMessage(Constants.Messages.FAILED_TO_SAVE_CONFIG_FILE);296
}298
return true;299
}301
}
1
package de.typable.minecrafthub.config;3
import java.io.File;4
import java.io.IOException;5
import java.util.List;6
import java.util.ArrayList;8
import org.bukkit.configuration.file.FileConfiguration;9
import org.bukkit.configuration.file.YamlConfiguration;10
import org.bukkit.entity.Player;11
import org.bukkit.Location;13
import de.typable.minecrafthub.util.Util;15
public class Config16
{17
private File file;18
private FileConfiguration configuration;20
public Config(final String path)21
{22
this.file = new File(path);23
this.configuration = YamlConfiguration.loadConfiguration(this.file);24
}26
public void setHome(final Player player) throws IOException27
{28
final String path = "home." + player.getDisplayName();29
final Location location = Util.calcBlockCenter(player.getLocation());31
this.configuration.set(path, location);32
this.configuration.save(this.file);33
}35
public Location getHome(final Player player)36
{37
final String path = "home." + player.getDisplayName();39
return this.configuration.getLocation(path);40
}42
public boolean setWarp(final String name, final Location location) throws IOException43
{44
final String path = "warp." + name;46
if(this.configuration.getLocation(path) != null)47
{48
return false;49
}51
this.configuration.set(path, Util.calcBlockCenter(location));52
this.configuration.save(this.file);54
return true;55
}57
public Location getWarp(final String name)58
{59
final String path = "warp." + name;61
return this.configuration.getLocation(path);62
}64
public List<String> getInfoPages()65
{66
final String path = "info";67
List<String> pages = null;69
try70
{71
this.configuration.load(this.file);72
pages = (List<String>) this.configuration.getList(path);73
}74
catch(Exception ex)75
{76
// ignore77
}79
if(pages == null)80
{81
pages = new ArrayList<>();82
}84
return pages;85
}86
}
1
package de.typable.minecrafthub.constant;3
import org.bukkit.ChatColor;6
public class Constants7
{8
public static final long TICK = 20;9
public static final int BLOCKS_PER_CHUNK = 16;10
public static final int CHUNKS_PER_EMERALD = 25;11
public static final int MIN_FEE = 1;12
public static final int MAX_FEE = 64;14
public static final class Messages15
{16
public static final String NOT_ENOUGH_PERMISSION = ChatColor.RED + "You don't have enough Permission to perform this command!";17
public static final String FAILED_TO_SAVE_CONFIG_FILE = ChatColor.RED + "Failed to save changes!";18
}19
}
1
package de.typable.minecrafthub.event;3
import java.util.ArrayList;4
import java.util.Iterator;5
import java.util.List;6
import java.util.ListIterator;8
import org.bukkit.Bukkit;9
import org.bukkit.block.Block;10
import org.bukkit.block.BlockFace;11
import org.bukkit.block.Dropper;12
import org.bukkit.entity.Entity;13
import org.bukkit.entity.ItemFrame;14
import org.bukkit.event.EventHandler;15
import org.bukkit.event.Listener;16
import org.bukkit.event.inventory.InventoryMoveItemEvent;17
import org.bukkit.inventory.Inventory;18
import org.bukkit.inventory.ItemStack;19
import org.bukkit.inventory.Recipe;20
import org.bukkit.inventory.ShapedRecipe;21
import org.bukkit.inventory.ShapelessRecipe;23
import de.typable.minecrafthub.util.Util;26
public class AutoWorkbenchListener implements Listener27
{28
@EventHandler29
public void onItemMove(InventoryMoveItemEvent event)30
{31
Inventory source = event.getSource();32
Inventory target = event.getDestination();34
if(source.getHolder() instanceof Dropper)35
{36
Dropper dropper = (Dropper) source.getHolder();38
ItemFrame frame = getItemFrame(dropper.getBlock());40
if(frame == null)41
{42
return;43
}45
ItemStack item = frame.getItem();47
Recipe recipe = getCraftingRecipe(item, source, target);49
if(recipe != null)50
{51
if(recipe instanceof ShapelessRecipe)52
{53
ShapelessRecipe shapless = (ShapelessRecipe) recipe;55
target.addItem(shapless.getResult());56
}58
if(recipe instanceof ShapedRecipe)59
{60
ShapedRecipe shaped = (ShapedRecipe) recipe;62
target.addItem(shaped.getResult());63
}64
}66
event.setCancelled(true);67
}68
}70
private Recipe getCraftingRecipe(ItemStack item, Inventory source, Inventory target)71
{72
if(Util.isEmpty(item))73
{74
return null;75
}77
Iterator<Recipe> iterator = Bukkit.recipeIterator();79
while(iterator.hasNext())80
{81
Recipe recipe = iterator.next();83
if(Util.compare(item, recipe.getResult()))84
{85
List<ItemStack> ingredients = null;87
if(recipe instanceof ShapelessRecipe)88
{89
ShapelessRecipe shapless = (ShapelessRecipe) recipe;91
ingredients = shapless.getIngredientList();92
}94
if(recipe instanceof ShapedRecipe)95
{96
ShapedRecipe shaped = (ShapedRecipe) recipe;98
ingredients = new ArrayList<>();100
for(ItemStack value : shaped.getIngredientMap().values())101
{102
if(ingredients.isEmpty())103
{104
if(!Util.isEmpty(value))105
{106
ingredients.add(value);107
}108
}109
else110
{111
appendUniqueIngredient(ingredients, value);112
}113
}114
}116
if(ingredients == null)117
{118
continue;119
}121
if(!hasIngredients(source, ingredients))122
{123
continue;124
}126
if(Util.isInventoryFull(target, recipe.getResult()))127
{128
return null;129
}131
removeIngredients(ingredients, source);133
return recipe;134
}135
}137
return null;138
}140
private void removeIngredients(List<ItemStack> ingredients, Inventory inventory)141
{142
for(ItemStack ingredient : ingredients)143
{144
if(Util.isEmpty(ingredient))145
{146
continue;147
}149
int amount = ingredient.getAmount();151
ListIterator<ItemStack> iterator = inventory.iterator();153
while(iterator.hasNext())154
{155
ItemStack item = iterator.next();157
if(Util.isEmpty(item))158
{159
continue;160
}162
if(Util.compare(item, ingredient))163
{164
if(item.getAmount() > amount)165
{166
item.setAmount(item.getAmount() - amount);167
amount = 0;169
break;170
}172
if(item.getAmount() == amount)173
{174
amount = 0;175
inventory.removeItem(item);177
break;178
}180
if(item.getAmount() < amount)181
{182
amount -= item.getAmount();183
inventory.removeItem(item);184
}185
}186
}187
}188
}190
private void appendUniqueIngredient(List<ItemStack> ingredients, ItemStack item)191
{192
for(ItemStack ingredient : ingredients)193
{194
if(Util.compare(item, ingredient))195
{196
ingredient.setAmount(ingredient.getAmount() + item.getAmount());198
return;199
}200
}202
if(!Util.isEmpty(item))203
{204
ingredients.add(item);205
}206
}208
private boolean hasIngredients(Inventory inventory, List<ItemStack> ingredients)209
{210
for(ItemStack ingredient : ingredients)211
{212
if(ingredient != null && !Util.containsAtLeast(inventory, ingredient, ingredient.getAmount()))213
{214
return false;215
}216
}218
return true;219
}221
private ItemFrame getItemFrame(Block block)222
{223
for(Entity entity : block.getWorld().getNearbyEntities(block.getLocation(), 2, 2, 2))224
{225
if(entity instanceof ItemFrame)226
{227
ItemFrame frame = (ItemFrame) entity;229
if(frame.getFacing() == BlockFace.UP)230
{231
if(block.getLocation().add(0.5, 1.03125, 0.5).distance(frame.getLocation()) < 0.2D)232
{233
return frame;234
}235
}236
}237
}239
return null;240
}241
}
1
package de.typable.minecrafthub.event;3
import java.util.HashMap;4
import java.util.Map;5
import java.util.Map.Entry;7
import org.bukkit.Location;8
import org.bukkit.Material;9
import org.bukkit.block.Block;10
import org.bukkit.block.data.Bisected.Half;11
import org.bukkit.block.data.type.Stairs;12
import org.bukkit.entity.ArmorStand;13
import org.bukkit.entity.Entity;14
import org.bukkit.entity.EntityType;15
import org.bukkit.entity.Player;16
import org.bukkit.event.EventHandler;17
import org.bukkit.event.Listener;18
import org.bukkit.event.block.Action;19
import org.bukkit.event.block.BlockBreakEvent;20
import org.bukkit.event.player.PlayerInteractEvent;21
import org.bukkit.util.Vector;22
import org.spigotmc.event.entity.EntityDismountEvent;24
import de.typable.minecrafthub.util.Util;27
public class ChairListener implements Listener28
{29
private static final Material[] CHAIR_TYPE = new Material[]30
{31
Material.OAK_STAIRS,32
Material.SPRUCE_STAIRS,33
Material.BIRCH_STAIRS,34
Material.JUNGLE_STAIRS,35
Material.ACACIA_STAIRS,36
Material.DARK_OAK_STAIRS,37
Material.ACACIA_STAIRS,38
Material.CRIMSON_STAIRS,39
Material.WARPED_STAIRS40
};42
private Map<Block, ArmorStand> blockMap = new HashMap<>();44
public void onDisable()45
{46
for(ArmorStand armorStand : blockMap.values())47
{48
armorStand.eject();49
armorStand.remove();50
}51
}53
@EventHandler54
public void onPlayerInteract(PlayerInteractEvent event)55
{56
Player player = event.getPlayer();58
if(event.getAction() == Action.RIGHT_CLICK_BLOCK)59
{60
if(event.getClickedBlock() != null && !event.getPlayer().isSneaking())61
{62
Block block = event.getClickedBlock();64
if(isChair(block.getType()))65
{66
if(!isInRange(block, player))67
{68
return;69
}71
if(blockMap.containsKey(block))72
{73
return;74
}76
if(isCompatible(block))77
{78
ArmorStand armorStand = createMountableChair(block, player);80
if(armorStand == null)81
{82
return;83
}85
event.setCancelled(true);87
blockMap.put(block, armorStand);88
}89
}90
}91
}92
}94
@EventHandler95
public void onEntityDismount(EntityDismountEvent event)96
{97
if(event.getEntity() instanceof Player)98
{99
Entity entity = event.getDismounted();101
if(entity != null && entity instanceof ArmorStand)102
{103
if(blockMap.containsValue(entity))104
{105
for(Entry<Block, ArmorStand> entry : blockMap.entrySet())106
{107
if(entry.getValue() == entity)108
{109
blockMap.remove(entry.getKey());111
break;112
}113
}114
}116
Location location = entity.getLocation();117
location.add(0, 1, 0);119
for(Entity passenger : entity.getPassengers()) {120
location.setPitch(passenger.getLocation().getPitch());121
location.setYaw(passenger.getLocation().getYaw());122
passenger.teleport(location);123
}125
entity.remove();126
}127
}128
}130
@EventHandler131
public void onBlockBreak(BlockBreakEvent event)132
{133
Block block = event.getBlock();135
if(blockMap.containsKey(block))136
{137
ArmorStand armorStand = blockMap.get(block);138
armorStand.eject();140
blockMap.remove(block);141
}142
}144
private boolean isInRange(Block block, Player player)145
{146
return block.getLocation().add(0.5, 0.5, 0.5).distance(player.getLocation()) <= 2;147
}149
private boolean isChair(Material material)150
{151
for(Material chair : CHAIR_TYPE)152
{153
if(material == chair)154
{155
return true;156
}157
}159
return false;160
}162
private boolean isCompatible(Block block)163
{164
Block upperBlock = block.getWorld().getBlockAt(block.getLocation().add(0, 1, 0));166
if(!Util.isAir(upperBlock.getType()))167
{168
return false;169
}171
Stairs stairs = (Stairs) block.getState().getBlockData();173
if(stairs.getHalf() != Half.BOTTOM)174
{175
return false;176
}178
if(stairs.isWaterlogged())179
{180
return false;181
}183
if(stairs.getShape() == Stairs.Shape.INNER_RIGHT || stairs.getShape() == Stairs.Shape.INNER_LEFT)184
{185
return false;186
}188
return true;189
}191
@SuppressWarnings("deprecation")192
private ArmorStand createMountableChair(Block block, Player player)193
{194
Stairs stairs = (Stairs) block.getState().getBlockData();196
Float yaw = Util.convertFacingToYaw(stairs.getFacing());198
if(yaw == null)199
{200
return null;201
}203
Location location = block.getLocation().add(0.5, -0.4, 0.5);204
location.setYaw(yaw);206
ArmorStand armorStand = (ArmorStand) block.getWorld().spawnEntity(location, EntityType.ARMOR_STAND);207
armorStand.setPassenger((Entity) player);208
armorStand.setSmall(true);209
armorStand.setGravity(false);210
armorStand.setInvulnerable(true);211
armorStand.setVisible(false);213
return armorStand;214
}215
}
1
package de.typable.minecrafthub.event;3
import org.bukkit.Location;4
import org.bukkit.Material;5
import org.bukkit.Sound;6
import org.bukkit.block.Block;7
import org.bukkit.block.BlockState;8
import org.bukkit.block.data.type.Door;9
import org.bukkit.entity.Player;10
import org.bukkit.event.EventHandler;11
import org.bukkit.event.Listener;12
import org.bukkit.event.block.Action;13
import org.bukkit.event.player.PlayerInteractEvent;15
import de.typable.minecrafthub.util.Util;18
public class DoubleDoorListener implements Listener19
{20
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 };22
@EventHandler23
public void onPlayerInteract(PlayerInteractEvent event)24
{25
Player player = event.getPlayer();27
if(event.getAction() == Action.RIGHT_CLICK_BLOCK)28
{29
if(event.getClickedBlock() != null)30
{31
Block block = event.getClickedBlock();33
if(isDoor(block.getType()))34
{35
if(player.isSneaking())36
{37
if(!Util.isEmpty(player.getInventory().getItemInMainHand()))38
{39
return;40
}42
if(!Util.isEmpty(player.getInventory().getItemInOffHand()))43
{44
return;45
}46
}48
BlockState state = block.getState();49
Door door = (Door) state.getBlockData();51
Location location = getOppositeDoor(door, block.getLocation());53
if(location == null)54
{55
return;56
}58
Block opposite = block.getWorld().getBlockAt(location);60
if(block.getType() != opposite.getType())61
{62
return;63
}65
BlockState stateOpposite = opposite.getState();66
Door doorOpposite = (Door) stateOpposite.getBlockData();68
if(isCompatible(door, doorOpposite))69
{70
if(door.isOpen() && doorOpposite.isOpen())71
{72
doorOpposite.setOpen(false);74
stateOpposite.setBlockData(doorOpposite);75
stateOpposite.update();77
player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_DOOR_CLOSE, 1F, 1F);78
}80
if(!door.isOpen() && !doorOpposite.isOpen())81
{82
doorOpposite.setOpen(true);84
stateOpposite.setBlockData(doorOpposite);85
stateOpposite.update();87
player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_DOOR_OPEN, 1F, 1F);88
}89
}90
}91
}92
}93
}95
private boolean isDoor(Material material)96
{97
for(Material door : DOOR_TYPE)98
{99
if(material == door)100
{101
return true;102
}103
}105
return false;106
}108
private Location getOppositeDoor(Door door, Location location)109
{110
int invert = door.getHinge() == Door.Hinge.LEFT ? 1 : -1;112
switch(door.getFacing())113
{114
case NORTH:115
location.add(1 * invert, 0, 0);116
break;117
case EAST:118
location.add(0, 0, 1 * invert);119
break;120
case SOUTH:121
location.add(-1 * invert, 0, 0);122
break;123
case WEST:124
location.add(0, 0, -1 * invert);125
break;126
default:127
return null;128
}130
return location;131
}133
private boolean isCompatible(Door door, Door doorItem)134
{135
if(door.getFacing() != doorItem.getFacing())136
{137
return false;138
}140
if(door.getHalf() != doorItem.getHalf())141
{142
return false;143
}145
if(door.getHinge() == doorItem.getHinge())146
{147
return false;148
}150
return true;151
}152
}
1
package de.typable.minecrafthub.event;3
import org.bukkit.ChatColor;4
import org.bukkit.Material;5
import org.bukkit.block.Block;6
import org.bukkit.block.BlockFace;7
import org.bukkit.block.data.Ageable;8
import org.bukkit.block.data.BlockData;9
import org.bukkit.block.data.Directional;10
import org.bukkit.entity.ArmorStand;11
import org.bukkit.entity.EntityType;12
import org.bukkit.entity.Player;13
import org.bukkit.entity.Snowball;14
import org.bukkit.event.EventHandler;15
import org.bukkit.event.Listener;16
import org.bukkit.event.block.Action;17
import org.bukkit.event.entity.EntityDamageByEntityEvent;18
import org.bukkit.event.entity.EntityDeathEvent;19
import org.bukkit.event.entity.EntityExplodeEvent;20
import org.bukkit.event.player.AsyncPlayerChatEvent;21
import org.bukkit.event.player.PlayerInteractAtEntityEvent;22
import org.bukkit.event.player.PlayerInteractEvent;23
import org.bukkit.inventory.EquipmentSlot;24
import org.bukkit.inventory.ItemStack;25
import org.bukkit.potion.PotionEffect;26
import org.bukkit.potion.PotionEffectType;28
import de.typable.minecrafthub.util.Util;31
public class EventListener implements Listener32
{33
@EventHandler34
public void onPlayerInteract(PlayerInteractEvent event)35
{37
Player player = event.getPlayer();39
if(event.getAction() == Action.PHYSICAL)40
{41
if(event.getClickedBlock() != null)42
{43
if(event.getClickedBlock().getType() == Material.FARMLAND)44
{45
event.setCancelled(true);46
}47
}48
}50
EquipmentSlot equip = event.getHand();52
if(equip.equals(EquipmentSlot.HAND))53
{55
if(event.getAction() == Action.RIGHT_CLICK_BLOCK)56
{57
Block block = event.getClickedBlock();59
if(block == null)60
{61
return;62
}64
Material material = block.getType();66
if(player.isSneaking())67
{68
return;69
}71
BlockData blockdata = block.getBlockData();73
if(blockdata instanceof Ageable)74
{76
Ageable ageable = (Ageable) blockdata;78
if(Util.isFarmable(material) && ageable.getAge() == ageable.getMaximumAge())79
{81
event.setCancelled(true);83
if(blockdata instanceof Directional)84
{85
Directional directional = (Directional) blockdata;86
BlockFace blockface = directional.getFacing();88
block.breakNaturally(player.getItemInUse());89
block.setType(material);90
directional = (Directional) blockdata;91
ageable.setAge(0);92
directional.setFacing(blockface);93
block.setBlockData(blockdata);94
}95
else96
{98
block.breakNaturally(player.getItemInUse());99
block.setType(material);100
}101
}102
}104
if(material == Material.MELON && Util.hasStem(block) || material == Material.PUMPKIN && Util.hasStem(block))105
{106
block.breakNaturally(player.getInventory().getItemInMainHand());107
}108
}109
}110
}112
@EventHandler113
public void onEntityExplode(EntityExplodeEvent event)114
{115
if(event.getEntityType() == EntityType.CREEPER)116
{117
event.blockList().clear();118
}119
}121
@EventHandler122
public void onChat(AsyncPlayerChatEvent event)123
{124
String message = ChatColor.GRAY + event.getMessage().replace("%", "%%");125
String format = ChatColor.WHITE + event.getPlayer().getName() + ": " + message;126
event.setFormat(format);127
}129
@EventHandler130
public void onEntityHit(EntityDamageByEntityEvent event)131
{132
if(event.getDamager() instanceof Snowball)133
{134
Snowball snowball = (Snowball) event.getDamager();136
if(snowball.getShooter() instanceof Player)137
{138
Player player = (Player) event.getEntity();140
player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 2, 1));141
event.setDamage(1);142
}143
}144
}146
@EventHandler147
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event)148
{149
Player player = event.getPlayer();151
if(event.getRightClicked().getType().equals(EntityType.ARMOR_STAND))152
{153
ItemStack item = player.getInventory().getItemInMainHand();155
if(item.getType() == Material.STICK && item.getAmount() > 1 && player.isSneaking())156
{157
ArmorStand armorstand = (ArmorStand) event.getRightClicked();159
armorstand.setArms(true);160
item.setAmount(item.getAmount() - 2);162
event.setCancelled(true);163
}164
}165
}167
@EventHandler168
public void onArmorStandDestroy(EntityDeathEvent event)169
{170
if(event.getEntity() instanceof ArmorStand)171
{172
ArmorStand armorstand = (ArmorStand) event.getEntity();174
if(armorstand.hasArms())175
{176
event.getDrops().add(new ItemStack(Material.STICK, 2));177
}178
}179
}180
}180
\ No newline at end of file
1
package de.typable.minecrafthub.event;3
import java.util.ArrayList;4
import java.util.Arrays;5
import java.util.Collections;6
import java.util.List;8
import org.bukkit.Tag;9
import org.bukkit.block.Block;10
import org.bukkit.block.BlockFace;11
import org.bukkit.block.data.type.Leaves;12
import org.bukkit.event.EventHandler;13
import org.bukkit.event.Listener;14
import org.bukkit.event.block.BlockBreakEvent;15
import org.bukkit.event.block.LeavesDecayEvent;16
import org.bukkit.plugin.Plugin;18
public class LeavesDecayListener implements Listener19
{20
private static final int DELAY = 25;21
private static final List<BlockFace> NEIGHBORS = Arrays.asList(22
BlockFace.UP,23
BlockFace.NORTH,24
BlockFace.EAST,25
BlockFace.SOUTH,26
BlockFace.WEST,27
BlockFace.DOWN28
);30
private Plugin plugin;31
private List<Block> scheduled = new ArrayList<>();33
public LeavesDecayListener(Plugin plugin)34
{35
this.plugin = plugin;36
}38
@EventHandler39
public void onBlockBreak(BlockBreakEvent event)40
{41
onBlockRemove(event.getBlock());42
}44
@EventHandler45
public void onLeavesDecay(LeavesDecayEvent event)46
{47
onBlockRemove(event.getBlock());48
}50
private void onBlockRemove(Block block)51
{52
if(!Tag.LOGS.isTagged(block.getType()) && !Tag.LEAVES.isTagged(block.getType()))53
{54
return;55
}57
Collections.shuffle(NEIGHBORS);59
for(BlockFace face : NEIGHBORS)60
{61
final Block neighbor = block.getRelative(face);63
if(!Tag.LEAVES.isTagged(neighbor.getType()))64
{65
continue;66
}68
Leaves leaves = (Leaves) neighbor.getBlockData();70
if(leaves.isPersistent())71
{72
continue;73
}75
if(scheduled.contains(neighbor))76
{77
continue;78
}80
plugin.getServer().getScheduler().runTaskLater(plugin, () -> decay(neighbor), DELAY);82
scheduled.add(neighbor);83
}84
}86
private boolean decay(Block block)87
{88
scheduled.remove(block);90
if(!block.getWorld().isChunkLoaded(block.getX() >> 4, block.getZ() >> 4))91
{92
return false;93
}95
if(!Tag.LEAVES.isTagged(block.getType()))96
{97
return false;98
}100
Leaves leaves = (Leaves) block.getBlockData();102
if(leaves.isPersistent())103
{104
return false;105
}107
if(leaves.getDistance() < 7)108
{109
return false;110
}112
LeavesDecayEvent event = new LeavesDecayEvent(block);113
plugin.getServer().getPluginManager().callEvent(event);115
if(event.isCancelled())116
{117
return false;118
}120
block.breakNaturally();122
return true;123
}124
}
1
package de.typable.minecrafthub.util;3
import javax.swing.text.Position;5
import org.bukkit.Bukkit;6
import org.bukkit.Location;7
import org.bukkit.Material;8
import org.bukkit.block.Block;9
import org.bukkit.block.BlockFace;10
import org.bukkit.entity.Player;11
import org.bukkit.entity.Entity;12
import org.bukkit.inventory.Inventory;13
import org.bukkit.inventory.ItemStack;14
import org.bukkit.plugin.Plugin;15
import org.bukkit.Location;16
import org.bukkit.GameMode;17
import org.bukkit.plugin.Plugin;19
import de.typable.minecrafthub.constant.Constants;20
import net.md_5.bungee.api.ChatColor;21
import net.md_5.bungee.api.ChatMessageType;22
import net.md_5.bungee.api.chat.TextComponent;25
public class Util26
{27
public static boolean isEmpty(ItemStack item)28
{29
return item == null || item.getType() == Material.AIR;30
}32
public static boolean isType(ItemStack item, Material type)33
{34
return !isEmpty(item) && item.getType() == type;35
}37
public static boolean compare(ItemStack item, ItemStack item2)38
{39
if(item == null || item2 == null)40
{41
return false;42
}44
if(item.getType() != item2.getType())45
{46
return false;47
}49
return true;50
}52
public static boolean isInventoryFull(Inventory inventory, ItemStack result)53
{54
for(ItemStack item : inventory.getContents())55
{56
if(Util.isEmpty(item))57
{58
return false;59
}61
if(result.isSimilar(item))62
{63
if(result.getAmount() + item.getAmount() <= item.getMaxStackSize())64
{65
return false;66
}67
}68
}70
return true;71
}73
public static boolean containsAtLeast(Inventory inventory, ItemStack item, int amount)74
{75
for(int i = 0; i < inventory.getSize(); i++)76
{77
ItemStack current = inventory.getItem(i);79
if(Util.compare(item, current))80
{81
amount -= current.getAmount();83
if(amount <= 0)84
{85
return true;86
}87
}88
}90
return false;91
}93
public static void sendActionMessage(Player player, String message)94
{95
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));96
}98
public static void sendCountdown(Plugin plugin, final String message, final int time, Runnable runnable)99
{100
Bukkit.getScheduler().runTaskTimer(plugin, new Runnable()101
{102
int count = time;104
@Override105
public void run()106
{107
if(count == 0)108
{109
runnable.run();110
return;111
}113
Bukkit.getServer().broadcastMessage(ChatColor.YELLOW + message + " " + count + " sec");115
count--;116
}117
}, 0L, Constants.TICK);118
}120
public static Float convertFacingToYaw(BlockFace face)121
{122
switch(face)123
{124
case NORTH:125
return 0F;126
case EAST:127
return 90F;128
case SOUTH:129
return 180F;130
case WEST:131
return -90F;132
default:133
break;134
}136
return null;137
}139
public static boolean isAir(Material material)140
{141
return material == Material.AIR || material == Material.CAVE_AIR || material == Material.VOID_AIR;142
}144
public static boolean isFarmable(Material material)145
{146
return material == Material.WHEAT || material == Material.CARROTS || material == Material.POTATOES || material == Material.BEETROOTS || material == Material.NETHER_WART || material == Material.COCOA;147
}149
public static boolean isStem(Material material)150
{151
return material == Material.ATTACHED_PUMPKIN_STEM || material == Material.ATTACHED_MELON_STEM;152
}154
public static boolean hasStem(Block block)155
{156
Location blockLocation = block.getLocation();157
Material blockNorth = blockLocation.clone().add(0, 0, -1).getBlock().getType();158
Material blockEast = blockLocation.clone().add(1, 0, 0).getBlock().getType();159
Material blockSouth = blockLocation.clone().add(0, 0, 1).getBlock().getType();160
Material blockWest = blockLocation.clone().add(-1, 0, 0).getBlock().getType();162
return isStem(blockNorth) || isStem(blockEast) || isStem(blockSouth) || isStem(blockWest);163
}165
public static Location calcBlockCenter(final Location location)166
{167
Location centered = location.clone();168
centered.setX(Location.locToBlock(location.getX()) + 0.5);169
centered.setY(Location.locToBlock(location.getY()));170
centered.setZ(Location.locToBlock(location.getZ()) + 0.5);172
return centered;173
}175
public static int calcTravelFee(final Location from, final Location to)176
{177
final Double distance = from.distance(to);178
int fee = (int) Math.floor(distance / (Constants.BLOCKS_PER_CHUNK * Constants.CHUNKS_PER_EMERALD));180
if(fee < Constants.MIN_FEE)181
{182
fee = Constants.MIN_FEE;183
}185
if(fee > Constants.MAX_FEE)186
{187
fee = Constants.MAX_FEE;188
}190
return fee;191
}193
public static boolean travelTo(final Plugin plugin, final Player player, final Location location)194
{195
final int fee = Util.calcTravelFee(player.getLocation(), location);196
final String unit = fee == 1 ? "emerald" : "emeralds";198
if(!payFee(player, Material.EMERALD, fee) && player.getGameMode() == GameMode.SURVIVAL)199
{200
player.sendMessage(ChatColor.RED + "Not enough emeralds to teleport! Travel fee: " + fee + " " + unit);201
return false;202
}204
if(player.getVehicle() != null)205
{206
Entity vehicle = player.getVehicle();207
vehicle.eject();208
player.teleport(location);210
Bukkit.getScheduler().runTaskLater(plugin, () -> {211
vehicle.teleport(location);212
}, 3);214
Bukkit.getScheduler().runTaskLater(plugin, () -> {215
vehicle.addPassenger(player);216
}, 6);217
}218
else219
{220
player.teleport(location);221
}223
return true;224
}226
public static boolean payFee(final Player player, final Material unit, final int amount)227
{228
final ItemStack item = player.getInventory().getItemInMainHand();230
if(item.getType() != unit || item.getAmount() < amount)231
{232
return false;233
}235
item.setAmount(item.getAmount() - amount);237
return true;238
}239
}
1
package poppy;3
import java.io.File;4
import java.io.IOException;5
import java.util.List;6
import java.util.ArrayList;8
import org.bukkit.configuration.file.FileConfiguration;9
import org.bukkit.configuration.file.YamlConfiguration;10
import org.bukkit.entity.Player;11
import org.bukkit.Location;13
import poppy.Utils;15
public class Config16
{17
private File file;18
private FileConfiguration configuration;20
public Config(final String path)21
{22
this.file = new File(path);23
this.configuration = YamlConfiguration.loadConfiguration(this.file);24
}26
public void setHome(final Player player) throws IOException27
{28
final String path = "home." + player.getDisplayName();29
final Location location = Utils.calcBlockCenter(player.getLocation());31
this.configuration.set(path, location);32
this.configuration.save(this.file);33
}35
public Location getHome(final Player player)36
{37
final String path = "home." + player.getDisplayName();39
return this.configuration.getLocation(path);40
}42
public boolean setWarp(final String name, final Location location) throws IOException43
{44
final String path = "warp." + name;46
if(this.configuration.getLocation(path) != null)47
{48
return false;49
}51
this.configuration.set(path, Utils.calcBlockCenter(location));52
this.configuration.save(this.file);54
return true;55
}57
public Location getWarp(final String name)58
{59
final String path = "warp." + name;61
return this.configuration.getLocation(path);62
}64
public List<String> getInfoPages()65
{66
final String path = "info";67
List<String> pages = null;69
try70
{71
this.configuration.load(this.file);72
pages = (List<String>) this.configuration.getList(path);73
}74
catch(Exception ex)75
{76
// ignore77
}79
if(pages == null)80
{81
pages = new ArrayList<>();82
}84
return pages;85
}86
}
1
package poppy;3
import org.bukkit.ChatColor;6
public class Constants7
{8
public static final long TICK = 20;9
public static final int BLOCKS_PER_CHUNK = 16;10
public static final int CHUNKS_PER_EMERALD = 25;11
public static final int MIN_FEE = 1;12
public static final int MAX_FEE = 64;14
public static final class Messages15
{16
public static final String NOT_ENOUGH_PERMISSION = ChatColor.RED + "You don't have enough Permission to perform this command!";17
public static final String FAILED_TO_SAVE_CONFIG_FILE = ChatColor.RED + "Failed to save changes!";18
}19
}
1
package poppy;3
import java.io.File;4
import java.io.IOException;5
import java.net.BindException;6
import java.net.ServerSocket;7
import java.net.Socket;9
import org.bukkit.Bukkit;10
import org.bukkit.ChatColor;11
import org.bukkit.GameMode;12
import org.bukkit.Location;13
import org.bukkit.Material;14
import org.bukkit.World;15
import org.bukkit.WorldCreator;16
import org.bukkit.WorldType;17
import org.bukkit.command.Command;18
import org.bukkit.command.CommandSender;19
import org.bukkit.entity.Player;20
import org.bukkit.inventory.ItemStack;21
import org.bukkit.inventory.meta.SkullMeta;22
import org.bukkit.inventory.meta.BookMeta;23
import org.bukkit.material.Tree;24
import org.bukkit.plugin.Plugin;25
import org.bukkit.plugin.PluginManager;26
import org.bukkit.plugin.java.JavaPlugin;28
import poppy.Constants;29
import poppy.Config;30
import poppy.Utils;31
import poppy.modules.AutoWorkbenchModule;32
import poppy.modules.ChairModule;33
import poppy.modules.DoubleDoorModule;34
import poppy.modules.CommonModule;35
import poppy.modules.LeavesDecayModule;38
public class Main extends JavaPlugin39
{40
private Plugin plugin;41
private Config config;42
private PluginManager pluginManager;44
private DoubleDoorModule doubleDoorModule;45
private ChairModule chairModule;46
private AutoWorkbenchModule autoWorkbenchModule;47
private LeavesDecayModule leavesDecayModule;48
private CommonModule commonModule;50
@Override51
public void onEnable()52
{53
plugin = this;54
config = new Config("config/minecraft-hub.yml");56
pluginManager = Bukkit.getPluginManager();58
doubleDoorModule = new DoubleDoorModule();59
pluginManager.registerEvents(doubleDoorModule, this);61
chairModule = new ChairModule();62
pluginManager.registerEvents(chairModule, this);64
autoWorkbenchModule = new AutoWorkbenchModule();65
pluginManager.registerEvents(autoWorkbenchModule, this);67
leavesDecayModule = new LeavesDecayModule(this);68
pluginManager.registerEvents(leavesDecayModule, this);70
commonModule = new CommonModule();71
pluginManager.registerEvents(commonModule, this);72
}74
@Override75
public void onDisable()76
{77
chairModule.onDisable();78
}80
@Override81
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)82
{83
if(sender instanceof Player)84
{85
Player player = (Player) sender;87
switch(label)88
{89
case "head":90
return setItemAsHead(player, args);91
case "skull":92
return getSkullForName(player, args);93
case "invsee":94
return openInventoryForPlayer(player, args);95
case "info":96
return openInfoBook(player, args);97
case "spawn":98
return teleportToSpawn(player, args);99
case "home":100
return teleportToHome(player, args);101
case "warp":102
return teleportToWarppoint(player, args);103
case "sethome":104
return setHome(player, args);105
case "setwarp":106
return addWarppoint(player, args);107
default:108
return false;109
}110
}112
return true;113
}115
private boolean setItemAsHead(final Player player, final String[] args)116
{117
final ItemStack item = player.getInventory().getItemInMainHand();118
final ItemStack head = player.getInventory().getHelmet();120
player.getInventory().setHelmet(item);121
player.getInventory().setItemInMainHand((new ItemStack(Material.AIR)));123
if(player.getGameMode() == GameMode.SURVIVAL)124
{125
if(head != null)126
{127
player.getInventory().addItem(head);128
}129
}131
return true;132
}134
@SuppressWarnings("deprecation")135
private boolean getSkullForName(final Player player, final String[] args)136
{137
if(!player.isOp())138
{139
player.sendMessage(Constants.Messages.NOT_ENOUGH_PERMISSION);140
return true;141
}143
if(args.length != 1)144
{145
return false;146
}148
final String name = args[0];149
final ItemStack skull = new ItemStack(Material.PLAYER_HEAD);150
final SkullMeta meta = (SkullMeta) skull.getItemMeta();151
meta.setOwner(name);152
skull.setItemMeta(meta);154
player.getInventory().addItem(skull);156
return true;157
}159
private boolean openInventoryForPlayer(final Player player, final String[] args)160
{161
if(args.length == 0)162
{163
return false;164
}166
if(!player.isOp())167
{168
player.sendMessage(Constants.Messages.NOT_ENOUGH_PERMISSION);169
return true;170
}172
final Player target = Bukkit.getPlayer(args[0]);174
if(target == null)175
{176
player.sendMessage(ChatColor.RED + "Player not found!");177
return true;178
}180
player.openInventory(target.getInventory());182
return true;183
}185
private boolean openInfoBook(final Player player, final String[] args)186
{187
final ItemStack book = new ItemStack(Material.WRITTEN_BOOK);188
final BookMeta meta = (BookMeta) book.getItemMeta();189
meta.setTitle("Info");190
meta.setAuthor("Server");191
meta.setPages(config.getInfoPages());192
book.setItemMeta(meta);194
player.openBook(book);196
return true;197
}199
private boolean teleportToSpawn(final Player player, final String[] args)200
{201
final Location location = Bukkit.getWorld("world").getSpawnLocation();203
if(Utils.travelTo(plugin, player, location))204
{205
player.sendMessage(ChatColor.GRAY + "You've been teleported to spawn.");206
}208
return true;209
}211
private boolean teleportToHome(final Player player, final String[] args)212
{213
final Location location = config.getHome(player);215
if(location == null)216
{217
player.sendMessage(ChatColor.RED + "You've don't have a home point.");218
return true;219
}221
if(Utils.travelTo(plugin, player, location))222
{223
player.sendMessage(ChatColor.GRAY + "You've been teleported to your home.");224
}226
return true;227
}229
private boolean teleportToWarppoint(final Player player, final String[] args)230
{231
if(args.length != 1)232
{233
return false;234
}236
final String name = args[0];237
final Location location = config.getWarp(name);239
if(location == null)240
{241
player.sendMessage(ChatColor.RED + "Warp point " + name + " doesn't exist!");242
return true;243
}245
if(Utils.travelTo(plugin, player, location))246
{247
player.sendMessage(ChatColor.GRAY + "You've been teleported to warp point " + name + ".");248
}250
return true;251
}253
private boolean setHome(final Player player, final String[] args)254
{255
try256
{257
config.setHome(player);258
player.sendMessage(ChatColor.YELLOW + "Home point set.");259
}260
catch(Exception ex)261
{262
player.sendMessage(Constants.Messages.FAILED_TO_SAVE_CONFIG_FILE);263
}265
return true;266
}268
private boolean addWarppoint(final Player player, final String[] args)269
{270
if(args.length != 1)271
{272
return false;273
}275
final String name = args[0];277
if(!Utils.payFee(player, Material.COMPASS, 1))278
{279
player.sendMessage(ChatColor.RED + "The fee for creating a warp point is 1 compass!");280
return true;281
}283
try284
{285
if(!config.setWarp(name, player.getLocation()))286
{287
player.sendMessage(ChatColor.RED + "Warp point " + name + " already exists!");288
return true;289
}291
player.sendMessage(ChatColor.YELLOW + "Warp point " + name + " set.");292
}293
catch(Exception ex)294
{295
player.sendMessage(Constants.Messages.FAILED_TO_SAVE_CONFIG_FILE);296
}298
return true;299
}301
}
1
package poppy;3
import org.bukkit.Bukkit;4
import org.bukkit.Location;5
import org.bukkit.Material;6
import org.bukkit.block.Block;7
import org.bukkit.block.BlockFace;8
import org.bukkit.entity.Player;9
import org.bukkit.entity.Entity;10
import org.bukkit.inventory.Inventory;11
import org.bukkit.inventory.ItemStack;12
import org.bukkit.plugin.Plugin;13
import org.bukkit.Location;14
import org.bukkit.GameMode;15
import org.bukkit.plugin.Plugin;17
import net.md_5.bungee.api.ChatColor;18
import net.md_5.bungee.api.ChatMessageType;19
import net.md_5.bungee.api.chat.TextComponent;21
import poppy.Constants;24
public class Utils25
{26
public static boolean isEmpty(ItemStack item)27
{28
return item == null || item.getType() == Material.AIR;29
}31
public static boolean isType(ItemStack item, Material type)32
{33
return !isEmpty(item) && item.getType() == type;34
}36
public static boolean compare(ItemStack item, ItemStack item2)37
{38
if(item == null || item2 == null)39
{40
return false;41
}43
if(item.getType() != item2.getType())44
{45
return false;46
}48
return true;49
}51
public static boolean isInventoryFull(Inventory inventory, ItemStack result)52
{53
for(ItemStack item : inventory.getContents())54
{55
if(Utils.isEmpty(item))56
{57
return false;58
}60
if(result.isSimilar(item))61
{62
if(result.getAmount() + item.getAmount() <= item.getMaxStackSize())63
{64
return false;65
}66
}67
}69
return true;70
}72
public static boolean containsAtLeast(Inventory inventory, ItemStack item, int amount)73
{74
for(int i = 0; i < inventory.getSize(); i++)75
{76
ItemStack current = inventory.getItem(i);78
if(Utils.compare(item, current))79
{80
amount -= current.getAmount();82
if(amount <= 0)83
{84
return true;85
}86
}87
}89
return false;90
}92
public static void sendActionMessage(Player player, String message)93
{94
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));95
}97
public static void sendCountdown(Plugin plugin, final String message, final int time, Runnable runnable)98
{99
Bukkit.getScheduler().runTaskTimer(plugin, new Runnable()100
{101
int count = time;103
@Override104
public void run()105
{106
if(count == 0)107
{108
runnable.run();109
return;110
}112
Bukkit.getServer().broadcastMessage(ChatColor.YELLOW + message + " " + count + " sec");114
count--;115
}116
}, 0L, Constants.TICK);117
}119
public static Float convertFacingToYaw(BlockFace face)120
{121
switch(face)122
{123
case NORTH:124
return 0F;125
case EAST:126
return 90F;127
case SOUTH:128
return 180F;129
case WEST:130
return -90F;131
default:132
break;133
}135
return null;136
}138
public static boolean isAir(Material material)139
{140
return material == Material.AIR || material == Material.CAVE_AIR || material == Material.VOID_AIR;141
}143
public static boolean isFarmable(Material material)144
{145
return material == Material.WHEAT || material == Material.CARROTS || material == Material.POTATOES || material == Material.BEETROOTS || material == Material.NETHER_WART || material == Material.COCOA;146
}148
public static boolean isStem(Material material)149
{150
return material == Material.ATTACHED_PUMPKIN_STEM || material == Material.ATTACHED_MELON_STEM;151
}153
public static boolean hasStem(Block block)154
{155
Location blockLocation = block.getLocation();156
Material blockNorth = blockLocation.clone().add(0, 0, -1).getBlock().getType();157
Material blockEast = blockLocation.clone().add(1, 0, 0).getBlock().getType();158
Material blockSouth = blockLocation.clone().add(0, 0, 1).getBlock().getType();159
Material blockWest = blockLocation.clone().add(-1, 0, 0).getBlock().getType();161
return isStem(blockNorth) || isStem(blockEast) || isStem(blockSouth) || isStem(blockWest);162
}164
public static Location calcBlockCenter(final Location location)165
{166
Location centered = location.clone();167
centered.setX(Location.locToBlock(location.getX()) + 0.5);168
centered.setY(Location.locToBlock(location.getY()));169
centered.setZ(Location.locToBlock(location.getZ()) + 0.5);171
return centered;172
}174
public static int calcTravelFee(final Location from, final Location to)175
{176
final Double distance = from.distance(to);177
int fee = (int) Math.floor(distance / (Constants.BLOCKS_PER_CHUNK * Constants.CHUNKS_PER_EMERALD));179
if(fee < Constants.MIN_FEE)180
{181
fee = Constants.MIN_FEE;182
}184
if(fee > Constants.MAX_FEE)185
{186
fee = Constants.MAX_FEE;187
}189
return fee;190
}192
public static boolean travelTo(final Plugin plugin, final Player player, final Location location)193
{194
final int fee = Utils.calcTravelFee(player.getLocation(), location);195
final String unit = fee == 1 ? "emerald" : "emeralds";197
if(!payFee(player, Material.EMERALD, fee) && player.getGameMode() == GameMode.SURVIVAL)198
{199
player.sendMessage(ChatColor.RED + "Not enough emeralds to teleport! Travel fee: " + fee + " " + unit);200
return false;201
}203
if(player.getVehicle() != null)204
{205
Entity vehicle = player.getVehicle();206
vehicle.eject();207
player.teleport(location);209
Bukkit.getScheduler().runTaskLater(plugin, () -> {210
vehicle.teleport(location);211
}, 3);213
Bukkit.getScheduler().runTaskLater(plugin, () -> {214
vehicle.addPassenger(player);215
}, 6);216
}217
else218
{219
player.teleport(location);220
}222
return true;223
}225
public static boolean payFee(final Player player, final Material unit, final int amount)226
{227
final ItemStack item = player.getInventory().getItemInMainHand();229
if(item.getType() != unit || item.getAmount() < amount)230
{231
return false;232
}234
item.setAmount(item.getAmount() - amount);236
return true;237
}238
}
1
package poppy.modules;3
import java.util.ArrayList;4
import java.util.Iterator;5
import java.util.List;6
import java.util.ListIterator;8
import org.bukkit.Bukkit;9
import org.bukkit.block.Block;10
import org.bukkit.block.BlockFace;11
import org.bukkit.block.Dropper;12
import org.bukkit.entity.Entity;13
import org.bukkit.entity.ItemFrame;14
import org.bukkit.event.EventHandler;15
import org.bukkit.event.Listener;16
import org.bukkit.event.inventory.InventoryMoveItemEvent;17
import org.bukkit.inventory.Inventory;18
import org.bukkit.inventory.ItemStack;19
import org.bukkit.inventory.Recipe;20
import org.bukkit.inventory.ShapedRecipe;21
import org.bukkit.inventory.ShapelessRecipe;23
import poppy.Utils;26
public class AutoWorkbenchModule implements Listener27
{28
@EventHandler29
public void onItemMove(InventoryMoveItemEvent event)30
{31
Inventory source = event.getSource();32
Inventory target = event.getDestination();34
if(source.getHolder() instanceof Dropper)35
{36
Dropper dropper = (Dropper) source.getHolder();38
ItemFrame frame = getItemFrame(dropper.getBlock());40
if(frame == null)41
{42
return;43
}45
ItemStack item = frame.getItem();47
Recipe recipe = getCraftingRecipe(item, source, target);49
if(recipe != null)50
{51
if(recipe instanceof ShapelessRecipe)52
{53
ShapelessRecipe shapless = (ShapelessRecipe) recipe;55
target.addItem(shapless.getResult());56
}58
if(recipe instanceof ShapedRecipe)59
{60
ShapedRecipe shaped = (ShapedRecipe) recipe;62
target.addItem(shaped.getResult());63
}64
}66
event.setCancelled(true);67
}68
}70
private Recipe getCraftingRecipe(ItemStack item, Inventory source, Inventory target)71
{72
if(Utils.isEmpty(item))73
{74
return null;75
}77
Iterator<Recipe> iterator = Bukkit.recipeIterator();79
while(iterator.hasNext())80
{81
Recipe recipe = iterator.next();83
if(Utils.compare(item, recipe.getResult()))84
{85
List<ItemStack> ingredients = null;87
if(recipe instanceof ShapelessRecipe)88
{89
ShapelessRecipe shapless = (ShapelessRecipe) recipe;91
ingredients = shapless.getIngredientList();92
}94
if(recipe instanceof ShapedRecipe)95
{96
ShapedRecipe shaped = (ShapedRecipe) recipe;98
ingredients = new ArrayList<>();100
for(ItemStack value : shaped.getIngredientMap().values())101
{102
if(ingredients.isEmpty())103
{104
if(!Utils.isEmpty(value))105
{106
ingredients.add(value);107
}108
}109
else110
{111
appendUniqueIngredient(ingredients, value);112
}113
}114
}116
if(ingredients == null)117
{118
continue;119
}121
if(!hasIngredients(source, ingredients))122
{123
continue;124
}126
if(Utils.isInventoryFull(target, recipe.getResult()))127
{128
return null;129
}131
removeIngredients(ingredients, source);133
return recipe;134
}135
}137
return null;138
}140
private void removeIngredients(List<ItemStack> ingredients, Inventory inventory)141
{142
for(ItemStack ingredient : ingredients)143
{144
if(Utils.isEmpty(ingredient))145
{146
continue;147
}149
int amount = ingredient.getAmount();151
ListIterator<ItemStack> iterator = inventory.iterator();153
while(iterator.hasNext())154
{155
ItemStack item = iterator.next();157
if(Utils.isEmpty(item))158
{159
continue;160
}162
if(Utils.compare(item, ingredient))163
{164
if(item.getAmount() > amount)165
{166
item.setAmount(item.getAmount() - amount);167
amount = 0;169
break;170
}172
if(item.getAmount() == amount)173
{174
amount = 0;175
inventory.removeItem(item);177
break;178
}180
if(item.getAmount() < amount)181
{182
amount -= item.getAmount();183
inventory.removeItem(item);184
}185
}186
}187
}188
}190
private void appendUniqueIngredient(List<ItemStack> ingredients, ItemStack item)191
{192
for(ItemStack ingredient : ingredients)193
{194
if(Utils.compare(item, ingredient))195
{196
ingredient.setAmount(ingredient.getAmount() + item.getAmount());198
return;199
}200
}202
if(!Utils.isEmpty(item))203
{204
ingredients.add(item);205
}206
}208
private boolean hasIngredients(Inventory inventory, List<ItemStack> ingredients)209
{210
for(ItemStack ingredient : ingredients)211
{212
if(ingredient != null && !Utils.containsAtLeast(inventory, ingredient, ingredient.getAmount()))213
{214
return false;215
}216
}218
return true;219
}221
private ItemFrame getItemFrame(Block block)222
{223
for(Entity entity : block.getWorld().getNearbyEntities(block.getLocation(), 2, 2, 2))224
{225
if(entity instanceof ItemFrame)226
{227
ItemFrame frame = (ItemFrame) entity;229
if(frame.getFacing() == BlockFace.UP)230
{231
if(block.getLocation().add(0.5, 1.03125, 0.5).distance(frame.getLocation()) < 0.2D)232
{233
return frame;234
}235
}236
}237
}239
return null;240
}241
}
1
package poppy.modules;3
import java.util.HashMap;4
import java.util.Map;5
import java.util.Map.Entry;7
import org.bukkit.Location;8
import org.bukkit.Material;9
import org.bukkit.block.Block;10
import org.bukkit.block.data.Bisected.Half;11
import org.bukkit.block.data.type.Stairs;12
import org.bukkit.entity.ArmorStand;13
import org.bukkit.entity.Entity;14
import org.bukkit.entity.EntityType;15
import org.bukkit.entity.Player;16
import org.bukkit.event.EventHandler;17
import org.bukkit.event.Listener;18
import org.bukkit.event.block.Action;19
import org.bukkit.event.block.BlockBreakEvent;20
import org.bukkit.event.player.PlayerInteractEvent;21
import org.bukkit.util.Vector;22
import org.spigotmc.event.entity.EntityDismountEvent;24
import poppy.Utils;27
public class ChairModule implements Listener28
{29
private static final Material[] CHAIR_TYPE = new Material[]30
{31
Material.OAK_STAIRS,32
Material.SPRUCE_STAIRS,33
Material.BIRCH_STAIRS,34
Material.JUNGLE_STAIRS,35
Material.ACACIA_STAIRS,36
Material.DARK_OAK_STAIRS,37
Material.ACACIA_STAIRS,38
Material.CRIMSON_STAIRS,39
Material.WARPED_STAIRS40
};42
private Map<Block, ArmorStand> blockMap = new HashMap<>();44
public void onDisable()45
{46
for(ArmorStand armorStand : blockMap.values())47
{48
armorStand.eject();49
armorStand.remove();50
}51
}53
@EventHandler54
public void onPlayerInteract(PlayerInteractEvent event)55
{56
Player player = event.getPlayer();58
if(event.getAction() == Action.RIGHT_CLICK_BLOCK)59
{60
if(event.getClickedBlock() != null && !event.getPlayer().isSneaking())61
{62
Block block = event.getClickedBlock();64
if(isChair(block.getType()))65
{66
if(!isInRange(block, player))67
{68
return;69
}71
if(blockMap.containsKey(block))72
{73
return;74
}76
if(isCompatible(block))77
{78
ArmorStand armorStand = createMountableChair(block, player);80
if(armorStand == null)81
{82
return;83
}85
event.setCancelled(true);87
blockMap.put(block, armorStand);88
}89
}90
}91
}92
}94
@EventHandler95
public void onEntityDismount(EntityDismountEvent event)96
{97
if(event.getEntity() instanceof Player)98
{99
Entity entity = event.getDismounted();101
if(entity != null && entity instanceof ArmorStand)102
{103
if(blockMap.containsValue(entity))104
{105
for(Entry<Block, ArmorStand> entry : blockMap.entrySet())106
{107
if(entry.getValue() == entity)108
{109
blockMap.remove(entry.getKey());111
break;112
}113
}114
}116
Location location = entity.getLocation();117
location.add(0, 1, 0);119
for(Entity passenger : entity.getPassengers()) {120
location.setPitch(passenger.getLocation().getPitch());121
location.setYaw(passenger.getLocation().getYaw());122
passenger.teleport(location);123
}125
entity.remove();126
}127
}128
}130
@EventHandler131
public void onBlockBreak(BlockBreakEvent event)132
{133
Block block = event.getBlock();135
if(blockMap.containsKey(block))136
{137
ArmorStand armorStand = blockMap.get(block);138
armorStand.eject();140
blockMap.remove(block);141
}142
}144
private boolean isInRange(Block block, Player player)145
{146
return block.getLocation().add(0.5, 0.5, 0.5).distance(player.getLocation()) <= 2;147
}149
private boolean isChair(Material material)150
{151
for(Material chair : CHAIR_TYPE)152
{153
if(material == chair)154
{155
return true;156
}157
}159
return false;160
}162
private boolean isCompatible(Block block)163
{164
Block upperBlock = block.getWorld().getBlockAt(block.getLocation().add(0, 1, 0));166
if(!Utils.isAir(upperBlock.getType()))167
{168
return false;169
}171
Stairs stairs = (Stairs) block.getState().getBlockData();173
if(stairs.getHalf() != Half.BOTTOM)174
{175
return false;176
}178
if(stairs.isWaterlogged())179
{180
return false;181
}183
if(stairs.getShape() == Stairs.Shape.INNER_RIGHT || stairs.getShape() == Stairs.Shape.INNER_LEFT)184
{185
return false;186
}188
return true;189
}191
@SuppressWarnings("deprecation")192
private ArmorStand createMountableChair(Block block, Player player)193
{194
Stairs stairs = (Stairs) block.getState().getBlockData();196
Float yaw = Utils.convertFacingToYaw(stairs.getFacing());198
if(yaw == null)199
{200
return null;201
}203
Location location = block.getLocation().add(0.5, -0.4, 0.5);204
location.setYaw(yaw);206
ArmorStand armorStand = (ArmorStand) block.getWorld().spawnEntity(location, EntityType.ARMOR_STAND);207
armorStand.setPassenger((Entity) player);208
armorStand.setSmall(true);209
armorStand.setGravity(false);210
armorStand.setInvulnerable(true);211
armorStand.setVisible(false);213
return armorStand;214
}215
}
1
package poppy.modules;3
import org.bukkit.ChatColor;4
import org.bukkit.Material;5
import org.bukkit.block.Block;6
import org.bukkit.block.BlockFace;7
import org.bukkit.block.data.Ageable;8
import org.bukkit.block.data.BlockData;9
import org.bukkit.block.data.Directional;10
import org.bukkit.entity.ArmorStand;11
import org.bukkit.entity.EntityType;12
import org.bukkit.entity.Player;13
import org.bukkit.entity.Snowball;14
import org.bukkit.event.EventHandler;15
import org.bukkit.event.Listener;16
import org.bukkit.event.block.Action;17
import org.bukkit.event.entity.EntityDamageByEntityEvent;18
import org.bukkit.event.entity.EntityDeathEvent;19
import org.bukkit.event.entity.EntityExplodeEvent;20
import org.bukkit.event.player.AsyncPlayerChatEvent;21
import org.bukkit.event.player.PlayerInteractAtEntityEvent;22
import org.bukkit.event.player.PlayerInteractEvent;23
import org.bukkit.inventory.EquipmentSlot;24
import org.bukkit.inventory.ItemStack;25
import org.bukkit.potion.PotionEffect;26
import org.bukkit.potion.PotionEffectType;28
import poppy.Utils;31
public class CommonModule implements Listener32
{33
@EventHandler34
public void onPlayerInteract(PlayerInteractEvent event)35
{37
Player player = event.getPlayer();39
if(event.getAction() == Action.PHYSICAL)40
{41
if(event.getClickedBlock() != null)42
{43
if(event.getClickedBlock().getType() == Material.FARMLAND)44
{45
event.setCancelled(true);46
}47
}48
}50
EquipmentSlot equip = event.getHand();52
if(equip.equals(EquipmentSlot.HAND))53
{55
if(event.getAction() == Action.RIGHT_CLICK_BLOCK)56
{57
Block block = event.getClickedBlock();59
if(block == null)60
{61
return;62
}64
Material material = block.getType();66
if(player.isSneaking())67
{68
return;69
}71
BlockData blockdata = block.getBlockData();73
if(blockdata instanceof Ageable)74
{76
Ageable ageable = (Ageable) blockdata;78
if(Utils.isFarmable(material) && ageable.getAge() == ageable.getMaximumAge())79
{81
event.setCancelled(true);83
if(blockdata instanceof Directional)84
{85
Directional directional = (Directional) blockdata;86
BlockFace blockface = directional.getFacing();88
block.breakNaturally(player.getItemInUse());89
block.setType(material);90
directional = (Directional) blockdata;91
ageable.setAge(0);92
directional.setFacing(blockface);93
block.setBlockData(blockdata);94
}95
else96
{98
block.breakNaturally(player.getItemInUse());99
block.setType(material);100
}101
}102
}104
if(material == Material.MELON && Utils.hasStem(block) || material == Material.PUMPKIN && Utils.hasStem(block))105
{106
block.breakNaturally(player.getInventory().getItemInMainHand());107
}108
}109
}110
}112
@EventHandler113
public void onEntityExplode(EntityExplodeEvent event)114
{115
if(event.getEntityType() == EntityType.CREEPER)116
{117
event.blockList().clear();118
}119
}121
@EventHandler122
public void onChat(AsyncPlayerChatEvent event)123
{124
String message = ChatColor.GRAY + event.getMessage().replace("%", "%%");125
String format = ChatColor.WHITE + event.getPlayer().getName() + ": " + message;126
event.setFormat(format);127
}129
@EventHandler130
public void onEntityHit(EntityDamageByEntityEvent event)131
{132
if(event.getDamager() instanceof Snowball)133
{134
Snowball snowball = (Snowball) event.getDamager();136
if(snowball.getShooter() instanceof Player)137
{138
Player player = (Player) event.getEntity();140
player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 2, 1));141
event.setDamage(1);142
}143
}144
}146
@EventHandler147
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event)148
{149
Player player = event.getPlayer();151
if(event.getRightClicked().getType().equals(EntityType.ARMOR_STAND))152
{153
ItemStack item = player.getInventory().getItemInMainHand();155
if(item.getType() == Material.STICK && item.getAmount() > 1 && player.isSneaking())156
{157
ArmorStand armorstand = (ArmorStand) event.getRightClicked();159
armorstand.setArms(true);160
item.setAmount(item.getAmount() - 2);162
event.setCancelled(true);163
}164
}165
}167
@EventHandler168
public void onArmorStandDestroy(EntityDeathEvent event)169
{170
if(event.getEntity() instanceof ArmorStand)171
{172
ArmorStand armorstand = (ArmorStand) event.getEntity();174
if(armorstand.hasArms())175
{176
event.getDrops().add(new ItemStack(Material.STICK, 2));177
}178
}179
}180
}180
\ No newline at end of file
1
package poppy.modules;3
import org.bukkit.Location;4
import org.bukkit.Material;5
import org.bukkit.Sound;6
import org.bukkit.block.Block;7
import org.bukkit.block.BlockState;8
import org.bukkit.block.data.type.Door;9
import org.bukkit.entity.Player;10
import org.bukkit.event.EventHandler;11
import org.bukkit.event.Listener;12
import org.bukkit.event.block.Action;13
import org.bukkit.event.player.PlayerInteractEvent;15
import poppy.Utils;18
public class DoubleDoorModule implements Listener19
{20
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 };22
@EventHandler23
public void onPlayerInteract(PlayerInteractEvent event)24
{25
Player player = event.getPlayer();27
if(event.getAction() == Action.RIGHT_CLICK_BLOCK)28
{29
if(event.getClickedBlock() != null)30
{31
Block block = event.getClickedBlock();33
if(isDoor(block.getType()))34
{35
if(player.isSneaking())36
{37
if(!Utils.isEmpty(player.getInventory().getItemInMainHand()))38
{39
return;40
}42
if(!Utils.isEmpty(player.getInventory().getItemInOffHand()))43
{44
return;45
}46
}48
BlockState state = block.getState();49
Door door = (Door) state.getBlockData();51
Location location = getOppositeDoor(door, block.getLocation());53
if(location == null)54
{55
return;56
}58
Block opposite = block.getWorld().getBlockAt(location);60
if(block.getType() != opposite.getType())61
{62
return;63
}65
BlockState stateOpposite = opposite.getState();66
Door doorOpposite = (Door) stateOpposite.getBlockData();68
if(isCompatible(door, doorOpposite))69
{70
if(door.isOpen() && doorOpposite.isOpen())71
{72
doorOpposite.setOpen(false);74
stateOpposite.setBlockData(doorOpposite);75
stateOpposite.update();77
player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_DOOR_CLOSE, 1F, 1F);78
}80
if(!door.isOpen() && !doorOpposite.isOpen())81
{82
doorOpposite.setOpen(true);84
stateOpposite.setBlockData(doorOpposite);85
stateOpposite.update();87
player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_DOOR_OPEN, 1F, 1F);88
}89
}90
}91
}92
}93
}95
private boolean isDoor(Material material)96
{97
for(Material door : DOOR_TYPE)98
{99
if(material == door)100
{101
return true;102
}103
}105
return false;106
}108
private Location getOppositeDoor(Door door, Location location)109
{110
int invert = door.getHinge() == Door.Hinge.LEFT ? 1 : -1;112
switch(door.getFacing())113
{114
case NORTH:115
location.add(1 * invert, 0, 0);116
break;117
case EAST:118
location.add(0, 0, 1 * invert);119
break;120
case SOUTH:121
location.add(-1 * invert, 0, 0);122
break;123
case WEST:124
location.add(0, 0, -1 * invert);125
break;126
default:127
return null;128
}130
return location;131
}133
private boolean isCompatible(Door door, Door doorItem)134
{135
if(door.getFacing() != doorItem.getFacing())136
{137
return false;138
}140
if(door.getHalf() != doorItem.getHalf())141
{142
return false;143
}145
if(door.getHinge() == doorItem.getHinge())146
{147
return false;148
}150
return true;151
}152
}
1
package poppy.modules;3
import java.util.ArrayList;4
import java.util.Arrays;5
import java.util.Collections;6
import java.util.List;8
import org.bukkit.Tag;9
import org.bukkit.block.Block;10
import org.bukkit.block.BlockFace;11
import org.bukkit.block.data.type.Leaves;12
import org.bukkit.event.EventHandler;13
import org.bukkit.event.Listener;14
import org.bukkit.event.block.BlockBreakEvent;15
import org.bukkit.event.block.LeavesDecayEvent;16
import org.bukkit.plugin.Plugin;18
public class LeavesDecayModule implements Listener19
{20
private static final int DELAY = 25;21
private static final List<BlockFace> NEIGHBORS = Arrays.asList(22
BlockFace.UP,23
BlockFace.NORTH,24
BlockFace.EAST,25
BlockFace.SOUTH,26
BlockFace.WEST,27
BlockFace.DOWN28
);30
private Plugin plugin;31
private List<Block> scheduled = new ArrayList<>();33
public LeavesDecayModule(Plugin plugin)34
{35
this.plugin = plugin;36
}38
@EventHandler39
public void onBlockBreak(BlockBreakEvent event)40
{41
onBlockRemove(event.getBlock());42
}44
@EventHandler45
public void onLeavesDecay(LeavesDecayEvent event)46
{47
onBlockRemove(event.getBlock());48
}50
private void onBlockRemove(Block block)51
{52
if(!Tag.LOGS.isTagged(block.getType()) && !Tag.LEAVES.isTagged(block.getType()))53
{54
return;55
}57
Collections.shuffle(NEIGHBORS);59
for(BlockFace face : NEIGHBORS)60
{61
final Block neighbor = block.getRelative(face);63
if(!Tag.LEAVES.isTagged(neighbor.getType()))64
{65
continue;66
}68
Leaves leaves = (Leaves) neighbor.getBlockData();70
if(leaves.isPersistent())71
{72
continue;73
}75
if(scheduled.contains(neighbor))76
{77
continue;78
}80
plugin.getServer().getScheduler().runTaskLater(plugin, () -> decay(neighbor), DELAY);82
scheduled.add(neighbor);83
}84
}86
private boolean decay(Block block)87
{88
scheduled.remove(block);90
if(!block.getWorld().isChunkLoaded(block.getX() >> 4, block.getZ() >> 4))91
{92
return false;93
}95
if(!Tag.LEAVES.isTagged(block.getType()))96
{97
return false;98
}100
Leaves leaves = (Leaves) block.getBlockData();102
if(leaves.isPersistent())103
{104
return false;105
}107
if(leaves.getDistance() < 7)108
{109
return false;110
}112
LeavesDecayEvent event = new LeavesDecayEvent(block);113
plugin.getServer().getPluginManager().callEvent(event);115
if(event.isCancelled())116
{117
return false;118
}120
block.breakNaturally();122
return true;123
}124
}