Solved Load Object from a YAML Configuration doesnt work

Discussion in 'Plugin Development' started by Lasslos05, Mar 9, 2021.

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

    Lasslos05

    Hey Guys,
    I`ve got a problem. I want to develop a backpack plugin. However, saving an instance of my backpack class does work, loading doesnt. Here`s my main class:

    Code:
    package de.laslo.minecraftproject;
    
    import de.laslo.minecraftproject.backpack.Backpack;
    import de.laslo.minecraftproject.backpack.BackpackCommand;
    import org.bukkit.Bukkit;
    import org.bukkit.configuration.serialization.ConfigurationSerialization;
    import org.bukkit.plugin.PluginManager;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public final class Main extends JavaPlugin {
    
        private static Main main;
    
        static {
            ConfigurationSerialization.registerClass(Backpack.class);
        }
    
        @Override
        public void onEnable() {
            main = this;
            registerCommands();
            registerEvents();
        }
    
        @Override
        public void onDisable() {
            Backpack.onDisable();
        }
    
        private void registerCommands() {
            getCommand("backpack").setExecutor(new BackpackCommand());
        }
        private void registerEvents() {
            PluginManager manager = Bukkit.getPluginManager();
        }
    
        public static Main getMain() {
            return main;
        }
    }
    
    Here`s the backpack class:

    Code:
    package de.laslo.minecraftproject.backpack;
    
    import de.laslo.minecraftproject.utils.DataSave;
    import org.bukkit.Bukkit;
    import org.bukkit.configuration.serialization.ConfigurationSerializable;
    import org.bukkit.entity.Player;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    
    public class Backpack implements ConfigurationSerializable {
    
        private final Player player;
        private Inventory inventory;
        private String name = "Backpack";
        private int size = 27;
    
        private static final ArrayList<Player> players = new ArrayList<>();
        private static final HashMap<Player, Backpack> backpacks = new HashMap<>();
        private static final DataSave dataSave = new DataSave("backpack");
        private static boolean synchroniseSize = false;
        private static boolean synchroniseNames = false;
    
        static {
            ArrayList<String> uuids = (ArrayList<String>) dataSave.get("uuids");
            if (uuids != null) {
                for (String s : uuids) {
                    Player player = Bukkit.getPlayer(UUID.fromString(s));
                    if (!players.contains(player))
                        players.add(player);
                }
            }
        }
    
        private Backpack(Player player) {
            this.player = player;
    
            if (!backpacks.isEmpty()) {
                Backpack backpack = (Backpack) backpacks.values().toArray()[0];
                if (synchroniseNames)
                    this.name = backpack.getName();
                if (synchroniseSize)
                    this.size = backpack.getSize();
            }
    
            this.inventory = Bukkit.createInventory(player, size, name);
            backpacks.put(this.player, this);
            if (!players.contains(player))
                players.add(player);
        }
    
        public static Backpack getBackpack(Player player) {
            if (backpacks.containsKey(player)) {
                return backpacks.get(player);
            }
            if (dataSave.contains(player.getUniqueId().toString())) {
                dataSave.get(player.getUniqueId().toString());
                return getBackpack(player);
            }
            return new Backpack(player);
        }
    
        public static ArrayList<Player> getAllPlayers() {
            return players;
        }
    
        public Player getPlayer() {
            return player;
        }
    
        public String getName() {
            return name;
        }
    
        public int getSize() {
            return size;
        }
    
        public Inventory getInventory() {
            return inventory;
        }
    
        public void setName(String name) {
            if (synchroniseNames) {
                for (Player player : players) {
                    setName(name, getBackpack(player));
                }
                return;
            }
            setName(name, this);
        }
        private static void setName(String name, Backpack backpack) {
            backpack.name = name;
            if (backpack.inventory != null) {
                ItemStack[] contents = backpack.inventory.getContents().clone();
                backpack.inventory = Bukkit.createInventory(backpack.player, backpack.size, backpack.name);
                backpack.inventory.setContents(contents);
            }
        }
    
        public void setSize(int size) throws IllegalArgumentException {
            if (synchroniseSize) {
                for (Player player : players) {
                    setSize(size, Backpack.getBackpack(player));
                }
                return;
            }
            setSize(size, this);
        }
        private static void setSize(int size, Backpack backpack) throws IllegalArgumentException {
            if (size < 0 || size > 54 || size % 9 != 0)
                throw new IllegalArgumentException("Size for custom inventory must be a multiple of 9 between 9 and 54 slots.");
    
            backpack.size = size;
    
            if (size == 0) {
                backpack.inventory = null;
                return;
            }
    
            ItemStack[] contents = backpack.inventory.getContents().clone();
            ItemStack[] newContents = new ItemStack[size];
            for (int i = 0; i < newContents.length; i++) {
                if (contents.length <= i)
                    break;
                newContents[i] = contents[i];
            }
    
            backpack.inventory = Bukkit.createInventory(backpack.player, backpack.size, backpack.name);
            backpack.inventory.setContents(newContents);
        }
    
        public static boolean doSynchroniseSize() {
            return synchroniseSize;
        }
    
        public static void setSynchroniseSize(boolean synchroniseSize) {
            Backpack.synchroniseSize = synchroniseSize;
            for (Player player : players) {
                setSize(27, Backpack.getBackpack(player));
            }
        }
    
        public static boolean doSynchroniseNames() {
            return synchroniseNames;
        }
    
        public static void setSynchroniseNames(boolean synchroniseNames) {
            Backpack.synchroniseNames = synchroniseNames;
            for (Player player : players) {
                setName("Backpack", Backpack.getBackpack(player));
            }
        }
    
        public static void onDisable() {
            ArrayList<String> uuids = new ArrayList<>();
            for (Player player : players) {
                uuids.add(player.getUniqueId().toString());
            }
            dataSave.set("uuids", uuids);
            for (Backpack backpack : backpacks.values()) {
                dataSave.set(backpack.getPlayer().getUniqueId().toString(), backpack);
            }
        }
    
        public Map<String, Object> serialize() {
            HashMap<String, Object> result = new HashMap<>();
    
            result.put("player", this.player.getUniqueId().toString());
    
            if (inventory != null)
                result.put("inventory", this.inventory.getContents());
    
            result.put("name", this.name);
            result.put("size", this.size);
    
            return result;
        }
        public Backpack(HashMap<String, Object> map) {
            this.player = Bukkit.getPlayer(UUID.fromString((String) map.get("player")));
            this.name = (String) map.get("name");
            this.size = (int) map.get("size");
    
            if (map.get("inventory") == null)
                this.inventory = null;
            else {
                this.inventory = Bukkit.createInventory(player, size, name);
                this.inventory.setContents((ItemStack[]) map.get("inventory"));
            }
            backpacks.put(this.player, this);
            if (!players.contains(player))
                players.add(player);
        }
    }
    And finnally, here`s my Class that should load and save things to files:

    Code:
    package de.laslo.minecraftproject.utils;
    
    import org.bukkit.configuration.ConfigurationSection;
    import org.bukkit.configuration.file.YamlConfiguration;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.Set;
    
    public class DataSave {
    
        private final YamlConfiguration configuration;
        private final File file;
    
        public DataSave(String filename) {
            File dir = new File("./plugins/MinecraftProject");
            if (!dir.exists()) {
                dir.mkdir();
            }
    
            this.file = new File(dir, filename + ".yml");
            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            this.configuration = YamlConfiguration.loadConfiguration(file);
        }
    
        public Object get(String path) {
            System.out.println(path);
            if (contains(path)) {
                System.out.println(contains(path) + "ist der Contain wert");
                return configuration.get(path);
            }
            return null;
        }
        public boolean contains(String path) {
            return configuration.contains(path);
        }
        public void set(String path, Object o) {
            try {
                configuration.set(path, o);
                configuration.save(file);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public Set<String> getChildren(String parent) {
            ConfigurationSection section = configuration.getConfigurationSection(parent);
            if (section == null)
                return null;
            return section.getKeys(false);
        }
    }
    
    When i start the server and try my backpack with my backpack command (if you need the code pls tell me) and reload, the yml file contains the correct things. However, when the dataSave.contains(String path (which is the players uuid in this case))-method is called, it returns false, and the get()-method returns null although in the file it seems to be there.

    Thanks in advance.
     
  2. Offline

    Legendary_zotar

    Can you show us an example of how the config looks?
    Aswell as the "path" value when you use dataSave.contains?
    And if theres any errors can you pastebin it?
     
    Lasslos05 likes this.
  3. Offline

    Kars

    Save backpacks serialized, under a unique id that is a string. This way you can use contains and get by id, and deserialize the contents afterward.
     
    Lasslos05 likes this.
  4. Offline

    Lasslos05

    Here:
    Code:
    uuids:
    - 6ba22308-bcb5-4300-87ca-686c018ecf15
    6ba22308-bcb5-4300-87ca-686c018ecf15:
      ==: de.laslo.minecraftproject.backpack.Backpack
      size: 27
      name: Backpack
      inventory:
      - null
      - null
      - null
      - ==: org.bukkit.inventory.ItemStack
        v: 2586
        type: GRASS_BLOCK
        amount: 64
      - ==: org.bukkit.inventory.ItemStack
        v: 2586
        type: GRASS_BLOCK
        amount: 64
      - ==: org.bukkit.inventory.ItemStack
        v: 2586
        type: GRASS_BLOCK
        amount: 64
      - ==: org.bukkit.inventory.ItemStack
        v: 2586
        type: GRASS_BLOCK
        amount: 64
      - null
      - null
      - null
      - ==: org.bukkit.inventory.ItemStack
        v: 2586
        type: GRASS_BLOCK
        amount: 64
      - ==: org.bukkit.inventory.ItemStack
        v: 2586
        type: GRASS_BLOCK
        amount: 64
      - ==: org.bukkit.inventory.ItemStack
        v: 2586
        type: GRASS_BLOCK
        amount: 64
      - null
      - null
      - null
      - null
      - null
      - null
      - ==: org.bukkit.inventory.ItemStack
        v: 2586
        type: GRASS_BLOCK
        amount: 64
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      player: 6ba22308-bcb5-4300-87ca-686c018ecf15
    
    I think that is exactly what im doing, but it doesn't work...

    Haven't got any errors yet
    You can see it in my Code in Backpack.java:
    if (dataSave.contains(player.getUniqueId().toString())) {

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Mar 10, 2021
  5. Offline

    Kars

    Use json serialization with gson for example. Save the backpack as a serialized string and then specifically deserialize it.
    Now you are assuming that serialization/deserialization happens.
     
  6. Offline

    Lasslos05

    I think, that would change nothing, because it doesnt matter whether I use json and write it into a string in the config or bukkt serialization. Mabye it works, so im gonna try, but I dont really understand why that would help. Can you explain?
     
  7. Offline

    Kars

    Because turning a serialized string into an object using Gson will work 100%. I don't have experience with bukkit serialization but you said it wasn't working. So.
    Get the json-string from the config using a unique id. Once that is done, you deserialize the string and there you go. No reason why that shouldn't work.
     
  8. Offline

    CraftCreeper6

    @Lasslos05
    You can't directly serialize an Inventory/ItemStack like that, you need to do it manually.

    is not valid for Bukkit's yml.

    You need to save these parts individually, such as:

    Code:
    backpack-unique-identifier:
         owner: uuid
         slots: 27
         slot-values:
                  1:
                           material: WOOL
                           amount: 12
                           data: xyz
    ...
    Or something of the sort.

    (It's worth noting that the example I sent is not exactly what the config would look like, the numbers i.e 1, would look more like '1' than just the integer value.)

    I'm not certain if you can have children following a list like you have, in Bukkit's YML. It's valid YML elsewhere but may not be supported by the API for simplicity sake.
     
  9. Offline

    Lasslos05

    Hey Guys, i just found the problem. Serialization of custom objects (in this case backpack.class) needs two things: First, implementing ConfigurationSerialization and edit the serialize method, and second either a constructor that turns the return value of the serialze method back to the original object or a deserialze method or a valueOf method that does exatly the same. The thing is that the output of the serialze method is a map, in my case, a hashmap. My deserialze constructor only acceptet HashMaps
    but it have to accept any type of map to work with bukkit. So what happend is Bukkit could not find any deserialization method because it didn`t accept Map but HashMap, so it returned null as the value of my path, so it thougt the path wouldnt exsist.

    And to anwer the lastest Questions/Tips:

    You cannot directly serialize an Inventory, because it doesnt implements serializeable, but an ItemStack does implement it so you can. (it works, i prooved it).

    You were right it would have worked.

    Message to Moderator: How to close a thread?
     
  10. Online

    timtower Administrator Administrator Moderator

    You can only mark it solved, you can't lock it.
     
    Lasslos05 likes this.
Thread Status:
Not open for further replies.

Share This Page