EasyConfig 2.1

Discussion in 'Resources' started by codename_B, Aug 25, 2012.

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

    codename_B

    All credit to md_5 for the original idea, this is just tweaked and refined for my own use (support of HashMaps etc).

    Config.java
    Code:
    
    import java.io.File;
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.World;
    import org.bukkit.configuration.ConfigurationSection;
    import org.bukkit.configuration.InvalidConfigurationException;
    import org.bukkit.configuration.file.YamlConfiguration;
    import org.bukkit.plugin.Plugin;
    import org.json.simple.JSONObject;
    import org.json.simple.parser.JSONParser;
    
    /**
     * Inspired by md_5
     * 
     * An awesome super-duper-lazy Config lib!
     * Just extend it, set some (non-static) variables
     * 
     * @author codename_B
     * @version 2.1
     */
    public abstract class Config {
    
        private transient File file = null;
        private transient YamlConfiguration conf = new YamlConfiguration();
        
        /**
         * Must be called before using config.load() or config.save();
         * @param input
         * @return (Config) instance
         */
        public Config setFile(Object input) {
            // handle the File
            if(input == null) {
                new InvalidConfigurationException("File cannot be null!").printStackTrace();
            } else if(input instanceof File) {
                // the file, directly
                file = (File) input;
            } else if(input instanceof Plugin) {
                // the config.yml of the plugin
                file = getFile((Plugin) input);
            } else if(input instanceof String) {
                // the literal file from the string
                file = new File((String) input);
            }
            return this;
        }
        
        /**
         * Lazy load
         */
        public void load() {
            if(file != null) {
                try {
                    onLoad(file);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                new InvalidConfigurationException("File cannot be null!").printStackTrace();
            }
        }
        
        /**
         * Lazy save
         */
        public void save() {
            if(file != null) {
                try {
                    onSave(file);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                new InvalidConfigurationException("File cannot be null!").printStackTrace();
            }
        }
        
        /**
         * Internal method - used by load();
         * @param plugin
         * @throws Exception
         */
        private void onLoad(File file) throws Exception {
            if(!file.exists()) {
                if(file.getParentFile() != null)
                    file.getParentFile().mkdirs();
                file.createNewFile();
            }
            conf.load(file);
            for(Field field : getClass().getDeclaredFields()) {
                String path = field.getName().replaceAll("_", ".");
                if(doSkip(field)) {
                    // don't touch it
                } if(conf.isSet(path)) {
                    field.set(this, toBukkit(conf.get(path), field, path));
                } else {
                    conf.set(path, toConfig(field.get(this), field, path));
                }
            }
            conf.save(file);
        }
        
        /**
         * Internal method - used by save();
         * @param plugin
         * @throws Exception
         */
        private void onSave(File file) throws Exception {
            if(!file.exists()) {
                if(file.getParentFile() != null)
                    file.getParentFile().mkdirs();
                file.createNewFile();
            }
            for(Field field : getClass().getDeclaredFields()) {
                String path = field.getName().replaceAll("_", ".");
                if(doSkip(field)) {
                    // don't touch it
                } else {
                    conf.set(path, toConfig(field.get(this), field, path));
                }
            }
            conf.save(file);
        }
        
        /*
         * Main conversion methods
         */
        
        private Object toBukkit(Object in, Field field, String path) throws Exception {
            if(isConfigurationSection(in)) {
                return getMap((ConfigurationSection) in, field, path);
            } else if(isJSON(in)) {
                return getLocation((String) in);
            } else {
                return in;
            }
        }
        
        @SuppressWarnings("rawtypes")
        private Object toConfig(Object out, Field field, String path) throws Exception {
            if(isMap(out)) {
                return getMap((Map) out, field, path);
            } else if(isLocation(out)) {
                return getLocation((Location) out);
            } else {
                return out;
            }
        }
        
        /*
         * Checkers
         */
        
        private boolean isJSON(Object o) {
            try {
                if(o instanceof String) {
                    String s = (String) o;
                    if(s.startsWith("{")) {
                        return new JSONParser().parse(s) != null;
                    }
                }
                return false;
            } catch (Exception e) {
                return false;
            }
        }
        
        @SuppressWarnings("rawtypes")
        private boolean isMap(Object o) {
            try {
                return (Map) o != null;
            } catch (Exception e) {
                return false;
            }
        }
        
        private boolean isLocation(Object o) {
            try {
                return (Location) o != null;
            } catch (Exception e) {
                return false;
            }
        }
        
        private boolean isConfigurationSection(Object o) {
            try {
                return (ConfigurationSection) o != null;
            } catch (Exception e) {
                return false;
            }
        }
        
        /*
         * Converters
         */
        
        @SuppressWarnings({ "rawtypes", "unchecked" })
        private ConfigurationSection getMap(Map data, Field field, String path) throws Exception {
            ConfigurationSection cs = conf.createSection(path);
            Set<String> keys = data.keySet();
            if(keys != null && keys.size() > 0) {
                for(String key : keys) {
                    System.out.println("keys");
                    Object out = data.get(key);
                    System.out.println(out.getClass().getName());
                    out = toConfig(out, field, path);
                    System.out.println(out.getClass().getName());
                    cs.set(key, out);
                }
                return cs;
            }
            return cs;
        }
        
        @SuppressWarnings({ "rawtypes", "unchecked" })
        private Map getMap(ConfigurationSection data, Field field, String path) throws Exception {
            Set<String> keys = data.getKeys(false);
            Map map = new HashMap();
            if(keys != null && keys.size() > 0) {
                for(String key : keys) {
                    Object in = data.get(key);
                    in = toBukkit(in, field, path);
                    map.put(key, in);
                }
                return map;
            }
            return map;
        }
        
        private Location getLocation(String json) throws Exception {
            JSONObject data = (JSONObject) new JSONParser().parse(json);
            // world
            World world = Bukkit.getWorld((String) data.get("world"));
            // x, y, z
            double x = Double.parseDouble((String) data.get("x"));
            double y = Double.parseDouble((String) data.get("y"));
            double z = Double.parseDouble((String) data.get("z"));
            // pitch, yaw
            float pitch = Float.parseFloat((String) data.get("pitch"));
            float yaw = Float.parseFloat((String) data.get("yaw"));
            // generate Location
            Location loc = new Location(world, x, y, z);
            loc.setPitch(pitch);
            loc.setYaw(yaw);
            return loc;
        }
        
        @SuppressWarnings("unchecked")
        private String getLocation(Location loc) {
            JSONObject data = new JSONObject();
            // world
            data.put("world", loc.getWorld().getName());
            // x, y, z
            data.put("x", String.valueOf(loc.getX()));
            data.put("y", String.valueOf(loc.getY()));
            data.put("z", String.valueOf(loc.getZ()));
            // pitch, yaw
            data.put("pitch", String.valueOf(loc.getPitch()));
            data.put("yaw", String.valueOf(loc.getYaw()));
            return data.toJSONString();
        }
        
        /*
         * Utility methods
         */
        
        /**
         * A little internal method to save re-using code
         * @param field
         * @return skip
         */
        private boolean doSkip(Field field) {
            return Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers());
        }
        
        private File getFile(Plugin plugin) {
            return new File(plugin.getDataFolder(), "config.yml");
        }
        
    }
    
    ExampleConfig.java (extends Config)
    Code:
    import org.bukkit.plugin.Plugin;
     
     
    public class ExampleConfig extends Config {
     
        public ExampleConfig(Plugin plugin) {
            this.setFile(plugin);
        }
     
        String messages_hello = "Hello there!";
        String messages_goodbye = "Ok, bye :(";
        int timer = 60;
     
    }
    
     
    bobacadodl, Chrono7, jtjj222 and 4 others like this.
  2. Offline

    Icyene

    Yes! Thank you!
     
    bobacadodl and codename_B like this.
  3. Offline

    codename_B

    Glad you like it ;)
    It does make configs considerably less paintful to load/save.
     
  4. Offline

    Icyene

    It really does :) I usually add a .replaceAll("__", " ") for the config setting, so I can have spaces, and if the value had Modifier.VOLATILE, then .replaceAll("__", "-"). Makes it a bit more... versatile...
     
  5. What does this do? Does it allow condors with comments to be saved?
     
  6. Offline

    Icyene

    This is the epic-super-duper-quper-uber configuration engine. It is the holy grail of the lazy. You make a class that extends Config, and add some variables in it. Basically:

    Code:
    public class LazyConfig extends Config {
    public LazyConfig(Plugin p) {
    super(p);
    }
    public int A_Integer_Value = 5;
    }
    
    Then you do:

    Code:
    LazyConfig config = new LazyConfig(this);
    config.load();
    
    And codename_B's epic engine will store that in a config for you. The variable above will be config'd as A.Integer.Value: 5. The engine skips fields that are transient, final, or static. Version 2.0 has support for maps.

    Come to the dark side. We have cookies.

    In all seriousness thanks codename_B once again for this wonderful tool. I use it in all my plugins :)
     
    bobacadodl and hawkfalcon like this.
  7. Thats cool!
     
    Icyene likes this.
  8. Offline

    Ha1luciNate

    Do you still need to define where the plugin looks for the variables in the config file? (<- new to making plugins)
     
  9. Offline

    codename_B

    You can set any file!
     
  10. Offline

    StevasaurousREX

    codename_B I am just above the basics of java and very new to development of plugins for bukkit, can the be used to store a location of a player? If it can please can I have an example
     
  11. Offline

    codename_B

    I haven't made a "Serialisable Location" thing yet. But if you like I can add it?
     
  12. Offline

    StevasaurousREX

    Please, lol I've been working on a simple warp plugin. Currently the warps only stay till restart, and I'm having trouble finding out how to save locations
     
  13. Offline

    codename_B

    Consider it done.

    With the newly put on version (version 2.1)

    You can do this

    Code:
    import java.util.HashMap;
    import java.util.Map;
    import org.bukkit.Location;
    import org.bukkit.plugin.java.JavaPlugin;
    
    /**
     * An example config.yml
     * A warp plugin
     * 
     * @implements version 2.1
     * of codename_B's easy Config.java library
     */
    public class WarpConfig extends Config {
        // this is all we need!
        Map<String, Location> warps = new HashMap<String, Location>();
        
        // constructor sets the file
        public WarpConfig(JavaPlugin plugin) {
            setFile(plugin);
        }
        
        // set the warp
        public void setWarp(String name, Location loc) {
            warps.put(name, loc);
            save();
        }
        
        // unset the warp
        public void unsetWarp(String name) {
            warps.remove(name);
            save();
        }
        
        // get the warp by name (must be a genuine warp)
        public Location getWarp(String name) {
            return warps.get(name);
        }
    
    }
    
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 28, 2016
  14. Offline

    evilmidget38

    codename_B
    I made something similar to this for Bukkit Arena, and am now using it in Ban on Death. It's pretty similar to what you've got, just a few minor differences. The main difference is that mine is designed as almost a replacement for Bukkit's serialization, and is designed around ConfigurationSection's rather than a FileConfiguration. Maybe we could work together on a larger api?

    https://github.com/evilmidget38/Ban...a/configuration/EasyConfigurationSection.java
     
  15. Offline

    codename_B

    A ConfigurationSection is just a Map<String, Object> isn't it?
     
  16. Offline

    evilmidget38

    Pretty much, yes. The big difference, is that with a ConfigurationSection you have .getName(), which allows you to easily name the objects identically to the path they're saved as. Additionally, with the ConfigurationSection, you could make a simple save method would would push all the loaded values back into the ConfigurationSection, rather than using the set function of ConfigurationSection with a map(Bukkit serialization).
     
  17. Offline

    codename_B

    I just don't see the benefit of doing it your way?
    I mean what if you just wanted something like
    Code:
    message: 'hello world!'
    timer: 30
    
    How would you do that with yours?
     
  18. Offline

    evilmidget38

    You could pass the config into an object that extends EasyConfiguration object, or simply cast the FileConfiguration object to a ConfigurationSection and create a new instance of a class that extends EasyConfigurationSection. My system is very similar to yours, but is more useful when you've got a list of objects that all load from a ConfigurationSection, and all have the same fields, such as Tiers in Ban on Death, or any of the dozen or so objects in Bukkit Arena including Classes, Waves, Arenas, etc.
     
  19. Offline

    codename_B

    Ah I see, so you've taken it one stop further!
     
  20. Offline

    StevasaurousREX

    codename_B I tried the example you gave in my plugin and when using it is giving me
    Code:
    Cannot make a static reference to the non-static method setWarp(String, Location) from the type WarpConfig
    Just wondering if I'm not fully understanding something. I tried doing what it said and that just cause more issues so I thought I would ask.

    This is in my onCommand method
    Code:java
    1. if (label.equalsIgnoreCase("setwarp")) {// TODO
    2. if ((Player) sender != null) {
    3. Player player = (Player) sender;
    4. if (player.hasPermission("ProteusComands.setwarp")) {
    5. if (args.length == 0) {
    6. player.sendMessage("The correct usage is /setwarp <warpname>");
    7. } else if (args.length == 1) {
    8. Location playerLocation = player.getLocation();
    9. WarpConfig.setWarp(args[1], playerLocation);
    10. } else {
    11. player.sendMessage("The correct usage is /setwarp <warpname>");
    12. }
    13. } else {
    14. player.sendMessage("You dont have permission to use this command!");
    15. }
    16. }
    17. }
     
  21. Offline

    codename_B

    Don't make things static?
    Do you understand about instances and the like?

    Code:
    public WarpConfig config = new WarpConfig();
    
    Then do
    Code:
    config.setWarp(args[0], player.getLocation());
    
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 28, 2016
  22. Offline

    StevasaurousREX

    Alright thank you, and no I guess I do not understand instances very well. Ill take myself back a step and go over basic java again that way I don't ask simple questions here, thank you for your help codename_B

    And that of course fixed my problem, seems so simple looking back at it. Thank you again
     
  23. Offline

    codename_B

    No problem. Happy to have someone else find something useful that I do too :3
     
  24. Offline

    StevasaurousREX

    I almost came back here to ask a question about a problem I made xD Im attempting to get a string from args[1] when i only ask for 1 argument so it have to be args[0]. However when using the command it puts
    Code:
    10:01:25 [INFO] keys
    10:01:25 [INFO] org.bukkit.Location
    10:01:25 [INFO] java.lang.String
    In the console window and I saw that in the Config.java file it has that exact output, is that necessary? or can I remove those lines?
     
  25. Offline

    codename_B

    Erm, remove any System.out.println lines I left in there by accident :3
     
  26. Offline

    StevasaurousREX

    I thought it was just a debug thing but i wanted to make sure it wasnt an error that you changed to that, thanks for EasyConfig I'm working on converting all my configs to it now. Especially thanks for adding the warps part. Its exactly what I was looking for and I honestly dont think I would be able to make save-able warps with out this. I already use this same method to make /sethome and /home too. Thanks codename_B you were a big help
     
    codename_B likes this.
  27. Offline

    codename_B

    Some people are just awesome. I'm one of them ;)
     
    Icyene likes this.
  28. Offline

    ThatBox

    How would I add headers to this?
    Code:
    # header
    config: true
    generictwat: false
    
     
  29. Offline

    Icyene

    I modded it quite a bit. I use it so my plugin has a different config file for each world. Not a big change, but here it is:

    Code:Java
    1.  
    2. public class WorldConfiguration{
    3.  
    4. /*
    5.   * Based on codename_B's non static config 'offering' :-)
    6.   *
    7.   */
    8.  
    9. private Plugin plugin;
    10. private String world;
    11.  
    12. public WorldConfiguration(Plugin storm, String world) {
    13. this.plugin = storm;
    14. this.world = world;
    15. }
    16.  
    17. public void load() {
    18. if(plugin != null) {
    19. try {
    20. onLoad(plugin);
    21. } catch (Exception e) {
    22. e.printStackTrace();
    23. }
    24. } else {
    25. new InvalidConfigurationException("Plugin cannot be null!").printStackTrace();
    26. }
    27. }
    28.  
    29. private void onLoad(Plugin plugin) throws Exception {
    30.  
    31. File worldFile = new File(plugin.getDataFolder(), world + ".yml");
    32.  
    33. if(!worldFile.exists()) {
    34.  
    35. }
    36.  
    37. FileConfiguration worlds = YamlConfiguration.loadConfiguration(worldFile);
    38.  
    39.  
    40. for(Field field : getClass().getDeclaredFields()) {
    41. String path = "Storm." + field.getName().replaceAll("__", " ").replaceAll("_", ".");
    42. if(doSkip(field)) {
    43. } else if(worlds.isSet(path)) {
    44. field.set(this, worlds.get(path));
    45. } else {
    46. worlds.set(path, field.get(this));
    47. }
    48. }
    49. worlds.save(worldFile);
    50. }
    51.  
    52. private boolean doSkip(Field field) {
    53. return Modifier.isTransient(field.getModifiers())
    54. || Modifier.isStatic(field.getModifiers())
    55. || Modifier.isFinal(field.getModifiers())
    56. || Modifier.isPrivate(field.getModifiers());
    57. }
    58.  
    59. }
    60.  
     
  30. Offline

    RealDope

    codename_B

    The example code isn't working for me?

    I have:
    Code:JAVA
    1.  
    2. package net.goldenapplemc.EasyRefer;
    3.  
    4.  
    5. import org.bukkit.plugin.Plugin;
    6.  
    7. import net.goldenapplemc.EasyConfig.Config;
    8.  
    9. public class ConfigHandler extends Config {
    10.  
    11. public int test_test = 5;
    12.  
    13. public ConfigHandler(Plugin plugin) {
    14. this.setFile(plugin);
    15. }
    16.  
    17. public int getRefs(String username) {
    18. return 1;
    19. }
    20.  
    21. public void addRef(String givenTo, String givenBy) {
    22. }
    23. }
    24.  


    And in my main class:

    Code:JAVA
    1.  
    2. ConfigHandler config = new ConfigHandler(this);
    3.  
     
Thread Status:
Not open for further replies.

Share This Page