Introduction to the New Configuration/ru

Configuration API это набор инструментов направленных на помощь разработчику в быстрой загрузке и записи конфигурационных файлов, которые удобны для чтения и редактирования человеком. В настоящее время система поддерживает только YAML для разметки конфигурационных файлов. However, with the API, new formats can be added, as the overall API is meant to be schema agnostic.

For those of you who are already developing, you may have been surprised at the deprecation of the org.bukkit.util.Configuration package, but fear not for it has been replaced with something that is more powerful! You may be asking yourself: How do I use the new API? For those who are new to Bukkit Plugin Development, you may be asking yourself: How do you get started with creating configuration files?

This introduction assumes you have some knowledge about Java, programming Bukkit plugins, and Object-oriented programming.

## Basic Topics

### The Configuration Object

Your plugin extend JavaPlugin, doing so, you inherited methods and fields from JavaPlugin. The inherited method, *getConfig()* returns an object of type org.bukkit.configuration.file.FileConfiguration. This is the object that represents *config.yml* inside your plugin's data folder.

The first time *getConfig()* is invoked on your plugin, *config.yml* is loaded from disk, and default values are loaded from the jar. Subsequent invocations of *getConfig()* will return the exiting *FileConfiguration* object that is in memory. Operations performed on this object will not be written to disk unless explicitly saved. Likewise, any modifications done after the file has been loaded will not be reflected in the object. If *config.yml* does not exist in your data folder, it is equivalent to an empty *config.yml*, and will load an empty *FileConfiguration*.

 **Warning**: if you assign the returned object from *getConfig()* DO NOT assign it to a static field
  **Warning**: if you do the above, assign *getConfig()* to the variable AGAIN after a reloadConfig

 **Note**: it is better to just use *getConfig()* instead of storing it
### Значение по-умолчанию

Default values for your *config.yml* should be provided for the user of your plugin. If the config file in your plugin's data directory does not exist, is empty, or is missing keys, it will load the missing keys and values from your jar. Defaults should be provided in a YAML file that has the exact same structure as you intend config.yml to have. The file must be named *config.yml* and be placed in the same directory as your plugin.yml. If you want to copy and overwrite the defaults into the plugin's data folder, you will need to invoke the *saveDefaultConfig()* method of JavaPlugin. If you do not wish to overwrite the existing files, you set the copyDefaults option to true

If you are using dynamic values for defaults, defaults can be added to the configuration within code with addDefault(String, Object) and addDefaults(Map<String,Object>) methods.

In certain cases if you wish to append new defaults to an existing config.yml you can set the option copyDefaults to true

```
getConfig().options().copyDefaults(true)

```

### Получаем значения

Чтение значений из конфиг. файла производится при помощи одного из get методов. Полный список можно найти тут. Некоторые из наиболее используемых методов указаны ниже.

* getBoolean(String)
* getInt(String)
* getString(String)
* getList(String)
* getStringList(String)

#### Keys

The retrieval of keys being not values behaves differently from the other get methods. Invoking the method returns the set of keys for the current *FileConfigurationSection*. To get the section you will have to invoke *getConfigurationSection(String)* before invoking *getKeys(boolean)*. The boolean value determines if the returned set is recursive, if true it will return the keys of the given section and their children keys, if false will only return keys of the given section.

* getKeys(boolean)

 **Note**: This now returns a Set of Strings
### Setting Values

Writing values involves invoking the *set(String, Object)* method on an instance of Configuration. Unlike the different get methods that *FileConfiguration* has, there is only one set method. Not all objects can be set, only primitive types, *String*, *Lists*, and types that implement *ConfigurationSerializable*, such as *Vector* and *ItemStack*, can be set. To erase a value supply null as a parameter. All changes made by set will only affect the copy of the configuration in memory, and will not persist beyond restarting the server until the configuration is saved. Following are some example uses:

```
// setting a boolean value
this.getConfig().set("path.to.boolean", true);

// setting a String
String string = "Hello World!";
this.getConfig().set("path.to.string", stringValue);

// Setting a List of Strings
// The List of Strings is first defined in this array
String[] listOfStrings = {"Hello World", "Welcome to Bukkit", "Have a Good Day!"};
this.getConfig().set("path.to.list", Arrays.asList(listOfStrings);

// Setting a vector
// event is assumed to be an existing event inside an "onEvent" method.
Vector vector = event.getPlayer().getLocation().toVector();
this.getConfig().set("path.to.vector", vector);

// Erasing a value
this.getConfig().set("path.to.value", null);

```

#### HashMaps

If you wish to set a *HashMap*, you will instead need to create a *ConfigurationSection*. You can only save a HashMap where the key is a string the the value is something that is already ConfigurationSerializable.

```
createSection (String path, Map< String, Object > map)

```

### Сохранение файла

If make any changes to the*FileConfiguration* with set methods, or mutate any *Lists*, you will need to save the changes to disk if you wish to keep these changes after the plugin is disabled. To save the file to disk invoke the saveConfig method for your plugin, it will overwrite the file already there.

```
this.saveConfig();

```

### Перезагрузка с диска

If you suspect that users have made changes to the *config.yml* in the data folder, those changes are not reflected in memory. Invoke the *reloadConfig()* method of your plugin to load from the disk again. It will destroy all changes in memory.

```
this.reloadConfig();

```

## Advanced Topics

The following are some more advanced topics, meant for more advanced plugins. If you only require the default *config.yml*, creating custom methods for reading, and saving, you will not need to go this far.

### Опции

Every *FileConfiguration* instance is associated with a FileConfigurationOptions object. The *FileConfigurationOptions* object controls the behavior of the *FileConfiguration* it is associated with. *FileConfiguration'*s *options()* method returns the *FileConfigurationOption's* responsible for it. With it you can check and set each option. There are currently four options. Be aware that the methods are overloaded, for example *copyDefaults()* which returns a boolean and *copyDefaults(boolean)* which returns it self, but has a side effect which changes the state.

#### CopyDefaults

The *copyDefaults* option changes the behavior of Configuration's save method. By default, the defaults of the configuration will not be written to the target save file. If set to true, it will write out the default values, to the target file. However, once written, you will not be able to tell the difference between a default and a value from the configuration.

#### PathSeperator

PathSeperator changes the character that is used to separate the different levels of the configuration. By default it is the "." (period) but it can be changed to any char.

#### Header

Header is the comment block at the top of a YAML file, it is applied to the save output. The header is the only comment that Configuration API knows how to copy.

#### copyHeader

If *copyHeader()* returns true then the header will be copied on save, from the default source.

### Methods for Getting, Reloading, and Saving Custom Configurations

If you require additional YAML files, for storing configuration information or persisting additional game information you will need to write your own methods for accessing the additional configuration files. Modeled after JavaPlugin methods, the following is an example how to write your own methods to read and save to custom configuration files. Since these config files belong to your plugin, you can put this method in your main class so that you can have the same access as you have with config.yml. You will have to write a set of these methods for each YAML file. The advantage here, is that you can use each set in the same manner as the provided methods for the default config.yml.

 First you will need to declare two fields and initialize them for the custom configuration. One to hold the *FileConfiguration* and one to hold the File. The File Object represents the file on the disk, and the FileConfiguration represents the contents of the configuration.

```
private FileConfiguration customConfig = null;
private File customConfigFile = null;

```

 Then, write the method that is responsible for loading the config from disk. It will load the file, and search the jar for a default customConfig.yml.

```
public void reloadCustomConfig() {
 if (customConfigFile == null) {
 customConfigFile = new File(getDataFolder(), "customConfig.yml");
 }
 customConfig = YamlConfiguration.loadConfiguration(customConfigFile);

 // Look for defaults in the jar
 InputStream defConfigStream = getResource("customConfig.yml");
 if (defConfigStream != null) {
 YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream);
 customConfig.setDefaults(defConfig);
 }
}

```

 Next, you need to write the getter method. Check if *customConfig* is null, if it is load from disk.

```
public FileConfiguration getCustomConfig() {
 if (customConfig == null) {
 reloadCustomConfig();
 }
 return customConfig;
}

```

 Finally, write the save method, which saves changes and overwrites the file on disk.

```
public void saveCustomConfig() {
 if (customConfig == null || customConfigFile == null) {
 return;
 }
 try {
 customConfig.save(customConfigFile);
 } catch (IOException ex) {
 Logger.getLogger(JavaPlugin.class.getName()).log(Level.SEVERE, "Could not save config to " + customConfigFile, ex);
 }
}

```

 After adding these methods to your plugin's main class, you can use them in the same way as the inherited *getConfig()*, *reloadConfig()*, and *saveConfig()* methods.

### Serializing and Deserializing Objects

The Configuration API, as mentioned above can store Java objects that implment the *ConfigurationSerializable* Interface. Object serialization facilitates easy saving and loading so plugin authors can focus on other parts of their plugin. It greatly simplifies tasks such as storing a *Location* in YAML, a developer can serialize a wrapper class, which provide methods to retrieve a *Location*.

Classes, in addition to implementing the *ConfigurationSerializable* interface must also implment one of the following as noted in the Javadoc, so that they can be serialized by the API:

* A constructor that accepts a single *Map*.
* A static method "deserialize" that accepts a single *Map*and returns the class.
* A static method "valueOf" that accepts a single Map and returns the class.

 **Note**: a nested ConfigurationSerializable object is returned as type Map and needed to be casted as such and given to one of the deserialization methods when the parent class is being deserialized
In order for a serialized object to be deserialized, it must also be registered with ConfigurationSerilization. The static registerClass method must be invoked once per class that has been serialized.

This statement can be placed in a static initializer block in your main class.

```
ConfigurationSerialization.registerClass(Class<? extends ConfigurationSerializable>)

```

#### Aliases

When classes are serialized they are marked with their fully qualified name.

You can provide an alias to your class so that it does not serialize with the fully qualified name of your class, but the alias instead. You provide the alias with the *SerializeAs* annotation to the class implementing *ConfigurationSerializable*.

```
@SerilizeAs(String)

```
 When registering a class with an alias, the alias must be provided on registration.

```
ConfigurationSerialization.registerClass(Class<? extends ConfigurationSerializable>, String)

```

## Example Use

Below is the an example plugin that uses the new Configuration API to store messages to be displayed as an MOTD as players join, and for the player to retrieve the rules on command. It does not follow proper style and plugin layout as it was made to fit within 50 lines.

```
import java.util.\*;
import org.bukkit.command.\*;
import org.bukkit.event.\*;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.configuration.file.FileConfiguration;

public class SimpleMOTD extends JavaPlugin {

 public void onDisable() {
 System.out.println(this.toString() + " disabled");
 }

 public void onEnable() {
 getServer().getPluginManager().registerEvents(new Listener() {
 @EventHandler
 public playerJoin(PlayerJoinEvent evt) {
 event.getPlayer().sendMessage(getConfig().getString("message"));
 }
 }, this);

 this.getCommand("rules").setExecutor(new CommandExecutor() {

 public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
 List<String> rules = getConfig().getStringList("rules");
 for (String s : rules)
 sender.sendMessage(s);
 }
 return true;
 }
 });

 this.getConfig().options().copyDefaults(true);
 saveConfig();
 System.out.println(this.toString() + " enabled");
 }
}

```
 The default config.yml

```
# default config.yml
message: Hello World and Welcome! :)
rules:
- Play Nice
- Respect others
- Have Fun

```