Loading many subclasses

Discussion in 'Plugin Development' started by Ne0nx3r0, Jan 30, 2013.

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

    Ne0nx3r0

    So, I've run into this issue a few times and never come to a conclusion on a method to use that I'm happy with.

    Let's say you have about fifty player skills. Things like Dig, Throw, StrikeThatUglyGuyWithLightning, that sort of thing.

    You want to load them, reference them, etc. both in your code and by player input so that admins could do /myPlugin giveSkill <player> <skill> (or something similar), so you need to be able to reference them from a string as well as from some hard-coded method.

    My solution so far has been to create the classes and on load manually store an instance of each them in a hashmap<String,Skill> and then reference that instance or look it up by name when needed. I also usually include an enumerable constant to reference the skill in hard coded areas of the plugin.

    Is there a better way to do this? How would you handle it?
     
  2. Offline

    ZeusAllMighty11

    It's easy to maintain methods that can do simple getting and setting.

    like
    Code:
    public int getSkill(Player p){
        return someMap.getValue(p.getName());
    }
    
     
  3. Offline

    Ne0nx3r0

    Maybe I show you an example you can make fun of me and then show me how to do it better ; )

    https://github.com/Ne0nx3r0/RareIte...0/rareitems/item/ItemPropertyManager.java#L36

    Each of those classes extends a central class, and they have identical methods, except each does a particular thing.
     
  4. Offline

    MrTwiggy

    I couldn't really understand what the purpose of the item properties or how they are used/called/stored or the reasoning for storing them in the particular way. There wasn't much explanation or documentation, however.

    I am assuming you have a list of item properties/effects that each player has as active properties. In this case, I would create an object called PlayerStorage or something similar. You have a list of PlayerStorage objects that holds a single PlayerStorage object for every player on the server. When a player joins the server, you create one for them, and when they quit the server, you remove it or save it. Whichever is best for you. Then the PlayerStorage object holds the player's name, as well as a List of ItemProperties or ActiveEffects or whatever, and whenever you need the list of active effects or whatever you need, you can just call a method like getPlayerStorage(PLAYER_NAME).getActiveEffects()

    EDIT: Re-reading your main post, I understood a bit more. One solution is to have a list of all the effects or whatever, and each stores their own name, then you just iterate through all of them and check to see if the name of the property matches the name you are giving it.
     
  5. Offline

    Ne0nx3r0

    MrTwiggy Hrm. That's essentially what I'm doing now.

    Code:
    private void storeItemProperty(ItemProperty ip)
        {
            itemPropertiesLookup.put(ip.getName(), ip);
            itemPropertiesIdLookup.put(ip.getId(), ip);
        }
    
    I suppose it's not all that bad, It just feels wrong, like there is a better more normalized way to do this, I'm just not seeing it.
     
  6. Offline

    desht

    It sounds like what you're talking about is a way of dynamically loading a class, given its name. And for that, you want Class.forName(String className).

    E.g. to dynamically load & instantiate your one of your ItemProperty subclasses, you can do something like this:
    PHP:
    public ItemProperty createProperty(String propertyType) {
      try {
        class<? extends ItemPropertyclazz = Class.forName(propertyType).asSubClass(ItemProperty.class);
        
    Constructor <? extends ItemPropertyctor clazz.getDeclaredConstructor();
        return 
    ctor.newInstance();
      } catch (
    Exception e) {
         
    // NOTE: there any many possible exceptions, and "production" code should probably handle
         // each one in a sensible way
         
    return null;
      }
    }
    Note that propertyType needs to be a fully qualified classname, e.g. "com.gmail.ne0nx3r0.rareitems.item.enchantments.Fertilize".
     
  7. Offline

    MrTwiggy

    Yes, but what I'm saying would be more along the lines of

    Code:
     private ArrayList<ItemProperty> itemProperties = new ArrayList<ItemProperty>();
     
    private void storeItemProperty(ItemProperty ip)
    {
    itemProperties.add(ip);
    }
     
    private ItemProperty getItemProperty(String ipName)
    {
    for (ItemProperty itemProperty : itemProperties)
    {
    if (itemProperty.getName().equals(ipName))
    {
    return itemProperty;
    }
    }
     
    return null;
    }
     
  8. Offline

    Ne0nx3r0


    Oh I see, so lookups could be done based on different properties against the same list. That is a useful optimization (presuming it is actually faster). I like it.

    I'd still have to list them all individually though, and as a rule I try to avoid reflection as much as possible. That is a useful snippet to have though, thank you.

    ---

    I suppose I could be attacking a problem that doesn't really exist, I just feel like I'm missing out on a more advanced technique to handle situations like this.
     
  9. Offline

    wacossusca34

    You can further explore the java package with all your classes to retrieve all the names of it's classes. By doing this, you can have your plugin detect all the classes within a package, and load them. You can see all your classes and packages from a jar using a ZipInputStream object, cycling through the entries to determine the structure of your .jar
     
Thread Status:
Not open for further replies.

Share This Page