跳转到正文

Artifacts 与 BDX ​

Artifacts 是当前插件安装所属的有界二进制制品。它可承载较大的 BDX 输入、BDX 导出结果和导入中未确认坐标清单。制品 ID 不是路径;原生插件不能向 Host 指定任意主机文件。

本页对应公开工具包中的 neomega_runtime.artifacts 和 ctx.world。Host 必须实现 Artifacts 分发及对应世界适配器,并对当前安装授权。公开 SDK 版本或 host_api.min_minor 本身不保证目标实例支持大文件导入。

Artifacts 的五个方法 ​

在已启动的原生插件中使用 ctx.artifacts;也可以用 Artifacts(peer, session) 创建客户端,session 是游戏 session,而不是安装元数据对象。

异步方法返回与用途
upload(content: bytes, *, timeout=10)上传 1 字节至 8 MiB,返回 ArtifactDescriptor。
upload_file(path, *, timeout=10)读取插件自己可访问的普通文件,限制同上,然后上传一次。
retain(artifact_id: str, idempotency_key: str, *, timeout=10)在动作入队前,将完整制品保留到该业务键,返回描述符。
read(artifact_id: str, *, timeout=10) -> bytes分块读取,校验元数据、偏移、长度和 SHA-256,返回完整 bytes。
remove(artifact_id: str, *, timeout=10)显式请求删除,成功为 {"removed": true};仍被未结算动作占用时会被拒绝。

ArtifactDescriptor 是普通字典:

text
artifact_id: str   # 不透明 ID,仅用于 API 引用
size: int         # 总字节数
sha256: str       # 64 位小写十六进制摘要
received: int     # Host 已确认接收的字节数
complete: bool    # 完成校验并封存

SDK 以 48 KiB 分块上传和读取;timeout 限制每次 IPC 请求,不是整个文件传输的总预算。上传不自动重试,上传成功也不会导入世界。read 只接受完整制品;摘要或偏移不一致抛 ProtocolError,不能继续使用收到的一部分内容。

上传和 retain 要求 framework.world.bdx.import_artifact 授权。读取、清理历史上属于该安装的制品不因撤销这项操作授权而自动失去资格,但仍要求合法、活跃的安装身份、会话及代际;不能访问其他安装的制品。

上传与保留异常 ​

异常保留的信息和处理
ArtifactUploadErrorartifact_id(begin 回应丢失时可能为 None)、offset、phase。offset 仅为最后确认字节数;phase 为 begin/append/finish。保留可用引用,核对并显式清理。
ArtifactRetentionUncertainartifact_id、idempotency_key。retain 可能已生效,保留原 ID 和键;不要新建制品后悄悄换键提交。
IPCRejected保留 Host 的明确拒绝代码;上传时附带 ID/offset/phase,retain 时附带 ID/key。
asyncio.CancelledError上传/retain 附带相同上下文;Python 任务取消不能推出 Host 没有收到请求。

ArtifactUploadError 可从包根导入;ArtifactRetentionUncertain 从 neomega_runtime.artifacts 导入。当前高层 SDK 不提供断点续传方法,不能根据 offset 自行宣称可安全续传。

三种 BDX 导入入口 ​

以下方法均使用整数世界坐标 pos 三元组(每轴 ±30000000),以及必填的 idempotency_key: str、deadline: str。deadline 为带时区的绝对时间。

text
ctx.world.bdx(content: bytes, pos, *, idempotency_key: str, deadline: str,
              batch: bool = False, paused: bool = False,
              speed: float | None = None) -> OperationIntent

ctx.world.bdx_artifact(artifact_id: str, pos, *, idempotency_key: str,
                       deadline: str, batch: bool = False,
                       paused: bool = False,
                       speed: float | None = None) -> OperationIntent

await ctx.world.bdx_file(path, pos, *, idempotency_key: str, deadline: str,
                         batch: bool = False, paused: bool = False,
                         speed: float | None = None,
                         timeout=10) -> OperationIntent
入口操作权限输入与上限
bdxframework.world.bdx.import内联 bytes,4 字节至 180 KiB;解压最多 4 MiB,最多 256 步。适合小规模修改。
bdx_artifactframework.world.bdx.import_artifact引用已上传且以同一业务键 retain 的制品;压缩输入最多 8 MiB,解压最多 32 MiB,最多 100000 步。
bdx_fileframework.world.bdx.import_artifact读取插件本地文件 → 上传 → retain → 返回意图;不会调用 submit。

Artifact 导入还限制最多 65536 个字符串,单字符串/命令最多 32 KiB。Host 验证有界 BDX 格式,不是所有 BDX 扩展都受支持;不可接受的输入可返回 invalid_bounded_bdx,该原因表示在任何世界动作前拒绝。普通上传只验证字节和摘要,不等于通过 BDX 格式检查。

batch、paused 必须是 bool;batch=True 必须同时 paused=True。paused 是调用方声明已停用受影响指令链,不会执行全局暂停、改 gamerule 或替你停用链。speed 是每秒放置操作数,有限正数且不超过 1000000;极小值若无法表示其计时间隔同样拒绝。旧适配器可能不支持批量/速度选项并返回 bdx_options_unavailable。

明确上传、保留、提交 ​

以下为原生插件回调内片段。business_key 和 deadline 由业务为本次动作分配并保存;bdx_bytes 是已准备好的文件内容。示例不申请批量模式,因此不会假定指令链已停用。

python
artifact = await ctx.artifacts.upload(bdx_bytes)
artifact_id = artifact["artifact_id"]
# 业务在继续前持久保存 artifact_id、business_key 和 deadline。
await ctx.artifacts.retain(artifact_id, business_key)
intent = ctx.world.bdx_artifact(
    artifact_id, (0, 64, 0),
    idempotency_key=business_key, deadline=deadline,
)
# 业务在提交前持久保存 intent.payload();其中可能包含敏感数据,不要打印。
operation_id = await ctx.operations.submit(intent)
receipt = await ctx.operations.wait(operation_id, timeout=60)

需要方便入口时:

python
intent = await ctx.world.bdx_file(
    ctx.data_dir / "input.bdx", (0, 64, 0),
    idempotency_key=business_key, deadline=deadline,
)
# 到这里仅上传、保留、准备完毕;保存 intent 后才提交。
operation_id = await ctx.operations.submit(intent)

bdx_file 的文件来自插件自身可访问空间,不是供 Host 打开的路径。准备 intent 后不要更换 key 或 deadline:制品保留绑定的是原业务键。提交答复丢失时保留原意图及引用,按运行时操作核对处理。

进度和终态 ​

await ctx.operations.get(operation_id) 可带顶层 progress。进度是有界的内存快照,Host 最多保留 128 个操作的最近进度;重启后可能消失。它不是持久日志,也不是可用于恢复执行的检查点。

进度字段含义
stage, done, total当前阶段、本地已完成步骤、总步骤;done 不等于服务端已验收。
verified已经通过静态读回比对的步骤数。
statsmoves,syncs,repairs,batches,elapsed_ms,可有 stage_ms。
unknown_count, unknown_sample, unknown_details_complete未确认坐标数量、最多 8 项样本、详情是否完整。样本不是完整清单。
execution_verified当前固定为 false;导入静态状态检查不验证命令链执行。

Artifact 导入的终态摘要在 receipt["result"]["partial_effects"]。如果仍有未知坐标,Host 会尽量将完整清单保存为 unknown_artifact 描述符,读取后内容形如 {"unknown": [[x,y,z], ...]}。保存失败时 unknown_details_complete=false,可有 unknown_details_error="artifact_unavailable";不要只依赖样本修复全部范围。

python
row = await ctx.operations.get(operation_id)
progress = row.get("progress")
if progress:
    ctx.log.info("已处理=%s 已读回=%s 总数=%s",
                 progress["done"], progress["verified"], progress["total"])
if row["state"] in {"succeeded", "failed", "cancelled", "unknown"}:
    summary = (row.get("result") or {}).get("partial_effects") or {}
    unknown_artifact = summary.get("unknown_artifact")
    if unknown_artifact:
        unknown_bytes = await ctx.artifacts.read(unknown_artifact["artifact_id"])
        # 交由业务解析并保留完整清单;本片段不自动重建这些坐标。

批量导入只有在无错误、done 与 verified 都等于 total、且没有未知坐标时才可能为 succeeded / verified。串行导入即使本地步骤完成也可能保持 unknown / world_readback_required,不应以 100% 进度替代读回验收。

内联导入终态的 partial_effects 与 Artifact 版不同:通常含 import 报告、execution_verified=false,串行可有 local_completed_steps;旧适配器可能只有本地完成数。应按所用接口解析,不要把两种报告强行视为同一种扁平结构。

取消、重启和清理 ​

python
cancellation = await ctx.operations.cancel(operation_id)
receipt = await ctx.operations.get(operation_id)

取消回复中的 cancellation_requested=true 只说明请求已提出,不保证已发送的块操作停止。已放置方块不会回滚;wait 超时、Python 任务取消也不会自动取消世界动作。取消答复不确定时继续查原 operation_id。

Host 重启后的可用证据以持久操作回执和原制品引用为准,不从内存 progress 继续执行。遇到 unknown 应核对目标世界、终态摘要和未知坐标,必要时交管理员完成恢复核对;当前没有自动 BDX 续跑 API,也不能靠换键重复导入来“恢复”。

默认制品上限是单安装 16 MiB、Host 总计 64 MiB、总数 128。未 retain 制品默认 1 小时过期,在后续上传/启动时清扫,不保证刚满一小时立即删除。retain 的引用持久保存,防止操作尚未结算就丢失输入。

仅在业务确认不再需要后调用 remove。没有已接受操作占用,或关联操作已到 succeeded/failed/cancelled 时,Host 才能释放相关保留引用并删除;accepted/running 等状态会阻止删除。unknown 还需管理员恢复核对记录,不能凭超时或“看起来已经做完”删除。保留的制品既不是永久备份,也不能在异常分支统一强制清理。

导出 BDX ​

text
ctx.world.export_bdx(pos, size, *, idempotency_key: str, deadline: str)
    -> OperationIntent

需要 framework.world.bdx.export。size 三轴各 1–32,乘积最多 4096。Host 从服务端结构读回获取区域,要求位置完整且不重复、前景数据可用;读回不全会拒绝导出,不用缓存或空气猜补。

成功业务数据包含 artifact 描述符、pos、size、source="server_structure"、format="bdx" 及保留/排除信息。用 ctx.artifacts.read() 取 bytes,再写入插件自己的数据目录或交给上层交付流程。

python
intent = ctx.world.export_bdx(
    (0, 64, 0), (8, 4, 8),
    idempotency_key=business_key, deadline=deadline,
)
receipt = await ctx.operations.wait(await ctx.operations.submit(intent))
if receipt["state"] == "succeeded":
    exported = receipt["result"]["result"]
    bdx_bytes = await ctx.artifacts.read(exported["artifact"]["artifact_id"])
    (ctx.data_dir / "export.bdx").write_bytes(bdx_bytes)

导出保留前景方块名/状态和命令方块配置,不保留空气清除、背景层、非命令方块的实体 NBT、实体和计划 tick。它不能作为任意建筑的无损世界备份;有水层、容器、告示牌等内容时,应按返回的排除信息另行保存和验证。导出文件同样受 8 MiB 制品上限约束。

Neomega · 使用、开发与参考文档