Skip to content

配置API

配置文件用来储存配置信息, 以便使用文件开关功能、储存数据、修改信息.
我们往往需要读写配置文件. Bukkit为我们提供了配置API.

配置API是BukkitAPI提供的读写配置文件的工具. 其相对而言较为简单, 是插件开发中常用的API.

目前为止, 配置API只有YAML配置功能可用. 这也是大多数插件为什么配置文件是YAML文件的原因.
在本文中, 我们也将使用YAML配置API.

现在的配置API的类均在 org.bukkit.configurationorg.bukkit.configuration.file 包中.
但是这不代表你只能使用 YAML,如果你有无限的创意和实现方法,你甚至可以将表格作为配置文件以实现更现代化的配表方式.

了解YAML文件

键值对

相信开服的经验已经使你对YAML文件有了初步认识.
YAML文件的文件后缀是.yml. 其配置文件结构需要严格遵守YAML标准.

下面是一个符合标准的YAML配置文件的内容:

yaml
Settings:
  DebugMode: true
  Time:
    CoolDown: 10
Data:
  player1:
    NickName: HandsomeBoy
    Score: 50
    TotalTime: 40
    Title:
    - Toilet Protecter
    - Widow Maker
    - Chicken Fucker

相信你可以根据空格看出每个项目之间的所属关系, 如下:

我们把上面所属关系图中, 矩形框内的东西叫做键(Key). 例如, Settings是一个键, Data是个键. Settings键下存在DebugModeTime两个子键, 它们分别叫做Settings.DebugMode键和Settings.Time. 同理, 在Settings.Time键下还有CoolDown这个子键, 这个子键叫Settings.Time.CoolDown键.

我们可以用这样的命名方法来称呼一个YAML文件中的任一一个键了. 并且还可以根据名称看出所属关系.
例如, Data.player1.Score键对应的值是 50.

在YAML中, 键和值一一对应, 一个键一定会有一个值.

数据类型

通常可以用配置文件存储一些基本类型(int、double、boolean)、String、数组和可被序列化的对象.

Bukkit中给出的一些对象有些是可以直接存进配置文件的, 这需要看这个类是不是实现了ConfigurationSerializable接口. 例如, Player类型的对象就可以被直接存入配置文件, 因为查阅JavaDoc后可以发现它实现了ConfigurationSerializable.

后续会详细介绍, 这里需要知道判断方法.

在上面的配置文件中, 配置文件里储存了:

  1. 存储了一个boolean类型的值(Settings.DebugMode键).
  2. 存储了一些数字类型的值.
  3. 存储了一个String字符串(Data.player1.NickName键).
  4. 存储了一个StringList(YAML里的StringList就是Java中的List<String>, 例如Data.player1.Title键).

YAML中注释以#表示.

yaml
#就像这样写注释, 配置文件读取时会忽略掉注释
Settings:
  DebugMode: true

相信你可以通过这个例子明白配置文件中可以储存哪些数据了.

对于不存在的数据

很明显, 上面的配置文件中, 并没有Data.player2.NickName键, 那么如果我非要获取Data.player2.NickName键的值, 获取到的数据是什么呢?
答案是null. 换句话说, YAML里所有不存在的键, 值是null.

请记住这句话. 我们可以根据这个原理推导出, 如果你想删除一个已经存在的键, 那就是把这个键的值设置为null.

操作默认配置文件

这里的默认配置文件指的是config.yml文件.
首先我们需要准备一个默认的config.yml文件. 这个文件会在插件检测到plugins\插件名文件夹下没有config.yml文件时被放入该文件夹中.
在插件jar文件里, 默认的config.yml文件要与plugin.yml文件处于同一目录下, 所以创建默认config.yml的方法与创建plugin.yml文件的操作方法一致. 在这里我们在默认config.yml文件中存入我们一开始举的例子.

读取config.yml数据

下面做一个插件, 在玩家登陆服务器时, 给玩家显示配置文件Data.玩家名.Score键对应的值.

java
public class HelloWorld extends JavaPlugin implements Listener{
    public void onEnable(){
        saveDefaultConfig(); //这个代码会自动判断插件配置文件里是不是有config.yml, 没有就会放入默认的config.yml
        Bukkit.getPluginManager().registerEvents(this,this);
    }  
  
    public void onDisable(){}
  
    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent e){
        //在这里我们监听了PlayerJoinEvent, 并操作`config.yml`
        String key = "Data." + e.getPlayer().getName() + ".Score"; //这是我们要获取的键名
        int score;
        if(getConfig().contains(key)){ //先判断一下有没有这个键
            score = getConfig().getInt(key); //有的话读取
        } else {
            score = 0; //没有的话就按0处理
        }
        e.getPlayer().sendMessage("你的积分是: " + score); //然后给玩家发送
    }
}

如果你用getConfig().getString(key)获取玩家数据Score键的值, 那么获取到的就是一个String字符串.
也就是, YAML中值对应的数据类型具体是什么, 关键要看你用的getter是什么.

写入数据到config.yml

我们再来做个"加分项", 玩家挖掉一个石头后, 给他加分.

java
public class HelloWorld extends JavaPlugin implements Listener{
    public void onEnable(){
        saveDefaultConfig();
        Bukkit.getPluginManager().registerEvents(this,this);
    }  
  
    public void onDisable(){}
  
    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent e){
        //这里代码跟上面是一模一样的, 这里只是做了简化, 因为原先的if占篇幅太大
        String key = "Data." + e.getPlayer().getName() + ".Score";
        int score = getConfig().contains(key)?getConfig().getInt(key):0;
        e.getPlayer().sendMessage("你的积分是: " + score);
    }

    @EventHandler
    public void onBlockBreak(BlockBreakEvent e){
        if (e.isCancelled()) return; //判断此事件是不是被其它插件取消掉了
        if(e.getBlock().getType() == Material.STONE){ //判断类型, 是石头
            String key = "Data." + e.getPlayer().getName() + ".Score";
            int score = getConfig().contains(key)?getConfig().getInt(key):0; //获取玩家当前积分, 如果从未记录此玩家的积分数据则默认为0
            getConfig().set(key,score + 10); //挖一个石头加10分

            //但是写到这里要小心!你只是修改了内存上的数据, 你没有修改硬盘上的config.yml文件里的数据!
            saveConfig(); //所以要注意, 修改数据要记得保存
        }
    }
}

由此, 你需要小心, getConfig()的内容是内存上的内容, 修改它并没有修改硬盘上的内容, 关服/重载后就会消失, 因此要注意保存!

set不区分数据类型是什么, 存储数据全部都用set方法. set不管这个键在配置文件里存不存在, 都会写入这个数据.

还记得我们一开始说的YAML里所有不存在的键, 值是null吗? 如果你想删除掉player3的数据, 那你应该写成:

java
getConfig().set("Data.player3",null);

这样配置文件里Data键下就没有player3的数据了,也就达到了删除一个键的目的.

操作自定义的配置文件

关于非config.yml的YAML文件的操作, 有很多种方式可以做到.
下文叙述的是其中的一种.

准备默认配置文件

我们还是需要像config.yml那样准备一份默认配置文件, 放在与plugin.yml相同目录下. 不同的是, 除了saveDefaultConfig以外, 我们还需要其他的代码来保存默认配置文件.

例如我们有config.ymlbiu.yml两个配置文件, 插件加载时应该这样生成默认配置文件:

java
this.saveDefaultConfig(); //生成默认config.yml
this.saveResource("biu.yml", false); //生成默认biu.yml

saveResource方法的第一个参数是文件名, 第二个参数是是否覆盖, 设置成false可以达到saveDefaultConfig的效果.

同理,利用saveResource可以生成你想生成的默认的非config.yml的配置文件.

如果我想实现在插件配置文件夹创建一个新的文件夹存放配置文件怎么做呢? 很简单:

this.saveResource("test\biu.yml", false); //生成默认biu.yml, 放在test文件夹里, Jar文件中也需要有test文件夹

基本读写与保存

下面是一个读写与保存的示例:

java
// 读取配置文件
// this.getDataFolder()方法返回插件配置文件夹的File对象
File biuConfigFile = new File(this.getDataFolder(), "biu.yml");
// 也可以在插件配置文件夹创建一个新的文件夹以存放配置文件
// File biuConfigFile = new File(this.getDataFolder(), "test/biu.yml");
FileConfiguration biuConfig = YamlConfiguration.loadConfiguration(biuConfigFile);
biuConfig.get.......
biuConfig.set.......
// set完了记得保存!
biuConfig.save(biuConfigFile);