插件如何工作
简介
插件是一种扩展Minecraft服务器功能的方式。它们使用基于JVM的语言编写,如Java、Kotlin、Groovy或Scala。插件从服务器目录的plugins文件夹中加载。插件将从.jar文件中加载。每个插件都有一个在插件的plugin.yml文件中指定的主类。这个类必须继承JavaPlugin,它是插件的入口点,也是定义插件生命周期方法的地方。
我们不建议在主类的构造函数中编写代码,因为在那个时候无法保证哪些API是可用的。相反,你应该使用onLoad方法来初始化你的插件。
此外,不要直接调用插件的构造函数。这会导致插件出现问题。
插件生命周期
插件在运行时加载和卸载。当插件加载时,它会被初始化并启用。当插件卸载时,它会被禁用并完成。
初始化
当插件加载时,它会被初始化。这意味着插件被加载到内存中并调用其onLoad方法。这个方法用于初始化插件并设置它需要的任何资源。在这个时候,大部分Bukkit API都不可用,所以与它交互是不安全的。
启用
当插件启用时,会调用其onEnable方法。这个方法用于设置插件运行所需的任何资源。这个方法在插件初始化之后但在服务器开始计时之前调用,所以注册事件监听器和插件运行所需的其他资源是安全的,但与许多API交互通常是不安全的。
这也是你可以打开数据库连接、启动线程和其他在onLoad方法中不安全的操作的时候。
禁用
当插件禁用时,会调用其onDisable方法。这个方法用于清理插件分配的任何资源。这个方法在所有插件卸载之前调用,用于在插件卸载之前需要进行的任何清理。这可能包括将数据保存到磁盘或关闭数据库连接。
事件监听器
事件是插件监听服务器中发生的事情并在事件触发时运行代码的一种方式。例如,PlayerJoinEvent在玩家加入服务器时触发。这是一种比不断检查更高效的运行代码的方式。更多信息请参见我们的事件监听器页面。
一些事件是可取消的。这意味着当事件触发时,它可以被取消,这会否定或停止事件的效果。例如,PlayerMoveEvent是可取消的。这意味着当它被取消时,玩家将不会移动。这对于反作弊等功能很有用,在这种情况下,如果玩家移动太快,你想取消该事件。
在编写事件监听器时,考虑事件的"热度"很重要。"热"事件是经常触发的事件。例如,PlayerMoveEvent在玩家每次移动时都会触发。这意味着如果你在事件监听器中有很多昂贵的代码,它将在玩家每次移动时运行。这可能会导致大量延迟。保持事件监听器尽可能轻量级很重要。一种可能的方法是快速检查是否应该处理事件,如果不应该,则返回。例如,如果你只想在玩家从一个方块移动到另一个方块时处理事件,你可以检查玩家的位置是否改变了方块。如果没有,你可以从监听器返回。
命令
命令是玩家、控制台、RCON和命令方块在服务器上运行代码的一种方式。命令由插件注册,可以由命令发送者运行。例如,/help命令由服务器注册,可以由玩家运行。玩家可以通过在聊天中输入命令或从命令方块运行命令来运行命令。
命令可以有参数。例如,/give命令需要一个参数来指定给予物品的玩家和一个参数来指定要给予的物品。参数由空格分隔。例如,命令/give Notch diamond将给名为Notch的玩家一个钻石。注意这里参数是["Notch", "diamond"]。
权限
权限是一种控制谁可以运行命令和谁可以监听事件的方式。权限由插件注册,可以被其他插件检查。权限可以授予给玩家和组。
权限可以具有层次性,如果由插件在其plugin.yml中定义。例如,插件可以将example.command.help定义为example.command的子权限。
这意味着如果玩家有example.command权限,他们也将拥有example.command.help权限。
权限插件可以允许使用通配符权限,使用*字符来授予任何可用的权限或子权限,即使插件本身没有设置层次权限也允许层次权限。
例如,通过支持通配符的权限插件授予example.command.*将授予访问所有以example.command.开头的权限。
不建议使用通配符权限,特别是*(所有权限),因为它可能是一个巨大的安全风险,并且可能对玩家造成不必要的副作用。请谨慎使用。
配置
插件可以有配置文件。这些文件用于存储插件运行所需的数据。例如,一个向游戏添加新方块的插件可能有一个存储方块ID的配置文件。配置文件应该存储在插件的数据文件夹中,在plugins文件夹内。服务器提供了一个YAML配置API,可用于读写配置文件。更多信息请参见这里。
调度任务
插件可以调度任务在稍后运行。这对于需要在一定时间后运行代码的情况很有用。例如,插件可能想在5秒后运行代码。这可以通过调度任务在100个tick后运行来实现 - 在正常运行期间一秒是20个tick。重要的是要注意,如果服务器出现延迟,任务可能会延迟。例如,如果服务器每秒只运行10个tick,那么调度在100个tick后运行的任务将需要10秒。
在Java中,通常你可以使用Thread#sleep()来延迟代码的执行。
然而,如果代码在主线程上运行,这将导致服务器暂停延迟的时间。相反,你应该使用Scheduler API来调度任务稍后运行。
在这里了解更多关于Scheduler API的信息。
组件
自Minecraft 1.7和"组件"的引入以来,插件现在可以向玩家发送包含富文本的消息。这意味着插件可以发送包含颜色、粗体文本和可点击链接的消息。 颜色一直是可能的,但只能通过使用传统颜色代码。
Paper实现了一个名为Adventure的库,使创建和向玩家发送消息变得容易。从他们的文档这里或从我们的文档
这里了解更多关于Adventure API的信息。