条件视频

条件视频

当检测到特定的游戏内事件时,播放自定义视频。它专为策划的游戏体验而设计,如服务器、故事地图、任务包和角色扮演设置,在这些场景中,电影化的反馈可以提升沉浸感。

🎬 ConditionalVideos

为 Minecraft 设计的、由服务器感知的过场视频触发模组。只需配置一次条件,客户端即可在关键时机播放同步视频——无论是本地文件、URL 还是完整播放列表。

Modrinth 下载量 CurseForge 下载量

Fabric Forge 1.20.1 NeoForge 运行环境

Wiki 文档 问题反馈


✨ 概述

ConditionalVideos 会在检测到特定游戏内事件时播放自定义视频——包括首次加入、死亡、击杀、进度完成、物品里程碑、计分板阈值等等。

它可在客户端和专用服务器上运行:服务器负责检测条件并告知对应客户端播放内容,而客户端则负责实际播放。这使得它非常适合服务器、剧情地图、任务整合包以及角色扮演场景,在这些场景中,过场反馈能显著提升沉浸感。

核心亮点

  • 超过十种触发类型,从 firstJoin 到计分板阈值以及模组自定义条件。
  • 每种条件均可设置播放列表,支持淡入淡出/硬切转场、循环播放、文字叠加、每条片段独立音量以及定时切换。
  • 通过 WATERMeDIA 实现广泛的视频源支持——本地文件、直接 URL、高质量 YouTube 视频、Twitch/Kick 片段、TikTok、SoundCloud 等等。
  • 内置播放队列,确保重叠的触发事件按顺序播放,而不是互相打断。
  • 为其他模组提供小型公共 API(详见项目 Wiki)。

🧩 兼容性与需求

Minecraft 版本 模组加载器 Java 版本
1.20.1 Fabric, Forge 17+
1.21.1 Fabric, NeoForge 21+
1.21.11 Fabric, NeoForge 21+
26.1.2 Fabric, NeoForge 25+
26.2 Fabric, NeoForge 25+

在 26.2 版本中,游戏可使用任一渲染器运行。视频在两种渲染器下均可播放,但对 Vulkan 渲染器的支持尚处于实验阶段——Minecraft 将其作为可选的预览功能提供,因此如果遇到问题,OpenGL 仍然是最安全的选择。

必需依赖(客户端):

配置文件:

  • config/conditionalvideos.json — 客户端 / 单人游戏规则
  • config/conditionalvideos-server.json — 专用服务器的权威规则
  • config/conditionalvideos-common.json — 客户端播放行为(服务器也会读取其中同步的选项)

在多人游戏中,由专用服务器掌控配置,并自动将任何本地视频文件发送给客户端(在重连时会缓存并复用),而 URL 则由每个客户端直接流式播放。请将 conditionalvideos-server.json 视为服务器内容的唯一权威来源。


🎯 支持的条件

每个条件都通过一个播放列表进行配置。简单条件使用单个配置键;带键条件则是 id → condition 的映射。

简单条件(单键):

  • firstJoin — 当玩家进入世界/会话时播放。始终优先:如果世界加载期间其他条件也被触发,firstJoin 会先播放,其余条件则在队列中等待。
  • playerDeath — 任何死亡事件的默认过场视频。
  • totemUsed — 不死图腾救下玩家时触发。
  • bedSleep — 玩家开始在床上睡觉时触发。

带键条件(id → condition 映射):

  • deathByEntity — 被特定击杀者实体 ID 杀死时触发(会覆盖 playerDeath)。
  • entityKilled — 玩家击败了配置的实体 ID 时触发。
  • advancementCompleted — 完成了配置的进度时触发。
  • dimensionChanged — 玩家进入配置的维度时触发。
  • itemObtained — 玩家获得配置的物品时触发(拾取、合成或熔炼产物)。
  • itemCrafted — 实际合成了配置的物品时触发(独立于 itemObtained)。
  • recipeUnlocked — 配方书中新解锁了配置的配方时触发。
  • scoreboard — 玩家在某个计分板目标上的分数满足比较条件时触发(见下文)。
  • custom — 无内置检测器;仅由公共 API 或 play 命令触发。

计分板比较器

每个 scoreboard 条目都会使用 comparator 将玩家的分数与 value 进行比较:

comparator 值 触发条件
equal score == value
less score < value
greater score > value
lessOrEqual score <= value
greaterOrEqual score >= value(默认值)

它是边沿触发的:一个满足条件的比较只会触发一次,并且只有在条件变为假并再次变回真后才会重新武装。由于分数会随世界持久化保存,因此如果在退出登录前比较条件已经满足,重新加入时不会再次触发。


🗂️ 配置 conditionalvideos.json

每个条件条目在 videos: [...] 下包含一个播放列表,外加一些共享标志。每个 videos 数组中的项目都是一个 VideoEntry,用于描述单个视频片段及其叠加、跳过、循环和转场选项。只有 firstJoin 预配置了内容;其他所有条件在您添加视频之前都是空的 {}。

共享条件字段

属性 类型 必填 描述
repeatableInSameSession boolean 是 若为 false,该条件每次会话只能触发一次。若为 true,则可重复触发。
playlistLoop boolean 否 若为 true,播放列表在最后一个条目播放完毕后会从第一个条目重新开始。默认 false。
videos VideoEntry[] 是 一个或多个按顺序播放的条目。长度为 1 时等同于单视频设置。

scoreboard 条目会在条件层级添加两个字段:value(int,必填——阈值)和 comparator(string,可选——默认为 greaterOrEqual)。

VideoEntry 字段

属性 类型 必填 描述
source string 是 本地视频文件的路径(相对于游戏目录或绝对路径)或 URL(http://、https://、YouTube 链接)。
skippable boolean 否 若为 true,用户可以跳过播放。默认 true。当 videoLoop = true 时强制为 true。
videoLoop boolean 否 若为 true,该条目将无缝循环播放直至被跳过。默认 false。要求 skippable = true。
enableBackground boolean 否 在视频后方绘制纯色全屏背景。默认 true。
colorBackground string 否 十六进制颜色,格式为 #RRGGBB 或 #AARRGGBB。默认 #000000。
videoTitle string 否 可选的标题叠加。支持旧版格式代码(&6、&l、&r 等)。
videoTitlePosition string 否 topLeft、topRight、bottomLeft、bottomRight。默认 bottomLeft。
videoDescription string 否 可选的描述叠加。支持旧版格式代码。
videoDescriptionPosition string 否 topLeft、topRight、bottomLeft、bottomRight。默认 bottomLeft。
titleTextScale float 否 应用于标题字体的缩放倍数。默认 1.0。
descriptionTextScale float 否 应用于描述字体的缩放倍数。默认 1.0。
textBoxOpacity float 否 标题/描述后方文本框的不透明度,取值 0.0–1.0。省略则使用旧版的自动透明度。
videoVolume float 否 此条目的音量,取值 0.0–1.0。默认 1.0。
transition string 否 从上一个条目进入此条目时应用的转场效果。可为 cut(默认)或 fadeOut/In。对第一个条目无效。
nextAt float 否 (自从此条目开始播放算起的)秒数,到达该时间后切换到/转场至下一个条目。省略则等待视频自然结束。

transition 是传入条目的属性:如果 videos[1].transition = "fadeOut/In",则播放器会将 videos[0] 淡出,同时将 videos[1] 淡入。 cut 则是指瞬间、帧完美的切换。

示例

{
  "configVersion": 3,
  "firstJoin": {
    "repeatableInSameSession": false,
    "playlistLoop": false,
    "videos": [
      {
        "source": "videos/intro_part1.mp4",
        "skippable": true,
        "enableBackground": true,
        "colorBackground": "#FF000000",
        "videoTitle": "&6&l欢迎",
        "videoTitlePosition": "topLeft",
        "videoDescription": "&f祝您旅途愉快",
        "videoDescriptionPosition": "topLeft",
        "titleTextScale": 1.4,
        "textBoxOpacity": 0.5,
        "videoVolume": 0.8,
        "nextAt": 8.0
      },
      {
        "source": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "skippable": true,
        "videoVolume": 1.0,
        "transition": "fadeOut/In"
      }
    ]
  },
  "playerDeath": {
    "repeatableInSameSession": true,
    "videos": [
      { "source": "videos/death/default_death.mp4", "videoTitle": "&c你死了" }
    ]
  },
  "totemUsed": {
    "repeatableInSameSession": true,
    "videos": [
      { "source": "videos/totem.mp4", "videoTitle": "&e被图腾救了一命" }
    ]
  },
  "bedSleep": {},
  "entityKilled": {
    "minecraft:warden": {
      "repeatableInSameSession": false,
      "videos": [
        { "source": "videos/kills/warden.mp4", "skippable": false, "videoTitle": "&5&l史诗胜利" }
      ]
    }
  },
  "deathByEntity": {
    "minecraft:creeper": {
      "repeatableInSameSession": false,
      "videos": [
        { "source": "videos/death/creeper_death.mp4", "videoTitle": "&a轰隆…" }
      ]
    }
  },
  "advancementCompleted": {
    "minecraft:story/mine_diamond": {
      "repeatableInSameSession": false,
      "videos": [
        { "source": "videos/advancements/diamond.mp4", "videoTitle": "&b钻石!" }
      ]
    }
  },
  "dimensionChanged": {
    "minecraft:the_nether": {
      "repeatableInSameSession": true,
      "playlistLoop": true,
      "videos": [
        { "source": "videos/dimensions/nether_loop.mp4", "videoLoop": true, "videoTitle": "&c进入了下界" }
      ]
    }
  },
  "itemObtained": {
    "minecraft:diamond": {
      "repeatableInSameSession": false,
      "videos": [
        { "source": "videos/items/first_diamond.mp4", "videoTitle": "&b第一颗钻石" }
      ]
    }
  },
  "itemCrafted": {
    "minecraft:crafting_table": {
      "repeatableInSameSession": false,
      "videos": [
        { "source": "videos/items/first_table.mp4", "videoTitle": "&6工作台" }
      ]
    }
  },
  "recipeUnlocked": {
    "minecraft:furnace": {
      "repeatableInSameSession": false,
      "videos": [
        { "source": "videos/recipes/furnace.mp4", "videoTitle": "&7熔炉已解锁" }
      ]
    }
  },
  "scoreboard": {
    "kills": {
      "repeatableInSameSession": false,
      "value": 100,
      "comparator": "greaterOrEqual",
      "videos": [
        { "source": "videos/scoreboard/100_kills.mp4", "videoTitle": "&c击杀数达到100!" }
      ]
    }
  },
  "custom": {},
  "consumedConditionSessions": []
}

配置安全性:单个格式错误的条目绝不会导致文件被清空。条目的解析是宽松的——错误的条目会被跳过并记录日志,而所有有效的条目都会保留。如果出现 JSON 语法错误,文件将保持原样,并且仅当次会话在内存中使用默认值,因此您可以修复拼写错误而不会丢失配置。


⚙️ 通用配置(conditionalvideos-common.json)

控制客户端播放行为。会自动创建并使用安全默认值。

属性 类型 默认值 描述
videoQuality string AUTO AUTO 会自动选择最佳可用流。任何其他值(LOWEST、LOW、MEDIUM、HIGH、HIGHEST)都会强制使用该质量。仅对多码率源(如 YouTube 等)有效。
alwaysShowCursor boolean false 若为 true,播放界面永远不会自动隐藏鼠标光标。
allowGameSounds boolean false 若为 true,视频播放期间原版 Minecraft 音效会继续播放(默认静音)。
blockMatureContent boolean true 若为 true,包含成人内容的源会被阻止。仅客户端——服务器无法覆盖此设置。
debugLogging boolean false 若为 true,会输出详细的 [CV/...] 诊断信息。正常游玩时保持关闭;仅在排查问题时开启。

在多人游戏中,videoQuality、alwaysShowCursor 和 allowGameSounds 在服务器可用时优先使用服务器通用配置中的值;blockMatureContent 和 debugLogging 始终读取本地客户端文件中的设置。


⌨️ 游戏内控制

默认情况下,跳过键未绑定,这会回退到 ESC 键。您可以在 选项 → 控制 → Conditional Videos 下绑定一个专用按键;绑定后,该按键将成为唯一生效的跳过键,屏幕上的提示也会始终显示其名称。

  • 轻按跳过键 → 跳到播放列表的下一个条目(如果是最后一个条目,则关闭播放)。循环中的条目也会被打断。
  • 按住跳过键 → 会出现一个白色进度条填充;在进度条填满后松开即可跳过整个播放列表(关闭播放)。进度条填满时会出现“松开以跳过播放列表”的消息。在进度条填满之前松开则会取消操作,不会跳过任何内容。
  • skippable = false 会为该条目禁用以上两种操作,并隐藏跳过提示——玩家必须等待视频结束或播放列表推进。

其他行为:鼠标光标会在闲置几秒后自动隐藏(除非 alwaysShowCursor 为 true),视频播放期间原版音效会被静音(除非 allowGameSounds 为 true),并且播放过程中会隐藏游戏内的浮动通知。


🧑‍⚖️ 服务器命令

以下命令对权限等级 2 及以上的玩家(命令方块、管理员)和服务器控制台可用:

/conditionalvideos play <目标> <条件>
/conditionalvideos stop <目标>
/conditionalvideos pause <目标>
  • play 强制在每个目标上播放某个条件,忽略每会话一次的限制。 <条件> 会自动补全为至少包含一个视频的键。
  • stop 关闭当前正在进行的播放并清除待处理队列。
  • pause 切换当前视频的暂停/继续状态。

条件键对于简单条件使用裸键(firstJoin、playerDeath、totemUsed、bedSleep),对于带键条件则使用 类型/键 的形式,例如 entityKilled/minecraft:warden、advancement/minecraft:story/mine_diamond、dimension/minecraft:the_nether、scoreboard/kills、custom/my_event。

命令/API 键中的进度和维度使用 advancement/... 和 dimension/... 前缀,而配置文件 JSON 则将其存储在 advancementCompleted 和 dimensionChanged 映射下。


🌍 本地化

界面和命令文本目前提供 en_us、es_es、es_ar 和 es_mx 四种语言。如需添加更多语言,请将 <locale>.json 文件放入资源包中的 assets/conditionalvideos/lang/ 目录下。


🧰 开发者 API

其他模组可以通过 org.mateof24.conditionalvideos.api 包中一个小型、稳定的公共 API 来注册自定义条件以及触发/控制播放。