Skip to content

Latest commit

 

History

History
690 lines (483 loc) · 36.5 KB

File metadata and controls

690 lines (483 loc) · 36.5 KB

ScriptContext(ctx)API 参考文档

用户脚本入口函数 def tick(ctx): ... 中的 ctx 类型为 ScriptContext(定义于 core/script_context.py)。它是脚本与 VisionScript 运行时交互的唯一推荐入口:截图、感知/识别、键鼠执行、日志、向 UI 发事件、读写全局状态、使用事件总线。

相关代码core/script_context.pycore/script_host.pycore/world_state.pycore/script_manifest.pyexecutor/actions.pycore/event_bus.pycore/visionscript_events.py


目录

  1. API 总览
  2. API 详解
  3. 脚本生命周期与主循环
  4. 属性(简明)
  5. 日志 log
  6. UI 脚本事件 emit_ui / emit_ui_sync
  7. 截图 capture_frame / release_capture
  8. 感知流水线与识别
  9. 可中断等待与录制回放
  10. 事件总线 ctx.bus
  11. 世界状态 ctx.state
  12. 动作执行器 ctx.actions
  13. 清单 ctx.manifest
  14. 事件类型常量
  15. 示例
  16. 注意事项汇总

一、API 总览

1.1 公开成员一览

成员 类别 说明
ctx.manifest 属性 当前脚本的 ScriptManifest(路径、入口、fps、capture、perception 等)
ctx.state 属性 全局 WorldState(暂停/停止、fps、扩展数据等)
ctx.bus 属性 EventBus,与 UI/其它模块通讯
ctx.actions 属性 ActionExecutor,键鼠高层 API
ctx.finish() 方法 state.stop_requested 置为 True,结束引擎主循环
ctx.log(msg, level="info") 方法 同步发 ui.log 并写文件日志
ctx.emit_ui(name, **kwargs) 方法 异步发送 ui.script 自定义事件
ctx.emit_ui_sync(name, **kwargs) 方法 同步发送 ui.script
ctx.capture_frame() 方法 返回一帧 BGR 图像,或 None
ctx.release_capture() 方法 释放窗口捕获资源(由引擎在脚本卸载时也会调用)
ctx.perception_pipeline 属性 未启用则为 None;否则为 PerceptionPipeline 实例
ctx.recognition_runner() 方法 懒加载 RecognitionRunner(可带 OCR)
ctx.run_perception(frame_bgr) 方法 对整帧跑感知流水线,未启用则 None
ctx.make_template_match_ro(...) 方法 构造模板匹配用的 RecognitionObject
ctx.run_recognition(frame_bgr, ro) 方法 对整帧执行给定识别配置
ctx.wait_interruptible(seconds, slice_s=0.05) 方法 可被打断的睡眠(响应 stop_requested
ctx.run_recorded_ops(steps) 方法 执行录制器生成的步骤元组

1.2 用户不应依赖的内部细节

  • 以下划线开头的懒加载字段(_window_capture_screen_capture_pipeline_recognition_runner)为内部实现,勿在脚本中访问。
  • ScriptContext 无公开继承扩展点;逻辑放在用户脚本的模块级状态或 ctx.state.extras 中即可。

二、 API 详解

本节与源码逐项对齐,涵盖 ScriptContext 全部公开成员,以及通过 ctx.state / ctx.bus / ctx.actions / ctx.manifest 暴露的子对象 API。第三节起为按主题归纳的简明版与示例表,便于速查;细节若有出入以本节为准。

以下按「从 ctx 能访问到什么」说明:用途、签名、行为、返回值、典型用法与注意。实现均以 core/script_context.py 及嵌套类型源码为准。


ctx.manifestScriptManifest

  • 用途:只读使用当前运行脚本的项目元数据与 visionscript / YAML 中的运行时配置(截图模式、感知开关、OCR 语言、fps 等)。构造 ScriptContext 时已注入,脚本内不要重新赋值。
  • 主要字段project_rootmanifest_pathnamescript_versionentryentry_pathlibraryfpscaptureCaptureSection)、perceptionPerceptionSection)、uiraw
  • 注意entry_pathproject_root / entry 的绝对路径;library 目录在宿主初始化时已加入 sys.path,用于脚本侧 import 扩展模块。

ctx.stateWorldState

  • 用途:与引擎、UI 共享的唯一运行时状态(暂停、停止、帧率、UI 命令、扩展字典等)。脚本可读写其中多数字段;ui_command / ui_payload 的并发写入由内部锁保护。
  • ctx.manifest 的关系ScriptRuntimeModule.init 会把解析后的 ScriptManifest 赋给 state.manifest,并把 target_fps 设为清单 fps
  • 注意:修改 stop_requested 与调用 ctx.finish() 等价于请求结束;pause 为真时本帧不会调用 tick(ctx),因此暂停期间脚本逻辑完全静止。

ctx.busEventBus

  • 用途:类型为 core.event_bus.EventBus,在 Engine.start() 时已 start(),后台线程从队列取事件并 _dispatch。脚本通过 emit / emit_syncon / off 与 UI 或其它模块通讯。
  • 线程语义emit 将事件放入队列,处理可能发生在另一线程emit_sync当前调用线程立即执行所有订阅者,便于与 UI 同步但需注意重入与耗时回调阻塞主循环。
  • 注意:队列满时 emit丢弃事件并记日志;脚本侧一般不要 bus.stop()(由引擎管理生命周期)。

ctx.actionsActionExecutor

  • 用途:封装 MouseControllerKeyboardController 的高层键鼠 API(点击、拖拽、快捷键、组合动作、等待等)。ScriptContext.__init__ 中固定 ActionExecutor(),即默认 human_like=True
  • 属性mousekeyboard 为底层控制器;human_like 为可读实例属性,控制 navigate_click / click_at 等路径上的随机短延迟。
  • 注意wait(seconds) 使用 time.sleep不会检查 stop_requested;需要可中断等待请用 ctx.wait_interruptible 或在循环里自判 ctx.state.stop_requested

ctx.finish()None

  • 签名finish() -> None
  • 行为self.state.stop_requested = True,无其它副作用。
  • 用途:显式声明「本脚本逻辑结束」,引擎主循环退出;脚本队列场景下可衔接下一脚本。
  • 等价写法ctx.state.stop_requested = True;或与 tickreturn False(字面量)结合 ScriptHost.tick_once 的约定等价。

ctx.wait_interruptible(seconds, slice_s=0.05)None

  • 参数seconds 总等待时长(秒),<=0 立即返回;slice_s 每小段最长睡眠,内部夹紧为 >=0.01,且每段不超过剩余时间。
  • 行为:循环直到 time.perf_counter() 到达终点;任意时刻若 state.stop_requested 则提前返回。用于替代长 time.sleep,使停止/结束更快生效。
  • 注意不响应 pause(暂停在帧边界不进入 tick);若在 tick无法调用(脚本只能在 tick跑)。

ctx.run_recorded_ops(steps)None

  • 参数steps元组,元素为子元组,首元素标签支持
    "w"|"c"|"t"|"k"|"D"|"U"|"Bd"|"Bu"|"m"|"h"|"H"|"M"|"s"
  • 行为:按顺序执行;每一步开始前stop_requestedreturn
    • ("w", t)wait_interruptible(t)
    • ("c", x, y, button)actions.click_at(...)
    • ("t", text)actions.type_text(text)
    • ("k", key)actions.keyboard.key_press(key)
    • ("D", key) / ("U", key)actions.keyboard.key_down(key) / key_up(key)
    • ("h", ("ctrl","s"))actions.shortcut(*keys)
    • ("H", key, sec)actions.keyboard.hold_key(key, sec)
    • ("M", ("shift","w"), sec) → 依次 key_down 组合键,等待 sec(可中断),再逆序 key_up
    • ("m", x, y)mouse.move_to(x, y, smooth=False) 瞬时定位(避免默认类人贝塞尔导致轨迹回放极慢)
    • ("Bd", button, x, y) / ("Bu", button, x, y) → 先瞬时 move_to,再 mouse_down / mouse_up
    • ("s", amount, direction)actions.mouse.scroll(...)
  • 注意:当前录制器已改为按键原子事件(key_down / key_up)并在生成阶段换算为 D/U(以及必要的 h/H/M);如需保证“按住主键不被组合拆断”,优先依赖 D/U 序列。

ctx.log(msg, level="info")None

  • 参数msg 文本;level 字符串,用于 UI 与文件侧日志级别。
  • 行为:先 emit_sync(UI_LOG, {"message": msg, "level": level}),再按 _LOG_LEVEL_NUM(仅识别 debug/info/warning/error)映射到数值 logger.log;未知级别按数值 20(info) 写入文件 logger。
  • 注意:UI 收到的 level 为原始字符串;仅当你依赖「文件日志级别数值」时,才受未知字符串回落影响。

ctx.emit_ui(name, **kwargs)None

  • 行为bus.emit(UI_SCRIPT, {"name": name, **kwargs}),异步队列。
  • 用途:向订阅 ui.script 的界面发业务事件(名称 + 任意命名参数),不阻塞当前 tick 返回后的后续逻辑(但 emit 入队本身很快)。

ctx.emit_ui_sync(name, **kwargs)None

  • 行为bus.emit_sync(UI_SCRIPT, {"name": name, **kwargs}),当前线程立即分发。
  • 用途:需要同一调用栈内 UI 已更新时用;避免在处理器里再同步 emit_sync 造成死锁。

ctx.capture_frame()Optional[np.ndarray]

  • 返回值:成功为 BGR uint8 ndarray(H,W,3);失败 None
  • 行为:若 manifest.capture.mode == "screen",懒加载 ScreenCapturegrab();否则走 _grab_window():懒加载 WindowCapture(hwnd, title_pattern)resolve() 失败则打警告日志并 None;否则首次 grab() 前可按 auto_fix_win11_bitblt 调用 start(settings)
  • 注意屏幕模式与窗口模式各自缓存一个捕获器实例;切换清单配置通常需换脚本进程或自行理解缓存生命周期。

ctx.release_capture()None

  • 行为:若存在 _window_captureclose() 并置 None不释放 _screen_capture(全屏捕获器无对称逻辑于此方法)。
  • 用途:释放窗口 DC/钩子等;ScriptHost.close() 也会调用。

ctx.perception_pipeline(property)→ Optional[PerceptionPipeline]

  • 行为:若 manifest.perception.use_pipeline 为假 → None;否则懒加载 PerceptionPipeline,并按配置注册 UIRecognizer
  • 用途:需要直接访问流水线实例时(多数情况用 run_perception 即可)。

ctx.recognition_runner()RecognitionRunner

  • 行为:懒加载单例;首次创建时尝试 PaddleOCREngine(lang=perception.ocr_lang),异常则 ctx.log 警告且 OCR 为 None,仍构造 RecognitionRunner(ocr=None)
  • 用途:模板匹配不强制 OCR;但若要用 OCR,需保证依赖安装否则仅有模板等分支可用。

ctx.run_perception(frame_bgr)Optional[Dict[str, Any]]

  • 参数:一帧 BGR 图像。
  • 返回值:流水线未启用 None;否则 perception_pipeline.process(frame_bgr),字典结构由感知模块定义。
  • 注意:与 run_recognition 不同:前者跑整条流水线,后者跑单个 RecognitionObject

ctx.make_template_match_ro(template_bgr, *, threshold=0.8, roi=None, use_mask=False, use_3_channels=False, name="")

  • 返回值RecognitionObject(感知模块类型)。
  • 行为RecognitionObject.template_match(...) 后设置 use_3_channels提前加载 recognition_runner
  • 参数要点roi 为整图上的 (x,y,w,h)use_mask 按模块约定处理纯绿背景;name 便于调试日志。

ctx.run_recognition(frame_bgr, ro)RecognitionResult

  • 行为recognition_runner().run(frame_bgr, ro)
  • 用途:对单帧、单配置做匹配/OCR 等;结果对象字段见 perception 包(如 successtemplate_hits)。

WorldState 字段与方法(经 ctx.state

符号 详解
script_manifest_path 解析清单时设置的路径;脚本只读为宜。
pause 由 UI ui.command 同步处理器写入;为真时 ScriptRuntimeModule.tick 不调用用户 tick
stop_requested 停止请求;为真时引擎主循环退出且不再 tick_once
target_fps 主循环睡眠用;运行时模块会把清单 fps 同步进来。
ui_command / ui_payload 自定义 UI 命令槽;set_ui_command 写入,consume_ui_command 读取并清空。每帧 tick由运行时调用 consume_ui_command(),故你在本轮 **tick 内读到的应是「已被清空后的」状态——若需在本帧处理命令,应使用 EventBus 订阅 UI_COMMAND 或在文档约定的其它路径获取(见运行时实现)。
manifest 当前 ScriptManifest 引用。
extras 任意可序列化/不可序列化 Python 对象字典,脚本用于跨 **tick 或跨模块共享;无自动持久化。
set_ui_command(cmd, payload=None) 线程安全写入命令。
consume_ui_command() 返回 (cmd: str, payload: dict) 并清空内部存储。

EventBus 方法(经 ctx.bus

符号 详解
on(event_type, handler) 注册 handler(Event);多处理器按注册顺序在 _dispatch 中调用。
off(event_type, handler) 需传入同一函数对象引用方可移除。
emit(event_type, payload=None, source="") 构造 Event 入队;异步处理。
emit_sync(event_type, payload=None, source="") 立即 _dispatch;同一 event_type 的所有 handler 同步执行。

Eventtypepayloadsourcetimestamp


ActionExecutor(经 ctx.actions

符号 详解
human_like 若为真,navigate_clickdrag_between 等路径上 _human_delay 随机延迟;为假时延迟更短。
click_at(x, y, button="left", random_offset=0, clicks=1) random_offset>0,在 ±random_offset 内随机修正坐标,再 mouse.click
click_region(region, button="left", clicks=1) region=(left,top,right,bottom),在矩形内均匀随机选点再 click_at
navigate_click(x, y, pre_delay=0.0, post_delay=0.0) 可选前置/后置 sleep,再 move_to → 人性化延迟 → click
drag_between(x1,y1,x2,y2, button="left") 移动到起点 → 短延迟 → drag_to 终点。
shortcut(*keys) 展开为 keyboard.hotkey(*keys)
type_text(text, interval=None) keyboard.typewrite;长文本期间不检查停止。
combo_action(actions) 遍历 dict 列表,按 type 分发到 _execute_action;未知类型 warning。
wait(seconds) time.sleep(seconds),不可被 stop_requested 打断。
wait_for(predicate, timeout=5.0, interval=0.1) 轮询 predicate(),超时返回 False默认检查 stop_requested,可在 **predicate 内自行判断。
mouse MouseControllerexecutor/mouse.py):见下表。
keyboard KeyboardControllerexecutor/keyboard.py):见下表。

MouseController 常用公开方法move_tomove_relativeclick(可选坐标与 buttonclicks)、double_clickscroll(amount, direction="vertical")drag_todrag_relativemouse_down / mouse_upget_positionis_on_screen

KeyboardController 常用公开方法key_down / key_upkey_press(可选 presses)、hotkey(*keys)hold_keytypewritepress_sequenceis_key_pressed


ScriptManifest 与配置段(经 ctx.manifest

字段 详解
project_root 清单所在目录(绝对路径);入口 entry、资源路径均相对此目录。
manifest_path 当前清单文件路径;目录加载 manifest.json 时非空。
manifest_version 清单格式版本号(整数)。
name / script_version / description / authors 展示与发布用元数据;不影响运行时逻辑。
library 相对 project_root 的额外源码目录列表;存在目录会被插入 sys.path(见 ScriptHost._prepend_search_paths)。
entry 入口模块相对路径(如 tick.py);与 main(JSON)同源字段。
entry_path project_root / entry 解析后的绝对路径;用户 tick 所在文件。
fps 建议主循环帧率;运行时写入 state.target_fps
capture CaptureSectionmodewindow | screen)、title_patternhwndauto_fix_win11_bitblt → 决定 capture_frame 行为。
perception PerceptionSectionuse_pipelineregister_ui_recognizerocr_lang → 流水线与 OCR。
ui 自定义键值,供脚本或扩展读取(引擎核心不强制解释)。
raw 解析后的原始字典(JSON/YAML),便于读取未建模字段。

事件常量(core/visionscript_events

工程约定字符串,供 bus.emit / 订阅 与文档交叉引用:UI_COMMANDUI_LOGUI_STATEUI_SCRIPTUI_ERRORUI_SCRIPT_LOADED。脚本侧**ctx.log** 使用 UI_LOGemit_ui* 使用 UI_SCRIPT;用户脚本异常由 ScriptHostUI_ERROR


三、脚本生命周期与主循环

2.1 引擎如何调用 tick

  • 引擎按清单中的 fpsctx.manifest.fps → 同步到 ctx.state.target_fps)驱动主循环;每一帧会调用已注册运行时模块的 tick,其中 ScriptRuntimeModule.tick 在用户脚本未停止且未暂停时调用 ScriptHost.tick_once(),进而执行用户脚本的 tick(ctx)
  • state.pause == True:本帧不会调用 tick(ctx)(脚本完全暂停)。
  • state.stop_requested == True:主循环即将退出;同一帧内脚本 tick 也会因 ScriptRuntimeModule 提前 return 而不再执行。

因此:长时间阻塞且不使用 wait_interruptibletime.sleep,会拖慢整帧、且无法在等待期间响应暂停(暂停是在帧边界生效的)。

2.2 ctx.finish() -> None

等同于 ctx.state.stop_requested = True。用于声明「当前脚本任务已完成」,引擎主循环结束;在 GUI 脚本队列 中,结束后会自动加载下一脚本(见 script_queue.md)。

2.3 tick 的返回值

ScriptHost.tick_once 中:

  • tick 显式 return False(必须为字面量 False),运行时会设置 state.stop_requested = True,效果与 finish() 相同。
  • returnreturn None、不写 return不会结束脚本。
  • return 0return [] 等其它假值不会触发结束。

四、属性(简明)

属性 类型 说明
ctx.manifest ScriptManifest 当前脚本清单(解析自 YAML/JSON 或项目 manifest.json
ctx.state WorldState 全局运行时状态
ctx.bus EventBus 事件总线实例(引擎启动时已 start()
ctx.actions ActionExecutor 默认 human_like=True,操作带轻微随机延迟

五、日志 log

ctx.log(msg: str, level: str = "info") -> None

行为:

  1. emit_sync(UI_LOG, {"message": msg, "level": level}) — 同步派发,UI 侧订阅 ui.log 可立即更新日志面板等。
  2. 使用内部 _LOG_LEVEL_NUM 将字符串级别映射为数值后写入 core.script_context 模块 logger,从而进入文件日志体系。

支持的 level(大小写不敏感,strip 后匹配): "debug""info""warning""error"。其它字符串会按数值 20(info) 写入 logger。

建议: 业务脚本统一使用上述四类字符串,避免依赖「未知级别回落为 info」的细节。


六、UI 脚本事件 emit_ui / emit_ui_sync

二者均向 UI_SCRIPT(事件类型字符串 "ui.script")派发,payload 形状为:

{"name": name, **kwargs}

例如 ctx.emit_ui("battle_start", hp=100) → payload 为 {"name": "battle_start", "hp": 100}

方法 派发方式 适用场景
ctx.emit_ui(name, **kwargs) bus.emit → 入队异步处理 一般业务事件,不阻塞脚本线程
ctx.emit_ui_sync(name, **kwargs) bus.emit_sync → 立即在同线程调用订阅者 需要同一调用栈内立刻刷新 UI 时(注意避免重入与死锁)

主窗口是否展示脚本事件取决于 UI 是否订阅 ui.script;可自行扩展。


七、截图 capture_frame / release_capture

ctx.capture_frame() -> Optional[np.ndarray]

  • 返回值:成功为 numpy.ndarrayBGRuint8,形状 (H, W, 3);失败为 None
  • 模式由清单 ctx.manifest.capture.mode 决定:
    • "screen":全屏捕获;懒加载 capture.ScreenCapture,调用 grab()
    • "window"(默认):窗口客户区;懒加载 capture.WindowCapture,使用 title_pattern 和/或 hwnd 解析窗口。
  • 窗口模式首次 grab() 前若 resolve() 失败,会 ctx.log(..., "warning") 并返回 None
  • 若清单 capture.auto_fix_win11_bitblt 为真,start({"auto_fix_win11_bitblt": True})

JSON 清单中上述字段位于 visionscript.capture(兼容旧键 vhsr)。YAML 清单可为根级 capture

ctx.release_capture() -> None

关闭窗口捕获实例(若存在),重置内部引用。ScriptHost.close() 在脚本宿主卸载时会调用,用于释放 DXGI/GDI 等资源。若你在脚本内切换截图策略或长时间不用窗口捕获,可主动调用。


八、感知流水线与识别

ctx.perception_pipeline(只读属性)

  • manifest.perception.use_pipelineFalseNone
  • 否则懒加载 PerceptionPipeline;若 register_ui_recognizer 为真,会 register_source(UIRecognizer())

ctx.run_perception(frame_bgr: np.ndarray) -> Optional[Dict[str, Any]]

  • 流水线未启用 → None
  • 否则 perception_pipeline.process(frame_bgr),返回字典(具体键由感知模块定义)。

ctx.recognition_runner() -> RecognitionRunner

  • 首次调用时尝试构造 PaddleOCREngine(lang=manifest.perception.ocr_lang);失败则 ctx.log("OCR 未启用: ...", "warning"),OCR 为 None,但 RecognitionRunner 仍可用于模板匹配等。
  • ocr_lang 来自清单 perception.ocr_lang(默认 "ch")。

ctx.make_template_match_ro(template_bgr, *, threshold=0.8, roi=None, use_mask=False, use_3_channels=False, name="") -> RecognitionObject

  • 内部调用 RecognitionObject.template_match(...),再设置 ro.use_3_channels
  • 不会单独触发 recognition_runner 的懒加载;首次 run_recognition 仍会加载运行器。

ctx.run_recognition(frame_bgr: np.ndarray, ro: RecognitionObject) -> RecognitionResult

等价于 ctx.recognition_runner().run(frame_bgr, ro)。返回值类型由 perception 包定义(如 successtemplate_hitserror 等属性)。


九、可中断等待与录制回放

ctx.wait_interruptible(seconds: float, slice_s: float = 0.05) -> None

  • seconds <= 0:立即返回。
  • 否则循环:state.stop_requested 则立刻返回;否则 time.sleep(min(slice_s, 剩余时间))slice_s 下限夹紧为 0.01
  • 用于在长等待期间响应 UI 停止(以及任何将 stop_requested 置位的逻辑)。

ctx.run_recorded_ops(steps: Tuple[Any, ...]) -> None

按顺序执行 steps 中每个子元组;每一步开始前stop_requested立即 return
("w", sec) 使用 wait_interruptible,而非死睡眠。

首元素 含义 元组形状
"w" 等待 ("w", float秒)
"c" 点击 ("c", x, y, button_str)"left"
"t" 输入文本 ("t", text_str)actions.type_text
"k" 单键 ("k", key_str)actions.keyboard.key_press
"D" 键按下 ("D", key_str)actions.keyboard.key_down
"U" 键抬起 ("U", key_str)actions.keyboard.key_up
"h" 快捷键点击 ("h", ("ctrl","s",...))actions.shortcut(*keys)
"H" 单键长按 ("H", key_str, duration_sec)actions.keyboard.hold_key
"M" 组合键长按 ("M", ("shift","w",...), duration_sec)(按下组合→等待→释放)
"m" 鼠标绝对坐标 ("m", x, y)mouse.move_to(x, y, smooth=False)(轨迹录制用,关闭贝塞尔曲线)
"Bd" 鼠标键按下 ("Bd", button, x, y) → 先 move_tomouse_down(button)
"Bu" 鼠标键抬起 ("Bu", button, x, y) → 先 move_tomouse_up(button)
"s" 滚轮 ("s", amount_int, "vertical" | "horizontal") → **actions.mouse.scroll`**

录制源码生成见 utils.input_recorder.events_to_tick_source;当前实现优先生成 D/U 以精确复现按键按住与交叠时序,必要时补充 h/H/M。生成代码末尾常会追加 ctx.finish() 以便队列进入下一项。type_text 执行过程中一般不在字符间隙检查停止,停止多在步骤边界生效。


十、事件总线 ctx.bus

Event 对象

同步/异步最终都会构造 Event(event_type, payload, source),处理器接收的 event 含:

属性 说明
event.type 事件类型字符串
event.payload 任意负载
event.source 来源字符串,默认 ""
event.timestamp 创建时间(time.time()

常用方法

方法 说明
emit(event_type, payload=None, source="") 事件入队,由 EventBus 后台线程 _loop_dispatch
emit_sync(event_type, payload=None, source="") 当前线程立即 _dispatch,顺序调用全部订阅者
on(event_type, handler) 注册 Callable[[Event], None]
off(event_type, handler) 注销;handler 需为同一对象引用

队列满emit 在队列满时会丢弃事件并打日志,不阻塞脚本。

引擎侧EventBusEngine.start() 时已 start();脚本内通常不要stop 总线。


十一、世界状态 ctx.state

WorldStatedataclasscore/world_state.py),脚本可读写下列字段(线程上 UI 命令通过锁更新 ui_command / ui_payload)。

字段

字段 类型 说明
script_manifest_path Optional[Path] 当前加载的清单路径
pause bool 暂停时引擎不调用 tick(ctx)
stop_requested bool 为真时主循环与脚本 tick 均停止
target_fps float 主循环目标帧率(与清单 fps 同步)
ui_command / ui_payload str / dict 最近一次 UI 命令(见 set_ui_command / consume_ui_command
manifest Optional[ScriptManifest] 运行时模块 init 后填入
extras dict 脚本间或跨模块共享的扩展字典

方法

  • set_ui_command(cmd, payload=None):写命令与负载(带锁)。
  • consume_ui_command() -> tuple[str, dict]:读取并清空当前命令。

ScriptRuntimeModule.tick 在每帧调用用户 tick 之前会执行 state.consume_ui_command(),若脚本需要在本帧处理 UI 命令,应依赖 tick 返回前已被消费 的设计,或通过 EventBus 自行订阅(取决于你的 UI 实现)。


十二、动作执行器 ctx.actions

类型 ActionExecutorexecutor/actions.py)。构造参数 human_like 默认为 Truenavigate_clickclick_at 间会通过 _human_delay 插入随机短延迟;False 时间更短(仍有一定最小间隔)。

鼠标相关

方法 说明
click_at(x, y, button="left", random_offset=0, clicks=1) 坐标点击;random_offset>0 时坐标随机偏移
click_region(region, button="left", clicks=1) region=(left,top,right,bottom) 内随机点点击
navigate_click(x, y, pre_delay=0.0, post_delay=0.0) 移动到位后点击
drag_between(x1,y1,x2,y2, button="left") 拖拽

键盘与组合

方法 说明
shortcut(*keys) shortcut("ctrl","s")keyboard.hotkey
type_text(text, interval=None) 透传 keyboard.typewrite

combo_action(actions: List[dict])

顺序执行。支持 type 键:moveclickdragscrollkeyhotkeytype(注意与 Python 关键字同名,JSON 里为字符串 "type")、waithold

type 主要字段
move x, y
click 可选 button, x, y, clicks
drag x, y,可选 button
scroll amount,可选 direction(默认 vertical
key key,可选 presses
hotkey keys(列表或序列,由实现 hotkey(*action["keys"]) 使用)
type text,可选 interval
wait duration
hold key,可选 duration

未知 type 会打 warning 并跳过。

等待

方法 说明
wait(seconds) time.sleep不可stop_requested 打断
wait_for(predicate, timeout=5.0, interval=0.1) -> bool 轮询 predicate(),超时返回 False

底层控制器

属性 说明
ctx.actions.mouse MouseControllermove_toclickdrag_toscroll
ctx.actions.keyboard KeyboardControllerkey_presshotkeytypewritehold_key

需要更短延迟或细粒度控制时,可优先用底层 API 并自行控制间隔。


十三、清单 ctx.manifest

ScriptManifestcore/script_manifest.py)主要字段:

属性 说明
project_root 清单所在项目目录(绝对路径)
manifest_path 清单文件路径,可为 None
name / script_version / description / authors 元数据
entry 入口文件相对路径
entry_path project_root / entry 的绝对路径
library 额外 library 目录相对路径列表(解析后在 sys.path 前插)
fps 建议帧率
capture CaptureSection
perception PerceptionSection
ui 自定义 UI 配置字典
raw 原始解析字典(JSON/YAML 全文)

CaptureSection

字段 默认 说明
mode "window" window / screen
title_pattern None 窗口标题匹配
hwnd 0 窗口句柄
auto_fix_win11_bitblt False Win11 BitBlt 兼容

PerceptionSection

字段 默认 说明
use_pipeline False 是否启用感知流水线
register_ui_recognizer False 是否注册 UIRecognizer
ocr_lang "ch" PaddleOCR 语言

十四、事件类型常量(与 UI 的约定)

定义于 core/visionscript_events.py

常量 方向 / 用途
UI_COMMAND ui.command UI → 运行时:暂停/恢复/停止等
UI_LOG ui.log 核心/脚本 → UI:日志行
UI_STATE ui.state 状态同步
UI_SCRIPT ui.script emit_ui / emit_ui_sync 使用
UI_ERROR ui.error 用户脚本异常(由 ScriptHost 同步发出)
UI_SCRIPT_LOADED ui.script_loaded 清单加载完成信息

UI_COMMAND 的 payload 建议格式见源码注释:{"cmd": "pause"|"resume"|"stop", ...}


十五、示例

示例 1:模板匹配后双击并结束

import time
from pathlib import Path

import numpy as np
from PIL import Image

TARGET_IMAGE = "target.png"
MATCH_THRESHOLD = 0.75

_state = {"ro": None, "retries": 0, "done": False}


def _load_bgr(path: Path):
    with Image.open(path) as im:
        rgb = np.asarray(im.convert("RGB"), dtype=np.uint8)
    return rgb[:, :, ::-1].copy()


def tick(ctx):
    if _state["done"]:
        return

    if _state["ro"] is None:
        target_path = Path(ctx.manifest.project_root) / TARGET_IMAGE
        template_bgr = _load_bgr(target_path)
        _state["ro"] = ctx.make_template_match_ro(
            template_bgr,
            threshold=MATCH_THRESHOLD,
            use_3_channels=True,
            name="target",
        )

    frame = ctx.capture_frame()
    if frame is None:
        time.sleep(0.5)
        return

    result = ctx.run_recognition(frame, _state["ro"])

    if result.success and result.template_hits:
        cx, cy = result.template_hits[0].center
        ctx.log(f"找到目标,位置: ({cx}, {cy})")
        ctx.actions.click_at(cx, cy, clicks=2)
        _state["done"] = True
        ctx.finish()
    else:
        _state["retries"] += 1
        ctx.log(f"未找到,重试 {_state['retries']}")
        time.sleep(0.5)

示例 2:键鼠与 UI 事件

def tick(ctx):
    a = ctx.actions

    a.click_at(400, 300, random_offset=2)
    a.shortcut("ctrl", "c")
    a.type_text("hello", interval=0.05)
    a.combo_action([
        {"type": "move", "x": 200, "y": 200},
        {"type": "click"},
        {"type": "wait", "duration": 0.3},
        {"type": "key", "key": "esc"},
    ])

    ctx.emit_ui("my_event", status="ok")
    ctx.log("动作执行完毕", "info")

十六、注意事项汇总

  1. 清单中的 capture / fps:JSON 使用 visionscript(或兼容 vhsr)嵌套 capturefpsperception;根级若另有同名键,以加载器实现为准(参见 load_script_manifest)。
  2. 中文或空格路径读图:避免依赖 cv2.imread;可用 np.fromfile + cv2.imdecodePIL 读入再转 BGR numpy
  3. 懒加载:首次 capture_frameperception_pipelinerun_recognition 可能加载较重依赖;建议在循环外复用 RecognitionObject
  4. tick 状态:模块全局变量或 ctx.state.extras;多脚本间共享用 extras 需注意生命周期。
  5. 停止脚本ctx.finish()ctx.state.stop_requested = True、或 return False(字面量)。
  6. 暂停与停止pause 跳过 tickstop_requested 结束引擎。wait_interruptiblerun_recorded_ops 内的 stop_requested 检查在长逻辑内部仍有用。
  7. ctx.actions.human_like:默认人性化延迟;追求极限响应时可使用 mouse / keyboard 并自控间隔。
  8. ctx.log 的级别:未知字符串在内部 logger 侧按 info 数值处理;UI 侧仍收到原始 level 字符串(取决于订阅实现)。

更多运行时与 EventBus 总览见 core.md;脚本队列行为见 script_queue.md