Issues with Sign GUI (ProtocolLib)

Discussion in 'Plugin Development' started by Tim_M, Jul 22, 2021.

  1. Offline

    Tim_M

    Hello, I am trying to make a Sign Editor that asks a players to enter some information. I have found multiple tutorials on how to achieve this, however none of them provided on how to set some default text (so that when a players gets the menu the sign editor isn't empty but has text already).

    Here's my current code, how should I modify it to get the result I need?
    Code:
        void openSign(Player player, String[] defaults)
        {
            PacketContainer container = Main.pm.createPacket(PacketType.Play.Server.OPEN_SIGN_EDITOR);
    
            try
            {
                //Main.pm is basically ProtocolLibrary.getProtocolManager()
                Main.pm.sendServerPacket(player,container);
            }
    
            catch(InvocationTargetExceptione)
            {
                e.printStackTrace();
            }
        }
    
    UPDATE1
    I haven't been just lazing around, and tried a couple of things. I changed my code to:
    Code:
    void openSign(Player player, String[] defaults)
        {
            WrappedChatComponent[] lines = new WrappedChatComponent[4];
        
            for (int i = 0; i < 4; i++)
            {
                lines[i] = WrappedChatComponent.fromText(defaults[i]);
            }
        
            PacketContainer container = Main.pm.createPacket(PacketType.Play.Server.OPEN_SIGN_EDITOR);
            container.getChatComponentArrays().write(0, lines);
        
            try
            {
                Main.pm.sendServerPacket(player, container);
            }
            catch (InvocationTargetException e)
            {
                e.printStackTrace();
            }
        }
    
    But sadly this just drops a FieldAccessException so this is a dead end. I have no idea what to do now.

    UPDATE2
    The PacketType.Play.Server.OPEN_SIGN_EDITOR does not appear to have any writable Strings, StringArrays, IChatBaseComponents, so maybe using something else is required.

    UPDATE3
    I have been trying all night and here's my current code:
    Code:
    @SuppressWarnings("deprecation")
        void openSign(Player player, String[] defaults)
        {
            //TODO
            player.getLocation().getBlock().setType(Material.SIGN_POST);
            WrappedChatComponent[] lines = new WrappedChatComponent[4];
           
            try 
            {
                Sign s = (Sign) player.getLocation().getBlock().getState();
                Field sign = s.getClass().getDeclaredField("sign");
                sign.setAccessible(true);
                Object tileEntity = sign.get(s);
                Field editable = tileEntity.getClass().getDeclaredField("isEditable");
                editable.set(tileEntity, true);
                Field owner = tileEntity.getClass().getDeclaredField("h");
                owner.setAccessible(true);
               
                Method getHandle = player.getClass().getMethod("getHandle");
                Object nmsPlayer = getHandle.invoke(player);
               
                owner.set(tileEntity, nmsPlayer);
            } 
            catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e1) 
            {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
           
           
            for (int i = 0; i < 4; i++)
            {
                lines[i] = WrappedChatComponent.fromText(defaults[i]);
            }
           
            int x, y, z;
            x = (int) player.getLocation().getX();
            y = (int) player.getLocation().getY();
            z = (int) player.getLocation().getZ();
    
            PacketContainer packetBlockChange = Main.pm.createPacket(PacketType.Play.Server.BLOCK_CHANGE);
            //packetBlockChange.getIntegers().write(0, x).write(1, y).write(2, z);
            packetBlockChange.getBlockPositionModifier().write(0, new BlockPosition(x, y, z));
            //packetBlockChange.getBlocks().write(0, org.bukkit.Material.SIGN_POST);
           
            PacketContainer packetPlayOutSign = new PacketContainer(PacketType.Play.Server.UPDATE_SIGN);
            packetPlayOutSign.getChatComponentArrays().write(0, lines);
            packetPlayOutSign.getBlockPositionModifier().write(0, new BlockPosition(x, y, z));
           
            PacketContainer packetOpenSignEditor = Main.pm.createPacket(PacketType.Play.Server.OPEN_SIGN_EDITOR);
            packetOpenSignEditor.getBlockPositionModifier().write(0, new BlockPosition(x, y, z));
    
            try 
            {
                Main.pm.sendServerPacket(player, packetBlockChange);
               
                Main.pm.sendServerPacket(player, packetPlayOutSign);
                Main.pm.sendServerPacket(player, packetOpenSignEditor);
            } 
            catch (InvocationTargetException e) 
            {
                e.printStackTrace();
            }
        }
    
    This new code causes a (temporary) sign to appear at the player's location which has some text no it. The whole Field stuff is to prevent the warning: Player [name] just tried to change non-editable sign.

    Despite everything it doesn't work how I would like. When the command is ran it drops "Unable to locate sign at X Y Z" in chat. If I place the sign myself and then run the command it works. How can fix this "unable to locate sign" issue. Also, how can I make the sign invisible to people who access the SignGUI.
     
    Last edited: Jul 25, 2021
  2. Offline

    Tim_M

    I have updated lots of stuff in OP so I will
    bump

    Any answers are appreciated.
     
  3. Offline

    Tim_M

    Bump again :/
     

Share This Page