Save and load a GUI to the config

Discussion in 'Plugin Development' started by Teotia444, Jan 11, 2022.

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

    Teotia444

    Hello,
    I am currently making a plugin for our SMP. The goal would be to share enderchests. I managed to do the system where you chose with who you share the ender chest but not the saving stuff. I use a different GUI for the enderchest as it's 54 blocks. So I here is my code :
    For the onEnderChestOpen
    Code:
    package com.teotia444.customsmp.events;
    
    import com.teotia444.customsmp.CustomSMP;
    import com.teotia444.customsmp.inventories.SharedEC;
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.Material;
    import org.bukkit.Sound;
    import org.bukkit.entity.HumanEntity;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.Action;
    import org.bukkit.event.inventory.*;
    import org.bukkit.event.player.PlayerInteractEvent;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.scheduler.BukkitRunnable;
    
    import java.util.List;
    
    public class EnderChestOpenEvent implements Listener{
    
        static CustomSMP plugin;
    
        public EnderChestOpenEvent(CustomSMP plugin){
            this.plugin = plugin;
        }
    
        @EventHandler
        public static void onEnderChestOpened(PlayerInteractEvent event){
            Player player = event.getPlayer();
            String root = plugin.getConfig().getString("ec.team." + player.getName());
            SharedEC ec = new SharedEC(plugin, root);
            if(event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getType() == Material.ENDER_CHEST){
                new BukkitRunnable() {
                    @Override
                    public void run() {
                        player.closeInventory();
                        player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_LAND, 1, 1);
                    }
                }.runTaskLater(plugin, 1);
                new BukkitRunnable() {
                    @Override
                    public void run() {
                        player.openInventory(ec.getInventory());
                    }
                }.runTaskLater(plugin, 1);
            }
        }
        @EventHandler
        public static void onEnderChestClosed(InventoryCloseEvent event){
            new BukkitRunnable(){
                @Override
                public void run() {
                        Player player = (Player) event.getView().getPlayer();
                        String root = plugin.getConfig().getString("ec.team." + player.getName()); //root is the team name of the player
                        if(event.getView().getTitle().equals("Shared Ender Chest")){ //saving the gui in config here
                        }}
            }.runTaskLaterAsynchronously(plugin, 2);
        }
    }
    
    
    and here is the enderchest gui code :
    Code:
    package com.teotia444.customsmp.inventories;
    
    import com.teotia444.customsmp.CustomSMP;
    import org.bukkit.Bukkit;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.InventoryHolder;
    import org.bukkit.inventory.ItemStack;
    
    import java.util.*;
    
    
    public class SharedEC implements InventoryHolder {
    
        private Inventory ec;
    
        public SharedEC(CustomSMP plugin, String team){
            ec = Bukkit.createInventory(this, 54, "Shared Ender Chest");
            setEc(plugin, team);
        }
    
        public SharedEC(){
            ec = Bukkit.createInventory(this, 54, "Shared Ender Chest");
        }
    
        public void setEc(CustomSMP plugin, String root){
    // here would be the load by config stuff
        }
    
    
        @Override
        public Inventory getInventory() {
            return ec;
        }
    }
    
    I would want an idea on how I can do it, on even maybe some code showing how to do it.
    Thank you
     
  2. Offline

    The_Spaceman

    Code:java
    1. //to save inventory content
    2. getConfig().set(path + ".content", inventory.getContents());
    3.  
    4. //this is an implementation to get the content I've used a long time ago (should still work)
    5. private Inventory getInventory(String path) {
    6. Inventory inv = Bukkit.createInventory(null, 18, NAME);
    7.  
    8. if (!getConfig().contains(path)) {
    9. return inv;
    10. }
    11.  
    12. List<?> content = getConfig().getList(path + ".content");
    13. if (content != null) {
    14. for (int i = 0; i < content.size(); i++) {
    15. Object o = content.get(i);
    16. if (o != null) {
    17. if (o instanceof ItemStack item) {
    18. inv.setItem(i, item);
    19. }
    20. }
    21. }
    22. }
    23. return inv;
    24. }


    Its better to cancel the PlayerInteractEvent than using the Runnables. Something like this:
    Code:java
    1. @EventHandler
    2. public static void onEnderChestOpened(PlayerInteractEvent event) {
    3. Player player = event.getPlayer();
    4. if(event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getType() == Material.ENDER_CHEST) {
    5. Inventory inv = Bukkit.createInventory(null, 54, "Shared Ender Chest");
    6. inv.addItem(new ItemStack(Material.STONE));
    7.  
    8. player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_LAND, 1, 1);
    9. player.openInventory(inv);
    10. event.setCancelled(true);
    11. }
    12. }
    13.  
     
  3. Offline

    Teotia444

    Thanks for the advice. It really helped me out. I still have problems to load : First time I load it's loading correctly but then the content list is null. This happens whenever I save using the GUI, and then re-open it
    Any advice?
    thanks
     
  4. Offline

    The_Spaceman

    at the end do you use 'saveConfig()'? If not, try that. Otherwise I don't know why its set to null.
    Can you post what you have?
     
  5. Offline

    Teotia444

    Ok, then here is in detail what I did : When I open the ender chest, it shows correctly the chest and it's content. Then I pick up some stuff, get off of the chest (where it saves AND use saveConfig) and try to re-open it I got this error :
    Code:
    [14:41:12] [Server thread/ERROR]: Could not pass event PlayerInteractEvent to CustomSMP v0.1
    java.lang.NullPointerException: Cannot invoke "java.util.List.size()" because "content" is null
        at com.teotia444.customsmp.events.EnderChestOpenEvent.getInventory(EnderChestOpenEvent.java:65) ~[CustomSMP.jar:?]
        at com.teotia444.customsmp.events.EnderChestOpenEvent.onEnderChestOpened(EnderChestOpenEvent.java:39) ~[CustomSMP.jar:?]
        at com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor.execute(StaticMethodHandleEventExecutor.java:38) ~[paper-api-1.18.1-R0.1-SNAPSHOT.jar:?]
        at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:80) ~[paper-api-1.18.1-R0.1-SNAPSHOT.jar:git-Paper-140]
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[paper-api-1.18.1-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:628) ~[paper-api-1.18.1-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.craftbukkit.v1_18_R1.event.CraftEventFactory.callPlayerInteractEvent(CraftEventFactory.java:543) ~[paper-1.18.1.jar:git-Paper-140]
        at net.minecraft.server.level.ServerPlayerGameMode.useItemOn(ServerPlayerGameMode.java:540) ~[?:?]
        at net.minecraft.server.network.ServerGamePacketListenerImpl.handleUseItemOn(ServerGamePacketListenerImpl.java:1838) ~[?:?]
        at net.minecraft.network.protocol.game.ServerboundUseItemOnPacket.handle(ServerboundUseItemOnPacket.java:33) ~[?:?]
        at net.minecraft.network.protocol.game.ServerboundUseItemOnPacket.a(ServerboundUseItemOnPacket.java:9) ~[?:?]
        at net.minecraft.network.protocol.PacketUtils.lambda$ensureRunningOnSameThread$1(PacketUtils.java:56) ~[?:?]
        at net.minecraft.server.TickTask.run(TickTask.java:18) ~[paper-1.18.1.jar:git-Paper-140]
        at net.minecraft.util.thread.BlockableEventLoop.doRunTask(BlockableEventLoop.java:149) ~[?:?]
        at net.minecraft.util.thread.ReentrantBlockableEventLoop.doRunTask(ReentrantBlockableEventLoop.java:23) ~[?:?]
        at net.minecraft.server.MinecraftServer.doRunTask(MinecraftServer.java:1413) ~[paper-1.18.1.jar:git-Paper-140]
        at net.minecraft.server.MinecraftServer.c(MinecraftServer.java:189) ~[paper-1.18.1.jar:git-Paper-140]
        at net.minecraft.util.thread.BlockableEventLoop.pollTask(BlockableEventLoop.java:122) ~[?:?]
        at net.minecraft.server.MinecraftServer.pollTaskInternal(MinecraftServer.java:1391) ~[paper-1.18.1.jar:git-Paper-140]
        at net.minecraft.server.MinecraftServer.pollTask(MinecraftServer.java:1384) ~[paper-1.18.1.jar:git-Paper-140]
        at net.minecraft.util.thread.BlockableEventLoop.managedBlock(BlockableEventLoop.java:132) ~[?:?]
        at net.minecraft.server.MinecraftServer.waitUntilNextTick(MinecraftServer.java:1362) ~[paper-1.18.1.jar:git-Paper-140]
        at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1268) ~[paper-1.18.1.jar:git-Paper-140]
        at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:317) ~[paper-1.18.1.jar:git-Paper-140]
        at java.lang.Thread.run(Thread.java:833) ~[?:?]
    along with the regular ender chesr, and for the code :
    Code:
    package com.teotia444.customsmp.events;
    
    import com.teotia444.customsmp.CustomSMP;
    import com.teotia444.customsmp.inventories.SharedEC;
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.Material;
    import org.bukkit.Sound;
    import org.bukkit.entity.HumanEntity;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.Action;
    import org.bukkit.event.inventory.*;
    import org.bukkit.event.player.PlayerInteractEvent;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.scheduler.BukkitRunnable;
    
    import java.util.List;
    import java.util.Objects;
    
    public class EnderChestOpenEvent implements Listener{
    
        static CustomSMP plugin;
    
        public EnderChestOpenEvent(CustomSMP plugin){
            this.plugin = plugin;
        }
    
        @EventHandler
        public static void onEnderChestOpened(PlayerInteractEvent event){
            Player player = event.getPlayer();
    
            if(event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getType() == Material.ENDER_CHEST){
                String root = plugin.getConfig().getString("ec.team." + player.getName());
    
                player.playSound(player.getLocation(), Sound.BLOCK_ENDER_CHEST_OPEN, 1, 1);
                Inventory inv = getInventory("ec." + root);
    
                player.openInventory(inv);
                event.setCancelled(true);
            }
        }
        @EventHandler
        public static void onEnderChestClosed(InventoryCloseEvent event){
            Player player = (Player) event.getView().getPlayer();
            String root = plugin.getConfig().getString("ec.team." + player.getName());
            if(event.getView().getTitle().equals("Shared Ender Chest")){
                plugin.getConfig().set("ec."+ root + ".content", event.getInventory().getContents());
                plugin.saveConfig();
                player.playSound(player.getLocation(), Sound.BLOCK_ENDER_CHEST_CLOSE, 1, 1);
            }
        }
    
        private static Inventory getInventory(String path) {
            plugin.getServer().getConsoleSender().sendMessage(path);
            Inventory inv = Bukkit.createInventory(null, 54, "Shared Ender Chest");
    
            if (!plugin.getConfig().contains(path)) {
                return inv;
            }
    
            List<?> content = plugin.getConfig().getList(path + ".content");
            if (content != null) {
                for (int i = 0; i < content.size(); i++) {
                    Object o = content.get(i);
                    if (o != null) {
                        if (o instanceof ItemStack item) {
                            inv.setItem(i, item);
                        }
                    }
                }
            }
            return inv;
        }
    }
    
    
    I tried to tweak some things with no success...
    Thanks for the help
     
  6. Offline

    The_Spaceman

    That's weird.
    You get a NullPointerException after you check if that object is not null. You sure this error log is from this code?
     
  7. Offline

    Teotia444

    Ok, After a LOT of research I got where the problem comes. Whenever I save something in the config I think my "plugin" reference variable somehow get screwed, making it no longer work properly. I Can solve this by using saveConfig() and loadConfig() directly but unfortunately I need this variable that got screwed in order to use these. Can you tell me how I Can use these without using my previous variable? (Maybe an implement?)
    Thanks
     
  8. Online

    timtower Administrator Administrator Moderator

  9. Offline

    Teotia444

    In order to use a variable in a static function (here the two functions to save and load stuff) I need to make the variable static. The void I use needs (i think) to be static in order to handle the event. Can I use a non-static void/variable?
     
  10. Online

    timtower Administrator Administrator Moderator

    @Teotia444 Nothing in there has to be static.
    Methods don't need static to work.
    Heck, for nothing in Bukkit you need static.
     
    Last edited: Jan 25, 2022
  11. Offline

    Teotia444

    Well, then this tutorial guy was lying! I'll try to pass static off of the method / variable when I will be to house. Thanks for the help so far! Just a little question : is it possible to use config method without using any variable? I've seen many pepoles telling to use saveConfig and not plugin.saveConfig, so I was wondering.
     
  12. Online

    timtower Administrator Administrator Moderator

    @Teotia444 That is when the config handling is done in the main class. Then you can do that.
    And the tutorial guy was lying bigtime. The only thing that you need is the @EventHandler and registering the listener
     
Thread Status:
Not open for further replies.

Share This Page