跳到主要内容

CannonRTP(WorldCannon)

CannonRTP 是一款适用于 Minecraft 服务器的多炮台随机传送插件。"WorldCannon" 是较早的 / wiki 板块名称;插件在 Bukkit 中注册为 CannonRTP,发布为 CannonRTP.jar,这也是玩家和管理员所看到的名称。

关键命名细节:

  • 插件名称:CannonRTP
  • 根命令:/cannonrtp
  • 别名:/crtp/wc
  • 权限节点:cannonrtp.admincannonrtp.use
  • 配置文件夹:plugins/CannonRTP/

功能介绍

CannonRTP 是一个多炮台随机落点系统,而非单一固定发射器。每个已配置的炮台可以在世界中放置一处或多处,每个放置点都会监测进入其触发半径的玩家。

每个炮台都可以:

  • 通过 /wc create/wc place 多次放置 —— 一份炮台配置驱动其所有放置点
  • 监测玩家进入该炮台的触发半径(默认 1.75 格)
  • 预加载并维护一个由已配置目标世界中安全落点组成的队列(支持跨世界传送)
  • 拒绝不安全的地形、被阻挡的空间、受保护的领地以及世界边界外的位置
  • 可选地要求额外的单炮台权限节点
  • 通过五阶段的电影化序列发射玩家
  • 展示一个 FreeMinecraftModels 的 3D 动画炮台模型(通过每个炮台的 customModel 或全局优先级列表配置);若未安装 FMM 则回退为变色环绕粒子
  • 在炮台上方显示一个面向玩家的悬浮状态标签(Ready / Charging / Maintaining / Exhausted / Disabled)

发射流程

使用前,请生成或探索目标世界配置的搜索区域。CannonRTP只加载现有区块,不生成地形;未探索的搜索半径可能无法提供任何目的地。

发射序列由五阶段状态机驱动(SEARCHING -> FIRING -> TELEPORTING -> DROPPING -> LANDING)。当玩家进入符合条件的炮台触发半径时:

  1. CannonRTP 检查 cannonrtp.use
  2. 检查炮台可选的 requiredPermission
  3. 检查每位玩家的发射冷却(runtime.launchCooldownSeconds,默认 30 秒)。该限制在所有炮台之间共享,并且不会消耗已排队的目的地。
  4. 验证该炮台至少有一个已预加载的落点排队。(已禁用的炮台、位于未加载世界中的炮台以及位于未加载区块中的炮台永远走不到这一步 —— 它们被完全排除在 tick 循环之外,因此根本无法被触发。)
  5. 从该炮台队列中消耗一个预加载的安全落点。
  6. 触发 CannonRTPLaunchEvent(可取消)。如果监听器取消该事件,目的地会被退还到队列中,并且不会开始冷却。
  7. Searching 阶段(默认 42 tick,可通过 launchWarmupTicks 配置):玩家获得漂浮效果,如果启用了自定义模型则炮台播放 fire 动画,同时随机坐标预览会通过标题/副标题闪烁显示。当模型激活时,玩家还会获得隐身效果,使动画呈现更清晰。
  8. Firing 阶段(默认 45 tick,由 verticalBoostTicks 控制):移除漂浮/隐身效果,播放发射音效,生成火焰+烟雾+爆炸效果,并每 tick 施加一次 verticalBoostVelocity。真实目的地坐标此时显示。
  9. Teleporting 阶段(单 tick):已排队的目的地会被重新校验(地形柱、保护插件集成、API 监听器)。若仍然通过校验,玩家会被传送到其正上方恰好 50 格处,并施加缓降效果。空投高度永远不会被钳制 —— 落点校验器已经保证到达方块位于世界最大高度之下,而不再通过校验的目的地会取消发射并转为回收玩家。
  10. Dropping 阶段:玩家拖着烟雾尾迹下落(LARGE_SMOKE + CAMPFIRE_SIGNAL_SMOKE)。
  11. Landing 阶段:玩家一触地便进入该阶段。移除缓降效果,播放落地爆发特效(云冲击波、火焰环、尘埃过渡),并触发 CannonRTPLandingEvent。如果下落反而超过了其最大时长(slowFallingSeconds x 20 tick),CannonRTP 会回收玩家,并且不会发出落地事件。

落点安全规则

在某个位置被加入预加载队列之前,当前代码会按以下顺序进行检查:

  • 目标世界已加载(在未加载期间,炮台会停止预加载并报告 Target world <name> is not loaded.
  • 搜索中心可解析 —— 优先使用配置的 searchCenter,其次是炮台自身位置(当它位于目标世界中时),最后是目标世界的出生点
  • 候选点位于世界边界之内
  • 候选点所在的区块已加载(按需加载,不会生成新地形)
  • 候选点所在列存在最高的非空气方块
  • 落点正下方的表面方块为固体且非液体
  • 该表面方块不在已配置的不安全地面材料列表中,也不是下界的基岩顶盖
  • 落点位于世界最小高度或以上,且其上方 51 格处的到达方块仍低于世界最大高度
  • 52 格空投柱(从落点一直到到达时的头部方块)中的每一个方块都是空气或可穿过
  • 该柱中没有任何方块在已配置的不安全身体材料列表中
  • 所有启用的保护插件集成均允许该位置
  • 没有任何 CannonRTPLocationValidationEvent 监听器否决该候选点

在下界,CannonRTP 会拒绝基岩顶盖,并向下扫描寻找一个整条空投柱都安全的裸露洞穴地面。这使得下界目标成为可能,而不会把玩家投放到顶盖之上或穿过实心地形。

搜索尝试在全局范围内被限速为每 tick 一次(20 次/秒),通过轮询方式在所有活跃炮台之间公平分配。每个炮台拥有自己的超时计数器(searchTimeoutAttempts,默认 100,最小 10)。

炮台状态

每个炮台都有一个内部状态,可通过 /wc status/wc list 查看:

显示内部状态含义
Disabled--该炮台在配置中被显式禁用
ChargingSEARCHING(队列为空)仍在预加载首批安全落点
MaintainingSEARCHING(队列非空)已有部分落点,仍在补充已消耗的槽位
ReadyREADY拥有足够的预加载落点(>= chargedLocationsPerCannon)以发射玩家
ExhaustedEXHAUSTED已用尽 searchTimeoutAttempts 仍未填满储备

内部搜索状态恰好只有三个取值(READYSEARCHINGEXHAUSTED);Disabled 在查询该状态之前就已判定,而 Charging / MaintainingSEARCHING 的两种呈现方式。Ready 优先于 Exhausted —— 仍持有已充能储备的炮台即使上一个搜索窗口超时,也会显示为 Ready。

不存在单独的"配置无效"状态。当炮台的 targetWorld 无法解析时,该炮台会保留当前的搜索状态标签,而 /wc status$reason 列会变为 Target world <name> is not loaded.statusLabels.invalid 消息键确实存在于 messages.yml 中,但当前版本不会渲染它。)

只要队列中至少有一个目的地,炮台就会立即发射玩家。chargedLocationsPerCannon 阈值仅影响视觉上的 READY 标签。

运行环境要求

  • Minecraft:plugin.yml 声明 api-version: 1.21.4;当前源码树基于 Spigot 26.2-R0.1-SNAPSHOT API 构建
  • Java:21
  • 推荐服务器软件:Paper 或当前兼容的分支
  • MagmaCore:2.2.0 或更新版本(共享库,已遮蔽打包进插件)
  • 可选依赖:FreeMinecraftModels(用于 3D 动画炮台模型)

可靠性

CannonRTP 在世界和区块生命周期事件中保持其视觉效果与队列的一致性:

  • 当炮台所在区块卸载时,其标签和模型会被移除;区块重新加载时会重新生成
  • 当炮台所在世界卸载时,该炮台会被挂起;世界再次加载时会唤醒
  • 当 FreeMinecraftModels 在运行期间被启用或禁用时,模型缓存会失效,视觉效果会在下一 tick 刷新
  • 在空投传送之前,已排队的目的地会针对地形、保护插件集成和 API 监听器重新检查;如果它已变得不安全,发射流程会转为回收玩家,而不是照旧使用过期坐标
  • 发射清理只会移除 CannonRTP 仍然拥有的漂浮、隐身和缓降效果,并恢复它临时替换掉的更早的效果,而不会删除其他插件更新的状态
  • 如果发射因目的地世界卸载而无法继续,CannonRTP 会将玩家回收到炮台座位或另一个已加载世界的出生点;当没有安全的回收世界可用时,会保留缓降效果

从这里开始