1. 项目概述:从玩家到创造者的第一步
如果你和我一样,在《我的世界》里从撸树开始,到建造红石机器,再到搭建自己的服务器,那么迟早有一天,你会盯着服务器里琳琅满目的插件列表,心里冒出一个念头:“这个功能要是能这样改一下就好了”,或者“为什么没有插件能实现我想要的这个玩法?” 这就是插件开发旅程的起点。Bukkit,作为Minecraft Java版服务器最经典、最庞大的插件API生态,是绝大多数开发者迈出第一步的地方。网上教程很多,但很多要么过于陈旧,要么一上来就堆砌代码,让人看得云里雾里。这个系列教程,我想用最贴近实战、最像朋友间分享经验的方式,带你从零开始,亲手做出你的第一个Bukkit插件,并理解每一个文件、每一行代码背后的“所以然”。
这个“第一个插件”的目标很纯粹:它不需要实现复杂的功能,它的核心价值在于帮你打通从“想法”到“一个能被服务器加载并运行”的完整流程。你会亲手创建项目结构,编写核心的插件描述文件,实现一个最简单的命令,并最终打包成JAR文件放进服务器的plugins文件夹。整个过程,你会遇到诸如“plugin.yml到底怎么写才对”、“为什么我的插件服务器不认”、“命令怎么注册不生效”这些新手必踩的坑。别担心,我会把这些坑都提前标出来,并告诉你最稳妥的绕过方法。无论你是刚学Java不久的学生,还是有一定编程基础但从未接触过Minecraft开发的爱好者,这篇教程都将是你最扎实的起点。我们用的工具会是目前最主流的IntelliJ IDEA,因为它对Java和Maven的支持无与伦比,能让我们更专注于逻辑本身,而不是环境配置的挣扎。
2. 开发环境与项目骨架搭建
2.1 工具链选择与配置要点
工欲善其事,必先利其器。对于Bukkit插件开发,一套顺手的工具能让你事半功倍。核心工具链就三样:JDK、构建工具和IDE。
首先是JDK。Bukkit插件基于Java,因此你需要安装Java Development Kit。这里有个关键点:你的JDK版本必须与目标服务器运行的Java版本兼容。目前绝大多数主流Minecraft服务器(1.12+)都运行在Java 8或Java 11上。为了获得最好的兼容性,我强烈建议你直接安装Java 8 (JDK 1.8)。你可以选择Oracle JDK 8或者OpenJDK 8。在IntelliJ IDEA中,你需要确保项目SDK指向正确的JDK 8路径。高版本JDK(如JDK 17)虽然也能编译,但在涉及反射等底层操作时,可能会遇到意想不到的兼容性问题,对于第一个插件,求稳是第一要务。
其次是构建工具。我们选择Maven,而不是手动管理JAR包。Maven能自动处理依赖下载、项目构建和打包,是现代化Java项目的标准。你不需要单独安装Maven,因为IDEA已经内置了Maven支持。我们需要做的是,在项目中创建一个pom.xml文件,这是Maven项目的“心脏”。在这个文件里,最关键的是声明对Bukkit API的依赖。这里有一个非常重要的细节:你必须使用与你目标Minecraft服务器版本匹配的Bukkit API版本。例如,如果你的服务器是1.16.5,你就应该去找对应1.16.5的Bukkit API。一个可靠的仓库是SpigotMC的Maven仓库。你的pom.xml依赖部分看起来会是这样:
<dependencies> <dependency> <groupId>org.spigotmc</groupId> <artifactId>spigot-api</artifactId> <version>1.16.5-R0.1-SNAPSHOT</version> <scope>provided</scope> </dependency> </dependencies>注意<scope>provided</scope>这一行,它告诉Maven:这个依赖在编译和测试时需要,但在最终打包插件JAR时不要包含进去。因为Bukkit API在服务器运行时已经提供了,重复打包只会增大插件体积并可能引起冲突。
最后是IDE,我们选择IntelliJ IDEA Community Edition(免费版)。它足够强大,对Maven和Java的支持是顶级的。安装后,你需要创建一个新的Maven项目(不要选普通的Java项目)。在创建过程中,IDEA可能会下载初始依赖,包括Maven本身,耐心等待即可。
注意:网络上有些非常古老的教程会教你手动下载
craftbukkit.jar或spigot.jar并添加到项目的库中。这种方法早已过时,难以管理依赖和版本,请务必使用Maven来管理你的项目。
2.2 创建项目与理解标准目录结构
打开IDEA,选择“New Project”,在左侧选择“Maven”。在“Project SDK”处,选择你安装的JDK 8。GroupId和ArtifactId是Maven项目的坐标,你可以简单理解为插件的“姓氏”和“名字”。例如,GroupId可以是com.yourname,ArtifactId可以是FirstPlugin。版本号Version先填1.0-SNAPSHOT即可。点击创建,IDEA会为你生成一个标准的Maven项目骨架。
项目创建好后,在左侧的项目视图中,你会看到这样的核心目录结构:
FirstPlugin ├── src │ ├── main │ │ ├── java // 你的Java源代码放在这里 │ │ └── resources // 资源文件,如plugin.yml、config.yml放在这里 │ └── test // 测试代码(暂时用不到) └── pom.xml // Maven项目配置文件现在,我们需要创建插件最核心的两个文件。首先,在src/main/resources目录上右键,选择New -> File,创建一个名为plugin.yml的文件。这个文件是Bukkit服务器识别插件的“身份证”,没有它,服务器根本不会加载你的插件。接着,在src/main/java目录下,按照你刚才填写的GroupId创建对应的包(package)。例如,如果GroupId是com.yourname,那么就创建com.yourname这个包。在这个包下,创建你的主类,比如叫Main。
这个目录结构是Maven的约定,严格遵守它能让你在后续开发、打包时避免很多路径错误。src/main/java下的包结构反映了你的代码组织逻辑,而resources目录下的文件在打包时会原封不动地放进JAR包的根目录,这正是Bukkit服务器所要求的。
3. 插件的心脏:plugin.yml 深度解析
3.1 基础字段:name、version、main 的玄机
plugin.yml是一个YAML格式的文件,它用键值对的方式来描述你的插件。它的语法非常严格,缩进必须使用空格(通常是2个),不能使用Tab键,并且大小写敏感。一个最基础的plugin.yml至少包含以下三个字段:
name: FirstPlugin version: 1.0.0 main: com.yourname.Main我们来逐一拆解,这里面每一个字段都有讲究:
name (名称):这是你插件的名字。它必须是唯一的,不能和服务器里已有的其他插件重名,并且应该保持简洁、无空格。通常使用驼峰命名法(如
MyFirstPlugin)或单词连接(如first-plugin)。这个名字会显示在服务器的插件列表里(如/plugins命令的输出)。version (版本):插件的版本号。强烈建议使用 语义化版本 规范,即
主版本号.次版本号.修订号。例如1.0.0。每次你发布一个包含新功能的更新,就增加次版本号(如1.1.0);如果只是修复bug,就增加修订号(如1.0.1)。这有助于服务器管理员理解更新的性质。切忌使用像1.0这样缺少一位的版本号,某些服务器可能无法正确解析。main (主类):这是整个插件最重要的配置项,也是新手最容易出错的地方。它指定了插件启动时,服务器应该去加载哪个Java类。这个值必须是你主类的完整限定名,也就是包名加类名。例如,你的主类
Main放在com.yourname包下,那么这里就必须写com.yourname.Main。写错了,服务器会抛出“Could not load 'FirstPlugin.jar' in folder 'plugins'”或“main class not found”之类的错误。
实操心得:我强烈建议你在
plugin.yml里把name字段的值,直接复制作为你项目ArtifactId和最终打包JAR文件名的基础。这样可以最大限度地减少因名称不一致导致的混淆。例如,name: FirstPlugin,项目ArtifactId也是FirstPlugin,最后打出的包就叫FirstPlugin-1.0.0.jar。
3.2 进阶字段:描述、作者、依赖与加载顺序
除了上述三个必填字段,plugin.yml还提供了一系列可选字段来完善你的插件信息和管理插件间关系:
name: FirstPlugin version: 1.0.0 main: com.yourname.Main description: This is my very first Bukkit plugin! author: YourName website: https://yourwebsite.com api-version: 1.16 depend: [Vault] softdepend: [WorldEdit] load: POSTWORLD- description、author、website:这些是展示性信息,会显示在
/plugins或/version PluginName命令中,方便管理员了解插件用途和作者。 - api-version:指定插件所依赖的Bukkit API版本。这应该与你
pom.xml中引入的API版本主要部分一致(如1.16)。设置这个可以防止插件被加载到不兼容的服务器版本上。 - depend (硬依赖):一个插件名称的列表。你的插件必须依赖这些插件才能运行。如果服务器没有安装列表中的某个插件,你的插件将不会被加载。例如,经济插件通常硬依赖
Vault,因为需要它的API来处理经济系统。使用硬依赖要非常谨慎,除非绝对必要。 - softdepend (软依赖):一个插件名称的列表。你的插件可以与这些插件协同工作,但没有它们也能正常运行。你需要在代码中检查这些插件是否存在。例如,你的插件可能为
WorldEdit提供一些扩展功能,但没有WE也不影响核心功能。 - load (加载顺序):定义插件相对于服务器启动阶段的加载时机。可选值有
STARTUP(服务器启动时最早加载)和POSTWORLD(世界加载完成后加载,默认值)。大多数插件使用POSTWORLD即可,因为这时世界数据已经就绪。如果你的插件需要修改世界生成等非常底层的逻辑,才考虑使用STARTUP。
理解并合理运用这些字段,能让你的插件更专业,与其他插件的集成更顺畅。
4. 主类与插件生命周期管理
4.1 继承JavaPlugin与重写关键方法
现在,让我们把目光转向Java代码。在之前创建的com.yourname.Main类中,你需要让它继承Bukkit API中的org.bukkit.plugin.java.JavaPlugin类。这是所有Bukkit插件的基石。
package com.yourname; import org.bukkit.plugin.java.JavaPlugin; public class Main extends JavaPlugin { @Override public void onEnable() { // 当插件被启用时,此方法被调用 getLogger().info("我的第一个插件已启用!"); } @Override public void onDisable() { // 当插件被禁用时,此方法被调用 getLogger().info("我的第一个插件已禁用。"); } }这个简单的类已经是一个功能完整的插件了!我们来分析一下:
extends JavaPlugin:这行代码宣告了你的类是一个Bukkit插件。onEnable():这是插件生命周期的起点。当服务器加载插件,或管理员使用/reload命令(不推荐使用)后,这个方法会被调用。你应该在这里进行所有的初始化工作:注册事件监听器、注册命令、读取配置文件、建立数据库连接、启动定时任务等。getLogger().info()用于向控制台输出一条信息日志,这是调试和告知管理员插件状态的重要手段。onDisable():这是插件生命周期的终点。当服务器关闭,或插件被卸载时,这个方法会被调用。你应该在这里进行所有的清理工作:保存数据、关闭数据库连接、取消所有定时任务、释放资源等。确保清理干净,避免内存泄漏或数据损坏。
服务器加载插件的流程是这样的:找到JAR -> 读取plugin.yml-> 根据main字段找到主类 -> 创建主类的实例 -> 调用onEnable()。如果onEnable()方法执行过程中抛出了未捕获的异常,整个插件加载就会失败。
4.2 onLoad() 方法与初始化陷阱
除了onEnable和onDisable,还有一个不那么常用但有时很关键的方法:onLoad()。
@Override public void onLoad() { // 在插件被启用之前,此方法被调用 getLogger().info("插件正在加载..."); }onLoad()的调用时机早于onEnable()。它发生在插件实例被创建之后,但在任何事件监听器或命令注册之前。那么,什么时候该用onLoad()呢?
主要场景是当你需要进行一些必须在插件启用前完成的、非常底层的初始化,或者需要与其他插件的onLoad()阶段进行交互时。例如,某些世界管理插件可能在onLoad()阶段就注册世界生成器。对于你的第一个插件,以及绝大多数功能型插件,你完全不需要重写onLoad()方法。把所有初始化逻辑放在onEnable()里就足够了。
这里有一个重要的注意事项:在onLoad()阶段,Bukkit的许多服务(如调度器Scheduler)可能还没有完全准备好。因此,绝对不要在onLoad()方法中尝试访问玩家、世界、注册事件或执行任何需要Bukkit核心服务已就绪的操作,否则很可能导致错误。如果你不确定,就别用它。
5. 实现第一个服务器命令
5.1 命令执行器的创建与注册
一个没有交互的插件是缺乏灵魂的。让我们为插件添加一个最简单的命令:/hello。当玩家或控制台执行这个命令时,插件会回复一条消息。
首先,你需要创建一个命令执行器(CommandExecutor)。在Bukkit中,任何类只要实现了org.bukkit.command.CommandExecutor接口,就可以处理命令。这个接口只有一个方法需要实现:boolean onCommand(CommandSender sender, Command command, String label, String[] args)。我们通常在主类中实现这个接口。
package com.yourname; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.plugin.java.JavaPlugin; public class Main extends JavaPlugin implements CommandExecutor { // 实现接口 @Override public void onEnable() { getLogger().info("我的第一个插件已启用!"); // 注册命令。参数1:命令名(不带斜杠),参数2:命令执行器(this指主类本身) this.getCommand("hello").setExecutor(this); } @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { // 当有人执行 /hello 命令时,此方法被调用 sender.sendMessage("§a你好,世界!这是我的第一个Bukkit插件命令。"); return true; // 返回true表示命令处理成功 } // ... onDisable 方法 }代码解释:
implements CommandExecutor:让主类具备处理命令的能力。this.getCommand("hello").setExecutor(this):这是在onEnable()中进行的命令注册。getCommand("hello")会获取一个PluginCommand对象,然后我们调用setExecutor(this)将这个命令的处理权交给当前主类实例。这一步必须做,否则命令不会生效。onCommand方法:这是命令处理的核心。CommandSender sender:命令的发送者。可以是玩家(Player)、控制台(ConsoleCommandSender)或命令方块。Command command:被执行的命令对象。String label:用户实际输入的命令别名(如果你为命令设置了别名,这里可能是别名)。String[] args:命令参数数组。例如/hello arg1 arg2,则args = ["arg1", "arg2"]。
sender.sendMessage(...):向命令发送者发送一条消息。§a是Minecraft的颜色代码,代表绿色。return true;:返回true告诉Bukkit命令已成功处理。如果返回false,Bukkit会自动向发送者显示该命令的用法(usage),这个用法需要在plugin.yml中定义。
5.2 在plugin.yml中声明命令与权限
仅仅在代码中注册命令执行器还不够,你必须在plugin.yml文件中声明这个命令,否则服务器不会认可它,getCommand("hello")会返回null,导致注册失败和空指针异常。
我们需要在plugin.yml中添加一个commands节点:
name: FirstPlugin version: 1.0.0 main: com.yourname.Main description: This is my very first Bukkit plugin! author: YourName commands: hello: description: 打个招呼 usage: /<command> aliases: [hi, greet] permission: firstplugin.hello permission-message: §c你没有权限使用这个命令!hello::命令的名称,必须和代码中getCommand("hello")里的字符串完全一致。description:命令的简短描述,会显示在/help等地方。usage:命令的使用方法。当onCommand返回false时,Bukkit会向玩家发送这个字符串。<command>是一个占位符,会被实际输入的命令或别名替换。aliases:命令的别名列表。玩家输入/hi或/greet同样可以触发这个命令。permission:执行此命令所需的权限节点。这是一个字符串,你可以自由定义,通常以插件名开头,如firstplugin.hello。permission-message:当发送者没有权限时,将收到这条消息。
现在,一个完整的命令系统就建立了:plugin.yml声明命令的存在和属性,onEnable()中注册执行逻辑,onCommand方法处理具体交互。
6. 配置文件 config.yml 的生成与使用
6.1 默认配置的创建与自动生成
一个良好的插件应该允许管理员通过配置文件来自定义其行为,而不是把参数硬编码在代码里。Bukkit提供了非常方便的org.bukkit.configuration.file.FileConfiguration类来管理YAML配置文件。
首先,我们需要创建一个默认的配置文件。在src/main/resources目录下,新建一个文件,命名为config.yml。在这个文件里,你可以定义所有可配置的选项及其默认值。
# FirstPlugin 配置文件 messages: welcome: "§a欢迎使用本插件!" goodbye: "§c再见!" settings: broadcast-join: true max-players: 50然后,在插件的onEnable()方法中,你需要添加代码来保存这个默认配置(如果它不存在的话),并加载它。
@Override public void onEnable() { getLogger().info("我的第一个插件已启用!"); this.getCommand("hello").setExecutor(this); // --- 配置文件处理 --- // 1. 保存默认配置(将JAR内的config.yml复制到插件数据文件夹,仅当文件不存在时) this.saveDefaultConfig(); // 2. 将配置文件加载到内存,得到一个FileConfiguration对象 // 之后可以通过 this.getConfig() 来获取这个对象 }saveDefaultConfig()这个方法非常关键。它会在插件的数据文件夹(通常位于服务器根目录的plugins/YourPluginName/)下寻找config.yml。如果找不到,它就会将你放在resources目录下的那个默认config.yml复制过去。这样,管理员第一次安装你的插件时,就会自动生成一个带有所有默认值的配置文件,无需手动创建。
6.2 配置的读取、修改与热重载
生成了配置文件,接下来就要在代码中读取和使用它。我们修改之前的onCommand方法,让问候语从配置文件中读取:
@Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { // 从配置文件中读取消息 String welcomeMessage = this.getConfig().getString("messages.welcome"); // 如果配置项不存在,提供一个默认值 if (welcomeMessage == null) { welcomeMessage = "§a默认欢迎信息"; } sender.sendMessage(welcomeMessage); return true; }this.getConfig()返回的就是我们之前加载的FileConfiguration对象。getString("messages.welcome")使用点分隔的路径来获取嵌套的配置值。YAML的层次结构在这里表现得非常直观。
你还可以让管理员在游戏内重载配置,而无需重启服务器。这通常通过一个命令来实现,例如/yourplugin reload。实现步骤如下:
- 在
onCommand方法中判断命令和参数。 - 调用
this.reloadConfig()。这个方法会丢弃内存中当前的配置,并从数据文件夹的config.yml文件重新加载。 - 通知管理员重载完成。
@Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (label.equalsIgnoreCase("yourplugin")) { if (args.length > 0 && args[0].equalsIgnoreCase("reload")) { // 检查权限 if (!sender.hasPermission("firstplugin.reload")) { sender.sendMessage("§c你没有重载插件的权限。"); return true; } // 重载配置 this.reloadConfig(); sender.sendMessage("§a插件配置已重载!"); return true; } } // ... 其他命令处理逻辑 return false; }注意事项:
reloadConfig()是一个比较“重”的操作,它会重新读取整个文件。对于大型配置文件或高频操作,频繁重载可能影响性能。更高级的做法是只监听配置文件的变化(例如使用Java的WatchService),但作为第一个插件,简单的重载命令已经足够。
7. 项目构建、打包与服务器测试
7.1 使用Maven进行打包与依赖管理
代码写好了,配置文件也齐了,现在是时候把它们打包成一个可以扔进服务器plugins文件夹的JAR文件了。这就是Maven大显身手的时候。
在IDEA的右侧边栏,找到并打开Maven工具窗口(如果没看到,可以在顶部菜单栏选择 View -> Tool Windows -> Maven)。展开你的项目,你会看到一系列Maven生命周期(Lifecycle)命令。我们只需要关注两个:
clean:清理之前构建生成的文件(如target目录)。package:编译代码,运行测试(如果有),并将项目打包成JAR文件。
直接双击package,Maven就会开始工作。你可以在底部的 “Run” 或 “Build” 工具窗口看到构建日志。如果一切顺利,最后会显示BUILD SUCCESS。
打包好的JAR文件位于项目的target目录下,文件名通常是你的ArtifactId-版本号.jar,例如FirstPlugin-1.0.0.jar。这个JAR文件是“可执行”的(对于Bukkit服务器来说),它里面包含了:
- 你编译好的所有
.class文件(在com/yourname/等目录下)。 META-INF/MANIFEST.MF文件(由Maven生成,包含JAR元信息)。- 你放在
src/main/resources下的所有文件(plugin.yml,config.yml),它们会被放在JAR包的根目录。
关键检查点:在把JAR包放入服务器之前,我习惯先用压缩软件(如7-Zip)打开它,快速检查两样东西:
- 根目录下是否有
plugin.yml文件。 plugin.yml里的main类路径是否正确,并且这个类确实存在于JAR包中对应的路径下。 很多新手遇到的“插件加载失败”问题,根源都在这两步。
7.2 服务器部署、调试与日志查看
现在,将生成的FirstPlugin-1.0.0.jar文件复制到你的Minecraft服务器的plugins文件夹中。确保服务器处于关闭状态。
启动服务器。在启动日志中,你应该能看到类似这样的信息:
[INFO] [FirstPlugin] Loading FirstPlugin v1.0.0 [INFO] [FirstPlugin] 我的第一个插件已启用!这表明你的插件已经被成功加载并启用了。
接下来进行功能测试:
- 在服务器控制台或游戏内输入
/plugins,确认FirstPlugin在插件列表中。 - 在游戏内或控制台输入
/hello,你应该能看到绿色的“你好,世界!”消息。 - 检查插件数据文件夹(
plugins/FirstPlugin/),确认里面自动生成了config.yml文件,并且内容与你设置的默认值一致。 - 修改
plugins/FirstPlugin/config.yml文件中的messages.welcome内容,然后在游戏内执行你设定的重载命令(如果有),再次执行/hello,看看消息是否更新。
调试与日志:如果插件没有按预期工作,服务器日志是你的第一求助对象。查看logs/latest.log文件,或者直接看控制台输出。常见的错误信息包括:
“Error occurred while enabling FirstPlugin v1.0.0 (Is it up to date?)”:通常意味着onEnable()方法中抛出了异常。往下翻日志,找到具体的错误堆栈信息(Caused by: ...),它能精准定位到出错的代码行。“Could not load 'FirstPlugin.jar' in folder 'plugins'”:通常是plugin.yml格式错误、缺失或main类路径错误。“No command 'hello' registered”:说明命令注册失败,检查plugin.yml中是否有commands: hello:的声明,以及代码中getCommand("hello")是否在onEnable()中被调用。
学会阅读和分析日志,是插件开发中最重要的调试技能。
8. 进阶第一步:事件监听入门
8.1 理解Bukkit事件机制
命令让插件可以主动响应玩家输入,而事件(Event)则让插件能够被动响应服务器中发生的各种事情,例如玩家加入、破坏方块、发送聊天消息等。Bukkit的事件系统是基于“监听器(Listener)”模式的。
整个流程可以这样理解:
- 服务器核心(或其他插件)里发生了某件事(比如玩家登录),它会创建一个对应的事件对象(如
PlayerJoinEvent),并“抛”出来。 - 所有对此类事件感兴趣的监听器,都会收到这个事件对象。
- 监听器执行你编写好的处理代码。
- 处理完毕后,事件可能被传递给下一个监听器,也可能被“取消”(如果事件是可取消的),从而阻止事件的默认行为(比如取消玩家的加入)。
要为你的插件添加事件监听,你需要做三件事:
- 创建一个类来实现
org.bukkit.event.Listener接口(这个接口是空的,只是一个标记)。 - 在这个类中编写一个或多个事件处理方法,并用
@EventHandler注解标记它们。 - 在插件的
onEnable()方法中,向服务器注册这个监听器。
8.2 实现一个玩家加入欢迎事件
让我们为第一个插件添加一个功能:当玩家加入服务器时,向他发送一条欢迎消息,并在控制台记录。
首先,创建一个新的类EventListener(名字可以自定),放在你的主包下。
package com.yourname; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; public class EventListener implements Listener { // 1. 实现Listener接口 private final Main plugin; // 持有插件主类的引用,方便调用插件方法 public EventListener(Main plugin) { this.plugin = plugin; } @EventHandler // 2. 用注解标记这是一个事件处理方法 public void onPlayerJoin(PlayerJoinEvent event) { // 从事件对象中获取加入的玩家 org.bukkit.entity.Player player = event.getPlayer(); // 向该玩家发送一条私聊欢迎消息 String welcomeMsg = plugin.getConfig().getString("messages.welcome", "§a欢迎加入服务器!"); player.sendMessage(welcomeMsg); // 在服务器控制台也记录一下 plugin.getLogger().info("玩家 " + player.getName() + " 加入了游戏。"); // 你可以修改加入时的系统消息(可选) // event.setJoinMessage("§e[+] " + player.getName()); } }代码解释:
implements Listener:声明这个类是事件监听器。@EventHandler:这是关键注解。它告诉Bukkit,下面的onPlayerJoin方法需要被注册为一个事件处理器。方法的参数类型PlayerJoinEvent决定了它监听的是哪种事件。- 方法名可以任意取,但参数必须是具体的事件类型。
- 我们在方法中通过事件对象
event获取了玩家,然后向他发送消息,并记录日志。注意我们通过plugin.getConfig()来读取配置,因此需要在构造时传入主类实例。
接下来,在主类Main的onEnable()方法中注册这个监听器:
@Override public void onEnable() { getLogger().info("我的第一个插件已启用!"); this.getCommand("hello").setExecutor(this); this.saveDefaultConfig(); // --- 注册事件监听器 --- // 参数1:你的监听器实例,参数2:你的插件实例(this) this.getServer().getPluginManager().registerEvents(new EventListener(this), this); }getServer().getPluginManager().registerEvents(listener, plugin)是标准的注册方法。第一个参数是监听器对象,第二个参数是插件主类对象(用于管理监听器的生命周期)。
现在,重新打包插件(mvn clean package),替换服务器中的旧JAR,重启服务器。当一个新玩家加入时,他应该会收到你配置的欢迎消息,同时控制台也会有对应的日志。至此,你的第一个Bukkit插件已经具备了命令交互、配置管理和事件响应的完整能力。这为你打开了一扇门,接下来你可以探索更多的事件类型(如PlayerQuitEvent,BlockBreakEvent,AsyncPlayerChatEvent),实现更复杂、更有趣的服务器功能了。