Change the direction of a sign

Discussion in 'Plugin Development' started by MrCreeper, Aug 15, 2011.

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

    MrCreeper

    Hey :)
    How can I get / set the direction of a (Sign) Block.getState() ?
     
  2. Offline

    Pandemoneus

    Code:java
    1. Sign s = (Sign) b.getState().getData();
    2. s.getAttachedFace().ordinal();


    and to set (didn't try whether that works)
    Code:java
    1. Sign s = (Sign) b.getState().getData();
    2. s.setFacingDirection(BlockFace.NORTH);
     
  3. Offline

    MrCreeper

    Code:java
    1. -BlockState state = block.getState();
    2. Sign sign = (Sign) state;
    3. Sign signData = (Sign) state.getData();

    I can't find getAttachedFace() and setFacingDirection() for signData. Did I make a mistake?
     
  4. Offline

    feildmaster Retired Staff

    Just use setData();

    The bytes are:
    • 0x0: West
    • 0x1: West-Northwest
    • 0x2: Northwest
    • 0x3: North-Northwest
    • 0x4: North
    • 0x5: North-Northeast
    • 0x6: Northeast
    • 0x7: East-Northeast
    • 0x8: East
    • 0x9: East-Southeast
    • 0xA: Southeast
    • 0xB: South-Southeast
    • 0xC: South
    • 0xD: South-Southwest
    • 0xE: Southwest
    • 0xF: West-Southwest
    and for wall signs
    • 0x2: Facing east
    • 0x3: Facing west
    • 0x4: Facing north
    • 0x5: Facing south
     
    mythbusterma and kroltan like this.
  5. Offline

    Shamebot

    Code:java
    1. org.bukkit.material.Sign sign = new Sign(block.getType(),block.getData());
    2. sign...
    3. block.setData(sign.getData());

    There are two Sign classes, org.bukkit.block.Sign and org.bukkit.material.Sign.
     
  6. Offline

    MrCreeper

    Sorry for bumping an older thread, but I need help with it again.
    How can I save and load the sign direction as a string (an integer would be nice too) ?
    Code:java
    1. ((org.bukkit.material.Sign) block.getState().getData()).getAttachedFace().name());

    This is my code for getting the direction name, but it seems to always return DOWN.
     
  7. Offline

    bergerkiller

    Lucky you, I already wrote all of these. :)

    Code:
        public BlockFace getFacing() {
            Block b = this.getBlock();
            return ((Directional) b.getType().getNewData(b.getData())).getFacing();
        }
        public void setFacing(BlockFace facing) {
            org.bukkit.material.Sign sign = new org.bukkit.material.Sign();
            sign.setFacingDirection(facing);
            getBlock().setData(sign.getData(), true);
        }
    Also: Don't use getState() on the fly, it does some more work in the background. (can be neglected for once-in-a-while operations)

    Also, you can use toString() to get the names. I recommend looping through the values and pick it from that, since valueOf is prone to fail.
    Code:
    public static BlockFace getFace(String name, BlockFace def) {
        for (BlockFace face : BlockFace.values()) {
            if (face.toString().equalsIgnoreCase(name)) {
                return face;
            }
        }
        return def;
    }
     
  8. Offline

    Diogyn

    Hi
    I have some trouble with this fonction getFacing(). I want the face of the dispenser. This is my code.
    Code:
    public void onBlockPlace(BlockPlaceEvent event){
    
            Player p = event.getPlayer();
            Block block = event.getBlockPlaced();
            int mat = block.getTypeId();
    
            if(mat == 23) {
                Dispenser disp = ((Dispenser)(block.getState()));
    
                BlockFace face = ((FurnaceAndDispenser) disp.getData()).getFacing();
                p.sendMessage("Dispenser "+face.getModX()+" "+face.getModZ());
    
                MaterialData material = block.getType().getNewData(block.getData());
                face = ((Directional) material).getFacing();
                p.sendMessage("Dispenser2 "+face.getModX()+" "+face.getModZ());
    
                face = ((Directional) disp.getData()).getFacing();
                p.sendMessage("Dispenser3 "+face.getModX()+" "+face.getModZ());
    
                Block pBlock = p.getLocation().getBlock();
                if(pBlock.getLocation().distance(block.getLocation()) <= 1) {
                    face = block.getFace(pBlock);
                    p.sendMessage("Dispenser4 "+face.getModX()+" "+face.getModZ());
                    ((Directional) disp.getData()).setFacingDirection(face);
                }
                       }
    I have some random result with the method 1, 2 and 3. The only correct solution is the 4, but it's not really practical... The MaterialData seems to be random...
    Have you another solution or an explanation ?
     
  9. Offline

    bergerkiller

    @Diogyn the reason that 'works' is because you simply used the player location yaw value. This does the same thing:
    Code:
        public static BlockFace yawToFace (float yaw) {
            return yawToFace(yaw, true);
        }
        public static BlockFace yawToFace(float yaw, boolean useSubCardinalDirections) {
            yaw = Util.normalAngle(yaw);
            if (useSubCardinalDirections) {
                switch ((int) yaw) {
                case 0 : return BlockFace.NORTH;
                case 45 : return BlockFace.NORTH_EAST;
                case 90 : return BlockFace.EAST;
                case 135 : return BlockFace.SOUTH_EAST;
                case 180 : return BlockFace.SOUTH;
                case 225 : return BlockFace.SOUTH_WEST;
                case 270 : return BlockFace.WEST;
                case 315 : return BlockFace.NORTH_WEST;
                }
                //Let's apply angle differences
                if (yaw >= -22.5 && yaw < 22.5) {
                    return BlockFace.NORTH;
                } else if (yaw >= 22.5 && yaw < 67.5) {
                    return BlockFace.NORTH_EAST;
                } else if (yaw >= 67.5 && yaw < 112.5) {
                    return BlockFace.EAST;
                } else if (yaw >= 112.5 && yaw < 157.5) {
                    return BlockFace.SOUTH_EAST;
                } else if (yaw >= -67.5 && yaw < -22.5) {
                    return BlockFace.NORTH_WEST;
                } else if (yaw >= -112.5 && yaw < -67.5) {
                    return BlockFace.WEST;
                } else if (yaw >= -157.5 && yaw < -112.5) {
                    return BlockFace.SOUTH_WEST;
                } else {
                    return BlockFace.SOUTH;
                }
            } else {
                switch ((int) yaw) {
                case 0 : return BlockFace.NORTH;
                case 90 : return BlockFace.EAST;
                case 180 : return BlockFace.SOUTH;
                case 270 : return BlockFace.WEST;
                }
                //Let's apply angle differences
                if (yaw >= -45 && yaw < 45) {
                    return BlockFace.NORTH;
                } else if (yaw >= 45 && yaw < 135) {
                    return BlockFace.EAST;
                } else if (yaw >= -135 && yaw < -45) {
                    return BlockFace.WEST;
                } else {
                    return BlockFace.SOUTH;
                }
            }
        }
    Code:
    BlockFace direction = yawToFace(p.getLocation().getYaw());
    Also, did you do the same face check in onPlayerInteract on a block? Could be the furnace data is not yet set on placement. (in that case it uses the player yaw, your method 4)
     
  10. Offline

    Diogyn

    Hi
    You're right, it works if a take the block in a onPlayerInteract event, I get the right face.
    The problem is that I don't want to wait a new interaction of the player to register the dispenser. Have you a simple idea to add the dispenser when it has the correct MaterialData ?
    And thanks for your code yawToFace. But where is your fonction yaw = Util.normalAngle(yaw); ? I couldn't find this class "Util". It doesn't work without it :s
     
  11. Offline

    bergerkiller

    @Diogyn NormalAngle converts angles to a -180 - 180 degree range.
    Code:
        public static float normalAngle(float angle) {
            while (angle <= -180) angle += 360;
            while (angle > 180) angle -= 360;
            return angle;
        }
    There's an easier method: delayed tasks. It kinda depends to what you want to do with this data, but here an example:
    Code:
    public class FurnacePlacementTask implements Runnable {
        public FurnacePlacementTask(Block b) {
            this.block = b;
        }
        private Block block;
    
        public void run() {
            BlockFace direction = ((Directional) block.getType().getNewData(block.getData())).getFacing();
            //Do some other stuff with it here
        }
    
    }
    Code:
    plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new FurnacePlacementTask(event.getBlockPlaced()), 0L);
     
  12. Offline

    Diogyn

    Yep, thanks a lot. It's what I needed.
     
  13. Offline

    Junrall

    Dusting off an old thread!

    Is it possible to set the direction of a portal block? And if so, how would I go about it?

    Thanks!
     
  14. Offline

    Shamebot

    No it's not possible, the client calculates the direction of a portal block from the position of other portal blocks adjacent to it.
     
  15. Offline

    Junrall

    Ah... good to know. Sounds like this might be something that Spout and Spoutcraft might handle... but not a big enough deal that I want to mess around with.

    Thanks for the input.
     
  16. Offline

    andreasabe

    Thanks for this code, I haven't found anywhere else a explanation like this, where yaw is north...
    I'm using this: (I think it's better)

    Code:
    public enum MyDirections {
            N, E, S, W, U, D, NE, NW, SE, SW, SELF;
    }
     
        private MyDirections getDirection(Location l) {
            return getDirection(l, true);
        }
     
        private static MyDirections getDirection(Location l, boolean useSubCardinalDirections) {
            float pitch = normalAngle(l.getPitch());
            if (pitch > 60) {
                return MyDirections.U;
            } else if (pitch < -60) {
                return MyDirections.D;
            }
            float yaw = normalAngle(l.getYaw());
            if (useSubCardinalDirections) {
                if (-22.5 <= yaw && yaw < 22.5) {
                    return MyDirections.N;
                } else if (22.5 <= yaw && yaw < 67.5) {
                    return MyDirections.NE;
                } else if (67.5 <= yaw && yaw < 112.5) {
                    return MyDirections.E;
                } else if (112.5 <= yaw && yaw < 157.5) {
                    return MyDirections.SE;
                } else if ((157.5 <= yaw && yaw <= 180) || (-180 <= yaw && yaw <= -157.5)) {
                    return MyDirections.S;
                } else if (-157.5 <= yaw && yaw < -122.5) {
                    return MyDirections.SW;
                } else if (-112.5 <= yaw && yaw < -67.5) {
                    return MyDirections.W;
                } else if (-67.5 <= yaw && yaw < -22.5) {
                    return MyDirections.NW;
                } else {
                    return MyDirections.SELF;
                }
            } else {
                if (-45 <= yaw && yaw < 45) {
                    return MyDirections.N;
                } else if (45 <= yaw && yaw < 135) {
                    return MyDirections.E;
                } else if ((135 <= yaw && yaw < 180) || (-180 <= yaw && yaw <= -135)) {
                    return MyDirections.S;
                } else if (-135 <= yaw && yaw < -45) {
                    return MyDirections.W;
                } else {
                    return MyDirections.SELF;
                }
            }
        }
        
        private static float normalAngle(float angle) {
            angle = (angle - 90) % 360;
            angle -= (angle > 180) ? 360 : 0;
            return angle;
    
    Just a question: the yawToFace method above will return to where the player is looking or what face of the block he is looking? Because I need to where he is looking.
    If pitch is 0 (zero) the player is looking to the horizon (right to front of him)?
     
  17. Offline

    bergerkiller

    andreasabe
    First: Why have a MyDirections enum? The BlockFace enum has all the directions you stated up there.

    Second: Player yaw angles differ slightly from the blockface constants, it is a 90 degree difference I believe. Do some simple tests with multiple yaw offsets and inversion (180 - playeryaw) to get the right results.

    Third: The 'SELF' is never returned, as all other angles are already taken account of. There is no 'else' going on, you might as well turn the last if statement of each block into an else.

    And yes, the player yaw is the horizontal angle in degrees to where he is looking. By inverting it you get the opposite, may you need that. (you have to invert if you want to place a sign facing the player)
     
  18. Offline

    andreasabe

    @bergerkiller
    First: I did the enum because I really don't need all the options BlockFace have. I did a clean enum only for this class, thank god I don't need to know the BlockFace.

    Second: I have double checked it and it's right, the code I made give me the right yaw from the player.

    Third: One else more will do no difference for me, and I will try to implement lather for something, I leave there only to not forget it :D.

    Thanks!
    Now I only need to know if the pitch is right. I have too much code to do and no time and guts to test it, will do when I finish it. Don't worry, there is too much getLooger.log(Level.INFO/SEVERE, ...) in my code, so I will not get lost.
     
Thread Status:
Not open for further replies.

Share This Page