nucleation 0.2.18 → 0.3.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/Autostack.d.ts +43 -0
- package/Autostack.mjs +134 -0
- package/BlockPos.d.ts +28 -0
- package/BlockPos.mjs +129 -0
- package/BlockState.d.ts +39 -0
- package/BlockState.mjs +134 -0
- package/Brush.d.ts +68 -0
- package/Brush.mjs +220 -0
- package/BuildingTool.d.ts +29 -0
- package/BuildingTool.mjs +74 -0
- package/ChunkMeshResult.d.ts +75 -0
- package/ChunkMeshResult.mjs +253 -0
- package/CircuitBuilder.d.ts +118 -0
- package/CircuitBuilder.mjs +516 -0
- package/DefinitionRegion.d.ts +274 -0
- package/DefinitionRegion.mjs +973 -0
- package/Diff.d.ts +88 -0
- package/Diff.mjs +316 -0
- package/Dimensions.d.ts +28 -0
- package/Dimensions.mjs +129 -0
- package/ExecutionMode.d.ts +42 -0
- package/ExecutionMode.mjs +127 -0
- package/Fingerprint.d.ts +44 -0
- package/Fingerprint.mjs +197 -0
- package/InterpolationSpace.d.ts +25 -0
- package/InterpolationSpace.mjs +73 -0
- package/IoLayout.d.ts +26 -0
- package/IoLayout.mjs +81 -0
- package/IoLayoutBuilder.d.ts +73 -0
- package/IoLayoutBuilder.mjs +315 -0
- package/IoType.d.ts +41 -0
- package/IoType.mjs +125 -0
- package/ItemModelConfig.d.ts +65 -0
- package/ItemModelConfig.mjs +223 -0
- package/ItemModelPackBuilder.d.ts +32 -0
- package/ItemModelPackBuilder.mjs +104 -0
- package/ItemModelResult.d.ts +72 -0
- package/ItemModelResult.mjs +268 -0
- package/ItemScale.d.ts +31 -0
- package/ItemScale.mjs +132 -0
- package/LayoutFunction.d.ts +52 -0
- package/LayoutFunction.mjs +159 -0
- package/MchprsWorld.d.ts +131 -0
- package/MchprsWorld.mjs +423 -0
- package/MeshBounds.d.ts +40 -0
- package/MeshBounds.mjs +180 -0
- package/MeshConfig.d.ts +101 -0
- package/MeshConfig.mjs +306 -0
- package/MeshJob.d.ts +44 -0
- package/MeshJob.mjs +116 -0
- package/MeshPhase.d.ts +38 -0
- package/MeshPhase.mjs +90 -0
- package/MeshProgress.d.ts +32 -0
- package/MeshProgress.mjs +133 -0
- package/MeshResult.d.ts +60 -0
- package/MeshResult.mjs +206 -0
- package/MultiMeshResult.d.ts +50 -0
- package/MultiMeshResult.mjs +166 -0
- package/Nbt.d.ts +50 -0
- package/Nbt.mjs +161 -0
- package/NucleationError.d.ts +36 -0
- package/NucleationError.mjs +104 -0
- package/OutputCondition.d.ts +45 -0
- package/OutputCondition.mjs +129 -0
- package/Palette.d.ts +84 -0
- package/Palette.mjs +269 -0
- package/PaletteBuilder.d.ts +76 -0
- package/PaletteBuilder.mjs +297 -0
- package/README.md +28 -197
- package/RawMeshExport.d.ts +74 -0
- package/RawMeshExport.mjs +243 -0
- package/RedstoneGraph.d.ts +58 -0
- package/RedstoneGraph.mjs +242 -0
- package/RegionBounds.d.ts +41 -0
- package/RegionBounds.mjs +181 -0
- package/RenderConfig.d.ts +66 -0
- package/RenderConfig.mjs +170 -0
- package/Renderer.d.ts +35 -0
- package/Renderer.mjs +139 -0
- package/ResourcePack.d.ts +105 -0
- package/ResourcePack.mjs +447 -0
- package/ResourcePackList.d.ts +32 -0
- package/ResourcePackList.mjs +96 -0
- package/Schematic.d.ts +655 -0
- package/Schematic.mjs +2647 -0
- package/SchematicBuilder.d.ts +103 -0
- package/SchematicBuilder.mjs +401 -0
- package/SchematicRegions.d.ts +93 -0
- package/SchematicRegions.mjs +411 -0
- package/Scripting.d.ts +40 -0
- package/Scripting.mjs +138 -0
- package/Sdf.d.ts +31 -0
- package/Sdf.mjs +107 -0
- package/Shape.d.ts +108 -0
- package/Shape.mjs +336 -0
- package/SortStrategy.d.ts +86 -0
- package/SortStrategy.mjs +272 -0
- package/Store.d.ts +83 -0
- package/Store.mjs +369 -0
- package/StoreIo.d.ts +71 -0
- package/StoreIo.mjs +292 -0
- package/TextureAtlas.d.ts +40 -0
- package/TextureAtlas.mjs +122 -0
- package/TextureInfo.d.ts +34 -0
- package/TextureInfo.mjs +148 -0
- package/TypedCircuitExecutor.d.ts +101 -0
- package/TypedCircuitExecutor.mjs +378 -0
- package/Value.d.ts +73 -0
- package/Value.mjs +275 -0
- package/WorldChunkView.d.ts +63 -0
- package/WorldChunkView.mjs +201 -0
- package/WorldSink.d.ts +50 -0
- package/WorldSink.mjs +177 -0
- package/WorldStream.d.ts +45 -0
- package/WorldStream.mjs +184 -0
- package/diplomat-runtime.d.ts +15 -0
- package/diplomat-runtime.mjs +774 -0
- package/diplomat-wasm.mjs +52 -0
- package/diplomat.config.mjs +6 -0
- package/index.d.ts +117 -0
- package/index.mjs +120 -0
- package/{nucleation_bg.wasm → nucleation.wasm} +0 -0
- package/package.json +19 -41
- package/LICENSE +0 -21
- package/api.js +0 -608
- package/nucleation-cdn-loader.js +0 -15
- package/nucleation-original.js +0 -8383
- package/nucleation.d.ts +0 -2947
- package/nucleation.js +0 -36
package/api.js
DELETED
|
@@ -1,608 +0,0 @@
|
|
|
1
|
-
// Polished JS API for Nucleation, layered over the wasm-bindgen output.
|
|
2
|
-
//
|
|
3
|
-
// The default `nucleation` import still exposes `init`, `SchematicWrapper`,
|
|
4
|
-
// `SchematicBuilderWrapper`, etc. — that surface is unchanged. This sub-module
|
|
5
|
-
// (`nucleation/api`) adds an ergonomic facade analogous to the Python API
|
|
6
|
-
// described in api_upgrade.md.
|
|
7
|
-
//
|
|
8
|
-
// Usage:
|
|
9
|
-
// import init from 'nucleation';
|
|
10
|
-
// import { Schematic, Block, UseBlock } from 'nucleation/api';
|
|
11
|
-
// await init();
|
|
12
|
-
//
|
|
13
|
-
// const schem = Schematic.new('test');
|
|
14
|
-
// schem.setBlock([0, 0, 0], 'minecraft:repeater', { state: { delay: 4 } });
|
|
15
|
-
// schem.save('out.litematic'); // browser: returns Uint8Array if no fs.
|
|
16
|
-
|
|
17
|
-
import init, * as raw from './nucleation.js';
|
|
18
|
-
|
|
19
|
-
export { init };
|
|
20
|
-
export const _raw = raw;
|
|
21
|
-
|
|
22
|
-
// --- Block ----------------------------------------------------------------
|
|
23
|
-
|
|
24
|
-
const SNBT_RAW = '__snbt__';
|
|
25
|
-
|
|
26
|
-
export class Block {
|
|
27
|
-
/**
|
|
28
|
-
* @param {string} id
|
|
29
|
-
* @param {object} [opts]
|
|
30
|
-
* @param {Record<string, string|number|boolean>} [opts.state]
|
|
31
|
-
* @param {Record<string, any>} [opts.nbt]
|
|
32
|
-
*/
|
|
33
|
-
constructor(id, { state = null, nbt = null } = {}) {
|
|
34
|
-
this.id = id;
|
|
35
|
-
this.state = state;
|
|
36
|
-
this.nbt = nbt;
|
|
37
|
-
// Cached lazily on first toString() call. Block is otherwise frozen below.
|
|
38
|
-
this._payload = null;
|
|
39
|
-
this._hasExtras = !!(state && Object.keys(state).length) || !!(nbt && Object.keys(nbt).length);
|
|
40
|
-
Object.seal(this); // allow _payload assignment, prevent new props
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Parse "id[k=v,...]{snbt}" form. */
|
|
44
|
-
static parse(s) {
|
|
45
|
-
if (typeof s !== 'string') {
|
|
46
|
-
throw new TypeError(`Block.parse() expects a string, got ${typeof s}`);
|
|
47
|
-
}
|
|
48
|
-
let rest = s.trim();
|
|
49
|
-
let snbt = null;
|
|
50
|
-
if (rest.endsWith('}')) {
|
|
51
|
-
let depth = 0;
|
|
52
|
-
let cut = -1;
|
|
53
|
-
for (let i = rest.length - 1; i >= 0; i--) {
|
|
54
|
-
const ch = rest[i];
|
|
55
|
-
if (ch === '}') depth++;
|
|
56
|
-
else if (ch === '{') {
|
|
57
|
-
depth--;
|
|
58
|
-
if (depth === 0) {
|
|
59
|
-
cut = i;
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (cut >= 0) {
|
|
65
|
-
snbt = rest.slice(cut + 1, -1);
|
|
66
|
-
rest = rest.slice(0, cut);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
let state = null;
|
|
70
|
-
if (rest.endsWith(']')) {
|
|
71
|
-
const cut = rest.lastIndexOf('[');
|
|
72
|
-
if (cut >= 0) {
|
|
73
|
-
const inner = rest.slice(cut + 1, -1);
|
|
74
|
-
rest = rest.slice(0, cut);
|
|
75
|
-
state = {};
|
|
76
|
-
for (const kv of inner.split(',')) {
|
|
77
|
-
if (!kv.trim()) continue;
|
|
78
|
-
const eq = kv.indexOf('=');
|
|
79
|
-
if (eq < 0) continue;
|
|
80
|
-
const k = kv.slice(0, eq).trim();
|
|
81
|
-
const v = kv.slice(eq + 1).trim();
|
|
82
|
-
state[k] = coerceStateValue(v);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
const nbt = snbt !== null ? { [SNBT_RAW]: snbt } : null;
|
|
87
|
-
return new Block(rest, { state, nbt });
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
withState(extra) {
|
|
91
|
-
return new Block(this.id, {
|
|
92
|
-
state: { ...(this.state || {}), ...extra },
|
|
93
|
-
nbt: this.nbt,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
withNbt(extra) {
|
|
98
|
-
return new Block(this.id, {
|
|
99
|
-
state: this.state,
|
|
100
|
-
nbt: { ...(this.nbt || {}), ...extra },
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
toString() {
|
|
105
|
-
if (this._payload !== null) return this._payload;
|
|
106
|
-
let out = this.id;
|
|
107
|
-
if (this.state) {
|
|
108
|
-
const parts = Object.entries(this.state).map(
|
|
109
|
-
([k, v]) => `${k}=${stateToStr(v)}`
|
|
110
|
-
);
|
|
111
|
-
if (parts.length) out += `[${parts.join(',')}]`;
|
|
112
|
-
}
|
|
113
|
-
if (this.nbt) {
|
|
114
|
-
if (SNBT_RAW in this.nbt && Object.keys(this.nbt).length === 1) {
|
|
115
|
-
out += `{${this.nbt[SNBT_RAW]}}`;
|
|
116
|
-
} else {
|
|
117
|
-
out += `{${dictToSnbt(this.nbt)}}`;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
this._payload = out;
|
|
121
|
-
return out;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function coerceStateValue(v) {
|
|
126
|
-
if (v === 'true') return true;
|
|
127
|
-
if (v === 'false') return false;
|
|
128
|
-
if (/^-?\d+$/.test(v)) return parseInt(v, 10);
|
|
129
|
-
return v;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function stateToStr(v) {
|
|
133
|
-
if (typeof v === 'boolean') return v ? 'true' : 'false';
|
|
134
|
-
return String(v);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function valueToSnbt(v) {
|
|
138
|
-
if (typeof v === 'boolean') return v ? '1b' : '0b';
|
|
139
|
-
if (typeof v === 'number') {
|
|
140
|
-
return Number.isInteger(v) ? `${v}` : `${v}f`;
|
|
141
|
-
}
|
|
142
|
-
if (typeof v === 'string') {
|
|
143
|
-
return `"${v.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
144
|
-
}
|
|
145
|
-
if (Array.isArray(v)) return `[${v.map(valueToSnbt).join(',')}]`;
|
|
146
|
-
if (v && typeof v === 'object') return `{${dictToSnbt(v)}}`;
|
|
147
|
-
throw new TypeError(`Cannot encode ${typeof v} as SNBT`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function dictToSnbt(d) {
|
|
151
|
-
if (SNBT_RAW in d && Object.keys(d).length === 1) return String(d[SNBT_RAW]);
|
|
152
|
-
return Object.entries(d)
|
|
153
|
-
.map(([k, v]) => `${k}:${valueToSnbt(v)}`)
|
|
154
|
-
.join(',');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// --- Minecraft helpers (chest, sign, text, Item) -------------------------
|
|
158
|
-
//
|
|
159
|
-
// Modern (1.20+) NBT schemas. For pre-1.20 layouts, build the dict by hand
|
|
160
|
-
// or use the `__snbt__` escape hatch in setBlock.
|
|
161
|
-
|
|
162
|
-
export function text(s, opts = {}) {
|
|
163
|
-
if (typeof s !== 'string') {
|
|
164
|
-
throw new TypeError(`text() expects a string, got ${typeof s}`);
|
|
165
|
-
}
|
|
166
|
-
const out = { text: s };
|
|
167
|
-
if (opts.color !== undefined) out.color = opts.color;
|
|
168
|
-
for (const k of ['bold', 'italic', 'underlined', 'strikethrough', 'obfuscated']) {
|
|
169
|
-
if (opts[k] !== undefined) out[k] = opts[k];
|
|
170
|
-
}
|
|
171
|
-
return JSON.stringify(out);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export class Item {
|
|
175
|
-
constructor(id, { count = 1, slot = null, components = null } = {}) {
|
|
176
|
-
this.id = id;
|
|
177
|
-
this.count = count;
|
|
178
|
-
this.slot = slot;
|
|
179
|
-
this.components = components;
|
|
180
|
-
Object.freeze(this);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function coerceItem(x, defaultSlot) {
|
|
185
|
-
if (x instanceof Item) {
|
|
186
|
-
const d = {
|
|
187
|
-
Slot: x.slot != null ? x.slot : defaultSlot,
|
|
188
|
-
id: x.id,
|
|
189
|
-
Count: x.count,
|
|
190
|
-
};
|
|
191
|
-
if (x.components) d.components = { ...x.components };
|
|
192
|
-
return d;
|
|
193
|
-
}
|
|
194
|
-
if (typeof x === 'string') {
|
|
195
|
-
return { Slot: defaultSlot, id: x, Count: 1 };
|
|
196
|
-
}
|
|
197
|
-
if (Array.isArray(x)) {
|
|
198
|
-
if (x.length === 2) {
|
|
199
|
-
const [id, count] = x;
|
|
200
|
-
return { Slot: defaultSlot, id, Count: count };
|
|
201
|
-
}
|
|
202
|
-
if (x.length === 3) {
|
|
203
|
-
const [id, count, components] = x;
|
|
204
|
-
const d = { Slot: defaultSlot, id, Count: count };
|
|
205
|
-
if (components) d.components = { ...components };
|
|
206
|
-
return d;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
throw new TypeError(
|
|
210
|
-
`Unsupported chest item: ${JSON.stringify(x)}. ` +
|
|
211
|
-
`Use Item(...), 'minecraft:foo', or [id, count, components?].`
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export function chest(items, { name = null, lock = null, lootTable = null } = {}) {
|
|
216
|
-
const out = [];
|
|
217
|
-
if (items && !Array.isArray(items) && typeof items === 'object') {
|
|
218
|
-
// Plain object → explicit-slot map.
|
|
219
|
-
for (const [slotStr, x] of Object.entries(items)) {
|
|
220
|
-
const slot = parseInt(slotStr, 10);
|
|
221
|
-
const d = coerceItem(x, slot);
|
|
222
|
-
d.Slot = slot;
|
|
223
|
-
out.push(d);
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
let i = 0;
|
|
227
|
-
for (const x of items || []) {
|
|
228
|
-
out.push(coerceItem(x, i));
|
|
229
|
-
i++;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
const nbt = { Items: out };
|
|
233
|
-
if (name !== null) nbt.CustomName = name.startsWith('{') ? name : text(name);
|
|
234
|
-
if (lock !== null) nbt.Lock = lock;
|
|
235
|
-
if (lootTable !== null) nbt.LootTable = lootTable;
|
|
236
|
-
return nbt;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function signMessages(lines) {
|
|
240
|
-
const msgs = [];
|
|
241
|
-
for (const line of lines || []) {
|
|
242
|
-
if (line == null || line === '') {
|
|
243
|
-
msgs.push('""');
|
|
244
|
-
} else if (typeof line === 'string') {
|
|
245
|
-
msgs.push(line.startsWith('{') ? line : text(line));
|
|
246
|
-
} else {
|
|
247
|
-
throw new TypeError('Sign line must be string (plain or JSON-component)');
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
while (msgs.length < 4) msgs.push('""');
|
|
251
|
-
if (msgs.length > 4) throw new RangeError('A sign has at most 4 lines per side');
|
|
252
|
-
return msgs;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
export function sign(lines = [], { back = [], color = 'black', glowing = false, waxed = false } = {}) {
|
|
256
|
-
return {
|
|
257
|
-
front_text: { messages: signMessages(lines), color, has_glowing_text: glowing },
|
|
258
|
-
back_text: { messages: signMessages(back), color, has_glowing_text: glowing },
|
|
259
|
-
is_waxed: waxed,
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// --- Events ---------------------------------------------------------------
|
|
264
|
-
|
|
265
|
-
export class UseBlock {
|
|
266
|
-
constructor(pos) {
|
|
267
|
-
this.pos = pos;
|
|
268
|
-
Object.freeze(this);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
export class ButtonPress {
|
|
273
|
-
constructor(pos) {
|
|
274
|
-
this.pos = pos;
|
|
275
|
-
Object.freeze(this);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// --- Cursor ---------------------------------------------------------------
|
|
280
|
-
|
|
281
|
-
export class Cursor {
|
|
282
|
-
constructor(schem, origin, step) {
|
|
283
|
-
this._schem = schem;
|
|
284
|
-
this._origin = origin;
|
|
285
|
-
this.pos = origin;
|
|
286
|
-
this.step = step;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
place(block, opts = {}) {
|
|
290
|
-
const offset = opts.offset || [0, 0, 0];
|
|
291
|
-
const target = [
|
|
292
|
-
this.pos[0] + offset[0],
|
|
293
|
-
this.pos[1] + offset[1],
|
|
294
|
-
this.pos[2] + offset[2],
|
|
295
|
-
];
|
|
296
|
-
this._schem.setBlock(target, block, {
|
|
297
|
-
state: opts.state,
|
|
298
|
-
nbt: opts.nbt,
|
|
299
|
-
});
|
|
300
|
-
return this;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
advance(n = 1) {
|
|
304
|
-
this.pos = [
|
|
305
|
-
this.pos[0] + this.step[0] * n,
|
|
306
|
-
this.pos[1] + this.step[1] * n,
|
|
307
|
-
this.pos[2] + this.step[2] * n,
|
|
308
|
-
];
|
|
309
|
-
return this;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
reset() {
|
|
313
|
-
this.pos = this._origin;
|
|
314
|
-
return this;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// --- Schematic ------------------------------------------------------------
|
|
319
|
-
|
|
320
|
-
const LOAD_EXTS = ['.schem', '.litematic', '.nbt', '.schematic', '.mcstructure'];
|
|
321
|
-
|
|
322
|
-
function suffixOf(path) {
|
|
323
|
-
const m = String(path).toLowerCase().match(/\.[^.\/\\]+$/);
|
|
324
|
-
return m ? m[0] : '';
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
export class Schematic {
|
|
328
|
-
constructor(rawWrapper, { pack = null } = {}) {
|
|
329
|
-
this.raw = rawWrapper;
|
|
330
|
-
this.pack = pack;
|
|
331
|
-
this._pendingBuilder = null;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/** Create a blank schematic. */
|
|
335
|
-
static new(name = 'untitled', { pack = null } = {}) {
|
|
336
|
-
if (typeof name !== 'string') {
|
|
337
|
-
throw new TypeError(`Schematic.new() name must be a string, got ${typeof name}`);
|
|
338
|
-
}
|
|
339
|
-
const w = new raw.SchematicWrapper();
|
|
340
|
-
if (typeof w.set_name === 'function') {
|
|
341
|
-
try { w.set_name(name); } catch {}
|
|
342
|
-
}
|
|
343
|
-
return new Schematic(w, { pack });
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Load from binary data (Uint8Array). Format inferred from the second arg
|
|
348
|
-
* if it ends in a known extension; otherwise from_data() autodetects.
|
|
349
|
-
*/
|
|
350
|
-
static open(data, { hint = null, pack = null } = {}) {
|
|
351
|
-
const w = new raw.SchematicWrapper();
|
|
352
|
-
const ext = hint ? suffixOf(hint) : '';
|
|
353
|
-
if (ext === '.litematic') w.from_litematic(data);
|
|
354
|
-
else if (ext === '.schem' || ext === '.schematic') w.from_schematic(data);
|
|
355
|
-
else if (ext === '.mcstructure') w.from_mcstructure(data);
|
|
356
|
-
else w.from_data(data);
|
|
357
|
-
return new Schematic(w, { pack });
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/** Build from an ASCII-art template via SchematicBuilderWrapper. */
|
|
361
|
-
static fromTemplate(template, { name = 'untitled', pack = null } = {}) {
|
|
362
|
-
const builder = raw.SchematicBuilderWrapper.from_template
|
|
363
|
-
? raw.SchematicBuilderWrapper.from_template(template)
|
|
364
|
-
: new raw.SchematicBuilderWrapper().from_template(template);
|
|
365
|
-
if (typeof builder.name === 'function') builder.name(name);
|
|
366
|
-
const schem = new Schematic(/* placeholder */ null, { pack });
|
|
367
|
-
schem._pendingBuilder = builder;
|
|
368
|
-
schem._pendingName = name;
|
|
369
|
-
return schem;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
_ensureBuilt() {
|
|
373
|
-
if (this._pendingBuilder) {
|
|
374
|
-
this.raw = this._pendingBuilder.build();
|
|
375
|
-
this._pendingBuilder = null;
|
|
376
|
-
}
|
|
377
|
-
return this.raw;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Pre-resolve a plain block id to a palette index. Pair with `place()`
|
|
382
|
-
* in hot loops to skip the per-call name lookup. Returns the index.
|
|
383
|
-
*/
|
|
384
|
-
prepareBlock(name) {
|
|
385
|
-
this._ensureBuilt();
|
|
386
|
-
return this.raw.prepareBlock(name);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Place a block by pre-resolved palette index. Pair with `prepareBlock`.
|
|
391
|
-
*
|
|
392
|
-
* Hot-loop pattern (~10 M placements/sec):
|
|
393
|
-
*
|
|
394
|
-
* const stone = schem.prepareBlock('minecraft:stone');
|
|
395
|
-
* const place = schem.raw.place.bind(schem.raw);
|
|
396
|
-
* for (const [x, y, z] of positions) place(x, y, z, stone);
|
|
397
|
-
*/
|
|
398
|
-
place(x, y, z, paletteIndex) {
|
|
399
|
-
this._ensureBuilt();
|
|
400
|
-
this.raw.place(x, y, z, paletteIndex);
|
|
401
|
-
return this;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* setBlock([x, y, z], "id" | Block, { state?, nbt? })
|
|
406
|
-
* setBlock(x, y, z, "id") — legacy form
|
|
407
|
-
*
|
|
408
|
-
* Performance: plain id strings and reused `Block` instances take fast
|
|
409
|
-
* paths (Block payloads cache after first use). For uniform regions or
|
|
410
|
-
* many positions of one block, prefer fill() / raw set_blocks().
|
|
411
|
-
*/
|
|
412
|
-
setBlock(...args) {
|
|
413
|
-
let x, y, z, block, opts;
|
|
414
|
-
if (args.length === 4 && typeof args[0] === 'number') {
|
|
415
|
-
[x, y, z, block] = args;
|
|
416
|
-
opts = null;
|
|
417
|
-
} else if ((args.length === 2 || args.length === 3) && Array.isArray(args[0])) {
|
|
418
|
-
const pos = args[0];
|
|
419
|
-
if (pos.length !== 3 || !pos.every((v) => typeof v === 'number')) {
|
|
420
|
-
throw new TypeError(
|
|
421
|
-
`setBlock((x, y, z), block): first arg must be a 3-tuple of numbers, got [${pos.join(', ')}]`
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
[[x, y, z], block, opts = null] = args;
|
|
425
|
-
} else {
|
|
426
|
-
throw new TypeError(
|
|
427
|
-
`setBlock expected (x, y, z, block) or ([x, y, z], block, opts?), got ${args.length} args`
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
|
-
if (typeof block !== 'string' && !(block instanceof Block)) {
|
|
431
|
-
throw new TypeError(`block must be a string or Block, got ${typeof block}`);
|
|
432
|
-
}
|
|
433
|
-
if (opts && typeof opts !== 'object') {
|
|
434
|
-
throw new TypeError(`setBlock opts must be an object, got ${typeof opts}`);
|
|
435
|
-
}
|
|
436
|
-
if (opts && opts.state != null && (typeof opts.state !== 'object' || Array.isArray(opts.state))) {
|
|
437
|
-
throw new TypeError(`setBlock opts.state must be an object, got ${typeof opts.state}`);
|
|
438
|
-
}
|
|
439
|
-
if (opts && opts.nbt != null && (typeof opts.nbt !== 'object' || Array.isArray(opts.nbt))) {
|
|
440
|
-
throw new TypeError(
|
|
441
|
-
`setBlock opts.nbt must be an object, got ${typeof opts.nbt}. ` +
|
|
442
|
-
`For raw SNBT pass nbt: { __snbt__: '<your-snbt>' }.`
|
|
443
|
-
);
|
|
444
|
-
}
|
|
445
|
-
const inner = this.raw || this._ensureBuilt();
|
|
446
|
-
|
|
447
|
-
// Ultra-fast path: plain id, no opts.
|
|
448
|
-
if (!opts && typeof block === 'string') {
|
|
449
|
-
if (block.indexOf('[') < 0 && block.indexOf('{') < 0) {
|
|
450
|
-
inner.set_block(x, y, z, block);
|
|
451
|
-
return this;
|
|
452
|
-
}
|
|
453
|
-
inner.set_block_from_string(x, y, z, block);
|
|
454
|
-
return this;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Fast path: reused Block, no override opts.
|
|
458
|
-
if (!opts && block instanceof Block) {
|
|
459
|
-
if (!block._hasExtras) {
|
|
460
|
-
inner.set_block(x, y, z, block.id);
|
|
461
|
-
} else if (block.nbt) {
|
|
462
|
-
inner.set_block_from_string(x, y, z, block.toString());
|
|
463
|
-
} else {
|
|
464
|
-
const props = {};
|
|
465
|
-
for (const [k, v] of Object.entries(block.state)) props[k] = stateToStr(v);
|
|
466
|
-
inner.set_block_with_properties(x, y, z, block.id, props);
|
|
467
|
-
}
|
|
468
|
-
return this;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Slow path: opts may augment.
|
|
472
|
-
opts = opts || {};
|
|
473
|
-
let blockObj;
|
|
474
|
-
if (block instanceof Block) blockObj = block;
|
|
475
|
-
else if (typeof block === 'string') {
|
|
476
|
-
if (!opts.state && !opts.nbt && (block.includes('[') || block.includes('{'))) {
|
|
477
|
-
blockObj = Block.parse(block);
|
|
478
|
-
} else {
|
|
479
|
-
blockObj = new Block(block, { state: opts.state, nbt: opts.nbt });
|
|
480
|
-
}
|
|
481
|
-
} else {
|
|
482
|
-
throw new TypeError(`block must be string or Block, got ${typeof block}`);
|
|
483
|
-
}
|
|
484
|
-
const effState = { ...(blockObj.state || {}), ...(opts.state || {}) };
|
|
485
|
-
const effNbt = { ...(blockObj.nbt || {}), ...(opts.nbt || {}) };
|
|
486
|
-
const hasState = Object.keys(effState).length > 0;
|
|
487
|
-
const hasNbt = Object.keys(effNbt).length > 0;
|
|
488
|
-
|
|
489
|
-
if (hasNbt) {
|
|
490
|
-
const snbt = (SNBT_RAW in effNbt && Object.keys(effNbt).length === 1)
|
|
491
|
-
? String(effNbt[SNBT_RAW])
|
|
492
|
-
: dictToSnbt(effNbt);
|
|
493
|
-
let payload = blockObj.id;
|
|
494
|
-
if (hasState) {
|
|
495
|
-
payload += '[' + Object.entries(effState).map(([k, v]) => `${k}=${stateToStr(v)}`).join(',') + ']';
|
|
496
|
-
}
|
|
497
|
-
payload += '{' + snbt + '}';
|
|
498
|
-
inner.set_block_from_string(x, y, z, payload);
|
|
499
|
-
} else if (hasState) {
|
|
500
|
-
const props = {};
|
|
501
|
-
for (const [k, v] of Object.entries(effState)) props[k] = stateToStr(v);
|
|
502
|
-
inner.set_block_with_properties(x, y, z, blockObj.id, props);
|
|
503
|
-
} else {
|
|
504
|
-
inner.set_block(x, y, z, blockObj.id);
|
|
505
|
-
}
|
|
506
|
-
return this;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
map(char, block, { state = null, nbt = null } = {}) {
|
|
510
|
-
if (!this._pendingBuilder) {
|
|
511
|
-
throw new Error('map() is only valid on Schematic.fromTemplate()');
|
|
512
|
-
}
|
|
513
|
-
let payload;
|
|
514
|
-
if (block instanceof Block) payload = block.toString();
|
|
515
|
-
else if (state || nbt) payload = new Block(block, { state, nbt }).toString();
|
|
516
|
-
else payload = block;
|
|
517
|
-
this._pendingBuilder.map(char, payload);
|
|
518
|
-
return this;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
fill([p1, p2], block) {
|
|
522
|
-
const blockId = block instanceof Block ? block.toString() : block;
|
|
523
|
-
const inner = this._ensureBuilt();
|
|
524
|
-
inner.fillCuboid(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], blockId);
|
|
525
|
-
return this;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
cursor({ origin = [0, 0, 0], step = [1, 0, 0] } = {}) {
|
|
529
|
-
this._ensureBuilt();
|
|
530
|
-
return new Cursor(this, origin, step);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
withPack(pack) {
|
|
534
|
-
this.pack = pack;
|
|
535
|
-
return this;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
copy() {
|
|
539
|
-
const inner = this._ensureBuilt();
|
|
540
|
-
const data = inner.to_litematic();
|
|
541
|
-
const w = new raw.SchematicWrapper();
|
|
542
|
-
w.from_litematic(data);
|
|
543
|
-
return new Schematic(w, { pack: this.pack });
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
/** Run a redstone simulation, then sync results back into this schematic. */
|
|
547
|
-
simulate({ ticks = 1, events = [] } = {}) {
|
|
548
|
-
const inner = this._ensureBuilt();
|
|
549
|
-
if (typeof inner.create_simulation_world !== 'function') {
|
|
550
|
-
throw new Error('simulation feature is not available in this WASM build');
|
|
551
|
-
}
|
|
552
|
-
const world = inner.create_simulation_world();
|
|
553
|
-
for (const ev of events) {
|
|
554
|
-
if (ev instanceof UseBlock || ev instanceof ButtonPress) {
|
|
555
|
-
const [x, y, z] = ev.pos;
|
|
556
|
-
world.on_use_block(x, y, z);
|
|
557
|
-
} else {
|
|
558
|
-
throw new TypeError('Unsupported event; use UseBlock or ButtonPress');
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
world.tick(ticks);
|
|
562
|
-
world.sync_to_schematic();
|
|
563
|
-
if (typeof world.into_schematic === 'function') {
|
|
564
|
-
this.raw = world.into_schematic();
|
|
565
|
-
} else if (typeof world.get_schematic === 'function') {
|
|
566
|
-
this.raw = world.get_schematic();
|
|
567
|
-
}
|
|
568
|
-
return this;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
/**
|
|
572
|
-
* Serialize to bytes by format extension; if a Node fs is provided
|
|
573
|
-
* (the default in Node), write to disk.
|
|
574
|
-
*/
|
|
575
|
-
async save(path, { format = null, fs = null } = {}) {
|
|
576
|
-
const inner = this._ensureBuilt();
|
|
577
|
-
const ext = format ? '.' + format : suffixOf(path);
|
|
578
|
-
let bytes;
|
|
579
|
-
if (ext === '.litematic') bytes = inner.to_litematic();
|
|
580
|
-
else if (ext === '.schem' || ext === '.schematic') bytes = inner.to_schematic();
|
|
581
|
-
else if (ext === '.mcstructure') bytes = inner.to_mcstructure();
|
|
582
|
-
else throw new Error(`save: unknown format for ${path}`);
|
|
583
|
-
bytes = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
|
|
584
|
-
if (typeof process !== 'undefined' && process.versions?.node) {
|
|
585
|
-
const nodeFs = fs || (await import('node:fs/promises'));
|
|
586
|
-
await nodeFs.writeFile(path, bytes);
|
|
587
|
-
return null;
|
|
588
|
-
}
|
|
589
|
-
return bytes;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// --- SchematicBuilder shim ------------------------------------------------
|
|
594
|
-
|
|
595
|
-
export class SchematicBuilder {
|
|
596
|
-
constructor() {
|
|
597
|
-
if (typeof console !== 'undefined' && console.warn) {
|
|
598
|
-
console.warn(
|
|
599
|
-
'[nucleation] SchematicBuilder is deprecated; use Schematic.fromTemplate(...)'
|
|
600
|
-
);
|
|
601
|
-
}
|
|
602
|
-
this._raw = new raw.SchematicBuilderWrapper();
|
|
603
|
-
}
|
|
604
|
-
name(n) { this._raw.name(n); return this; }
|
|
605
|
-
fromTemplate(t) { this._raw = raw.SchematicBuilderWrapper.from_template(t); return this; }
|
|
606
|
-
map(c, b) { this._raw.map(c, b); return this; }
|
|
607
|
-
build() { return new Schematic(this._raw.build()); }
|
|
608
|
-
}
|
package/nucleation-cdn-loader.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// This loader is for use in a browser via <script type="module"> from a CDN.
|
|
2
|
-
// It ensures that the .wasm file is loaded from the correct relative path.
|
|
3
|
-
|
|
4
|
-
// Import the real init function and all the classes from the original module.
|
|
5
|
-
import init, * as wasm from './nucleation-original.js';
|
|
6
|
-
|
|
7
|
-
// The default export is a new initializer function for CDN use.
|
|
8
|
-
// It calls the real 'init' but provides the URL to the .wasm file.
|
|
9
|
-
export default async function() {
|
|
10
|
-
const wasmUrl = new URL('./nucleation_bg.wasm', import.meta.url);
|
|
11
|
-
await init(wasmUrl);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// Re-export all the named classes (SchematicWrapper, etc.).
|
|
15
|
-
export * from './nucleation-original.js';
|