第五节 如何编写配置文件

上一节 下一节

第一章 第五节 如何编写配置文件

参与编写者: MagicLu550

建议学习时间: 40分钟

学习要点: 了解如何创建配置文件,了解使用SimpleConfig

配置文件用于存储插件的配置信息,供用户自定义和修改,以及存储一些永久数据,我们称
配置文件属于 持久层

nukkit提供了多种配置文件格式,如yaml,json,properties等,其中最常用的是yaml,
我们主要讲解这个配置文件格式,其他如果想要了解,可以发送issues,我们可以补充。

一. 关于yaml

nukkit的yaml框架基于snakeYaml实现的,
snakeYaml是一款使用广泛的yaml解析库,我们可以从它的官网了解
他们的语法,在nukkit开发中,我们更多使用key: value的映射形式

这是一个yaml的文件案例

1
2
3
4
5
6
7
8
server:
name: 12
player:
- nihao
- xiaoming
- xiaogang
time:
year: 2019

yaml的标准语法是使用空格来划分级别,前面为键,后面为值,且值和冒号之间有空格,
虽然yaml的语法不止如此简单,但是我们最常用的也就这些很简单的东西。

yaml的数组有两个表示形式

1
2
3
4
5
6
7
array1: ["1","2"] #yaml的注释
array2: [1,2] #yaml不允许有重复的键
array3:
- 1
- 2
- 3

如果还要了解其他,可以上yaml官网查看他们语法,这里只讲解这些语法

二. 如何使用nukkit的配置文件库

原本的snakeYaml使用起来比较复杂,因此nukkit官方提供了简化,同一
使用Config对象来表达和操作。

使用默认的配置

默认配置文件为config.yml,可以通过saveDefaultConfig()方法来实现,
前提是你的resources下面要创建一个config.yml,这个方法会默认在
plugins/${你的插件名字}下创建一个config.yml,并且会把resources下面的那个
config.yml内容复制过来.
5-01
之后我们调用这个方法即可
5-02
我们这里打开一个服务器,做一个实验可以看看,插件名为FirstPlugin
5-03
我们插件被加载成功,我们看看我们的文件夹
5-04
发现./plugins/FirstPlugin下面出现了一模一样的config.yml

使用自定义的配置

自定义配置有两种方式,一种是已经初始化的文件,一种是空白文件,元素后期添加

  1. 初始化的文件
    saveResource(String fileName, boolean replace)

第一个是文件名称,默认是this.getDataFolder()+“/”+fileName的路径
getDataFolder()为./plugins/你的插件名 ,不包含后面的"/",使用时记得注意
假如你的插件名称为abc,那么路径为./plugins/abc

第二个是是否替换文件,每次重新启动服务器时,会把文件内容重新更新,如果为false,
则不会更新。或者已经存在config,将不会换掉。如果为true,那么就会换掉它。之前修改
的内容就会被替换(实际上加了true就是把文件删掉重新创建一遍)

而文件初始化的来源和之前的config.yml一样,我们可以看看saveDefaultConfig()源码会发现,
它的本质也是saveResource

PluginBase.java

1
2
3
4
5
6
7
@Override
public void saveDefaultConfig() {
if (!this.configFile.exists()) {
this.saveResource("config.yml", false);
}
}

  1. 空白文件
    空白文件的文件默认没有getDataFolder(),它的默认路径是和nukkit.jar同一级别的文件目录.
1
2
Config config = new Config(this.getDataFolder()+"/myConfig.yml",Config.YAML);
config.save();//保存文件,文件不存在就会创建

Config可以实现对文件的操作,例如先前的config.yml,我们想对其实现操作,可以

1
2
3
Config config = new Config(this.getDataFolder()+"/config.yml",Config.YAML);
config.set("me","12");//将me修改为12,如果me不存在将创建me
config.save();

当然值得注意,每次重新运行,set都会修改一次me,所以如果手动修改了me,就会被还原。
所以你可以做一个条件判断来避免还原的问题,比如判断文件是否存在。
当然这是初始化文件出现的问题,我还是建议初始化文件使用saveResource来初始化

Config的常用方法
1.构造方法

我们可以看官方源码

Config.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Constructor for Config instance with undefined file object
*
* @param type - Config type
*/
public Config(int type) {
this.type = type;
this.correct = true;
this.config = new ConfigSection();
}

/**
* Constructor for Config (YAML) instance with undefined file object
*/
public Config() {
this(Config.YAML);
}

public Config(String file) {
this(file, Config.DETECT);
}

public Config(File file) {
this(file.toString(), Config.DETECT);
}

public Config(String file, int type) {
this(file, type, new ConfigSection());
}

public Config(File file, int type) {
this(file.toString(), type, new ConfigSection());
}


file为文件名称,默认路径为nukkit的根目录
type为类型,主要使用的类型是

Config.java

1
2
3
4
5
6
7
8
9
10
11
public static final int DETECT = -1; //Detect by file extension
public static final int PROPERTIES = 0; // .properties
public static final int CNF = Config.PROPERTIES; // .cnf
public static final int JSON = 1; // .js, .json
public static final int YAML = 2; // .yml, .yaml
//public static final int EXPORT = 3; // .export, .xport
//public static final int SERIALIZED = 4; // .sl
public static final int ENUM = 5; // .txt, .list, .enum
public static final int ENUMERATION = Config.ENUM;


我们主要使用yaml,json.properties,其他大家可以自行查询。

如何实现动态内容

比如一些插件可以这样做

1
message: ${player}加入了信息

其实可以使用replace做到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package net.noyark.www;

import cn.nukkit.event.EventHandler;
import cn.nukkit.event.Listener;
import cn.nukkit.event.player.PlayerJoinEvent;


public class OtherListener implements Listener {

@EventHandler
public void onPLayerJoin(PlayerJoinEvent e){
String message;
//获取到内容后...
e.getPlayer().sendMessage(message.replace("${player}",e.getPlayer().getName()));
}
}

当然我们也可以基于反射做一个简单的解析工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Utils{
String[] vals = {"player","ip"};
Map map = new HashMap(){
{
put("player","getName");
put("ip","getAddress");
}
};
public String translate(Event e,String message){
try{
Set<Map.Entry<String,String>> entries = map.entrySet();
for(Map.Entry<String,String> e1:entries){
message = message.replace("${"+e1.getKey()+"}",e.getClass().getDeclaredMethod(e1.getValue()).invoke(e).toString());
}
}catch (Exception e2){
e2.printStackTrace();
}
return message;
}
}

上一节 下一节