I know this may look like I am doing too much work or something, but this same method is set up to be added to for other blocks, so don't worry about that. What I am trying to do is make sponges work, by checking the config for the variable configRadius, and setting a radius around that from water to air (only water is being changed). Why isn't it working? Code: package com.github.JamesNorris.Flow; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; public class PlacedBlockEvents implements Listener { private Flow plugin; public PlacedBlockEvents(final Flow instance) { plugin = instance; } @EventHandler(priority = EventPriority.HIGHEST) public void BPE(BlockPlaceEvent event){ if(!event.isCancelled()){ Block placed = event.getBlock(); int configFace = plugin.getConfig().getInt("spongeRadius"); if (placed.getType() == Material.SPONGE){//SPONGES final Block block = new Location(placed.getWorld(), placed.getLocation().getX(), placed.getLocation().getY(), placed.getLocation().getZ()).getBlock(); final World world = block.getWorld(); final int x = block.getX(); final int y = block.getY(); final int z = block.getZ(); final int minX = x - configFace; final int minY = y - configFace; final int minZ = z - configFace; final int maxX = x + configFace; final int maxY = y + configFace; final int maxZ = z + configFace; for (int counterX = minX; counterX <= maxX; counterX++) { for (int counterY = minY; counterY <= maxY; counterY++) { for (int counterZ = minZ; counterZ <= maxZ; counterZ++) { final Block face = world.getBlockAt(counterX, counterY, counterZ); if (face.getType() != Material.WATER){ break; } if (face.getType() == Material.WATER || face.getType() == Material.STATIONARY_WATER) { face.setType(Material.AIR); break; } } } } } } } }
I have few comments: Code: if (face.getType() != Material.WATER){ break; } Is useless, because you make the same check right after it. You loop trough all x, y but not z. Remove the "break" see if it improves. You are changing only one cube face to air which may be imminently fixed back to water.
now what would I put if I want to cancel that event on block break? EDIT: I tried setCancelled, but the water doesnt form streams back into the hole left by the sponge...
Not sure what you mean. If I understand you correctly, you want to make the water flow towards the spondge and not fix itself. Try modifying BlockFormToEvent. You need to cancel all events where WATER forms to STATIONARY_WATER.
No, I want it so when you place a sponge, the water is removed (done that), then when the sponge is removed, the blocks that were water before, are changed back into water. (ignoring air and other blocks in the area)
There is no certain way to do it, unless you want to save all block locations, that have been changed, to the disk. You could just set every block in the radius that got drained back to water. The special cases make it very messy though. If the player doesn't submerge the sponge deep enough, then it will result in a fountain effect. Those problems may be avoided if you set radius to 1. Just replace the sponge with water when you remove it. Hopefully that additional water block will fix the water around the sponge.
wait... is there a way to just remove the water around the sponge, instead of turning the water to air?
Maybe save locations and a List in a hashmap, where the location is the location of the sponge and the List contains locations of where water was previously? For an BlockBreakEvent it would be simple enough to call that hashmap and restore water.
Hmm, but what about the edges of the water (at the outside of the sponges' affect). Could those be turned into streams? EDIT: EnvisionRed great idea! trying now!
How would I define the list changed in this? Code: package com.github.JamesNorris.Flow; import java.awt.List; import java.util.HashMap; import java.util.Map; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; public class PlacedBlockEvents implements Listener { private Flow plugin; public PlacedBlockEvents(final Flow instance) { plugin = instance; } public Map<Location, List> blocks = new HashMap<Location, List>(); @EventHandler(priority = EventPriority.HIGHEST) public void BPE(BlockPlaceEvent event){ if (!event.isCancelled()) { Block placed = event.getBlock(); int configFace = plugin.getConfig().getInt("spongeRadius"); if (placed.getType() == Material.SPONGE){//SPONGES final Block block = new Location(placed.getWorld(), placed.getLocation().getX(), placed.getLocation().getY(), placed.getLocation().getZ()).getBlock(); final World world = block.getWorld(); final int x = block.getX(); final int y = block.getY(); final int z = block.getZ(); final int minX = x - configFace; final int minY = y - configFace; final int minZ = z - configFace; final int maxX = x + configFace; final int maxY = y + configFace; final int maxZ = z + configFace; for (int counterX = minX; counterX <= maxX; counterX++) { for (int counterY = minY; counterY <= maxY; counterY++) { for (int counterZ = minZ; counterZ <= maxZ; counterZ++) { final Block face = world.getBlockAt(counterX, counterY, counterZ); if (face.getType() == Material.WATER || face.getType() == Material.STATIONARY_WATER) { blocks.put(placed.getLocation(), changed.getLocation()); face.setType(Material.AIR); if (placed.getType() == Material.AIR){ event.setCancelled(true); break; } } } } } } } } } So that its a list of all the blocks that were within the "configFace" (radius), and that were water?
You will also need to save that hashmap, because you don't want to loose the functionality when you /reload or reboot.
This is working, but only partially. If you destroy 1 sponge, all of thier water returns to normal. How would I fix this? Code: package com.github.JamesNorris.Flow; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; public class PlacedBlockEvents implements Listener { private Flow plugin; public PlacedBlockEvents(final Flow instance) { plugin = instance; } public HashSet<BlockState> blocks = new HashSet<BlockState>(); public Map<Location, HashSet<BlockState>> area = new HashMap<Location, HashSet<BlockState>>(); @EventHandler(priority = EventPriority.HIGHEST) public void BPE(BlockPlaceEvent event){ if (!event.isCancelled()) { Block placed = event.getBlock(); Location placedloc = event.getBlock().getLocation(); int configFace = plugin.getConfig().getInt("spongeRadius"); if (placed.getType() == Material.SPONGE){ final Block block = new Location(placed.getWorld(), placed.getLocation().getX(), placed.getLocation().getY(), placed.getLocation().getZ()).getBlock(); final World world = block.getWorld(); final int x = block.getX(); final int y = block.getY(); final int z = block.getZ(); final int minX = x - configFace; final int minY = y - configFace; final int minZ = z - configFace; final int maxX = x + configFace; final int maxY = y + configFace; final int maxZ = z + configFace; for (int counterX = minX; counterX <= maxX; counterX++) { for (int counterY = minY; counterY <= maxY; counterY++) { for (int counterZ = minZ; counterZ <= maxZ; counterZ++) { final Block face = world.getBlockAt(counterX, counterY, counterZ); if (face.getType() == Material.WATER || face.getType() == Material.STATIONARY_WATER) { blockChange(face, placed, placedloc); } } } } } } } public void blockChange(Block face, Block placed, Location placedloc){ Location loc = placed.getLocation(); BlockState blockstate = face.getState(); blocks.add(blockstate); area.put(loc, blocks); face.setType(Material.AIR); } public void checkIfBroken(Location loc) { for (BlockState state : area.get(loc)) { state.update(true); } } @EventHandler(priority = EventPriority.HIGHEST) public void BBE(BlockBreakEvent event){ Block destroyed = event.getBlock(); if (destroyed.getType() == Material.SPONGE){ checkIfBroken(destroyed.getLocation()); } } }
I think you need to listen to onBlockFromTo and verify if a sponge is near. It's the event I used to make water unable to spread outside a zone.
I thought that to, but now it works without it, saving time... NEW PROBLEMS! If a half bubble is formed above water, it does not get filled in, although I have fixed this problem for below water. Code: package com.github.JamesNorris.Flow; import java.util.HashMap; import java.util.HashSet; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockFromToEvent; import org.bukkit.event.block.BlockPlaceEvent; public class SpongeEvents implements Listener { private final Flow plugin; public SpongeEvents(final Flow instance) { plugin = instance; } public HashSet<BlockState> blocks = new HashSet<BlockState>(); public HashMap<Location, HashSet<BlockState>> area = new HashMap<Location, HashSet<BlockState>>(); @EventHandler(priority = EventPriority.HIGHEST) public void BPE(final BlockPlaceEvent event) { if (!event.isCancelled()) { final Block placed = event.getBlock(); final int configFace = plugin.getConfig().getInt("spongeRadius"); if (placed.getType() == Material.SPONGE) { final Block block = new Location(placed.getWorld(), placed.getLocation().getX(), placed.getLocation().getY(), placed.getLocation().getZ()).getBlock(); final World world = block.getWorld(); final int x = block.getX(); final int y = block.getY(); final int z = block.getZ(); final int minX = x - configFace; final int minY = y - configFace; final int minZ = z - configFace; final int maxX = x + configFace; final int maxY = y + configFace; final int maxZ = z + configFace; for (int counterX = minX; counterX <= maxX; counterX++) { for (int counterY = minY; counterY <= maxY; counterY++) { for (int counterZ = minZ; counterZ <= maxZ; counterZ++) { final Block face = world.getBlockAt(counterX, counterY, counterZ); if (face.getType() == Material.WATER || face.getType() == Material.STATIONARY_WATER && plugin.getConfig().getBoolean("enableWater") == true) { blockChange(face, placed); } if (face.getType() == Material.LAVA || face.getType() == Material.STATIONARY_LAVA && plugin.getConfig().getBoolean("enableLava") == true) { blockChange(face, placed); } } } } } } } public void blockChange(final Block face, final Block placed) { final Location loc = placed.getLocation(); final BlockState blockstate = face.getState(); blocks.add(blockstate); area.put(loc, blocks); face.setType(Material.AIR); } public void checkIfBroken(Location loc, Block destroyed) { if (area.containsKey(loc)) { if (area.get(destroyed) == blocks){ for (final BlockState state : area.get(loc)) { state.update(true); } } } } @EventHandler(priority = EventPriority.HIGHEST) public void BBE(final BlockBreakEvent event) { final Block destroyed = event.getBlock(); if (plugin.getConfig().getBoolean("enableSponges") == true) { if (destroyed.getType() == Material.SPONGE) { if (plugin.getConfig().getBoolean("liquidReplacement") == true) { final Location loc = destroyed.getLocation(); checkIfBroken(loc, destroyed); } else { final int configFace = plugin.getConfig().getInt("spongeRadius"); final Block block = new Location(destroyed.getWorld(), destroyed.getLocation().getX(), destroyed.getLocation().getY(), destroyed.getLocation().getZ()).getBlock(); final World world = block.getWorld(); final int x = block.getX(); final int y = block.getY(); final int z = block.getZ(); final int minX = x - configFace - 1; final int minY = y - configFace - 1; final int minZ = z - configFace - 1; final int maxX = x + configFace + 1; final int maxY = y + configFace + 1; final int maxZ = z + configFace + 1; for (int counterX = minX; counterX <= maxX; counterX++) { for (int counterY = minY; counterY <= maxY; counterY++) { for (int counterZ = minZ; counterZ <= maxZ; counterZ++) { final Block face = world.getBlockAt(counterX, counterY, counterZ); if (face.getData() == 0x8) { if (face.getType() != Material.CACTUS || face.getType() != Material.SUGAR_CANE_BLOCK || face.getType() != Material.SNOW_BLOCK) { if (face.getType() != Material.SOIL || face.getType() != Material.CROPS || face.getType() != Material.WOOL || face.getType() != Material.RAILS) { if (face.getType() != Material.WOOD_DOOR || face.getType() != Material.IRON_DOOR || face.getType() != Material.SIGN_POST) { if (face.getType() != Material.BED_BLOCK || face.getType() != Material.REDSTONE_WIRE || face.getType() != Material.PISTON_BASE) { if (face.getType() != Material.PISTON_STICKY_BASE || face.getType() != Material.PISTON_EXTENSION || face.getType() != Material.RED_MUSHROOM) { if (face.getType() != Material.HUGE_MUSHROOM_1 || face.getType() != Material.HUGE_MUSHROOM_2 || face.getType() != Material.VINE) { if (plugin.getConfig().getBoolean("enableWater") == true) { face.setType(Material.STATIONARY_WATER); face.setData((byte) 0x3); } if (plugin.getConfig().getBoolean("enableLava") == true) { face.setType(Material.STATIONARY_LAVA); face.setData((byte) 0x2); } } } } } } } } if (face.getType() == Material.WATER || face.getType() == Material.STATIONARY_WATER && plugin.getConfig().getBoolean("enableWater") == true) { face.setType(Material.STATIONARY_WATER); face.setData((byte) 0x3); } if (face.getType() == Material.LAVA || face.getType() == Material.STATIONARY_LAVA && plugin.getConfig().getBoolean("enableLava") == true) { face.setType(Material.STATIONARY_LAVA); face.setData((byte) 0x2); } } } } } } } } @EventHandler(priority = EventPriority.HIGHEST) public void BFTE(BlockFromToEvent event){ if (!event.isCancelled()) { if (plugin.getConfig().getBoolean("enableSponges") == true){ Block changed = event.getBlock(); int configFace = plugin.getConfig().getInt("spongeRadius"); if (changed.getType() == Material.WATER || changed.getType() == Material.STATIONARY_WATER){ Block block = event.getToBlock(); World world = block.getWorld(); int x = block.getX(); int y = block.getY(); int z = block.getZ(); int minX = x - configFace; int minY = y - configFace; int minZ = z - configFace; int maxX = x + configFace; int maxY = y + configFace; int maxZ = z + configFace; for (int counterX = minX; counterX <= maxX; counterX++) { for (int counterY = minY; counterY <= maxY; counterY++) { for (int counterZ = minZ; counterZ <= maxZ; counterZ++) { final Block face = world.getBlockAt(counterX, counterY, counterZ); if (face.getType() == Material.SPONGE) { event.setCancelled(true); return; } } } } } } } } } If you can fix any or all of these, please post it below!
instead of saving al the blocks that are inside the area of the sponge (and have risk of runnin gout of memory) why not do this on runtime, just ad this listener methode: Code:java @EventHandler(priority = EventPriority.HIGHEST) public void BPE(BlockFromToEvent event){ if (!event.isCancelled()) { Block placed = getBlock(); int configFace = plugin.getConfig().getInt("spongeRadius"); if ( placed.getType() == Material.WATER || placed.getType() == Material.STATIONARY_WATER)){ final Block block = event.getToBlock(); final World world = block.getWorld(); final int x = block.getX(); final int y = block.getY(); final int z = block.getZ(); final int minX = x - configFace; final int minY = y - configFace; final int minZ = z - configFace; int maxX = x + configFace; int maxY = y + configFace; int maxZ = z + configFace; for (int counterX = minX; counterX <= maxX; counterX++) { for (int counterY = minY; counterY <= maxY; counterY++) { for (int counterZ = minZ; counterZ <= maxZ; counterZ++) { final Block face = world.getBlockAt(counterX, counterY, counterZ); if (face.getType() == Material.SPONGE) { event.setCancelled(true);return; } } } } } } }
@ferrybig After I add this should I remove the HashSet and HashMap? EDIT: and if I set a max radius of 10, how much memory could this take up? EDITEDIT: Changed the code that I just posted... EDITEDITEDIT: Added another problem, that I will eventually have to fix..
it fixes 2 of the 3 problems, and requires much more code, and the source is scattered, and I want to learn from this, not just copy some code and put a licence on it.
@ferrybig Jeez, i tried what you said and it fixed a problem! Thanks! EDIT: 2 of 3 down, 1 more to go, and its the same problem I get with worldguard sponges.
When you remove a sponge from the surface, a water "crater" is left. For me this tries to fix itself, but it doesnt work completely. Thats all I have to do to finish sponges.
I think the water crator was also there in the classic game, so the sponges just work, but you do want to add it as feacture?