Kzeroko KTM2

问路 API

服务端线程上的目的地搜索、结构勘测、工作上限、结果处理、对话集成与指南针状态。

更新于 2026/9/30 15 分钟阅读

WayfindingAPI 搜索当前维度中的群系、地形家族或结构,不接管调用方的交互。回调给出受工作预算限制的搜索结果;使用前仍须验证玩家、世界与当前交互是否有效。survey 查找一组结构最近的已生成起始点,并附带边界。

入口

门面为 net.kzeroko.isekaiexpansion.api.wayfinding.WayfindingAPI。公开记录 LocateTarget、LocateRequest、LocateResult、SurveyRequest、SurveyResult 位于同包,实现位于 internal.wayfinding 与 world.terrain.runtime。

在逻辑服务端线程使用已存在的 ServerWorld。locate、cancel、survey 与 cancelSurvey 在其他线程会抛出 IllegalStateException;惰性目录没有线程断言,但使用未同步的映射,因此也须遵守同一要求。世界创建前没有可用入口。

常见用法

发起搜索并拒绝过期玩家上下文

static void findDesert(ServerPlayerEntity player) {
    var world = player.getServerWorld();
    var target = new LocateTarget(LocateTarget.Kind.BIOME,
            new Identifier("minecraft", "desert"));
    var request = new LocateRequest(target, player.getBlockPos(), 512, 8192);
    WayfindingAPI.locate(world, player.getUuid(), request, result -> {
        if (world.getServer().getPlayerManager().getPlayer(player.getUuid()) != player
                || player.getWorld() != world) return;
        player.sendMessage(Text.literal(result.status().name()), false);
    });
}

示例使用上述 API 包,以及 Minecraft 的 ServerPlayerEntity、Identifier 与 Text。界面调用还应像内置村民适配器一样,捕获并比较会话和 token。提交时可能同步调用回调,因此必须先建立上下文,再调用 locate。

读取目录或取消

static List<LocateTarget> biomeChoices(ServerWorld world) {
    return WayfindingAPI.destinations(world, LocateTarget.Kind.BIOME);
}

static void cancelSearch(ServerPlayerEntity player) {
    WayfindingAPI.cancel(player.getServerWorld(), player.getUuid());
}

示例使用 java.util.List 和 Minecraft 的 ServerWorld、ServerPlayerEntity。取消依据所有者 UUID,不依据维度;传入世界用于服务端线程检查。所有者没有任务时不执行任何变更。

勘测最近的村庄

static void nearestVillages(ServerPlayerEntity player) {
    var world = player.getServerWorld();
    var request = new SurveyRequest(List.of("#minecraft:village"),
            player.getBlockPos(), 2048, 5);
    WayfindingAPI.survey(world, player.getUuid(), request, result -> {
        if (world.getServer().getPlayerManager().getPlayer(player.getUuid()) != player) return;
        for (var found : result.structures())
            player.sendMessage(Text.literal(found.structure() + " at "
                    + found.center().toShortString()), false);
    });
}

示例使用同包的 SurveyRequest,以及 java.util.List 和 Minecraft 的 Text。选择器是结构 ID 或 #tag。每个结果都带有结构 ID、起始区块、完整包围盒和包围盒中心,调用方可以标出真实占地,而不只是一个定位点。WayfindingAPI.cancelSurvey(world, owner) 会以 CANCELLED 结束该所有者的勘测。

方法一览

门面与记录

签名返回或效果
destinations(ServerWorld, LocateTarget.Kind)按目标 ID 排序、去重的不可变列表;按世界对象与类别惰性缓存。
locate(ServerWorld, UUID, LocateRequest, Consumer<LocateResult>)返回 void;接收任务或立即回调终态结果。
cancel(ServerWorld, UUID)移除所有者任务,取消存在的地形 future,并回调 CANCELLED。
survey(ServerWorld, UUID, SurveyRequest, Consumer<SurveyResult>)返回 void;接收勘测或立即回调终态结果。
cancelSurvey(ServerWorld, UUID)移除所有者的勘测并回调 CANCELLED;所有者没有勘测时不执行任何变更。
new LocateTarget(Kind, Identifier)两字段不可为空;类别为 TERRAIN、BIOME、STRUCTURE。
LocateTarget.name()带回退的可翻译标签,规则见下文。
new LocateRequest(target, origin, minimumDistance, radius)目标不可为空,起点保存不可变副本;水平格数须满足 128 ≤ minimumDistance < radius ≤ 64000。
new LocateResult(status, target, dimension, position)位置保存不可变副本;FOUND 必须有位置,其余状态不能有。构造器仅检查此约定,不检查世界安全或目标注册。
new SurveyRequest(structures, origin, radius, limit)选择器列表不能为空,保存不可变副本,每项须是可解析的 ID 或 #tag;起点保存不可变副本;水平格数须满足 128 ≤ radius ≤ 16384;1 ≤ limit ≤ 32。此处不检查是否已注册。
new SurveyResult(status, dimension, structures)起始点保存不可变副本。服务按由近到远的顺序提供,且只在 COMPLETE 和 PARTIAL 时提供。
SurveyResult.Found(structure, start, bounds, center, distance)结构 ID、起始 ChunkPos、完整 BlockBox、包围盒中心,以及起点到放置定位点的水平距离。

请求起点的 Y 是群系采样输入之一,不是唯一采样高度。半径为水平距离,候选检查包含边界。搜索顺序与粗粒度采样不保证返回最近的目的地。

状态含义
FOUND存在已确认位置。
NOT_FOUND搜索按当前算法完成但未命中;稀疏采样不等于遍查世界。
UNAVAILABLE目标不在该维度和类别目录中。
BUSY所有者已有任务、全局上限、同类专用搜索忙,或执行器拒绝。
CANCELLED显式取消或生命周期重置。
LIMIT_REACHED真实时间或探测预算耗尽、结构候选被截断、不支持的放置类型,或区块结果不完整。
FAILED准备或搜索抛出异常,详见服务端日志。

被禁用的地形家族仍可能存在于目录。管理命令会在提交前检测禁用状态;直接调用 API 则可能返回 NOT_FOUND。群系源兼容但地形引擎不可用时,准备阶段返回 FAILED。

目录与名称

类别目录来源搜索实现
BIOME当前维度群系源的条目,而非全局群系注册表。采样生成器群系,不请求区块。
TERRAIN群系源为 TerrainBiomeSource 时的全部 TerrainFamily ID。专用工作线程执行已准备的地形引擎任务,不请求区块。
STRUCTURE当前世界中拥有非空放置列表的实时结构注册项。候选放置与实际结构起点。

群系与地形使用 ID 的 biome 翻译键,缺失时回退为 ID。结构使用 structure.<namespace>.<path>,路径中的斜杠改为点。英文回退名称按斜杠、下划线、点和连字符分词,再将每词首字母大写。目录按 ID 排序,翻译后界面的排序由展示层负责。

工作预算

限制数值与范围
活动任务全局最多 8 个,每个所有者 UUID 最多 1 个;新请求不会替换该所有者旧任务。
结构搜索全局最多 1 个活动结构任务。
地形搜索全局最多 1 个活动地形 future;使用单个守护工作线程,队列容量为 1。
共享刻预算2,000,000 纳秒(2 ms),任务轮换起始顺序。
群系工作量共享截止时间内,每任务每刻最多 1024 步;每任务最多 300000 个唯一探测点。
结构工作量每刻最多 1 次提交或轮询步骤;最多 512 个候选探测,已等待中的候选可继续完成。
任务期限群系和结构为真实时间 30 秒,地形为真实时间 120 秒。
结构候选随机分布候选映射阈值 16384,枚举最多检查 32768 个偏移后截断。

这些是调度预算,不是整次服务端刻耗时的硬上限:候选准备发生在提交期间,回调内联执行,Minecraft 自行调度区块工作。等待中的结构可以在共享截止时间之后轮询,以刷新请求票据。已完成的地形 future 会在期限检查前读取。

搜索语义

群系使用相对请求起点的 64 格 X/Z 网格。高度包含截断到世界边界的起点 Y,以及世界底部 +16 起每隔 32 格、低于世界顶部的高度,最后去重排序。先标记 minimumDistance +64 内命中的种子,再沿 8 方向按 64 和 128 格及相邻采样高度扩展,最后从内向外寻找未被排除的命中点。128 格连接可以跨过一格采样缝隙。采样受世界边界限制。这是保守的采样连通区排除,不是精确群系拓扑。

结构搜索支持同心环与随机分布放置。起始区块去重,按定位点的水平范围和世界边界过滤,再按距离排序。候选须通过 shouldGenerate,随后通过调度器请求 STRUCTURE_STARTS 并用 getNow 轮询,不在服务端刻线程 join。实际起点必须有子结构,且包围盒上最近的水平点距起点至少为 minimumDistance。返回放置规则的定位点,不将结构标记为已探索。不支持的放置类型或区块结果失败会使搜索不完整,耗尽此类候选时返回 LIMIT_REACHED。同心环候选不使用随机分布映射阈值,但仍受服务的探测数和期限限制。

地形准备在服务端线程捕获引擎、采样器与边界,再提交采样任务。世界树相关家族检查共享区域,平原检查规划区域。其他家族先检查确定性加权顺序中目标家族排首位的分区,避免构造无关几何;首轮未找到结果时,再完整枚举分区并保留正常竞争规则。这只改变搜索顺序,不改变生成归属,也不保证返回最近结果。使用 64 格环形采样、对齐到 4 格的坐标、家族与群系确认及请求水平范围;区域采样还要求权重大于 0.6。返回位置的 Y = 0,仅供方向或指南针引用,不是已验证的传送安全点。枚举与确认期间检查线程中断。

结构勘测

勘测回答「这些结构最近的已生成起始点在哪里」,并给出真实边界。它与 locate 共用结构预测规则,但在独立的服务中运行,同一个所有者可以同时持有一个搜索任务和一个勘测。

状态含义
COMPLETE列表包含范围内最近的 limit 个起始点;范围内不足这么多时包含全部。
PARTIAL期限或确认预算先用完。列表按由近到远包含已确认的起始点,可能还有更近但未确认的。
UNAVAILABLE没有任何选择器解析到在此世界有放置规则的结构。
BUSY所有者已有勘测,或已有 4 个勘测在运行。
CANCELLEDcancelSurvey、数据重载成功或服务器停止。
FAILED准备或推进时抛出异常,见服务器日志。
上限数值与范围
活动勘测全局最多 4 个;每个所有者 UUID 最多 1 个。与搜索任务的上限相互独立。
共享 tick 预算3,000,000 纳秒(3 ms),勘测顺序轮换。
区块请求每个勘测同时最多 3 个。
确认次数每个勘测最多 96 个候选区块。
期限现实时间 120 秒;到期后以 PARTIAL 返回已有结果。

选择器按给定顺序在当前结构注册表中解析,未知的 ID 和标签会被跳过并记录警告。候选来自半径和世界边界内的随机分布网格与同心环位置,其他放置类型不产生候选。共用同一放置规则的结构共享候选区块,每个区块只被认领一次。候选按放置定位点的水平距离由近到远尝试,这个距离也就是结果里的 distance。

候选须先通过 shouldGenerate 和结构存在检查;后者应用每个结构自己的选址规则,并在存档里已有区块数据时读取它。随后通过原版调度器把区块请求到 STRUCTURE_STARTS 来确认,每 tick 重新请求,从不阻塞等待。记录该组中第一个拥有子结构的起始点。不放置任何方块,也不把起始点标记为已探索。当确认了 limit 个起始点,且没有尚未测试或仍在请求中的候选比保留的最远一个更近时,勘测结束。

线程与生命周期

LocateService 在 END_SERVER_TICK 推进任务。回调位于服务端线程,包括立即返回的 BUSY、UNAVAILABLE 与准备失败。通常的任务完成会捕获并记录回调异常;最初的所有者已忙或全局上限分支直接调用回调,异常会传播给调用方。

数据重载成功与服务器停止时,会将当前任务以 CANCELLED 结束,中断地形任务、关闭工作线程并清空目录。失败重载不重置此服务。没有持久任务队列。内置对话适配器之外的调用方须自行处理断线或交互取消。完成回调应能在停服期间安全执行,避免在重置回调中启动替代任务。

SurveyService 同样在 END_SERVER_TICK 推进,使用自己的预算。BUSY、UNAVAILABLE 与准备阶段的 FAILED 在调用 survey 时就会回调。完成回调的异常会被捕获并记录,只有 BUSY 分支直接调用回调。数据重载成功与服务器停止会以 CANCELLED 结束所有勘测。

村民适配器与指南针写入

WayfindingDialogue 是内部 Blabber 适配器。菜单为 isekaiexpansion:wayfinding/villager,问路、交易和告别分别处理。交易处理器在铁匠路由之后,为TRADE或NO_TRADE中符合条件且受到欢迎的交谈选择它。重大与轻微负面流言合计绝对值至少为 50 时,不进入问路路由。

资格要求成年且清醒。制图师了解全部 3 类;农民、渔夫和牧羊人仅在 floorMod(uuid.hashCode(), 3) == 0 时符合条件,了解群系与地形。两类搜索半径分别为 16384 与 6144 格。继续交互要求双方存活、同世界、距离平方不超过 64(8 格),村民没有攻击者。

开始搜索时,适配器设置基于 nanoTime 的 30 秒冷却,排除距离为 512。它捕获世界、screen handler、对话会话 UUID 和阻塞对象 token。结果到达时,重新检查全部上下文与村民可用性,再替换面板。取消搜索对象会取消 API 任务。无位置的各类结果共用同一“不知道”答复。

方向由 atan2(dx, -dz) / (π / 4) 四舍五入映射到 8 个扇区。距离带为少于 1500、少于 4000、少于 9000 与其余距离,均从捕获起点计算。对话选项携带目的地 ID 与标签,已找到坐标保留在服务端回调中。

指南针选项检查快捷栏 0–8 格,复制 Items.COMPASS 物品堆作为报价快照。写入前,适配器检查活动村民,并用 ItemStack.areEqual 比较当前物品与原副本;写入器还检查格子、目标位置与当前维度。数量大于 1 时拆出一枚放到第一个空快捷栏格,没有空格则失败。

NBT 键类型默认值含义
LodestonePosobject标记前可不存在含整数 X、Y、Z 的目标方块位置,覆盖旧位置。
LodestonePos.Xinteger从结果写入目标 X。
LodestonePos.Yinteger从结果写入目标 Y;地形结果为 0。
LodestonePos.Zinteger从结果写入目标 Z。
LodestoneDimensionidentifier从结果写入维度 ID。
LodestoneTrackedboolean写入 false对此标记禁用实体磁石校验。
IsekaiDestinationidentifier从结果写入目标 ID;没有单独保存目的地类别。

这些是物品存档字段,不是编写格式。修改后将背包标记为 dirty 并同步 screen handler 内容。玩家没有提供指南针时,不会凭空创建指南针。

管理工具与验证

规范根命令为 /isekaiexpansion,/ise 为别名。以下分支要求权限等级 2。

命令行为
/ise find <biome/terrain/structure> <destination> [radius] [exclude]默认半径 8192、排除距离 512 格。显式半径为 1024–64000,排除距离为 128–63999 且小于半径。补全使用当前维度目录。
/ise find cancel取消命令所有者的任务。
/ise dev dumpStructure用全部实时结构注册表的有序 ID 覆盖 config/isekaiseries/ktm2structuredump.json。
/ise dev dumpStructureTranslations覆盖 config/isekaiseries/structure_translations/en_us.json 与 zh_cn.json,生成英文标签与空白中文翻译模板。

实体命令来源使用实体 UUID,所有无实体来源共享零 UUID。因此玩家命令与该玩家的问路对话共用任务槽。命令输出坐标,并提供 /execute in <dimension> run tp @s <x> ~ <z> 建议,不执行传送,也不选择安全 Y。翻译导出包含全部已注册结构,与维度中过滤后的目的地列表不同。

检查同所有者拒绝、8 个任务上限、专用任务上限、取消与重载、回调上下文变化、禁用地形、边界排除、多层或洞穴群系及结构边界。确认叠放指南针只拆到快捷栏,报价变化会失败,满快捷栏保留原物品,只覆盖所选指南针。分别在普通生成器与兼容地形生成器中验证;有限搜索失败不能证明目标不存在。

相关页面