So currently on my server we use factions so there is a fair bit of Tnt cannons going around for raiding bases and what not the issue I have noticed is that there is currently no block in the game that can be moved with pistons and still protect from TNT. So The idea for this plugin was created from that need to fill the gap. Ideally the block type should be changeable from a config and even setting a list of block types in the config. this leaves server owners like my self in control and the plugin my dynamic. meaning useful to more people. personally i would use Gold blocks as it makes protection come at a high cost just like farming Obsidian because it comes at the cost of time. and the block is largely unused as it is a non cheating based server. NB: if this could be done with an existing plugin let me know please. I Just starting to wonder if WorldGuard could do it.
I'll try this, seems fun to make. edit: Not as easy as I hoped. I see no way to actually stop a specific block from destruction caused by an explosion. I do see a possibility to quickly rebuild the block and cancel its droppings, so I'll try and do that. But maybe another dev might know a better method.
JayEffKay you should tag people when you reply Thanks for having a go let me know if it works out cheer's
Try something like this: Code: @Override public void onEntityExplode(EntityExplodeEvent event) { if (event.isCancelled()) return; List<Block> blockListCopy = new ArrayList<Block>(); blockListCopy.addAll(event.blockList()); for (Block block : blockListCopy) { if (block.getType() == Material.GOLD_BLOCK) event.blockList().remove(block); } The tricky part is that this will only stop gold blocks from being destroyed - not stop blocks behind the gold block from blowing up. I guess you could save the location of each gold block and do some maths to try and work out which blocks are behind them then remove those blocks too.
Zarius JayEffKay Why not instead cancel the event, and then call BlockBreak on the NOT included blocks in the blocklist?
romobomo Why would we do that? Seems slower than removing the protected blocks from the blocklist. As mentioned above the tricky bit is the maths to work out which blocks are "behind" the gold blocks - not sure how you'd work out where the TNT hit either... perhaps you could use "event.getEntity().getLocation().getDirection();"
Zarius Oh sorry, I read the guy before you're post. I didn't look at your code, though either way would work about the same speed, honestly. As for the math, if you use the cancel first method, you can just get the location of the TNT entity at the time of the explosion, iterate around it in an oooh i dunno 5x5x5 area (dunno off the top of my head the size of a tnt explosion), and call BlockDestroy for each block in that area that is both in the blocklist and NOT behind a "protected" block.
romobomo Explosions could be variable size depending on the entity - and TNT explosions could vary depending on local plugins, best to deal with the blocks within the event - again the trick is determining which direction is "behind" the protected block (the TNT could be coming in from below, straight into, above, angled to the side, etc)
Zarius Hence the iterator (or a nested for loop) AROUND the explosion area. If the block at the iterated location is not within the blocklist or is MATERIAL.AIR (ID 0), then continue;, otherwise check if the block is a protected block. if it is, set a protectedFound TRUE flag for the next iterations beyond that (already having eliminated non effected blocks), and continue; through that iteration. If it is NOT, destroy the block and check the next iteration. This would be a lot easier (and I'd wager faster) than determining physics... in which you'll STILL need to iterate as you're only determining a straight line vector, not a boxed vector.
Hmm, an interesting problem (protecting blocks behind the "shield" blocks, that is - just protecting blocks is trivial, as Zarius already showed with that example event handler). I can see two possibilities: 1. Simple, but not very efficient: for each block, run a block iterator from the explosion's centre to the block. If you encounter a "shield" block along the way, remove the block from the event's destroyed list. 2. More complex (but hopefully more efficient?) : Consider the explosion area as a sphere. Every block in the area can have its (x,y,z) Cartesian co-ordinates converted to polar co-ordinates with the explosion's centre as the origin (basically a latitude, longitude and distance from centre - see http://electron9.phys.utk.edu/vectors/3dcoordinates.htm for conversion formulae) Divide the surface of your sphere into subdivisions, based on latitude & longitude - the number of subdivisions would really depend on the radius of the sphere for best results. Implement a method that returns a unique ID for each subdivision that a block falls in. For each "shield" block, build a Map<Integer,Integer> which maps a subdivision ID to the distance of the closest shield block in that subdivision to the center of the explosion. Also remove it from the destroyed list, of course. For each other block, if there's a "shield" block in that subdivision closer to the centre than itself (which we can now look up via the Map above), remove it from the destroyed list. Calculating the optimal subdivision resolution would take a little consideration, but I'd say it's doable. Would be interesting to see if method 2 really is more efficient...
desht Zarius I wouldn't bother with converting to spherical coordinates, we're working in cuboids... there's only 22 directions we need to check (8 corners, 8 edges, 6 faces), as opposed to a whole sphere. Also, Java's Sin and Cos are RIDDIC-slow. Here's an example that will work... it may look heavy, but I assure you, it will likely run quickly.... it can easily be shrunk (line wise) by building a hashmap or method construct to hold the directions and looping through that with a single for loop (instead of 22)... but this is what's happening happening now matter how you pretty it up, might as well keep it as such. I havn't tested it, so it may need some slight tweaking, and can probably be made even more efficient. You can also swap to your method of removing from the block list instead of canceling the event before destroying, but I stick to my prefered method ... Up to you... anyway, give it a whirl, should work... The following code checks 10 blocks out in each direction for a "protected ID block". It ignores air blocks/non-effected blocks, destroys non protected blocks, until it hits a "protected ID block", at which time it breaks from the loop and tries the next direction. Meaning that the protected block and all after it will not be affected. Code to follow: Code:java List<Block> blocklist; // get this from the event HashSet<Integer> protIDs; // from a config file possibly? Location loc; //location of explosion Location loc2 = loc; //copy that location to work with // first handle the block AT the explosion... if(!blocklist.contains(loc.getBlock())) loc.getBlock().breakNaturally(); // y+ for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y+, x+ for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()+i); loc2.setX(loc.getX()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y+, x+, z+ for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()+i); loc2.setX(loc.getX()+i); loc2.setZ(loc.getZ()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y+, z+ for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()+i); loc2.setZ(loc.getZ()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y+, z+, x- for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()+i); loc2.setX(loc.getX()-i); loc2.setZ(loc.getZ()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y+, x- for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()+i); loc2.setX(loc.getX()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y+, x-, z- for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()+i); loc2.setX(loc.getX()-i); loc2.setZ(loc.getZ()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y+, z- for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()+i); loc2.setZ(loc.getZ()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y+, z-, x+ for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()+i); loc2.setX(loc.getX()+i); loc2.setZ(loc.getZ()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // x+ for(int i = 1; i <= 10; i++) { loc2.setX(loc.getX()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // x- for(int i = 1; i <= 10; i++) { loc2.setX(loc.getX()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // z+ for(int i = 1; i <= 10; i++) { loc2.setZ(loc.getZ()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // z- for(int i = 1; i <= 10; i++) { loc2.setZ(loc.getZ()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y- for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y-, x+ for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()-i); loc2.setX(loc.getX()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y-, x+, z+ for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()-i); loc2.setX(loc.getX()+i); loc2.setZ(loc.getZ()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y-, z+ for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()-i); loc2.setZ(loc.getZ()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y-, z+, x- for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()-i); loc2.setX(loc.getX()-i); loc2.setZ(loc.getZ()+i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y-, x- for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()-i); loc2.setX(loc.getX()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y-, x-, z- for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()-i); loc2.setX(loc.getX()-i); loc2.setZ(loc.getZ()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y-, z- for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()-i); loc2.setZ(loc.getZ()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } loc2 = loc; // y-, z-, x+ for(int i = 1; i <= 10; i++) { loc2.setY(loc.getY()-i); loc2.setX(loc.getX()+i); loc2.setZ(loc.getZ()-i); if(!blocklist.contains(loc2.getBlock())) continue; if(loc2.getBlock().getTypeId() == 0) continue; if(!protIDs.contains(loc2.getBlock().getTypeId())) { loc2.getBlock().breakNaturally(); } else { break; } } Sorry for any typo's, I pounded that out pretty fast... also, if you want to speed up each loop, you can predefine your iterator (int i = 1; imax = 10, then for(i; i<imax; i++)) EDIT by Moderator: merged posts, please use the edit button instead of double posting.
RustyDagger No problem, I'll do that. There's also a 'watch thread' button, maybe you can use that next time as well Anyway, although others suggest also protecting blocks behind the tnt-free blocks, we don't even know what you want. So in that case the method Zarius suggested seems to be enough (and I've been building a whole 'repairing'-plugin for nothing, except teh learn ). Anyway, here's the thing in a nice package, with source and credits to Zarius. Might publish it properly later. Do let me know if you do want blocks behind protected, I could use my previous code to temporary change the blocks into Obsidian, not sure if that's a good idea, but willing to test edit(3): romobomo If I understand it right, your method involves canceling the explosion event. But wouldn't that also cancel other physical effects that we want when building a TnT-cannon?
JayEffKay Protecting blocks behind the Said gold blocks would be nice however its not 100% needed because we can just make the doors to our vaults more away from what we are protecting. the only down side to that might be our buttons or levers getting destroyed. I intended it to be used with a lot of obsid around it any way. as a vault door. another option for me would be just allowing obsidian to be moved with pistons :/
RustyDagger OtherDrops should be able to do the basic protection (ie. just stopping the gold blocks themselves, not protecting behind) now in the most recent version - 2.3-beta4. Example config: Code: GOLD_BLOCK: - action: BLOCK_BREAK tool: EXPLOSION # or just EXPLOSION_TNT if you don't want to protect against creepers drop: DENY
so a block's blast resistance can't just be altered? this was a question i had that seems to fit in well here. if a gold block just had obby's blast resistance, wouldnt that be easiest?
Doesn't seem to be any way to do this easily yet (I did a quick Bukkit & Google search - people asking how to do it but no definitive answers). You could also kinda "fake" a blast resistance in OtherDrops using this config: Code: GOLD_BLOCK: - action: BLOCK_BREAK tool: EXPLOSION # or just EXPLOSION_TNT if you don't want to protect against creepers drop: DENY chance: 99.5% # this would let 1 in 200 blocks actually get destroyed Although it's not dependant on explosion "strength" at all. Let me know if there are any problems with my solution - I should be able to fix OtherDrops pretty quickly if there are any problems.
Zarius yup will do will open a ticket if i run into any thing not acting as I think it should About to but the new bukkit RB on new CombatTag then otherdrops Config seems nice btw well laid out and iv seen a lot of bad configs in my time