FML, Better way to get materials?

Discussion in 'Plugin Development' started by Jayjay110, May 27, 2011.

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

    Jayjay110

    OK so in my code, I put materials and their probabilities into a hashmap, then I create another hashmap to add amounts.

    First I need to put all the material values into the hashmap, and match them to their probabilities, then I have to redo this for the amounts (there is alot of materials!)

    Then I need to create a config file that can load all the materials amounts and probabilities into the amount and probability hashmaps

    As you can see this would be a reallly long peice of code and Im too lazy to type them out 1 by 1, Is there any way to use a for loop to automate it

    P.S: I already have code to load and write to a config, I just cant seem to reduce like 120 lines of material stuff into about 10 - 20

    Thankyou If you help :p
     
  2. Offline

    garbagemule

    I'm not sure why you can't do both at the same time, but to really help out, I think we need a little more information.

    Are the lists of materials and their amounts and probabilities static, or are they loaded from a file? Is there an absolute maximum number of materials, or does it vary? You mention HashMaps, but there might be better data structures for your specific purpose. Fork over some bits of code so we can get a better idea of what you're trying to accomplish :)
     
  3. Offline

    Jayjay110

    OK so the materials amounts and probabilites are loaded from a yml file, so that the user can change them, but they have inbuilt defaults I need to enter, there is no maximum to the amount of materials, It is a single list that I access to try a random check with a probability statement, here is the bits of my code that matter:

    Code:
    public Material randomItem(){
    
        Random rnd = new Random();
        int x = 0;
        int r = rnd.nextInt(100);
    
        for (Entry<Material, Integer> entry : plugin.con.mysteryItem.entrySet()) {
            x = x + entry.getValue();
            if (r < x){
                return entry.getKey();
            }
        }
        return Material.APPLE;
    
        }
    plugin.con.mysteryItem Is this hashmap in another class:
    public Map<Material, Integer> mysteryItem = new HashMap<Material, Integer>();

    Which when I load the code, I add the defaults like so:
    mysteryItem.put(Material.ARROW, 1);

    But after this it checks if the config file is different and loads the config values with the yaml built in thing

    I want my .yml file to be laid out like this:
    Code:
    Items:
        Arrow:
            Probability (%): 1
            Amount: 5
        Bed:
            Probability (%): 2
            Amount: 1
    etc...
    
    Basically to load the Material into the hashmap with the probability I have to go through the list of materials and type the name and the probability like this:

    mysteryItem.put(Material.ARROW, 1);
    mysteryItem.put(Material.BED, 2);
    etc...

    Then when I want to do the Amount I do:

    mysteryItemAmount.put(Material.ARROW, 1);
    mysteryItemAmount.put(Material.BED, 2);
    etc...

    Were mysteryItemAmount is the same type of hashmap, but it holds the amount instead


    So when I want to spawn a random material, with the correct amount in the world I run:

    Code:
            ItemStack is = (ItemStack) new ItemStack(randomItem(),1);
    
            int amount = plugin.con.mysteryItemAmount.get(is.getType());
    
            is.setAmount(amount);
    
            Item item = (Item) world.dropItem(loc, is);
    
    It would then drop the item on the world at my location or the location I specify


    Basically I cant figure out how to make it automate most of the copy paste stuff :)
     
  4. Offline

    garbagemule

    Ahh, I see. Shouldn't be too difficult. You will definitely need to do some sanity checking (to see if the specified item is indeed a valid enum value), but I have a piece of code that I think is going to work. I'd rather try to point you in the right direction first, though...

    So first of all, Configuration provides a method called getKeys(String path). Here, path would simply be "Items". This returns a list of all the items in your YML file, in case of the example you provided above, a list consisting of "Arrow" and "Bed". Having a list means you can iterate through the entire thing in a for-each loop, so run through all the items in that list.

    Now comes the hacking. Configuration also provides a getString(String path) method. The path variable works like it did with getKeys(String path), but at this point you are iterating through a list of Strings. You know that the path for Arrow's probability and amount are Items.Arrow.Probability and Items.Arrow.Amount, so you can hack up a String to feed getString(String path). Simple concatenation is all it takes.

    The string that is returned must be verified. You're expecting a number, so see if it matches a regular expression checking for numerical values (String provides a matches(String regex) method for this purpose). This is a good habit to get into when trying to optimize your code, because exceptions are much slower (and take up a lot more lines of code) than verifying with regular expressions. If you aren't too regex-savvy, here's a very basic example:
    Regex (open)
    Code:
    String bla = ...;
    someStringVariable.matches("[0-9]+");
    You've verified that the two values from the file are indeed numbers, so you parse them to Integers. Now, all you have to do is create a new Material value out of the string, and then feed the HashMaps. Java's Enum provides a method valueOf() that might look a bit scary, but you can simply feed it a String, and it will return an Enum value (if such a value exists). So, initialize a Material variable, and call Material.valueOf(someItemStringName.toUpperCase()), and now use put(yourMaterialVariable, theAmountYouParsed) and likewise for probability.

    I hope the length of this post doesn't invoke a TL;DR reaction, but I hope it was helpful :)
     
    Jayjay110 likes this.
  5. Offline

    Jayjay110

    Wow Ok this is good, I kinda get the theory I just dont quite understand the first bit, I think I did It tho, You sir are a gentleman!

    ... Oh crap, now comes the long part, How do I write all the material values to the config file for defualts :3


    EDIT:

    btw just tested code it works YAY :)
     
  6. Offline

    garbagemule

    If you don't want to keep a list of valid enum values, you're going to have to wrap the valueOf-method in a try-catch clause. valueOf throws an IllegalArgumentException if there is no enum value that matches the provided String, and a NullPointerException if the String is null. This would probably be least troublesome approach. In the catch-clause(s), make sure you notify the host of the problem, and put a "continue;" after the notification, so the rest of the items can be processed by the for-each loop :)
     
  7. Offline

    Jayjay110

    Wait what? I want to do basically the opposite of wat we did before, and instead of read, write to the file?
     
  8. Offline

    garbagemule

    Oh, sorry! What is it that you want to write to the config file exactly?
     
  9. Offline

    Jayjay110

    All the enum values of material, and the sub headings Probabilities and Amount :), dw its ok u dont have to say sorry lol

    Nvm I figured it out :)

    Thanks A Bunch :D

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 16, 2016
Thread Status:
Not open for further replies.

Share This Page