4 Data Structure Guide
Daniel Saukel edited this page 2021-02-08 23:32:53 +01:00

This article does not have anything to do with DungeonsXL, it explains some basic concepts that are related to Minecraft servers in general, but are asked repeatedly here and on the DXL Discord server.


  1. YAML
  2. Data types

YAML

YAML (a recursive acronym for "YAML Ain't Markup Language") is a human-readable data-serialization language. It is commonly used for configuration files and in applications where data is being stored or transmitted. ~https://en.wikipedia.org/wiki/YAML

Because YAML libraries are integrated in the Bukkit API, it became a de facto standard for configuration and data files wherever databases are not needed or wanted.

DungeonsXL too uses YAML files (.yml) for multiple purposes. Its usage is mostly intuitive, but often, users fail to understand the logic behind more complex structures. For the sake of comprehensibility to end-users, this guide does not differentiate between "YAML" and the Bukkit configuration API.

YAML files consist of key-value pairs.

Plugins use the key to search for the information in the file and the value is the actual data.

key: value

One configuration section may contain multiple keys. YAML does not care for the order of its keys.

key1: value
key2: value

equals:

key2: value
key1: value

A value may be a configuration section.

That means, you might find keys containing a simple string next to a key that contains a whole new configuration section.

key1: {key1_1: value, key1_2: value}
key2: "some string"

YAML syntax is rather tolerant.

There are often multiple ways to express a certain data type. Strings do not necessarily need the " symbols to show where they begin and end. ' is equally valid, and key: validString will also be recognized as a string without these symbols. However, some strings that contain some symbols need ' or " to be recognized (correctly).

Unfortunately, the YAML library that Bukkit uses generates string values only then with ', if the symbol is required, and leaves it out if it is not. That being said, it does not hurt to add " or ' to your config when you replace a generated string value with a different string even if the generated one worked without them.

YAML is indentation-sensitive.

Remember the "configuration section in a configuration section" example above?

key1: {key1_1: value, key1_2: value}
key2: "some string"

This equals:

key1:
  key1_1: value
  key1_2: value
key2: 'some string'

Which is much easier to read, especially if there are many key-value pairs in "key1". It however seems that some people cannot intuitively tell that "key1_1" and "key1_2" are inside key1. A reason for this might be that YAML allows different amounts of indents for child keys, and both two and four indents are commonly used. However, do not mix key-value pairs that have two and four indents.

This also equals the YAML above:

key1:
    key1_1: value
    key1_2: value
key2: 'some string'

But this is wrong:

key1:
    key1_1: value
  key1_2: value
key2: 'some string'

Make sure that the indents match relatively compared to the parent key, especially if you copy a section from another config where it has, absolutely, fewer or more indents.

Mistakes if it comes to this often occur when a user copies a configuration section that is a serialized custom item from Caliburn / ItemsXL into a loottable.

It is possible for plugins to expect different types of data in one key.

As it has been mentioned just yet, let us use the example of a configuration setting where a custom item is the expected input to explain one more thing.

The following config may tell the plugin that the user would like to have an iron helmet set as an entity's helmet.

helmet: "IRON_HELMET"

But what if one needs a more complex item with meta data where putting all data into one string would be too messy?

helmet:
  ==: de.erethon.caliburn.item.CustomItem # Internal Bukkit configuration API stuff
  name: "MY_CUSTOM_HEAD"
  material: "PLAYER_HEAD"
  skullOwner: "baaa8e9f-5fda-4429-a1db-564a6d06eab4"
  textureValue: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE5OTM0MmUyYzczYTlmMzgyMjYyOGU3OTY0ODgyMzRmMjU4NDQ2ZjVhMmQ0ZDU5ZGRlNGFhODdkYjk4In19fQ=="
  ...

(Note: This is not an item format DungeonsXL currently uses)

Use yamllint.com

A parser like yamllint.com can help you figuring out if your YAML is syntactically correct. It can also automatically give your YAML a consistent look.

Note that a parser can only check for syntactical errors. If you made a semantical error, it cannot help you.

Data types

Primitive types

Type Size Annotation Example
Byte 8 Bit Numeric value from -128 to 127 key: 64
Short 16 Bit Numeric value from -32,768 to 32,767 key: 367
Integer 32 Bit Numeric value from -2^31 to 2^31-1 key: 5000
Long 64 Bit Numeric value from -2^63 to 2^63-1 key: 1525199972497
Float 32 Bit Decimal number key: .23
Double 64 Bit Decimal number (may be large af) key: 5430.674343
Boolean 1 Bit True / false value key: true

String

A String is a sequence of characters. Since some values break the YAML syntax, you might need to add "" to indicate the beginning and the end of the string.

key: "This is a String"

List

A list is a value that consists of multiple elements that may be different data types or lists themselves. They are not to be confused with maps as the elements do not have keys and are all of the same type.

key:
  - "element"
  - "another element"

equals

key: ["element", "another element"]

Map

key:
  value_key: "Value String"
  another_value_key: 5.678
otherKey: "This value is next to, but not inside the section of 'key'."

equals

key: {value_key: "Value String", another_value_key: 5.678}
otherKey: "This value is next to, but not inside the section of 'key'."

Note: The Bukkit configuration API can only represent maps as sections of the configuration. In this user-oriented wiki, the terms "configuration section" and "map" are mostly used as synonyms, even though developers must not confuse them with each other.

Types represented by strings

Some data types are not actually strings, but simple enough to be represented by a single string. The plugin handles the conversion into the actual data type.

Common examples are UUIDs and enumeration values (materials, inventory slot names, ...).