├── .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 |
--------------------------------------------------------------------------------