跳转到正文

移动、跳跃与同高导航 ​

使用 NativeMovement 执行一次有界直线移动;需要绕开已知障碍时,用 FlatGrid 规划同高网格路线,再交给 FlatNavigation 逐段执行。所有控制都依赖独立的位置观察和当前连接的 AuthInput 证据,不能用出生点、旧 tick 或本地预测代替。

动作需要有效游戏连接及对应授权。按下文建立目标引用、准备意图,再用 Operations 提交并读取结果。

接口选择与权限 ​

入口用途操作权限与附加条件
MovementControllerPython 侧约 20 Hz 的短距离平地输入循环由 send、observe 适配器决定;内置发送适配器需要 framework.packet.send_typed 和 packet_send_ids: [144]
NativeMovement、FlatNavigationHost 执行有界移动framework.self.move 和 packet_send_ids: [144]
framework.self.jump固定有界跳跃序列同名操作权限和包号 144
framework.self.auth_input.observe、framework.self.action_audit.read读取当前输入证据、动作审计对应同名操作权限
framework.self.auth_input.bootstrap、framework.self.auth_input.sequence显式候选输入、实验序列对应同名操作权限和包号 144

以上写操作还要求 Host 已进游戏、接入原生控制且允许世界写入。位置查询、方块观察、实体观察需要各自的权限。申请方式见权限与 manifest。插件通过 ctx.operations 调用;这些操作名不是 HTTP URL,也不要给插件硬编码管理令牌。

使用上下文准备控制意图 ​

ctx.control 提供 RobotControl 入口:move()、jump()、auth_input_bootstrap() 和 auth_input_sequence() 准备对应控制意图;auth_input_observe()、action_audit()、death()、action_guard() 准备观察意图。各方法仍需原操作要求的连接、revision、位置等参数,以及 idempotency_key、deadline。

这些方法返回 OperationIntent,由 ctx.operations.execute(intent) 或提交/等待流程执行;不会自动刷新观察、创建业务键或重试。inventory_support() 和 equipment_move() 的用途见库存。它与下文协调控制器的 ActionControl 锁是不同对象。

一次原生移动 ​

text
from neomega_runtime.movement import NativeMovement

NativeMovement(ctx)
await handle.walk_to(
    target, *, connection_id, initial_tick, dimension,
    auth_input_height_offset, speed=.1, tolerance=.2,
    timeout_ms=5000, expected_auth_input_revision=None,
    experimental_ground=None,
)

target 为三个有限坐标。connection_id 必须是原生 self.action_audit 的连接标识,不是 ctx.operations.session。initial_tick 与 expected_auth_input_revision 来自当前原生输入证据;不要自行递增一个历史 tick 来开启下一动作。auth_input_height_offset 是已验证的位置查询坐标与 AuthInput 坐标之间的高度偏移,范围 -3..3。

参数范围与含义
speed0.01..0.15 方块/tick,默认 0.1;不是方块/秒
tolerance0.05..0.5 方块,默认 0.2
timeout_msHost 接受 100..10000 毫秒
dimension0..2,必须与当前观察一致
initial_tick / expected_auth_input_revision前者 0..18446744073709550000;后者提供时必须为正 uint64

每个 handle 只接受一次调用。返回完整 operation receipt,检查 receipt['state']、receipt['result']['evidence'] 和内层 receipt['result']['result']。普通移动的 arrived、already_at_target 对应 verified;unknown、unobserved 不构成到达证明。取消 await 不会自动取消已受理的 Host 动作:保留 handle.intent 和 handle.operation_id,用 ctx.operations.cancel() 请求取消,再读取原操作与当前位置。

NativeMovement 内部准备并提交动作,但没有提交前的持久化回调。业务必须在提交前保存完整 intent 时,直接使用 Operations,如下例。sample 必须由应用的独立观察适配器提供,目标路径必须已确认为同高、无障碍且在短距离范围内。

python
async def move_once(ctx, sample, target, height_offset, key, deadline, journal):
    intent = ctx.operations.prepare(
        'framework.self.move',
        dict(connection_id=sample['connection_id'],
             initial_tick=sample['initial_tick'],
             expected_auth_input_revision=sample['auth_input_revision'],
             dimension=sample['dimension'], target=list(target),
             auth_input_height_offset=height_offset,
             speed=.1, tolerance=.2, timeout_ms=5000),
        idempotency_key=key, deadline=deadline,
    )
    record = dict(intent=intent.payload(), operation_id=None, receipt=None)
    await journal(record)  # 返回前须持久化;失败则不提交。
    try:
        record['operation_id'] = await ctx.operations.submit(intent)
        await journal(record)
        record['receipt'] = await ctx.operations.wait(record['operation_id'], timeout=10)
        return record['receipt']
    finally:
        await journal(record)  # 保留原 key,异常后先核对原操作。

experimental_ground 是可选实验配置,必须同时提供精确 revision。配置包含 profile='experimental_full_forward_neutral_0098_0546_v1'、on_ground、observed_at、evidence_ref、max_frames、cleanup_ms、initial_position、initial_velocity、bounds_min、bounds_max,可选 turn_to_target。max_frames 为 4..200,cleanup_ms 为 50..2000。它要求明确的接地证据与空间预算;modeled_target_observed 和 cancelled_modeled_stop 的证据仍为 dispatched,不能改写成普通移动的 verified。

Python 移动控制器与观察类型 ​

text
from neomega_runtime.movement import (
    PositionObservation, MovementResult, MovementController,
    ManagedMovementTransport,
)

PositionObservation(connection_id: str, sequence: int,
                    sampled_at: float, position: tuple)
MovementResult(status: str, ticks_sent: int, last_tick: int,
               stopped: bool, observations: tuple, detail: str = '')
MovementController(send, observe, *, connection_id, initial_tick, control_lock=None)
await controller.walk_to(target, *, timeout=10, speed=.1, tolerance=.2, cancel=None)
ManagedMovementTransport(ctx, *, connection_id, player_name, player_uuid,
                         dimension, auth_input_height_offset)
await transport.send(frame, *, timeout)
await transport.observe(*, timeout)

send(frame, timeout=...) 仅在确认写出后返回字面值 'dispatched';其他返回或异常按不确定处理。observe(timeout=...) 返回 PositionObservation,sampled_at 使用进程单调时钟;sequence 只随新的独立服务端观察增长,不能每次读取同一缓存就增长。

控制器单次水平距离最多 8 格,timeout 为 0.1..30 秒,速度与容差范围同上。位置观察不能超过 0.5 秒;超过 1 格的位置纠正、高度变化、约 1 秒无观察进展或无法维持输入节奏都会停止。它不模拟重力、台阶、碰撞、飞行或跳跃。

返回的 status 可能为 arrived、already_at_target、cancelled、timeout、corrected、terrain_changed、stalled、timing_limited、stopped、unconfirmed、observation_failed、unknown。ticks_sent 包含已确认发送的停止帧;stopped 只有新观察支持停止时才为真。写入不确定时不会再补发停止帧,也不能重建 controller 绕过核对。

ManagedMovementTransport 用 Operations 发送包 144,用命令位置查询作为独立观察。它要求 connection_id == ctx.operations.session,这一点与 NativeMovement 不同;它直接使用标准 PluginContext 的 ctx.positions.sample(),需要 framework.entities.query 权限。位置查询须返回唯一实体,其 uniqueId 与 dimension 匹配预期;适配器读取 position.x/y/z 并在 y 上加高度偏移。适配器的 records 保存每次 intent、operation ID、receipt,调用者负责持久化;命令查询延迟可能让移动返回 timing_limited。

从已知方块构建同高路线 ​

text
from neomega_runtime.navigation import FlatGrid, FlatNavigation

FlatGrid(connection_id: str, dimension: int, y: int,
         cells: frozenset, observed_monotonic: float)
FlatGrid.from_clearance(*, connection_id, dimension, y, columns, observed_monotonic)
grid.route(start, target, *, max_steps=64)
FlatNavigation(ctx)
await navigation.run(
    grid, start, target, *, observe, journal, control,
    auth_input_height_offset, cancel=None, timeout=60,
    max_map_age=30, max_sample_age=.5, max_steps=64,
    step_timeout_ms=5000, speed=.1, tolerance=.2,
)

y 为脚部高度。columns[(x,z)] = (solid_floor, clear_feet, clear_head) 的三个值都必须为字面值 True,该格才可通行:要求完整实心地面与上方两格空间。缺失、未加载、半格形状或不确定状态不能当空气。由方块观察适配器分类;SDK 不推断地形。

网格最多 4096 格,构造时观察年龄不能超过 30 秒。route 是确定性的四邻域最短路线,返回含起点的格中心 (x+.5, y, z+.5) 元组;max_steps 为 1..256。以下是纯离线路线计算示例,不证明这些坐标在游戏内可走:

python
import time
from neomega_runtime.navigation import FlatGrid

grid = FlatGrid.from_clearance(
    connection_id='offline-example', dimension=0, y=64,
    columns={(0, 0): (True, True, True),
             (1, 0): (True, True, True),
             (1, 1): (True, True, True)},
    observed_monotonic=time.monotonic(),
)
assert grid.route((0, 0), (1, 1)) == (
    (.5, 64, .5), (1.5, 64, .5), (1.5, 64, 1.5),
)

执行路线时,observe() 返回 position(脚部坐标三元组)、connection_id、dimension、initial_tick、auth_input_revision、observed_monotonic。必须使用当前位置与原生审计;起点横向距离格中心各轴不得超过 0.2 格,后续位置要符合上一 waypoint。journal(record) 异步持久化路线和每一步 intent、ID、receipt;即使日志写入慢,也不会刷新原观察年龄。

run 整体预算 0.1..120 秒,地图年龄 0.1..30 秒,采样年龄 0.01..1 秒,单段 100..10000 毫秒,导航容差 0.05..0.2。每个 waypoint 各提交一次原生动作,只接受 verified 且 arrived / already_at_target 后继续。返回记录的 status 包括 arrived、busy、cancelled、stopped、unknown;异常时保留 navigation.record,可能为 interrupted。未知动作会封锁共享控制器。路线不会动态重规划,也不支持上下台阶、洞穴、游泳或全地形自动寻路。

跳跃与原生输入操作 ​

这些入口通过 ctx.operations.prepare(operation, arguments, idempotency_key=..., deadline=...) 准备并持久化后提交,没有对应的 ctx.jump()。

操作参数与返回语义
framework.self.jump必填 connection_id、initial_tick、position、ground_y、eye_height、pitch、yaw、head_yaw、delta_semantics、dimension;可选正数 expected_auth_input_revision。eye_height 在 (0,3),position[1] 与 ground_y+eye_height 在 float32 下误差不超过 1e-4;delta_semantics 为 end_velocity 或 position_difference。最多发送 24 帧;完整 dispatched 仅证明发送,不证明起跳和落地。数值检查不证明接地。
framework.self.auth_input.observe可选 connection_id、max_age_ms(1..10000,默认 1000)。返回原生输入观察;读取成功不保证每个字段都已观察到,须检查可用性与新鲜度。
framework.self.action_audit.read可选 after={connection_id, sequence};sequence 为 0..9007199254740991。返回动作审计;连接变化、缺口与输入 revision 都要由调用方处理。
framework.self.auth_input.bootstrap发送一个显式中性候选,见下方 SDK builder。成功只表示本地接纳并写出,server_accepted、usable_as_movement_clock 不能据此设真。
framework.self.auth_input.sequence必填 connection_id、expected_uuid、initial_tick、expected_auth_input_revision、initial_position、bounds_min、bounds_max、dimension、cadence_ms、timeout_ms、auth_input_height_offset、frames。仅 4..12 帧,间隔 50..100 毫秒,总预算 100..1500 毫秒,每轴空间跨度不超过 8 格。帧 tick 连续、同高,完整姿态与重复角度字段都要提供,所有帧朝向相同,最后四帧必须中性;这不是生产移动配置。返回 ledger 不证明步行或服务端停止。

Bootstrap 的纯准备函数返回 OperationIntent,不会 IO 或自动重试:

text
from neomega_runtime.movement import prepare_auth_input_bootstrap

prepare_auth_input_bootstrap(
    operations, *, connection_id, expected_auth_input_revision, expected_uuid,
    dimension, position, pitch, yaw, head_yaw, candidate_tick,
    auth_input_height_offset, idempotency_key, deadline,
)

position 是精确线协议坐标,高度偏移只用于验证查询。pitch 范围 ±90,yaw/head_yaw 为 ±360,candidate tick 需为 0..2**64-1-1000。不要在失败或未知后自动尝试下一个 candidate。

控制器的生命周期 ​

同一机器人在同一 worker 中共享一个 ActionControl,包括移动、物品动作和瞄准战斗。它只协调同进程参与者,不是跨插件或跨客户端的 Host 独占租约。

python
from neomega_runtime.action_control import ActionControl

control = ActionControl()
# control.blocked / control.blocked_record 读取封锁状态与副本。
# 持锁时 control.block(record) 保存待核对记录。
# 停止活动控制后 await control.reconcile(check)。

check(record) 必须异步核对原操作和当前世界/输入观察,只有确实支持恢复时才返回 True。不要传 lambda: True,也不要换一把锁来绕过 unknown。取消请求成功不等于服务端已停止;停止插件前保存活动记录,恢复时先核对再接受新任务。

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