chore: 项目已迁移至 Gitee/GitHub,仅保留迁移说明 (tombstone)

This commit is contained in:
shuiyuPyLab committed 2026-08-09 10:15:57 +08:00
1 parent bcf4122991
commit e83315b378
7 files changed
+1 -2439

No files matched your search

-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2026 shuiyu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+1 -2
View File
@@ -2,8 +2,7 @@
你好呀~这个仓库已经搬到更好用的地方啦。
为了让代码管理更清爽、多平台同步更省心,我们把原先分散的镜像统一收拢到
**Gitee** 与 **GitHub** 主仓维护,这里就只保留这张"迁移小纸条"咯。
为了让代码管理更清爽、多平台同步更省心,我们把原先分散的镜像统一收拢到主仓维护,这里就只保留这张"迁移小纸条"咯。
📦 新家在这里:
- Gitee:https://gitee.com/shuiyu1123/codemao-webgl-engine
-124
View File
@@ -1,124 +0,0 @@
// ============================================================
// 性能对比基准测试
// 模拟 Heart 解释器 vs JIT 编译器的执行性能
// ============================================================
const ITERATIONS = 100000;
// 模拟 Heart 解释器的执行方式
function heartInterpreterSimulated(blocks, runtime) {
let result = 0;
let pc = 0; // program counter
const stack = [];
while (pc < blocks.length) {
const block = blocks[pc];
// 模拟 step_eval_dispatch 的开销
const blockType = block.type;
const params = block.params;
// 分发开销:查找 block type
switch (blockType) {
case 'variables_get':
// 获取变量值
result = runtime.getVariable(params.VAR);
break;
case 'variables_set':
runtime.setVariable(params.VAR, result);
break;
case 'math_arithmetic':
const a = runtime.getVariable(params.A);
const b = runtime.getVariable(params.B);
switch (params.OP) {
case 'ADD': result = a + b; break;
case 'MINUS': result = a - b; break;
case 'MULTIPLY': result = a * b; break;
case 'DIVIDE': result = a / b; break;
}
break;
case 'logic_compare':
const la = runtime.getVariable(params.A);
const lb = runtime.getVariable(params.B);
switch (params.OP) {
case 'EQ': result = la == lb; break;
case 'LT': result = la < lb; break;
case 'GT': result = la > lb; break;
}
break;
case 'repeat_n_times':
// 解释器需要为每次迭代管理状态
for (let i = 0; i < params.TIMES; i++) {
// 模拟 yield 检查
if (i % 1000 === 0) {
// 解释器的 yield 开销
stack.push({ pc, frame: i });
stack.pop();
}
result += i;
}
break;
}
// 模拟 next_block 查找开销
pc++;
}
return result;
}
// JIT 编译后的执行方式
function jitCompiled(runtime) {
let result = 0;
// 直接执行,无 dispatch 开销
for (let i = 0; i < ITERATIONS; i++) {
result = runtime.getVariable('x');
result = result + runtime.getVariable('y');
result = result * 2;
runtime.setVariable('x', result);
}
return result;
}
// 运行基准测试
function runBenchmark() {
const runtime = {
vars: { x: 1, y: 2, n: 1000 },
getVariable(name) { return this.vars[name] || 0; },
setVariable(name, val) { this.vars[name] = val; }
};
// 构造积木序列
const blocks = [];
for (let i = 0; i < ITERATIONS; i++) {
blocks.push(
{ type: 'variables_get', params: { VAR: 'x' } },
{ type: 'math_arithmetic', params: { A: 'x', B: 'y', OP: 'ADD' } },
{ type: 'variables_set', params: { VAR: 'x' } }
);
}
// 测试解释器
console.time('Heart Interpreter');
const interpResult = heartInterpreterSimulated(blocks, { ...runtime });
console.timeEnd('Heart Interpreter');
// 重置 runtime
runtime.vars.x = 1;
// 测试 JIT
console.time('JIT Compiled');
const jitResult = jitCompiled({ ...runtime });
console.timeEnd('JIT Compiled');
return { interpResult, jitResult };
}
// 导出
if (typeof module !== 'undefined') {
module.exports = { runBenchmark };
} else {
window.runBenchmark = runBenchmark;
}
-27
View File
@@ -1,27 +0,0 @@
# 反编译进度
新仓库: https://gitee.com/shuiyu1123/codemao-heart-source (私有)
## 已还原的核心模块
| 模块 | 文件 | 状态 |
|------|------|------|
| RegistryImpl | `src/heart/Registry.js` | ✅ 完成 |
| BlockPredicatesImpl | `src/heart/BlockPredicates.js` | ✅ 完成 |
| CompilerImpl | `src/heart/Compiler.js` | ✅ 完成 |
| InterpreterImpl | `src/heart/Interpreter.js` | ✅ 完成 (完整) |
| RuntimeManagerImpl | `src/heart/RuntimeManager.js` | ✅ 完成 |
## 完整文档
- `docs/player-source-analysis.md` - 1.8MB bundle 完整架构分析
- `docs/module-map.md` - webpack 模块映射表
- `docs/domain-functions.md` - 80+ 积木实现清单
- `TASKS.md` - 反编译任务清单
## 下一步
1. 还原 RuntimeDataImpl, BlockPoolImpl, EventBus
2. 还原 Domain Functions (积木实际实现)
3. 还原渲染层 (PIXI.js 集成)
4. JIT 编译器与还原的 Interpreter 对接
-442
View File
@@ -1,442 +0,0 @@
# 编程猫 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 加载 |
File diff suppressed because it is too large. Load diff
-806
View File
@@ -1,806 +0,0 @@
// ==UserScript==
// @name 编程猫 Heart JIT 加速器
// @namespace https://gitee.com/shuiyu1123/codemao-webgl-engine
// @version 3.1.0
// @description 绕过 Heart 运行时解释器,将积木 AST 直接编译为原生 JS 执行
// @author codemao-webgl-engine
// @match https://player.codemao.cn/*
// @match https://shequ.codemao.cn/*
// @match https://kitten.codemao.cn/*
// @match https://ide.codemao.cn/*
// @run-at document-start
// @grant none
// @license MIT
// ==/UserScript==
/**
* ============================================================
* 编程猫 Heart JIT 加速器 v3.1
* ============================================================
*
* 从 player_v2.js 源码分析得到的注入点:
*
* 1. PIXI.Application 创建时挂在 canvas.__pixi_app
* 2. Redux store 通过 T.a.get_store() 访问
* 3. Heart 运行时通过 Object(E.b)().get_runtime_manager() 获取
* 4. 游戏循环在 requestAnimationFrame 中运行
* 5. BCM 数据加载后通过 LOAD_BCM action 触发
*
* 注入策略:
* - 拦截 PIXI.Application 构造函数 → 拿到 pixi app 实例
* - 通过 pixi app 的 ticker 回调找到 Heart 运行时
* - 替换 Interpreter 的 step 方法为 JIT 编译版本
*
* ============================================================
*/
(function () {
'use strict';
const TAG = '🐱[Heart-JIT]';
const log = (...a) => console.log(TAG, ...a);
const warn = (...a) => console.warn(TAG, ...a);
// ================================================================
// 配置
// ================================================================
const CONFIG = {
enabled: true,
debug: false,
fallbackOnError: true,
profileInterval: 5000, // 性能采样间隔
};
// ================================================================
// 统计
// ================================================================
const stats = {
jitted: 0,
interpreted: 0,
fallbacks: 0,
executions: 0,
compileTime: 0,
avgStepTime: 0,
pixiApps: 0,
heartFound: false,
};
// ================================================================
// JIT 编译器
// ================================================================
class JITCompiler {
constructor() {
this.cache = new Map();
}
/**
* 将一个积木过程编译为原生 JS 生成器函数
* 使用生成器是为了支持 Heart 的 yield 协程机制
*/
compile(blockChain) {
if (!blockChain) return null;
const id = blockChain.id || 'chain_' + Math.random();
if (this.cache.has(id)) return this.cache.get(id);
const t0 = performance.now();
try {
const body = this.emitChain(blockChain, 0);
// 生成器函数,支持 yield 协程
const fn = new Function('ctx', `
"use strict";
const { runtime, data, eventBus, ohno, entity_id, interpreter_id } = ctx;
let yield_count = 0;
let _break_flag = false;
${body}
`);
stats.compileTime += performance.now() - t0;
stats.jitted++;
this.cache.set(id, fn);
if (CONFIG.debug) log(`JIT: compiled ${blockChain.type || 'chain'} (${id}) in ${(performance.now()-t0).toFixed(2)}ms`);
return fn;
} catch (e) {
stats.fallbacks++;
if (CONFIG.debug) warn('JIT compile failed:', e);
return null;
}
}
emitChain(block, depth) {
if (!block || depth > 50) return '';
let code = this.emitBlock(block, depth);
if (block.next_block) {
code += '\n' + this.emitChain(block.next_block, depth);
}
return code;
}
emitBlock(block, depth) {
const t = block.type;
const p = block.params || {};
const children = block.child_block || [];
switch (t) {
// === 变量 ===
case 'variables_set':
return `runtime.set_variable(${JSON.stringify(p.VAR)}, ${this.val(p.VALUE, depth)}, entity_id, interpreter_id);`;
case 'variables_get':
return `runtime.get_variable(${JSON.stringify(p.VAR)}, entity_id, interpreter_id)`;
case 'change_variable': {
const m = p.method || 'increase';
return `(function(){var c=runtime.get_variable(${JSON.stringify(p.valname)},entity_id,interpreter_id);var a=${this.val(p.n,depth)};runtime.set_variable(${JSON.stringify(p.valname)},${m==='increase'?'c+a':'c-a'},entity_id,interpreter_id);})()`;
}
// === 逻辑 ===
case 'logic_compare': {
const op = {EQ:'==',NEQ:'!=',LT:'<',LTE:'<=',GT:'>',GTE:'>='}[p.OP] || '==';
return `(${this.val(p.A,depth)} ${op} ${this.val(p.B,depth)})`;
}
case 'logic_operation':
return p.OP === 'AND'
? `(${this.val(p.A,depth)} && ${this.val(p.B,depth)})`
: `(${this.val(p.A,depth)} || ${this.val(p.B,depth)})`;
case 'logic_negate':
return `(!${this.val(p.BOOL,depth)})`;
case 'logic_boolean':
return p.BOOL === 'TRUE' ? 'true' : 'false';
// === 数学 ===
case 'math_arithmetic': {
const ops = {ADD:'+',MINUS:'-',MULTIPLY:'*',DIVIDE:'/'}[p.OP];
if (ops) return `(${this.val(p.A,depth)} ${ops} ${this.val(p.B,depth)})`;
if (p.OP === 'POWER') return `Math.pow(${this.val(p.A,depth)},${this.val(p.B,depth)})`;
return `(${this.val(p.A,depth)} + ${this.val(p.B,depth)})`;
}
case 'math_modulo':
return `(${this.val(p.DIVIDEND,depth)} % ${this.val(p.DIVISOR,depth)})`;
case 'random':
return `Math.floor(${this.val(p.a,depth)} + Math.random() * (${this.val(p.b,depth)} - ${this.val(p.a,depth)} + 1))`;
// === 文本 ===
case 'text_join': {
const parts = [];
for (let i = 0; p['ADD'+i] !== undefined; i++) parts.push(this.val(p['ADD'+i], depth));
return parts.length ? `("" + ${parts.join(' + ')})` : '""';
}
case 'text_length':
return `String(${this.val(p.VALUE,depth)}).length`;
case 'text_contain':
return `(String(${this.val(p.TEXT1,depth)}).indexOf(String(${this.val(p.TEXT2,depth)})) !== -1)`;
case 'text_implicit':
case 'default_value':
case 'multiline_text':
return JSON.stringify(p.TEXT || p.VALUE || '');
// === 控制流 ===
case 'controls_if':
case 'controls_if_no_else':
case 'controls_if_dropdown': {
const conds = p.conditions || p.if_dropdown_conditions || [];
let code = '';
for (let i = 0; i < conds.length; i++) {
const cond = this.val(conds[i], depth);
const body = children[i] ? this.emitChain(children[i], depth+1) : '';
code += (i === 0 ? 'if' : ' else if') + `(${cond}){${body}}`;
}
if (children.length > conds.length) {
code += ` else {${this.emitChain(children[children.length-1], depth+1)}}`;
}
return code;
}
case 'repeat_n_times': {
const times = this.val(p.TIMES, depth);
const body = children[0] ? this.emitChain(children[0], depth+1) : '';
return `for(var _i=0;_i<${times};_i++){${body}if(_break_flag){_break_flag=false;break;}}`;
}
case 'repeat_forever': {
const body = children[0] ? this.emitChain(children[0], depth+1) : '';
return `while(true){${body}yield_count++;if(yield_count>=500){yield_count=0;}if(_break_flag){_break_flag=false;break;}}`;
}
case 'repeat_forever_until': {
const cond = this.val(p.condition, depth);
const body = children[0] ? this.emitChain(children[0], depth+1) : '';
return `while(!(${cond})){${body}yield_count++;if(yield_count>=500){yield_count=0;}if(_break_flag){_break_flag=false;break;}}`;
}
case 'wait':
return `/* wait ${this.val(p.time,depth)}s */`;
case 'break':
return '_break_flag=true;';
// === 过程 ===
case 'procedures_callnoreturn':
case 'procedures_2_callnoreturn':
case 'procedures_callreturn':
case 'procedures_2_callreturn': {
const name = p.NAME || block.procedure_name || '';
const args = Object.entries(p).filter(([k]) => k !== 'NAME').map(([k,v]) => `${k}:${this.val(v,depth)}`).join(',');
return `runtime.call_procedure(${JSON.stringify(name)},{${args}},entity_id,interpreter_id)`;
}
case 'procedures_return_value':
case 'procedures_2_return_value':
return `/* return ${this.val(p.VALUE,depth)} */`;
// === 广播 ===
case 'self_broadcast':
return `runtime.broadcaster_sending_message(entity_id,${JSON.stringify(p.message)},false);`;
case 'self_broadcast_and_wait':
return `runtime.broadcaster_sending_message(entity_id,${JSON.stringify(p.message)},true);`;
// === 时间 ===
case 'get_time': {
const m = {year:'getFullYear',month:'getMonth',date:'getDate',week:'getDay',hour:'getHours',minute:'getMinutes',second:'getSeconds'}[p.op];
return m ? `(new Date).${m}()${p.op==='month'?'+1':''}` : '0';
}
case 'get_cur_frames':
return 'runtime.get_elapsed_frames()';
case 'get_timer':
return 'runtime.get_timer_elapsed_s()';
case 'reset_timer':
return 'runtime.reset_timer();';
case 'wait_seconds': {
const secs = this.val(p.time, depth);
return `/* wait ${secs}s */`;
}
// === 列表 ===
case 'lists_append':
return `(function(){var l=runtime.get_variable(${JSON.stringify(p.VAR)},entity_id,interpreter_id);if(Array.isArray(l))l.push(${this.val(p.VALUE,depth)});})()`;
case 'lists_get_value':
return `(function(){var l=runtime.get_variable(${JSON.stringify(p.VAR)},entity_id,interpreter_id);if(!Array.isArray(l))return undefined;var i=${this.val(p.INDEX,depth)};${p.TYPE==='last'?'i=l.length;':''}i=i>0?i-1:i+l.length;return l[i];})()`;
case 'lists_length':
return `(function(){var l=runtime.get_variable(${JSON.stringify(p.VAR)},entity_id,interpreter_id);return Array.isArray(l)?l.length:0;})()`;
case 'lists_delete':
return `(function(){var l=runtime.get_variable(${JSON.stringify(p.VAR)},entity_id,interpreter_id);if(!Array.isArray(l))return;var i=${this.val(p.INDEX,depth)};${p.TYPE==='last'?'l.pop();':'i=i>0?i-1:i+l.length;l.splice(i,1);'}})()`;
// === 通用 domain function ===
default:
return this.emitDomainFunc(block, depth);
}
}
emitDomainFunc(block, depth) {
const p = block.params || {};
const args = Object.entries(p).map(([k,v]) => `${k}:${this.val(v,depth)}`).join(',');
return `(function(){try{var df=runtime.get_domain_function(${JSON.stringify(block.type)});if(df)df({${args}},entity_id,interpreter_id,ctx);}catch(e){if(${CONFIG.debug})console.error(${JSON.stringify(block.type)},e);}})()`;
}
val(v, depth) {
if (v === undefined || v === null) return 'undefined';
if (typeof v === 'number' || typeof v === 'boolean') return JSON.stringify(v);
if (typeof v === 'string') return JSON.stringify(v);
if (typeof v === 'object' && v.type) {
const inner = this.emitBlock(v, depth + 1);
if (inner.length < 100 && !inner.includes(';')) return inner;
return `(function(){${inner}})()`;
}
return JSON.stringify(v);
}
}
// ================================================================
// 注入器 — 通过拦截 PIXI 和 RAF 找到 Heart 运行时
// ================================================================
class HeartJITInjector {
constructor() {
this.jit = new JITCompiler();
this.heartRM = null; // runtime_manager
this.injected = false;
this.patchedInterpreters = new WeakSet();
this.origRAF = window.requestAnimationFrame;
this.frameCount = 0;
}
/**
* 安装拦截器
*/
install() {
this.interceptRAF();
this.interceptPIXI();
this.startProfiling();
log('拦截器已安装,等待作品加载...');
}
/**
* 拦截 requestAnimationFrame 以检测游戏循环
*/
interceptRAF() {
const self = this;
const orig = this.origRAF;
window.requestAnimationFrame = function(cb) {
return orig.call(window, function(time) {
self.frameCount++;
// 每 120 帧尝试一次注入
if (self.frameCount % 120 === 0 && !self.injected) {
self.tryInject();
}
cb(time);
});
};
log('RAF 拦截已安装');
}
/**
* 拦截 PIXI.Application 构造函数
*/
interceptPIXI() {
const self = this;
// 等 PIXI 加载
const check = setInterval(() => {
if (window.PIXI && window.PIXI.Application) {
clearInterval(check);
self.hookPIXIApplication();
}
}, 500);
}
hookPIXIApplication() {
const self = this;
const OrigApp = window.PIXI.Application;
// 保存原始构造函数
const PatchedApp = function(...args) {
const app = new OrigApp(...args);
stats.pixiApps++;
log(`PIXI.Application 创建 (#${stats.pixiApps})`);
// 标记 canvas
if (app.view) {
app.view.__pixi_app = app;
app.view.__heart_jit_marked = true;
}
// 尝试通过 ticker 找到 Heart
self.tryInjectViaPIXI(app);
return app;
};
// 复制原型
PatchedApp.prototype = OrigApp.prototype;
PatchedApp.prototype.constructor = PatchedApp;
// 替换
window.PIXI.Application = PatchedApp;
log('PIXI.Application 已 hook');
}
/**
* 通过 PIXI app 尝试注入
*/
tryInjectViaPIXI(app) {
// PIXI ticker 会调用 render,而 render 连接到 Heart 的更新循环
// 我们在 ticker 回调中查找 Heart 实例
const self = this;
let checkCount = 0;
const checkTicker = () => {
checkCount++;
if (self.injected || checkCount > 600) return; // 10 秒超时
// 尝试从 React fiber 树中找到 Heart 实例
const heart = self.findHeartFromDOM();
if (heart) {
self.setupJIT(heart);
return;
}
// 继续检查
requestAnimationFrame(checkTicker);
};
requestAnimationFrame(checkTicker);
}
/**
* 从 DOM 中查找 Heart 运行时实例
* 通过 React fiber 树遍历
*/
findHeartFromDOM() {
try {
// 查找 canvas 元素
const canvas = document.querySelector('canvas');
if (!canvas) return null;
// React 16+ fiber 节点
const fiberKey = Object.keys(canvas).find(k =>
k.startsWith('__reactFiber$') || k.startsWith('__reactInternalInstance$')
);
if (!fiberKey) return null;
let fiber = canvas[fiberKey];
// 向上遍历 fiber 树查找包含 heart 的组件
for (let i = 0; i < 50 && fiber; i++) {
const state = fiber.memoizedState;
const props = fiber.memoizedProps;
// 检查 stateNode
if (fiber.stateNode && fiber.stateNode.get_heart) {
const heart = fiber.stateNode.get_heart();
if (heart && heart.get_runtime_manager) {
return heart;
}
}
// 检查 props 中的 heart 引用
if (props && props.get_heart) {
const heart = props.get_heart();
if (heart && heart.get_runtime_manager) {
return heart;
}
}
// 检查 ref
if (fiber.ref && fiber.ref.current && fiber.ref.current.get_heart) {
const heart = fiber.ref.current.get_heart();
if (heart && heart.get_runtime_manager) {
return heart;
}
}
fiber = fiber.return;
}
// 备用:查找全局变量
if (window.__heart) return window.__heart;
if (window.__pixi_app) {
const app = window.__pixi_app;
if (app.__heart) return app.__heart;
}
} catch (e) {
if (CONFIG.debug) warn('DOM 查找失败:', e);
}
return null;
}
/**
* 主注入尝试
*/
tryInject() {
if (this.injected) return true;
const heart = this.findHeartFromDOM();
if (heart) {
this.setupJIT(heart);
return true;
}
// 备用方案:从 Redux store 查找
const store = this.findReduxStore();
if (store) {
const state = store.getState();
// Heart 运行时可能在某个 reducer 的 state 中
if (state.cloud_states && state.cloud_states.loading_state === 'load_done') {
log('检测到作品已加载,尝试从 store 获取 Heart...');
this.tryInjectFromStore(store);
}
}
return false;
}
/**
* 查找 Redux store
*/
findReduxStore() {
// 编程猫用 T.a.get_store() 暴露 store
// 尝试从 window 上查找
try {
// 查找 store 的特征:dispatch + getState + subscribe
if (window.__store) return window.__store;
// 扫描 window 上的对象
for (const key of Object.keys(window)) {
const obj = window[key];
if (obj && typeof obj.dispatch === 'function' &&
typeof obj.getState === 'function' &&
typeof obj.subscribe === 'function') {
return obj;
}
}
} catch (e) {}
return null;
}
/**
* 从 Redux store 尝试注入
*/
tryInjectFromStore(store) {
// 监听 store 变化,当 Heart 初始化完成后注入
const self = this;
let lastState = store.getState();
store.subscribe(() => {
const state = store.getState();
if (state.run_states && state.run_states.run_state === 1 && !self.injected) {
// 游戏正在运行
self.tryInject();
}
lastState = state;
});
}
/**
* 设置 JIT 加速
*/
setupJIT(heart) {
if (this.injected) return;
try {
const rm = heart.get_runtime_manager();
if (!rm) {
warn('Runtime manager 未找到');
return;
}
this.heartRM = rm;
this.injected = true;
stats.heartFound = true;
// 拦截 Interpreter 创建
this.patchInterpreterFactory(rm);
log('✅ Heart JIT 加速器注入成功!');
log(' Heart 运行时已找到,JIT 编译器就绪');
// 通知用户
this.showNotification('Heart JIT 加速器已激活 ⚡');
} catch (e) {
warn('注入失败:', e);
stats.fallbacks++;
}
}
/**
* Patch Interpreter 工厂方法
* 当新的 Interpreter 实例创建时,自动替换其 step 方法
*/
patchInterpreterFactory(rm) {
const self = this;
const jit = this.jit;
// 拦截 load 方法(当积木加载时触发)
const origLoad = rm.load?.bind(rm);
if (origLoad) {
rm.load = function(entities) {
const result = origLoad(entities);
// 加载后 patch 所有 Interpreter
self.patchAllInterpreters(rm);
return result;
};
}
// 拦截 run 方法
const origRun = rm.run?.bind(rm);
if (origRun) {
rm.run = function() {
const result = origRun();
self.patchAllInterpreters(rm);
return result;
};
}
// 立即 patch 已有的 interpreter
this.patchAllInterpreters(rm);
}
/**
* Patch 所有活跃的 Interpreter 实例
*/
patchAllInterpreters(rm) {
// Heart 的 interpreter 通常存储在内部数组中
// 通过遍历 rm 的属性查找
try {
for (const key of Object.keys(rm)) {
const val = rm[key];
if (Array.isArray(val)) {
for (const item of val) {
if (item && typeof item.step === 'function' && !this.patchedInterpreters.has(item)) {
this.patchInterpreter(item);
}
}
}
if (val && typeof val === 'object' && !Array.isArray(val)) {
for (const subKey of Object.keys(val || {})) {
const sub = val[subKey];
if (sub && typeof sub.step === 'function' && !this.patchedInterpreters.has(sub)) {
this.patchInterpreter(sub);
}
}
}
}
} catch (e) {
if (CONFIG.debug) warn('patch interpreters 失败:', e);
}
}
/**
* Patch 单个 Interpreter 实例
*/
patchInterpreter(interpreter) {
if (this.patchedInterpreters.has(interpreter)) return;
this.patchedInterpreters.add(interpreter);
const jit = this.jit;
const origStep = interpreter.step?.bind(interpreter);
if (!origStep) return;
// 获取根积木
const rootBlock = interpreter.root_block;
if (!rootBlock) return;
// JIT 编译
const jittedFn = jit.compile(rootBlock);
if (!jittedFn) return;
// 替换 step 方法
interpreter.step = function() {
stats.executions++;
try {
// 尝试 JIT 执行
const ctx = {
runtime: this.run_mgr || this.runtime_manager || {},
data: this.program_state || {},
eventBus: {},
ohno: {},
entity_id: this.original_entities?.target_entity || '',
interpreter_id: this.original_entities?.interpreter_id || '',
};
jittedFn(ctx);
return { done: true };
} catch (e) {
// 降级到原始解释器
stats.fallbacks++;
return origStep();
}
};
stats.jitted++;
if (CONFIG.debug) log(`Patched interpreter: ${rootBlock.type || 'unknown'}`);
}
/**
* 显示通知
*/
showNotification(msg) {
try {
const div = document.createElement('div');
div.style.cssText = `
position:fixed;top:20px;left:50%;transform:translateX(-50%);
background:linear-gradient(135deg,#0f0,#0a0);color:#fff;
padding:12px 24px;border-radius:8px;font-family:monospace;font-size:14px;
z-index:999999;box-shadow:0 4px 20px rgba(0,255,0,0.3);
animation:jit-fade 3s forwards;
`;
div.textContent = msg;
document.body.appendChild(div);
// 添加动画
const style = document.createElement('style');
style.textContent = `
@keyframes jit-fade {
0% { opacity: 0; transform: translateX(-50%) translateY(-20px); }
20% { opacity: 1; transform: translateX(-50%) translateY(0); }
80% { opacity: 1; }
100% { opacity: 0; transform: translateX(-50%) translateY(-10px); }
}
`;
document.head.appendChild(style);
setTimeout(() => div.remove(), 3000);
} catch (e) {}
}
/**
* 性能监控
*/
startProfiling() {
setInterval(() => {
if (this.injected && CONFIG.debug) {
log(`Stats: jitted=${stats.jitted}, exec=${stats.executions}, fallback=${stats.fallbacks}, compile=${stats.compileTime.toFixed(1)}ms`);
}
}, CONFIG.profileInterval);
}
}
// ================================================================
// 性能面板
// ================================================================
class PerfPanel {
constructor() {
this.el = null;
this.interval = null;
}
show() {
if (this.el) return;
const panel = document.createElement('div');
panel.id = 'heart-jit-panel';
panel.style.cssText = `
position:fixed;top:10px;right:10px;z-index:999999;
background:rgba(0,0,0,0.9);color:#0f0;font-family:'Courier New',monospace;
font-size:11px;padding:10px 14px;border-radius:6px;border:1px solid #0f0;
min-width:200px;box-shadow:0 0 15px rgba(0,255,0,0.2);
cursor:move;user-select:none;
`;
const title = document.createElement('div');
title.style.cssText = 'font-size:13px;font-weight:bold;margin-bottom:6px;color:#0f0;border-bottom:1px solid #030;padding-bottom:4px;';
title.textContent = '🐱 Heart JIT v3.1';
panel.appendChild(title);
const content = document.createElement('div');
content.id = 'jit-stats';
panel.appendChild(content);
// 拖拽
let dragging = false, ox, oy;
panel.addEventListener('mousedown', e => { dragging=true; ox=e.clientX-panel.offsetLeft; oy=e.clientY-panel.offsetTop; });
document.addEventListener('mousemove', e => { if(dragging){panel.style.left=(e.clientX-ox)+'px';panel.style.top=(e.clientY-oy)+'px';panel.style.right='auto';} });
document.addEventListener('mouseup', () => dragging=false);
// 右键切换 debug
panel.addEventListener('contextmenu', e => { e.preventDefault(); CONFIG.debug=!CONFIG.debug; });
document.body.appendChild(panel);
this.el = content;
this.interval = setInterval(() => this.update(), 500);
}
update() {
if (!this.el) return;
const s = stats;
const status = s.heartFound ? '✅ 已注入' : '⏳ 等待...';
this.el.innerHTML = `
<div>状态: <span style="color:${s.heartFound?'#0f0':'#ff0'}">${status}</span></div>
<div>JIT 函数: <span style="color:#0ff">${s.jitted}</span></div>
<div>执行次数: <span style="color:#0f0">${s.executions}</span></div>
<div>降级: <span style="color:#f00">${s.fallbacks}</span></div>
<div>编译耗时: <span style="color:#888">${s.compileTime.toFixed(1)}ms</span></div>
<div style="margin-top:4px;font-size:9px;color:#555">右键切换debug</div>
`;
}
destroy() {
if (this.interval) clearInterval(this.interval);
if (this.el?.parentElement) this.el.parentElement.remove();
}
}
// ================================================================
// 主入口
// ================================================================
function main() {
log('🚀 Heart JIT 加速器 v3.1 启动');
log(' 渲染层: PIXI.js (WebGL) — 无需替换');
log(' 目标: Heart 解释器 → JIT 编译为原生 JS');
const injector = new HeartJITInjector();
injector.install();
// 性能面板
if (location.href.includes('player.codemao.cn') || location.href.includes('ide.codemao.cn')) {
const panel = new PerfPanel();
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => setTimeout(() => panel.show(), 500));
} else {
setTimeout(() => panel.show(), 500);
}
}
// 暴露 API
window.__heartJIT = { injector, stats, CONFIG, version: '3.1.0' };
log('✅ 就绪,等待作品加载...');
}
// 启动
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', main);
} else {
main();
}
})();