[Resource] Tornado! Spawn a tornado with zero client mods. v3.2

Discussion in 'Resources' started by LucasEmanuel, Nov 19, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    LucasEmanuel

    Hi all! Using this small handy method you will be able to spawn a tornado using Bukkit only. :)

    In the future it will be able to suck up blocks it "crashes" into as well as animals and players.
    As of version 2.0 and 3.0 the tornado is now able to pick up any block and entity that comes in its way.

    Some videos of it in action:
    v2.0:

    v 1.0:


    Changelog:
    The code:
    Code:
    /**
    * Spawns a tornado at the given location l.
    *
    * @param plugin
    *            - Plugin instance that spawns the tornado.
    * @param location
    *            - Location to spawn the tornado.
    * @param material
    *            - The base material for the tornado.
    * @param data
    *            - Data for the block.
    * @param direction
    *            - The direction the tornado should move in.
    * @param speed
    *            - How fast it moves in the given direction. Warning! A number greater than 0.3 makes it look weird.
    * @param amount_of_blocks
    *            - The max amount of blocks that can exist in the tornado.
    * @param time
    *            - The amount of ticks the tornado should be alive.
    * @param spew
    *            - Defines if the tornado should remove or throw out any block it picks up.
    * @param explode
    *            - This defines if the tornado should "explode" when it dies. Warning! Right now it only creates a huge mess.
    */
    public static void spawnTornado(
            final JavaPlugin plugin,
            final Location  location,
            final Material  material,
            final byte      data,
            final Vector    direction,
            final double    speed,
            final int        amount_of_blocks,
            final long      time,
            final boolean    spew,
            final boolean    explode
    ) {
       
        class VortexBlock {
     
            private Entity entity;
           
            public boolean removable = true;
     
            private float ticker_vertical = 0.0f;
            private float ticker_horisontal = (float) (Math.random() * 2 * Math.PI);
     
            @SuppressWarnings("deprecation")
            public VortexBlock(Location l, Material m, byte d) {
     
                if (l.getBlock().getType() != Material.AIR) {
     
                    Block b = l.getBlock();
                    entity = l.getWorld().spawnFallingBlock(l, b.getType(), b.getData());
     
                    if (b.getType() != Material.WATER)
                        b.setType(Material.AIR);
                   
                    removable = !spew;
                }
                else {
                    entity = l.getWorld().spawnFallingBlock(l, m, d);
                    removable = !explode;
                }
               
                addMetadata();
            }
           
            public VortexBlock(Entity e) {
                entity    = e;
                removable = false;
                addMetadata();
            }
           
            private void addMetadata() {
                entity.setMetadata("vortex", new FixedMetadataValue(plugin, "protected"));
            }
           
            public void remove() {
                if(removable) {
                    entity.remove();
                }
                entity.removeMetadata("vortex", plugin);
            }
     
            @SuppressWarnings("deprecation")
            public HashSet<VortexBlock> tick() {
               
                double radius    = Math.sin(verticalTicker()) * 2;
                float  horisontal = horisontalTicker();
               
                Vector v = new Vector(radius * Math.cos(horisontal), 0.5D, radius * Math.sin(horisontal));
               
                HashSet<VortexBlock> new_blocks = new HashSet<VortexBlock>();
               
                // Pick up blocks
                Block b = entity.getLocation().add(v.clone().normalize()).getBlock();
                if(b.getType() != Material.AIR) {
                    new_blocks.add(new VortexBlock(b.getLocation(), b.getType(), b.getData()));
                }
               
                // Pick up other entities
                List<Entity> entities = entity.getNearbyEntities(1.0D, 1.0D, 1.0D);
                for(Entity e : entities) {
                    if(!e.hasMetadata("vortex")) {
                        new_blocks.add(new VortexBlock(e));
                    }
                }
               
                setVelocity(v);
               
                return new_blocks;
            }
     
            private void setVelocity(Vector v) {
                entity.setVelocity(v);
            }
     
            private float verticalTicker() {
                if (ticker_vertical < 1.0f) {
                    ticker_vertical += 0.05f;
                }
                return ticker_vertical;
            }
     
            private float horisontalTicker() {
    //                ticker_horisontal = (float) ((ticker_horisontal + 0.8f) % 2*Math.PI);
                return (ticker_horisontal += 0.8f);
            }
        }
       
        // Modify the direction vector using the speed argument.
        if (direction != null) {
            direction.normalize().multiply(speed);
        }
       
        // This set will contain every block created to make sure the metadata for each and everyone is removed.
        final HashSet<VortexBlock> clear = new HashSet<VortexBlock>();
       
        final int id = new BukkitRunnable() {
     
            private ArrayDeque<VortexBlock> blocks = new ArrayDeque<VortexBlock>();
     
            public void run() {
               
                if (direction != null) {
                    location.add(direction);
                }
     
                // Spawns 10 blocks at the time.
                for (int i = 0; i < 10; i++) {
                    checkListSize();
                    VortexBlock vb = new VortexBlock(location, material, data);
                    blocks.add(vb);
                    clear.add(vb);
                }
               
                // Make all blocks in the list spin, and pick up any blocks that get in the way.
                ArrayDeque<VortexBlock> que = new ArrayDeque<VortexBlock>();
     
                for (VortexBlock vb : blocks) {
                    HashSet<VortexBlock> new_blocks = vb.tick();
                    for(VortexBlock temp : new_blocks) {
                        que.add(temp);
                    }
                }
               
                // Add the new blocks
                for(VortexBlock vb : que) {
                    checkListSize();
                    blocks.add(vb);
                    clear.add(vb);
                }
            }
           
            // Removes the oldest block if the list goes over the limit.
            private void checkListSize() {
                while(blocks.size() >= amount_of_blocks) {
                    VortexBlock vb = blocks.getFirst();
                    vb.remove();
                    blocks.remove(vb);
                    clear.remove(vb);
                }
            }
        }.runTaskTimer(plugin, 5L, 5L).getTaskId();
     
        // Stop the "tornado" after the given time.
        new BukkitRunnable() {
            public void run() {
                for(VortexBlock vb : clear) {
                    vb.remove();
                }
                plugin.getServer().getScheduler().cancelTask(id);
            }
        }.runTaskLater(plugin, time);
    }
    It can also be found in my handy library called "LucasUtils" in the Effects class. And I recommend keeping an eye on that repository if you want to have the latest and most up to date version of this resource since I will probably forget to update this post when I make changes to how the tornado work.

    I hope you find use for it, I probably will. :)
     
    codex01, BDKing88, bfgbfggf and 32 others like this.
  2. Offline

    Ape101

    Can you supply an example of how to turn this into a command?
     
  3. Offline

    xTrollxDudex

    Ape101
    You call the method...
     
  4. Offline

    Jake6177

    Code:java
    1. public boolean onCommand(methodargs) {
    2. if (l.equalsIgnoreCase("cmd") {
    3. classobj.spawnTornado(methodargs);
    4. }
    5. }


    have fun
     
  5. Offline

    BungeeTheCookie

    LucasEmanuel
    Thank you for turning that snippet of code to help me with my problem on my black hole creation into a resource. Keep up the good work!
     
  6. Offline

    desht

    Very nice!

    One small suggestion: since you're removing blocks from the list, I suspect a queue-type structure such as ArrayDeque rather than ArrayList would offer better performance.

    Also, it might be worth building lookup tables for sin() and cos() since they're pretty expensive calls. That would really require using an integer for the angles (degrees, or fractions thereof). Just a thought...
     
  7. Offline

    LucasEmanuel

    I will do that :)
     
  8. Offline

    minelazz

    cant get the tornado to look nice like the tornado in the video :(. What args did u use in the video. I used this,

    Code:java
    1.  
    2. Player s = (Player)sender;
    3. Vector vec = new Vector(2, 2, 2);
    4. Tornado.spawnTornado(this,s.getLocation(), vec, 1d, 200, 40);
     
  9. Offline

    LucasEmanuel

    minelazz
    If you want the tornado to just stand still as it does in the video you can do this:
    Code:
    spawnTornado(plugin, location, null, null, 200, 30);
    PS:
    You have a very high speed, I recommend a speed lower than 0.3, or 0.06 that I use myself as the speed. :)
     
    minelazz likes this.
  10. Offline

    ArthurHoeke

  11. Offline

    LucasEmanuel

    ArthurHoeke
    Call the method with fitting parameters :)

    Version 2.0 is out, adding more features like destruction and more configuration. :)

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
  12. Offline

    ArthurHoeke

  13. Offline

    CaptainBern Retired Staff

    LucasEmanuel I can imagine this with cob webs instead of dirt (so it looks like a real tornado) This is really cool btw...
     
  14. Offline

    LucasEmanuel

    Take a look at the code I posted in the post just above your first post. :)
     
  15. Offline

    maxben34

    Awesome. I saw this yesterday with the black hole post and have messed around with it a little bit. It would be even cooler if this used the explosion particle effect to create an even more tornado like effect.
     
  16. Offline

    darkness1999

    It would be awesome if you could choose whether or not the tornado should destroy things.
     
  17. Offline

    ArthurHoeke

    LucasEmanuel of i do that code he dont fonds location and plugin
     
  18. Offline

    minelazz

    Thx!!
     
  19. Offline

    Ape101

    Whats an argument for the byte section? i've tried lots of things, doubles and normal integers, nothing works
     
  20. Offline

    LucasEmanuel

    Ape101
    That is the data for the block, for example there you can define the color of a wool block. :)

    Just use "(byte) 0" as value :)
     
  21. Offline

    maxben34

    Some things that currently are buggy/suggestions:

    I don't think that the spew boolean is properly working (It seems to always spew).
    The tornado doesn't pick anything up unless it is completely at the bottom center of the tornado. It should pick up all blocks and entities around it.
    There are probably many more things that would be awesome for this but I really thank you for the hard work that you've put into this.

    LucasEmanuel
     
  22. Offline

    LucasEmanuel

    The bug where the tornado is only picking up some of the blocks and entities might be a glitch in the server/minecraft. My code keeps looking one block ahead every time it updates every single block in the vortex and creates a new VortexBlock out of any block that is in front of the current VortexBlock.

    If you look closely at the video for v2.0 you can see that it picks up a lot of blocks but immediately puts them back down, this might be because I never touch the BlockPhysicsEvent where it handles falling blocks and their collision (if I remember correctly) and I have made some "workarounds" in order to not have to do that.

    I tried to make this code as compact as possible and within a single method for easy usage. The best way to do this would be to create an entire plugin out of it that correctly manages events and such to fix all these glitches.

    As for the spewing, it is spewing out every block it has picked up as far as I can tell from my tests and the code. But I will keep a closer eye on it. :)
     
    maxben34 likes this.
  23. Offline

    Ape101

    Last question :p
    How do we choose the direction of the tornado? whats the argument?
     
  24. Offline

    CaptainBern Retired Staff

  25. Offline

    BungeeTheCookie

    Ah my black hole post (I will try out the code tomorrow hopefully - all of the messages I have been sending for the past 4 days were on my ipad xd sorry to keep all of you that were on my blackhole post waiting) :D
     
  26. Offline

    darkness1999

    Some ideas:
    • boolean whether or not a tornado can pick up waterblocks(and lava) (or maybe completly disable flying water blocks because this is not very realistic...)
    • I think it would be nice if you could also decide whether or not the fallingblocks should be placed
    • boolean whether or not entities should be picked up
    • EDIT: boolean whether or not blocks should be picked up
    • EDIT: boolean whether or not "real" blocks should be picked up (what I suggest is to create those picked up blocks ONLY and not remove them from landscape
     
  27. Offline

    DevRosemberg

    How come this dosent work on V3

    Code:java
    1. TornadoUtils.spawnTornado(MinereachCore.getInstance(), player.getLocation(), Material.DIRT, 0, vec, 0.3D, 10, 20, false);
     
  28. Offline

    LucasEmanuel

    You have defined the time the tornado should be alive as 20 ticks, or 1 second. :)
     
  29. Offline

    ArthurHoeke

    LucasEmanuel I got now this to spawn the tornado but i get a error on Minereachcore
    Code:
        if(commandLabel.equalsIgnoreCase("tornado")){
            Player s = (Player)sender;
            Vector vec = new Vector(2, 2, 2);
            Ores.spawnTornado(MinereachCore.getInstance(), s.getLocation(), Material.DIRT, 0, vec, 0.3D, 10, 20, false);
        }
     
  30. Offline

    DevRosemberg

    ArthurHoeke MinereachCore is a private plugin im doing, nothing to do with LucasEmanuel-

    LucasEmanuel I meant, it appears as an error, it wouldnt compile.
     
Thread Status:
Not open for further replies.

Share This Page