Sign protection

Discussion in 'Plugin Development' started by 9903286, Jan 31, 2012.

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

    9903286

    If i wanna make a plugin that makes so that only the player on the second line can break it, how do i do?
    I am guessing i need an listener for BLOCK_BREAK?
     
  2. Offline

    Steeveeo

    Under the new system, something like the following should work:

    Code:java
    1.  
    2. class SignProtectListener implements Listener
    3. {
    4. @EventHandler(priority = EventPriority.LOWEST)
    5. public void onBlockBreak(BlockBreakEvent event)
    6. {
    7. if(event.isCancelled()){return;}
    8.  
    9. if(event.getBlock().getState() instanceof Sign)
    10. {
    11. Player player = event.getPlayer();
    12. Sign sign = (Sign)event.getBlock().getState();
    13. if(!player.getName().equalsIgnoreCase(sign.getLine(1)))
    14. {
    15. event.setCancelled(true);
    16. }
    17. }
    18. }
    19. }
    20.  


    Note, I wrote that in the thread reply box, so remember to add any dependencies and check for errors. I do not guarantee that it works 100%, but it's worth a shot.

    EDIT:
    Also, you would need something like this in your JavaPlugin class:

    Code:java
    1.  
    2. getServer().getPluginManager().registerEvents(new SignProtectListener(), this);
    3.  
     
    9903286 likes this.
  3. Offline

    9903286

    Thank you, everything worked except that you forgot to add an (), but like you said, you did it without help from eclipse.
     
  4. Offline

    Steeveeo

    Hah. I'm so used to hitting "Down-Enter" when typing partial member/method names that sometimes I just forget proper conventions. :p

    BTW, you might try an OR (||) on that name check expression and see if it matches player.getDisplayName() as well, so users can put in either account or nickname on a server and still be correct.
     
  5. Offline

    9903286

    Thanks, but.. How do i do so that the block behind the sign (or under), can't get destroyed?
     
  6. In the listener you could check around the block for a sign
    and then check if it is attached to the block with
    Code:
    BlockFace face = sign.getAttachedFace();
    signBlock.getRelative(face); //get the block the sign is attached to
     
  7. Offline

    9903286

    Uhm, could you please add it for me? I have no idea where i should add it, and "sign.getAttachedFace();" just gives me an error.. Here is the code:

    Code:
    class SignProtectListener implements Listener {
    
        @EventHandler
        public void onBlockBreak(BlockBreakEvent event)
            {
                if(event.isCancelled()){return;}
     
                if(event.getBlock().getState() instanceof Sign)
                {
                    Player player = event.getPlayer();
                    Sign sign = (Sign)event.getBlock().getState();
                    String[] signText = sign.getLines();
                    
                    if(player.getName() == signText[1] && signText[0].equals("[XP Sign]")) {
                        
                        int SignLevel = Integer.parseInt(signText[3]);
                        int PLevel = player.getLevel();
                        int pLevel = PLevel + SignLevel;
                        
                        player.setLevel(pLevel);
                        
                        player.sendMessage(ChatColor.DARK_RED + "You just destroyed your XP bank!");
                        
                    } else if(player.getName() != signText[1] && signText[0].equals("[XP Sign]")) {
                        event.setCancelled(true);
                        sign.update();
                    } else {
                        }
                    }
                }
            }
    
    Could someone help me with this, i can't get the block to be protected.. :(

    I'll take that as a no...

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 23, 2016
  8. Offline

    Father Of Time

    We will assist you with correcting your code, but it's unlikely that anyone will do it for you, that's just counter productive to your learning. The best thing for you to do is just try and see what happens... It's not like you can't undo your code changes. Once you try and fail you will have example code for us to point out "this is wrong", or "you did this perfect".

    Steps to solve your issue:
    1) on block break event get relative blocks for N/S/E/W/UP/
    2) check to see if any of those blocks are signs
    3) cast the sign block as org.bukkit.material.Sign
    3) get the block that sign is attached to with BlockFace org.bukkit.material.Sign.getAttachedFace
    4) if the block being broken in the event equals the block the sign is attached to cancel the break event.

    Also, on a side note... There are several other ways signs can be broken and that need to be taken into account (I found this out the hard way when making my shop plugin). A few examples are Explosions and Pistons.
     
    9903286 likes this.
  9. Offline

    9903286

    I'll try this out, but i wan't it to get destroyed by some things, but not a piston, i'll try to fix that when I've tried this.

    EDIT: There is one problem... I have NO IDEA how to get the block that the sign is attached to... Or actually, i have no idea how to getRelative(), cause when i do it, it's just gives me error:
    Code:
    The method getRelative() is undefined for the type Sign
     
  10. Offline

    Steeveeo

    That's because getRelative() is a method of Block, and Sign extends BlockState. Either store the sign block beforehand or use sign.getBlock().
     
  11. Offline

    9903286

    I'm getting confused by all this...
    I think i just made it worse:
    Code:
               
    Sign sign = (Sign)event.getBlock().getState();
    Block signblock = sign.getBlock();
    BlockFace signface = event.getBlock();
    signblock.getRelative(signface);
    
     
  12. Offline

    Steeveeo

    BlockFace signface = event.getBlock();

    Change that to just "Block signBlock" and use signBlock.getRelative(X,Y,Z).
     
    9903286 likes this.
  13. Offline

    9903286

    Well, i tried doing this:
    Code:
                int X = 0;
                int Y = 0;
                int Z = 0;
               
                Sign sign = (Sign)event.getBlock().getState();
                Block signBlock = event.getBlock();
     
                if(event.getBlock().getLocation().equals(signBlock.getRelative(X, Y, Z))) {
                   
                    event.setCancelled(true);
                    sign.update();
                   
                }
    But it just gives me error in console:
    Code:
    [SEVERE] Could not pass event org.bukkit.event.block.BlockBreakEvent to XPSIGN
    org.bukkit.event.EventException
        at org.bukkit.plugin.java.JavaPluginLoader$103.execute(JavaPluginLoader.java:1026)
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:57)
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:453)
        at net.minecraft.server.ItemInWorldManager.breakBlock(ItemInWorldManager.java:216)
        at net.minecraft.server.ItemInWorldManager.a(ItemInWorldManager.java:171)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:510)
        at net.minecraft.server.Packet14BlockDig.handle(SourceFile:43)
        at net.minecraft.server.NetworkManager.b(NetworkManager.java:226)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:100)
        at net.minecraft.server.NetworkListenThread.a(NetworkListenThread.java:78)
        at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:537)
        at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:435)
        at net.minecraft.server.ThreadServerApplication.run(SourceFile:465)
    Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.bukkit.plugin.java.JavaPluginLoader$103.execute(JavaPluginLoader.java:1024)
        ... 12 more
    Caused by: java.lang.ClassCastException: org.bukkit.craftbukkit.block.CraftBlockState cannot be cast to org.bukkit.block.Sign
        at com.thedevils.at.ua.xpsign.SignProtectListener.onBlockBreak(SignProtectListener.java:22)
        ... 17 more
     
  14. Offline

    rolf_smit

    Code:
    [SEVERE] Could not pass event org.bukkit.event.block.BlockBreakEvent to XPSIGN
     
    More stuff here!
     
    Caused by: java.lang.ClassCastException: [B]org.bukkit.craftbukkit.block.CraftBlockState cannot be [COLOR=#ff0000][U]cast[/U][/COLOR] to org.bukkit.block.Sign[/B]
        at com.thedevils.at.ua.xpsign.SignProtectListener.onBlockBreak(SignProtectListener.java:22)
        ... 17 more
    What i think is:

    Sign sign = (Sign)event.getBlock().getState();

    So on this line you use a not valid cast, i don't have Experience with signs but i think you should first check if the block that you destroy/click is a sing or not. If so cast it to a Sign object.

    Not sure but now trying it for my self.

    Rolf



    What Sign import are you using?

    Right one:
    import org.bukkit.block.Sign;

    False one:
    import org.bukkit.material.Sign;

    The following code worked on my server in a click event (using the right import, the other import gave me the same error as you)

    if(event.getClickedBlock().getType() == Material.SIGN_POST){
    Sign sign = (Sign) event.getClickedBlock().getState();
    event.getPlayer().sendMessage("Sign line 1: " + sign.getLine(1));
    }


    [​IMG]
    Ignore the Biome line, its a test i use for a plugin i'm developing.


    Rolf

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 23, 2016
  15. Offline

    9903286

    I am using, "import org.bukkit.block.Sign;" but that code, what does that have to do with getting the block that the sign is attached to?
     
  16. Offline

    rolf_smit

    Because the error you posted had to do with the sign part.

    Rolf
     
  17. Offline

    9903286

    That i'll fix later, right now all i'm looking for is how to get the block that the sign is attached to.

    Well, it doesn't seem like i'm going to get this. So i'll give up, the sign is protected, but the block won't be... :(

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 23, 2016
  18. Offline

    rolf_smit

    Which block do you want to be protected, the block behind it and to block under it?

    Code:
     @EventHandler(priority = EventPriority.NORMAL)
    public void onBlockBreak(BlockBreakEvent event){
    Block block = event.getBlock();
    Material type = block.getType();
     
    //check if destroyed block is a sign
    if(type == Material.WALL_SIGN || type == Material.SIGN_POST){
    Sign sign = (Sign) block.getState();
     
    //You may want to add to lowercase function
    if(!event.getPlayer().getName().equals(sign.getLine(1))){
    //player name is not equal to the one on the sign
    event.setCancelled(true);
    return;
    } else {
    //if the sign is the players sign just remove it and stop checking the blocks around it because a sign can't support any thing else.
    return;
    }
    }
     
     
    //Check blocks around destroyed block for signs
    for(BlockFace face: faces){
    type = block.getRelative(face).getType();
     
    //if sign found
    if(type == Material.WALL_SIGN || type == Material.SIGN_POST){
     
    //check the found sign for the players name.
    Sign sign = (Sign) block.getRelative(face).getState();
    //You may want to add to lowercase function
    if(!event.getPlayer().getName().equals(sign.getLine(1))){
     
    //player name is not equal to the one on the sign
    event.setCancelled(true);
    return;
    }
    }
    }
    return;
    }
    And add this BlockFace array to you class:

    Code:
    private static final BlockFace[] faces =  new BlockFace[]{BlockFace.UP, BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST};
    
    There you go, tested it at my own server and it works.

    Btw: A block can have more than one sign around it, when 2 players add signs to one block both can not remove it. Before players place a sign you should check if there is already a sign. A solution for both players would be: One player has to remove his sign first, but that would mean that only the other player is capable of breaking to block under it. I'm not sure how you going to use signs but depending on what you want you should be checking some of the above stuff.

    Example image down: 2 players, 2 signs and one block. Both players can't remove the block, but they can remove there own signs.

    [​IMG]



    Rolf

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 23, 2016
  19. Offline

    9903286

    Well, if it's a wall sign, i want the block that it's on to be protected, but if it's on the ground, then i want the block it stands on to be protected.
     
  20. Offline

    rolf_smit

    You where a moment to late posting this =)
     
  21. Offline

    9903286

    I saw that, i'll be testing it soon.

    EDIT: Everything works except for this part:
    Code:
        for(BlockFace face:faces){
    ERROR: faces cannot be resolved to a variable
     
  22. Offline

    Father Of Time

    You should never give up bro, half the fun of programming is the joy of overcoming a problem. I don't like to see new programmers struggling, so I've decided to put together a demo of how to handle your request. Please note that I wrote this in notepad at work, so it likely has little typos that will need tweaking, but the concept should be sound.

    Code:
    class SignProtectListener implements Listener
    {
        @EventHandler
        public void onBlockBreak(BlockBreakEvent event)
        {
            boolean CancelEvent = false;
            Block eventblock = event.getBlock();
            List<Block> relativeblocks = new ArrayList<Block>();
     
            relativeblocks.add( eventblock.getRelative( BlockFace.NORTH );
            relativeblocks.add( eventblock.getRelative( BlockFace.SOUTH );
            relativeblocks.add( eventblock.getRelative( BlockFace.EAST );
            relativeblocks.add( eventblock.getRelative( BlockFace.WEST );
            relativeblocks.add( eventblock.getRelative( BlockFace.UP );
     
            for( int i = 0; i < relativeblocks.size(); i++ )
            {
                Block toinspect = relativeblocks.get(i);
               
                if( eventblock.getMaterial == Material.WALL_SIGN || eventblock.getMaterial == Material.SIGN_POST )
                {
                    org.bukkit.material.Sign sign = (org.bukkit.material.Sign)toinspect.getState();
                    BlockFace attacheddir = sign.getAttachedFace();
                    Block attachedto = toinspect.getRelative( attacheddir );
                    if( eventblock.equals( attachedto );
                    {
                        CancelEvent = true;
                        break;
                    }
                }
            }
     
            if( CancelEvent ) // if this is triggered the block you are breaking has a sign attached to it, so cancel
                event.setCancelled( true );
        }
    }
    This may not be the most efficient way of doing it, but it's enough to get you moving forward. Also, it's important to understand the difference between Block.Sign and Material.Sign, they both contain different functions and you need to pay very close attention to which you are casting. For instance if you want to get what block the sign is attached to you would use Block.Sign, but if you want to change the text on the sign you use Material.Sign... Confusing I know, but vital when working with signs. You can read about the differences here:

    Material:
    http://jd.bukkit.org/doxygen/d5/da4/classorg_1_1bukkit_1_1material_1_1Sign.html

    Block:
    http://jd.bukkit.org/doxygen/db/d26/interfaceorg_1_1bukkit_1_1block_1_1Sign.html

    Good luck with your project, I hope this helps!
     
    9903286 likes this.
  23. Offline

    rolf_smit

    Creating a new list for every block break wouldn't be very efficient =)
    So your pretty right when saying its not the best way.

    And instead of using break + boolean etc you could use

    event.setCanceled(true);
    return;

    Rolf
     
    9903286 likes this.
  24. Offline

    9903286

    Did you read my last post?
    EDIT: My bad. (lol)
     
  25. Offline

    Father Of Time

    Well, you could use a Set instead of list, you could limit the set size to 5 since you know the overall count each time, and you can put the set initialization outside of the block break event and continually use the same set... Seems a bit nit picking to me...

    I'm sorry but as I said I wrote this in 20 seconds free hand and I wasn't exactly focusing on code efficiency, more proof of concept and showing the OP how to implement the methods hes been requesting.
     
    9903286 likes this.
  26. Offline

    rolf_smit

    I don't blame you;)
     
  27. Offline

    9903286

    Uhm, with your code... I've got a small problem, is there ANY way to check the block that is in front of the sign, cause right now you can block it totally..?
     
  28. Offline

    Father Of Time

    You sure can, check this out:

    http://jd.bukkit.org/doxygen/d5/da4/classorg_1_1bukkit_1_1material_1_1Sign.html

    Material.Block has a function called getFacing()

    Code:
    BlockFace org.bukkit.material.Sign.getFacing ()
    Which returns a blockface of the direction the sign is facing. So simply do something like this:

    Code:
        BlockFace signdir = sign.getFacing();        // use Material.Sign
        Block frontofsign = sign.getRelative( signdir ); // use the Block.Sign
    which will result in the local variable "frontofsign" being the block directly in front of the sign, and by front I mean in the direction the words on the sign are currently facing.

    I hope this helps, good luck!
     
  29. Offline

    9903286

    The getFacing() and getRelative() just gives me: The method "getFacing()/getRelative()" is undefined for the type Sign.
     
  30. Offline

    Father Of Time

    That is because you are casting sign incorrectly. Block, Material.Sign and Block.Sign all have different functions inside them. It's not the object that you are working with that has the functions, its the class that you cast the object as. Look at the comments in the code below (sampled from above):

    Code:
        BlockFace signdir = sign.getFacing();        // use Material.Sign
        Block frontofsign = sign.getRelative( signdir ); // use the Block.Sign
    To get the facing you need to cast your block as org.bukkit.Material.Sign, however, to get the relative block you need to cast your block as block.

    It's confusing, I know... It sounds like you need to do a little reading on object casting and how to externally access functions in a class. The answer is in the previous post, you just need to review how you are casting your objects and make sure they are being casted to the appropriate type.

    Good luck with your project!

    Edit: again, look at these two links, they tell you what functions are contained in Block.Sign and what functions are contained in Material.Sign, they are two entirely different classes.

    Material sign:
    http://jd.bukkit.org/doxygen/d5/da4/classorg_1_1bukkit_1_1material_1_1Sign.html

    Block sign:
    http://jd.bukkit.org/doxygen/db/d26/interfaceorg_1_1bukkit_1_1block_1_1Sign.html
     
Thread Status:
Not open for further replies.

Share This Page