BedWars 游戏事件系统
概述
游戏事件系统(Game Event System)管理 BedWars 游戏中的定时事件链,如产矿机升级、床自毁、末影龙出没、游戏结束等。事件按配置文件中的顺序依次执行倒计时,倒计时结束后触发事件动作,然后开始下一个事件的倒计时。
核心设计原则:
- 配置驱动:所有事件数据通过 YAML 配置文件定义,不包含硬编码数值
- 模式支持:通过
mode-mapping机制为不同游戏模式加载不同事件配置 - 可扩展:新增事件类型只需实现
EventAction接口并在EventManager中注册 - 生命周期联动:事件系统随游戏启动而创建,随游戏结束而销毁
架构对标产矿机系统,采用相同的独立配置文件 + 模式映射模式。
默认事件序列
在默认的 4 队模式中,事件按以下顺序依次执行:
| 序号 | 事件 ID | 显示名 | 类型 | 倒计时 | 效果 |
|---|---|---|---|---|---|
| 1 | diamond_upgrade_2 | 钻石点II | generator_upgrade | 6 分钟 | 钻石产矿机升级为 2 级 |
| 2 | emerald_upgrade_2 | 绿宝石点II | generator_upgrade | 6 分钟 | 绿宝石产矿机升级为 2 级 |
| 3 | diamond_upgrade_3 | 钻石点III | generator_upgrade | 6 分钟 | 钻石产矿机升级为 3 级 |
| 4 | emerald_upgrade_3 | 绿宝石点III | generator_upgrade | 6 分钟 | 绿宝石产矿机升级为 3 级 |
| 5 | bed_destroy | 床自毁 | bed_destroy | 6 分钟 | 所有存活队伍的床自动破坏 |
| 6 | dragon_spawn | 末影龙出没 | dragon_spawn | 6 分钟 | 每个存活队伍出生点上方生成末影龙 |
| 7 | game_end | 游戏结束 | game_end | 6 分钟 | 强制平局结束游戏 |
每个事件的倒计时是独立计算的上文倒计时,不是从游戏开始累计。上一个事件执行完毕后才开始下一个事件的倒计时。
配置文件
目录结构
plugins/BedWars/
└── events/
└── default.yml # 默认配置(所有模式未单独指定时使用)
# 可按需添加更多模式配置,如 fast.yml配置文件在插件启动时通过 saveResource("events/default.yml", false) 自动释放。
配置文件格式
以 default.yml 为例:
# 模式映射:模式ID → 配置文件名(不含 .yml 后缀)
# 未映射的模式使用 default
mode-mapping:
4t: "default"
# fast: "fast" # 示例:快节奏模式使用 fast.yml
# 事件序列(有序列表,按顺序依次执行倒计时)
# countdown 单位:秒
# display-name-key:i18n key,用于获取显示名称
events:
- id: "diamond_upgrade_2"
display-name-key: "bedwars-event-diamond-point-2"
type: "generator_upgrade"
countdown: 360
params:
generator-type: "diamond_generator"
upgrade-level: 2
- id: "emerald_upgrade_2"
display-name-key: "bedwars-event-emerald-point-2"
type: "generator_upgrade"
countdown: 360
params:
generator-type: "emerald_generator"
upgrade-level: 2
# ... 更多事件
- id: "game_end"
display-name-key: "bedwars-event-game-end"
type: "game_end"
countdown: 360事件字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | String | 是 | 事件唯一标识符 |
display-name-key | String | 是 | i18n key,用于获取事件显示名称(非硬编码文本) |
type | String | 是 | 事件类型,对应 EventAction 实现类 |
countdown | int | 是 | 倒计时秒数,上一个事件执行后开始倒计时 |
params | Map | 否 | 扩展参数,不同事件类型有不同参数 |
模式配置映射
与产矿机系统完全相同的模式映射机制:
mode-mapping:
4t: "default" # 4 队模式使用 default.yml
fast: "fast" # fast 模式使用 fast.yml重要:mode-mapping 可以定义在任意配置文件中,系统启动时扫描 events/ 目录下所有 .yml 文件收集映射。
加载逻辑:
- 启动时扫描所有
events/*.yml,收集所有mode-mapping段 EventConfig.loadForMode(modeId)查找已收集的映射- 找到映射 → 加载对应文件;未找到 → 使用
default - 配置文件不存在 → 自动降级到
default - 已加载的配置会被缓存,不会重复解析
核心类
包结构
cn.enderrealm.bedwars.game.event/
├── EventConfig.java # 配置加载器
├── EventData.java # 事件数据模型
├── EventAction.java # 事件动作接口
├── EventScheduler.java # 事件链调度器
├── EventManager.java # 生命周期管理
├── GeneratorUpgradeAction.java # 产矿机升级
├── BedDestroyAction.java # 床自毁
├── DragonSpawnAction.java # 末影龙生成
└── GameEndAction.java # 游戏结束
cn.enderrealm.bedwars.entity/
└── DragonManager.java # 末影龙实体管理类关系图
GameMode.setupEvents()
→ new EventManager(plugin, gameManager)
→ eventManager.setupEvents()
→ config.loadForMode(modeId) // 加载配置
→ new EventScheduler(...) // 创建调度器
→ scheduler.start() // 启动倒计时链
EventScheduler.run() (每秒 tick)
→ countdownRemaining--
→ countdownRemaining <= 0?
→ eventManager.getAction(type) // 获取动作
→ action.execute(gameManager, eventData) // 执行动作
→ currentIndex++ // 切换下一个事件
→ 所有事件完成 → scheduler.cancel()
GameManager.cleanup()
→ eventManager.stop()
→ scheduler.stop()
→ action.cleanup() (所有动作)
→ DragonManager.removeAll()EventConfig
cn.enderrealm.bedwars.game.event.EventConfig事件配置管理器,从 YAML 文件动态加载事件序列。与 GeneratorConfig 同构。
| 方法 | 说明 |
|---|---|
loadForMode(modeId) | 根据模式 ID 加载对应配置文件 |
getActiveEvents() | 获取当前活跃的事件序列(只读) |
getActiveConfigName() | 当前使用的配置文件名 |
getModeMapping() | 获取模式映射表(只读) |
EventData
cn.enderrealm.bedwars.game.event.EventData单个事件的纯数据模型,从配置文件加载。
| 字段/方法 | 类型 | 说明 |
|---|---|---|
id | String | 事件唯一标识 |
displayNameKey | String | i18n key(如 bedwars-event-diamond-point-2) |
type | String | 事件类型(如 generator_upgrade) |
countdown | int | 倒计时秒数 |
params | Map<String, Object> | 扩展参数 |
getStringParam(key) | String | 获取字符串参数 |
getIntParam(key, default) | int | 获取整数参数 |
EventAction
cn.enderrealm.bedwars.game.event.EventAction (接口)事件动作接口,每种事件类型实现此接口。
| 方法 | 说明 |
|---|---|
execute(GameManager, EventData) | 执行事件逻辑 |
cleanup() | 游戏结束时清理资源 |
EventScheduler
cn.enderrealm.bedwars.game.event.EventScheduler事件链调度器,继承 BukkitRunnable,每秒 tick 一次管理倒计时。
| 方法 | 说明 |
|---|---|
start() | 启动调度器,开始第一个事件的倒计时 |
stop() | 停止调度器,取消所有倒计时 |
getCurrentEvent() | 获取当前倒计时中的事件 |
getCurrentEventIndex() | 当前事件索引,-1 表示未开始或已结束 |
getCountdownRemaining() | 当前事件剩余秒数 |
getCurrentEventId() | 当前事件 ID |
getCurrentEventNameKey() | 当前事件显示名 i18n key |
isRunning() | 调度器是否运行中 |
getCurrentEvent()、getCountdownRemaining()等查询方法设计为供外部系统(如计分板、Sidebar)调用,事件系统本身不做倒计时广播。
EventManager
cn.enderrealm.bedwars.game.event.EventManager事件生命周期管理器,等价于产矿机系统中的 GeneratorManager。
| 方法 | 说明 |
|---|---|
setupEvents() | 初始化并启动事件系统 |
stop() | 停止并清理事件系统(游戏结束时调用) |
registerAction(type, action) | 注册事件类型 |
getAction(type) | 获取事件动作实现 |
getCurrentEvent() | 代理给调度器的查询方法 |
getCountdownRemaining() | 代理给调度器的查询方法 |
内置注册的事件类型:
| type | 实现类 | 说明 |
|---|---|---|
generator_upgrade | GeneratorUpgradeAction | 产矿机升级 |
bed_destroy | BedDestroyAction | 床自毁 |
dragon_spawn | DragonSpawnAction | 末影龙生成 |
game_end | GameEndAction | 游戏结束 |
事件类型详解
产矿机升级 (generator_upgrade)
调用现有的 GeneratorManager.upgradeAllByType() 方法升级指定类型的所有产矿机。
| 参数 | 类型 | 说明 |
|---|---|---|
generator-type | String | 产矿机类型,如 "diamond_generator"、"emerald_generator" |
upgrade-level | int | 目标等级,如 2 或 3 |
// 等效于
gameManager.getGeneratorManager().upgradeAllByType("diamond_generator", 2);床自毁 (bed_destroy)
强制破坏所有存活队伍的床,触发与手动破坏相同的正反馈效果:
- 移除床方块:检查床位置的方块,设置 AIR
- 更新状态:
gameManager.breakBed(teamId) - 正反馈:对每个玩家发送与
BedBreakTask完全相同的 Title、Sound、Chat 消息- 己方:红色 Title + 凋零声音
- 敌方:队伍名 Title + 末影龙嘶吼声音
- 额外全局通知:发送
bedwars-event-bed-auto-destroy消息通知全房间
与玩家手动破坏的唯一区别:没有"破坏者",反馈中不包含玩家名信息。
末影龙生成 (dragon_spawn)
在每个存活队伍的出生点 Y+20 位置生成末影龙。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
level | int | 1 | 每队生成的龙数量 |
末影龙行为:
- 持续飞行:默认
Phase.CIRCLING,不主动攻击玩家 - 定时冲撞:每 15 秒短暂切换到
Phase.CHARGE_PLAYER,3 秒后恢复盘旋 - 偏向建筑物:冲撞行为使龙周期性靠近建筑
- 方块破坏:监听
EntityExplodeEvent,仅处理被追踪的龙- 20% 方块 →
FallingBlock(向四周喷射,5 秒后自动移除) - 80% 方块 → 直接消失(不掉落物)
- 20% 方块 →
DragonManager 提供 upgradeDragonLevel() 公开 API,预留给未来商店系统调用,可以给队伍增加额外的龙。
游戏结束 (game_end)
触发平局结束逻辑,与 GameCheckTask 的流程相同:
- 检查
gameManager.isGameEnding()→ 如果已经结束则跳过(防止重复触发) - 设置
gameManager.setGameEnding(true) - 取消所有重生任务
- 执行
new GameEndTask(plugin, gameManager, true, null).runTask(plugin)(平局)
如果游戏在事件序列中途因 GameCheckTask 自然结束(只剩 1 队),事件系统会随
GameManager.cleanup()被销毁,后续事件不会执行。
末影龙管理器
DragonManager
cn.enderrealm.bedwars.entity.DragonManager末影龙实体管理器,独立于事件系统所在的包(位于 entity 包下)。
| 方法 | 说明 |
|---|---|
spawnDragon(loc, teamId) | 在指定位置生成末影龙,返回龙实体 |
upgradeDragonLevel(gm, newLevel) | 升级每队龙数量(API,预留给商店系统) |
isTrackedDragon(entity) | 检查实体是否为被追踪的末影龙 |
removeAll() | 清除所有龙实体 |
cleanup() | 清理资源(移除龙 + 注销监听器) |
getDragonCount() | 当前存活龙数量 |
getCurrentLevel() | 当前龙等级 |
游戏流程中的事件系统
生命周期
游戏开始
→ GameInitTask 步骤 8
→ GameMode.setupEvents(gameManager) ← 模式钩子
→ 默认: new EventManager(plugin, gm)
→ eventManager.setupEvents()
→ config.loadForMode(modeId) // 加载事件配置
→ scheduler.start() // 开始倒计时链
游戏进行中
→ EventScheduler 每秒 tick
→ 倒计时归零 → 执行 EventAction.execute()
→ 所有事件完成 → scheduler 自动结束
任意时刻游戏自然结束(GameCheckTask 检测到 ≤1 队存活)
→ GameManager.cleanup()
→ eventManager.stop()
→ scheduler.cancel()
→ 所有 EventAction.cleanup()
→ DragonManager.removeAll() // 移除所有末影龙启动时机
事件系统在游戏初始化任务链的第 8 步启动(在 initGameData() 之前),确保玩家位置、产矿机、游戏状态均已完成设置。
GameInitTask 执行顺序:
1. LoadTeamLocationsTask [异步]
2. AssignTeamsTask [异步]
3. SetupPlayerTeamsTask [同步]
4. InitTeamBedsTask [同步]
5. TeleportPlayersTask [同步]
6. setupGenerators + setupShops [同步]
7. onGameStart [同步]
8. setupEvents [同步] ← 事件系统在此启动
9. initGameData [同步]i18n Keys
所有事件显示名称通过 display-name-key 引用 i18n key,不在代码中硬编码文本。
| Key | 中文 | English |
|---|---|---|
bedwars-event-diamond-point-2 | §b钻石点II | §bDiamond Point II |
bedwars-event-diamond-point-3 | §b钻石点III | §bDiamond Point III |
bedwars-event-emerald-point-2 | §a绿宝石点II | §aEmerald Point II |
bedwars-event-emerald-point-3 | §a绿宝石点III | §aEmerald Point III |
bedwars-event-bed-self-destruct | §c床自毁 | §cBed Self-Destruct |
bedwars-event-dragon-spawn | §5末影龙出没 | §5Dragon Incoming |
bedwars-event-game-end | §c游戏结束 | §cGame End |
bedwars-event-bed-auto-destroy | §c所有队伍的床已自动毁灭! | §cAll beds have been automatically destroyed! |
bedwars-event-dragon-name | §5末影龙 | §5Ender Dragon |
扩展指南
添加新事件类型
- 创建
EventAction实现类:
public class MyCustomAction implements EventAction {
@Override
public void execute(GameManager gameManager, EventData eventData) {
// 事件逻辑
}
@Override
public void cleanup() {
// 清理资源
}
}- 在
EventManager.registerBuiltinActions()中注册:
registerAction("my_custom_type", new MyCustomAction());- 在配置文件中添加事件:
events:
- id: "my_custom_event"
display-name-key: "bedwars-event-my-custom"
type: "my_custom_type"
countdown: 180
params:
custom-param: "value"- 在语言文件中添加
bedwars-event-my-customkey。
添加新模式专属事件配置
- 在
events/目录下创建新配置文件(如fast.yml) - 在新配置文件中添加
mode-mapping段:
# fast.yml
mode-mapping:
fast: "fast"
events:
- id: "diamond_upgrade_2"
display-name-key: "bedwars-event-diamond-point-2"
type: "generator_upgrade"
countdown: 180 # 更快的节奏
params:
generator-type: "diamond_generator"
upgrade-level: 2
# ...- 系统启动时会自动扫描所有配置文件,收集
mode-mapping - 无需修改代码
通过 GameMode 钩子定制事件
模式可以覆写 setupEvents() 来自定义事件行为:
public class CustomMode extends GameMode {
// ...
@Override
public void setupEvents(GameManager gm) {
BedWars plugin = gm.getPlugin();
EventManager eventManager = new EventManager(plugin, gm);
// 注册自定义事件类型
eventManager.registerAction("my_custom_type", new MyCustomAction());
eventManager.setupEvents();
gm.setEventManager(eventManager);
}
}外部系统获取事件信息
计分板或 Sidebar 可以通过 EventManager 的查询方法获取当前事件状态:
EventManager eventManager = gameManager.getEventManager();
if (eventManager != null) {
EventData current = eventManager.getCurrentEvent();
int remaining = eventManager.getCountdownRemaining();
if (current != null) {
String nameKey = current.getDisplayNameKey();
String displayName = plugin.getLanguageManager().getText(nameKey, player);
// 显示: "下一次事件: 钻石点II (还有 120 秒)"
}
}