# process.blender

用 Blender 内置 Python 执行脚本和 `bpy` 操作。独立于 Autos、MCP 和外部 Python 环境，不安装插件。

## 可见窗口：持久场景

```aardio
import process.blender;
var c,err,detail = process.blender.jsonRpc({session="demo"});
if(!c) return {error=err;detail=detail};

var code = /**
obj = bpy.data.objects.get('aardioCube')
if obj is None:
    bpy.ops.mesh.primitive_cube_add(size=2)
    obj = bpy.context.object
    obj.name = 'aardioCube'
obj.location.x = 3
result = {'name': obj.name, 'x': obj.location.x}
**/;
var r,err,detail = c.exec(code);
c.close(); // 不关闭 Blender
return {result=r;error=err;detail=detail};
```

另一个执行上下文可以继续：

```aardio
import process.blender;
var c,err = process.blender.connect("demo");
if(!c) return err;
var info = c.eval("[bpy.data.objects['aardioCube'].name, bpy.data.objects['aardioCube'].location.x]");
c.close();
return info;
```

`jsonRpc` 创建或重连命名会话，默认名为 default。已有描述时只尝试重连，故障不自动新开进程。`connect` 只连接现有会话，参数也可以是之前客户端的 `connection` 纯表。客户端实例不能跨线程传递。

选项：session、timeoutMs（响应等待默认30000毫秒）、startupTimeoutMs（默认30000毫秒）、blendFile、factoryStartup（默认true）。默认使用工厂启动配置并禁用 `.blend` 内嵌自动脚本，但不修改已保存的用户偏好。

## 返回值、日志与错误

- `c.exec(code,args)`：Python 中通过 args 读取 JSON 参数，通过 result 变量指定返回值。成功返回 `{result,stdout,stderr}`；每次清除旧 result，其余 Python 全局变量保留。
- `c.eval(expression)`：直接返回 JSON 值。false、0、null 都可能成功，应检查错误返回值。
- `c.ping()`：读取 PID、版本、主线程标记、场景与对象数。
- 失败返回 `null,错误信息,detail`。detail.delivery 为 responded / unknown / not_sent；exec 的 traceback 在 detail.data 中。
- 超时不代表远程操作被取消，不重发、不自动重启。unknown 后要重新 connect 并回读真实状态，禁止盲目重放。
- 同一客户端不支持并发/重入调用。大消息按完整 LF 帧传输，单帧上限为16 MiB。
- 桥接使用主线程计时器非阻塞收发；长脚本、保存、渲染仍可能暂时占用 Blender 主线程。按任务需要调整 `c.rpc.timeoutMs`。

## 保存和退出

```aardio
import process.blender;
var c,err = process.blender.connect("demo");
if(!c) return err;
io.createDir("/output");
var saved = io.fullpath("/output/native-demo.blend");
var code = /**
bpy.ops.wm.save_as_mainfile(filepath=args['path'])
result = bpy.data.filepath
**/;
var r,err,detail = c.exec(code,{path=saved});
c.close();
return {result=r;error=err;detail=detail};
```

上例会保存到程序基准目录的 output 子目录，重复运行可能覆盖同名示例文件。

`close()` 仅断开连接；`quit()` 明确退出 Blender，**不会自动保存**。先保存，再在确实需要退出时调用 quit。正常退出会清理会话描述；异常终止遗留描述时，检查窗口与错误，或明确换新 session。

## 单次后台脚本

```aardio
import process.blender;
var p,err = process.blender.exec("import bpy; print(bpy.app.version_string)");
if(!p) return err;
var out,stderr,exitCode = p.readAll();
return {stdout=out;stderr=stderr;exitCode=exitCode};
```

`execfile(path,options)` 执行 Python 文件。两者都返回 process.popen，options 可指定 blendFile、factoryStartup。后台代码异常退出码为1。每次后台执行是独立进程；`.blend` 可保存文件状态，但不是同一个 Python 内存上下文。

## 安装与本机安全边界

`findPath()` 只读查找，`path` 可显式指定 blender.exe。找不到时 `checkPath()` 读取官方 Windows MSI 链接，交给 `inet.installer.asInvoker` 安装，不自建环境管理器。

只监听127.0.0.1，用随机口令鉴权，只接管本库启动的实例，不向任意已有窗口注入。会话描述、bridge1.py、jsonrpyc2.py 放在当前用户应用数据目录；版本脚本只在不存在时释放，不做哈希更新或迁移。描述包含口令，不分享或打包。不要并发启动同一命名会话。

2026-09-11 已在 Blender 5.2.1 LTS 验证。当前机器已有安装，本次未重复测试下载/安装分支。
