【Minecraft】使用Bukkit/Spigot插件可以控制时间
2020年5月5日:由于代码中出现了一个小错误,所以进行了修正。
开始制作Bukkit插件时,记录了遇到的困难。
我想做的事情
在Minecraft的聊天栏中输入特定的词汇,将触发并设定游戏内的时间。在这里,我们将创建一个插件,当输入”朝”时,将时间设定为0(早上)。
不好的例子
//パッケージ文、インポート文は省略
public class main extends JavaPlugin{
@Override
public void onEnable() {
getServer().getPluginManager().registerEvents(new eventListener(this), this);
}
}
//パッケージ文、インポート文は省略
public class eventListener implements Listener {
private final main m;
public eventListener(main m_){m=m_;}
@EventHandler
public void onPlayerChat(AsyncPlayerChatEvent event){
if(event.getMessage().equals("朝")){
event.getPlayer().getWorld().setTime(0L);
event.getPlayer().sendMessage("ワード「朝」を検知しました。");
m.getLogger().info(event.getPlayer().getName()+"さんがワード「朝」を発言しました");
}
}
}
玩家发送的聊天消息可以在AsyncPlayerChatEvent事件中捕获,并且可以在插件中进行自由操作。此外,文章中提到的世界(World)可以在事件处理器中使用event.getPlayer().getWorld()进行获取。
麻煩的是,在这里能成功编译。
为什么不行?
编译成功并且实际安装后没有出现错误。然而,当实际输入「朝」时,服务器端会出现两个错误。
[00:00:00 ERROR]: Could not pass event AsyncPlayerChatEvent to hogehoge_plugin v1.0.0
org.bukkit.event.EventException: null
at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:312) ~[craftbukkit-1.15.2.jar:git-Bukkit-8160e29]
at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[craftbukkit-1.15.2.jar:git-Bukkit-8160e29]
~略~
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:461) [craftbukkit-1.15.2.jar:git-Bukkit-8160e29]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) [craftbukkit-1.15.2.jar:git-Bukkit-8160e29]
at java.lang.Thread.run(Thread.java:830) [?:?]
Caused by: java.lang.IllegalStateException: TimeSkipEvent cannot be triggered asynchronously from another thread.
at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:510) ~[craftbukkit-1.15.2.jar:git-Bukkit-8160e29]
at org.bukkit.craftbukkit.v1_15_R1.CraftWorld.setFullTime(CraftWorld.java:803) ~[craftbukkit-1.15.2.jar:git-Bukkit-8160e29]
~略~
就像文档中所写的一样,AsyncPlayerChatEvent基本上是以异步方式执行的。然而,event.getPlayer().getWorld().setTime(0L);必须以同步方式执行。
方法的解决
有几种解决方法,但最简单的是通过实现匿名类来避免错误。
//そのままで良い
//パッケージ文、インポート文は省略
public class eventListener implements Listener {
private final main m;
public eventListener(main m_){m=m_;}
@EventHandler
public void onPlayerChat(AsyncPlayerChatEvent event){
if(event.getMessage().equals("朝")){
m.getServer().getScheduler().runTask(m, new Runnable() {
@Override
public void run() {event.getPlayer().getWorld().setTime(0L);}
});
event.getPlayer().sendMessage("ワード「朝」を検知しました。");
m.getLogger().info(event.getPlayer().getName()+"さんがワード「朝」を発言しました");
}
}
}
为了从非同步的AsyncPlayerChatEvent中调用同步的处理,使用了org.bukkit.scheduler的调度器。runTask会在下一个tick(服务器tick)执行注册的类。如果需要稍等一会儿才执行,可以使用runTaskLater代替。
请用中文将以下句子改述一遍:
以上。