项目搭建
Paper 团队主要使用 IntelliJ IDEA,本文档将围绕该 IDE 进行讲解;但下方步骤仅需小幅修改即可适配其他 IDE。
Paper 采用 Gradle 作为构建系统,配套工具均基于 Gradle 开发。下文绝大多数代码可改造适配 Maven 等其他构建工具,但本文仅覆盖Gradle Kotlin DSL写法。
如需将 Maven 项目迁移至 Gradle,可查阅官方迁移文档:https://docs.gradle.org/current/userguide/migrating_from_maven.html
新建项目
打开 IDE,选择新建项目。在 IntelliJ 中点击「New Project」,项目类型选择Gradle - Kotlin DSL,点击创建。
创建完成后会自动打开build.gradle.kts,你可在此文件中添加项目依赖。
将 Paper 作为项目依赖
想要引入 Paper 依赖,需要在build.gradle.kts中配置 Paper 仓库与依赖声明。
提示:
如需锁定指定构建版本,将版本号末尾的+替换为完整构建标识,例如{版本号}.build.25-alpha代表对应版本的第25个Alpha测试构建。
26.1(对应1.21.11)及更早版本版本号格式为{版本号}-R0.1-SNAPSHOT,无法单独指定某一个构建。
- Gradle 配置文档:https://docs.papermc.io/paper/dev/project-setup/#tab-panel-77
- Maven(不推荐使用):https://docs.papermc.io/paper/dev/project-setup/#tab-panel-78
若使用 Maven 并希望自动拉取最新构建,版本使用区间写法[26.1.2.build,);锁定固定构建则填写完整版本26.1.2.build.74-stable。
pom.xml 配置示例
<project><repositories><repository><id>papermc</id><url>https://repo.papermc.io/repository/maven-public/</url></repository></repositories><dependencies><dependency><groupId>io.papermc.paper</groupId><artifactId>paper-api</artifactId><version>[26.1.2.build,)</version><scope>provided</scope></dependency></dependencies></project>配置 src 源码目录
备注:若你的 IDE 已自动生成 src 目录,可跳过本节。
手动创建目录结构:新建src文件夹,内部创建main;在 main 内新建两个文件夹:java(Java源码)、resources(资源文件)。
完整目录结构:
example-plugin/ ├─ build.gradle.kts ├─ settings.gradle.kts └─ src/ └─ main/ ├─ java/ └─ resources/java 源码目录规范
所有 Java 源代码存放于 java 文件夹,必须通过包分层管理代码。本示例创建包io.papermc.testplugin,并在包内新建主类ExamplePlugin.java。
目录层级:
example-plugin/ ├─ build.gradle.kts ├─ settings.gradle.kts └─ src/ └─ main/ ├─ java/ │ └─ io/ │ └─ papermc/ │ └─ testplugin/ │ └─ ExamplePlugin.java └─ resources/包命名规范
前文示例中ExamplePlugin类位于io.papermc.testplugin包下。包是代码分层管理机制,本质是文件夹,用于归类功能相近的类。Oracle 官方包教程:https://docs.oracle.com/javase/tutorial/java/package/packages.html
包命名规范文档:https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html
- 优先使用域名倒序作为基础包名
例:官网域名 papermc.io → 基础包io.papermc - 无自有域名可使用 GitHub 用户名:用户名为 torvalds →
io.github.torvalds - 末尾追加项目名,保证全平台包名唯一
例:项目名为 ExamplePlugin → 完整包io.github.torvalds.exampleplugin
插件主类
主类是插件唯一入口,整个插件仅允许一个类继承JavaPlugin。
开发规范:不建议直接命名为 Main,建议使用插件名称命名,例如插件名为 Example,主类命名为 ExamplePlugin。
ExamplePlugin.java 完整示例
packageio.papermc.testplugin;importnet.kyori.adventure.text.Component;importorg.bukkit.Bukkit;importorg.bukkit.event.EventHandler;importorg.bukkit.event.Listener;importorg.bukkit.event.player.PlayerJoinEvent;importorg.bukkit.plugin.java.JavaPlugin;publicclassExamplePluginextendsJavaPluginimplementsListener{@OverridepublicvoidonEnable(){// 注册当前类为事件监听器Bukkit.getPluginManager().registerEvents(this,this);}// 玩家进入服务器事件@EventHandlerpublicvoidonPlayerJoin(PlayerJoinEventevent){event.getPlayer().sendMessage(Component.text("Hello, "+event.getPlayer().getName()+"!"));}}resources 资源目录
resources 文件夹用于存放插件配置核心文件plugin.yml,配置文档参考:https://docs.papermc.io/paper/dev/plugin-yml
使用 IntelliJ Minecraft Development 插件快速创建项目
你也可以借助 Minecraft Development IntelliJ 插件 一键生成项目。
备注:该教程仅支持 IntelliJ IDEA,其他 IDE 请遵循上文手动搭建流程。
安装 Minecraft Development 插件
- 打开
文件 > 设置 > 插件(File > Settings > Plugins) - 在市场(Marketplace)分类搜索
Minecraft Development完成安装
安装完成后点击重启 IDE(Restart IDE)按钮生效。
通过插件新建项目
安装插件后,打开文件 > 新建 > 项目(File > New > Project…),左侧分类选择Minecraft。
填写项目参数说明表:
| 字段 | 说明 |
|---|---|
| Name | 项目文件夹名称 |
| Location | 项目本地存储路径 |
| Platform Type | 开发目标类型,固定填写Plugin |
| Platform | 服务端平台,固定填写Paper |
| Minecraft Version | 目标 Minecraft 游戏版本 |
| Plugin Name | 插件对外展示名称 |
| Main Class | 插件主类,必须继承JavaPlugin |
| Optional Settings | 可选配置:作者、官网、插件描述等,不填不影响插件运行 |
| Build System | 构建工具,Paper 推荐 Gradle,也可选择 Maven |
| Paper Manifest | 是否启用新式 Paper 插件(paper-plugin.yml),目前仍处于开发阶段,不推荐开启 |
| Group ID | Maven/Gradle 分组标识,规范为域名倒序;无域名可用io.github.你的用户名,无 GitHub 则用me.你的用户名 |
| Artifact ID | 项目构件标识,一般与项目 Name 保持一致 |
| Version | 项目版本号,默认1.0-SNAPSHOT,开发阶段无需严格定义 |
| JDK | 编译使用的 Java 版本,最低 Java 25 及以上 |
填写完成点击「Create」,IDEA 将自动生成完整插件项目结构。
插件运行原理
插件是用于拓展 Minecraft 服务端功能的程序,使用 JVM 系语言开发(Java、Kotlin、Groovy、Scala)。
插件存放于服务端根目录的plugins文件夹,以.jar压缩包形式加载。每个插件都在plugin.yml中声明主类,该类必须继承 JavaPlugin,是插件执行入口,同时定义插件全生命周期回调方法。
不建议在主类构造函数中编写业务代码,插件加载阶段无法保证 Bukkit API 可用。初始化逻辑请放在onLoad方法中;同时禁止手动调用插件主类构造函数,会引发插件运行异常。
插件生命周期
插件在服务端运行时会经历加载/卸载流程:加载时完成初始化与启用;卸载时执行停用与资源回收。
初始化阶段(onLoad)
插件被载入内存时触发onLoad方法,用于初始化底层资源。
此阶段绝大多数 Bukkit API 未就绪,禁止调用游戏相关接口。
启用阶段(onEnable)
插件启用时触发onEnable,用于初始化运行所需资源。
该阶段插件已完成初始化,但服务端尚未开始游戏刻度循环,可安全注册事件监听器;但大量游戏API仍不可调用。
适合操作:建立数据库连接、启动后台线程等无法在 onLoad 执行的逻辑。
停用阶段(onDisable)
插件卸载前触发onDisable,用于清理插件占用的全部资源。
会在所有插件统一卸载前执行,负责持久化本地数据、关闭数据库连接等回收操作。
事件监听器
事件机制允许插件监听服务端发生的各类行为,对应事件触发时自动执行自定义代码,相比循环轮询性能更高。
示例:玩家进入服务器时触发PlayerJoinEvent
事件完整文档:https://docs.papermc.io/paper/dev/event-listeners
部分事件支持取消(cancellable),取消后事件对应的行为不会生效。
示例:PlayerMoveEvent玩家移动事件,取消后玩家无法移动,常用于反作弊限速检测。
编写监听器必须注意事件热度:高频触发的事件称为“热事件”(例如玩家移动事件),监听器内禁止执行复杂耗时逻辑,极易造成服务器卡顿。
优化方案:前置快速判断,不满足处理条件直接 return;例如仅当玩家更换方块坐标时才执行逻辑,坐标未变化直接跳过。
指令系统
指令允许玩家、控制台、RCON、命令方块在服务端执行插件代码,由插件注册、指令发送者调用。
示例:服务端内置/help指令,玩家可在聊天框或命令方块执行。
指令支持参数,参数以空格分隔,例/give Notch diamond,参数数组为["Notch", "diamond"]。
权限系统
权限用于管控指令、事件功能的访问权限,由插件注册,可被其他插件读取;权限可分配给玩家或权限组,支持层级继承。
示例:插件定义example.command.help为example.command的子权限,拥有父权限的玩家自动获得子权限。
备注:权限管理插件支持通配符*,授予example.command.*会匹配所有以该前缀开头的权限。
强烈不推荐使用全局通配符*(全部权限),存在严重安全风险,还会产生非预期功能副作用,谨慎使用。
配置文件
插件可自定义配置文件,用于存储运行所需数据(例如自定义方块ID)。
配置文件存放于服务端plugins目录下对应插件的数据文件夹,服务端提供标准 YAML 读写API。
配置文档:https://docs.papermc.io/paper/dev/plugin-configurations
任务调度
插件可调度延时/循环任务,例如延迟5秒执行逻辑。
时间换算:服务器正常运行下 20 tick = 1 秒;延时100 tick 等价5秒。
注意:服务器卡顿会导致任务延后执行,例如TPS仅10时,100tick任务实际耗时10秒。
Java 原生Thread#sleep()会阻塞主线程,直接造成服务器卡死,禁止在主线程使用,统一使用官方Scheduler调度API。
调度文档:https://docs.papermc.io/paper/dev/scheduler
富文本组件(Component)
Minecraft 1.7 引入富文本组件机制,插件可向玩家发送带格式消息(颜色、加粗、可点击链接)。旧版仅支持传统颜色代码,格式受限。
Paper 内置 Adventure 富文本库,快速构建格式化消息。
Adventure 官方文档:https://docs.papermc.io/adventure/
Paper 适配文档:https://docs.papermc.io/paper/dev/component-api/introduction
Paper新式插件(paper-plugin.yml 实验性功能)
Paper 新式插件允许开发者使用 Mojang 原生数据包等现代特性,拓展 Paper API 能力边界。
实验性功能:接口随时可能大幅调整,不建议生产环境直接使用
- 引导器(Bootstrapper):https://docs.papermc.io/paper/dev/getting-started/paper-plugins/#bootstrapper
- 加载器(Loader):https://docs.papermc.io/paper/dev/getting-started/paper-plugins/#loaders
- 新旧差异:https://docs.papermc.io/paper/dev/getting-started/paper-plugins/#differences
使用方式
与传统 Bukkit 插件类似,需在资源目录添加paper-plugin.yml,但不能完全替代plugin.yml,二者配置声明规则存在区别。
同一Jar包可同时携带plugin.yml+paper-plugin.yml两份配置。
paper-plugin.yml 基础示例
name:Paper-Test-Pluginversion:'1.0'main:io.papermc.testplugin.TestPlugindescription:Paper 测试插件api-version:'26.1.2'bootstrapper:io.papermc.testplugin.TestPluginBootstraploader:io.papermc.testplugin.TestPluginLoader依赖声明
新式插件将依赖分为两大模块,配置示例:
dependencies:bootstrap:# RegistryPlugin 在启动阶段注册数据,运行时无需依赖,仅引导阶段加载RegistryPlugin:load:BEFORErequired:truejoin-classpath:true# 默认trueserver:# 运行时必需插件,在本插件加载完成后再加载RequiredPlugin:load:AFTERrequired:true# 本插件无法访问该插件的类路径join-classpath:false分类说明:
bootstrap:引导阶段依赖,用于 Bootstrapper 引导器代码server:服务运行阶段依赖,插件核心业务逻辑使用
单条依赖配置参数详解:
RegistryPlugin:load:BEFORE# 默认 OMITrequired:true# 默认 truejoin-classpath:true# 默认 trueload:可选值BEFORE/AFTER/OMIT,控制目标插件在本插件之前/之后加载;OMIT 加载顺序无定义required:true=缺少该插件则本插件加载失败;false=可选依赖join-classpath:true=本插件可读取目标插件内部类与依赖;false=隔离类加载器
多插件互相前置依赖会形成加载死循环,服务器启动失败。
依赖场景示例
# 1. 前置必需依赖 ProtocolLibProtocolLib:load:BEFORErequired:true# 2. 可选后置依赖,本插件加载完成后再加载商店插件SuperShopsXUnlimited:load:AFTERrequired:false# 3. 需要读取对方内部代码,开启类路径共享SuperDuperTacoParty:required:truejoin-classpath:true新式插件设计目标
为未来官方API提供底层框架,对齐原版Mojang原生机制;通过引导器(Bootstrapper)在服务端启动前加载插件资源,解锁更多原生拓展能力。
引导器 Bootstrapper
实现PluginBootstrap接口,并在paper-plugin.yml声明类路径即可启用自定义引导器。
TestPluginBootstrap.java
publicclassTestPluginBootstrapimplementsPluginBootstrap{@Overridepublicvoidbootstrap(BootstrapContextcontext){}@OverridepublicJavaPlugincreatePlugin(PluginProviderContextcontext){// 支持自定义构造参数传入主类returnnewTestPlugin("My custom parameter");}}引导器可自定义插件初始化流程,向主类构造函数传参;当前功能较少,仍处于高度实验阶段,后续API会持续改动。
加载器 Loader
实现PluginLoader接口,在配置文件声明全类名,自定义插件类加载环境。
当前核心用途:动态引入外部依赖库,构建插件专属类路径。
TestPluginLoader.java
publicclassTestPluginLoaderimplementsPluginLoader{@Overridepublicvoidclassloader(PluginClasspathBuilderclasspathBuilder){// 引入本地Jar依赖classpathBuilder.addLibrary(newJarLibrary(Path.of("dependency.jar")));// Maven远程依赖解析器MavenLibraryResolverresolver=newMavenLibraryResolver();resolver.addDependency(newDependency(newDefaultArtifact("com.example:example:version"),null));resolver.addRepository(newRemoteRepository.Builder("paper","default","https://repo.papermc.io/repository/maven-public/").build());classpathBuilder.addLibrary(resolver);}}支持两种依赖库类型:
JarLibrary:本地Jar文件MavenLibraryResolver:Maven远程仓库依赖
拉取Maven中央库必须使用镜像源,直接访问maven.org违反服务条款,会触发访问限流。
推荐使用Paper内置镜像,配置代码:
resolver.addRepository(newRemoteRepository.Builder("central","default",MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR).build());直接使用Maven中央源会在控制台输出警告日志。
新旧插件核心差异
1. Bukkit序列化机制
新式插件仍兼容 Bukkit 序列化工具org.bukkit.configuration.serialization,但自定义类不会自动注册序列化。
调用ConfigurationSection#getObject读取自定义对象前,必须手动执行ConfigurationSerialization#registerClass(Class)注册类。
2. 类加载隔离机制
默认情况下新式插件互相隔离,无法读取对方内部类与依赖;仅在配置join-classpath: true时才能访问目标插件类加载器。
PluginName:join-classpath:true# 允许读取该插件内部代码注意:单向生效,其他插件无法反向访问你的插件类加载器。
3. 加载顺序逻辑拆分
新式插件不再依靠基础 dependencies 字段控制加载顺序,完全拆分依赖与加载时序配置,实现精细化类路径共享。
加载顺序配置文档:https://docs.papermc.io/paper/dev/getting-started/paper-plugins/#dependency-declaration
4. 指令注册方式
新式插件不再通过paper-plugin.yml的 commands 节点注册指令,统一使用 Brigadier 原生指令API 在代码中动态注册。
5. 循环加载报错机制
传统Bukkit插件会自动尝试修复循环依赖,新式插件不会自动处理,检测到加载死循环直接抛出致命错误并终止服务端启动。
报错示例:
[ERROR]: [LoadOrderTree] ================================= [ERROR]: [LoadOrderTree] Circular plugin loading detected: [ERROR]: [LoadOrderTree] 1) Paper-Test-Plugin1 -> Paper-Test-Plugin -> Paper-Test-Plugin1 [ERROR]: [LoadOrderTree] Paper-Test-Plugin1 loadbefore: [Paper-Test-Plugin] [ERROR]: [LoadOrderTree] Paper-Test-Plugin loadbefore: [Paper-Test-Plugin1] [ERROR]: [LoadOrderTree] Please report this to the plugin authors of the first plugin of each loop or join the PaperMC Discord server for further help. [ERROR]: [LoadOrderTree] =================================循环依赖问题需要开发者自行调整依赖加载顺序解决。
plugin.yml 传统插件配置文件
plugin.yml是传统Bukkit/Paper插件的核心配置文件,存放插件基础信息、依赖、权限、指令等元数据。
文件路径:项目src/main/resources/plugin.yml
完整示例
name:ExamplePluginversion:1.0.0main:io.papermc.testplugin.ExamplePlugindescription:示例演示插件author:PaperMCwebsite:https://papermc.ioapi-version:'26.1.2'字段详解
备注:字段无固定顺序,带*标记为必填项。
name*
插件名称,日志、插件列表展示;若配置 prefix 日志会优先显示前缀。name: ExamplePlugin
version*
插件版本号,日志与插件信息指令展示。version: 1.0.0
main*
插件主类全限定路径,必须继承 JavaPlugin,插件唯一入口。main: io.papermc.testplugin.ExamplePlugin
description
插件简短功能描述,/plugins 指令展示。description: 示例演示插件
author / authors
插件作者,单作者使用 author,多作者数组使用 authors
author:PaperMCauthors:[PaperMC,SpigotMC,Bukkit]contributors
非核心维护贡献者列表contributors: [PaperMC, SpigotMC, Bukkit]
website
插件官网/GitHub地址website: https://papermc.io
api-version
目标PaperAPI版本,1.20.5起支持小版本号;低于该版本的服务端拒绝加载插件,合法区间 1.13 ~ 26.1.2。api-version: '26.1.2'
备注:未填写会被识别为遗留插件,控制台输出警告。
load
插件加载时机,可选STARTUP(世界生成前)/POSTWORLD(世界生成后,默认)load: STARTUP
prefix
日志输出自定义前缀,替代插件名称prefix: EpicPaperMCHypePlugin
libraries
远程Maven依赖,服务端自动下载引入,无需手动打包依赖(shade)
libraries:-com.google.guava:guava:30.1.1-jre-com.google.code.gson:gson:2.8.6中央仓库地址可通过环境变量PAPER_DEFAULT_CENTRAL_REPOSITORY、系统属性org.bukkit.plugin.java.LibraryLoader.centralURL自定义。
permissions
权限节点定义,控制功能访问权限
permissions:permission.node:description:"基础权限节点"default:opchildren:permission.node.child:trueanother.permission.node:description:"第二个权限节点"default:notop参数说明:
- description:权限说明文本
- default:默认持有者,op/notop/true/false;未填写继承全局 default-permission(默认op)
- children:子权限,true代表拥有父权限自动获得子权限
default-permission
未单独设置 default 的权限默认归属default-permission: true
paper-plugin-loader
新式插件自定义加载器全类名,实验性功能paper-plugin-loader: com.example.paperplugin.MyPluginLoader
paper-skip-libraries
true=跳过自动下载libraries节点依赖,交由自定义Loader管理依赖,实验性功能paper-skip-libraries: false
commands 指令配置节点
传统插件可在yml声明指令元数据:
commands:command:description:"指令功能描述"usage:"/command <arg>"aliases:[cmd,command]permission:permission.nodepermission-message:"你没有权限执行该指令"- description:指令说明,/help 查询展示
- usage:指令参数格式提示
- aliases:指令别名列表
- permission:执行所需权限节点;玩家仅能看见拥有权限的指令
- permission-message:无权限时提示文本
依赖相关配置
depend 内插件会在本插件前加载,互相依赖会形成死循环导致启动失败。
depend
强制前置依赖,缺少则插件加载失败depend: [Vault, WorldEdit]
softdepend
可选前置依赖,缺失不影响插件加载,仅部分功能失效softdepend: [Vault, WorldEdit]
loadbefore
声明本插件需要在指定插件之前加载,用于对外提供APIloadbefore: [Vault, FactionsUUID]
provides
声明本插件替代某插件/库,其他依赖该插件的程序会将本插件视为目标依赖存在provides: [SomeOtherPlugin]
paperweight-userdev 开发工具
paperweight 是 Paper 官方自研构建工具集;paperweight-userdev 是配套 Gradle 插件,用于开发阶段直接访问服务端内部代码(NMS)。
前置要求:掌握基础 Gradle Kotlin DSL;完整可运行示例插件仓库:https://github.com/PaperMC/paperweight-test-plugin
工具作用
这是官方唯一支持的NMS访问方案;直接分发服务端Jar违反Minecraft用户协议EULA。
Spigot及1.20.5前Paper使用混淆映射,开发体验极差;该工具在开发阶段提供完整反混淆代码提示,打包时自动重映射适配线上混淆服务端。
注意:反射代码不会自动重映射,如需反射使用原生名称可引入库:https://github.com/jpenilla/reflection-remapper
26.1版本重大改动
Minecraft 26.1起官方移除服务端混淆,Paper不再支持混淆插件,重混淆功能对26.1+开发包完全失效,本节仅作旧版本参考。
引入插件
build.gradle.kts 配置:
plugins{id("io.papermc.paperweight.userdev")version"2.0.0-beta.21"}Gradle版本要求
使用最新稳定版Gradle,升级文档:https://docs.gradle.org/current/userguide/gradle_wrapper.html
当前版本支持1.17.1及以上Minecraft版本开发包;仅最新版官方提供技术支持,旧版本问题会要求升级。
疑难问题可前往PaperMC Discord #build-tooling-help 频道咨询:https://discord.gg/PaperMC
SNAPSHOT预览版仓库配置
settings.gradle.kts
pluginManagement{repositories{gradlePluginPortal()maven("https://repo.papermc.io/repository/maven-public/")}}引入开发包依赖
项目缺少开发包会直接报错,在dependencies块添加:
dependencies{// 其他依赖paperweight.paperDevBundle("26.1.2.build.+")}提示:引入开发包后请删除原paper-api依赖,开发包已内置完整API。
自定义Java工具链
部分版本开发包对JDK版本有限制,执行 paperweightUserdevSetup 补丁失败时可手动指定JDK:
示例 1.17.1适配:
paperweight{javaLauncher=javaToolchains.launcherFor{// 场景示例:1.17.1原生编译JDK16,开发包不兼容21+,但编译使用JDK25languageVersion=JavaLanguageVersion.of(17)}}多项目示例仓库:https://github.com/PaperMC/paperweight-test-plugin/tree/multi-project
重混淆打包(仅1.21.11及以下旧版本)
26.1起该功能彻底失效,仅作历史参考reobfJar任务生成适配Spigot混淆映射的插件Jar,可在标准Paper服务端运行。
输出目录build/libs:
-dev后缀包:Mojang原生映射,未混淆,无法在非Paper服务端使用
Shadow打包兼容
项目引入shadow插件时,工具会自动以打包后的Jar作为重混淆输入;-dev-all.jar是打包但未混淆产物。
编译时自动执行重混淆配置:
tasks.assemble{dependsOn(tasks.reobfJar)}1.20.5及以上版本映射规则
1.20.5起Paper服务端原生使用Mojang无混淆映射,CraftBukkit类不再分版本包;插件按需自动反混淆加载,绝大多数流程由paperweight自动处理。
默认映射判定规则
- 无清单映射声明的Spigot/Bukkit插件默认判定为Spigot混淆映射,首次加载需反混淆
- 无清单映射声明的Paper插件默认判定为Mojang原生映射,无需反混淆
打包输出映射模式
1. 输出Mojang原生映射(推荐)
优势:跳过服务端启动时一次性重映射,小版本间兼容性更好;缺陷:无法在Spigot服务端运行
移除所有 dependsOn(reobfJar),添加配置:
paperweight.reobfArtifactConfiguration=io.papermc.paperweight.userdev.ReobfArtifactConfiguration.MOJANG_PRODUCTION2. 输出Spigot混淆映射
兼容Spigot与Paper双端,配置:
paperweight.reobfArtifactConfiguration=io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION备注:Gradle Groovy DSL需调用静态方法getMOJANG_PRODUCTION()获取枚举。