1.14.4 Refresh custom GUI's contents

Discussion in 'Spigot Plugin Development' started by i998979, Jun 20, 2020.

  1. So I'm coding a room system where player can join/leave and invite new players to the room and have fun.
    But I'm stuck in refreshing the menu when the contents changed

    For example, A is viewing MenuGUI, which shows all available rooms. B created a new room, B's new room was added to the list.
    A's MenuGUI should be updated with B's new room in the list

    Another example, A is viewing RoomInfoGUI, which shows which players are in the room, their online state. B has been removed from the room.
    A's gui content should be updated as B is no longer in the room.

    So what's the best way to update player's custom gui's contents like this?

    Abstract class MythicGUI
    (The code inside #update looks so dumb but I can't think of any alternatives)
    Code (Java):
    public abstract class MythicGUI {

        public static HashMap<UUID, MythicGUI> openedInv = new HashMap<>();
       
        Inventory inv;
       
        public MythicGUI(int size, String title) {
            this.inv = Bukkit.createInventory(new MythicHolder(this), size, ChatColor.translateAlternateColorCodes('&', title));
        }
       
        public Inventory getInventory() {
            return inv;
        }
       
        public void setItem(int slot, ItemStack stack) {
            inv.setItem(slot, stack);
        }
       
        // TODO - Update all player that is opening the same inventory
        public void open(Player player) {
            // TODO - Reuse old Inventory where possible
            player.openInventory(inv);
            openedInv.put(player.getUniqueId(), this);
        }
       
        public void update(MythicGUI mythicgui) {
            for (Map.Entry<UUID, MythicGUI> entry : openedInv.entrySet()) {
                UUID uuid = entry.getKey();
                MythicGUI openedGui = entry.getValue();
               
                Player player = Bukkit.getPlayer(uuid);
               
                if (mythicgui.equals(openedGui)) {
                    if (mythicgui instanceof MenuGUI) {
                        MenuGUI gui = (MenuGUI) mythicgui;
                        MenuGUI menugui = new MenuGUI(Bukkit.getPlayer(uuid), gui.sorting, gui.searching, gui.page);
                        menugui.open(player);
                    }
                    if (mythicgui instanceof RoomGUI) {
                        RoomGUI gui = (RoomGUI) mythicgui;
                        RoomGUI roomgui = new RoomGUI(Bukkit.getPlayer(uuid), gui.room, gui.page);
                        roomgui.open(player);
                    }
                    if (mythicgui instanceof InviteGUI) {
                        InviteGUI gui = (InviteGUI) mythicgui;
                        InviteGUI invitegui = new InviteGUI(gui.room, gui.page);
                        invitegui.open(player);
                    }
                   
                    Bukkit.getPlayer(uuid).openInventory(inv);
                    Bukkit.broadcastMessage("Updated");
                }
            }
        }
       
        public void close(Player player) {
            player.closeInventory();
            openedInv.remove(player.getUniqueId());
        }
       
        /**
         * Return player's opened MythicGUI
         * @param player Player to get
         * @return Player's opened MythicGUI, null if none
         */

        public MythicGUI get(Player player) {
            return openedInv.get(player.getUniqueId());
        }
       
        public void onClick(InventoryClickEvent event) {}
        public void onOpen(InventoryOpenEvent event) {}
        public void onClose(InventoryCloseEvent event) {}
    }
    CreateGUI which let players create a new room
    Code (Java):
    ]public class CreateGUI extends MythicGUI {
       
        ItemStack pane;
        ItemStack min;
        ItemStack max;
        ...
       
        DungeonGroup group;
        UUID uuid;
        Room room;
       
        public CreateGUI(DungeonGroup group, UUID uuid) {
            super(45, "Creating " + group.getName() + "&r room...");
           
            this.group = group;
            this.uuid = uuid;
           
            this.room = new Room(plugin.getRoomManager().getNext(), group.getType(), uuid);
           
            this.room.setPrivacy(RoomPrivacy.PUBLIC);
            this.room.setMin(group.getMinPlayer());
            this.room.setMax(group.getMaxPlayer());
           
            ...
           
            setItem(10, this.min);
            setItem(12, this.max);
            setItem(14, this.public0);
            setItem(15, this.password);
            setItem(16, this.private0);
            // setItem(20, this.type);
            setItem(37, this.cancel);
            setItem(43, this.create);
        }
       
       
        @Override
        public void onClick(InventoryClickEvent event) {
            event.setCancelled(true);
           
            ItemStack clicked = event.getCurrentItem();
            Player clicker = (Player) event.getWhoClicked();
            UUID uuid = clicker.getUniqueId();
            ClickType click = event.getClick();
           
            if (clicked.isSimilar(min)) {
                ...
            }
            else if (clicked.equals(public0)) {
                room.setPrivacy(RoomPrivacy.PUBLIC);
                public0 = new ItemBuilder(public0).setGlow(true).toItemStack();
                password = new ItemBuilder(password).setGlow(false).toItemStack();
                private0 = new ItemBuilder(private0).setGlow(false).toItemStack();
                setItem(14, this.public0);
                setItem(15, this.password);
                setItem(16, this.private0);
                setItem(24, null);
            }
            ...
            /*else i
        }
     
    #1 i998979, Jun 20, 2020
    Last edited: Jun 20, 2020
  2. Why not make global instances of the inventories. Have 1 inventory for holding all the room info and update the single inventory. ItemStacks are mutable and when mutated send proper packets to their viewers/handlers. So what you can do is modify the item, and that's it, or you can modify the item, and do something like "inventory.setItem(i, inventory.getItem(i))" to force the packet out
     
  3. This is a good idea but it breaks page-switching as everyone is watching the same gui, if one of the player switched page, everyone switch as well, so I would prefer player-dependent guis
     
  4. You don't have to do it that way, 1 inventory per page.
     
  5. Same issue, everyone is looking at the same inventory.
     
  6. It is kinda dumb if 1 inventory per page. Why don't I do per-player inventory for more flexibility?
     
  7. Why is that an issue? He's trying to display proper updates to everyone isn't he?

    What kind of flexibility are you looking for?
     
  8. You have to recreate the items that you want when the user clicks them