diff --git a/src/api.js b/src/api.js index 3496da2..ecf074a 100644 --- a/src/api.js +++ b/src/api.js @@ -97,3 +97,127 @@ const ENDPOINTS = [ ]; module.exports = { ENDPOINTS, DOMAINS }; + +// 已知积木类型 (从编辑器代码逆向) +const BLOCK_TYPES = { + // 事件 + 'sprite_on_tap': '角色点击事件', + 'event_when_run': '当绿旗被点击', + 'event_when_key': '当按下按键', + 'event_when_receive': '当接收到广播', + 'event_broadcast': '广播消息', + 'event_broadcast_wait': '广播并等待', + 'scene_on_tap': '场景点击事件', + 'stage_on_tap': '舞台点击事件', + 'self_on_start_as_clone': '当作为克隆体启动', + 'self_listen_with_param': '监听事件', + + // 动作 + 'move': '移动', + 'turn_right': '右转', + 'turn_left': '左转', + 'goto_xy': '移到坐标', + 'glide_to_xy': '滑行到坐标', + 'set_x': '设置 x', + 'set_y': '设置 y', + 'change_x': 'x 增加', + 'change_y': 'y 增加', + 'point_dir': '面向方向', + 'point_towards': '面向角色', + 'if_on_edge_bounce': '碰边缘反弹', + 'set_rotation_style': '设置旋转方式', + + // 外观 + 'show': '显示', + 'hide': '隐藏', + 'say': '说话', + 'say_for': '说话(限时)', + 'self_prev_next_style': '切换造型', + 'self_set_style': '设置造型', + 'set_size': '设置大小', + 'change_size': '大小增加', + 'set_effect': '设置特效', + 'change_effect': '特效增加', + 'clear_effects': '清除特效', + 'go_to_layer': '移到图层', + + // 控制 + 'wait': '等待', + 'repeat': '重复', + 'forever': '重复执行', + 'if': '如果', + 'if_else': '如果...否则', + 'repeat_until': '重复直到', + 'wait_until': '等待直到', + 'stop': '停止', + 'clone': '克隆', + 'dispose_clone': '删除克隆体', + + // 侦测 + 'touching': '碰到角色', + 'touching_color': '碰到颜色', + 'color_touching_color': '颜色碰颜色', + 'ask': '询问', + 'get_mouse_x': '鼠标 x', + 'get_mouse_y': '鼠标 y', + 'is_mouse_down': '按下鼠标', + 'get_timer': '计时器', + 'reset_timer': '重置计时器', + + // 运算 + 'add': '加法', + 'subtract': '减法', + 'multiply': '乘法', + 'divide': '除法', + 'random': '随机数', + 'gt': '大于', + 'lt': '小于', + 'equals': '等于', + 'and': '且', + 'or': '或', + 'not': '不是', + 'join': '连接', + 'length': '长度', + 'mod': '取余', + 'round': '四舍五入', + 'math_op': '数学运算', + + // 变量 + 'set_variable': '设置变量', + 'change_variable': '变量增加', + 'get_variable': '获取变量', + 'add_to_list': '添加到列表', + 'delete_of_list': '删除列表项', + 'insert_at_list': '插入列表项', + 'replace_at_list': '替换列表项', + 'item_of_list': '列表项', + 'item_num_of_list': '列表项编号', + 'length_of_list': '列表长度', + 'list_contains': '列表包含', + + // 声音 + 'play_sound': '播放声音', + 'stop_all_sounds': '停止所有声音', + + // 画笔 + 'pen_down': '落笔', + 'pen_up': '抬笔', + 'pen_clear': '清除画笔', + 'pen_set_color': '设置画笔颜色', + 'pen_set_size': '设置画笔粗细', + + // AI + 'ai_text_actor': 'AI 文本识别(角色)', + 'ai_text_photo': 'AI 拍照识别', + 'ai_text_result': 'AI 识别结果', + 'ai_chat_ask': 'AI 聊天提问', + 'ai_chat_answer': 'AI 聊天回答', + + // 硬件 + 'microbit_display': 'micro:bit 显示', + 'microbit_get_button': 'micro:bit 按钮', + 'tudao_motor': '途道电机', + 'tudao_servo': '途道舵机', +}; + +module.exports = { ENDPOINTS, DOMAINS, BLOCK_TYPES }; diff --git a/src/bcm.js b/src/bcm.js index 5e617bd..6abd06a 100644 --- a/src/bcm.js +++ b/src/bcm.js @@ -67,11 +67,13 @@ function listActors(bcm) { } function listBlocks(bcm) { + const { BLOCK_TYPES } = require('./api'); const result = []; Object.values(bcm.actors?.actorsDict || {}).forEach(a => { (a.nekoBlockJsonList || []).forEach((b, i) => { const bj = typeof b === 'string' ? JSON.parse(b) : b; - result.push({ actor: a.name, index: i, type: bj.type, id: bj.id, hasNext: !!bj.next }); + const desc = BLOCK_TYPES[bj.type] || ''; + result.push({ actor: a.name, index: i, type: bj.type, desc, id: bj.id, hasNext: !!bj.next }); }); }); return result; diff --git a/src/index.js b/src/index.js index 14d9259..650dcf3 100755 --- a/src/index.js +++ b/src/index.js @@ -161,8 +161,8 @@ commands.bcm = { let lastActor = ''; blocks.forEach(b => { if (b.actor !== lastActor) { console.log(`\n[${b.actor}]`); lastActor = b.actor; } - const next = b.hasNext ? ' → ...' : ''; - console.log(` ${b.index}: ${b.type} (${b.id})${next}`); + const desc = b.desc ? ` [${b.desc}]` : ''; const next = b.hasNext ? ' → ...' : ''; + console.log(` ${b.index}: ${b.type} (${b.id})${desc}${next}`); }); } else if (sub === 'extract') { const bcm = BCM.parse(file); @@ -300,6 +300,26 @@ commands.download = { } }; + +// ─── blocks: 积木类型一览 ─── + +commands.blocks = { + desc: '显示所有已知积木类型', + run(args) { + const { BLOCK_TYPES } = require('./api'); + const filter = args[0]; + let entries = Object.entries(BLOCK_TYPES); + if (filter) { + const f = filter.toLowerCase(); + entries = entries.filter(([k, v]) => k.includes(f) || v.includes(f)); + } + console.log(`\n已知积木类型 (${entries.length}):\n`); + printTable(['类型', '说明'], entries.map(([k, v]) => [k, v])); + console.log(); + } +}; + + // ─── version / help ─── commands.version = {