Skip to content

Commit

Permalink
Correctly drop own BlockState drops when breaking (#63)
Browse files Browse the repository at this point in the history
blocks: Fix drop of own BlockState when breaking
  • Loading branch information
Jikoo authored and nitnelave committed Feb 25, 2019
1 parent ae039cf commit f0388aa
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 35 deletions.
36 changes: 20 additions & 16 deletions src/main/java/com/nitnelave/CreeperHeal/block/CreeperBanner.java
Original file line number Diff line number Diff line change
@@ -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;
}

}
51 changes: 35 additions & 16 deletions src/main/java/com/nitnelave/CreeperHeal/block/CreeperBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<Material> EMPTY_BLOCKS =
private final static Set<Material> EMPTY_BLOCKS =
CreeperUtils.createFinalHashSet(Material.AIR, Material.WATER, Material.STATIONARY_WATER,
Material.LAVA, Material.STATIONARY_LAVA, Material.FIRE, Material.SNOW);
/*
Expand Down Expand Up @@ -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
Expand All @@ -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())
Expand Down Expand Up @@ -149,7 +165,7 @@ public static CreeperBlock newBlock(BlockState state)
/*
* The constructor.
*/
protected CreeperBlock(BlockState blockState)
CreeperBlock(BlockState blockState)
{
this.blockState = blockState;
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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.
Expand All @@ -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);
}
Expand Down Expand Up @@ -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<ItemStack> 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;
Expand All @@ -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();
Expand All @@ -311,7 +330,7 @@ public static boolean isSolid(Block block)
return block.getType().isSolid();
}

protected boolean checkForDrop()
boolean checkForDrop()
{

Block block = blockState.getBlock();
Expand All @@ -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)
Expand Down Expand Up @@ -418,7 +437,7 @@ void record(Collection<ShortLocation> checked)
checked.add(new ShortLocation(getLocation()));
}

protected <T extends MaterialData> T castData(BlockState b, Class<T> c)
<T extends MaterialData> T castData(BlockState b, Class<T> c)
{
MaterialData data = b.getData();
if (c.isInstance(data))
Expand Down
85 changes: 85 additions & 0 deletions src/main/java/com/nitnelave/CreeperHeal/block/CreeperJukebox.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}

}

0 comments on commit f0388aa

Please sign in to comment.