跳到主要内容

玩家伪装

FreeMinecraftModels 可以将任何在线玩家伪装为已加载的模型。伪装由命令、公共 DisguiseAPI 以及每位玩家对应的 PlayerDisguiseEntity 共同驱动,后者负责处理被伪装玩家的不可见性与模型渲染。

命令

命令权限说明
/fmm disguise <modelID>freeminecraftmodels.disguise.self伪装发送者。仅限玩家
/fmm disguise <modelID> <player>freeminecraftmodels.disguise.others伪装指定玩家。可从控制台执行
/fmm undisguisefreeminecraftmodels.disguise.self解除发送者的伪装。仅限玩家
/fmm undisguise <player>freeminecraftmodels.disguise.others解除指定玩家的伪装。可从控制台执行
/fmm disguiselistfreeminecraftmodels.disguise.others列出所有处于伪装中的玩家及各自的伪装模型

通配符 freeminecraftmodels.* 在 OP 默认下授予 admindeletealldisguise.selfdisguise.others。它同时也授予单独注册的 freeminecraftmodels.bypassregionprotection 权限。

行为

  • 对已经伪装的玩家执行伪装时,会干净地替换之前的伪装 —— 无需先解除伪装。
  • 被伪装的玩家对其他玩家保持不可见,因此只看得到模型。被伪装的玩家自己仍能正常看到自己。
  • 不可见效果在喝牛奶、/effect clear、信标效果清除、死亡与重生,以及任何其他通常会清除效果的交互或插件之后仍会持续(DisguiseEffectListener 会在下一刻重新施加)。
  • 玩家的碰撞箱保持不变。怪物的目标选定、碰撞与 PvP 都照常工作。
  • 伪装不会在服务器重启、/fmm reload 或玩家退出后保留 —— 它们只在内存中追踪,DisguiseListeners.onQuit 处理器会在 PlayerQuitEvent 时移除伪装。死亡与切换世界不会解除玩家的伪装。
  • 执行 /fmm reload 时,所有活动伪装会作为插件关闭流程的一部分被销毁。重载后玩家需要重新被伪装。

伪装动画

伪装不会使用普通模型化实体的动画状态机。每个伪装都有自己的控制器,它每 tick 读取被伪装的玩家,并按名称挑选一个动画。

它识别五个保留的动画名称,按以下优先级顺序(从高到低):

优先级动画类型触发条件
1attack一次性玩家挥动手臂
2jump一次性玩家向上离开地面
3sneak循环玩家正在潜行
4walk循环玩家自上一 tick 起移动超过约 0.01 格
5idle循环以上都不适用时

值得了解的行为:

  • 只有模型实际拥有的动画才会被考虑。没有 sneak 动画的模型会直接落到 walkidle

  • 一次性动画会中断当前的循环,并在固定的 **20 tick(1 秒)**内压制优先级更低的动画。动画系统不提供完成回调,所以这只是一个假定的上限而非真实长度 —— 如果你希望干净地交接回循环,请把 attackjump 动画控制在一秒以内。

  • 只有当选中的动画确实发生变化时才会重新下发循环,因此稳定的行走不会每 tick 被重启。

  • 与常规模型化实体上(当前处于失效状态的)jump 状态不同,jump 在伪装中是真正接上了线的。参见动画

  • 没有 idle 动画的伪装模型,每次伪装时都会记录一条警告:

    Disguise model '<model>' has no 'idle' animation — disguised players using this model will freeze on the last animation frame whenever no other action is active.

    请为任何打算用作伪装的模型附带一个 idle 动画。

基岩版客户端

伪装依赖 FMM 渲染自定义模型。config.ymlsendCustomModelsToBedrockClientsV2: true 是默认值,因此向基岩版发送模型的功能开箱即用;如果你将其设为 false(或沿用了较旧的 sendCustomModelsToBedrockClients: false),基岩版玩家既看不到模型也看不到底层的不可见玩家 —— 在被伪装玩家所站的位置,他们什么也看不到。即便开关处于开启状态,仍然需要基岩版兼容的资源包链路(Floodgate + Geyser + 转换后的资源包)才能让模型渲染出来。

DisguiseAPI

第三方插件可以通过 com.magmaguy.freeminecraftmodels.api.DisguiseAPI 以编程方式驱动伪装。

import com.magmaguy.freeminecraftmodels.api.DisguiseAPI;

// 伪装(若模型 ID 未加载则返回 false)
boolean ok = DisguiseAPI.disguise(player, "dragon");

// 解除伪装(若有伪装被移除则返回 true)
DisguiseAPI.undisguise(player);

// 查询
boolean isDisguised = DisguiseAPI.isDisguised(player);
String modelID = DisguiseAPI.getDisguiseModelID(player); // 未伪装时为 null

// 所有伪装玩家的不可修改快照
Collection<Player> all = DisguiseAPI.getDisguisedPlayers();

该 API 是公共的、对重构安全的入口。插件应调用 DisguiseAPI,而不是内部的 DisguiseManager

常见用例

  • 角色扮演与 RPG 服务器: 在电影化片段或任务脚本中将玩家伪装为 Boss 模型。
  • 活动主持: 将主持人伪装为巨大的自定义模型。
  • 坐骑与载具:/fmm mount/fmm disguise 结合,搭建创意的运输方案。
  • EliteMobs 集成: Boss 脚本可以将触发事件的玩家伪装,作为临时变身效果。

故障排查

我执行 /fmm disguise dragon 后什么都没发生。 模型 ID 必须与某个已加载模型完全匹配。请通过 /fmm admin 或该命令的 Tab 补全验证模型名称。指定目标玩家的形式会在解析模型或玩家之前先检查 freeminecraftmodels.disguise.others,并直接报告缺失的权限。

我的伪装在 /fmm reload 后消失了。 这是预期行为。所有伪装都会在重载时被销毁。如需在重载后自动重新应用伪装,请监听 FmmReloadedEvent

基岩版玩家看不到伪装。 请参阅上方的 基岩版客户端

被伪装玩家对其他人仍然可见。 不可见性是以数据包级别的效果应用的。如果有另一个插件每刻都强制移除不可见性(一些反作弊插件会这么做),它就会和 FMM 的重新应用相冲突。请将 FMM 列入白名单或禁用冲突的检查。