跳到主要内容

玩家伪装

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

命令​

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

通配符 freeminecraftmodels.* 在 OP 默认下授予 admin、deleteall、disguise.self 和 disguise.others。它同时也授予单独注册的 freeminecraftmodels.bypassregionprotection 权限。

行为​

  • 对已经伪装的玩家执行伪装时,会干净地替换之前的伪装 —— 无需先解除伪装。
  • FMM 使用 setVisibleByDefault(false) 向其他观察者隐藏玩家,并在玩家尚无隐身药水效果时添加该效果。装备显示覆盖会向其他观察者隐藏盔甲和手持物品,不改变库存。玩家自己的视角不受这些装备覆盖影响;自身身体的渲染仍取决于客户端的可见性处理。
  • FMM 会在相关效果移除或变更事件以及重生后一个 tick 重新施加隐身,但仅限于该伪装最初添加了此效果的情况。伪装开始前已有的隐身效果不会被保留或恢复。解除伪装会将默认可见性设回 true,移除 FMM 添加的效果,并重新发送玩家当前的装备。
  • 玩家加入和世界切换时,会向观察者重新发送装备隐藏信息。这不会替换玩家实际的盔甲或手持物品。
  • 玩家的碰撞箱保持不变。装饰性伪装不会创建数据包交互实体,其点击处理器也不执行操作,因此不会提供用于攻击或骑乘的独立目标。隐身仍可能影响 FMM 之外的行为,不能保证怪物的目标选择不变。
  • 伪装不会在服务器重启、/fmm reload 或玩家退出后保留 —— 它们只在内存中追踪,DisguiseListeners.onQuit 处理器会在 PlayerQuitEvent 时移除伪装。死亡与切换世界不会解除玩家的伪装。
  • 成功的 /fmm reload 会在关闭流程中销毁活动伪装,之后需要重新应用。如果重载在候选内容准备阶段被拒绝,当前运行状态会保留。

伪装动画​

每个伪装都有控制器,在模型实体共用的播放引擎运行前,根据玩家状态选择动画。它不会绕过该引擎。控制器检查动画是否存在时区分大小写,因此保留名称必须使用小写。

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

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

值得了解的行为:

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

  • 一次性动画会请求立即进行非循环播放,并在固定的 20 tick(20 TPS 下为 1 秒)内暂停所有新的选择。这只是倒计时,并非测量动画时长。较长的动画可能被下一次选择打断,较短的动画可能在选择恢复前结束。暂停期间的挥臂会合并成一次待处理攻击,跳跃状态变化则不会排队。

  • 只有当选中的动画确实发生变化时才会重新下发循环,因此稳定的行走不会每 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.yml 中的默认值 sendCustomModelsToBedrockClientsV2: true 启用基岩版模型发送。设为 false 会阻止模型到达基岩版观察者,而被伪装的玩家仍然隐身。已废弃的 sendCustomModelsToBedrockClients 键不再读取。即使 V2 已启用,客户端仍需转换后的资源包和正常工作的 Geyser/Floodgate 集成。

DisguiseAPI​

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

import com.magmaguy.freeminecraftmodels.api.DisguiseAPI;

// Disguise (returns false if the model ID is not loaded)
boolean ok = DisguiseAPI.disguise(player, "dragon");

// Undisguise (returns true if a disguise was removed)
DisguiseAPI.undisguise(player);

// Queries
boolean isDisguised = DisguiseAPI.isDisguised(player);
String modelID = DisguiseAPI.getDisguiseModelID(player); // null if not disguised

// Unmodifiable snapshot of all disguised players
Collection<Player> all = DisguiseAPI.getDisguisedPlayers();

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

API 不检查命令权限,也不规范化模型 ID。请传入在线玩家和准确的已加载 ID。disguise 会在尝试创建替代伪装之前移除现有伪装,因此未知 ID 会在移除旧伪装后返回 false。命令会先检查模型,所以无效的命令 ID 会保留旧伪装。API 返回成功仅确认创建,不确认客户端渲染或资源包接受情况。

常见用例​

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

故障排查​

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

我的伪装在 /fmm reload 后消失了。 完整重载成功后,这是预期行为。如需自动重新应用伪装,请监听 FmmReloadedEvent;它会被安排在初始化后 40 tick 于主线程执行。准备阶段被拒绝不会销毁当前运行状态。

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

被伪装玩家对其他人仍然可见。 检查玩家在伪装开始时是否已经隐身:FMM 不接管该效果,效果消失后也不会恢复。还应检查会改变玩家可见性、效果或装备数据包的插件。FMM 同时使用玩家可见性、真实药水效果和装备显示覆盖;修改其他插件设置前,先确认冲突行为。