modsmith 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +6 -0
- package/README.md +131 -20
- package/bin/modsmith.mjs +573 -405
- package/docs/conformance/README.md +62 -0
- package/docs/conformance/farmers-delight-1.21.1-3.3.6.json +209 -0
- package/docs/conformance/farmers-delight-dev-live.json +321 -0
- package/docs/conformance/moredelight-26.04.30-1.21.json +47 -0
- package/docs/conformance/supplementaries-1.21.1-4.0.2.json +227 -0
- package/docs/conformance/twilightforest-1.21.1-4.8.796.json +317 -0
- package/package.json +16 -3
- package/schema/manifest.schema.json +7 -0
- package/sidesheets/farmers-delight-3.3.6.crops.json +42 -42
- package/src/block-shapes.mjs +176 -0
- package/src/calibrate.mjs +1 -0
- package/src/conformance-live.mjs +208 -0
- package/src/conformance.mjs +366 -0
- package/src/cortico-bridge.mjs +397 -325
- package/src/crops.mjs +246 -227
- package/src/import-dump.mjs +139 -0
- package/src/index.mjs +3 -1
- package/src/inspect.mjs +466 -461
- package/src/manifest-io.mjs +1 -1
- package/src/onboard.mjs +21 -3
- package/src/probe.mjs +325 -316
- package/src/rcon.mjs +14 -8
- package/src/server-fingerprint.mjs +5 -5
- package/src/stations.mjs +22 -1
- package/src/validate.mjs +231 -223
- package/src/verify.mjs +18 -10
- package/templates/reference-bot/README.md +22 -0
- package/templates/reference-bot/index.mjs +59 -0
- package/templates/registry-dump/README.md +48 -0
- package/templates/registry-dump/build.gradle +39 -0
- package/templates/registry-dump/gradle.properties +2 -0
- package/templates/registry-dump/modsmith-dump-0.1.2.jar +0 -0
- package/templates/registry-dump/settings.gradle +9 -0
- package/templates/registry-dump/src/main/java/dev/modsmith/dump/RegistryDumpMod.java +98 -0
- package/templates/registry-dump/src/main/resources/fabric.mod.json +18 -0
- package/types/index.d.ts +174 -135
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 最小参考消费者:不依赖 Cortico,只证明「manifest + ids → 普通 mineflayer bot 能用」。
|
|
3
|
+
*
|
|
4
|
+
* 用法(先 npm i modsmith mineflayer):
|
|
5
|
+
* node index.mjs --host 127.0.0.1 --port 25565 \
|
|
6
|
+
* --manifest ../../mods/<pack>.json --ids ../../mods/<pack>-ids.json
|
|
7
|
+
*
|
|
8
|
+
* 只读:连上、在 inject_allowed 前注入注册表、打印方块形状/实体/boss 检查,然后退出。
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import mineflayer from 'mineflayer';
|
|
12
|
+
import { installModRegistry, installMineflayerFixes } from 'modsmith';
|
|
13
|
+
|
|
14
|
+
function arg(name, fallback) {
|
|
15
|
+
const i = process.argv.indexOf(`--${name}`);
|
|
16
|
+
return i >= 0 && process.argv[i + 1] ? process.argv[i + 1] : fallback;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const manifestPath = arg('manifest');
|
|
20
|
+
const idsPath = arg('ids');
|
|
21
|
+
if (!manifestPath || !idsPath) {
|
|
22
|
+
console.error('要 --manifest <manifest.json> --ids <ids.json>');
|
|
23
|
+
process.exit(2);
|
|
24
|
+
}
|
|
25
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
26
|
+
const ids = JSON.parse(readFileSync(idsPath, 'utf8'));
|
|
27
|
+
const bot = mineflayer.createBot({
|
|
28
|
+
host: arg('host', '127.0.0.1'),
|
|
29
|
+
port: Number(arg('port', '25565')),
|
|
30
|
+
username: arg('username', 'ModReference'),
|
|
31
|
+
version: arg('version', '1.21.1'),
|
|
32
|
+
auth: 'offline',
|
|
33
|
+
viewDistance: 2,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 必须在 inject_allowed 之前;大 mod 的配方/命令/实体元数据包先丢掉,只读验证不需要。
|
|
37
|
+
const counts = installModRegistry(bot, { manifest, ids });
|
|
38
|
+
installMineflayerFixes(bot, { extraDrop: ['entity_metadata', 'declare_commands'], dropCommands: true });
|
|
39
|
+
|
|
40
|
+
bot.once('spawn', () => {
|
|
41
|
+
const blockName = Object.keys(manifest.blocks ?? {})[0];
|
|
42
|
+
const block = blockName ? bot.registry.blocksByName[blockName] : null;
|
|
43
|
+
const entityName = Object.keys(ids.entities ?? {})[0];
|
|
44
|
+
const entity = entityName ? bot.registry.entitiesByName[entityName] : null;
|
|
45
|
+
console.log(`bot ${bot.username} @ ${bot.version} ${bot.game?.dimension ?? ''}`);
|
|
46
|
+
console.log(`注入:方块 ${counts.blocks} / 状态 ${counts.states} / 物品 ${counts.items} / 实体 ${counts.entities}`);
|
|
47
|
+
if (block) {
|
|
48
|
+
const shapes = bot.registry.blockCollisionShapes?.blocks?.[blockName];
|
|
49
|
+
console.log(`方块 ${blockName}: states ${block.stateShapes?.length ?? shapes?.length ?? 0}`);
|
|
50
|
+
}
|
|
51
|
+
if (entity) console.log(`实体 ${entityName}: ${entity.displayName ?? entity.name}${entity.boss ? ' BOSS' : ''}`);
|
|
52
|
+
bot.quit('reference done');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
bot.on('error', (err) => {
|
|
56
|
+
console.error(`连接/消费失败:${err.message}`);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
try { bot.quit('reference error'); } catch { /* noop */ }
|
|
59
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# modsmith registry dump
|
|
2
|
+
|
|
3
|
+
A tiny Fabric **server-side** mod that writes the server's real registry to
|
|
4
|
+
`config/modsmith-dump.json` right after startup:
|
|
5
|
+
|
|
6
|
+
```json
|
|
7
|
+
{
|
|
8
|
+
"blocks": { "supplementaries:ash": [{ "props": { "layers": "1" }, "stateId": 63586 }] },
|
|
9
|
+
"items": { "supplementaries:ash": 2437 },
|
|
10
|
+
"entities": {
|
|
11
|
+
"twilightforest:naga": { "id": 158, "spawnGroup": "monster", "width": 1.2, "height": 2.5 }
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Entities (0.1.2+) are what make mod bosses readable: without them the client only
|
|
17
|
+
sees a number, so a Naga shows up as `unknown` in the bot's logs and tool readouts.
|
|
18
|
+
|
|
19
|
+
It registers **no blocks or items**, so it does not change the registry. Install
|
|
20
|
+
it once, start the server, take the dump, stop the server and **remove the jar**
|
|
21
|
+
before running the host. Then:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
modsmith import-dump config/modsmith-dump.json \
|
|
25
|
+
--manifest mods/<pack>.json \
|
|
26
|
+
--ids mods/<pack>-ids.json \
|
|
27
|
+
--server-mods mods
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This replaces the hours-long `calibrate` (`setblock` per state) with a seconds-long
|
|
31
|
+
registry read. The prebuilt jar is bundled with modsmith at
|
|
32
|
+
`templates/registry-dump/modsmith-dump-0.1.2.jar` (run `modsmith dump-jar` to print
|
|
33
|
+
its absolute path); it is also attached to the
|
|
34
|
+
[registry-dump-v0.1.2 release](https://github.com/xiaoxiao150/modsmith/releases/tag/registry-dump-v0.1.2).
|
|
35
|
+
`import-dump` still filters: only manifest blocks/items, every entity in that
|
|
36
|
+
namespace, and nothing inside the vanilla ranges (block state ids or entity ids
|
|
37
|
+
0–129).
|
|
38
|
+
|
|
39
|
+
## Build
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
cd templates/registry-dump
|
|
43
|
+
gradle build # Java 21, Gradle 8.x
|
|
44
|
+
# jar: build/libs/modsmith-dump-0.1.2.jar
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Copy the jar into the server's `mods/`, restart, then check the log for
|
|
48
|
+
`wrote registry dump to .../config/modsmith-dump.json`.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
plugins {
|
|
2
|
+
id 'fabric-loom' version '1.9-SNAPSHOT'
|
|
3
|
+
id 'java'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
version = '0.1.2'
|
|
7
|
+
group = 'dev.modsmith'
|
|
8
|
+
base {
|
|
9
|
+
archivesName = 'modsmith-dump'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
repositories {
|
|
13
|
+
mavenCentral()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
dependencies {
|
|
17
|
+
minecraft "com.mojang:minecraft:1.21.1"
|
|
18
|
+
mappings "net.fabricmc:yarn:1.21.1+build.3:v2"
|
|
19
|
+
modImplementation "net.fabricmc:fabric-loader:0.16.9"
|
|
20
|
+
modImplementation "net.fabricmc.fabric-api:fabric-api:0.115.6+1.21.1"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
processResources {
|
|
24
|
+
inputs.property "version", project.version
|
|
25
|
+
inputs.property "minecraft_version", '1.21.1'
|
|
26
|
+
filesMatching("fabric.mod.json") {
|
|
27
|
+
expand "version": project.version, "minecraft_version": '1.21.1'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
tasks.withType(JavaCompile).configureEach {
|
|
32
|
+
it.options.release = 21
|
|
33
|
+
it.options.encoding = 'UTF-8'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
java {
|
|
37
|
+
sourceCompatibility = JavaVersion.VERSION_21
|
|
38
|
+
targetCompatibility = JavaVersion.VERSION_21
|
|
39
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
package dev.modsmith.dump;
|
|
2
|
+
|
|
3
|
+
import com.google.gson.GsonBuilder;
|
|
4
|
+
import com.google.gson.JsonArray;
|
|
5
|
+
import com.google.gson.JsonObject;
|
|
6
|
+
import net.fabricmc.api.ModInitializer;
|
|
7
|
+
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
|
8
|
+
import net.fabricmc.loader.api.FabricLoader;
|
|
9
|
+
import net.minecraft.SharedConstants;
|
|
10
|
+
import net.minecraft.block.Block;
|
|
11
|
+
import net.minecraft.block.BlockState;
|
|
12
|
+
import net.minecraft.entity.EntityDimensions;
|
|
13
|
+
import net.minecraft.entity.EntityType;
|
|
14
|
+
import net.minecraft.item.Item;
|
|
15
|
+
import net.minecraft.registry.Registries;
|
|
16
|
+
import net.minecraft.state.property.Property;
|
|
17
|
+
import net.minecraft.util.Identifier;
|
|
18
|
+
import org.slf4j.Logger;
|
|
19
|
+
import org.slf4j.LoggerFactory;
|
|
20
|
+
|
|
21
|
+
import java.io.IOException;
|
|
22
|
+
import java.nio.file.Files;
|
|
23
|
+
import java.nio.file.Path;
|
|
24
|
+
import java.util.Map;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Writes the server's real registry ids right after it starts.
|
|
28
|
+
*
|
|
29
|
+
* Why: measuring 3000+ block states over RCON takes hours. The registry is already
|
|
30
|
+
* the source of truth, so dump it in one pass. This mod registers no blocks/items,
|
|
31
|
+
* so it does not change the registry; remove the jar after the dump.
|
|
32
|
+
*/
|
|
33
|
+
public class RegistryDumpMod implements ModInitializer {
|
|
34
|
+
private static final Logger LOG = LoggerFactory.getLogger("modsmith-dump");
|
|
35
|
+
|
|
36
|
+
@Override
|
|
37
|
+
public void onInitialize() {
|
|
38
|
+
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
|
|
39
|
+
try {
|
|
40
|
+
dump();
|
|
41
|
+
} catch (Throwable error) {
|
|
42
|
+
LOG.error("registry dump failed", error);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private static void dump() throws IOException {
|
|
48
|
+
JsonObject root = new JsonObject();
|
|
49
|
+
root.addProperty("schema", 1);
|
|
50
|
+
root.addProperty("minecraftVersion", SharedConstants.getGameVersion().getName());
|
|
51
|
+
root.addProperty("dumpMod", "modsmith-dump");
|
|
52
|
+
root.addProperty("dumpModVersion", "0.1.2");
|
|
53
|
+
|
|
54
|
+
JsonObject blocks = new JsonObject();
|
|
55
|
+
for (Block block : Registries.BLOCK) {
|
|
56
|
+
Identifier blockId = Registries.BLOCK.getId(block);
|
|
57
|
+
JsonArray states = new JsonArray();
|
|
58
|
+
for (BlockState state : block.getStateManager().getStates()) {
|
|
59
|
+
JsonObject entry = new JsonObject();
|
|
60
|
+
JsonObject props = new JsonObject();
|
|
61
|
+
for (Map.Entry<Property<?>, Comparable<?>> prop : state.getEntries().entrySet()) {
|
|
62
|
+
props.addProperty(prop.getKey().getName(), prop.getValue().toString());
|
|
63
|
+
}
|
|
64
|
+
entry.add("props", props);
|
|
65
|
+
entry.addProperty("stateId", Block.STATE_IDS.getRawId(state));
|
|
66
|
+
states.add(entry);
|
|
67
|
+
}
|
|
68
|
+
blocks.add(blockId.toString(), states);
|
|
69
|
+
}
|
|
70
|
+
root.add("blocks", blocks);
|
|
71
|
+
|
|
72
|
+
JsonObject items = new JsonObject();
|
|
73
|
+
for (Item item : Registries.ITEM) {
|
|
74
|
+
Identifier itemId = Registries.ITEM.getId(item);
|
|
75
|
+
items.addProperty(itemId.toString(), Registries.ITEM.getRawId(item));
|
|
76
|
+
}
|
|
77
|
+
root.add("items", items);
|
|
78
|
+
|
|
79
|
+
// 实体:名字 → 数字 id + 碰撞箱 + 生成组(monster/creature/...)。
|
|
80
|
+
// 机器人按数字 id 认实体;没有这张表,模组 boss 在她眼里叫 unknown。
|
|
81
|
+
JsonObject entities = new JsonObject();
|
|
82
|
+
for (EntityType<?> type : Registries.ENTITY_TYPE) {
|
|
83
|
+
Identifier typeId = Registries.ENTITY_TYPE.getId(type);
|
|
84
|
+
EntityDimensions dims = type.getDimensions();
|
|
85
|
+
JsonObject entry = new JsonObject();
|
|
86
|
+
entry.addProperty("id", Registries.ENTITY_TYPE.getRawId(type));
|
|
87
|
+
entry.addProperty("spawnGroup", type.getSpawnGroup().getName());
|
|
88
|
+
entry.addProperty("width", dims.width());
|
|
89
|
+
entry.addProperty("height", dims.height());
|
|
90
|
+
entities.add(typeId.toString(), entry);
|
|
91
|
+
}
|
|
92
|
+
root.add("entities", entities);
|
|
93
|
+
|
|
94
|
+
Path out = FabricLoader.getInstance().getConfigDir().resolve("modsmith-dump.json");
|
|
95
|
+
Files.writeString(out, new GsonBuilder().setPrettyPrinting().create().toJson(root));
|
|
96
|
+
LOG.info("wrote registry dump to {}", out.toAbsolutePath());
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "modsmith_dump",
|
|
4
|
+
"version": "${version}",
|
|
5
|
+
"name": "modsmith registry dump",
|
|
6
|
+
"description": "Dump every block state id and item id from the running server registry into config/modsmith-dump.json. Registers no content; remove it after the dump.",
|
|
7
|
+
"authors": ["modsmith"],
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"environment": "server",
|
|
10
|
+
"entrypoints": {
|
|
11
|
+
"main": ["dev.modsmith.dump.RegistryDumpMod"]
|
|
12
|
+
},
|
|
13
|
+
"depends": {
|
|
14
|
+
"fabricloader": ">=0.16.0",
|
|
15
|
+
"fabric-api": "*",
|
|
16
|
+
"minecraft": "~${minecraft_version}"
|
|
17
|
+
}
|
|
18
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,135 +1,174 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* modsmith 的 TypeScript 面(手写,只声明宿主用到的窄面)。
|
|
3
|
-
* modsmith 本体是 ESM JS;这仨类型按结构最小化,宿主自己的类型(ModManifest 等)
|
|
4
|
-
* 在宿主侧定义,传进来时按需收窄。
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export interface RegistryCounts {
|
|
8
|
-
blocks: number;
|
|
9
|
-
states: number;
|
|
10
|
-
items: number;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export function
|
|
26
|
-
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export function
|
|
36
|
-
export function
|
|
37
|
-
export function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
export function
|
|
86
|
-
export function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
1
|
+
/**
|
|
2
|
+
* modsmith 的 TypeScript 面(手写,只声明宿主用到的窄面)。
|
|
3
|
+
* modsmith 本体是 ESM JS;这仨类型按结构最小化,宿主自己的类型(ModManifest 等)
|
|
4
|
+
* 在宿主侧定义,传进来时按需收窄。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface RegistryCounts {
|
|
8
|
+
blocks: number;
|
|
9
|
+
states: number;
|
|
10
|
+
items: number;
|
|
11
|
+
/** 模组实体(registry-dump 0.1.2+ 的 entities;老 ids 为 0) */
|
|
12
|
+
entities: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ModPackLike {
|
|
16
|
+
manifest: object;
|
|
17
|
+
ids: object;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** bot 只按形状使用(bot.registry / bot._client),不依赖 mineflayer 的完整类型。 */
|
|
21
|
+
export function installModRegistry(bot: unknown, pack: ModPackLike): RegistryCounts;
|
|
22
|
+
export function installMineflayerFixes(bot: unknown): void;
|
|
23
|
+
|
|
24
|
+
/** 从 modsDir(setModsDir 设置,默认 cwd/mods)读 <name>.json 与 <name>-ids.json。 */
|
|
25
|
+
export function loadModPack(name: string): ModPackLike | null;
|
|
26
|
+
export function setModsDir(dir: string): void;
|
|
27
|
+
export function listPacks(): string[];
|
|
28
|
+
|
|
29
|
+
export interface ManifestIssueLike {
|
|
30
|
+
level: 'error' | 'warn';
|
|
31
|
+
path: string;
|
|
32
|
+
message: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function validateManifest(raw: unknown): ManifestIssueLike[];
|
|
36
|
+
export function hasErrors(issues: ManifestIssueLike[]): boolean;
|
|
37
|
+
export function describeIssues(issues: ManifestIssueLike[]): string[];
|
|
38
|
+
export function parseManifest<T = Record<string, unknown>>(raw: unknown): T | null;
|
|
39
|
+
export function statsOf(manifest: Record<string, unknown>, ids?: Record<string, unknown> | null): Record<string, number>;
|
|
40
|
+
|
|
41
|
+
/** 服务器 mods 目录指纹:ids.serverMods 的写入与加载侧校验(calibrate --server-mods)。 */
|
|
42
|
+
export interface ServerModsFingerprint {
|
|
43
|
+
fingerprint: string;
|
|
44
|
+
files: Array<{ file: string; bytes: number; sha256: string }>;
|
|
45
|
+
}
|
|
46
|
+
export function fingerprintDir(dir: string): ServerModsFingerprint;
|
|
47
|
+
export function checkServerMods(
|
|
48
|
+
stored: ServerModsFingerprint | undefined,
|
|
49
|
+
dir: string | undefined,
|
|
50
|
+
): { ok: boolean; fatal: boolean; lines: string[] };
|
|
51
|
+
|
|
52
|
+
/** 清单 → mineflayer 可消费的合成视图(pattern/key 或候选数组,已归一)。 */
|
|
53
|
+
export interface CraftRecipeView {
|
|
54
|
+
id?: string;
|
|
55
|
+
type: 'crafting_shaped' | 'crafting_shapeless';
|
|
56
|
+
pattern?: string[];
|
|
57
|
+
key?: Record<string, { item?: string; id?: string; tag?: string } | Array<{ item?: string; id?: string; tag?: string }>>;
|
|
58
|
+
ingredients?: Array<Array<{ item?: string; id?: string; tag?: string }>>;
|
|
59
|
+
result: { id: string; count: number };
|
|
60
|
+
}
|
|
61
|
+
export function craftRecipeViews(manifest: object): CraftRecipeView[];
|
|
62
|
+
|
|
63
|
+
/** 配方依赖图 + 目标规划(宿主 make 技能的输入)。 */
|
|
64
|
+
export interface PlannedStep {
|
|
65
|
+
skill: 'take' | 'craft' | 'cut' | 'pot' | 'cook' | 'smelt' | 'place' | 'use' | 'pickup';
|
|
66
|
+
item?: string;
|
|
67
|
+
items?: string[];
|
|
68
|
+
recipe?: string;
|
|
69
|
+
input?: string;
|
|
70
|
+
fuel?: string;
|
|
71
|
+
block?: string;
|
|
72
|
+
times?: number;
|
|
73
|
+
count?: number;
|
|
74
|
+
}
|
|
75
|
+
export interface PlanResult {
|
|
76
|
+
ok: boolean;
|
|
77
|
+
steps: PlannedStep[];
|
|
78
|
+
missing: Array<{ item: string; reason: string }>;
|
|
79
|
+
notes: string[];
|
|
80
|
+
}
|
|
81
|
+
export function buildRecipeGraph(
|
|
82
|
+
manifest: object,
|
|
83
|
+
opts?: { stations?: Array<{ id: string; kind: string; recipeType?: string; recipeTypes?: string[] }> },
|
|
84
|
+
): { byResult: Map<string, unknown[]>; views: CraftRecipeView[] };
|
|
85
|
+
export function canMake(graph: { byResult: Map<string, unknown[]> }, item: string): boolean;
|
|
86
|
+
export function outputOf(recipe: object): string | null;
|
|
87
|
+
export function outputCountOf(recipe: object): number;
|
|
88
|
+
export function planTarget(
|
|
89
|
+
graph: { byResult: Map<string, unknown[]> },
|
|
90
|
+
opts: {
|
|
91
|
+
item: string;
|
|
92
|
+
count?: number;
|
|
93
|
+
have?: Record<string, number>;
|
|
94
|
+
/** 不在背包、但在够得着的箱子里的东西(缺料时排 take) */
|
|
95
|
+
stock?: Record<string, number>;
|
|
96
|
+
stations?: Array<{ id: string; kind: string; recipeType?: string; recipeTypes?: string[] }>;
|
|
97
|
+
maxSteps?: number;
|
|
98
|
+
},
|
|
99
|
+
): PlanResult;
|
|
100
|
+
|
|
101
|
+
/** vanilla 物品数字 id → 全名(minecraft-data 表)。 */
|
|
102
|
+
export function vanillaItemTable(mcVersion?: string): Record<string, string>;
|
|
103
|
+
|
|
104
|
+
/** 文法发现:未知序列化器的候选(discoverSerializers 的产物,永不自动生效)。 */
|
|
105
|
+
export interface DiscoveredSerializer {
|
|
106
|
+
typeId: number;
|
|
107
|
+
fields: Array<{ name: string; kind: string; item?: Array<{ name: string; kind: string }> }>;
|
|
108
|
+
shape: string | null;
|
|
109
|
+
occurrences: number;
|
|
110
|
+
slotIds: number[];
|
|
111
|
+
packetValidated: boolean;
|
|
112
|
+
}
|
|
113
|
+
export interface DiscoveryResult {
|
|
114
|
+
ok: boolean;
|
|
115
|
+
count: number;
|
|
116
|
+
segments: Array<{ index: number; typeId: number; start: number; end: number; known: boolean; occurrences: number }>;
|
|
117
|
+
discovered: DiscoveredSerializer[];
|
|
118
|
+
candidates: Record<string, DiscoveredSerializer[]>;
|
|
119
|
+
notes: string[];
|
|
120
|
+
budgetLeft: number;
|
|
121
|
+
}
|
|
122
|
+
export function discoverSerializers(
|
|
123
|
+
buf: Buffer,
|
|
124
|
+
opts?: {
|
|
125
|
+
serializers?: Record<string, { name?: string; fields: Array<{ name: string; kind: string; item?: unknown }> }>;
|
|
126
|
+
knownItemIds?: Set<number>;
|
|
127
|
+
maxItemId?: number;
|
|
128
|
+
maxTypeId?: number;
|
|
129
|
+
budget?: number;
|
|
130
|
+
maxCandidates?: number;
|
|
131
|
+
trace?: (phase: string, info: unknown) => void;
|
|
132
|
+
},
|
|
133
|
+
): DiscoveryResult;
|
|
134
|
+
export function sidesheetFromDiscovery(
|
|
135
|
+
result: DiscoveryResult,
|
|
136
|
+
meta?: { mod?: string },
|
|
137
|
+
): Record<string, unknown>;
|
|
138
|
+
|
|
139
|
+
/** 接包验收(conformance)的一条检查。 */
|
|
140
|
+
export interface ConformanceCheck {
|
|
141
|
+
id: string;
|
|
142
|
+
level: 'pass' | 'warn' | 'fail';
|
|
143
|
+
subject: string;
|
|
144
|
+
message: string;
|
|
145
|
+
details?: unknown;
|
|
146
|
+
}
|
|
147
|
+
export interface ConformanceSummary {
|
|
148
|
+
pass: number;
|
|
149
|
+
warn: number;
|
|
150
|
+
fail: number;
|
|
151
|
+
total: number;
|
|
152
|
+
}
|
|
153
|
+
export interface ConformanceReport {
|
|
154
|
+
pack: string;
|
|
155
|
+
summary: ConformanceSummary;
|
|
156
|
+
checks: ConformanceCheck[];
|
|
157
|
+
live?: { username: string; version: string; dimension: string; position: unknown };
|
|
158
|
+
registry?: { blocks: number; states: number; items: number; entities: number };
|
|
159
|
+
}
|
|
160
|
+
export function checkManifest(manifest: object): ConformanceCheck[];
|
|
161
|
+
export function checkIds(
|
|
162
|
+
manifest: object,
|
|
163
|
+
ids: object,
|
|
164
|
+
opts?: { blockStateCeiling?: number; itemCeiling?: number; entityCeiling?: number; serverMods?: string },
|
|
165
|
+
): ConformanceCheck[];
|
|
166
|
+
export function checkRegistry(manifest: object, ids: object, registry: object): ConformanceCheck[];
|
|
167
|
+
export function summarize(checks: ConformanceCheck[]): ConformanceSummary;
|
|
168
|
+
export function runConformance(opts: {
|
|
169
|
+
manifest: object;
|
|
170
|
+
ids?: object | null;
|
|
171
|
+
registry?: object | null;
|
|
172
|
+
serverMods?: string;
|
|
173
|
+
mcv?: string;
|
|
174
|
+
}): ConformanceReport;
|