Kzeroko KTM2

过场场景运行时

场景所有权、触发历史、演员控制权、中途加入与客户端清理。

更新于 2026/9/26 17 分钟阅读

每个过场场景包含一条服务端时间线,以及每位观众各自的本地播放。服务端负责演员绑定、世界事件和队伍会话,客户端负责镜头采样、玩家转向与呈现;集成时必须同时释放两侧持有的状态。

它做什么

internal.scene.ServerSceneManager 是服务端内部入口,不是公共 API 门面。它启动数据包加载的定义,并将场景共享给符合条件的观众。全部制作字段见场景数据参考;独立的纯客户端动画使用镜头 API。

触发方块提供自动准入、按进度选取场景和持久重播规则。它们不保存活动时间线,也不会在服务器重启后续播被中断的场景。

运行时模型

所有者状态与更新时机
SceneDefinitionLoader当前定义表与修订号,服务端数据重载时替换;已有会话继续持有捕获的定义
ServerSceneManager以 team:<uuid> 或 player:<uuid> 为键的静态映射;在 END_SERVER_TICK 更新,并移除断线观众
ServerScenePlayback世界、枢轴、演员、观众 UUID、跳过票数、已触发事件索引和播放年龄
ScenePuppetController演员 AI/疾跑快照、指令起始标记及服务端路径跟随器
ClientSceneManager一个活动或待启动场景、退出过渡、保存的 HUD/视角与输入所有权
ClientScenePlayback演员实体 ID、本地移动跟随器、呈现事件标记与本地年龄
SceneTriggerMemoryState持久触发器/观众历史,与活动会话分开保存

服务端只解析一次演员,取得控制权后发送启动包。每个服务端刻依次移除无效观众、接纳附近的合格观众、停止空会话、更新演员、触发到期世界事件,最后增加年龄。年龄超过 lengthTicks 才停止,因此包含最后一个制作刻。

客户端在实体更新前应用移动,在实体更新后推进呈现。启动包包含当前年龄、枢轴、演员实体 ID 和重建后的定义。场景 JSON 压缩为 NBT,压缩后上限为 262144 字节,包内最多携带 64 个演员绑定。经 SceneAuthoringDraft 重建时会规范化并舍入数据,不是源 JSON 的逐字节副本。尤其是含 look_at 的镜头节点,其制作时的 rot 会在这条路径中丢失。

准入与替换

观众必须存活、非创造且非旁观、仍连接服务器,并处于场景所在世界。队伍身份来自 IsekaiCore 队伍桥接;无队伍玩家使用个人键。本仓库在队伍拥有者在线时读取其主线进度,否则读取触发玩家的进度。

观众模式初始及后续准入
TRIGGERING_PLAYER / triggering_player仅触发玩家
TEAM_NEARBY / team_nearby枢轴球形半径内符合条件的同队玩家
ALL_NEARBY / all_nearby球形范围内符合条件的任意队伍玩家

玩家演员也会加入观众,因为移动由他们自己的客户端驱动;仍需通过资格与世界检查。半径大于零时启用后续准入检查;已有观众不会仅因离开半径而被移除。非演员观众必须继续满足模式对应的身份或队伍条件;演员绕过身份限制,但不能绕过世界或资格检查。

启动场景会替换该队伍键的现有会话,并停止包含任一初始观众的其他会话。后续观众刷新和玩家演员准入不会执行同样的冲突扫描,因此不能保证每名玩家始终只属于一个会话。应避免观众或演员重叠的触发器同时启动。

isPlaying(player) 先查玩家当前队伍的会话,再查包含该观众的会话。因此,队友即使不是观众也可能返回正在播放,stop(player, ...) 也能停止该队伍会话。跳过请求另行要求实际观众身份。

触发选择与重播

isekaiexpansion:scene_trigger 方块不可见且无碰撞。可选中轮廓与主手编辑均要求创造模式及权限等级 2。放置时使用玩家的水平方向;枢轴为方块中心,朝向提供偏航。

检测范围为以配置半径作为半边长的立方体,与观众搜索使用的球形范围不同。冷却之外的每个服务端刻都会扫描合格玩家,第一个成功启动所选场景的玩家会消耗本次触发机会。规则按列表顺序检查含端点的进度区间,没有匹配项时使用默认场景。若已匹配规则引用的定义不存在,不会继续尝试后续规则或默认场景。

重播模式记忆与冷却
ONCE_PER_AUDIENCE / once_per_audience为本触发器与所选场景保存触发者的队伍/个人键
GLOBAL_ONCE / global_once为本触发器与所选场景保存 global 键
REPEATABLE / repeatable不保存持久历史;冷却至少 200 刻(10 秒)

重播范围独立于观众模式。例如,all_nearby 配合 once_per_audience 仅记录触发队伍的键,不会记录每位观众的队伍。历史在启动被接受时写入,而不是播放完成后,因此跳过或断线不会撤销记录。已关联活动会话的玩家会被触发器跳过。

冷却由整个方块共享,不按观众分别计算。配置默认值为 80 刻(4 秒),限制为 1–72000 刻(0.05–3600 秒);可重复模式则为 200–72000 刻(10–3600 秒)。剩余倒计时不保存,重载后只保留配置时长。

约定

演员与世界控制权

演员解析及指令格式见数据参考。所有已解析演员都会被接管,即使没有指令:停止生物导航、禁用 AI,并取得 NPC 大脑控制权。停止时恢复原有 AI 和非玩家疾跑状态,释放控制权,清除场景移动及忙碌状态。不会恢复位置、世界时间或天气。

快照按演员键保存,而不是按唯一实体保存。不要将多个演员键绑定到同一实体后假定它们可以独立恢复。管理器也没有通用的跨会话演员锁。

指令路径控制权与时序
指令开始服务端年龄恰好等于指定刻时触发一次;世界事件则在到期或逾期时触发一次
玩家 walk / sprint所属客户端通过 PlayerLocomotionOverride.Source.CINEMATIC 写入移动,由正常行走流程产生位置更新
非玩家 walk / sprint服务端跟随器驱动带碰撞的移动、贴地及身体/头部转向
navigation对可寻路演员请求导航至终点,不走镜头跟随器路径
其他插值移动服务端沿制作路径插值并设置演员位置,不是贴地步态
姿态/传送服务端设置位置;玩家使用网络传送
玩家动画客户端动画层;NPC 动画和身体表情仍由服务端演员操作处理

移动跟随器根据实际位置计算进度。演员被挡住时不会仅因时间经过而沿路径前进。移动审计可警告路径与时长不匹配,但不会延长指令窗口或场景时长。玩家动画的淡入时长受指令持续时间约束,不用于重定时动画片段。

世界声音与粒子使用世界广播,时间和天气会改变世界。visible_to_all 开关属于 Effek 路径,不是通用观众过滤器。停止场景会阻止后续事件,但不会回滚此前事件。

锁定、跳过投票与清理

启用 lock_input 或 lock_movement 任一项时,服务端以唯一的 cinematic_scene:<uuid> 来源禁用物品使用、攻击和跳跃。动作系统的 MOVE 标记保持未设置,以便玩家行走流程继续运行。锁定时长为剩余场景刻数加退出淡化刻数,再加 20 刻(1 秒),最少 1 刻(0.05 秒)。清理只移除此场景自己的动作锁来源。

客户端强制背后第三人称视角,可按配置隐藏 HUD,在输入锁定期间关闭界面,并在需要时应用过场移动覆盖。它保存并恢复原有视角与 HUD 设置。场景活动时会隐藏不在演员表中的玩家实体,不会隐藏所有非演员实体。

只有当前观众且 allow_esc_skip 为 true 时,跳过请求才有效。每位观众只有一票,需要所有当前观众同意。离开的观众失去投票并可能降低所需票数,中途加入者则增加票数。重复投票返回当前状态。客户端用带键的弹窗显示票数,持续 2400 ms,进入淡化为 80 ms,退出淡化为 160 ms。

进入淡化会延后本地播放,并将淡化时长加到收到的年龄上,因为服务端仍在推进。迟到客户端只预载该年龄仍有效的呈现,不会重新播放已过期字幕或完整动画。移动从玩家实际位置开始跟随。世界事件不会为迟到观众重新执行。

退出淡化停止本地时间线工作,但保留最后的镜头姿态与锁定,直到回调恢复状态。常规 stop(false) 取消待启动场景时会恢复状态,但不显式清空淡化控制器;立即替换或断线清理会清空。断线还会清除过场移动、输入、字幕和动画状态。共享的震动/扭曲控制器按全局清空,效果并不按场景所有权隔离。

启动与停止包通过客户端执行器处理,跳过与更新包通过服务端执行器处理。停止/跳过包没有场景令牌;其他调用者必须协调,不能假定过时请求可对应到某次具体播放。

字幕与客户端设置

字幕以不可变呈现快照从客户端传给非交互式 ModernUI 浮层。共享的RetainedOverlay负责挂载、卸载与原子投递,忽略连续相同的快照,挂载时立即应用最新快照。浮层保留最新待处理快照,不在 UI 线程读取配置,并独立于原版 HUD 的可见性。正文与说话人按翻译键解析,找不到翻译时显示原文。

FeatheredPlateView为过场字幕和CaptionLineView提供共用背景;NPC指令反馈通过CaptionAPI的NPC_FEEDBACK频道进入后者。背景用缓存网格连接多层圆角轮廓,在一次绘制中插值五次缓动透明度。相邻区域共用边缘,不叠加透明度,最外层完全透明。两种字幕均使用这套羽化,不保留不透明边框,也不拉伸背景贴图。

只有尺寸、颜色、宽度比例、羽化轮廓或圆角半径改变时才重建几何数据,视图卸载时释放缓存数组。两种字幕的实心区域圆角半径均为10 dp乘以呈现缩放,外层圆角随羽化宽度向外扩展。文字逐字显示和位移动画共用已缓存的网格。

SubtitleFade为两种字幕提供五次缓动:淡入最长360 ms,自然淡出最长460 ms,各自不超过视图创建时剩余指令时长的35%。UI延迟收到字幕时,背景仍从全透明开始淡入,文字进度则按原定时间戳追赶。替换或清空字幕时,从当前显示的透明度开始,在360 ms内淡出;已经不可见的旧行可以立即移除。反馈旧行淡出时保留已有的弱化透明度,不再次叠加;字幕堆叠位置变化时,从当前显示位置平滑移至新位置。

过场字幕同一时刻只有一条当前指令。旧视图在交叉淡化期间保留自己的文字和布局;快速连续替换时,之前仍可见的视图也会完成淡出。浮层用同一个逐帧回调推进所有保留视图。逐字显示的时间戳使用墙钟毫秒,每个场景刻折算为50 ms,同时也按场景年龄检查指令过期。因此,渲染时钟的逐字显示不保证随场景刻一起暂停。主题值在显示指令时捕获,修改配置不会重新着色已发布的快照。

选项类型默认值作用
cinematicSubtitleBandColorstring"#0A0F18"字幕带 RGB,格式错误时回退到此值。
cinematicSubtitleBandOpacityinteger88百分比,限制为 0–100,按 ×2.55 四舍五入为透明度字节。
cinematicSubtitleBandWidthPercentinteger96字幕带宽度比例,限制为 40–100%。
cinematicSubtitleTextWidthPercentinteger62正文宽度比例,限制为 30–96%。
cinematicSubtitleSpeakerColorstring"#FFD79A"不透明说话人 RGB,格式错误时使用此回退值。
cinematicSubtitleTextColorstring"#F3F6FF"不透明正文 RGB;指令颜色的透明度字节非零时由指令覆盖。
cinematicSubtitleScalePercentinteger100缩放比例,限制为 60–160%。

这些是客户端呈现选项,不是场景数据,也不由服务端同步。颜色解析会去掉首尾空白,接受 6 或 8 位十六进制数字及可选的前导 #,忽略提供的透明度;字幕带透明度由独立选项控制。指令颜色的透明度字节为零时,继承配置的正文颜色。

触发器存档数据

下表是方块实体 NBT,不是场景 JSON。编辑器更新在服务端执行,要求同样的创造/权限条件、目标位置确有触发器,且距离不超过 8 方块。更新会验证 ID 语法,但不要求对应定义存在。

NBT 键类型默认值含义
Sceneidentifier无默认场景;读取时语法无效则为 null。
SceneRulesarray<object>[]保留前 16 条有效规则;缺失或列表类型错误时无规则。
SceneRules[].Sceneidentifier必填标识符无效时跳过此规则。
SceneRules[].MinProgressinteger0含端点的下界;上下界颠倒时交换。
SceneRules[].MaxProgressinteger0含端点的上界;不要求为正数。
Radiusnumber2.0方块。配置时限制为 0.25–128;NBT 读取仅应用 0.25 下限。
ReplayModestring"once_per_audience"上表中的重播 ID;空白或未知值使用默认值。
AudienceModestring"team_nearby"上表中的观众 ID;空白或未知值使用默认值。
CooldownTicksinteger80配置冷却,按重播模式校正;可重复模式的默认值变为 200。

模式读取器会去掉首尾空白并转为小写。半径校正是数值限幅,不包含显式有限数检查。规则保持原有顺序,不检测区间重叠,也不排序。

持久历史使用持久状态中说明的服务端作用域文件 isekaiexpansion/scene/trigger_memory_v2.dat。作用域包含维度、不可变方块位置及所选场景 ID,因此改换场景或移动方块都会得到不同的历史键。

NBT 键类型默认值含义
versioninteger0必须等于 2;缺失或版本不符时记录警告并丢弃读入历史。
entriesarray<object>[]触发器作用域;缺失或列表类型错误时得到空状态。
entries[].worldidentifier必填维度 ID 语法;无效条目被跳过。
entries[].x、entries[].y、entries[].zinteger0触发器坐标。
entries[].sceneidentifier必填所选场景 ID;无效条目被跳过。
entries[].audiencesarray<string>必填观众键集合;缺少列表时跳过条目,重复作用域/键会合并。空白键规范化为 unknown。

只有加入新观众键时才标记此状态需要保存。写入会排序作用域与观众键,并省略空集合。它记录触发历史,不是成功播放完成列表;此类不提供自动清理或重置命令。

扩展方式

内部服务端集成应在定义已加载、玩家已处于服务端世界后,从服务端线程调用:

boolean accepted = ServerSceneManager.play(
        player,
        new Identifier("isekaiexpansion", "hidden_hud_subtitle_scene"),
        new SceneTransform(player.getPos(), player.getYaw())
);

此重载仅将触发玩家作为观众,后续准入半径为零。场景缺失时在替换现有会话之前返回 false。True 表示已创建播放,不表示所有请求观众均已准入或播放已完成;创造模式触发玩家可能使会话没有观众,并在下一刻停止。

需要共享时,使用带显式 SceneAudienceMode 的 playFromTrigger。这些管理器调用不会自动切换线程,也不支持在服务端或玩家世界存在之前调用。专用服务端路径不得加载客户端管理器和镜头类。

添加指令或事件时,应同时更新定义解析、草稿序列化及对应服务端/客户端分派器。只改解析器,字段可能在网络包重建时丢失。保持按来源释放动作锁,并保留玩家与非玩家移动分工。

验证

  • 以生存玩家启动已知场景,再以不合格玩家启动,区分启动被接受与观众实际准入。
  • 使用另一队伍、无队伍玩家、中途到场、离开半径和切换维度,检查全部观众模式。
  • 检查进度规则首项匹配、队伍拥有者离线回退、缺失定义及可重复冷却。重启世界,检查持久与可重复历史的差别。
  • 投票跳过、让投票者断线、加入新观众并重复投票,确认所需票数由当前观众决定。
  • 让步行演员遇到障碍,确认碰撞影响实际进度,而场景仍按制作时长结束。
  • 中断进入和退出淡化、替换场景并断线,确认视角、HUD、移动及动作锁均已释放。
  • 使用内置 hidden_hud_subtitle_scene 检查隐藏 HUD 时的字幕、主题继承及中途加入。以上是验证步骤,不代表已完成多人或视觉测试。

相关页面