昨天才把Ver 1.0放出来,只实现了简单的功能还没进行细节的完善

子命令配置

将目前功能命令进行修改

/bvote setid [room_id]:设置绑定房间id号

/bvote setworld:设置当前世界为受影响世界

/bvote time [random|static] <args>:设置间隔时间为随机或定时

/bvote switch:设置插件状态

对于子命令的实现,之前进行time指令的实现中使用参数的方式可以进行实现

但是在游戏中输入指令的时候没用补全提示,现在需要实现的就是补全提示

在查阅了文档和一些开源代码后,在插件主类中可以覆写一个onTabComplete方法,其声明如下

1
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args);

在主类中,可以通过判断参数然后返回一个列表作为待选的可以通过tab补全的子命令,而在onCommand中可以使用参数实现子命令

项目中的命令是通过实现CommandExecutor的接口进行命令的实现的,这个地方把所有命令封装到一个bvote命令下的类中,然后在这个类下调用已经实现的其他命令类

但是这个地方需要实现的是TabExecutor接口,在其中实现onCommand方法和onTabComplete方法

现在, VoteCommands类的实现如下,实现还是比较的繁琐,或许还会有更简单的方法(现在的一些开源代码这一部分的实现还不是看的很清楚)

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class VoteCommands implements TabExecutor {
private DanmakuVote plugin;
private String[] subCommands = {"setid", "setworld", "switch", "time", "status"};

public VoteCommands(DanmakuVote plugin) {
this.plugin = plugin;
}

@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
switch (args[0]) {
case "setid": {
VoteIdSetExecutor idSetExecutor = new VoteIdSetExecutor(plugin);
return idSetExecutor.onCommand(sender, command, label, args);
}
case "setworld": {
VoteWorldSetExecutor worldSetExecutor = new VoteWorldSetExecutor(plugin);
return worldSetExecutor.onCommand(sender, command, label, args);
}
case "switch": {
VoteSwitchExecutor switchExecutor = new VoteSwitchExecutor(plugin);
return switchExecutor.onCommand(sender, command, label, args);
}
case "time": {
VoteTimeSetExecutor timeSetExecutor = new VoteTimeSetExecutor(plugin);
return timeSetExecutor.onCommand(sender, command, label, args);
}
case "status": {
VoteStatusExecutor statusExecutor = new VoteStatusExecutor(plugin);
return statusExecutor.onCommand(sender, command, label, args);
}
default: {
sender.sendMessage(ChatColor.RED + "BVote command argument error");
}
}
return false;
}


@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
if (args.length == 1) {
return Arrays.asList(subCommands);
}
else {
return new ArrayList<>();
}
}
}

配置文件添加实体/事件

之前代码中的实体选择是直接写死了的,考虑一定的灵活性就需要通过配置文件进行实体的增删

考虑在配置文件中添加如下内容

1
2
3
4
5
6
7
8
Monsters:
-"creeper"
-""
...
Animals:
-"pig"
_"cow"
...

通过写入指定字符串进行实体选择的添加,但是这样做带来的问题是代码实现的复杂

实体生成的代码是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MonsterPut extends WorldEvent {
...

public final void effect() {
Player player = randomChosePlayer();
Location location = player.getLocation();
Bukkit.getWorld(worldName).spawnEntity(location, RandomChooser.RandomMonsterChoose());
}
}

public final class RandomChooser {
public static EntityType RandomMonsterChoose() {
EntityType[] MonsterArray = {EntityType.ENDERMAN, EntityType.SPIDER, EntityType.CREEPER, EntityType.SKELETON};
Random random = new Random();
return MonsterArray[random.nextInt(MonsterArray.length)];
}
}

在这里是有实体的Enum进行实体的生成,需要通过接收字符串映射到Enum

当然最简单的方法就是通过switch进行实现,这个作为最后的一个方案,现在先看看能不能有其他的方法进行替代

Enum可以通过方法valueof通过字符串获取Enum值,所以此处的实现就比较简单了

配置文件中进行如下配置

1
2
3
4
5
6
Monsters:
- ENDERMAN
- CREEPER
- SPIDER
- SHULKER
- ZOMBIE

添加RandomEntityChoose 方法,实现进行实体的随机选择

1
2
3
4
5
6
7
8
9
private static EntityType RandomEntityChoose(DanmakuVote plugin, String _path) {
FileConfiguration config = plugin.getConfig();
List monsterList = config.getStringList(_path);
Random random = new Random();
int listSize = monsterList.size();
int randomInteger = random.nextInt(listSize);
EntityType type = EntityType.valueOf(String.valueOf(monsterList.get(randomInteger)));
return type;
}

对于Monster的选择,传入参数调用RandomEntityChoose方法即可

1
2
3
public static EntityType RandomMonsterChoose(DanmakuVote plugin) {
return RandomEntityChoose(plugin, "Monsters");
}

配置文件进行命令名修改

这里需要建立一个新的配置文件events.yml来实现对事件相关参数的配置

文件的格式如下

1
2
3
4
5
6
7
WeatherClear:
name: "Weather Clear"
switch: true
description: "将天气修改为无天气"
hint: ""
ticks: 0
...

在读取配置文件的时候,自然与config.yml不一样,需要使用YamlConfiguration 类中的方法读取该配置文件,在不检查文件是否存在的情况下,读取配置文件的方式如下

1
2
File f = new File(_plugin.getDataFolder(), _fileName);
FileConfiguration config = YamlConfiguration.loadConfiguration(f);

进行文件检查,将其封装为一个工具进行调用:

1
2
3
4
5
6
7
8
public static FileConfiguration getFileConfig(Plugin _plugin, String _fileName) {
File f = new File(_plugin.getDataFolder(), _fileName);
if (!f.exists()) {
_plugin.saveResource(_fileName, true);
f = new File(_plugin.getDataFolder(), _fileName);
}
return YamlConfiguration.loadConfiguration(f);
}

于是可以在VoteEvent类中获取对应的配置文件,进行读取

在抽取事件时,检查配置文件中对应事件的switch是否为 true,否则丢弃该事件进行重新选取

由于配置文件中进行了对description与name的配置,在实例化对象的时候进行初始化,而不需要传入值

这样,用户可以直接修改配置文件自定义投票名称以及事件效果描述

1
2
3
4
5
6
7
8
9
10
11
public VoteEvent(String _worldName, String _configName, EventEnum _type, DanmakuVote _plugin) {
worldName = _worldName;
configName = _configName;
EventType = _type;
count = 0;
plugin = _plugin;

FileConfiguration config = FileUtil.getFileConfig(_plugin, configFileName);
eventName = config.getString(String.format("%s.name", configName));
description = config.getString(String.format("%s.description", configName));
}