[Minecraft 插件] 服务器插件开发教程(一)- 事件机制(上)

UPD(2023-5-3):调整了部分文字的格式。

关键词:事件(event)、事件侦听器(Event Listener)、示例(给玩家发送登录欢迎)、示例(彩色文字)、示例(使玩家无法移动)。


  在本篇教程中我将引入事件(event)这一概念,并实现一些简单的功能。

  很多程序是依赖事件机制工作的,比如说某些 GUI 库,当用户按下键盘上的某个键时,就会产生一个事件,当用户松开那个键时,又会产生一个事件,在这个过程中,程序可以捕获事件,根据事件的内容进行相应的处理。在 Minecraft 中,玩家移动会产生事件,破坏方块会产生事件,退出服务器会产生事件……程序员只需要给对应的事件编写相应的处理代码,就能实现丰富的交互效果。

  事件机制有什么优点呢?试想,如果不使用事件机制,为了实现同样的效果,程序就要不停地检测许多变量的变化情况,一般来说,这是非常浪费资源的,而且也不方便处理。使用事件机制,我们不仅可以更方便地管理这些“变化”,还能根据实际情况解决 “什么时候去处理?怎样处理?先处理谁?” 这些问题。

  有了以上知识作为铺垫,现在我们来看代码。如果你正确地按照教程的上一篇配置好了环境,新建项目后应该会看到如下预置的模板代码:

复制代码
package group.testplugin; // 这一行因你的项目配置变化而变化,并不一定要和我一样

import org.bukkit.plugin.java.JavaPlugin;

public final class Testplugin extends JavaPlugin {

    @Override
    public void onEnable() {
        // Plugin startup logic

    }

    @Override
    public void onDisable() {
        // Plugin shutdown logic
    }
}
复制代码

   现在让我们来引入事件机制。(注:下面的一些代码需要你自行添加相应的 import)

  为了处理事件,我们需要一个事件侦听器类 (EventListener),那么如何让一个类成为所谓的事件侦听器类呢?很简单,只需在定义后面加上 implements Listener 即可,对于上面的代码,就是写成

public final class Testplugin extends JavaPlugin implements Listener

  但是,插件此时并不知道我们定义的事件侦听器的存在,这也很好理解,因为接口是一个“被动”的存在,而你只是通过 implements 关键字表明自己要去实现里面的方法,为了能在触发各种事件时调用我们实现的接口,我们必须注册这个事件侦听器类,很简单,一行代码就可以搞定:

getServer().getPluginManager().registerEvents(this, this);

  其实,事件侦听器类不一定是我们的 Testplugin 类(插件主类,即上面代码中继承了 JavaPlugin 的类),你可以另外定义一个类来实现事件侦听器然后与 Testplugin 类来交互(但是 Testplugin 类是必需的,因为它继承了 JavaPlugin 类,是整个插件的核心,负责插件启动和关闭时的行为)。

  参照 registerEvents 的定义:

  我们就可以把插件主类和事件侦听器类分开,然后进行注册。这里我把两个类合二为一,一方面方便讲解,一方面要实现的功能不是很多,所以放在一起更紧凑。

  一般来说,上面这行注册代码必须在一开始就要执行掉,如果你的事件侦听器类和插件主类是同一个类,那么把它放在插件主类的 onEnable() 方法里是不错的选择。如果两个类不同,你可以考虑将注册代码写在事件侦听器的构造函数内,或者在插件主类中定义一个事件侦听器类的对象,依然在插件主类的 onEnable() 方法中调用注册代码。


  下面我们来实现一些基本的功能。(以下的方法均定义在你的事件侦听器类里面)

  比如说,当玩家加入游戏的时候给他们发送欢迎消息:

复制代码
@EventHandler
    public void onPlayerJoin(PlayerJoinEvent event) {
        event.getPlayer().sendMessage("Welcome, " + ChatColor.AQUA + event.getPlayer().getName() + ChatColor.WHITE + " !");
        if (!player_list.containsKey(event.getPlayer().getUniqueId())) {
            event.getPlayer().sendMessage("Please register before playing :)");
            event.getPlayer().sendMessage("Use " + ChatColor.AQUA + "\"/register <password>\"" + ChatColor.WHITE + " to register.");
            event.getPlayer().sendMessage("And use " + ChatColor.AQUA + "\"/login <password>" + ChatColor.WHITE + " to login.\"");
        } else
            event.getPlayer().sendMessage("Use " + ChatColor.AQUA + "\"/login <password>" + ChatColor.WHITE + " to login.\"");
    }
复制代码

  上面的代码来自是我初学的时候写的简易登录插件。注意:每一个事件处理方法都要在最前面加上 @EventHandler 的注释。如果你想知道为什么这个方法是这样定义的,请查询插件的官方文档,对于这段代码,我查到的是PlayerJoinEvent (Paper-API 1.16.5-R0.1-SNAPSHOT API)。只要知道对应的事件名称,我们就可以编写相应的方法来处理它。

  细心的你也许会发现,我们编写的方法名 onPlayerJoin 似乎和事件名 PlayerJoinEvent 有关,其实这样写是方便理解,当然你想写 onPlayerFxxkJoin 也是可以的,不过可读性就降低了,只要你保证唯一的参数是 PlayerJoinEvent 类型的即可。

  我们具体到方法内部看,很容易可以知道给玩家发送信息的方法是 sendMessage,但是发送信息前我们需要先知道给发送,这里使用了 event.getPlayer() 来获得这个事件对应的玩家——绝大多数事件都是和玩家有关的,而你就可以通过这个方法来获得对应的玩家,并且,不仅仅可以做到对其发送信息,他的生杀大权已经掌握在你手里了!比如 event.getPlayer().setHealth(0.0)……

  可以看到输了个 set 就出来这么多方法,大家可以结合官方文档自行尝试效果。注意,上面这个方法当然要定义在你的事件侦听器类里面


  还有一个很重要的功能是彩色文字,这个从上面的代码里也可以知道,只需要在字符串之间用 ChatColor.XXX 来连接即可实现,每一种 ChatColor 的效果会被应用于其之后的文字:

  并且,在左边还会贴心地显示出你当前使用的颜色。


   再来看一个功能,比如,当玩家未注册时无法移动,这个在很多服务器里非常常见:

@EventHandler
    public void onPlayerMove(PlayerMoveEvent event) {
        if (!player_list.containsKey(event.getPlayer().getUniqueId()))
            event.setCancelled(true);
        else if (player_list.get(event.getPlayer().getUniqueId()).if_logined == Boolean.FALSE)
            event.setCancelled(true);
    }

  使用 event.setCancelled(true) 即可让玩家移动的事件被“取消”,直观上来看就是无法移动,或者移动了一点点距离就马上被拉回原位,注意这里的移动包括视角的变化。

  注意,上面这段代码直接复制粘贴是无法正确运行的,因为里面的 player_list 和 if_logined 都是我自己定义的,如果你想实现类似的效果需要自己编写额外的代码。


  [Minecraft 插件] 服务器插件开发教程(二)- 事件机制(下)

posted @   ZXPrism  阅读(2348)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示