Resource CustomFileConfiguration

Discussion in 'Spigot Plugin Development' started by Varmetek, Jun 29, 2018.


  1. CustomFileConfig is an API that bridges the gap between other data representation formats and Spigot's Configuration API

    Goals
    The solution for supporting alternate configuration formats must be
    - Extensible
    - Fast
    - Connect directly with the Bukkit Configuration File
    - Serve as an alternative to the YamlConfiguration class

    Problems Seeking to solve
    - Uprooting entire code base to support an alternative configuration format
    - End user complaints of configuration breaking due to misalignment of indent
    - Easily switch to a more end user friendly configuration format without much hassle.

    How it works
    Each of the implementations work by acting as a translator between the configuration format and Bukkit's configuration api. These translation needs to happen in both way's which brings us to the Constructor and Representer classes. The Representer builds a configuration format representation of objects passed to it and the Constructor constructs Java objects from the configuration representation.


    Format Comparison
    Code (YAML):

    broken_sword
    :
      ==
    : org.bukkit.inventory.ItemStack
      type
    : WOOD_SWORD
      damage
    : 60
      meta
    :
        ==
    : ItemMeta
        meta-type
    : UNSPECIFIC
        display-name
    : broken sword
        lore
    :
       - falling apart...
        enchants
    :
          DAMAGE_ALL
    : 9999
          ARROW_DAMAGE
    : 9999
          DAMAGE_UNDEAD
    : 9999
          ARROW_KNOCKBACK
    : 34463
          DURABILITY
    : 9999
          DAMAGE_ARTHROPODS
    : 34463
          KNOCKBACK
    : 9999
          FIRE_ASPECT
    : 9999
          LOOT_BONUS_MOBS
    : 5
        ItemFlags
    :
       - HIDE_ENCHANTS
        - HIDE_ATTRIBUTES
    myboots
    :
      ==
    : org.bukkit.inventory.ItemStack
      type
    : LEATHER_BOOTS
      meta
    :
        ==
    : ItemMeta
        meta-type
    : LEATHER_ARMOR
        display-name
    : Sonic's Speedys
        lore
    :
       - Use these
        enchants
    :
          PROTECTION_FALL
    : 5
        ItemFlags
    :
       - HIDE_ENCHANTS
        - HIDE_ATTRIBUTES
        Unbreakable
    : true
        internal
    : H4sIAAAAAAAAAONiYOBkEHIsKSnKTCotSfXNT8lMy0wtKuZiYGBgZGbgCA31dPHNLy5hYJjDzczACeL6pCYC+ezre5kZ2Bxz80vzSkBqORh44ab4JeamMoimp+alFmUm6+Xml6XmpuaVBBekpqYAzfAvSC1KLMnMzwNqY+BgYMGjmoEBAKJKxwagAAAA
        color
    :
          ==
    : Color
          RED
    : 254
          BLUE
    : 3
          GREEN
    : 3
     
    Code (Text):

    {
      "broken_sword": {
        "_BUKKITTYPE_": "org.bukkit.inventory.ItemStack",
        "type": "WOOD_SWORD",
        "damage": "60$i$",
        "meta": {
          "_BUKKITTYPE_": "ItemMeta",
          "meta-type": "UNSPECIFIC",
          "display-name": "broken sword",
          "lore": [
            "falling apart..."
          ],
          "enchants": {
            "DAMAGE_ALL": "9999$i$",
            "ARROW_DAMAGE": "9999$i$",
            "DAMAGE_UNDEAD": "9999$i$",
            "ARROW_KNOCKBACK": "34463$i$",
            "DURABILITY": "9999$i$",
            "DAMAGE_ARTHROPODS": "34463$i$",
            "KNOCKBACK": "9999$i$",
            "FIRE_ASPECT": "9999$i$",
            "LOOT_BONUS_MOBS": "5$i$"
          },
          "ItemFlags": [
            "HIDE_ENCHANTS",
            "HIDE_ATTRIBUTES"
          ]
        }
      },
      "myboots": {
        "_BUKKITTYPE_": "org.bukkit.inventory.ItemStack",
        "type": "LEATHER_BOOTS",
        "meta": {
          "_BUKKITTYPE_": "ItemMeta",
          "meta-type": "LEATHER_ARMOR",
          "display-name": "Sonic\u0027s Speedys",
          "lore": [
            "Use these"
          ],
          "enchants": {
            "PROTECTION_FALL": "5$i$"
          },
          "ItemFlags": [
            "HIDE_ENCHANTS",
            "HIDE_ATTRIBUTES"
          ],
          "Unbreakable": true,
          "internal": "H4sIAAAAAAAAAONiYOBkEHIsKSnKTCotSfXNT8lMy0wtKuZiYGBgZGbgCA31dPHNLy5hYJjDzczACeL6pCYC+ezre5kZ2Bxz80vzSkBqORh44ab4JeamMoimp+alFmUm6+Xml6XmpuaVBBekpqYAzfAvSC1KLMnMzwNqY+BgYMGjmoEBAKJKxwagAAAA",
          "color": {
            "_BUKKITTYPE_": "Color",
            "RED": "254$i$",
            "BLUE": "3$i$",
            "GREEN": "3$i$"
          }
        }
      }
    }
     
    Code (Text):

    <?xml version="1.0" encoding="UTF-8"?>
    <config>
      <broken_sword>
        <_BUKKITTYPE_>org.bukkit.inventory.ItemStack</_BUKKITTYPE_>
        <type>WOOD_SWORD</type>
        <damage>60</damage>
        <meta>
          <_BUKKITTYPE_>ItemMeta</_BUKKITTYPE_>
          <meta-type>UNSPECIFIC</meta-type>
          <display-name>broken sword</display-name>
          <lore>
            <_>falling apart...</_>
          </lore>
          <enchants>
            <DAMAGE_ALL>9999</DAMAGE_ALL>
            <ARROW_DAMAGE>9999</ARROW_DAMAGE>
            <DAMAGE_UNDEAD>9999</DAMAGE_UNDEAD>
            <ARROW_KNOCKBACK>34463</ARROW_KNOCKBACK>
            <DURABILITY>9999</DURABILITY>
            <DAMAGE_ARTHROPODS>34463</DAMAGE_ARTHROPODS>
            <KNOCKBACK>9999</KNOCKBACK>
            <FIRE_ASPECT>9999</FIRE_ASPECT>
            <LOOT_BONUS_MOBS>5</LOOT_BONUS_MOBS>
          </enchants>
          <ItemFlags>
            <_>HIDE_ENCHANTS</_>
            <_>HIDE_ATTRIBUTES</_>
          </ItemFlags>
        </meta>
      </broken_sword>
      <myboots>
        <_BUKKITTYPE_>org.bukkit.inventory.ItemStack</_BUKKITTYPE_>
        <type>LEATHER_BOOTS</type>
        <meta>
          <_BUKKITTYPE_>ItemMeta</_BUKKITTYPE_>
          <meta-type>LEATHER_ARMOR</meta-type>
          <display-name>Sonic's Speedys</display-name>
          <lore>
            <_>Use these</_>
          </lore>
          <enchants>
            <PROTECTION_FALL>5</PROTECTION_FALL>
          </enchants>
          <ItemFlags>
            <_>HIDE_ENCHANTS</_>
            <_>HIDE_ATTRIBUTES</_>
          </ItemFlags>
          <Unbreakable>true</Unbreakable>
          <internal>H4sIAAAAAAAAAONiYOBkEHIsKSnKTCotSfXNT8lMy0wtKuZiYGBgZGbgCA31dPHNLy5hYJjDzczACeL6pCYC+ezre5kZ2Bxz80vzSkBqORh44ab4JeamMoimp+alFmUm6+Xml6XmpuaVBBekpqYAzfAvSC1KLMnMzwNqY+BgYMGjmoEBAKJKxwagAAAA</internal>
          <color>
            <_BUKKITTYPE_>Color</_BUKKITTYPE_>
            <RED>254</RED>
            <BLUE>3</BLUE>
            <GREEN>3</GREEN>
          </color>
        </meta>
      </myboots>
    </config>
     
    Code (Text):

    {
      broken_sword:
      {
        ==: org.bukkit.inventory.ItemStack
        type: WOOD_SWORD
        damage: 60$i$
        meta:
        {
          ==: ItemMeta
          meta-type: UNSPECIFIC
          display-name: broken sword
          lore:
          [
            falling apart...
          ]
          enchants:
          {
            DAMAGE_ALL: 9999$i$
            ARROW_DAMAGE: 9999$i$
            DAMAGE_UNDEAD: 9999$i$
            ARROW_KNOCKBACK: 34463$i$
            DURABILITY: 9999$i$
            DAMAGE_ARTHROPODS: 34463$i$
            KNOCKBACK: 9999$i$
            FIRE_ASPECT: 9999$i$
            LOOT_BONUS_MOBS: 5$i$
          }
          ItemFlags:
          [
            HIDE_ENCHANTS
            HIDE_ATTRIBUTES
          ]
        }
      }
      myboots:
      {
        ==: org.bukkit.inventory.ItemStack
        type: LEATHER_BOOTS
        meta:
        {
          ==: ItemMeta
          meta-type: LEATHER_ARMOR
          display-name: Sonic's Speedys
          lore:
          [
            Use these
          ]
          enchants:
          {
            PROTECTION_FALL: 5$i$
          }
          ItemFlags:
          [
            HIDE_ENCHANTS
            HIDE_ATTRIBUTES
          ]
          Unbreakable: true
          internal: H4sIAAAAAAAAAONiYOBkEHIsKSnKTCotSfXNT8lMy0wtKuZiYGBgZGbgCA31dPHNLy5hYJjDzczACeL6pCYC+ezre5kZ2Bxz80vzSkBqORh44ab4JeamMoimp+alFmUm6+Xml6XmpuaVBBekpqYAzfAvSC1KLMnMzwNqY+BgYMGjmoEBAKJKxwagAAAA
          color:
          {
            ==: Color
            RED: 254$i$
            BLUE: 3$i$
            GREEN: 3$i$
          }
        }
      }
    }
     

    How to use
    Simply replace YamlConfiguration with any of the provided solutions to seamlessly began saving and loading data in a completely different format.

    Code (Java):
      YamlConfiguration config = new YamlConfiguration();
      File file = new File(plugin.getDataFolder(),"data.yml");

      try {
        config.load(file);
      } catch (InvalidConfigurationException e) {
        e.printStackTrace();
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
     


    In that code block, the first line can easily be replaced with something like

    Code (Java):
     GsonConfiguration config = new GsonConfiguration();
    and use Google's Gson library.

    If you are really ambitious, this api will meet you there and even handle the Xml format.

    Code (Java):
       XmlConfiguration config = new XmlConfiguration();


    Since these alternative configuration formats are not included in spigot by default, you will need to shade them in to your final build.
    Code (Text):
     
            <dependency>
                <groupId>[library group id]</groupId>
                <artifactId>[library artifact id]</artifactId>
                <version>[library version]</version>
                <scope>compile</scope>
            </dependency>
           
        <build>
            <plugins>
         
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>3.1.1</version>
                    <configuration>
                        <relocations>
                            <relocation>
                                <pattern>[library package]</pattern>
                                <shadedPattern>[your package].[library name]</shadedPattern>
                            </relocation>
                        </relocations>
                    </configuration>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>shade</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
     



    Demo Plugin Link: https://www.spigotmc.org/resources/customfileconfig-demo.58204/

    Source: https://github.com/XDMAN500/CustomFileConfig


    Happy Coding!!
     
  2. This seems very cool, but I don't know why anyone would want to store in XML, JSON and Hjson when yaml is a more practical format. (in terms of resources used and the easiness of yaml)
     
    • Agree Agree x 1
  3. Yaml is indeed very easy to read and a practical format, however it unfortunately suffers when there is a heavy reliance on the end user to edit the configuration by hand. Uneven indentation is a common error that can cause many plugins to just throw out the entire configuration because it can't be read properly. This is usually seen when novice configuration editors want to make their own Essentials custom item or edit a kit for their favorite kitpvp plugin. Allowing a seamless switch to a fast and lightweight format that doesn't use indentation for mapping like Hjson is made easy with this API and only creates convenience for the plugin developer and the end user.

    All the other formats included in the project are just so I can show off how flexible the API is. I guess if you ever wanted to edit Jsoned NBT data with the Bukkit configuration API that option is now available.