Skip to content

Repository files navigation

PlayerMusic

基于 CraftEngine 与 Residence 的领地及全服公共音乐盒

领地/全服公共播放 · 自动转换 MP3/OGG · SQLite/MySQL 收藏 · Luminol/Folia 支持

版本 Minecraft Folia Java 许可证


PlayerMusic 会为每个已开启音乐功能的 Residence 领地维护一套公共播放会话,并额外提供一套管理员控制的全服会话。两种会话互相独立:控制或停止全服音乐不会修改任何领地会话,领地中的玩家仍可正常使用原版物品 GUI 选歌、收藏、暂停、切歌和切换播放模式。

目录

主要功能

  • 每个 Residence 领地拥有独立的公共音乐播放会话。
  • 同一领地中的玩家共同听歌,任意拥有使用权限的玩家都能控制该领地的音乐。
  • 管理员可开启独立的全服播放会话,所有在线玩家都能听到,且不会停止或改写任何领地会话。
  • Residence 提供普通与顶级两级音乐 flag;顶级音乐领地会覆盖当前位置的普通音乐领地。
  • 玩家可在 GUI 中按 10% 档位调整个人音乐音量,设置持久化到 SQLite/MySQL。
  • 支持“全部音乐”“我的收藏”“收音机”三种列表。
  • 支持单曲、随机、顺序三种播放模式。
  • 支持上一页、下一页、暂停、继续、停止和下一首。
  • 支持右键歌曲加入或取消收藏。
  • 支持 .mp3.ogg,自动生成 CraftEngine 声音资源。
  • 内置 Windows/Linux x64 FFmpeg,通常不需要服务器额外安装,并支持调整转码码率减小资源包。
  • 使用 SHA-256 增量缓存,未变化的音乐不会重复转换。
  • 收藏数据支持 SQLite 与 MySQL,默认使用 SQLite。
  • 使用 Folia/Paper 官方调度接口,支持 Luminol/Folia Region 线程模型。
  • 配置、消息、数据库连接和音乐库支持 /playermusic reload 热重载;少数标识项需要重启。

运行环境

项目 目标版本 说明
服务端 Luminol 1.21.11-DEV@311f4dc 同时面向兼容 Paper 1.21.11 API 的 Folia 服务端
Java 21 必须使用 Java 21 运行和构建
CraftEngine 26.7.3 必装前置,用于承载并发送 OGG 声音资源
Residence 6.0.1.8 必装前置,用于确定播放范围和领地开关
FFmpeg 内置 4.4.1 内置版本支持 Windows/Linux x64,其他平台可配置外部程序

plugin.yml 已声明 folia-supported: true。这表示插件允许在 Folia 上加载;项目同时使用统一调度封装、玩家实体调度和线程安全状态表处理实际兼容性。

安装与首次使用

  1. 确认服务器已经安装 CraftEngine 26.7.3 和 Residence 6.0.1.8。

  2. 关闭服务器,将 PlayerMusic-1.1.5-folia.jar 放入服务器的 plugins/

  3. 启动服务器,等待生成 plugins/PlayerMusic/

  4. .mp3.ogg 文件放入 plugins/PlayerMusic/music/

  5. 站在目标领地内执行:

    /res set playermusic true
    
  6. 执行音乐库重载:

    /playermusic reload
    
  7. 如果提示资源有变化,再执行:

    /ce reload all
    
  8. 在线玩家没有收到新资源包时,执行:

    /ce feature send-pack
    
  9. 玩家站在已开启音乐功能的领地内,执行:

    /playermusic gui
    

播放规则

场景 实际行为
播放会话范围 每个 Residence 领地各自维护一套会话,不同领地互不影响
全服播放 全服会话独立于 Residence;开始、暂停、切歌和停止全服音乐都不会修改领地会话
全服与领地同时播放 两套声音使用不同声音事件,可同时存在;停止其中一个不会误停另一个
领地内现有玩家 选歌后会收到同一首歌曲的播放调用,共享列表、模式、暂停、停止和切歌状态
中途进入领地 会加入当前会话,但声音会从当前歌曲开头播放
离开领地 默认最多约 20 tick 后停止该领地的声音
关闭领地 flag 默认最多约 20 tick 后,领地内玩家停止收到该会话声音
重新选歌 替换当前领地的旧会话,先停止旧声音,再播放新歌曲
暂停后继续 会重新从当前歌曲开头播放,不能从暂停位置续播
单曲播放 当前歌曲结束后停止会话;手动“下一首”仍会立即切换
随机播放 从当前列表随机选择下一首,列表大于一首时不会连续重复同一首
顺序播放 按当前列表顺序播放,到末尾后回到第一首
收音机 从全部音乐中持续随机播放,点击后立即随机开播
收藏列表会话 开播时固定本次会话的收藏歌曲快照,之后修改收藏不会改写正在播放的队列

关于“同步进度”

PlayerMusic 同步的是领地播放会话和控制状态,不是客户端音频的精确时间轴。当前 Bukkit/CraftEngine 自定义声音播放接口可以播放或停止声音,但不能让服务器指定“从歌曲第 N 秒开始”。因此:

  • 同一时间已经在领地中的玩家会接近同时开始播放。
  • 中途进入的玩家会从这首歌的开头开始,而不是追到其他玩家的当前秒数。
  • 暂停后继续会重新播放当前歌曲,而不是从暂停位置恢复。
  • 服务器仍按公共会话的歌曲时长统一决定何时切换下一首。

GUI 操作

GUI 固定为 54 格,歌曲区域每页最多显示 36 首。

歌曲操作

  • 左键歌曲: 在当前领地播放该歌曲。
  • 右键歌曲: 加入收藏或取消收藏。
  • 歌曲 Lore 会显示时长、当前列表、播放状态、收藏状态和操作提示。
  • 当前歌曲、列表和播放模式会使用附魔光效高亮。

列表与模式

选项 说明
全部音乐 显示音乐库中的全部歌曲
我的收藏 只显示当前玩家收藏的歌曲
收音机 从全部音乐中持续随机播放
单曲播放 当前歌曲自然结束后停止
随机播放 随机选择下一首,避免连续重复
顺序播放 按列表顺序循环播放

底栏还提供页码、上一页、下一页、暂停/继续、停止、下一首和关闭按钮。点击“个人音乐音量”可调节音量:左键增加 10%,右键减少 10%,Shift+点击恢复 100%。调整只影响当前玩家,并保存到当前数据库;正在播放的声音会按新音量从头重播。

命令

主命令别名:/pmusic/musicbox

命令 执行者 权限 说明
/playermusic 玩家 playermusic.use 不带参数时等同于打开 GUI
/playermusic gui 玩家 playermusic.use 在当前已启用的领地打开音乐盒 GUI
/playermusic stop 玩家 playermusic.use 停止玩家当前所在领地的公共播放会话
/playermusic stop 控制台 控制台 停止服务器中的全服与全部领地播放会话
/playermusic global 玩家 playermusic.global 打开全服播放 GUI,不要求位于 Residence 领地
/playermusic global stop 玩家或控制台 playermusic.global 只停止全服播放,不停止任何领地音乐
/playermusic reload 玩家或控制台 playermusic.admin 重载配置、消息、数据库和音乐资源

执行 /playermusic reload 时会关闭已打开的音乐 GUI,并停止现有播放会话。重载过程使用全局互斥锁;已有重载任务运行时,新的请求会收到“正在重载”提示,不会重复转换。

权限

权限节点 默认值 包含功能
playermusic.use 所有玩家 打开 GUI、选歌、收藏、切换模式、暂停、继续、停止当前领地和切歌
playermusic.admin 仅 OP 执行 /playermusic reload
playermusic.global 仅 OP 打开全服 GUI 并控制全服播放、暂停、切歌和停止

权限节点只控制 PlayerMusic 自己的命令和 GUI。普通 playermusic flag 已向 Residence 默认组开放;顶级 playermusicpriority flag 仍要求 Residence 管理员权限。

LuckPerms 示例:

# 允许默认玩家使用音乐盒
/lp group default permission set playermusic.use true

# 禁止某个组使用音乐盒
/lp group muted permission set playermusic.use false

# 允许管理员热重载插件
/lp group admin permission set playermusic.admin true

# 允许管理员控制全服音乐
/lp group admin permission set playermusic.global true

PlayerMusic 只允许普通玩家修改自己领地的普通音乐 flag,不会授予 /resadmin 或顶级 flag 权限。

Residence 设置

PlayerMusic 注册两个默认关闭的 Residence flag:普通 playermusic 与顶级 playermusicpriority

# 普通领地主开启/关闭普通音乐
/res set playermusic true
/res set playermusic false

# Residence 管理员开启/关闭顶级音乐
/resadmin set playermusicpriority true
/resadmin set playermusicpriority false
  • 默认组可使用 /res set playermusic,但不能设置 playermusicpriority
  • 顶级 flag 只通过 Residence 管理权限设置;同一位置存在顶级与普通 flag 时,顶级优先。
  • 子领地与父领地按继承层级解析:最近的显式设置生效,生效的顶级领地覆盖普通领地。
  • 两种 flag 都未开启时不能打开领地 GUI 或开始播放。
  • 玩家离开已开启的领地后会停止听到该领地声音。
  • 每个领地的播放会话互相独立。
  • 修改 config.yml 中的 residence-flag 后必须重启服务器,不能只执行热重载。

音乐导入与资源生成

支持格式

  • .mp3:通过 FFmpeg 转换为 OGG Vorbis。
  • .ogg:直接复制到 CraftEngine 资源包。
  • 只扫描 music/ 目录第一层,不递归扫描子目录。
  • GUI 显示名称取自文件名,并移除扩展名。

示例:

plugins/PlayerMusic/music/
├─ 夜空中最亮的星.mp3
├─ Summer.ogg
└─ 大厅背景音乐.mp3

增量重载

插件使用 music-cache.yml 保存源文件 SHA-256、转换结果 SHA-256、时长和转换参数:

  • 未变化的歌曲直接复用旧 OGG,不再次调用 FFmpeg。
  • 整个音乐目录都未变化时,跳过 CraftEngine 资源重建。
  • 提示“音乐文件没有变化”时,不需要执行 /ce reload all
  • 新增、修改或删除歌曲后,需要执行 /ce reload all
  • music-index.yml 固定“源文件名 -> 声音 ID”,避免歌曲增删后收藏 ID 无故变化。
  • 重载失败时保留上一版可用的 CraftEngine 资源,不用损坏的新文件覆盖旧包。

生成位置默认为:

plugins/CraftEngine/resources/playermusic/
├─ pack.yml
├─ configuration/sounds.yml
└─ resourcepack/assets/playermusic/sounds/*.ogg

请勿直接修改自动生成的 playermusic 资源目录;源音乐应统一放在 plugins/PlayerMusic/music/

FFmpeg

默认配置:

ffmpeg-command: bundled
ffmpeg-timeout-seconds: 120
ffmpeg-bitrate-kbps: 96

bundled 会在首次需要转换 MP3 时释放插件内置的 FFmpeg。ffmpeg-bitrate-kbps 控制 MP3 转 OGG 的目标码率,默认 96kbps;降低它可以减小资源包,提高它会增加音质和体积。旧配置值 ffmpeg 也会自动使用内置版本。需要使用自定义版本时,可填写 PATH 中的命令或绝对路径:

ffmpeg-command: "D:/tools/ffmpeg/bin/ffmpeg.exe"

内置程序目前支持 Windows x64 和 Linux x64。其他操作系统或 CPU 架构必须提供外部 FFmpeg。

配置说明

默认配置位于 plugins/PlayerMusic/config.yml,所有选项都带中文注释。

配置项 默认值 热重载 说明
residence-flag playermusic Residence 自定义 flag,修改后必须重启
priority-residence-flag playermusicpriority 顶级 Residence flag,修改后必须重启
player-data-key name 收藏使用玩家名或 UUID,修改后必须重启
database.type sqlite 可选 sqlitemysql
database.table-prefix playermusic_ 仅允许字母、数字、下划线,长度 1-32
craftengine-resources plugins/CraftEngine/resources CraftEngine 资源根目录
music-directory music 相对于插件数据目录的音乐源目录
ffmpeg-command bundled 内置命令、PATH 命令或绝对路径
ffmpeg-timeout-seconds 120 单首 MP3 转换超时秒数,最小为 1
ffmpeg-bitrate-kbps 96 MP3 转 OGG 的目标码率,范围 32-320;越低资源包越小
fallback-duration-seconds 180 无法读取 OGG 时长时使用的回退时长
volume 1.0 服务器总音量;最终音量为总音量 × 玩家个人音量
sound-category RECORDS Bukkit 声音分类,默认对应唱片机/唱片音量
actionbar true 是否在动作栏显示播放状态
start-delay-ticks 1 开始播放前延迟,最小 1 tick
residence-check-interval-ticks 20 玩家范围和 flag 复查周期,最小 1 tick
gui-title <dark_gray>领地音乐盒 支持 MiniMessage
page-size 36 每页歌曲数,范围 1-36

messages.yml 也会随 /playermusic reload 重新读取,支持 MiniMessage。动态歌曲名通过安全组件占位符插入,不会被当作 MiniMessage 标签解析。

数据库

收藏数据支持 SQLite 和 MySQL,JAR 已包含两种 JDBC 驱动。

SQLite(默认)

database:
  type: sqlite
  table-prefix: playermusic_
  sqlite:
    file: favorites.db

默认数据库文件为 plugins/PlayerMusic/favorites.db,适合单服直接使用。

MySQL

database:
  type: mysql
  table-prefix: playermusic_
  mysql:
    host: localhost
    port: 3306
    database: playermusic
    username: root
    password: "请修改为真实密码"
    use-ssl: false

修改数据库配置后执行 /playermusic reload 即可热切换。需要注意:

  • SQLite 与 MySQL 之间不会自动迁移收藏数据。
  • 切换成功后,新收藏读写进入新数据库。
  • 切换失败时会保留旧连接或暂时禁用收藏,并在控制台输出错误。
  • 不要把包含真实 MySQL 密码的服务器配置提交到公开仓库。

玩家数据标识

player-data-key: name
  • name:按玩家名保存,适合离线服,默认使用此模式。
  • uuid:按 UUID 保存,适合正版服或 UUID 稳定的服务器。
  • 修改该值后必须重启服务器,旧标识数据不会自动迁移。

文件目录

plugins/PlayerMusic/
├─ config.yml          # 主配置,带中文注释
├─ messages.yml        # MiniMessage 消息配置
├─ favorites.db        # 默认 SQLite 收藏数据库
├─ music/              # 管理员放入 MP3/OGG 的目录
├─ music-cache.yml     # 音乐增量缓存,请勿手改
├─ music-index.yml     # 稳定声音 ID 索引,请勿手改
└─ tools/              # 内置 FFmpeg 首次使用后释放到此处

从旧版升级时,插件会在区分大小写的系统上尝试把 plugins/playermusic 迁移为 plugins/PlayerMusic。升级前必须删除旧 JAR,不能让两个版本同时加载。命令、权限、CraftEngine 命名空间和 Residence flag 继续使用小写 playermusic,原有设置无需重做。

常见问题

GUI 能打开,但是没有声音

依次检查:

  1. /playermusic reload 是否成功。
  2. 资源变化后是否执行了 /ce reload all
  3. 是否执行 /ce feature send-pack 给在线玩家重新发送资源包。
  4. 客户端是否接受并成功加载服务器资源包。
  5. 客户端“唱片机/唱片”音量是否开启。
  6. sound-category 是否仍为预期分类。
  7. 当前领地是否执行了 /res set playermusic true/resadmin set playermusicpriority true

每次 reload 都会重新转换全部歌曲吗

不会。插件会对源文件和生成的 OGG 计算 SHA-256。未变化的歌曲直接复用,整个音乐目录未变化时还会跳过 CraftEngine 资源重建。

什么情况下需要执行 /ce reload all

  • 新增歌曲:需要。
  • 修改歌曲内容:需要。
  • 删除歌曲:需要。
  • 只修改数据库、GUI 标题、消息、音量等配置:不需要。
  • 重载提示“音乐文件没有变化”:不需要。

为什么后进入领地的玩家进度不同

CraftEngine 最终仍通过客户端声音接口播放 OGG。该接口没有“从指定秒数开始”参数,所以后进入的玩家只能从当前歌曲开头播放。插件可以同步切歌和停止,但不能让客户端跳转到相同音频位置。

MP3 转换提示 FFmpeg 错误

  • 保持 ffmpeg-command: bundled,让插件使用内置版本。
  • 确认操作系统为 Windows/Linux x64。
  • 其他平台请安装 FFmpeg,并在配置中填写绝对路径。
  • 资源包过大时可降低 ffmpeg-bitrate-kbps 后重新执行 /playermusic reload

数据库切换后收藏不见了

SQLite 和 MySQL 是两套独立数据源,插件不会自动迁移。切回原数据库仍可读取原数据;需要迁移时应由管理员自行处理数据库记录。

提示需要重启服务器

residence-flagpriority-residence-flagplayer-data-key 发生变化时不能热应用。恢复原值后再次重载,或者完整重启服务器。

构建

项目不提交 Residence 第三方 JAR。构建时必须显式指定 Residence 6.0.1.8:

gradlew clean test build -PresidenceJar=D:\path\to\Residence6.0.1.8.jar

构建产物:

build/libs/PlayerMusic-1.1.5-folia.jar

最终 JAR 包含 MySQL、SQLite JDBC 驱动,以及 JAVE2 3.5.0 提供的 Windows/Linux x64 FFmpeg 4.4.1 原生程序。

开源许可

PlayerMusic 使用 GNU GPL v3.0 开源。

最终 JAR 通过 JAVE2 3.5.0 携带 FFmpeg 4.4.1 Windows/Linux x64 原生程序。JAVE2 原生包和该 FFmpeg 构建均按 GPL v3.0 分发,与本项目许可证保持一致。

About

基于 CraftEngine 与 Residence 的 Luminol/Folia 1.21.11 领地公共音乐盒插件,支持 MP3/OGG、收音机、收藏和 SQLite/MySQL。

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages