4.7 KiB
4.7 KiB
| name | description |
|---|---|
| runtime | 元景 W-10 运行时执行引擎模块(前端 JS 引擎 + 可选服务端辅助)。世界运行时初始化、实体状态、脚本执行调度、事件分发、定时器、碰撞检测、暂停恢复、错误降级、独立世界本地引擎。开发/修改 runtime 相关功能前必读。 |
runtime 模块(W-10 运行时执行引擎)
架构
wwwroot/runtime.js 前端核心引擎(RuntimeEngine 类,事件循环 tick 驱动)
wwwroot/play.html 游戏运行页(画布 + 日志 + 控件,验收入口)
wwwroot/index.ui 模块入口页(bricks)
wwwroot/api/*.dspy 可选服务端辅助(load_world / runtime_status / runtime_event / runtime_control)
runtime/runtime_service.py 服务端辅助实现(ServerEnv 注册,无自有数据表,只读复用 world 模块)
scripts/load_path.py RBAC 路径注册(any/logined 分层,禁通配符)
- 运行时引擎核心在前端 JS(浏览器本地执行,事件循环 + 实体状态 + 脚本执行)。
- 服务端辅助是可选的:
/runtime/api/load_world.dspy从 world 模块读取世界与实体; 后端不可用/查无数据时前端自动降级独立模式(W-10i),本地构建演示世界继续运行。 - 本模块为交互层模块,无自有数据表(无 models/、json/、init/)。
功能点映射(W-10a ~ W-10i)
| 功能点 | 实现位置 | 验收口径 |
|---|---|---|
| W-10a 世界运行时初始化(构建运行态实体树) | runtime.js initWorld/buildTree + api/load_world.dspy |
开始玩即初始化实体树,实体可点击 |
| W-10b 实体运行时状态管理 | makeEntity / state 机(idle/active/done/failed) |
点击后实体 state 变化并绘制 |
| W-10c 脚本运行时执行调度 | executeScript/executeAction(与 script_engine 编译产物 actions 对接) |
点击触发脚本动作执行 |
| W-10d 事件分发(路由到对应脚本) | dispatchEvent/processEvents/_routeEvent |
click/timer/collide 事件路由到实体绑定脚本 |
| W-10e 定时器管理 | addTimer/processTimers(tick 驱动,非 setInterval) |
定时器按间隔触发脚本 |
| W-10f 碰撞检测 | checkCollisions(AABB 两两检测) |
移动后实体碰撞触发 onCollide |
| W-10g 运行时暂停/恢复 | pause/resume/stop + api/runtime_control.dspy |
暂停后 tick 挂起,恢复继续 |
| W-10h 错误处理与降级 | handleError(try/catch 捕获,单脚本失败不整页崩溃) |
故意抛错脚本 → 日志记录错误,引擎继续运行 |
| W-10i 独立世界本地引擎 | _localWorldEntities + initWorld 降级分支 |
后端不可用仍可本地构建世界运行 |
脚本对接契约(script_engine 编译产物格式)
{ "id": "script_click", "name": "点击响应",
"actions": [
{"op": "log", "message": "..."},
{"op": "set_state", "state": "active"},
{"op": "move", "dx": 12, "dy": 0},
{"op": "emit", "event": "active_changed", "entity_id": "hero", "payload": {}},
{"op": "delay", "ms": 1000},
{"op": "fail", "message": "故意抛错"}
]}
实体绑定脚本:props.scripts = ["script_click", ...];碰撞回调:props.onCollide = "script_id"。
DSPY 端点
GET /runtime/api/load_world.dspy?world_id=xxx→{ok, degraded, mode, world, entities}GET /runtime/api/runtime_status.dspy?runtime_id=xxx→{runtime_id, running, paused, mode, entities, events, errors}POST /runtime/api/runtime_event.dspy(event_type/entity_id/payload)→{ok, queued}POST /runtime/api/runtime_control.dspy(action=start/pause/resume)→{ok, action, running, paused}
RBAC 路径(scripts/load_path.py 已注册)
any:/runtime/runtime.jslogined:/runtime、/runtime/index.ui、/runtime/play.html、/runtime/api/*.dspy(4 个显式)
陷阱
- dspy 禁项:dspy 内禁 import / f-string / print / uuid —— 全部用 ServerEnv 注入全局
(
load_world_runtime等),return显式返回。 - 三处同步注册:新增服务端函数必须同步 ① runtime_service.py ② runtime/init.py
③ runtime/init.py
env.xxx = xxx,漏一处 → NameError。 - 取库名禁硬编码:服务端辅助用
ServerEnv().get_module_dbname('world'),禁止写死 DBNAME。 - DictObject 不可 dict():读 world 记录用
_row_to_dict逐字段 getattr。 - 前端引擎不依赖 setInterval:定时器/帧循环用
setTimeout自调度 + tick 驱动, bricks script actiontype 禁止 fetch/setInterval(play.html 是独立 HTML,不受此限)。 - 降级优先:服务端任何异常都返回
ok=True, degraded=True,绝不抛 500 —— 前端据此切独立模式。