提供: Minecraft Modding Wiki
2013年4月29日 (月) 22:20時点におけるUcchy (トーク | 投稿記録)による版 (任意の設定)
移動先: 案内検索

Configuration APIは、人が読み書き可能な形式のコンフィグファイルの解析と出力を素早く行う機能のセットです。

~APIという名前によらず、簡単にプラグインのデータを、コンフィグファイルへ保管する事が出来ます。
YAML 形式のファイルのみに対応しています。
APIは、いかに独自の拡張に対応しやすくするかを考えて設計されています。

Configuration APIは、org.bukkit.configurationorg.bukkit.configuration.file パッケージの配下にあります。
Bukkit1.1-R5以前に作られたプラグインは、org.bukkit.util.configurationパッケージ配下に存在した、
古いライブラリを利用した実装を採用しているかもしれません。
新旧の実装方法には互換性がありませんので、古いパッケージを使う処理は除去して下さい。

このページの解説は、オブジェクト指向とJava、Bukkitプラグインの基本的な設計に関する知識が、
いくらかある読者に読まれる事を想定しています。
このページは、BukkitのJavadoc内のFileConfiguration Classに取って代わる内容ではありません。

基礎

コンフィグファイルのオブジェクト

あなたのプラグインがJavaPluginをextendsし、フィールドとメソッドを継承しているものとして話を進めます。

継承メソッドgetConfig()は、 org.bukkit.configuration.file.FileConfiguration型のオブジェクトをreturnしますが、 このオブジェクトは、プラグインのデータフォルダ配下のconfig.ymlに相当します。

初めてgetConfig()が呼び出されたタイミングでは、ディスク上のconfig.ymlの内容と、プラグインのJarファイル中に定義されたデフォルト値が、メモリ上にロードされ、その内容が戻り値として返されます。2回目以降のgetConfig()の呼び出しでは、メモリ上に存在するFileConfigurationオブジェクトが戻り値として返されます。

このオブジェクトは、明示的に保存しない限りディスクへ保持されません。同様に、config.ymlファイルに加えられた変更も、メモリ上にロード済みのオブジェクトには反映されません。

config.ymlがデータフォルダ配下に存在しない場合は、空のconfig.ymlファイルを読み込んだ事と等しい結果となり、FileConfigurationオブジェクトも空の状態でロードされます。

Attention.pngWarning: getConfig()の戻り値は、staticなフィールドに割り当てないで下さい。
Attention.pngWarning: このような割り当てを行うと、getConfig()はreloadConfigの後でも再び割り当て処理を繰り返してしまいます。
File Lightbulb.pngNote:getConfig()の戻り値は一旦適切なフィールドに割り当ててから利用する事をお勧めします

デフォルト値

config.ymlのデフォルト値は、プラグインのユーザに提供されます。 設定ファイルが、プラグインのデータディレクトリ配下に存在しない, 空である, キーが無い・・・といった状態である場合には、プラグインのJarファイル内に定義された値が、デフォルト値としてロードされます。

デフォルト値は、データフォルダ配下に存在するconfig.ymlが提供しようと意図していた内容と、まったく同一な内容のYAML形式ファイルによって提供されるべきで、そのファイル名はconfig.ymlであり、plugin.ymlと同一の場所に配置されている必要があります。

プラグインのデータフォルダ配下のconfig.ymlをデフォルト値で上書きしたい場合は、JavaPluginクラスのsaveDefaultConfig()メソッドを呼び出す必要があります。既存のファイルを上書きしたくない場合は、copyDefaultsオプションにtrueを設定します。

動的な値をデフォルト値とする場合、addDefaults(Map<String,Object>)やaddDefault(String, Object)のようにコーディングする事で実現できます。

特殊なケースとして、新規のデフォルト値を既存のconfig.ymlに追加したい場合は、copyDefaultsにtrueをセットします。

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

コンフィグ値の取得

コンフィグ値の読み込み処理は、複数のgetterメソッドの呼び出し処理から成ります。全てのgetterメソッドの一覧はこちらです。一般的な用途のgetterメソッドは下記です。

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

Keyの活用

キーを用いたコンフィグ値の取得処理には、FileConfigurationSection(コンフィグファイルの階層構造を表すオブジェクト)と、それにアクセスするためのキーと呼ばれる値を利用して行います。キー値の取得にはgetKeys(boolean)メソッドを用い、セクションの取得にはgetConfigurationSection(String)メソッドを用います。キーに先立って、コンフィグファイルのセクションが必要です。

getKeys(boolean)メソッドのboolean型パラメタは、キーを再帰的に取得するかどうかを指定します。trueであれば、子階層のキーも含めて取得します。falseであれば、対象階層のみのキーを返します。

  • getKeys(boolean)
File Lightbulb.pngNote: このメソッドは、String型のSet を返します。

コンフィグ値のセット

コンフィグ値をセットするには、設定ファイルのインスタンスのset(String, Object)メソッドを利用します。FileConfigurationのgetメソッドとは異なり、setメソッドは1種類しか存在しません。setメソッドであらゆる型のオブジェクトがセット出来る訳ではく、下記のデータ型のオブジェクトだけがセット可能です。

  • プリミティブ
  • String
  • List
  • VectorItemStackのようなConfigurationSerializableインタフェースを実装した型

コンフィグ値を削除するにはnullをセットします。セット処理は、メモリ上に展開されたコンフィグ値に対してのみ行われ、コンフィグ値をファイルにセーブしなければ、サーバを再起動したタイミング(正確にはプラグインがdisabledされたタイミング)で失われます。

利用例:

// 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);


HashMapの活用

HashMapをコンフィグ値としてセーブする場合は、ConfigurationSectionを利用して下さい。 また、HashMapはキーがString型、値がConfigurationSerializableを実装したデータ型でなければなりません。

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

コンフィグファイルのセーブ

setメソッドを利用してFileConfigurationに多くの変更を加えるか、Lists(設定値インスタンスの内部値がList派生型になっている領域を指している)の内容を変更した場合、プラグインの無効化後も残したい設定値であればディスクに書き出すべきです。saveConfigメソッドを呼び出して、既存の(ディスク上の)コンフィグファイルに上書き保存しましょう。

this.saveConfig();

ディスクからのリロード

プラグインのデータフォルダ上のconfig.ymlが、ユーザによって変更されている可能性を疑って下さい。この変更点はメモリ上の設定値に反映されていません。reloadConfig()メソッドを呼び出して、ディスク上の設定値をプラグインにロードする事ができます。ただしメモリ上の設定値が、ロード内容で上書きされる事にも留意して下さい。

this.reloadConfig();

応用

以下は、より高度なプラグインを製作するための、応用のトピックです。
あなたは既定のconfig.ymlを作成するだけでよく、保存したり、移動したりする必要は今後ありません。

コンフィグのオプション

全てのFileConfigurationインスタンスは、FileConfigurationOptions オブジェクトに紐付いています。
FileConfigurationOptionsオブジェクトは、FileConfigurationの動作を制御することができます。
FileConfigurationoptions()メソッドは、対応したFileConfigurationOptionsを返します。
これを使って、オプションの現在内容の確認をしたり、設定を行うことができます。
現在、4つのオプションがあります。
メソッドはオーバーロードされているものがあり、例えば、copyDefaults()はブール値を返しますが、copyDefaults(boolean)は自分自身を返します。
訳者注 引数を指定しないメソッドはオプション値を返し、引数を指定するメソッドはオプション値を設定するようです。

CopyDefaults

CopyDefaultsオプションはConfigurationクラスのsaveメソッドを変更しています。
既定では、デフォルトのコンフィグを保存先ファイルに上書きしません。
もし引数にtrueが設定された場合、ファイルの上書きをします。
しかし、1度書き込みが行われるのみで、あなたがデフォルト値を変更したとしてもその値が反映されるわけではありません。

PathSeparator

PathSeparatorは、コンフィグの階層を示すセパレータ文字の変更を行うことができます。
既定では「.」(ピリオド)ですが、好きな文字へ変更することが可能です。

Header

HeaderはYAMLファイルの上部のコメントブロックの変更を行うことができます。
HeaderはコンフィグAPIの中で、唯一、コメントをコピーすることができる手段です。

copyHeader()

もしcopyHeader()がtrueを返したら、既定のconfig.ymlから保存先にヘッダーを保存したことを示します。

任意の設定

構成情報の格納やゲームの追加情報を保存する追加の YAML ファイルが必要な場合は、追加のコンフィグファイルにアクセスするための独自のメソッドを記述する必要があります。
JavaPlugin クラスの getConfig、reloadConfig、saveConfig メソッドをモデルとして、カスタムコンフィグファイルを保存する独自のメソッドを記述する方法を示します。
これらの config ファイルはプラグインに属しているため、config.yml が配置されるパッケージにおいて、アクセス権をもったメソッドからアクセスされる必要があります。
これらのメソッドの各 YAML ファイルのセットを記述する必要があります。
ここでは、利点はであるデフォルトの config.yml を提供されているメソッドと同じ方法で各セットを使用することができます。
代わりに、追加メソッドは少なくすみ、複数ファイルへのアクセスをすることもできます。

JavaPlugin 実装をミラーリング

JavaPlugin メソッドの config.yml を実装します。
プラグインはプラグインに固有のコンフィグファイルにアクセスする独自のメソッドを実装する必要があります。
プラグインのメソッドを実装した後、それと同じコンテキストで継承されたgetConfig()reloadConfig()saveConfig()、および saveDefaultConfig()メソッドで呼び出すことができます。
下記のコード例では、1つのクラスで複数の yaml ファイルにアクセスすることができます。
このようなクラス実装例を、 ここに 示します。

まず、2つのフィールドを宣言し、カスタム構成ファイルごとに null に初期化する必要があります。
1つはFileConfigurationオブジェクトを保持し、1つはFileオブジェクトを保持します。
Fileオブジェクトはディスク上のファイル、FileConfiguration は設定の内容を表します。

private FileConfiguration customConfig = null;
private File customConfigFile = null;
リロードの実装

次に、ディスクからコンフィグを読み込むメソッドを記述します。
ファイルをロードし、デフォルトの customConfig.yml の jar を検索します。

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

    // jarファイルの中からデフォルトを探します。
    InputStream defConfigStream = this.getResource("customConfig.yml");
    if (defConfigStream != null) {
        YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream);
        customConfig.setDefaults(defConfig);
    }
}
取得処理の実装

次に、取得処理メソッドを記述する必要があります。
CustomConfigをディスクから読み込む場合、nullであるかを確認します。

public FileConfiguration getCustomConfig() {
    if (customConfig == null) {
        this.reloadCustomConfig();
    }
    return customConfig;
}
保存の実装

最後に、変更を保存しディスク上のファイルを上書きする、保存メソッドを記述します。

public void saveCustomConfig() {
    if (customConfig == null || customConfigFile == null) {
        return;
    }
    try {
        getCustomConfig().save(customConfigFile);
    } catch (IOException ex) {
        this.getLogger().log(Level.SEVERE, "Could not save config to " + customConfigFile, ex);
    }
}
規定値の実装

必要に応じて、JavaPlugin の saveDefaultConfig() メソッドを模倣するメソッドを記述することができます。

public void saveDefaultConfig() {
    if (customConfigFile == null) {
        customConfigFile = new File(getDataFolder(), "customConfig.yml");
    }
    if (!configFile.exists()) {            
         this.plugin.saveResource(fileName, false);
    }
}

シリアライズとデシリアライズ

コンフィグAPI は、前述のようにConfigurationSerializableインターフェイスを実装する Java オブジェクトを格納することができます。
オブジェクトのシリアル化では、各種オブジェクトを簡単に保存したり読み込んだりする仕組みを、実装者に提供してくれています。
開発者は'Locationを取得できるシリアライズラッパークラスを使うことで、YAMLにLocationを保存するような処理がとても簡単に使用することができます。

API でシリアル化することができますようにクラスはConfigurationSerializableインターフェイスを実装するだけでなく、また implment、Javadoc で指摘したように、以下のいずれかの必要があります。

  • 1つのMapを受け入れるコンストラクター
  • 1つのMapを受け入れてクラスを返す、"deserialize" という名前のstaticメソッド
  • 1つのMapを受け入れてクラスを返す、"valueOf" という名前のstaticメソッド

シリアライズされたオブジェクトをデシリアライズするには、ConfigurationSerialization に登録されている必要があります。
registerClass メソッドは、シリアル化されたクラスごとに1回呼び出す必要があります。

このステートメントは、メインクラスの初期化ブロックに記述することができます。

ConfigurationSerialization.registerClass(Class<? extends ConfigurationSerializable>)

エイリアス

クラスがシリアル化されるとき、完全修飾名でマークされています。

エイリアスをクラスに設定しておくと、代わりにクラスが、エイリアスの完全修飾名を持つ形でシリアル化されません。
SerializeAsアノテーションを、ConfigurationSerializableを実装するクラスに指定します。

@SerilizeAs(String)

エイリアスをクラス登録と共に行いたい場合は、登録時に引数に一緒に指定します。

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

利用例

以下は、新しい Configuration API を使ってプラグインを実装した例です。
プレイヤー参加時に config.yml から message を取得して MOTD としてメッセージを表示したり、 rulesコマンド実行時に config.yml から rules を取得して表示したりします。
なるべく手短な例を示したので、最適な実装例になっていないことをご了承ください。

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 {

    @Override
    public void onEnable() {
        // もしconfig.ymlが存在しないなら、既定のconfig.ymlをコピーします。
        this.saveDefaultConfig();
        
        // 新しいリスナーを登録します。
        getServer().getPluginManager().registerEvents(new Listener() {
            
            @EventHandler
            public playerJoin(PlayerJoinEvent event) {
                // プレイヤーがサーバーに参加したときに、config.ymlに書かれたメッセージを送ります。
                event.getPlayer().sendMessage(SimpleMOTD.this.getConfig().getString("message"));
            }
        }, this);

        // rulesコマンドのCommandExecutorを登録します。
        this.getCommand("rules").setExecutor(new CommandExecutor() {
            
            public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
                // コマンド実行時にコマンド実行者へ、config.ymlのrulesの内容を送ります。
                List<String> rules = SimpleMOTD.this.getConfig().getStringList("rules");
                for (String s : rules)
                    sender.sendMessage(s);
                }
                return true;
            }
        });
    }
}

デフォルトのconfig.ymlの内容は、下記のとおりです。

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