diff --git a/src/main/java/com/nitnelave/CreeperHeal/block/CreeperBanner.java b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperBanner.java index 1351eb2..7d46ed6 100644 --- a/src/main/java/com/nitnelave/CreeperHeal/block/CreeperBanner.java +++ b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperBanner.java @@ -1,39 +1,43 @@ package com.nitnelave.CreeperHeal.block; +import com.nitnelave.CreeperHeal.config.CreeperConfig; +import org.bukkit.Bukkit; import org.bukkit.block.Banner; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BannerMeta; /** * Banner implementation of CreeperBlock. - * + * * @author drexplosionpd - * */ public class CreeperBanner extends CreeperBlock { - + /* * Constructor. */ - protected CreeperBanner(Banner banner) + CreeperBanner(Banner banner) { super(banner); } /* - * (non-Javadoc) - * - * @see com.nitnelave.CreeperHeal.block.CreeperBlock#update() + * @see com.nitnelave.CreeperHeal.block.Replaceable#drop(boolean) */ @Override - public void update() + public boolean drop(boolean forced) { - super.update(); - Banner state = (Banner) getBlock().getState(); - Banner banner = (Banner) blockState; - state.setBaseColor(banner.getBaseColor()); - state.setPatterns(banner.getPatterns()); - - state.setData(banner.getData()); - state.update(true); + if (forced || CreeperConfig.shouldDrop()) + { + ItemStack itemStack = new ItemStack(blockState.getType()); + BannerMeta bannerMeta = ((BannerMeta) Bukkit.getItemFactory().getItemMeta(blockState.getType())); + bannerMeta.setPatterns(((Banner) blockState).getPatterns()); + itemStack.setItemMeta(bannerMeta); + blockState.getWorld().dropItemNaturally(blockState.getLocation().add(0.5, 0.5, 0.5), itemStack); + return true; + } + return false; } + } diff --git a/src/main/java/com/nitnelave/CreeperHeal/block/CreeperBlock.java b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperBlock.java index 8f74044..2cfd413 100644 --- a/src/main/java/com/nitnelave/CreeperHeal/block/CreeperBlock.java +++ b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperBlock.java @@ -7,13 +7,25 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.block.*; +import org.bukkit.block.Banner; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.block.Jukebox; +import org.bukkit.block.NoteBlock; +import org.bukkit.block.ShulkerBox; +import org.bukkit.block.Sign; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.material.Attachable; import org.bukkit.material.MaterialData; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.Set; /** * Represents a block that can be replaced. Every special type of block derives @@ -28,7 +40,7 @@ public class CreeperBlock implements Replaceable /* * Blocks a player can breathe in and that are replaced by other blocks. */ - protected final static Set EMPTY_BLOCKS = + private final static Set EMPTY_BLOCKS = CreeperUtils.createFinalHashSet(Material.AIR, Material.WATER, Material.STATIONARY_WATER, Material.LAVA, Material.STATIONARY_LAVA, Material.FIRE, Material.SNOW); /* @@ -72,7 +84,7 @@ public class CreeperBlock implements Replaceable /* * The block represented. */ - protected BlockState blockState; + BlockState blockState; /** * Create a new CreeperBlock of the right class. Factory method that should @@ -85,8 +97,12 @@ public class CreeperBlock implements Replaceable public static CreeperBlock newBlock(BlockState state) { CreeperConfig.getWorld(state.getWorld()).getReplacement(state); + if (state instanceof ShulkerBox) + return new CreeperShulkerBox((ShulkerBox) state); if (state instanceof InventoryHolder) return new CreeperContainer(state); + if (state instanceof Jukebox) + return new CreeperJukebox((Jukebox) state); if (state.getType().hasGravity()) return new CreeperPhysicsBlock(state); switch (state.getType()) @@ -149,7 +165,7 @@ public static CreeperBlock newBlock(BlockState state) /* * The constructor. */ - protected CreeperBlock(BlockState blockState) + CreeperBlock(BlockState blockState) { this.blockState = blockState; } @@ -158,7 +174,7 @@ protected CreeperBlock(BlockState blockState) * Get whether the block is empty, i.e. if a player can breathe inside it * and if it can be replaced by other blocks (snow, water...) */ - protected static boolean isEmpty(Material type) + static boolean isEmpty(Material type) { return EMPTY_BLOCKS.contains(type); } @@ -222,7 +238,7 @@ public static boolean isSolid(Material type) } /** - * Get whether blocks of a type are dependent on another block . + * Get whether blocks of a type are dependent on another block. * * @param type * The type of the block. @@ -238,6 +254,7 @@ public static boolean isDependent(Material type) */ public void update() { + getLocation().getChunk().load(); blockState.update(true, false); getWorld().playSound(getLocation(), CreeperConfig.getSound(), CreeperConfig.getInt(CfgVal.SOUND_VOLUME) / 10F, random.nextFloat() * 2); } @@ -267,12 +284,14 @@ public boolean drop(boolean forced) { if (forced || CreeperConfig.shouldDrop()) { - Location loc = blockState.getBlock().getLocation(); - World w = loc.getWorld(); - + BlockState current = blockState.getBlock().getState(); + blockState.update(true, false); Collection drop = blockState.getBlock().getDrops(); - for (ItemStack s : drop) - w.dropItemNaturally(loc, s); + current.update(true, false); + Location location = blockState.getLocation().add(0.5, 0.5, 0.5); + World world = blockState.getWorld(); + for (ItemStack itemStack : drop) + world.dropItemNaturally(location, itemStack); return true; } return false; @@ -290,7 +309,7 @@ public final boolean replace(boolean shouldDrop) return true; if (!shouldDrop && isDependent(getType()) - && isEmpty(getBlock().getRelative(getAttachingFace()).getType())) + && isEmpty(getBlock().getRelative(getAttachingFace()).getType())) return false; update(); @@ -311,7 +330,7 @@ public static boolean isSolid(Block block) return block.getType().isSolid(); } - protected boolean checkForDrop() + boolean checkForDrop() { Block block = blockState.getBlock(); @@ -323,7 +342,7 @@ protected boolean checkForDrop() drop(true); return true; } else if (CreeperConfig.getBool(CfgVal.OVERWRITE_BLOCKS) && !isEmpty(type) - && CreeperConfig.getBool(CfgVal.DROP_DESTROYED_BLOCKS)) + && CreeperConfig.getBool(CfgVal.DROP_DESTROYED_BLOCKS)) { CreeperBlock b = CreeperBlock.newBlock(block.getState()); if (b == null) @@ -418,7 +437,7 @@ void record(Collection checked) checked.add(new ShortLocation(getLocation())); } - protected T castData(BlockState b, Class c) + T castData(BlockState b, Class c) { MaterialData data = b.getData(); if (c.isInstance(data)) diff --git a/src/main/java/com/nitnelave/CreeperHeal/block/CreeperJukebox.java b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperJukebox.java new file mode 100644 index 0000000..f1874ff --- /dev/null +++ b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperJukebox.java @@ -0,0 +1,85 @@ +package com.nitnelave.CreeperHeal.block; + +import com.nitnelave.CreeperHeal.CreeperHeal; +import com.nitnelave.CreeperHeal.config.CreeperConfig; +import com.nitnelave.CreeperHeal.config.WCfgVal; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Jukebox; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.ItemSpawnEvent; + +/** + * Jukebox implementation of CreeperBlock. + * + * @author Jikoo + */ +public class CreeperJukebox extends CreeperBlock +{ + + /* + * Constructor. + */ + CreeperJukebox(Jukebox blockState) + { + super(blockState); + + } + + /* + * In Minecraft 1.13, discs inserted into jukeboxes preserve item meta. Craftbukkit does not properly handle this. + * The only way to "prevent" the disc dropping is to remove it immediately after it spawns. + * + * @see com.nitnelave.CreeperHeal.block.Replaceable#remove() + */ + @Override + public void remove() + { + Jukebox jukebox = ((Jukebox) blockState); + + Listener recordDropListener = null; + + if (!CreeperConfig.getWorld(getWorld()).getBool(WCfgVal.DROP_CHEST_CONTENTS)) + { + recordDropListener = new RecordDropListener(jukebox.getPlaying()); + Bukkit.getPluginManager().registerEvents(recordDropListener, CreeperHeal.getInstance()); + } + + super.remove(); + + if (recordDropListener != null) { + HandlerList.unregisterAll(recordDropListener); + } + } + + /* + * @see com.nitnelave.CreeperHeal.block.Replaceable#update() + */ + @Override + public void update() + { + if (CreeperConfig.getWorld(getWorld()).getBool(WCfgVal.DROP_CHEST_CONTENTS)) + blockState.getBlock().setType(Material.JUKEBOX); + else + super.update(); + } + + private class RecordDropListener implements Listener { + + private final Material record; + + private RecordDropListener(Material record) { + this.record = record; + } + + @EventHandler(ignoreCancelled = true) + public void onItemSpawn(ItemSpawnEvent event) { + if (event.getEntity().getItemStack().getType() == record) { + event.setCancelled(true); + } + } + } + +} diff --git a/src/main/java/com/nitnelave/CreeperHeal/block/CreeperMultiblock.java b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperMultiblock.java index d90794d..c2aaae5 100644 --- a/src/main/java/com/nitnelave/CreeperHeal/block/CreeperMultiblock.java +++ b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperMultiblock.java @@ -38,18 +38,18 @@ public void update() @Override protected boolean checkForDrop() { - if (checkForDropHelper(getBlock())) + if (checkForDependentDrop(getBlock())) return true; for (BlockState dependent : dependents) - if (checkForDropHelper(dependent.getBlock())) + if (checkForDependentDrop(dependent.getBlock())) return true; return false; } - private boolean checkForDropHelper(Block block) + private boolean checkForDependentDrop(Block block) { Material type = block.getType(); diff --git a/src/main/java/com/nitnelave/CreeperHeal/block/CreeperShulkerBox.java b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperShulkerBox.java new file mode 100644 index 0000000..7e7841e --- /dev/null +++ b/src/main/java/com/nitnelave/CreeperHeal/block/CreeperShulkerBox.java @@ -0,0 +1,62 @@ +package com.nitnelave.CreeperHeal.block; + +import com.nitnelave.CreeperHeal.config.CreeperConfig; +import com.nitnelave.CreeperHeal.config.WCfgVal; +import org.bukkit.Location; +import org.bukkit.block.BlockState; +import org.bukkit.block.ShulkerBox; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + +/** + * Shulker box implementation of CreeperBlock. + * + * @author Jikoo + */ +public class CreeperShulkerBox extends CreeperBlock +{ + + private final ItemStack[] contents; + + CreeperShulkerBox(ShulkerBox blockState) + { + super(blockState); + this.contents = blockState.getInventory().getContents(); + } + + /* + * @see com.nitnelave.CreeperHeal.block.Replaceable#drop(boolean) + */ + @Override + public boolean drop(boolean forced) + { + Location location = blockState.getLocation().add(0.5, 0.5, 0.5); + if (forced || CreeperConfig.shouldDrop()) + { + // Drop shulker with contents inside + ItemStack itemStack = new ItemStack(blockState.getType()); + blockState.getWorld().dropItemNaturally(location, itemStack); + } + // Always drop container contents + for (ItemStack itemStack : contents) { + if (itemStack == null) + continue; + blockState.getWorld().dropItemNaturally(location, itemStack); + } + return false; + } + + @Override + public void update() + { + super.update(); + + if (CreeperConfig.getWorld(getWorld()).getBool(WCfgVal.DROP_CHEST_CONTENTS)) + return; + + BlockState newState = blockState.getBlock().getState(); + if (newState instanceof InventoryHolder) + ((InventoryHolder) newState).getInventory().setContents(contents); + } + +}