How to Listen for a Block Powering-up

Discussion in 'Resources' started by carapace7940, Oct 22, 2012.

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

    carapace7940

    Problem:

    How do you trap the situation where a particular block is “powered up”; that is, goes from un-powered to powered.

    There have been some discussions about how to do it, but I was never able to find anything definitive. So here is what I have come up with. (It is not the only way.) I hope you find it useful. (And I hope that I have covered all of the cases!)

    Overview:

    Okay, what we want is:

    To catch all cases (for some subset of minecraft blocks) where a block goes from isBlockPowered() == false to isBlockPowered() == true.​

    For this to happen, a neighboring redstone-associated block (e.g., redstone wire, redstone-torch, lever or button) has to go from OldCurrent() == 0 to NewCurrent() > 0. The BlockRedstoneEvent is the key to catching this. It is fired whenever this happens.
    So we build a listener and inside of it we build an event handler for the BlockRedstoneEvent. In the handler, we look at the triggering-block’s adjacent neighbors to see if any of them are of the type of block we are interested in. In order to be “powered up” that adjacent block must be unpowered at this point. So we also check for that:

    if (adjBlock.isBlockPowered()) break;

    If it passes that test, then we have a very good candidate for a block that is just about to get powered up.

    But it isn’t definite. For example the triggering block could be a redstone wire that is running right by the side of the block we are interested in and won’t power it up. Now we could check all possible permutations of redstone wire configurations to see if it will power up the block we are interested in – but do we want to do that? And fall prey to any subtle Minecraft changes that change the way that redstone power works? Definitely not!

    But we have uncovered a candidate for powering up. Now we just need to wait and see our block-of-interest actually goes to isBlockPowered() == true. And we can find out in a jiffy because our block of interest is going to get a BlockPhysicsEvent fired for it. We can check it then, to see if our block-of-interest, indeed, has its isBlockPowered()==true.

    But we need to pass the fact that our block-of-interest is a block-of-interest from the BlockRedstoneEvent handler to the BlockPhysicsEvent handler. So we define a temporary, short term storage class where our candidate blocks are recorded and saved so that the BlockPhysicsEvent can know to check them.

    Here is the listener code so far: (Note in the code the type of block we are interested in being powered up is GOLD_BLOCK.)




    Code:
        @EventHandler(priority = EventPriority.LOWEST)
          publicvoidonBlockRedstone(BlockRedstoneEvent e) {
                  Block triggeringBlock = e.getBlock();
                  // Block b must a redstonewire, a redstone torch, a lever, or button
     
                  if (e.getOldCurrent() == 0 && e.getNewCurrent() > 0) {
                        final BlockFace adjFaces[] = { BlockFace.NORTH, BlockFace.EAST,
                                      BlockFace.SOUTH, BlockFace.WEST, BlockFace.UP,
                                      BlockFace.DOWN };
     
                        for (BlockFace bf : adjFaces) {
     
                              Block adjBlock = triggeringBlock.getRelative(bf);
                              if (adjBlock.getType() == Material.GOLD_BLOCK) // or whatever type
                                                                                // block you are
                                                                                // interested in
                                                                                // ....
                              {
                                      if (adjBlock.isBlockPowered())
                                            break; // ie its *already* powered, so it can't be
                                                          // powered-on!
                                      blocksWaitingForPhysicsEvent.add(adjBlock);
                              }
                        }
                  }
          }
     
          private HashSet<Block> blocksWaitingForPhysicsEvent = newHashSet<Block>();
     
          @EventHandler(priority = EventPriority.LOWEST)
          publicvoidonBlockPhysics(BlockPhysicsEvent e) {
                  Block b = e.getBlock();
                  if (b.getType() == Material.GOLD_BLOCK) // or whatever type block you
                                                          // are interested in ....
                  {
                        if (blocksWaitingForPhysicsEvent.contains(b)) {
                              blocksWaitingForPhysicsEvent.remove(b);
                              if (b.isBlockPowered())
                                      doPowerup(b); // ie, call your method that handles the
                                                                  // power-up of your block.
                        }
                  }
    
    But there is a wrinkle: Diodes (ie repeaters) can also power up a block. But, they don’t have BlockRedstoneEvents fired for them when they power up. So we have to find another way when they are the redstone block that powers up out block-of-interest. Turns out, we can use the BlockPhysicsEvent, instead of the BlockRedstoneEvent for detecting when the diode powers up (and we can also determine which block the diode powers up next).

    Here is what is interesting about the BlockPhysicsEvent for diodes: There are a bunch of them that occur during the power-up cycle of a diode. But when the diode actually send power onward, the block changes type from:

    getType() == Material.DIODE_BLOCK_OFF

    ... to:
    getType() == Material.DIODE_BLOCK_ON

    So in the BlockPhysicsEvent, we check for getType() == Material.DIODE_BLOCK_ON and when found, we determine what blockface is being powered next:

    Code:
              for (BlockFace bf : nsewFaces) {
                      if (b.isBlockFacePowered(bf)) {
                          Block rc = b.getRelative(bf);
                      }
              }
    
    And if the powered blockface leads to one of our blocks-of-interest and that block-of-interest has isBlockPowered() == false, then we have a candidate for being powered-up. (Actually I thinks its a sure-deal, but it doesn’t hurt to wait and confirm it during the block-of-interest’s BlockPhysicsEvent.)

    Here is the code for the diode’s BlockPhysicsEvent

    Code:
    @EventHandler(priority = EventPriority.LOWEST)
        publicvoidonBlockPhysics(BlockPhysicsEvent e) {
              Block b = e.getBlock();
              if (b.getType() == Material.DIODE_BLOCK_ON) {
                    final BlockFace nsewFaces[] = { BlockFace.NORTH,
                              BlockFace.EAST,
                              BlockFace.SOUTH, BlockFace.WEST };
                    for (BlockFace bf : nsewFaces) {
                        if (b.isBlockFacePowered(bf)) {
                              Block rc = b.getRelative(bf);
                              if (rc.getType() == Material.GOLD_BLOCK)
                                            // or whatever type
                                            // block you are 
                                            // interested in
                                  blocksWaitingForPhysicsEvent.add(rc);
                        }
                    }
              }
        }
    
    And here is all of the code for the complete listener:

    Code:
    [/FONT]
    import java.util.HashSet;
    import org.bukkit.Material;
    import org.bukkit.block.Block;
    import org.bukkit.block.BlockFace;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.BlockPhysicsEvent;
    import org.bukkit.event.block.BlockRedstoneEvent;
    public class PowerOnListener implements Listener {
          public PowerOnListener() {
          }
          @EventHandler(priority = EventPriority.LOWEST)
          public void onBlockRedstone(BlockRedstoneEvent e) {
                  Block triggeringBlock = e.getBlock();
    
                  // Block b must a redstonewire, a redstone torch, a lever, or button
    
                  if (e.getOldCurrent() == 0 && e.getNewCurrent() > 0) {
                        final BlockFace adjFaces[] = { BlockFace.NORTH, BlockFace.EAST,
                                      BlockFace.SOUTH, BlockFace.WEST, BlockFace.UP,
                                      BlockFace.DOWN };
    
                        for (BlockFace bf : adjFaces) {
                              Block adjBlock = triggeringBlock.getRelative(bf);
                              if (adjBlock.getType() == Material.GOLD_BLOCK) // or whatever
                                                                        // type
                                                                        // block you are
                                                                        // interested in
                                                                        // ....
                              {
                                      if (adjBlock.isBlockPowered())
                                            break; // ie its *already* powered, so it can't be
                                                          // powered-on!
                                      blocksWaitingForPhysicsEvent.add(adjBlock);
                              }
                        }
                  }
          }
          private HashSet<Block> blocksWaitingForPhysicsEvent = new HashSet<Block>();
          @EventHandler(priority = EventPriority.LOWEST)
          public void onBlockPhysics(BlockPhysicsEvent e) {
                  Block b = e.getBlock();
                  if (b.getType() == Material.GOLD_BLOCK) // or whatever type block you
                                                    // are interested in ....
                  {
                        if (blocksWaitingForPhysicsEvent.contains(b)) {
                              blocksWaitingForPhysicsEvent.remove(b);
                              if (b.isBlockPowered())
                                      doPowerup(b); // ie, call your method that handles the
                                                    // power-up of your block.
                        }
                  }
                  if (b.getType() == Material.DIODE_BLOCK_ON) {
                        final BlockFace nsewFaces[] = { BlockFace.NORTH, BlockFace.EAST,
                                      BlockFace.SOUTH, BlockFace.WEST };
                        for (BlockFace bf : nsewFaces) {
                              if (b.isBlockFacePowered(bf)) {
                                      Block rc = b.getRelative(bf);
                                      if (rc.getType() == Material.GOLD_BLOCK)
                                                                        // or whatever type
                                                                        // block you are
                                                                        // interested in
                                                                        // ....
                                            blocksWaitingForPhysicsEvent.add(rc);
                              }
                        }
                  }
          }
          private void doPowerup(Block block) {
                  if (!block.isBlockPowered())
                        return;
                  // your power-up stuff goes here
          }
    }
     
    mythcaptor and WarmakerT like this.
Thread Status:
Not open for further replies.

Share This Page