添加 player_v2.js 完整源码架构分析

从 1.8MB webpack bundle 中提取的关键信息:
- Heart 运行时完整类结构 (Registry, Compiler, Interpreter, RuntimeManager)
- 80+ domain functions (积木实现) 清单
- Interpreter.do_step() 执行流程详解
- BCM 加载流程
- PIXI.js 渲染层架构
- 性能瓶颈分析和 JIT 切入点
- 关键代码的 webpack 模块位置
This commit is contained in:
openclaw committed 2026-05-02 22:21:29 +08:00
1 parent cd50c395b1
commit 39dec4376d
1 file changed
+442
+442
View File
@@ -0,0 +1,442 @@
# 编程猫 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` (入口)
```javascript
// 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` (积木注册表)
```javascript
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` (编译器)
```javascript
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` (解释器) ⭐ 性能瓶颈
```javascript
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` (运行时管理器)
```javascript
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` (运行时数据)
```javascript
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` (积木谓词)
```javascript
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 变量操作
```javascript
variables_get(t, e, n) // 获取变量
variables_set(t, e, n) // 设置变量
change_variable(t, e, n) // 改变变量
```
### 3.2 列表操作
```javascript
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 运动
```javascript
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 外观
```javascript
show(t, e, n) // 显示
hide(t, e, n) // 隐藏
self_set_effect_2(t, e, n) // 设置特效
self_change_effect_3(t, e, n) // 改变特效
```
### 3.5 声音
```javascript
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 事件
```javascript
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 控制
```javascript
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 逻辑和数学
```javascript
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 文本
```javascript
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 询问/语音
```javascript
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 时间
```javascript
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
```javascript
// 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()
```javascript
// 找到 Interpreter 实例
const rm = heart.get_runtime_manager();
// rm 内部维护 interpreter 列表
// 替换每个 interpreter 的 step 方法
```
### 7.2 拦截 Compiler.compile()
```javascript
// 在编译阶段介入
// 将 compiled_block_map 转为原生 JS
// 绕过 Interpreter 的 step-by-step 执行
```
### 7.3 优化 step_eval_dispatch()
```javascript
// 将 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 加载 |