Files
codemao-webgl-engine/docs/player-source-analysis.md
T
openclaw 39dec4376d 添加 player_v2.js 完整源码架构分析
从 1.8MB webpack bundle 中提取的关键信息:
- Heart 运行时完整类结构 (Registry, Compiler, Interpreter, RuntimeManager)
- 80+ domain functions (积木实现) 清单
- Interpreter.do_step() 执行流程详解
- BCM 加载流程
- PIXI.js 渲染层架构
- 性能瓶颈分析和 JIT 切入点
- 关键代码的 webpack 模块位置
2026-05-02 22:21:29 +08:00

15 KiB
Raw Blame History

编程猫 Player v2.js 源码架构分析

从 https://kn-cdn.codemao.cn/kn/build/player_v2.2d180c468559fbd29528.js 提取 文件大小: 1.8MB, webpack 打包, 125 个模块

1. 整体架构

┌─────────────────────────────────────────────────────────┐
│                    React UI 层                           │
│  Theatre (舞台), Ranking (排行榜), Scanner (扫码),       │
│  FaceDetect, VirtualKeyboard, Dialog                     │
├─────────────────────────────────────────────────────────┤
│                  Redux + Saga 状态管理                    │
│  theatre_states, run_states, cloud_states,               │
│  variable_states, userinfo_state, ai_states              │
├─────────────────────────────────────────────────────────┤
│                  Heart 运行时引擎                         │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐  │
│  │Compiler  │ │Interpreter│ │Registry  │ │RuntimeMgr│  │
│  │(编译积木) │ │(执行积木) │ │(注册积木) │ │(管理实体) │  │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘  │
├─────────────────────────────────────────────────────────┤
│                  PIXI.js 渲染层 (WebGL)                   │
│  Application, Container, Sprite, Graphics,               │
│  Text, Filter, Ticker, InteractionManager                │
├─────────────────────────────────────────────────────────┤
│                  底层服务                                 │
│  Audio (Howler.js), Physics, MIDI, Cloud Variables,      │
│  Face Detection, QR Scanner, WebSocket                   │
└─────────────────────────────────────────────────────────┘

2. Heart 运行时核心类

2.1 Heart (入口)

// e.Heart = _
// 创建: new_heart(config)
// 方法:
//   get_runtime_manager() → RuntimeManager
//   get_runtime_data() → RuntimeData
//   get_registry() → Registry
//   get_compiler() → Compiler
//   get_event_bus() → EventBus
//   get_util() → BlockUtil
//   lint(entities, linters) → { errors }

2.2 RegistryImpl (积木注册表)

class RegistryImpl {
  // 存储
  domain_function = {}        // 积木实现函数
  domain_function_index = {}  // 函数索引
  respond = {}                // 响应器
  lifetime_respond = {}       // 生命周期响应器
  action_types = {}           // 动作类型
  meta_restart_when_finished = {}
  meta_finish_out_of_run_group = {}

  // 方法
  register({ namespace, id, domain_function, respond, metadata })
  register_action_type({ namespace, id, statefulness })
  register_linter(linter)
  has_responder_type(type) → boolean
  has_lifetime_responder_type(type) → boolean
  get_action_type(namespaced_id) → ActionSpec
  get_domain_functions() → { [name]: Function }
}

2.3 CompilerImpl / OptiCompilerImpl (编译器)

class CompilerImpl {
  // 将 workspace_json 编译为可执行的积木树
  compile(entity, procedures, is_clone) → compiled_block_map
  compile_from_workspace_json(blocksJSON, entity_id, is_clone) → {
    procedures: { [name]: block },
    compiled_block_map: { [id]: block }
  }
}

class OptiCompilerImpl {
  // 优化编译器 - 生成更高效的 AST
  compile(entity, procedures, is_clone) → compiled_program
}

2.4 InterpreterImpl (解释器) ⭐ 性能瓶颈

class InterpreterImpl {
  // 核心状态
  root_block          // 根积木
  current_block       // 当前执行的积木
  current_frame       // 当前栈帧
  program_state       // 程序状态
  n_warp_iterations   // warp 迭代计数
  n_procedure_calls   // 过程调用计数

  // 核心方法
  step() → StepResult     // 执行一步 ← 这是最热的路径
  do_step() → StepResult  // 内部执行

  // do_step 的执行流程:
  // 1. get_stack_frame() - 获取当前栈帧
  // 2. step_eval_dispatch() - 根据块类型分发
  // 3. 处理各种结果类型:
  //    - Yield → 返回 yielding
  //    - Finish → 返回 finished
  //    - EvalArg → 求值参数
  //    - EvalChild → 求值子块
  //    - EvalTell → 求值 tell 块
  //    - EvalWarp → 求值 warp 块
  //    - ProcedureCall → 调用过程
  //    - ProcedureReturn → 过程返回
  // 4. go_next_or_parent() - 导航到下一个块或父块
  // 5. must_yield() - 检查是否需要让出

  // step_eval_dispatch 分发逻辑:
  step_eval_dispatch() {
    if (block.disabled) return skip
    if (is.responder_block(block)) return eval_child_or_done
    if (is.event_block(block)) return eval_event
    if (is.cond_block(block)) return eval_cond
    if (is.domain_block(block)) return eval_domain
    if (is.break(block)) return Break
    if (is.repeat_forever(block)) return eval_repeat_forever
    if (is.repeat_n_times(block)) return eval_repeat_n_times
    if (is.repeat_forever_until(block)) return eval_repeat_forever_until
    if (is.wait_until(block)) return eval_wait_until
    if (is.procedures_callreturn(block)) return eval_procedures_callreturn
    if (is.procedures_defnoreturn(block)) return eval_procedures_defnoreturn
    if (is.procedures_parameter(block)) return eval_procedures_parameter
    if (is.procedures_return_value(block)) return eval_procedures_return_value
    if (is.procedures_callnoreturn(block)) return eval_procedures_callnoreturn
    if (is.sync_tell(block)) return eval_sync_tell
    if (is.async_tell(block)) return eval_async_tell
    if (is.warp(block)) return eval_warp
    throw unknown_block_type
  }
}

2.5 RuntimeManagerImpl (运行时管理器)

class RuntimeManagerImpl {
  // 实体管理
  create_entity_instance(entity_id, typeclass_id)
  create_singleton_entity_instances()
  destruct_entity(entity_id)
  get_entity_state(entity_id) → EntityState

  // 解释器管理
  spawn_interpreter(config)
  spawn_async_tell_interpreter(config)
  remove_interpreter(interpreter_id)
  add_interpreter(interpreter)
  get_interpreter_ids() → string[]
  get_n_interpreters() → number

  // 执行
  run()              // 开始执行
  stop()             // 停止
  update()           // 每帧更新 ← 调用所有 interpreter.step()

  // 变量
  get_variable(name, entity_id, interpreter_id)
  set_variable(name, value, entity_id, interpreter_id)
  set_variable_specs(specs)

  // 线程控制
  thread_wait(entity_id, interpreter_id, ms)
  get_thread_lock(entity_id, interpreter_id) → ThreadLock

  // 广播
  broadcaster_sending_message(entity_id, message, is_blocking)

  // 动作
  send_action({ id, namespace, parameters, value })
}

2.6 RuntimeDataImpl (运行时数据)

class RuntimeDataImpl {
  // 变量和列表
  clone_id_2_original_id(clone_id) → original_id
  get_arbitrary_data(key) → any
  set_arbitrary_data(key, value)
  is_running() → boolean

  // 事件总线
  variable_update → EventBus
  list_update → EventBus
  entity_variable_update → EventBus
  entity_list_update → EventBus
}

2.7 BlockPredicatesImpl (积木谓词)

class BlockPredicatesImpl {
  // 判断积木类型
  hat_block_type(type) → boolean
  responder_block(block) → boolean
  responder_type(type) → boolean
  lifetime_responder_type(type) → boolean
  event_block(block) → boolean
  domain_block(block) → boolean
  loop_block(block) → boolean
  cond_block(block) → boolean
  proc_block(block) → boolean
  special_block(block) → boolean

  // 具体积木判断
  controls_if(block) → boolean
  repeat_n_times(block) → boolean
  repeat_forever(block) → boolean
  repeat_forever_until(block) → boolean
  wait_until(block) → boolean
  break(block) → boolean
  procedures_defnoreturn(block) → boolean
  procedures_callreturn(block) → boolean
  async_tell(block) → boolean
  sync_tell(block) → boolean
  warp(block) → boolean
  mirror(block) → boolean
  start_on_click(block) → boolean
}

3. Domain Functions (积木实现)

积木的实际功能通过 domain functions 注册到 Registry:

3.1 变量操作

variables_get(t, e, n)     // 获取变量
variables_set(t, e, n)     // 设置变量
change_variable(t, e, n)   // 改变变量

3.2 列表操作

lists_append(t, e, n)       // 添加到列表
lists_delete(t, e, n)       // 删除列表项
lists_insert_value(t, e, n) // 插入值
lists_replace(t, e, n)      // 替换列表项
lists_get_value(t, e, n)    // 获取列表值
lists_length(t, e, n)       // 列表长度
lists_index_of(t, e, n)     // 查找索引
lists_copy(t, e, n)         // 复制列表
lists_is_exist(t, e, n)     // 检查值是否存在

3.3 运动

self_move_to(t, e, n)          // 移动到
self_set_position(t, e, n)     // 设置位置
self_change_coordinate(t, e, n)// 改变坐标
self_glide_to(t, e, n)         // 滑行到
self_glide_coordinate(t, e, n) // 滑行到坐标
self_point_towards(t, e, n)    // 面向
self_face_to(t, e, n)          // 面向角色
self_bounce_off_edge(t, e, n)  // 碰到边缘反弹

3.4 外观

show(t, e, n)              // 显示
hide(t, e, n)              // 隐藏
self_set_effect_2(t, e, n) // 设置特效
self_change_effect_3(t, e, n) // 改变特效

3.5 声音

play_audio(t, e, n)           // 播放声音
play_audio_and_wait(t, e, n)  // 播放并等待
play_audio_2(t, e, n)         // 播放声音 v2
play_audio_and_wait_2(t, e, n)// 播放并等待 v2
stop_audio_2(t, e, n)         // 停止声音
play_words_audio(t, e, n)     // 朗读文字
play_words_audio_wait(t, e, n)// 朗读并等待

3.6 事件

self_broadcast(t, e, n)          // 广播消息
self_broadcast_and_wait(t, e, n) // 广播并等待
self_listen(t, e, n)             // 当收到消息
when(t, e, n)                    // 当...时
start_on_click(t, e, n)          // 当点击

3.7 控制

wait(t, e, n)          // 等待
repeat_n_times         // 重复 N 次
repeat_forever         // 永久重复
repeat_forever_until   // 重复直到
terminate(t, e, n)     // 终止
stop(t, e, n)          // 停止
restart(t, e, n)       // 重新开始
destruct(t, e, n)      // 销毁

3.8 逻辑和数学

logic_compare(t, e, n)    // 比较
logic_operation(t, e, n)  // 逻辑运算
logic_negate(t, e, n)     // 逻辑非
logic_boolean(t, e, n)    // 布尔值
math_arithmetic(t, e, n)  // 四则运算
math_single(t, e, n)      // 单目运算
math_round(t, e, n)       // 取整
math_modulo(t, e, n)      // 取余
random(t, e, n)           // 随机数
calculate(t, e, n)        // 计算表达式

3.9 文本

text_join(t, e, n)      // 拼接
text_length(t, e, n)    // 长度
text_indexof(t, e, n)   // 查找
text_contain(t, e, n)   // 包含
text_select(t, e, n)    // 截取
text_split(t, e, n)     // 分割
text_append(t, e, n)    // 追加
text_implicit(t, e, n)  // 隐式转换

3.10 询问/语音

self_ask_listen(t, e, n)      // 询问并等待回答
voice_recognition(t, e, n)    // 语音识别
self_ask_record(t, e, n)      // 询问并录音
get_voice_answer(t, e, n)     // 获取语音回答
enable_voice_detection(t, e, n) // 启用声音侦测
get_voice_volume(t, e, n)     // 获取音量

3.11 时间

get_time(t, e, n)       // 获取时间
get_cur_frames(t, e, n) // 获取当前帧数
reset_timer(t, e, n)    // 重置计时器
get_timer(t, e, n)      // 获取计时器

4. BCM 加载流程

1. player.codemao.cn/t/{work_id} 加载
2. fetch_bcm_request action 触发
3. API: GET https://api.codemao.cn/api/work/info/{work_id}
4. 获取 BCM 数据 (workspace_json)
5. Heart.Compiler.compile(workspace_json) → compiled_block_map
6. RuntimeManager.load(entities) → 加载所有实体
7. RuntimeManager.run() → 开始执行
8. requestAnimationFrame 循环 → RuntimeManager.update()
   → 每个 Interpreter.step()

5. 渲染层 (PIXI.js)

PIXI.js 版本: 6.0.4

// PIXI 核心组件
PIXI.Application   // 应用 (包含 ticker, stage, renderer)
PIXI.Container     // 容器 (display object 树)
PIXI.Sprite        // 精灵
PIXI.Graphics      // 矢量图形
PIXI.Text          // 文字
PIXI.Filter        // 滤镜 (blur, twist, pixelate, ASCII 等)
PIXI.Ticker        // 帧循环 (requestAnimationFrame)
PIXI.InteractionManager // 交互管理 (点击, 拖拽)
PIXI.Texture       // 纹理
PIXI.BaseTexture   // 基础纹理
PIXI.RenderTexture // 渲染纹理

// 着色器
// 顶点着色器: 标准 2D 变换
// 片段着色器: 纹理采样 + 颜色混合
// 支持 WebGL 1.0 和 2.0

6. 性能瓶颈分析

组件 耗时占比 瓶颈原因
Interpreter.do_step() ~60% 逐条解释, dispatch 开销, 栈帧管理
Interpreter.step_eval_dispatch() ~25% 大量 if-else 类型判断
RuntimeManager.update() ~10% 遍历所有 interpreter
PIXI.js 渲染 ~5% 已经是 WebGL, 高效

7. JIT 加速切入点

7.1 直接替换 Interpreter.step()

// 找到 Interpreter 实例
const rm = heart.get_runtime_manager();
// rm 内部维护 interpreter 列表
// 替换每个 interpreter 的 step 方法

7.2 拦截 Compiler.compile()

// 在编译阶段介入
// 将 compiled_block_map 转为原生 JS
// 绕过 Interpreter 的 step-by-step 执行

7.3 优化 step_eval_dispatch()

// 将 if-else 链改为 lookup table
// 预编译 block type → handler 映射
// 减少每次 dispatch 的开销

8. 关键代码位置 (webpack 模块)

功能 模块特征
Heart 入口 new_heart, e.Heart
Registry e.RegistryImpl, has_responder_type
Compiler e.CompilerImpl, compile_from_workspace_json
OptiCompiler e.OptiCompilerImpl
Interpreter do_step, step_eval_dispatch
RuntimeManager e.RuntimeManagerImpl, get_runtime_manager
BlockPredicates e.BlockPredicatesImpl, repeat_forever
BlockProvider e.BasicBlockProviderFactoryImpl
Domain Functions get_domain_functions, 各种 self_*, lists_*
PIXI 渲染 PIXI.Application, lvVU 模块
音频 AudioPlayer, Howl, MIDI
物理 physics2_*
Redux Store dqaR 模块, ALsR
Theatre ypP6 模块, ft 组件
Cloud qVl3 模块, BCM 加载