nucleation 0.8.0 → 0.9.2
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/TickSettleMode.d.mts +34 -0
- package/TickSettleMode.d.ts +34 -0
- package/TickSettleMode.mjs +84 -0
- package/TickSimulation.d.mts +312 -0
- package/TickSimulation.d.ts +312 -0
- package/TickSimulation.mjs +828 -0
- package/diplomat.config.mjs +3 -4
- package/index.d.mts +4 -0
- package/index.d.ts +4 -0
- package/index.mjs +5 -1
- package/nucleation.wasm +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,828 @@
|
|
|
1
|
+
// generated by diplomat-tool
|
|
2
|
+
import { NucleationError } from "./NucleationError.mjs"
|
|
3
|
+
import { Schematic } from "./Schematic.mjs"
|
|
4
|
+
import { TickSettleMode } from "./TickSettleMode.mjs"
|
|
5
|
+
import wasm from "./diplomat-wasm.mjs";
|
|
6
|
+
import * as diplomatRuntime from "./diplomat-runtime.mjs";
|
|
7
|
+
|
|
8
|
+
const TickSimulation_box_destroy_registry = new FinalizationRegistry((ptr) => {
|
|
9
|
+
wasm.TickSimulation_destroy(ptr);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A headless, vanilla-accurate tick simulation of one structure.
|
|
14
|
+
*/
|
|
15
|
+
export class TickSimulation {
|
|
16
|
+
// Internal ptr reference:
|
|
17
|
+
#ptr = null;
|
|
18
|
+
|
|
19
|
+
// Lifetimes are only to keep dependencies alive.
|
|
20
|
+
// Since JS won't garbage collect until there are no incoming edges.
|
|
21
|
+
#selfEdge = [];
|
|
22
|
+
|
|
23
|
+
#internalConstructor(symbol, ptr, selfEdge) {
|
|
24
|
+
if (symbol !== diplomatRuntime.internalConstructor) {
|
|
25
|
+
console.error("TickSimulation is an Opaque type. You cannot call its constructor.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
this.#ptr = ptr;
|
|
29
|
+
this.#selfEdge = selfEdge;
|
|
30
|
+
|
|
31
|
+
// Are we being borrowed? If not, we can register.
|
|
32
|
+
if (this.#selfEdge.length === 0) {
|
|
33
|
+
TickSimulation_box_destroy_registry.register(this, this.#ptr);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
/** @internal */
|
|
39
|
+
get ffiValue() {
|
|
40
|
+
return this.#ptr;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Why the last constructor on this thread failed, in words.
|
|
46
|
+
*
|
|
47
|
+
* The enum cannot carry a message, and "Simulation" is useless to
|
|
48
|
+
* someone holding a door that will not load: the engine already knows
|
|
49
|
+
* it is `minecraft:waxed_copper_bulb` at (4,2,1) and says so here.
|
|
50
|
+
* Empty when the last construction succeeded.
|
|
51
|
+
*/
|
|
52
|
+
static lastErrorDetail() {
|
|
53
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
54
|
+
|
|
55
|
+
wasm.TickSimulation_last_error_detail(write.buffer);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
return write.readString8();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
finally {
|
|
62
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
63
|
+
write.free();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Largest build this will attempt, in cells.
|
|
69
|
+
*
|
|
70
|
+
* A 500x379x442 "door" is a saved world, and loading one exhausts the
|
|
71
|
+
* wasm heap — after which every later call on that instance traps,
|
|
72
|
+
* not just the one that overflowed. Refused up front instead.
|
|
73
|
+
*/
|
|
74
|
+
static maxVolume() {
|
|
75
|
+
|
|
76
|
+
const result = wasm.TickSimulation_max_volume();
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
finally {
|
|
83
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Load from Java structure SNBT text.
|
|
89
|
+
*
|
|
90
|
+
* `extra_states`: semicolon-separated block-state descriptors that
|
|
91
|
+
* later `place_block` calls may write (behaviours bind at
|
|
92
|
+
* construction). `minecraft:redstone_block` is always available.
|
|
93
|
+
* `origin_*`: where the build's (0,0,0) sits in world coordinates —
|
|
94
|
+
* wire update order hashes absolute positions.
|
|
95
|
+
*
|
|
96
|
+
* The text's own `DataVersion` selects `Entity.load` Motion semantics,
|
|
97
|
+
* exactly as {@link TickSimulation::from_schematic} uses the schematic's —
|
|
98
|
+
* so `gametest_snbt` → `from_snbt` keeps a nan-cart build's NaN
|
|
99
|
+
* velocities instead of quietly sanitising them. A text with no
|
|
100
|
+
* `DataVersion` gets the engine default (the modern, NaN-dropping
|
|
101
|
+
* rule); read {@link TickSimulation::motion_semantics} to see which
|
|
102
|
+
* applied.
|
|
103
|
+
*/
|
|
104
|
+
static fromSnbt(snbt, settle, originX, originY, originZ, extraStates) {
|
|
105
|
+
let functionCleanupArena = new diplomatRuntime.CleanupArena();
|
|
106
|
+
|
|
107
|
+
const snbtSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.sliceWrapper(wasm, diplomatRuntime.DiplomatBuf.str8(wasm, snbt)));
|
|
108
|
+
const extraStatesSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.sliceWrapper(wasm, diplomatRuntime.DiplomatBuf.str8(wasm, extraStates)));
|
|
109
|
+
const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true);
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
const result = wasm.TickSimulation_from_snbt(diplomatReceive.buffer, snbtSlice.ptr, settle.ffiValue, originX, originY, originZ, extraStatesSlice.ptr);
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
if (!diplomatReceive.resultFlag) {
|
|
116
|
+
const cause = new NucleationError(diplomatRuntime.internalConstructor, diplomatRuntime.enumDiscriminant(wasm, diplomatReceive.buffer));
|
|
117
|
+
throw new globalThis.Error('NucleationError.' + cause.value, { cause });
|
|
118
|
+
}
|
|
119
|
+
return new TickSimulation(diplomatRuntime.internalConstructor, diplomatRuntime.ptrRead(wasm, diplomatReceive.buffer), []);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
finally {
|
|
123
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
124
|
+
functionCleanupArena.free();
|
|
125
|
+
|
|
126
|
+
diplomatReceive.free();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Load from a schematic (any format nucleation can read), rendered
|
|
132
|
+
* to gametest-flavor structure SNBT for mc-tick's parser.
|
|
133
|
+
*/
|
|
134
|
+
static fromSchematic(schematic, settle, originX, originY, originZ, extraStates) {
|
|
135
|
+
let functionCleanupArena = new diplomatRuntime.CleanupArena();
|
|
136
|
+
|
|
137
|
+
const extraStatesSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.sliceWrapper(wasm, diplomatRuntime.DiplomatBuf.str8(wasm, extraStates)));
|
|
138
|
+
const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true);
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
const result = wasm.TickSimulation_from_schematic(diplomatReceive.buffer, schematic.ffiValue, settle.ffiValue, originX, originY, originZ, extraStatesSlice.ptr);
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
if (!diplomatReceive.resultFlag) {
|
|
145
|
+
const cause = new NucleationError(diplomatRuntime.internalConstructor, diplomatRuntime.enumDiscriminant(wasm, diplomatReceive.buffer));
|
|
146
|
+
throw new globalThis.Error('NucleationError.' + cause.value, { cause });
|
|
147
|
+
}
|
|
148
|
+
return new TickSimulation(diplomatRuntime.internalConstructor, diplomatRuntime.ptrRead(wasm, diplomatReceive.buffer), []);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
finally {
|
|
152
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
153
|
+
functionCleanupArena.free();
|
|
154
|
+
|
|
155
|
+
diplomatReceive.free();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* GA fast path: construct from a flat genome-cell array — no SNBT
|
|
161
|
+
* text built or parsed. Corridor layout matches the flying-ga app:
|
|
162
|
+
* machine at `x_off`, world size `[bx + travel, by + 2, bz + 2]`,
|
|
163
|
+
* cells flattened `((y * bz) + z) * bx + x`, `air_index` = empty
|
|
164
|
+
* cell. `palette` is the run's alphabet, semicolon-separated; every
|
|
165
|
+
* entry is pre-interned so behaviours bind exactly as the SNBT
|
|
166
|
+
* path's EXTRA_STATES did.
|
|
167
|
+
*/
|
|
168
|
+
static fromBlocks(bx, by, bz, travel, xOff, palette, cells, airIndex, settle, originX, originY, originZ) {
|
|
169
|
+
let functionCleanupArena = new diplomatRuntime.CleanupArena();
|
|
170
|
+
|
|
171
|
+
const paletteSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.sliceWrapper(wasm, diplomatRuntime.DiplomatBuf.str8(wasm, palette)));
|
|
172
|
+
const cellsSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.sliceWrapper(wasm, diplomatRuntime.DiplomatBuf.slice(wasm, cells, "u16")));
|
|
173
|
+
const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true);
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
const result = wasm.TickSimulation_from_blocks(diplomatReceive.buffer, bx, by, bz, travel, xOff, paletteSlice.ptr, cellsSlice.ptr, airIndex, settle.ffiValue, originX, originY, originZ);
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
if (!diplomatReceive.resultFlag) {
|
|
180
|
+
const cause = new NucleationError(diplomatRuntime.internalConstructor, diplomatRuntime.enumDiscriminant(wasm, diplomatReceive.buffer));
|
|
181
|
+
throw new globalThis.Error('NucleationError.' + cause.value, { cause });
|
|
182
|
+
}
|
|
183
|
+
return new TickSimulation(diplomatRuntime.internalConstructor, diplomatRuntime.ptrRead(wasm, diplomatReceive.buffer), []);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
finally {
|
|
187
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
188
|
+
functionCleanupArena.free();
|
|
189
|
+
|
|
190
|
+
diplomatReceive.free();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Evaluate a whole batch of kicked flights inside the engine — one
|
|
196
|
+
* wasm call per generation chunk instead of a dozen boundary calls
|
|
197
|
+
* per machine. `cells` holds N genomes concatenated (each
|
|
198
|
+
* `bx*by*bz` entries), `kicks` N structure-space `[x,y,z]` triples.
|
|
199
|
+
* The flight protocol, probe schedule and gait detection mirror the
|
|
200
|
+
* app's evalCore exactly; `early_exit` stops provably-frozen
|
|
201
|
+
* machines at tick 40 without changing any reported value. Writes
|
|
202
|
+
* JSON rows `[n0, startCom, startMinX, startMaxX, comAtMoveCheck |
|
|
203
|
+
* null, comAtMid, period, n1, endCom, endMinX, endMaxX]`.
|
|
204
|
+
*/
|
|
205
|
+
static evalFlightBatch(bx, by, bz, travel, xOff, palette, cells, airIndex, kicks, evalTicks, seed, mustMoveByTick, needPeriod, earlyExit) {
|
|
206
|
+
let functionCleanupArena = new diplomatRuntime.CleanupArena();
|
|
207
|
+
|
|
208
|
+
const paletteSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.sliceWrapper(wasm, diplomatRuntime.DiplomatBuf.str8(wasm, palette)));
|
|
209
|
+
const cellsSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.sliceWrapper(wasm, diplomatRuntime.DiplomatBuf.slice(wasm, cells, "u16")));
|
|
210
|
+
const kicksSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.sliceWrapper(wasm, diplomatRuntime.DiplomatBuf.slice(wasm, kicks, "i32")));
|
|
211
|
+
const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true);
|
|
212
|
+
|
|
213
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
const result = wasm.TickSimulation_eval_flight_batch(diplomatReceive.buffer, bx, by, bz, travel, xOff, paletteSlice.ptr, cellsSlice.ptr, airIndex, kicksSlice.ptr, evalTicks, seed, mustMoveByTick, needPeriod, earlyExit, write.buffer);
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
if (!diplomatReceive.resultFlag) {
|
|
220
|
+
const cause = new NucleationError(diplomatRuntime.internalConstructor, diplomatRuntime.enumDiscriminant(wasm, diplomatReceive.buffer));
|
|
221
|
+
throw new globalThis.Error('NucleationError.' + cause.value, { cause });
|
|
222
|
+
}
|
|
223
|
+
return write.readString8();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
finally {
|
|
227
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
228
|
+
functionCleanupArena.free();
|
|
229
|
+
|
|
230
|
+
diplomatReceive.free();
|
|
231
|
+
write.free();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Seed the vanilla random source (`java.util.Random`'s LCG,
|
|
237
|
+
* bit-for-bit). Unseeded, jittering behaviours use each
|
|
238
|
+
* distribution's mean — fully deterministic, no noise.
|
|
239
|
+
*/
|
|
240
|
+
setRngSeed(seed) {
|
|
241
|
+
wasm.TickSimulation_set_rng_seed(this.ffiValue, seed);
|
|
242
|
+
|
|
243
|
+
try {}
|
|
244
|
+
|
|
245
|
+
finally {
|
|
246
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Advance one game tick.
|
|
252
|
+
*/
|
|
253
|
+
step() {
|
|
254
|
+
wasm.TickSimulation_step(this.ffiValue);
|
|
255
|
+
|
|
256
|
+
try {}
|
|
257
|
+
|
|
258
|
+
finally {
|
|
259
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Advance `ticks` game ticks.
|
|
265
|
+
*/
|
|
266
|
+
run(ticks) {
|
|
267
|
+
wasm.TickSimulation_run(this.ffiValue, ticks);
|
|
268
|
+
|
|
269
|
+
try {}
|
|
270
|
+
|
|
271
|
+
finally {
|
|
272
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Run until nothing is scheduled or `budget` ticks pass. Returns
|
|
278
|
+
* whether the world went quiet.
|
|
279
|
+
*/
|
|
280
|
+
runUntilQuiescent(budget) {
|
|
281
|
+
|
|
282
|
+
const result = wasm.TickSimulation_run_until_quiescent(this.ffiValue, budget);
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
finally {
|
|
289
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Game ticks elapsed since settle.
|
|
295
|
+
*/
|
|
296
|
+
tickCount() {
|
|
297
|
+
|
|
298
|
+
const result = wasm.TickSimulation_tick_count(this.ffiValue);
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
finally {
|
|
305
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Whether nothing is scheduled or queued.
|
|
311
|
+
*/
|
|
312
|
+
isQuiescent() {
|
|
313
|
+
|
|
314
|
+
const result = wasm.TickSimulation_is_quiescent(this.ffiValue);
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
finally {
|
|
321
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Right-click a block with an empty hand (lever, button, note block).
|
|
327
|
+
*/
|
|
328
|
+
useBlock(x, y, z) {
|
|
329
|
+
wasm.TickSimulation_use_block(this.ffiValue, x, y, z);
|
|
330
|
+
|
|
331
|
+
try {}
|
|
332
|
+
|
|
333
|
+
finally {
|
|
334
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Write a block state (`minecraft:air` breaks). The state must be in
|
|
340
|
+
* the structure, in `extra_states`, or `minecraft:redstone_block`.
|
|
341
|
+
*/
|
|
342
|
+
placeBlock(x, y, z, state) {
|
|
343
|
+
let functionCleanupArena = new diplomatRuntime.CleanupArena();
|
|
344
|
+
|
|
345
|
+
const stateSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.sliceWrapper(wasm, diplomatRuntime.DiplomatBuf.str8(wasm, state)));
|
|
346
|
+
const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true);
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
const result = wasm.TickSimulation_place_block(diplomatReceive.buffer, this.ffiValue, x, y, z, stateSlice.ptr);
|
|
350
|
+
|
|
351
|
+
try {
|
|
352
|
+
if (!diplomatReceive.resultFlag) {
|
|
353
|
+
const cause = new NucleationError(diplomatRuntime.internalConstructor, diplomatRuntime.enumDiscriminant(wasm, diplomatReceive.buffer));
|
|
354
|
+
throw new globalThis.Error('NucleationError.' + cause.value, { cause });
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
finally {
|
|
359
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
360
|
+
functionCleanupArena.free();
|
|
361
|
+
|
|
362
|
+
diplomatReceive.free();
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* The block state descriptor at a position (`minecraft:air` for empty).
|
|
368
|
+
*/
|
|
369
|
+
getBlock(x, y, z) {
|
|
370
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
371
|
+
|
|
372
|
+
wasm.TickSimulation_get_block(this.ffiValue, x, y, z, write.buffer);
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
return write.readString8();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
finally {
|
|
379
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
380
|
+
write.free();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Snapshot the entire simulation; returns a checkpoint id.
|
|
386
|
+
*/
|
|
387
|
+
checkpoint() {
|
|
388
|
+
|
|
389
|
+
const result = wasm.TickSimulation_checkpoint(this.ffiValue);
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
return result;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
finally {
|
|
396
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Restore a checkpoint taken earlier on this simulation.
|
|
402
|
+
*/
|
|
403
|
+
restore(id) {
|
|
404
|
+
const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true);
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
const result = wasm.TickSimulation_restore(diplomatReceive.buffer, this.ffiValue, id);
|
|
408
|
+
|
|
409
|
+
try {
|
|
410
|
+
if (!diplomatReceive.resultFlag) {
|
|
411
|
+
const cause = new NucleationError(diplomatRuntime.internalConstructor, diplomatRuntime.enumDiscriminant(wasm, diplomatReceive.buffer));
|
|
412
|
+
throw new globalThis.Error('NucleationError.' + cause.value, { cause });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
finally {
|
|
417
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
418
|
+
diplomatReceive.free();
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Render a schematic as gametest-flavor structure SNBT — the text
|
|
424
|
+
* `from_snbt` and the corpus/render tooling consume. Lets hosts hand
|
|
425
|
+
* a converted `.litematic`/`.schem` to the video renderer.
|
|
426
|
+
*/
|
|
427
|
+
static gametestSnbt(schematic) {
|
|
428
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
429
|
+
|
|
430
|
+
wasm.TickSimulation_gametest_snbt(schematic.ffiValue, write.buffer);
|
|
431
|
+
|
|
432
|
+
try {
|
|
433
|
+
return write.readString8();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
finally {
|
|
437
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
438
|
+
write.free();
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Report blocks whose behaviour is defined by block-entity data the
|
|
444
|
+
* file does not carry.
|
|
445
|
+
*
|
|
446
|
+
* Some exporters write the blocks and drop the block entities. The
|
|
447
|
+
* build then loads clean and simulates *wrongly but plausibly*: a
|
|
448
|
+
* comparator with no `OutputSignal` reads 0, a barrel holding the
|
|
449
|
+
* item that latched a repeater reads empty, and the door quietly
|
|
450
|
+
* fails to reset. Two files with identical block arrays get
|
|
451
|
+
* different verdicts and nothing says why. `0.45_4x4_funnel.schem`
|
|
452
|
+
* is exactly this — 4 comparators, 2 furnaces, `BlockEntities` of
|
|
453
|
+
* length 0, while its `.litematic` twin carries all 9.
|
|
454
|
+
*
|
|
455
|
+
* This does not refuse the build; it names the doubt so a host can.
|
|
456
|
+
* JSON: `{"present":N,"missing_total":N,"missing":[{"name":..,
|
|
457
|
+
* "count":N}],"summary":"..."}` — `summary` is empty when nothing
|
|
458
|
+
* is missing, and otherwise a sentence fit to show as-is.
|
|
459
|
+
*/
|
|
460
|
+
static blockEntityAuditJson(schematic) {
|
|
461
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
462
|
+
|
|
463
|
+
wasm.TickSimulation_block_entity_audit_json(schematic.ffiValue, write.buffer);
|
|
464
|
+
|
|
465
|
+
try {
|
|
466
|
+
return write.readString8();
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
finally {
|
|
470
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
471
|
+
write.free();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Start (or stop) recording every delivered redstone update.
|
|
477
|
+
*
|
|
478
|
+
* Off by default and much larger than the block-change log — a door's
|
|
479
|
+
* cycle runs several updates per change — so a propagation view asks
|
|
480
|
+
* for it explicitly and pages with
|
|
481
|
+
* {@link TickSimulation::updates_json_between}.
|
|
482
|
+
*
|
|
483
|
+
* Switching it off keeps what was recorded; use
|
|
484
|
+
* {@link TickSimulation::clear_updates} to free it.
|
|
485
|
+
*/
|
|
486
|
+
recordUpdates(on) {
|
|
487
|
+
wasm.TickSimulation_record_updates(this.ffiValue, on);
|
|
488
|
+
|
|
489
|
+
try {}
|
|
490
|
+
|
|
491
|
+
finally {
|
|
492
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Drop the recorded updates without changing whether recording is on.
|
|
498
|
+
*
|
|
499
|
+
* A cycle of a 6x6 door is tens of megabytes of log, so a page that
|
|
500
|
+
* certifies several builds on one instance needs to release one
|
|
501
|
+
* before recording the next.
|
|
502
|
+
*/
|
|
503
|
+
clearUpdates() {
|
|
504
|
+
wasm.TickSimulation_clear_updates(this.ffiValue);
|
|
505
|
+
|
|
506
|
+
try {}
|
|
507
|
+
|
|
508
|
+
finally {
|
|
509
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* How many updates have been recorded — page before pulling them.
|
|
515
|
+
*/
|
|
516
|
+
updatesCount() {
|
|
517
|
+
|
|
518
|
+
const result = wasm.TickSimulation_updates_count(this.ffiValue);
|
|
519
|
+
|
|
520
|
+
try {
|
|
521
|
+
return result;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
finally {
|
|
525
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Every recorded update, in delivery order.
|
|
531
|
+
*
|
|
532
|
+
* `seq` counts from 0 within each tick: that is the sub-tick axis, and
|
|
533
|
+
* `(tick, seq)` is the order the engine actually delivered them in.
|
|
534
|
+
* `state` is the block as it stood **at dispatch time**, which is what
|
|
535
|
+
* makes intra-tick order legible — a snapshot cannot show it.
|
|
536
|
+
*/
|
|
537
|
+
updatesJson() {
|
|
538
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
539
|
+
|
|
540
|
+
wasm.TickSimulation_updates_json(this.ffiValue, write.buffer);
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
return write.readString8();
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
finally {
|
|
547
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
548
|
+
write.free();
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* The recorded updates for ticks in `[from_tick, to_tick)`.
|
|
554
|
+
*
|
|
555
|
+
* The whole log for a 6x6 door's cycle is megabytes; a scrubber only
|
|
556
|
+
* ever shows one tick, so it should ask for one tick.
|
|
557
|
+
*/
|
|
558
|
+
updatesJsonBetween(fromTick, toTick) {
|
|
559
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
560
|
+
|
|
561
|
+
wasm.TickSimulation_updates_json_between(this.ffiValue, fromTick, toTick, write.buffer);
|
|
562
|
+
|
|
563
|
+
try {
|
|
564
|
+
return write.readString8();
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
finally {
|
|
568
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
569
|
+
write.free();
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Per-tick, per-cell update counts for ticks in `[from_tick, to_tick)`.
|
|
575
|
+
*
|
|
576
|
+
* The resolution playback should run at: `{phases, ticks:[{tick, total,
|
|
577
|
+
* cells:[{p:[x,y,z], n, nb, sh, ph:[…]}]}]}`, where `nb`/`sh` split
|
|
578
|
+
* neighbour from shape and `ph` indexes the `phases` legend. Collapses
|
|
579
|
+
* a tick's tens of thousands of updates into a few hundred cells.
|
|
580
|
+
*/
|
|
581
|
+
updatesHeatJson(fromTick, toTick) {
|
|
582
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
583
|
+
|
|
584
|
+
wasm.TickSimulation_updates_heat_json(this.ffiValue, fromTick, toTick, write.buffer);
|
|
585
|
+
|
|
586
|
+
try {
|
|
587
|
+
return write.readString8();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
finally {
|
|
591
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
592
|
+
write.free();
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* One tick's updates in delivery order, as parallel arrays.
|
|
598
|
+
*
|
|
599
|
+
* For stepping *within* a tick: `seq` is the array index, `pos` is flat
|
|
600
|
+
* x,y,z triples, `kind`/`phase`/`from` are integer codes with legends
|
|
601
|
+
* in the payload, and `state` indexes a deduplicated `states` table.
|
|
602
|
+
*/
|
|
603
|
+
updatesWaveJson(tick) {
|
|
604
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
605
|
+
|
|
606
|
+
wasm.TickSimulation_updates_wave_json(this.ffiValue, tick, write.buffer);
|
|
607
|
+
|
|
608
|
+
try {
|
|
609
|
+
return write.readString8();
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
finally {
|
|
613
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
614
|
+
write.free();
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
changesJson() {
|
|
619
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
620
|
+
|
|
621
|
+
wasm.TickSimulation_changes_json(this.ffiValue, write.buffer);
|
|
622
|
+
|
|
623
|
+
try {
|
|
624
|
+
return write.readString8();
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
finally {
|
|
628
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
629
|
+
write.free();
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Live item entities and minecarts, as JSON:
|
|
635
|
+
* `{"items":[{"id":N,"item":"...","count":N,"pos":[..],"vel":[..],
|
|
636
|
+
* "on_ground":bool,"contents":[{"id":"...","count":N}]}],
|
|
637
|
+
* "minecarts":[{"id":N,"kind":"...","pos":[..],"vel":[..]}]}`.
|
|
638
|
+
*/
|
|
639
|
+
itemEntitiesJson() {
|
|
640
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
641
|
+
|
|
642
|
+
wasm.TickSimulation_item_entities_json(this.ffiValue, write.buffer);
|
|
643
|
+
|
|
644
|
+
try {
|
|
645
|
+
return write.readString8();
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
finally {
|
|
649
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
650
|
+
write.free();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Which `Entity.load` Motion semantics this run uses:
|
|
656
|
+
* `"clamp_abs_ten"` (DataVersion <= 4556 — NaN survives a cold load)
|
|
657
|
+
* or `"drop_non_finite"` (>= 4671 — it does not).
|
|
658
|
+
*
|
|
659
|
+
* Exposed because a door built on nan carts is a *different machine*
|
|
660
|
+
* under the two, and a caller that cannot tell them apart cannot
|
|
661
|
+
* report why it came apart.
|
|
662
|
+
*/
|
|
663
|
+
motionSemantics() {
|
|
664
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
665
|
+
|
|
666
|
+
wasm.TickSimulation_motion_semantics(this.ffiValue, write.buffer);
|
|
667
|
+
|
|
668
|
+
try {
|
|
669
|
+
return write.readString8();
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
finally {
|
|
673
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
674
|
+
write.free();
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* How many times an entity stood in a **retracting** piston's sweep
|
|
680
|
+
* that the engine could not reproduce.
|
|
681
|
+
*
|
|
682
|
+
* A tripwire from when retraction was unmodelled — extension
|
|
683
|
+
* displacement was measured and implemented while
|
|
684
|
+
* `tools/gametest/captures/piston_pull.entities.log`'s sub-0.03
|
|
685
|
+
* movements, not uniformly backwards, had no model here. All three
|
|
686
|
+
* retraction geometries are implemented now, so this reports **0**,
|
|
687
|
+
* including on the record 3x3 door, which used to name six. It is kept
|
|
688
|
+
* because the next geometry that turns out not to be covered should be
|
|
689
|
+
* reported rather than guessed at: non-zero means this run leaned on
|
|
690
|
+
* behaviour we do not reproduce and its result is not trustworthy.
|
|
691
|
+
*/
|
|
692
|
+
pistonRetractContacts() {
|
|
693
|
+
|
|
694
|
+
const result = wasm.TickSimulation_piston_retract_contacts(this.ffiValue);
|
|
695
|
+
|
|
696
|
+
try {
|
|
697
|
+
return result;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
finally {
|
|
701
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Per-tick aggregates over the recorded changes, as JSON:
|
|
707
|
+
* `[{"tick":N,"changes":N,"piston":N,"redstone":N}]` — `piston`
|
|
708
|
+
* counts changes touching piston blocks (base, head, moving), and
|
|
709
|
+
* `redstone` changes touching wire/torch/repeater/comparator/
|
|
710
|
+
* observer/lamp/lever/button/pressure-plate states.
|
|
711
|
+
*/
|
|
712
|
+
eventsSummaryJson() {
|
|
713
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
714
|
+
|
|
715
|
+
wasm.TickSimulation_events_summary_json(this.ffiValue, write.buffer);
|
|
716
|
+
|
|
717
|
+
try {
|
|
718
|
+
return write.readString8();
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
finally {
|
|
722
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
723
|
+
write.free();
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Every non-air block, as JSON:
|
|
729
|
+
* `[{"pos":[x,y,z],"state":"..."}]`.
|
|
730
|
+
* How many non-air blocks stand in the world right now.
|
|
731
|
+
*/
|
|
732
|
+
nonAirCount() {
|
|
733
|
+
|
|
734
|
+
const result = wasm.TickSimulation_non_air_count(this.ffiValue);
|
|
735
|
+
|
|
736
|
+
try {
|
|
737
|
+
return result;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
finally {
|
|
741
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Center of mass (x) of every non-air block — the GA's displacement
|
|
747
|
+
* metric without a JSON round-trip. NaN when the world is empty.
|
|
748
|
+
*/
|
|
749
|
+
nonAirCenterX() {
|
|
750
|
+
|
|
751
|
+
const result = wasm.TickSimulation_non_air_center_x(this.ffiValue);
|
|
752
|
+
|
|
753
|
+
try {
|
|
754
|
+
return result;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
finally {
|
|
758
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Smallest x holding a non-air block; `i32::MAX` when empty.
|
|
764
|
+
*/
|
|
765
|
+
nonAirMinX() {
|
|
766
|
+
|
|
767
|
+
const result = wasm.TickSimulation_non_air_min_x(this.ffiValue);
|
|
768
|
+
|
|
769
|
+
try {
|
|
770
|
+
return result;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
finally {
|
|
774
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Largest x holding a non-air block; `i32::MIN` when empty.
|
|
780
|
+
*/
|
|
781
|
+
nonAirMaxX() {
|
|
782
|
+
|
|
783
|
+
const result = wasm.TickSimulation_non_air_max_x(this.ffiValue);
|
|
784
|
+
|
|
785
|
+
try {
|
|
786
|
+
return result;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
finally {
|
|
790
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* How many block changes recording has captured so far.
|
|
796
|
+
*/
|
|
797
|
+
changesCount() {
|
|
798
|
+
|
|
799
|
+
const result = wasm.TickSimulation_changes_count(this.ffiValue);
|
|
800
|
+
|
|
801
|
+
try {
|
|
802
|
+
return result;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
finally {
|
|
806
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
worldSnapshotJson() {
|
|
811
|
+
const write = new diplomatRuntime.DiplomatWriteBuf(wasm);
|
|
812
|
+
|
|
813
|
+
wasm.TickSimulation_world_snapshot_json(this.ffiValue, write.buffer);
|
|
814
|
+
|
|
815
|
+
try {
|
|
816
|
+
return write.readString8();
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
finally {
|
|
820
|
+
diplomatRuntime.FUNCTION_PARAM_ALLOC.clean();
|
|
821
|
+
write.free();
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
constructor(symbol, ptr, selfEdge) {
|
|
826
|
+
return this.#internalConstructor(...arguments)
|
|
827
|
+
}
|
|
828
|
+
}
|