├── .gitignore ├── README.md ├── src └── main │ ├── resources │ ├── plugin.yml │ └── config.yml │ └── java │ └── me │ └── petersoj │ ├── FallingBlocks.java │ ├── controller │ └── BlocksController.java │ ├── listener │ └── Listeners.java │ └── explosion │ └── Explosion.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | target/ 3 | .project 4 | .settings 5 | .classpath 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Regen Terrain and Falling Blocks # 2 | This plugin adds regeneration of terrain and falling blocks after an explosion. 3 | -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | author: Petersoj 2 | name: FallingBlocks 3 | version: 1.5 4 | main: me.petersoj.FallingBlocks 5 | description: Adds Falling blocks and regeneration when an explosion happens -------------------------------------------------------------------------------- /src/main/java/me/petersoj/FallingBlocks.java: -------------------------------------------------------------------------------- 1 | package me.petersoj; 2 | 3 | import org.bukkit.plugin.java.JavaPlugin; 4 | 5 | import me.petersoj.controller.BlocksController; 6 | import me.petersoj.listener.Listeners; 7 | 8 | public class FallingBlocks extends JavaPlugin { 9 | 10 | private BlocksController blocksController; 11 | private Listeners listeners; 12 | 13 | @Override 14 | public void onEnable() { 15 | this.blocksController = new BlocksController(this); 16 | this.listeners = new Listeners(this); 17 | 18 | this.blocksController.start(); 19 | this.listeners.start(); 20 | } 21 | 22 | public BlocksController getBlocksController() { 23 | return blocksController; 24 | } 25 | 26 | public Listeners getListeners() { 27 | return listeners; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # This option enables or disables the particles as the terrain is being regenerated. 2 | # Use true or false. 3 | particles: true 4 | 5 | # This option sets the delay time before the blocks start spawning in seconds. 6 | delay: 5 7 | 8 | # This option sets the respawn interval/rate of the blocks in ticks. 9 | interval: 5 10 | 11 | # This option sets percentage chance that a falling block will spawn. 12 | spawn chance: 25 13 | 14 | # This option sets whether to add randomness to the respawn rate. 15 | # (aka not constant and more jittery) 16 | # Use true or false. 17 | random respawn rate: true 18 | 19 | # This option sets whether the explosion drops items or not. 20 | # Use true or false. 21 | drops: false 22 | 23 | # Option to enable regeneration of the exploded blocks. 24 | regen terrain: true 25 | 26 | # Option to enable falling blocks when an explosion happens. 27 | # Use true or false. 28 | falling blocks: true -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | me.petersoj 5 | FallingBlocks 6 | 1.5 7 | 8 | 9 | 10 | org.spigotmc 11 | spigot 12 | 1.11.2-R0.1-SNAPSHOT 13 | provided 14 | 15 | 16 | 17 | 18 | 19 | 20 | org.apache.maven.plugins 21 | maven-compiler-plugin 22 | 3.6.1 23 | 24 | 1.8 25 | 1.8 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/me/petersoj/controller/BlocksController.java: -------------------------------------------------------------------------------- 1 | package me.petersoj.controller; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.bukkit.Location; 7 | import org.bukkit.block.Block; 8 | import org.bukkit.configuration.file.FileConfiguration; 9 | 10 | import me.petersoj.FallingBlocks; 11 | import me.petersoj.explosion.Explosion; 12 | 13 | public class BlocksController { 14 | 15 | private FallingBlocks plugin; 16 | 17 | private ArrayList explosions; 18 | private boolean particles; 19 | private int delay; 20 | private int interval; 21 | private int spawnChance; 22 | private boolean randomRespawn; 23 | private boolean drops; 24 | private boolean regenTerrain; 25 | private boolean spawnFallingBlocks; 26 | 27 | public BlocksController(FallingBlocks plugin){ 28 | this.plugin = plugin; 29 | this.explosions = new ArrayList(); 30 | } 31 | 32 | public void start(){ 33 | 34 | plugin.saveDefaultConfig(); // Copys default config if it does not exist 35 | 36 | FileConfiguration config = plugin.getConfig(); 37 | 38 | this.particles = config.getBoolean("particles", true); 39 | this.delay = config.getInt("delay", 5); 40 | this.interval = config.getInt("interval", 20); 41 | this.spawnChance = config.getInt("spawn chance", 30); 42 | this.randomRespawn = config.getBoolean("random respawn rate", true); 43 | this.drops = config.getBoolean("drops", true); 44 | this.regenTerrain = config.getBoolean("regen terrain", true); 45 | this.spawnFallingBlocks = config.getBoolean("falling blocks", true); 46 | } 47 | 48 | public void createExplosion(List blockList, Location center){ 49 | Explosion explosion = new Explosion(this, blockList, center); 50 | explosions.add(explosion); 51 | explosion.explode(particles, delay, interval, spawnChance, randomRespawn, regenTerrain, spawnFallingBlocks); 52 | } 53 | 54 | public FallingBlocks getPlugin(){ 55 | return plugin; 56 | } 57 | 58 | public ArrayList getExplosions(){ 59 | return explosions; 60 | } 61 | 62 | public boolean doDrops(){ 63 | return drops; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/me/petersoj/listener/Listeners.java: -------------------------------------------------------------------------------- 1 | package me.petersoj.listener; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.Effect; 5 | import org.bukkit.block.Block; 6 | import org.bukkit.entity.FallingBlock; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.EventPriority; 9 | import org.bukkit.event.Listener; 10 | import org.bukkit.event.block.BlockExplodeEvent; 11 | import org.bukkit.event.entity.EntityChangeBlockEvent; 12 | import org.bukkit.event.entity.EntityExplodeEvent; 13 | 14 | import me.petersoj.FallingBlocks; 15 | import me.petersoj.controller.BlocksController; 16 | import me.petersoj.explosion.Explosion; 17 | 18 | public class Listeners implements Listener { 19 | 20 | private FallingBlocks plugin; 21 | 22 | public Listeners(FallingBlocks plugin){ 23 | this.plugin = plugin; 24 | } 25 | 26 | public void start(){ 27 | Bukkit.getPluginManager().registerEvents(this, plugin); 28 | } 29 | 30 | @EventHandler(priority=EventPriority.HIGHEST, ignoreCancelled = true) // Happens very last to check if cancelled 31 | public void onEntityExplode(EntityExplodeEvent e){ 32 | BlocksController controller = plugin.getBlocksController(); 33 | if(!controller.doDrops()){ 34 | e.setYield(0); 35 | } 36 | 37 | controller.createExplosion(e.blockList(), e.getLocation()); 38 | } 39 | 40 | @EventHandler(priority=EventPriority.HIGHEST, ignoreCancelled = true) // Happens very last to check if cancelled 41 | public void onBlockExplode(BlockExplodeEvent e){ 42 | BlocksController controller = plugin.getBlocksController(); 43 | if(!controller.doDrops()){ 44 | e.setYield(0); 45 | } 46 | 47 | controller.createExplosion(e.blockList(), e.getBlock().getLocation()); 48 | } 49 | 50 | @SuppressWarnings("deprecation") 51 | @EventHandler(priority=EventPriority.HIGHEST, ignoreCancelled = true) // Happens very last to check if cancelled 52 | public void onEntityChangeBlock(EntityChangeBlockEvent e){ 53 | Block block = e.getBlock(); 54 | 55 | for(Explosion explosion : plugin.getBlocksController().getExplosions()){ 56 | if(explosion.getFallingBlocks().contains(e.getEntity())){ 57 | explosion.getFallingBlocks().remove(e.getEntity()); 58 | block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, ((FallingBlock)e.getEntity()).getBlockId()); 59 | e.setCancelled(true); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/me/petersoj/explosion/Explosion.java: -------------------------------------------------------------------------------- 1 | package me.petersoj.explosion; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Comparator; 6 | import java.util.List; 7 | import java.util.concurrent.ThreadLocalRandom; 8 | 9 | import org.bukkit.Effect; 10 | import org.bukkit.Location; 11 | import org.bukkit.Material; 12 | import org.bukkit.block.Block; 13 | import org.bukkit.block.BlockState; 14 | import org.bukkit.entity.FallingBlock; 15 | import org.bukkit.scheduler.BukkitRunnable; 16 | import org.bukkit.util.Vector; 17 | 18 | import me.petersoj.controller.BlocksController; 19 | 20 | public class Explosion { 21 | 22 | private BlocksController blockController; 23 | 24 | private ArrayList explodedBlocks; 25 | private ArrayList dropTypeBlocks; 26 | private ArrayList fallingBlocks; 27 | private Location center; 28 | private double radius = 1.0; 29 | 30 | public Explosion(BlocksController blockController, List blockList, Location center){ 31 | this.blockController = blockController; 32 | 33 | this.explodedBlocks = new ArrayList(); 34 | this.dropTypeBlocks = new ArrayList(); 35 | this.fallingBlocks = new ArrayList(); 36 | this.center = center; 37 | 38 | this.setupExplosion(blockList); 39 | } 40 | 41 | // Adds blockStates to list and then sorts 42 | private void setupExplosion(List blockList){ 43 | double maxRadius = 1; 44 | 45 | for(int i = 0; i < blockList.size(); i++){ 46 | Block block = blockList.get(i); 47 | 48 | BlockState state = block.getState(); 49 | 50 | double distanceSquared = state.getLocation().distanceSquared(center); 51 | if(distanceSquared > maxRadius){ 52 | maxRadius = distanceSquared; 53 | } 54 | 55 | radius = Math.sqrt(maxRadius); 56 | 57 | block.setType(Material.AIR, false); 58 | 59 | explodedBlocks.add(state); 60 | } 61 | 62 | // Sort exploded blocks for Y values 63 | Collections.sort(explodedBlocks, new Comparator() { 64 | 65 | // Compares the block Y's cause that's all we care about 66 | public int compare(BlockState blockState1, BlockState blockState2) { 67 | return Integer.compare(blockState1.getY(), blockState2.getY()); 68 | } 69 | }); 70 | } 71 | 72 | public void explode(boolean particles, int delay, int interval,int spawnChance, boolean randomRespawn, boolean regenTerrain, boolean spawnFallingBlocks){ 73 | if(spawnFallingBlocks){ 74 | createFallingBlocks(spawnChance); 75 | } 76 | if(regenTerrain){ 77 | startBlockRegen(particles, delay, interval, randomRespawn); 78 | } 79 | } 80 | 81 | private void createFallingBlocks(int spawnChance){ 82 | ThreadLocalRandom random = ThreadLocalRandom.current(); 83 | 84 | for(BlockState blockState : explodedBlocks){ 85 | if(blockState.getType().isBlock() && random.nextInt(1, 101) <= spawnChance){ 86 | Location fallingBlockLoc = blockState.getLocation(); 87 | 88 | FallingBlock fallingBlock = (FallingBlock) fallingBlockLoc.getWorld().spawnFallingBlock(fallingBlockLoc, blockState.getData()); 89 | fallingBlock.setVelocity(getNewFallingBlockVector(fallingBlockLoc)); 90 | fallingBlock.setDropItem(false); 91 | fallingBlock.setHurtEntities(false); 92 | fallingBlock.setInvulnerable(true); 93 | fallingBlock.setSilent(true); 94 | 95 | fallingBlocks.add(fallingBlock); 96 | } 97 | } 98 | } 99 | 100 | private void startBlockRegen(boolean particles, int delay, int interval, boolean randomSpawn){ 101 | new BukkitRunnable() { 102 | int index = 0; 103 | ThreadLocalRandom random = ThreadLocalRandom.current(); 104 | 105 | public void run() { 106 | if(index >= explodedBlocks.size()){ 107 | 108 | for(BlockState state : dropTypeBlocks){ 109 | state.update(true, false); 110 | } 111 | 112 | fallingBlocks.clear(); 113 | removeExplosion(); 114 | 115 | this.cancel(); 116 | return; 117 | } 118 | 119 | if(randomSpawn){ 120 | if(random.nextInt(1, 11) < 7){ // 70 percent chance 121 | regenBlock(explodedBlocks.get(index++)); 122 | } 123 | }else{ 124 | regenBlock(explodedBlocks.get(index++)); 125 | } 126 | } 127 | }.runTaskTimer(blockController.getPlugin(), delay * 20, interval); 128 | } 129 | 130 | private Vector getNewFallingBlockVector(Location blockLocation){ 131 | Vector blockDirection = blockLocation.toVector().subtract(center.toVector()); 132 | 133 | double divide = radius / blockDirection.lengthSquared(); 134 | blockDirection.divide(new Vector(divide, divide, divide)); 135 | 136 | blockDirection.setY(Math.abs(blockDirection.getY())); 137 | 138 | return blockDirection.normalize(); 139 | } 140 | 141 | @SuppressWarnings("deprecation") 142 | private void regenBlock(BlockState blockState){ 143 | if(isDropType(blockState.getType())){ 144 | dropTypeBlocks.add(blockState); 145 | }else{ 146 | Location stateLocation = blockState.getLocation(); 147 | blockState.update(true, false); 148 | stateLocation.getWorld().playEffect(stateLocation, Effect.STEP_SOUND, blockState.getTypeId()); 149 | } 150 | } 151 | 152 | private boolean isDropType(Material type){ 153 | for(Material dropType : DROP_TYPES){ 154 | if(dropType == type){ 155 | return true; 156 | } 157 | } 158 | return false; 159 | } 160 | 161 | // Method needed for outside reference of Runnable 162 | private void removeExplosion(){ 163 | blockController.getExplosions().remove(this); 164 | } 165 | 166 | public ArrayList getFallingBlocks(){ 167 | return fallingBlocks; 168 | } 169 | 170 | 171 | private static final Material[] DROP_TYPES = { 172 | Material.SAPLING, 173 | Material.LONG_GRASS, 174 | Material.DEAD_BUSH, 175 | Material.YELLOW_FLOWER, 176 | Material.RED_ROSE, 177 | Material.BROWN_MUSHROOM, 178 | Material.RED_MUSHROOM, 179 | Material.TORCH, 180 | Material.LADDER, 181 | Material.SNOW, 182 | Material.VINE, 183 | Material.WATER_LILY, 184 | Material.CARPET, 185 | Material.DOUBLE_PLANT, 186 | Material.PAINTING, 187 | Material.ITEM_FRAME, 188 | Material.SIGN, 189 | Material.FLOWER_POT, 190 | Material.LEVER, 191 | Material.STONE_PLATE, 192 | Material.WOOD_PLATE, 193 | Material.REDSTONE_TORCH_ON, 194 | Material.REDSTONE_TORCH_OFF, 195 | Material.STONE_BUTTON, 196 | Material.TRAP_DOOR, 197 | Material.TRIPWIRE_HOOK, 198 | Material.WOOD_BUTTON, 199 | Material.GOLD_PLATE, 200 | Material.IRON_PLATE, 201 | Material.IRON_TRAPDOOR, 202 | Material.IRON_DOOR_BLOCK, 203 | Material.IRON_DOOR, 204 | Material.WOODEN_DOOR, 205 | Material.WOOD_DOOR, 206 | Material.ACACIA_DOOR, 207 | Material.BIRCH_DOOR, 208 | Material.DARK_OAK_DOOR, 209 | Material.JUNGLE_DOOR, 210 | Material.SPRUCE_DOOR, 211 | Material.REDSTONE, 212 | Material.REDSTONE_COMPARATOR, 213 | Material.REDSTONE_COMPARATOR_ON, 214 | Material.REDSTONE_COMPARATOR_OFF, 215 | Material.REDSTONE_WIRE, 216 | Material.RAILS, 217 | Material.ACTIVATOR_RAIL, 218 | Material.POWERED_RAIL, 219 | Material.DETECTOR_RAIL, 220 | }; 221 | } 222 | --------------------------------------------------------------------------------