Solved Saving HashMap values after server close

Discussion in 'Spigot Plugin Development' started by theboyjamal, Apr 13, 2017.

  1. Hello, I am trying to make a plugin where i would save the contents of a custom class thats a constructor in a hashmap as a value to a file when the server closes. Then, on the server opening load the contents to the hashmap again. However, whats the best way to save all the data to the file and have it load back on the server opening again
     
  2. #2 Trigary, Apr 13, 2017
    Last edited: Apr 13, 2017
    • Agree Agree x 1
  3. both of those wont work since the value of the hashmap is a constuctor class with more than one value. this is my constructor.
    Code (Text):
    package me.boyjamal.utils;

    import java.util.List;

    public class NPCInfo {
       
        private String npcname;
        private boolean checkinventory;
        private boolean iteminhand;
        private List<String> error;
        private List<String> rewards;
        private boolean permission;
        private String permissiontext;
        private List<String> nopermission;
        private List<String> missionsuccess;
        private List<String> missionquest;
        private List<Item> items;
       
       
        public NPCInfo(String npcname, boolean checkinventory, boolean iteminhand, List<Item> items, List<String> error, List<String> rewards, boolean permission,
                String permissiontext, List<String> nopermission, List<String> missionsuccess, List<String> missionquest)
        {
            this.npcname = npcname;
            this.error = error;
            this.rewards = rewards;
            this.permission = permission;
            this.permissiontext = permissiontext;
            this.nopermission = nopermission;
            this.missionquest = missionquest;
            this.missionsuccess = missionsuccess;
            this.checkinventory = checkinventory;
            this.iteminhand = iteminhand;
            this.items = items;
        }
       
        public boolean isCheckInventory()
        {
            return checkinventory;
        }
       
        public List<Item> getItems()
        {
            return items;
        }
       
        public boolean isIteminHand()
        {
            return iteminhand;
        }
       
        public String getNPCName()
        {
            return npcname;
        }
       
        public List<String> getMissionSuccess()
        {
            return missionsuccess;
        }

        public List<String> getMissionQuest()
        {
            return missionquest;
        }
       
        public List<String> getError()
        {
            return error;
        }
       
        public List<String> getRewards()
        {
            return rewards;
        }
       
        public boolean needPermission()
        {
            return permission;
        }
       
        public String getPermission()
        {
            return permissiontext;
        }
       
        public List<String> getPermissionError()
        {
            return nopermission;
        }
    }
     
  4. What is a constructor class? Do you mean a class with a constructor? What does that change? Have you tested them? My methods which are based on ObjectOutputStream and ObjectInputStream work with a hashmap which's values are my custom class' instances.
     
  5. What was suggested is what you want. You could create some sort of method to serialize/deserialize the class and save that information to a file, or.. perhaps better, a YML, using the built in config functionality of Bukkit. Serialization is likely what you want.
     
  6. yes that is correct. however, since its a custom constructor and its not serializeable. it returns the error unserializeable. what i need help on is making it so it can be serializeable. how would i go about doing that
     
  7. Depending how complex the information is.. from what I see, not very, you can use different methods. For this class, I'd probably create a toList() method or similar, which returns an ArrayList built to a specific pattern. Something like making the first line of it the NPCName, the second like for the booleans ("0,0,1") or something you can split and parse, the next line as the permissiontext, the next few lines with a String representation of the various String lists and then finally a String representation of a list of String representatioms of Items.

    That might sound convoluted but I find it useful at times. Then just add a static method in the class to return the object from an ArrayList, following your steps, backward.
     
  8. WAS

    WAS

    It's been explained in the first post. For example. Retrieving my hashmap

    Code (Java):
    HashMap<UUID, String> userMap = null;
    FileInputStream is = new FileInputStream(getDataFolder() + File.separator + "cache" + File.separator + "users.ser");
    ObjectInputStream ois = new ObjectInputStream(is);
    userMap = (HashMap<UUID, String>) ois.readObject();
    ois.close();
    is.close();
    userMap is now my HashMap from file.

    Writing my object
    Code (Java):
    FileOutputStream fileOut = new FileOutputStream(getDataFolder() + File.separator + "cache" + File.separator + "rooms.ser");
    ObjectOutputStream out = new ObjectOutputStream(fileOut);
    out.writeObject(userMap);
    out.close();
    fileOut.close();[.code]
    The file, with encoding comes back similar to (Forum won't allow most the characters)
    Code (Text):
    ¬í sr java.util.LinkedHashMap4ÀN\lÀû Z accessOrderxr java.util.HashMapÚÁÃ`Ñ F
    loadFactorI    [email protected]  w    x
     
  9. Ok, doing game development and server creation, this is how I serialise classes to be sent over a network/to a file in your case.

    This will output to json by the way

    Download the gson API by Google. A simple gson Java Google phrase will help you find it.

    Then in your class, make all your vars public and add an empty constructor for gson to use when deserializing your classes.
    Code (Text):

        public String npcname;
        public boolean checkinventory;
      //...etc change private to public
       
        public NPCInfo(){
    //Nothing in here, you can keep your old constructor, this is only used by gson to deserialise
    }
       
     
    Use the gson API to convert the class to an output stream of bytes or a string if u want it to be readable to the user.

    Then save that string/ stream to a file.

    Then when loading just load that file, convert it to a string/stream and load it into gson. It will use ur empty constructor to "construct" the class for you!

    Lemme know if you need any help.

    I wont spoon feed code if you plan to ask for an example. Try googling your questions and thinking constructively (I promise the Java puns stop there). That will put you on the correct path to becoming a confident programmer. Good luck!

    BTW , your object io streams weren't working because you didn't implement serializable into your custom class.
     
    #9 xBallisticBlazex, Apr 14, 2017
    Last edited: Apr 14, 2017
  10. Let me put that into simple terms for u :)

    Say for example an ItemStack

    i save the item name as a string
    I save the item display name as a string
    I save the item lore as a list
    I save the enchants as a integer (like sharpness: 5)
    save the amount as a int

    Then when you load it back

    I use Material.getMaterial(file.getString("material")); to get the item
    Then file.getString("name") to get the name
    getList to get lore
    and the effective way (since enchantments dont have Enchantment.getEnchant())

    Code (Text):
    item.getItemMeta().addEnchant(Enchantment.DAMAGE_ALL, file.getInt("sharpness"), true);
    Get the idea?
     
  11. If you look at the class needed to be serialised, there is no custom class needing of serialisation such as an ItemStack. Just Lists and primitive data types. Guidance is just needed in transferring a class into a file. What are you trying to demonstrate?
     
  12. For example

    His variable "npcname"

    On disable
    NPCInfo npcinfo = new NPCInfo(Variables Here);
    datafile.set("npcname", npcinfo.getNPCName());

    On Enable
    NPCInfo npcinfo = new NPCInfo(Variables withe the name looking like, datafile.getString("npcname"));
    hashmap.put(variable, npcname);