跳转到正文

世界读写与快照 ​

ctx.world 提供命令方块、告示牌、物品、容器、结构和 BDX 的原生插件动作。方块/区域查询在 ctx.queries,见命令与查询;大文件导入及导出制品见Artifacts 与 BDX。

本页所有 ctx.world builder 都返回 OperationIntent,必须指定关键字参数 idempotency_key: str、deadline: str,再通过 ctx.operations.submit() 和 wait() 执行。例外是 bdx_file() 为异步上传、保留后创建意图,但仍不会提交。下方签名省略的公共参数始终必填。

操作名称必须分别加入 manifest 的 permissions.operations 并获授权。Host 还要有对应的游戏适配器、机器人在游戏中;写操作另须允许世界写入。export_bdx 是只读例外,需要区域读回与 BDX 编码能力,不要求开启世界写入。声明 API 版本或 SDK 中存在函数都不能替代这些条件。原生插件传显式坐标;不要把外部 HTTP 工具的 workspace.set、自动切换模式等约定套在这里。

坐标和回执 ​

除明确标为子区块坐标的接口外,pos、anvil_pos、workspace_pos 都是三个整数构成的世界坐标,每轴 ±30000000。每项独立业务动作应使用独立、持久保存的键和固定 deadline。以下示例中的 business_key、deadline 已由调用方为当前动作准备。

python
intent = ctx.world.sign(
    (0, 65, 0), "欢迎来到这里", back_text="请遵守服务器规则",
    idempotency_key=business_key, deadline=deadline,
)
operation_id = await ctx.operations.submit(intent)
receipt = await ctx.operations.wait(operation_id)
completion = receipt.get("result") or {}
ctx.log.info("状态=%s 证据=%s", receipt["state"], completion.get("evidence"))

succeeded / verified 只证明该接口约定检查的字段。命令方块配置正确不代表红石运行正常,物品字段匹配不代表任意 NBT 完整复制。unknown 表示可能已有副作用,需读回核对,不能直接重新执行。详见动作回执。

命令方块、告示牌与结构方块 ​

command_block ​

text
ctx.world.command_block(pos, command: str, *, mode: int, facing: int,
    idempotency_key: str, deadline: str, need_redstone: bool = False,
    conditional: bool = False, tick_delay: int = 0, name: str = '',
    track_output: bool = False, execute_on_first_tick: bool = False)

需要 framework.world.command_block。mode 为 0 脉冲、1 循环、2 连锁,facing 是协议方向值 0–5。tick_delay 为 0–2147483647;command 最多 32768 UTF-8 字节,无 NUL/CR/LF;name 最多 1024 字节。

need_redstone=False 是默认值,配置后可能直接运行。配置指令链时先由业务安排停用和恢复,再写入目标块;这个 API 不会自动停用整条链。conditional 为条件执行,track_output 控制输出跟踪,execute_on_first_tick 控制首 tick 执行。成功证据来自方块及相关配置读回,不是命令执行结果或客户端显示验收。

sign ​

text
ctx.world.sign(pos, text: str, *, idempotency_key: str, deadline: str,
    back_text: str = '', block: str = 'minecraft:standing_sign',
    glow: bool = False, back_glow: bool = False,
    waxed: bool = False, slot: int = 0)

需要 framework.nbt.sign。block 只支持 minecraft:standing_sign 和 minecraft:wall_sign;text 与 back_text 各最多 32768 UTF-8 字节。slot 是机器人快捷栏槽 0–8。glow/back_glow 分别控制正反面发光,waxed 控制上蜡。Host 读回两面文字及相关属性;目标游戏版本不具备对应字段、缺少读回或值不匹配时,不能声称验证成功。

structure_block ​

text
ctx.world.structure_block(pos, name: str, *, mode: int, size, offset,
    idempotency_key: str, deadline: str, include_players=False,
    ignore_entities=True, ignore_blocks=False, show_bounding_box=False,
    rotation=0, mirror=0)

需要 framework.world.structure_block。name 为 1–128 UTF-8 字节,mode 为协议模式值 0–3;size 三轴各 1–32,offset 三轴为 ±30000000 的整数;rotation、mirror 为协议枚举 0–3。布尔项分别控制玩家、忽略实体、忽略方块、边框。它放置并配置结构方块,验证的是配置,不会替你确认结构已经保存或载入。需要明确保存/载入动作时用本页的 save_structure/load_structure。

生成物品与容器内容 ​

基础物品 item ​

text
ctx.world.item(name: str, *, slot: int, anvil_pos, workspace_pos,
    idempotency_key: str, deadline: str, count: int = 1,
    value: int = 0, custom_name: str = '')

需要 framework.nbt.item。name 为可选 minecraft: 前缀加 1–128 个小写字母、数字或下划线;count 为 1–64,value 为 0–32767,slot 为 0–8。生成位置是机器人自身快捷栏,不能将 slot 解释为某位玩家的背包位置。

anvil_pos 和 workspace_pos 必须显式传入。重命名需要 anvil_pos 已存在真实铁砧;机器人可能移动并进行交互,工作区域须能容纳所需辅助方块。该原生调用不隐含 HTTP 工作区配置,也不承诺自动清理全部辅助方块。

python
intent = ctx.world.item(
    "minecraft:diamond", count=1, custom_name="纪念钻石", slot=0,
    anvil_pos=(2, 64, 0), workspace_pos=(4, 64, 0),
    idempotency_key=business_key, deadline=deadline,
)

增强物品 enhanced_item ​

text
ctx.world.enhanced_item(item: dict, *, slot: int, anvil_pos, workspace_pos,
                       idempotency_key: str, deadline: str)

需要 framework.nbt.item.enhanced。它使用有限的物品生成字段,不是任意 NBT 写入接口。不要把物品栏读出的整个原生 Item 字典原样传入。

item 字段类型与意义
name必填物品标识,规则同基础物品。
count, val, custom_name可选数量 1–64、数据值 0–32767、字符串自定义名称;这里用 val,基础 builder 的参数名是 value。
enchants对象数组,表达附魔;具体条目需被游戏适配器和目标物品支持。
pages, title, author书页字符串数组、标题字符串、作者字符串。
Patterns旗帜图案对象数组,大小写必须一致。
can_place_on, can_destroy可放置/可破坏方块的字符串数组。
keep_on_death布尔值,死亡保留。
item_locklock_in_slot 或 lock_in_inventory。

Host 外层 schema 对 enchants 和 Patterns 只声明对象数组,不代表接受任意内层对象或所有组合;具体物品、附魔、图案和版本还受游戏适配器限制。没有声明的顶层字段会被拒绝,包括任意 tag、嵌套 Items 和完整原生 NBT。

python
intent = ctx.world.enhanced_item(
    {"name": "minecraft:written_book", "count": 1,
     "title": "新手手册", "author": "服务器", "pages": ["欢迎", "从这里开始"]},
    slot=0, anvil_pos=(2, 64, 0), workspace_pos=(4, 64, 0),
    idempotency_key=business_key, deadline=deadline,
)

旗帜图案流程可能在 workspace_pos + (3, 0, 3) 放置织布机;调用方要规划工作区和善后。物品生成由多个阶段组成,失败不等于没有生成、附魔或改名。

容器内容 container ​

text
ctx.world.container(pos, slots: dict, *, anvil_pos, workspace_pos,
                    idempotency_key: str, deadline: str,
                    block: str | None = None)

需要 framework.nbt.container。一次写 1–9 个指定槽位,槽编号为 0–26;SDK 将字典键转成字符串,Host 要求规范十进制编号。每项为 {"item": <增强物品字段>, "count": 1..64}。block 省略时保留已有容器类型;指定时只支持 minecraft:chest、minecraft:barrel、minecraft:shulker_box。未指定的槽位不会清空。

python
intent = ctx.world.container(
    (8, 64, 0), {0: {"item": {"name": "minecraft:apple"}, "count": 8}},
    block="minecraft:barrel", anvil_pos=(2, 64, 0), workspace_pos=(4, 64, 0),
    idempotency_key=business_key, deadline=deadline,
)

这是生成并写入容器内容的高层操作。打开现有容器、移动原有物品和事务对账使用物品栏与容器中的原生交互接口。

物品写入的验证和失败 ​

item/enhanced_item 只有在同一连接收到比写入前更新的原生槽位观察、且请求的支持字段匹配时,才返回 succeeded / verified。成功业务数据含 scope="requested_item_fields"、source="native_inventory_packets"、matched=true 和 observed。旧缓存、连接改变、没有新包或字段不匹配均不能作为成功依据。

container 读回目标方块实体的 Items,验证请求槽位及字段;缺失、不完整、过大或不匹配的读回保留 unknown。未请求槽位和任意 NBT 不属于验证范围。

常见未知原因有 world_readback_required、world_readback_not_observed、world_readback_connection_changed、world_readback_mismatch、world_readback_incomplete。执行中错误为 world_operation_error,可带 recovery_required=true。增强物品的 partial_effects 可含 failed_stage(例如 item_prepare/item_book/item_enchant/item_rename)和 failure_code(例如 anvil_not_present/container_open_timeout/item_stack_timeout/item_stack_rejected/rename_mismatch/deadline_exceeded);先按该阶段检查现场,不要从头重做。

拾取、放置与展示物品 ​

下列方法均需公共 idempotency_key、deadline,slot 都是快捷栏 0–8。

Builder操作权限效果和限制
pick_block(pos, *, slot, assign_nbt=False)framework.world.pick_block创造模式 PickBlock;assign_nbt 请求附带 NBT。返回槽位不证明复制完整。
place_block(pos, *, slot, facing)framework.world.place_block放置指定槽的方块;facing 0–5;可能移动机器人、建立或移除辅助块。
held_on_block(pos, block, *, slot)framework.world.held_on_block放置讲台/唱片机并使用手持书/唱片;block 为 lectern/jukebox,可带 minecraft:。
item_frame(pos, *, slot, rotation=0)framework.world.item_frame放置朝上的展示框及支撑,再插入/旋转手持物;rotation 0–7。

这些接口即使完成动作并读回目标块,当前仍返回 unknown / world_effect_unverified,业务数据含 partial、observed、effect_verified=false;PickBlock 的 partial 可含 returned_slot 和 assign_nbt。单个块的读回不能证明书已插入、唱片在播放或 NBT 保真。必须按业务追加观察和人工/客户端验收,不能用“函数没报错”替代。

服务端内存结构 ​

text
ctx.world.save_structure(name: str, pos, size, *, idempotency_key: str, deadline: str)
ctx.world.load_structure(name: str, pos, *, idempotency_key: str, deadline: str)
ctx.world.export_bdx(pos, size, *, idempotency_key: str, deadline: str)
方法操作权限合同
save_structureframework.world.structure.savename 匹配 [A-Za-z0-9_.-]{1,64};size 三轴各 1–32,总数 ≤4096;保存到服务端内存,排除实体,同名可能覆盖。
load_structureframework.world.structure.load按同样的 name 规则,使用默认旋转和镜像载入目标位置。
export_bdxframework.world.bdx.export同样的区域上限;从新鲜服务端结构读回生成所属安装的制品,详见 BDX 导出。

保存/载入的业务结果为 name,pos,server_acknowledged=true,content_verified=false。内存结构不是跨服务器备份,也不保证重启后保留。载入返回确认后仍应读回关键块和数据;不要将其称为逐字段恢复验证。

主动请求子区块 ​

text
ctx.world.subchunk(dimension: int, pos, *, idempotency_key: str, deadline: str)

需要 framework.world.subchunk.request。dimension 为有符号 32 位整数;pos 是子区块坐标,X/Z 在 ±1875000 内、Y 在 -128–127 内。世界坐标转为子区块坐标用向下整除 16,例如 -1 // 16 == -1。

该调用会发请求,不是只读内存;当前同样要求实例允许世界写入。succeeded / dispatched 的数据是 requested=true,send_returned=true,observed=false,只代表发送返回。错误可能为 unknown / subchunk_request_error。要确认实际数据到达,使用独立的缓存快照入口;不能立刻把请求成功当作区块已加载。

临时子区块快照 ​

快照是原生插件的可选数据通道,不是 ctx.world 动作,也不是持久世界数据库。使用前检查 ctx.capabilities["data"]:应有 world_snapshot=true、transport="http-binary-v1" 和当前 world_epoch。Host 还需对该安装和具体 key 独立授权;宽泛的命令权限不会自动授予快照。

python
import io
from neomega_runtime.bulk import BulkClient, snapshot
from neomega_runtime.subchunk import parse_subchunk

caps = ctx.capabilities.get("data", {})
if caps.get("world_snapshot") and caps.get("transport") == "http-binary-v1":
    key = {"epoch": caps["world_epoch"], "dimension": 0, "x": 0, "y": 4, "z": 0}
    descriptor = await snapshot(ctx.peer, key)
    staging = io.BytesIO()
    async with BulkClient(max_bytes=1 << 20) as bulk:
        await bulk.consume(descriptor, staging.write)
    view = parse_subchunk(staging.getvalue())
    runtime_id = view.block(0, 0, 0)
    # runtime_id 为 None 表示未知;不能直接当作空气。

snapshot(peer, key) 通过 world.snapshot 返回描述符:url,token,ref,metadata,expires_at。ref 含 id,digest,length,format;metadata 含 key,revision,completeness,encoding,key 内含 epoch、维度和坐标。必须保留这些元数据与字节的绑定,不能只存 Runtime ID。描述符为临时、所属安装可访问的传输凭据,不要写日志或分享。

快照只读已观察缓存,不会移动机器人、主动请求区块或访问任意文件。常见拒绝为 unsupported、permission_denied、cache_miss、world_epoch_expired、quota_exceeded;会话/安装代际变化也可能使授权失效。未命中就保持未知;epoch 更换后重新获取当前能力和观察,不沿用旧凭据。

BulkClient 与二进制解析 ​

text
BulkClient(*, max_transfers=2, max_waiters=32, max_bytes=16777216, timeout=30)
await bulk.consume(descriptor, sink) -> ref
await bulk.aclose()
bulk.owned_threads()
parse_subchunk(data: bytes | bytearray | memoryview) -> SubChunkView

BulkClient 只访问数字回环地址的 HTTP 数据通道,校验长度和 SHA-256,不进行自动重试。sink 是同步函数,在 I/O 线程调用,必须及时返回。收到的字节在 consume 成功前只是临时数据:先写暂存区,成功后再发布;失败就丢弃暂存结果。使用异步上下文或在 finally 中 aclose();关闭会等待实际线程退出,不合作的 sink 会拖延关闭。owned_threads() 可用于资源清理诊断。

parse_subchunk 接受 NSC v1 格式,单对象最多 1 MiB,1–2 层;格式错误抛 ValueError,输入类型错误抛 TypeError。解析本身不证明传输完整性,先完成 Bulk 校验。

视图成员含义
view.block(x,y,z,layer=0)本地坐标各 0–15,返回 Runtime ID 或未知 None;Runtime ID 0 不隐含空气。
view.nbt(x,y,z)返回 NBTRecord(encoding, data) 或 None;保留原始编码和 bytes,不自动展开 NBT/__tag。
view.layer_count, view.nbt_count当前观察中的层数和 NBT 记录数。
view.nbt_complete只有为 true 时,缺失记录才可以解释为该次观察确认无 NBT。

Blob 缓存与显式获取 ​

Blob 是按 uint64 hash 寻址的原始区块数据,与 NSC 快照不同;不能直接拿 Blob 字节调用 parse_subchunk()。

text
await cached_blob(peer, session, hash_value) -> descriptor
await consume_cached_blob(peer, session, hash_value, bulk, sink) -> ref
await fetch_payload(peer, session, raw, bulk) -> bytes
request_keys(raw) -> Counter
response_receipts(raw, requested) -> dict

前两项来自 neomega_runtime.blobs。需要 Host 的 blob_cache 能力及独立授权;使用 ctx.operations.session 作为 session,hash 为 0–18446744073709551615 的整数。cached_blob 返回绑定 session,hash,url,token,ref,expires_at 的描述符;未命中不会自动向游戏侧获取。每个 Blob 最大 1 MiB,Host 校验内容 hash,Bulk 校验传输 SHA-256。

后三项来自 neomega_runtime.blob_fetch,另需 blob_fetch 能力及显式获取授权。它只开放有界的原始 get-hash-payload 协议,不是通用 RPC 转发器。

请求 raw 必须是 bytes:前两字节为小端 uint16 数量(1–64),随后每项是 struct.Struct('<QiiiB'):hash、X、Y、Z、类型。坐标和类型应来自合法的原始请求上下文,不要从快照坐标猜造。响应最多 8 MiB,每个 payload 最多 1 MiB。

python
from neomega_runtime.blob_fetch import request_keys, fetch_payload, response_receipts
from neomega_runtime.bulk import BulkClient

# raw_request 是业务已持有的合法原始 Blob 请求 bytes。
requested = request_keys(raw_request)
async with BulkClient(max_bytes=8 << 20) as bulk:
    raw_response = await fetch_payload(
        ctx.peer, ctx.operations.session, raw_request, bulk
    )
receipts = response_receipts(raw_response, requested)

fetch_payload 验证描述符绑定 session 和请求 SHA-256,并通过 Bulk 校验传输。调用方仍需执行 response_receipts 核对响应项属于原请求、长度正确、无尾随数据及冲突 hash;返回 hash 到 (size, sha256_bytes) 的映射。缺少某项不意味着空内容;解析失败保留未知,不将未核对字节回填为已确认数据。

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