外观
原生 Bus 与观察流
通过 ctx.bus 调用其他模块、订阅原子快照与增量,或把持久动作放进业务事务。已有 ctx.commands、ctx.inventory、ctx.containers 等便利接口继续有效;按所选入口声明权限,不需要为使用 Bus 重写全部插件。
1.1.0 新增资源会话以及远程连接与可恢复投影。普通 Watch 的合同保持不变;需要自动恢复观察基线时显式选择 projection()。
选择成员种类
| 种类 | 用途与返回 | 调用约束 |
|---|---|---|
read | 读取有类型的结果 | 仍需授权;候选初始化只能访问允许候选读取的活动来源。 |
service | 调用业务处理器,返回该业务的结果 | 返回成功不自动意味着它提交的游戏动作成功;有副作用的业务须定义持久去重与对账。 |
op | 接纳一个持久动作,返回 OpAdmission | 保存完整 OpIntent;再按原 operation ID 查询回执。 |
view | 同一来源的原子初始快照与连续增量 | 每个 Watch 独立,检查 epoch、revision、complete、reason 并关闭订阅。 |
event | 向已订阅消费者发送有类型的在线元素 | 不替代持久事件 ACK,不补放未知间隔。 |
成员以完整名称、major 与结构合同识别;提供者由 installation、generation 区分。目录可见、已授权、当前可用是不同条件。catalog() 返回的 entries 中,检查 member、kind、contract、authorized、availability 和 provider;同名多个提供者时明确选择目标。
Python 可调用 read/service/op、消费 View、发布与订阅在线元素,并提供异步 read/service;不提供 Python op 处理器。Go 和 Lua 的具体范围见Go 宿主模块与驻留 Lua。
调用与结构类型
python
result = await ctx.bus.call(
member, request, result_type=Result,
major=1, kind="service", provider=provider, timeout=5,
)这里的 member、request、Result 与 provider 必须来自你选择的实际成员合同。请求 dataclass 可从对象推导;整数宽度使用 SDK 的 u32、u64 等类型,普通 Optional 和 NBT 保留结构语义。标量或 union 根应明确 request_type。动态消费者可用 bind_schema 绑定目录提供的完整 schema,不能猜测字段。
timeout 必须大于 0 且最多 30 秒。一次调用绑定一个具体提供者;提供者繁忙、撤权、合同变化或不可用会返回错误。SDK 不自动重试 service。Call 元数据中的调用方、期限与 cause 由 Host 提供,不从业务请求接受伪造身份;嵌套调用沿当前 cause,循环与过深调用被拒绝。
持久动作:接纳和完成分开
ctx.bus.call(..., kind="op", intent=original_intent, result_type=OpAdmission) 返回的是持久接纳。operation_id、state 和 duplicate 不等于最终游戏效果;使用 ctx.operations.get/wait 读取原回执。
需要与插件状态原子提交时,使用同步 ctx.bus.prepare_op(member, arguments, intent=...)。它只冻结合同、参数、原 session、deadline 与 cause,不执行 IO,也不表示已经授权。将返回的意图放入 tx.action(intent),再 await tx.save();Host 在事务提交和执行时重新核权限及合同。完整购买链见持续计数与一次发放。
取消父 service 或等待超时,不自动取消已接纳子 op,也不延长原 deadline。不确定接纳时保留 op_request(error) / op_context(error) 中的原请求和已知 ID;先查原 operation 或 commit receipt,不换 key、session 或 cause 自动重放。
command.execute
Bus 命令使用 permissions.services: ["command.execute"]。参数是 cmd: str、identity: str、wait: bool | None、timeout: f64 | None;major 为 1。cmd 非空、最多 32768 UTF-8 字节,不含 NUL/换行;identity 为 player/ws/wo/ai。typed wait=None 按 false,timeout 缺省或非正值按 30 秒,最高 300 秒。
这与 Commands helper 的默认 wait=True 不同。需要命令输出时显式设置 wait;wait=False 或 wo 没有输出保证,可得到 unknown/response_omitted。有效命令输出按成功数形成 succeeded 或 failed;传输后错误、没有可验证输出则保留 unknown。命令 ACK 不等于独立世界读回。
View:先基线,再增量
python
from neomega_runtime import u64
watch = await ctx.bus.watch(
"stats_commands.count", snapshot_type=u64, delta_type=u64,
provider=provider,
)
try:
initial = watch.initial
print(initial.snapshot, initial.complete, initial.reason)
update = await watch.read()
print(update.delta, update.epoch, update.revision)
finally:
await watch.close()本段仅演示一次读取和关闭。它需要已安装的 stats provider 与 service:stats_commands.count 授权;完整连续处理见完整示例。该 View 的 delta 是新的累计值,不能再累加一次。其他 View 的 delta 按各自合同解释。
| 领域成员 | 快照的含义 |
|---|---|
players.online | 当前来源观察到的玩家;持续保留 complete=false,不等于全服完整名单。 |
actors.known | 连接内保留的已知实体集合;replace 增量替换集合,完整性不等于全部字段或全世界覆盖。 |
environment.current | 客户端观察;envelope epoch 为连接身份,payload 内还有领域 epoch。未知字段不能填零或 false。 |
inventory.current | 当前连接的库存观察;未知槽不能当空槽,不完整到完整时建立新 epoch。 |
selfdeath.evidence | 有界原始证据;不推断完整库存、物品归属或最终生死状态。 |
断流、溢出、撤权或替换可能终止 Watch。instance_replaced 后若业务允许,关闭旧 Watch、重新发现提供者并打开新基线;这是新订阅,不是旧流重放。其他错误须按原因处理。重新订阅、重启或新数据到达不会自行修复来源的 complete=false。
授权与停止
托管 Bus 的 read/service/op/View 都按精确成员放在 permissions.services,由管理员授权 service:<member>;这不等于旧 operation grant。在线事件还需对应订阅声明与事件授权。玩家能力等少数成员有额外权限条件,见玩家。
on_init 中声明导出和受管订阅;激活后才启动活动来源和一般调用。候选可读标记不绕过权限。停止会请求取消并等待回调、来源和执行实际退出;等待方收到取消不表示资源已释放,更不表示已撤销游戏效果。不要让同步阻塞代码长期占据 Python 事件循环。