Skip to content

核心概念

上一页:快速上手 · 下一页:对接总览

这一页讲架构——给"想先搞懂再配置"的你。读完你会明白:一次按键在 QS 内部到底经历了什么、状态机为什么存在、技能为什么有"两套字段"、QS 到底做什么不做什么。


🎯 运行管线:一次按键的 7 个阶段

QS 的核心是一条固定的运行管线。无论触发来自物品、命令、API 还是被动事件,都走这同一条路:

text
   ① 输入                玩家按键 / 命令 / API / 被动事件
      │                  统一归一成标准触发信号

   ② 状态机(State)       现在是什么状态?空闲?连招窗口?被封锁?
      │                  决定这次输入能不能进、走哪条路

   ③ 图解析(Graph)+连招   在当前状态下,这个键命中哪个节点?
      │  (Combo)          是不是某段连招序列的一环?

   ④ 执行计划(Plan)       拼出"放哪个 MM 技能、目标是谁、带哪些参数"


   ⑤ 门控(Gate)          逐项检查:解锁?冷却?充能?GCD?资源?血祭?冲突?条件?
      │                  任一不过 → 拦下并提示,管线在此中止

   ⑥ 执行(Exec)          MythicExecutor 把计划交给 MythicMobs 演出


   ⑦ 后处理(Post)        进冷却 / 改状态 / 推进连招 / 刷 actionbar

💡 为什么要"一条管线管所有触发"? 这样冷却、充能、连招、目标这些规则只写一遍,对"物品放""命令放""被动放"一视同仁。你永远不会遇到"命令能放但物品放不了"这种两套逻辑打架的问题。

记住这条管线的固定顺序——门控在执行之前。所以"明明 MM 技能写好了却放不出来",几乎总是卡在第 ⑤ 步门控(没解锁 / 在冷却 / 资源不够),而不是 MM 的问题。


🔄 状态机:6 个状态

QS 给每个玩家维护一个技能状态机。它存在的意义:让"连招""续段""被沉默"这类有时序的事变得可判定。

状态中文含义
IDLE空闲默认态,可以正常起手放技能
CASTING施放中技能正在放出
COMBO_WINDOW连招窗口起手成功后短暂开窗,此窗内的输入算"续段"
RECOVERY恢复预留状态(后摇 / 硬直,暂未启用具体逻辑)
LOCKED被封锁被沉默(silence),放不出任何技能
INTERRUPTED中断吟唱 / 施放被打断

状态什么时候转换

text
IDLE ──首次按键起手成功──► CASTING
CASTING ──成功且该技能有连招──► COMBO_WINDOW
COMBO_WINDOW ──超过 combo_window_ms(默认800) 没续上──► IDLE   (连招断)
任意状态 ──/qs silence N──► LOCKED ──N 秒后──► IDLE
吟唱/施放被位移或受伤打断 ──► INTERRUPTED ──► IDLE

要点:

  • 起手 vs 续段靠状态区分。 同一个右键,在 IDLE 走起手节点,在 COMBO_WINDOW 走续段节点(graph 节点用 require_state 标谁是谁)。这就是连招能成立的底层机制。
  • 连招窗口会超时。 combo_window_ms(默认 800ms)内没按出下一段,状态回 IDLE,连招断。
  • 被沉默 = LOCKED /qs silence 5 让玩家 5 秒内进 LOCKED,所有技能放不出;/qs silence 0 解除。这是技能封锁 / 沉默 debuff 的实现入口。

详见 graph 与连招施法模式与吟唱


📑 技能的"两套字段":生态校验 vs 运行期读取

打开任何技能 yml,你会看到字段分成两半。这是 QS 的一个刻意设计,搞懂它能少踩大坑。

这套字段作用谁来读
meta / trigger / state / graph / execution生态信息 —— 分类归档、reload 时一致性校验、连招编排参照schema 校验器
type / cooldown / resource / cast_mode / levels / variables运行期实际读取 —— 真正决定行为runtime loader

举例对照(来自 fire_wave):

yaml
meta:
  type: active          # 生态标签:归类用
trigger:
  primary: RIGHT_CLICK  # 生态:声明主触发键(校验时比对 graph)
state:
  required: IDLE        # 生态:声明所需状态(校验时比对入口节点)
execution:
  mythic_skill: fire_wave   # 生态:声明执行哪个 MM 技能

type: active            # ← 运行期真正决定主动/被动的是这一行
mythic_skill: fire_wave # ← 运行期实际用的(execution.mythic_skill 优先)

⚠️ 两套必须保持一致。 比如 state.required: IDLE 要和 graph 入口节点的 require_state: IDLE 一致;execution.mythic_skill 要和入口节点的 mythic_skill 一致。/qs reload 会做一致性校验,对不上会报 schema 警告。

为什么要分两套? 上半套让生态(校验器、连招编排、未来的编辑器 GUI)能在不跑技能的情况下读懂"这技能长什么样、归哪类、连不连招";下半套是引擎运行时真正吃的配置。一个供"理解",一个供"执行"。


🚪 门控(Gate):放行前的有序闸门

门控是管线第 ⑤ 步,也是 QS 最核心的价值之一。它是一串按固定顺序执行的检查,任一不过就拦下技能并给玩家提示:

闸门检查什么
解锁这个玩家解锁这技能了吗?
冷却 / 冷却组在 CD 里吗?同冷却组的技能是否共享了 CD?
充能充能层数还有吗(充能技能用层数替代二元冷却)?
全局冷却 GCD刚放过别的技能、还在全局冷却里吗?
资源mana 够吗(临时占位,将来归 QC)?
生命 / 饥饿(血祭)扣血扣饿够吗?血量太低不让放?
冲突组短期内放过同冲突组的技能吗(gate.conflict_window_ms 默认 1000ms)?
声明式条件conditions: 里的条件全满足吗?

💡 门控是"判定层",不是"表现层"。 它只回答能不能放,从不画任何东西。所以技能放不出来时,先想门控(哪道闸没过),别一头扎进 MM 排查。各闸门详细配置见 冷却充能GCD与冲突消耗条件与变量


🌉 桥(Bridge):QS → MythicMobs

门控通过后,QS 要把执行计划交给 MM。这条交接缝叫桥(Bridge)

桥模式(config.ymlmythic.bridge_mode行为
AUTO(推荐 / 默认)优先用 MM API 注册技能 → 校验 → 失败则降级写 YAML 并 loadSkills()
API_MODE只走 API,不降级(开发 / 测试用)
YAML_STUB只写 MM 技能文件夹 + 走加载生命周期

关于桥,记住三件事:

  1. 没装 MM 也能跑。 桥进占位模式,触发技能 → 聊天栏 [QinhSkills] 技能名。看到它就证明 QS 这侧全通。
  2. 永不覆盖你的同名 MM 技能。 占位只在"你没写同名技能"时存在;你写了真技能,桥就用你的。
  3. /qs bridge 看桥状态,诊断 MM 是否在场、注册是否成功。

详见 对接 MythicMobs


🧭 职责边界:QS 做什么 / 不做什么

最后把边界钉死,这是理解整个秦淮生态的关键。

QS 做: cast 逻辑 / 触发归一 / 目标索敌 / 门控(解锁·冷却·充能·冷却组·GCD·冲突·资源·血祭·条件·cast_mode·吟唱读条与打断)/ 把变量参数透传给 MM / JS 脚本出口(pre_js / post_js)。

QS 不做:

不做的事归谁
粒子 / 位移 / 表现 / 机制本体MythicMobs
伤害数值结算AttributePlus 等属性插件(在 MM 那侧)
玩家职业 / 玩家等级 / 法力·耐力资源池 / 冷却缩减(CDR) / 玩家属性QinhClass(QC)

🔑 关于 mana: 技能 yml 里的 resource.manaconfig.yml 里的 resources.default_mana/max_mana 都是 QC 接管前的临时占位。资源扣费走的是 QS 既有的玩家档案缝(PlayerSkillProfile),不另造池子;将来 QC 接管资源时只改这一处,技能 yml 不用动。

这条边界和 QS 第一条设计哲学一脉相承:QS 只管逻辑,不管表现、不管数值、不管玩家成长。 各司其职,谁的活谁干。


继续阅读