Best practise to store and load objects from config

Discussion in 'Spigot Plugin Development' started by Franz-san, May 13, 2016.

  1. Hello,

    as written in the title I would like to get some input on what is best practise to store and load objects from config. Currently i'm using a List<HashMap<String,Object>> and go through it with an Iterable without any getConfig().
    Does the bukkit config api support something like that and how?

    I.e.
    Code (Text):
    weapons.yml
    ->Weapons
    -->ItemName: salmon
    -->AtkSpeed:1024
    -->Damage:500
    -->Lore:The salmon is living!
    -->DisplayName: &aSalmon Sword
    -->Base: IRON_SWORD

    -->ItemName: diamondkatana
    -->AtkSpeed:1024
    -->Damage:500
    -->Lore:This katana resembles eastern weapon crafts
    -->DisplayName: &aDiamond Katana
    -->Base: DIAMOND_SWORD
     
     
  2. Why don't you use JSON? You can simply serialize and deserialize data with JSON (Gson)
     
    • Like Like x 1
    • Agree Agree x 1
  3. do you have/know an example link/class on how to use it? thanks
     
  4. I'll write an example how you can serialize and deserialize your weapons.
    Give me some minutes :)
     
    • Useful Useful x 1
  5. So, this is what your "config" will look like in JSON:
    Code (Text):
    {
      "weapons": [
        {
          "itemName": "salmon",
          "attackSpeed": 1024,
          "damage": 500,
          "lore": [
            "&cThe salmon is living!",
            "&6Punch him right into his face...!",
            "&7Some example lines. :P"
          ],
          "displayName": "&aSalmon Sword",
          "base": "IRON_SWORD"
        },
        {
          "itemName": "diamondkatana",
          "attackSpeed": 1024,
          "damage": 500,
          "lore": [
            "&7This katana resembles eastern weapon crafts",
            "&6Another example line :D"
          ],
          "displayName": "&aDiamond Katana",
          "base": "DIAMOND_SWORD"
        }
      ]
    }
    Spigot contains the JSONSimple library. So you can do following to get your weapons:

    "Deserializer":
    Code (Text):
    try {
                JSONParser parser = new JSONParser();
                // Initiate the json parser

                JSONObject rootObject = (JSONObject) parser.parse(new InputStreamReader(DesSes.class.getResourceAsStream("weapons.json")));
                // When the file is in the same package as the class you can just simply type the name of the file like "weapons.json"
                // It's "rootObject" called because it contains the whole content

                JSONArray weapons = (JSONArray) rootObject.get("weapons");
                // The "weapons" object is an array out of json objects containing your "weapons"

                for (int i = 0; i < weapons.size(); i++) {
                    // For loop to get all "weapons" as single object
                    JSONObject weapon = (JSONObject) weapons.get(i);

                    // To deserialize the data you can do something like this:

                    // Create a new class for the weapons, where you can put the data in
                    // Just a tip: JSON returns all the time a long instance when you use numbers, so don't forget to cast long to int or double
                    // otherwise you will get a exception
                    Weapon resultWeapon = new Weapon((String) weapon.get("itemName"), (String) weapon.get("displayName"), (long) weapon.get("damage"),(long) weapon.get("attackSpeed"),
                            (List<String>) weapon.get("lore"), Material.getMaterial((String) weapon.get("base")));

                    System.out.println(resultWeapon.getOriginName());
                    System.out.println(resultWeapon.getDisplayName());
                    System.out.println(resultWeapon.getAttackDamage());
                    System.out.println(resultWeapon.getAttackSpeed());
                    System.out.println(resultWeapon.getLore());
                    System.out.println(resultWeapon.getMaterial());

                    System.out.println("-----------------------------------------------------------------------");

                }

            } catch (IOException | ParseException e) {
                e.printStackTrace();
            }
    Weapon class:

    Code (Text):
    public class Weapon {

        private String originName;
        private String displayName;
        private long attackDamage;
        private long attackSpeed;
        private List<String> lore;
        private Material material;

        public Weapon(String originName, String displayName, long attackDamage, long attackSpeed, List<String> lore, Material material) {
            this.originName = originName;
            this.displayName = displayName;
            this.attackDamage = attackDamage;
            this.attackSpeed = attackSpeed;
            this.lore = lore;
            this.material = material;
        }

        public String getOriginName() {
            return originName;
        }

        public String getDisplayName() {
            return displayName;
        }

        public long getAttackDamage() {
            return attackDamage;
        }

        public long getAttackSpeed() {
            return attackSpeed;
        }

        public List<String> getLore() {
            return lore;
        }

        public Material getMaterial() {
            return material;
        }
    }
    You can save the weapons in a list. Example:
    Code (Text):
    List<Weapon> weapons = new ArrayList();
    If you have any questions left, ask me :)
     
    • Friendly Friendly x 1
  6. thank you.
    Code (Text):
    DesSes.class.getResourceAsStream("weapons.json")
    Do I need to replace DesSes with Weapon?

    Code (Text):
    List<Weapon> weapons = new ArrayList();
    how can i get a specific weapon from that? do I need for loop for that?
     
    #6 Franz-san, May 13, 2016
    Last edited: May 13, 2016
  7. Replace "DesSes" with your own class. Don't forget to put the json file(s) in the same package. :D

    Specific weapon:

    Code (Text):
    List<Weapon> weapons = yourWeapons;

    for(Weapon weapon : weapons) {
      if(weapon.getOriginName().equalsIgnoreCase("salmon")) {
         // I guess

        // Code...
      }
    }
     
    • Friendly Friendly x 1
  8. that should be quite resource intensive if there are a lot of weapons? 100-500 weapons is what im aiming at
     
  9. I don't know but I guess it won't be that resource intensive. Just try it, testing is the best practise :p
     
    • Friendly Friendly x 1
  10. Now, do you have still any problems? If not then mark the thread as solved. :)
     
  11. You can also simply do this (untested, but should work):
    Code (Java):
    Weapon weapon = (Weapon) weapons.stream().filter((Weapon e) -> e.getOriginName().equals("salmon")).toArray()[0];
    (requires java 8)
     
  12. maybe someone knows an alternative to the for loop
     
  13. I just posted one.
     
    • Useful Useful x 1
  14. ah, cool I got the quote wrong thx
     
  15. is this correct to read a json?
    Code (Text):

    FileInputStream fis = new FileInputStream(FlawlordArtifactSan.confdirectory + File.separatorChar + "weapons.json");
    JSONObject rootObject = (JSONObject) parser.parse(new InputStreamReader(fis));
     
  16. edit: you need to cast double to it not long.

    Code (Text):

        private void loadWeapons() {
            try {
                JSONParser parser = new JSONParser();
                File file = new File(FlawlordArtifactSan.confdirectory + File.separatorChar + "weapons.json");
                FileInputStream fis = new FileInputStream(file);
                JSONObject rootObject = (JSONObject) parser.parse(new InputStreamReader(fis));
                JSONArray weapons = (JSONArray) rootObject.get("weapons");

                for (Object weapon1 : weapons) {
                    JSONObject weapon = (JSONObject) weapon1;
                    final Weapon result = new Weapon();
                    final String itemName = (String) weapon.get("itemName");
                    result.setDisplayName((String) weapon.get("displayName"));
                    result.setLore((List<String>) weapon.get("lore"));
                    result.setAttackDamage(((Long) weapon.get("attackDamage")).intValue());
                    result.setAttackSpeed(((Long) weapon.get("attackSpeed")).doubleValue());
                    result.setMaterial(Material.getMaterial((String) weapon.get("baseMaterial")));
                    result.setDurability(((Long) weapon.get("durability")).intValue());
                    result.setUnbreakable((Boolean) weapon.get("unbreakable"));
                    result.setHideFlags((Boolean) weapon.get("hideFlags"));
                    result.setItemName(itemName);

    //                weaponList.add(new HashMap<String, Weapon>() {{
    //                    put(itemName, result);
    //                }});
                    weaponsList.add(result);
                }

            } catch (IOException | ParseException e) {
                e.printStackTrace();
                Flawlord.log(ChatColor.RED + "weapons.json weapons could not be loaded.");
            }
        }
        private void loadWeaponModifiers() {
            try {
                JSONParser parser = new JSONParser();
                File file = new File(FlawlordArtifactSan.confdirectory + File.separatorChar + "weapons.json");
                FileInputStream fis = new FileInputStream(file);
                JSONObject rootObject = (JSONObject) parser.parse(new InputStreamReader(fis));
                JSONArray weaponModifiers = (JSONArray) rootObject.get("weaponModifiers");

                for (Object weaponModifier : weaponModifiers) { //for (int i = 0; i < weaponModifiers.size(); i++) {
                    JSONObject modifier = (JSONObject) weaponModifier;
                    final WeaponModifier result = new WeaponModifier();
                    result.setText((String) modifier.get("text"));
                    result.setChance(((Long) modifier.get("chance")).intValue());
                    result.setDamage(((Long) modifier.get("damage")).intValue());
                    result.setAttackSpeed(((Long) modifier.get("speed")).doubleValue());

                    for (int i = 0; i <= result.getChance(); i++)
                        weaponModifiersList.add(result);
                }

            } catch (IOException | ParseException e) {
                e.printStackTrace();
                Flawlord.log(ChatColor.RED + "weapons.json weaponmodifiers could not be loaded.");
            }
        }
    I get ClassCastException Double can not be cast to Long at loadWeaponModifiers() result.setAttackSpeed(((Long) modifier.get("speed")).doubleValue());

    For what reason? I dont see any difference to loadWeapons() where the same line works ...

    Weapon class:
    @Getter @Setter private double attackSpeed;

    Weapon Modifier class:
    @Getter @Setter private double attackSpeed;

    Json looks like this

    Code (Text):

    {
      "weapons": [
      {
      "itemName": "phaeton",
        "displayName": "&6Phaeton Dagger",
        "lore": [
      "&eThe dagger of Phaeton"
      ],
        "attackDamage": 24,
      "attackSpeed": 4,
      "baseMaterial": "IRON_SWORD",
        "durability": 1,
        "unbreakable": true,
        "hideFlags": false
      },
      {
      "itemName": "sol",
        "displayName": "&dSol Blade",
        "lore": [
      "&eThe ultimate legendary sword of Helios",
         "&eThe strongest sword in Weyard"
      ],
        "attackDamage": 100,
      "attackSpeed": 2,
      "baseMaterial": "DIAMOND_SWORD",
        "durability": 1,
        "unbreakable": true,
        "hideFlags": false
      }
      ],
      "weaponModifiers": [
      {
      "text": "&bLegendary",
        "chance": 1,
        "damage": 15,
      "speed": 0
      },
      {
      "text": "&bHuge",
        "chance": 2,
        "damage": 5,
      "speed": -0.5
      }
      ]
    }
     
    #16 Franz-san, May 14, 2016
    Last edited: May 14, 2016