跳转至

Allay

Allay是面向Minecraft基岩版的第三方自实现服务端软件。它使用Java21运行,从网络协议、世界管理、实体系统、方块系统、物品系统到插件系统均由社区项目自行实现,而不是在BDS进程内加载插件。

Allay不是BDS的原生组成部分,也不是Mojang提供的官方服务端插件系统。Allay公开的API、配置文件、世界生成器、线程模型和插件能力均属于Allay项目本身,不能视为BDS或原版基岩版客户端直接具备的能力。

概述

Allay的定位接近Java生态中的社区服务端:它尝试以可维护的代码结构重新实现基岩版服务器,并在此基础上提供插件API。其目标包括可靠、快速、功能丰富、开发者友好、跨平台以及支持多协议版本。

与基于BDS的插件加载器相比,Allay不依赖封闭的BDS二进制接口,因此可以在服务端内部结构、调度模型、世界生成、容器界面和插件API设计上具有更高自由度。与此同时,这也意味着Allay必须自行实现原版服务端行为、协议细节和大量游戏机制;其原版趋同程度取决于Allay当前版本,而不是取决于BDS本身。

与其他服务端的关系

Allay不基于Nukkit、PowerNukkitX或其他Nukkit分支,而是重新编写的自实现服务端。Allay与PowerNukkitX、Nukkit-MOT、PocketMine-MP等项目同属自实现服务端生态,但面向JVM语言和Allay自有API

Allay在实现过程中会参考其他项目。例如,Allay使用Endstone开发工具从BDS导出方块、物品、配方等数据,使用CloudburstMC相关协议库和RakNet实现,并参考PocketMine-MP、gophertunnel等项目的协议或服务端实现经验。这些关系表示生态协作和技术参考,不表示Allay是这些项目的分支。

架构

Allay将API和服务端实现分开维护。插件通常只依赖org.allaymc.allay:api模块;allay-server中的接口属于服务端实现内部接口,可能在未通知插件开发者的情况下变更、移动或删除。需要使用高级自定义方块、物品等功能时,通常需要通过AllayGradle关闭apiOnly,这相当于直接接触服务端模块,应理解为更高风险的内部API使用方式。

Allay的核心对象采用组件化设计。开发组件注入系统使用ComponentComponentProviderComponentInitInfo创建组件实例,并通过@Dependency@ComponentObject@Manager@OnInitFinish等注解处理依赖、所有者对象、管理器和初始化回调。该系统主要用于物品、方块、方块实体和实体的服务端实现。

线程模型

Allay的世界线程模型不同于Nukkit。Allay中的一个世界由多个维度组成,并且每个世界运行在单独线程上。世界拥有自己的事件总线和任务调度器;服务器实例运行在主线程上,也拥有独立的事件总线和任务调度器。

网络数据包处理分为异步处理和同步处理。数据包会先在Netty相关线程上尝试执行异步处理;未处理的数据包会进入世界的同步数据包队列,再由对应世界的网络线程同步处理。Allay设计该模型的目的,是减少把所有数据包都延迟到20刻主循环处理所造成的交互延迟。

这种模型要求插件在选择调度器和访问对象时注意作用域。Allay教程将调度器分为服务器调度器、世界调度器、维度调度器和实体调度器。插件应尽量选择能覆盖所访问数据的最小调度范围,以降低跨线程访问和生命周期错误的风险。

插件模型

Allay插件可以使用Java、Kotlin、Scala以及其他JVM语言编写。常规插件以JAR文件放置在服务器的plugins目录中,并通过plugin.json声明元数据。当前公开的插件描述文件架构列出了插件名称、入口类、作者、版本、描述、网站和依赖等字段。

Allay插件系统大致可拆分为以下组成部分:

组成部分 作用
PluginSource 提供本地或远程插件路径。
PluginLoaderPluginLoaderFactory 判断插件文件是否可加载,并创建对应加载器实例。
PluginDescriptor 保存插件名称、入口、版本、依赖和API版本等描述信息。
PluginManager 管理插件发现、加载、依赖检查、启用和禁用流程。
PluginContainer 保存正在运行的插件主体、描述符、加载器和数据目录。
Plugin 插件逻辑主体,提供onLoad()onEnable()onDisable()等生命周期方法。

服务器启动时,插件管理器会遍历插件源,找到适合每个插件文件的加载器,读取插件描述符,检查循环依赖,然后调用插件的onLoad()方法。此时服务器尚未完全启动,插件不应注册监听器、注册命令、创建调度任务或访问世界。游戏相关初始化通常应放在onEnable()中。

Allay对热重载持谨慎态度。JAR插件默认不能热重载;插件只有在确认自身能正确清理监听器、命令、调度任务和状态后,才应覆盖Plugin.isReloadable()并实现Plugin.reload()。仅把Plugin.isReloadable()返回为true并不等于真正支持热重载;对于JAR插件,调用reload()也不表示会重新从插件文件加载字节码。

API范围

Allay插件API覆盖以下常见能力:

  • 命令树、命令参数、发送者限制、权限和错误输出。
  • 事件监听器和事件总线。
  • 服务器、世界、维度和实体调度器。
  • 玩家、实体、方块、方块状态、方块属性、物品、物品栈、物品标签和魔咒。
  • 容器、玩家物品栏、方块容器、伪容器和自定义容器界面。
  • 表单、Boss栏、记分板、颜色格式和国际化。
  • 配置文件读取与保存。
  • 持久化数据容器。
  • 自定义方块和自定义物品的客户端定义生成。
  • 调试形状、迷雾、相机、地图、网络接口和世界生成等较新的或高级的接口。

这些能力会随Allay版本和API版本变化。具体接口名称、参数和可用性应以当前Javadoc、发行版和运行时行为为准。概览可参见Allay API概览

版本

Allay同时存在API版本和服务端版本。API版本遵循语义化版本;除非插件需要使用特殊功能,插件通常应依赖API版本而不是服务端实现版本。服务端版本描述Allay服务器实现本身,其主版本与API主版本同步,次版本通常随Minecraft基岩版协议版本更新,修订版本随每次发布递增。

Allay只按协议版本判断客户端兼容范围。Minecraft基岩版的多个游戏版本可能共享同一协议版本,因此一个游戏版本号有时代表该协议版本覆盖的一组补丁版本。带有@MinecraftVersionSensitive标注的API类、包或方法会随Minecraft版本更新而变化,不受普通API版本兼容承诺完全保护。

世界生成

Allay支持插件介入世界生成。安装Terra-allay-<version>-shaded.jar后,可以在worlds/world-settings.yml中将维度的generator-type设置为TERRA,并通过generator-preset指定元包和种子。Allay变更记录也显示,项目后续加入了自定义维度、自定义生物群系以及世界生成扩展事件等能力。

这些能力属于Allay服务端和Allay插件生态。它们不表示BDS原生支持相同的世界生成器插件接口。

局限性

Allay作为自实现服务端具有以下限制:

  • 原版机制、红石、实体AI、方块实体、容器和世界生成行为需要由Allay逐步实现,不能默认等同于BDS
  • 基岩版协议更新可能要求Allay更新协议库、运行时数据、方块和物品数据以及状态更新逻辑。
  • 插件API快速演进时,服务端模块、@MinecraftVersionSensitive接口和高级自定义内容接口可能出现破坏性变更。
  • 自实现服务端的世界格式、配置文件和插件模型通常不能与BDS、LeviLamina、Endstone、Nukkit或PocketMine-MP直接互换。
  • 部分实现线索仍需结合当前版本的实际行为复核,不能直接照搬。