MCIO Plugins MCIO Plugins
首页
爱发电 (opens new window)
无法下载? (opens new window)

人间工作P

我每天都好困… 最近在学习和进行 VOCALOID 创作
首页
爱发电 (opens new window)
无法下载? (opens new window)
  • PluginBase

    • PluginBase 简介
      • 简介
      • 开始使用
      • 正在使用 PluginBase 的插件
      • 项目发布于
      • 开发文档
      • shadow 去除不必要部分
      • shadow 部分 relocate
    • 构建脚本
    • 插件元数据
    • 插件主类
    • 一些工具
    • 菜单
    • 菜单配置文件
    • Vault 经济
    • 数据库连接池
    • Adventure 支持
    • 本地化系统
  • Item-NBT-API

  • 开发文档
  • PluginBase
2025-06-04
目录

PluginBase 简介

Minecraft 插件开发前置

# 简介

经过一年多 Minecraft 服务器插件的开发,我逐渐感觉到有一些步骤没有必要。
于是我创建了插件模板,但这还不够,还是太麻烦了。
这个库包含了我常用的工具类,以及惯用的设计结构。
此外,我非常讨厌一个插件还要带上前置插件这种拖家带口行为,所以,这个前置是通过 shadow 打进插件 jar 里的。并且,以我设计的模块工作原理,必须要把这个依赖 shadow 打进 jar 并 relocate 到插件自己的包。

# 开始使用

详见左侧文档目录

插件模板生成器详见 https://bukkit.mcio.dev (opens new window)

# 正在使用 PluginBase 的插件

  • SweetRiceBase [闭源] NeoWorld 服务器基础玩法插件
  • SweetRiceTeam [闭源] NeoWorld 服务器副本组队插件
  • SweetRiceActivity [闭源] NeoWorld 服务器活动服机制
  • SweetGenerator [闭源] NeoWorld 服务器肉鸽地牢生成插件
  • SweetQuests [暂定闭源] NeoWorld 服务器剧情系统
  • CraftItem (opens new window) 物品锻造插件
  • SweetWarehouse (opens new window) 云物品仓库插件
  • SweetInventory (opens new window) 自定义菜单插件
  • SweetAdaptiveShop (opens new window) 动态价格商店插件
  • SweetCheckout (opens new window) 充值插件
  • SweetRewards (opens new window) 累积点数插件
  • SweetDrops (opens new window) 方块挖掘概率事件插件
  • SweetFlight (opens new window) 限时飞行插件
  • SweetMessages (opens new window) 基础消息插件
  • ...其它 Sweet系列插件 (opens new window)

# 项目发布于

  • Github (opens new window)
  • MineBBS (opens new window)

# 开发文档

通过这篇文档,来上手使用 PluginBase 进行 Minecraft 插件开发。

请按顺序阅读并操作。

  1. 构建脚本 build.gradle.kts
  2. 插件元数据 plugin.yml
  3. 插件主类 PluginMain.java
  4. 一些工具 ColorHelper, ItemStackUtil, Util 等等
  5. (可选) 菜单 GuiManager
  6. (可选) 菜单配置文件 AbstractGuiModule
  7. (可选) Vault 经济 IEconomy
  8. (可选) HikariCP 数据库连接池 IDatabase
  9. (可选) Adventure 在非 Paper 服务端的富文本支持 AdventureUtil
  10. (可选) 本地化(语言文件)系统 LanguageManager

# shadow 去除不必要部分

适当地给插件减重,去除当前插件不需要的功能
(部分功能仅能在 1.0.8 版本后去除,否则会出现一些问题)

tasks {
    // ...
    shadowJar {
        // ...
        // 避免匿名类没删除,最好加通配符*来匹配
        listOf(
            // 界面配置
            "top/mrxiaom/pluginbase/func/AbstractGui*",
            "top/mrxiaom/pluginbase/func/gui/*",
            // PAPI兼容 (注意: 界面配置依赖这个)
            "top/mrxiaom/pluginbase/utils/PAPI*",
            // ItemsAdder 支持
            "top/mrxiaom/pluginbase/utils/IA*",
            // 物品操作相关支持
            "top/mrxiaom/pluginbase/utils/ItemStackUtil*",
            // 界面菜单管理器
            "top/mrxiaom/pluginbase/func/GuiManager*",
            "top/mrxiaom/pluginbase/gui/*",
            // 多语言支持
            "top/mrxiaom/pluginbase/func/LanguageManager*",
            "top/mrxiaom/pluginbase/func/language/*",
            // Adventure (消息和物品) 支持
            "top/mrxiaom/pluginbase/utils/Adventure*",
            // BungeeCord 消息通道 ByteArrayDataOutput 消警告
            "top/mrxiaom/pluginbase/utils/Bytes*",
        ).forEach(this::exclude)
    }
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# shadow 部分 relocate

我在做 paper 与 spigot 兼容的时候发现,因为我要把 adventure 打包到插件里并 relocate 到我的包,那么如果我要调用 paper 的 Bukkit.createInventory 来在标题使用 adventure,那么就会因为包被 relocate 了而报错。

我的解决方法是,把 paper 的操作放到了一个单独的类 PaperInventoryFactory,里面有一个 create(InventoryHolder, int, String),参数 String 是标题。
执行之后,会调用 mini message 转换为 Component 对象,传给 paper 的 Bukkit.createInventory。只要修改 shadowJar 插件让这个 PaperInventoryFactory 类不会被 relocate 即可。
我已经把 shadowJar 改好了,直接用就行:

// settings.gradle.kts
buildscript {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
    dependencies {
        classpath("top.mrxiaom:shadow:7.1.3")
    }
}
1
2
3
4
5
6
7
8
9
10

shadow 7.1.2 的工具链有点老了,发布不到 Gradle Plugin Portal,升级工具链又不支持 gradle 7.x,干脆就发 Maven Central 了。反正这样添加起来也不麻烦,多几行代码不碍事,能解决问题就行。也测试了支持在 Gradle 8.5 跑,不求在太高的 Gradle 版本能用,目前能兼容 Java 21 就行。

// build.gradle.kts
plugins {
    // ...
    id("top.mrxiaom.shadow")
}
// ...
tasks {
    // ...
    shadowJar {
        // ...
        ignoreRelocations("org/example/plugin/utils/PaperInventoryFactory.class")
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

我的需求比较简单,所以现用 String 通过 mini message 转 Component。如果复杂一点,可以用 GsonComponentSerializer 作桥梁,沟通打包到你插件里的 adventure 和 paper 的 adventure。

顺带一提,可以加 ProtocolLib、packetevents 之类的依赖来解决 spigot 不支持在容器标题使用 adventure 的问题。不过,要加依赖插件的东西就不写到这个框架里了。如有需要,请参见 SweetMail 的实现 (opens new window)。

上次更新: 2025/06/04, 12:03:38
构建脚本

构建脚本→

Theme fork from Vdoing | Copyright © 2018-2025 人间工作P | 到爱发电支持我

除非特别说明,本站点所有文章均以 CC BY-SA 协议授权

  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式