@onimaxxing/worldgen-node 0.15.0
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/LICENSE +21 -0
- package/README.md +442 -0
- package/editor_settings.d.ts +1034 -0
- package/index.cjs +147 -0
- package/index.d.ts +682 -0
- package/oni_wasm.d.ts +274 -0
- package/oni_wasm.js +1047 -0
- package/oni_wasm_bg.wasm +0 -0
- package/package.json +30 -0
- package/yaml.cjs +44 -0
- package/yaml.d.ts +19 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
// Consumer-facing type surface for
|
|
2
|
+
// `@onimaxxing/worldgen`.
|
|
3
|
+
//
|
|
4
|
+
// This is the single types entry point for the package. The nested
|
|
5
|
+
// settings types (World, Subworld, BiomeSettings, NoiseTree, etc.)
|
|
6
|
+
// live in `editor_settings.d.ts` and are re-exported here so consumers
|
|
7
|
+
// can import every type by name from the package root.
|
|
8
|
+
|
|
9
|
+
// Klei-faithful YAML → JS parser. Pair with `worldgen.snapshot.merge`
|
|
10
|
+
// to ingest mod content (which ships as `.yaml`):
|
|
11
|
+
//
|
|
12
|
+
// const json = parseKleiYaml(readFileSync('mod/cluster.yaml', 'utf8'));
|
|
13
|
+
// worldgen.snapshot.merge({ 'expansion1::worldgen/clusters/X.yaml': JSON.stringify(json) });
|
|
14
|
+
export { parseKleiYaml } from './yaml.js';
|
|
15
|
+
|
|
16
|
+
// -----------------------------------------------------------------------
|
|
17
|
+
// Settings types (imported and re-exported from editor_settings.d.ts).
|
|
18
|
+
// `ClusterLayout`, `World`, `Subworld`, etc. are the typed schemas for
|
|
19
|
+
// the JSON-string values in each entry of the `path → JSON-string`
|
|
20
|
+
// snapshot files map.
|
|
21
|
+
// -----------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
import type {
|
|
24
|
+
MinMax,
|
|
25
|
+
Vector2I,
|
|
26
|
+
WorldSize,
|
|
27
|
+
LayoutMethod,
|
|
28
|
+
WorldCategory,
|
|
29
|
+
ListRule,
|
|
30
|
+
TagCommand,
|
|
31
|
+
FilterCommand,
|
|
32
|
+
SampleBehaviour,
|
|
33
|
+
ZoneType,
|
|
34
|
+
TemperatureRange,
|
|
35
|
+
AllowedCellsFilter,
|
|
36
|
+
TraitRule,
|
|
37
|
+
SubworldMixingRule,
|
|
38
|
+
ModifyLayoutTagsRule,
|
|
39
|
+
TemplateSpawnRules,
|
|
40
|
+
World,
|
|
41
|
+
WeightedSubworldName,
|
|
42
|
+
Sampler,
|
|
43
|
+
Subworld,
|
|
44
|
+
Feature,
|
|
45
|
+
InternalMob,
|
|
46
|
+
CountRange,
|
|
47
|
+
WeightedBiome,
|
|
48
|
+
BaseLocation,
|
|
49
|
+
StartingWorldElement,
|
|
50
|
+
DefaultSettings,
|
|
51
|
+
MinMaxConfig,
|
|
52
|
+
MobLocation,
|
|
53
|
+
MobConfig,
|
|
54
|
+
RoomConfig,
|
|
55
|
+
TemplateVec2I,
|
|
56
|
+
TemplateInfo,
|
|
57
|
+
TemplateCell,
|
|
58
|
+
TemplateStorageItem,
|
|
59
|
+
TemplatePrefab,
|
|
60
|
+
TemplateContainer,
|
|
61
|
+
ClusterLayout,
|
|
62
|
+
NoiseTree,
|
|
63
|
+
BiomeSettings,
|
|
64
|
+
WorldTrait,
|
|
65
|
+
FeatureSettings,
|
|
66
|
+
DlcMixingSettings,
|
|
67
|
+
WorldMixingSettings,
|
|
68
|
+
SubworldMixingSettings,
|
|
69
|
+
} from './editor_settings.js';
|
|
70
|
+
|
|
71
|
+
export type {
|
|
72
|
+
MinMax,
|
|
73
|
+
Vector2I,
|
|
74
|
+
WorldSize,
|
|
75
|
+
LayoutMethod,
|
|
76
|
+
WorldCategory,
|
|
77
|
+
ListRule,
|
|
78
|
+
TagCommand,
|
|
79
|
+
FilterCommand,
|
|
80
|
+
SampleBehaviour,
|
|
81
|
+
ZoneType,
|
|
82
|
+
TemperatureRange,
|
|
83
|
+
AllowedCellsFilter,
|
|
84
|
+
TraitRule,
|
|
85
|
+
SubworldMixingRule,
|
|
86
|
+
ModifyLayoutTagsRule,
|
|
87
|
+
TemplateSpawnRules,
|
|
88
|
+
World,
|
|
89
|
+
WeightedSubworldName,
|
|
90
|
+
Sampler,
|
|
91
|
+
Subworld,
|
|
92
|
+
Feature,
|
|
93
|
+
InternalMob,
|
|
94
|
+
CountRange,
|
|
95
|
+
WeightedBiome,
|
|
96
|
+
BaseLocation,
|
|
97
|
+
StartingWorldElement,
|
|
98
|
+
DefaultSettings,
|
|
99
|
+
MinMaxConfig,
|
|
100
|
+
MobLocation,
|
|
101
|
+
MobConfig,
|
|
102
|
+
RoomConfig,
|
|
103
|
+
TemplateVec2I,
|
|
104
|
+
TemplateInfo,
|
|
105
|
+
TemplateCell,
|
|
106
|
+
TemplateStorageItem,
|
|
107
|
+
TemplatePrefab,
|
|
108
|
+
TemplateContainer,
|
|
109
|
+
ClusterLayout,
|
|
110
|
+
NoiseTree,
|
|
111
|
+
BiomeSettings,
|
|
112
|
+
WorldTrait,
|
|
113
|
+
FeatureSettings,
|
|
114
|
+
DlcMixingSettings,
|
|
115
|
+
WorldMixingSettings,
|
|
116
|
+
SubworldMixingSettings,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// -----------------------------------------------------------------------
|
|
120
|
+
// Map data types (returned by worldgen.generate)
|
|
121
|
+
// -----------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Full map payload returned by `worldgen.generate(coordinate)`. One
|
|
125
|
+
* top-level envelope for cluster metadata plus a per-world array with
|
|
126
|
+
* element grid, biome polygons, and entity spawns.
|
|
127
|
+
*/
|
|
128
|
+
export interface MapData {
|
|
129
|
+
coordinate: string;
|
|
130
|
+
seed: number;
|
|
131
|
+
cluster_id: string;
|
|
132
|
+
/**
|
|
133
|
+
* Short cluster tag from the coord grammar, e.g. `SNDST-C`, `V-BAD-C`,
|
|
134
|
+
* `M-FRZ-C`, `VOLCA`. Matches the `coordinatePrefix` in the cluster
|
|
135
|
+
* YAML. Stable across seeds; use it to group results by cluster type
|
|
136
|
+
* without parsing the full coord string (prefixes can contain hyphens,
|
|
137
|
+
* so naive splitting is unreliable).
|
|
138
|
+
*/
|
|
139
|
+
coordinate_prefix: string;
|
|
140
|
+
/** Element ids, indexed by the `element_idx` values in each world's cell grid. */
|
|
141
|
+
element_table: string[];
|
|
142
|
+
/** Spaced Out hex-grid world locations. One entry per asteroid. */
|
|
143
|
+
starmap: StarmapEntry[];
|
|
144
|
+
/** Spaced Out non-asteroid hex POIs (harvestable clouds, artifact sites, etc). */
|
|
145
|
+
starmap_pois: StarmapPoi[];
|
|
146
|
+
/** Basegame (non-SpacedOut) rocket destinations. Empty on SpacedOut clusters. */
|
|
147
|
+
vanilla_starmap: VanillaStarmapEntry[];
|
|
148
|
+
worlds: WorldMapData[];
|
|
149
|
+
/**
|
|
150
|
+
* Populated when the worldgen pipeline detected a fatal failure
|
|
151
|
+
* (e.g. "Could not guarantee minCount of Subworld X", story trait
|
|
152
|
+
* couldn't place on any world, layout collapse). Mirrors the game's
|
|
153
|
+
* `ReportWorldGenError` + abort path. `null` on successful generation.
|
|
154
|
+
*/
|
|
155
|
+
failure: WorldgenFailure | null;
|
|
156
|
+
/**
|
|
157
|
+
* Recoverable per-world or cluster-level warnings that didn't abort
|
|
158
|
+
* worldgen. Per-world entries have the world index prepended to the
|
|
159
|
+
* message. Empty array on clean runs.
|
|
160
|
+
*/
|
|
161
|
+
telemetry: WorldgenEvent[];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface WorldgenFailure {
|
|
165
|
+
/** Where in the pipeline the failure was detected (e.g. "AssignClusterLocations", "render_to_map"). */
|
|
166
|
+
stage: string;
|
|
167
|
+
/** World index where the failure happened. `-1` for cluster-level failures. */
|
|
168
|
+
world_index: number;
|
|
169
|
+
/** Human-readable description. */
|
|
170
|
+
message: string;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface WorldgenEvent {
|
|
174
|
+
/** Stable short tag for grouping (e.g. "layout", "noise", "mob_spawning", "template_rules"). */
|
|
175
|
+
category: string;
|
|
176
|
+
/** Free-form description. Per-world entries are prefixed with `world[N]:`. */
|
|
177
|
+
message: string;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface WorldMapData {
|
|
181
|
+
/**
|
|
182
|
+
* World config path — **post-substitution** when the placement was
|
|
183
|
+
* swapped via `WorldgenMixing.DoWorldMixing`. On seeds where a
|
|
184
|
+
* Ceres / Prehistoric / Aquatic Asteroid Mixing fragment took this
|
|
185
|
+
* slot, `name` is the fragment path (e.g.
|
|
186
|
+
* `"dlc5::worlds/MixingAquaticAsteroid"`). Use `remixed_from` to
|
|
187
|
+
* recover the vanilla identity that the cluster picker showed.
|
|
188
|
+
*/
|
|
189
|
+
name: string;
|
|
190
|
+
/**
|
|
191
|
+
* Pre-substitution world path when this slot was swapped by
|
|
192
|
+
* world-mixing, else `null`. Set from the `MixingApplied.from_world`
|
|
193
|
+
* recorded during `Cluster.generate_with_settings`. Consumers that
|
|
194
|
+
* query by the world they see in the cluster picker
|
|
195
|
+
* (`"TundraMoonlet"`, `"MarshyMoonlet"`, …) should substring-match
|
|
196
|
+
* this field as a fallback when `name` — which is post-substitution
|
|
197
|
+
* — doesn't contain the vanilla needle. Mirrors
|
|
198
|
+
* `ClusterSummary.remixed_from` in the gambling wasm.
|
|
199
|
+
*/
|
|
200
|
+
remixed_from: string | null;
|
|
201
|
+
/**
|
|
202
|
+
* CGM-style mixing source id when this slot was swapped, else
|
|
203
|
+
* `null`. One of `"CeresAsteroidMixing"`,
|
|
204
|
+
* `"PrehistoricAsteroidMixing"`, `"AquaticAsteroidMixing"`. Stable
|
|
205
|
+
* across builds; safe to use for badge-rendering.
|
|
206
|
+
*/
|
|
207
|
+
remixed_source: string | null;
|
|
208
|
+
width: number;
|
|
209
|
+
height: number;
|
|
210
|
+
is_starting: boolean;
|
|
211
|
+
world_traits: string[];
|
|
212
|
+
/**
|
|
213
|
+
* u16 per cell, row-major (`width * height`). Backed by a
|
|
214
|
+
* freshly-allocated JS typed array (`wasm-bindgen` copies out of
|
|
215
|
+
* WASM linear memory), so it's safe to retain across subsequent
|
|
216
|
+
* `worldgen.generate` calls without being invalidated.
|
|
217
|
+
*/
|
|
218
|
+
element_idx: Uint16Array;
|
|
219
|
+
mass: Float32Array;
|
|
220
|
+
temperature: Float32Array;
|
|
221
|
+
/** u8 per cell; 255 means no disease. */
|
|
222
|
+
disease_idx: Uint8Array;
|
|
223
|
+
/** i32 per cell. */
|
|
224
|
+
disease_count: Int32Array;
|
|
225
|
+
/**
|
|
226
|
+
* U59 backwall element ids, one u16 per cell. Vacuum-filled (the
|
|
227
|
+
* Vacuum element's index in `MapData.element_table`) for worlds
|
|
228
|
+
* whose subworld YAML doesn't declare a `backwallNoise` channel —
|
|
229
|
+
* only DLC5 aquatic biomes (Reef / Abyss / shallows) populate
|
|
230
|
+
* non-Vacuum backwall.
|
|
231
|
+
*/
|
|
232
|
+
backwall_element_idx: Uint16Array;
|
|
233
|
+
/** U59 backwall mass per cell, in kg. Zero on Vacuum cells. */
|
|
234
|
+
backwall_mass: Float32Array;
|
|
235
|
+
/** U59 backwall temperature per cell, in K. Zero on Vacuum cells. */
|
|
236
|
+
backwall_temperature: Float32Array;
|
|
237
|
+
biome_cells: BiomeCell[];
|
|
238
|
+
geysers: GeyserSpawn[];
|
|
239
|
+
buildings: EntitySpawn[];
|
|
240
|
+
pickupables: EntitySpawn[];
|
|
241
|
+
other_entities: EntitySpawn[];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export interface BiomeCell {
|
|
245
|
+
id: number;
|
|
246
|
+
/** Subworld type path, e.g. `"expansion1::subworlds/jungle/med_Jungle"`. */
|
|
247
|
+
type: string;
|
|
248
|
+
/**
|
|
249
|
+
* The Subworld's `ZoneType` enum value as a string (matches the
|
|
250
|
+
* `ZoneType` union in `editor_settings.d.ts`). `null` when the
|
|
251
|
+
* subworld path couldn't be resolved in the current settings.
|
|
252
|
+
*/
|
|
253
|
+
zone_type: ZoneType | null;
|
|
254
|
+
x: number;
|
|
255
|
+
y: number;
|
|
256
|
+
/** Flat polygon vertex array: `[x0, y0, x1, y1,...]`. */
|
|
257
|
+
poly: number[];
|
|
258
|
+
/**
|
|
259
|
+
* The layout tags this overworld node carries — e.g. `"AtSurface"`,
|
|
260
|
+
* `"AtDepths"`, `"AtEdge"`, distance tags (`"AtSurface_Distance2"`),
|
|
261
|
+
* the subworld's `ZoneType` tag, and its subworld tags. These are the
|
|
262
|
+
* keys `AllowedCellsFilter` matches against, so they let you
|
|
263
|
+
* visualize/explain why a subworld landed here and interpret the
|
|
264
|
+
* filter chain client-side. Not a closed vocabulary (subworld/world
|
|
265
|
+
* YAML can declare arbitrary tags).
|
|
266
|
+
*/
|
|
267
|
+
tags: string[];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export interface EntitySpawn {
|
|
271
|
+
/** Game prefab name. */
|
|
272
|
+
tag: string;
|
|
273
|
+
/** Grid cell index. */
|
|
274
|
+
cell: number;
|
|
275
|
+
/** `cell % width`. */
|
|
276
|
+
x: number;
|
|
277
|
+
/** `cell / width`. */
|
|
278
|
+
y: number;
|
|
279
|
+
/**
|
|
280
|
+
* Connections bitmask preserved from the source
|
|
281
|
+
* `TemplatePrefab.connections`. Present only for template-placed
|
|
282
|
+
* conduit-aware buildings (LogicGate, LogicWire, etc.). Absent for
|
|
283
|
+
* ambient / terrain mob spawns and for prefabs that had no
|
|
284
|
+
* connections field in the YAML.
|
|
285
|
+
*/
|
|
286
|
+
connections?: number;
|
|
287
|
+
/**
|
|
288
|
+
* Rotation / orientation preserved from
|
|
289
|
+
* `TemplatePrefab.rotationOrientation`. e.g. `"R90"`, `"R180"`,
|
|
290
|
+
* `"R270"`, `"FlipH"`. Present only for rotated template buildings
|
|
291
|
+
* (e.g. the R270 LiquidValve in `poi_old_pool`). Absent otherwise.
|
|
292
|
+
*/
|
|
293
|
+
rotationOrientation?: string;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Geyser spawn. `type` is the resolved template id (what the game
|
|
298
|
+
* rolls `GeyserGeneric_*` into); `scaled_*` fields come from the
|
|
299
|
+
* per-geyser stats roll and are absent for non-random geysers.
|
|
300
|
+
*/
|
|
301
|
+
export interface GeyserSpawn extends EntitySpawn {
|
|
302
|
+
type: string;
|
|
303
|
+
scaled_rate?: number;
|
|
304
|
+
scaled_iter_len?: number;
|
|
305
|
+
scaled_iter_pct?: number;
|
|
306
|
+
scaled_year_len?: number;
|
|
307
|
+
scaled_year_pct?: number;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface StarmapEntry {
|
|
311
|
+
world_index: number;
|
|
312
|
+
q: number;
|
|
313
|
+
r: number;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export interface StarmapPoi {
|
|
317
|
+
/** e.g. `"HarvestableSpacePOI_*"`, `"ArtifactSpacePOI"`. */
|
|
318
|
+
poi_type: string;
|
|
319
|
+
q: number;
|
|
320
|
+
r: number;
|
|
321
|
+
// Present only on harvestable POIs:
|
|
322
|
+
capacity_roll?: number;
|
|
323
|
+
recharge_roll?: number;
|
|
324
|
+
total_capacity?: number;
|
|
325
|
+
recharge_time?: number;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface VanillaStarmapEntry {
|
|
329
|
+
type: string;
|
|
330
|
+
distance: number;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// -----------------------------------------------------------------------
|
|
334
|
+
// Settle snapshot (returned by worldgen.advance)
|
|
335
|
+
// -----------------------------------------------------------------------
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* A per-tick snapshot of settle state, one decoded v4 binary frame.
|
|
339
|
+
* Arrays are parallel (indexed by row-major cell position).
|
|
340
|
+
*/
|
|
341
|
+
export interface SettleSnapshot {
|
|
342
|
+
/** Tick this snapshot was taken at. Monotonic, 1..=499. */
|
|
343
|
+
tick: number;
|
|
344
|
+
worlds: SettleWorld[];
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export interface SettleWorld {
|
|
348
|
+
width: number;
|
|
349
|
+
height: number;
|
|
350
|
+
element_idx: Uint16Array;
|
|
351
|
+
mass: Float32Array;
|
|
352
|
+
temperature: Float32Array;
|
|
353
|
+
/** 255 = no disease on that cell. */
|
|
354
|
+
disease_idx: Uint8Array;
|
|
355
|
+
disease_count: Int32Array;
|
|
356
|
+
/**
|
|
357
|
+
* U59 backwall element ids, live at the snapshot's `tick`. Vacuum
|
|
358
|
+
* (`element_table.indexOf("Vacuum")` from `MapData`) on worlds
|
|
359
|
+
* without `backwallNoise` in their subworld YAML — populated only
|
|
360
|
+
* for DLC5 aquatic biomes.
|
|
361
|
+
*/
|
|
362
|
+
backwall_element_idx: Uint16Array;
|
|
363
|
+
/** U59 backwall mass per cell, in kg. Zero on Vacuum cells. */
|
|
364
|
+
backwall_mass: Float32Array;
|
|
365
|
+
/** U59 backwall temperature per cell, in K. Zero on Vacuum cells. */
|
|
366
|
+
backwall_temperature: Float32Array;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// -----------------------------------------------------------------------
|
|
370
|
+
// Entity spawners (returned by worldgen.entities)
|
|
371
|
+
// -----------------------------------------------------------------------
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Refreshed entity spawns against the cached cluster's current sim
|
|
375
|
+
* state. Shape mirrors the per-world entity arrays in `MapData`.
|
|
376
|
+
*/
|
|
377
|
+
export interface EntitySpawners {
|
|
378
|
+
worlds: EntitySpawnerWorld[];
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export interface EntitySpawnerWorld {
|
|
382
|
+
geysers: GeyserSpawn[];
|
|
383
|
+
buildings: EntitySpawn[];
|
|
384
|
+
pickupables: EntitySpawn[];
|
|
385
|
+
other_entities: EntitySpawn[];
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// -----------------------------------------------------------------------
|
|
389
|
+
// init + worldgen singleton
|
|
390
|
+
// -----------------------------------------------------------------------
|
|
391
|
+
|
|
392
|
+
export interface InitOptions {
|
|
393
|
+
/**
|
|
394
|
+
* Custom URL / Request / pre-compiled module for the .wasm binary.
|
|
395
|
+
* Omit to use the bundler-rewritten default.
|
|
396
|
+
*/
|
|
397
|
+
module_or_path?:
|
|
398
|
+
| string
|
|
399
|
+
| URL
|
|
400
|
+
| Request
|
|
401
|
+
| Response
|
|
402
|
+
| BufferSource
|
|
403
|
+
| WebAssembly.Module
|
|
404
|
+
| Promise<
|
|
405
|
+
string | URL | Request | Response | BufferSource | WebAssembly.Module
|
|
406
|
+
>;
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* - `'auto'` (default): pick parallel when `crossOriginIsolated` and
|
|
410
|
+
* `SharedArrayBuffer` are available, with
|
|
411
|
+
* `navigator.hardwareConcurrency` workers. Otherwise serial.
|
|
412
|
+
* - `'serial'`: force the serial build.
|
|
413
|
+
* - `number`: force parallel with this many workers (falls back to
|
|
414
|
+
* serial when parallel isn't available).
|
|
415
|
+
*/
|
|
416
|
+
threads?: number | 'auto' | 'serial';
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Initialise the WASM module. The web package ships both a serial and
|
|
421
|
+
* a parallel (rayon + SharedArrayBuffer) build; `init()` feature-detects
|
|
422
|
+
* the runtime, loads the appropriate one, and on parallel hosts also
|
|
423
|
+
* spawns the worker pool. Memoized — extra calls short-circuit.
|
|
424
|
+
*/
|
|
425
|
+
export default function init(options?: InitOptions): Promise<void>;
|
|
426
|
+
|
|
427
|
+
/** `true` for parallel, `false` for serial, `null` before init resolves. */
|
|
428
|
+
export function isParallel(): boolean | null;
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Singleton that wraps the one-slot cluster cache in WASM. All methods
|
|
432
|
+
* (except `generate`, `reset`, and `version`) operate on whatever
|
|
433
|
+
* cluster is currently cached; call `generate(coord)` first to populate.
|
|
434
|
+
*/
|
|
435
|
+
export const worldgen: {
|
|
436
|
+
/**
|
|
437
|
+
* Generate a cluster from a game coordinate. Caches the cluster in
|
|
438
|
+
* the WASM thread-local slot, replacing any previously cached cluster.
|
|
439
|
+
*/
|
|
440
|
+
generate(coordinate: string): MapData;
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Advance the cached cluster's settle sim to `targetTick` (in
|
|
444
|
+
* `1..=499`) and return a decoded snapshot at that tick. Call
|
|
445
|
+
* repeatedly with increasing ticks for progressive rendering. The
|
|
446
|
+
* settle runs 499 ticks total; the final call with `targetTick = 499`
|
|
447
|
+
* finalises the cluster.
|
|
448
|
+
*
|
|
449
|
+
* Throws if the cache is empty or `targetTick` is out of range.
|
|
450
|
+
*/
|
|
451
|
+
advance(targetTick: number): SettleSnapshot;
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Re-run ambient mob spawning against the cached cluster's current
|
|
455
|
+
* cell state and return the refreshed entity lists. Pairs with
|
|
456
|
+
* `advance()`. liquid/gas settling can invalidate earlier mob
|
|
457
|
+
* placements. Template-placed entities persist across calls.
|
|
458
|
+
*/
|
|
459
|
+
entities(): EntitySpawners;
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Drop the cached generated cluster. Editor settings (if mutated)
|
|
463
|
+
* are preserved.
|
|
464
|
+
*/
|
|
465
|
+
clear(): void;
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Snapshot-based settings I/O. Each entry of the `files` map keys a
|
|
469
|
+
* Klei config path (e.g.
|
|
470
|
+
* `expansion1::worldgen/clusters/CGMCluster.yaml`) to that file's
|
|
471
|
+
* JSON-encoded content — the same shape Klei's YAML loader produces
|
|
472
|
+
* after parsing. `load*` / `merge` / `remove` calls evict the
|
|
473
|
+
* cluster cache; the next `generate()` rebuilds with the new
|
|
474
|
+
* settings.
|
|
475
|
+
*
|
|
476
|
+
* ### Stability contracts
|
|
477
|
+
*
|
|
478
|
+
* - **Canonical stringification.** `files()[path]` for an unchanged
|
|
479
|
+
* file is byte-equivalent across calls and across processes.
|
|
480
|
+
* JSON object-key order is alphabetical for `HashMap`-backed
|
|
481
|
+
* storage (the four `ComposableDict<K,V>` tables — mobs, rooms,
|
|
482
|
+
* borders, temperatures); `IndexMap`-backed fields preserve
|
|
483
|
+
* insertion order (the load order from the source bytes); struct
|
|
484
|
+
* fields use declared order. No floating-point reformatting.
|
|
485
|
+
* - **Idempotent `load(files())`.** Calling `load(files())` is a
|
|
486
|
+
* no-op against engine state; the very next `files()` returns
|
|
487
|
+
* byte-equivalent strings to the input. Verified across all 913
|
|
488
|
+
* vanilla paths.
|
|
489
|
+
* - **Deep-copy returns.** `files()` returns a fresh, freely
|
|
490
|
+
* mutable plain object (the engine `JSON.parse`s its internal
|
|
491
|
+
* string representation per call). Mutating the returned map
|
|
492
|
+
* does not affect the engine's snapshot. The `Readonly<...>`
|
|
493
|
+
* typing below is advisory: it nudges callers toward
|
|
494
|
+
* defensive-copy hygiene at the API surface even though the
|
|
495
|
+
* underlying object is yours to mutate.
|
|
496
|
+
* - **Path-set preservation.** `load(filesMap)` neither adds nor
|
|
497
|
+
* drops paths. The set of keys in the next `files()` exactly
|
|
498
|
+
* matches the keys you passed in.
|
|
499
|
+
* - **Merge collision = last-wins.** When `merge(files)` is called
|
|
500
|
+
* with a path already present in SETTINGS, the new value
|
|
501
|
+
* replaces the old one. Within a single `merge()` call the same
|
|
502
|
+
* semantics apply: later entries in the input map win over
|
|
503
|
+
* earlier ones for the same path.
|
|
504
|
+
*/
|
|
505
|
+
snapshot: {
|
|
506
|
+
/** Reset SETTINGS to the embedded vanilla baseline. Strict mode
|
|
507
|
+
* (closed parity surface — rejects mod-defined enum extensions
|
|
508
|
+
* like custom TemperatureRange values). */
|
|
509
|
+
loadVanilla(): void;
|
|
510
|
+
/** Extensions-mode `loadVanilla`. Identical bytes for the vanilla
|
|
511
|
+
* case; the difference surfaces on subsequent `merge(modFiles)`
|
|
512
|
+
* calls, where Extensions mode accepts `TemperatureRange::Custom(X)`
|
|
513
|
+
* and similar mod-defined enum extensions provided the mod also
|
|
514
|
+
* registers them in `tables.temperatures.add`. Use this when
|
|
515
|
+
* bootstrapping the slot for a mod-overlay flow (e.g. Baator's
|
|
516
|
+
* HellHot temperature, custom Tag definitions). */
|
|
517
|
+
loadVanillaExtensions(): void;
|
|
518
|
+
/** Replace SETTINGS with the `path → JSON-string` `files` map.
|
|
519
|
+
* Strict mode. The next `files()` call returns byte-equivalent
|
|
520
|
+
* strings to the input (idempotent round-trip; see contract
|
|
521
|
+
* above). */
|
|
522
|
+
load(files: Readonly<Record<string, string>>): void;
|
|
523
|
+
/** Extensions-mode counterpart of `load`. Accepts mod-defined
|
|
524
|
+
* enum extensions when the mod registers them in the
|
|
525
|
+
* corresponding `add` table. Subsequent `merge`s on the slot
|
|
526
|
+
* inherit the Extensions mode — no need to call `_extensions`
|
|
527
|
+
* variants for merges. */
|
|
528
|
+
loadExtensions(files: Readonly<Record<string, string>>): void;
|
|
529
|
+
/**
|
|
530
|
+
* Merge `files` into the active SETTINGS (last-wins on duplicate
|
|
531
|
+
* paths — both vs. existing SETTINGS and within the same input
|
|
532
|
+
* map). Auto-loads vanilla as the base if SETTINGS hasn't been
|
|
533
|
+
* initialised. Typical mod-overlay entry point.
|
|
534
|
+
*/
|
|
535
|
+
merge(files: Readonly<Record<string, string>>): void;
|
|
536
|
+
/**
|
|
537
|
+
* Return the active SETTINGS as a `path → JSON-string` files map.
|
|
538
|
+
* Auto-loads vanilla if SETTINGS hasn't been initialised.
|
|
539
|
+
*
|
|
540
|
+
* Returns a fresh deep copy each call — the engine does not share
|
|
541
|
+
* state with the returned object. Mutate it freely; it won't
|
|
542
|
+
* affect the engine. Subsequent `files()` calls re-emit from the
|
|
543
|
+
* engine state, not the previously-returned object.
|
|
544
|
+
*/
|
|
545
|
+
files(): Readonly<Record<string, string>>;
|
|
546
|
+
/**
|
|
547
|
+
* Stable hex hash of the active snapshot's canonical projection
|
|
548
|
+
* (the same projection `files()` returns). Auto-loads vanilla if
|
|
549
|
+
* SETTINGS hasn't been initialised.
|
|
550
|
+
*
|
|
551
|
+
* Contract: two snapshots with the same logical content produce
|
|
552
|
+
* the same hash regardless of HashMap/IndexMap iteration order or
|
|
553
|
+
* load history. `client.load(server.files())` followed by
|
|
554
|
+
* `client.checksum()` reproduces `server.checksum()` — that's the
|
|
555
|
+
* worker fast-path: client posts its checksum, worker fast-paths
|
|
556
|
+
* if equal instead of demanding a full `load(fullMap)`.
|
|
557
|
+
*
|
|
558
|
+
* Use to decide between `merge(delta)` (fast-path) and
|
|
559
|
+
* `load(fullMap)` (re-sync) when reconciling client + worker
|
|
560
|
+
* settings.
|
|
561
|
+
*
|
|
562
|
+
* Cached: the hash is computed once per snapshot version, on the
|
|
563
|
+
* first call after any `loadVanilla` / `load` / `merge` / `remove`
|
|
564
|
+
* / `reset`. Subsequent calls return the cached string until the
|
|
565
|
+
* next mutation. Cold recompute is ≈80 ms on the full vanilla
|
|
566
|
+
* snapshot; steady-state cache hit is a single property read.
|
|
567
|
+
*/
|
|
568
|
+
checksum(): string;
|
|
569
|
+
/**
|
|
570
|
+
* Drop `paths` from the active SETTINGS. Auto-loads vanilla as
|
|
571
|
+
* the base if SETTINGS hasn't been initialised. Paths not present
|
|
572
|
+
* in the snapshot are silently ignored.
|
|
573
|
+
*
|
|
574
|
+
* Closes the additive-only gap in `merge` — lets the worker
|
|
575
|
+
* apply a "user deleted a custom world" delta without forcing a
|
|
576
|
+
* full re-sync. Surgical: O(paths × categories) in-place drops
|
|
577
|
+
* on the engine-side snapshot, no `to_files` / `from_files`
|
|
578
|
+
* round-trip.
|
|
579
|
+
*/
|
|
580
|
+
remove(paths: readonly string[]): void;
|
|
581
|
+
/**
|
|
582
|
+
* The ONI game build this WASM was baselined against (e.g.
|
|
583
|
+
* `"737195"`). Same value as `worldgen.version()`; exposed under
|
|
584
|
+
* `snapshot` for persistence flows.
|
|
585
|
+
*
|
|
586
|
+
* Recommended use: editors persist
|
|
587
|
+
* `{snapshot: files(), schemaVersion: snapshot.schemaVersion()}`
|
|
588
|
+
* to IndexedDB / share URLs / disk. On load, compare the
|
|
589
|
+
* persisted `schemaVersion` against the current
|
|
590
|
+
* `snapshot.schemaVersion()` and warn / migrate / refuse before
|
|
591
|
+
* calling `load(snapshot)`. Without the stamp, a checkpoint from
|
|
592
|
+
* an older engine silently coerces missing or renamed fields.
|
|
593
|
+
*/
|
|
594
|
+
schemaVersion(): string;
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Drop both the editor settings and the cluster cache. Next
|
|
599
|
+
* `generate()` reloads the embedded stock settings from scratch.
|
|
600
|
+
*/
|
|
601
|
+
reset(): void;
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Evaluate a noise tree over a `width × height` 2D grid and return one
|
|
605
|
+
* scalar per cell, row-major (`y * width + x`). Values are
|
|
606
|
+
* **unnormalised** — the consumer applies any colour ramp / contrast
|
|
607
|
+
* on the JS side, avoiding a hidden contract about how a particular
|
|
608
|
+
* range maps to biomes.
|
|
609
|
+
*
|
|
610
|
+
* Pass `{ kind: "named", name }` to evaluate one of the trees in the
|
|
611
|
+
* live SETTINGS' noise map (sourced from `worldgen/noise/*.yaml`
|
|
612
|
+
* — preview reflects pending edits made via `snapshot.merge` /
|
|
613
|
+
* `snapshot.load` without re-running cluster generation). Pass
|
|
614
|
+
* `{ kind: "inline", yaml }` to evaluate a YAML document parsed in
|
|
615
|
+
* isolation, useful for previewing edits that haven't been merged
|
|
616
|
+
* back into the active SETTINGS yet.
|
|
617
|
+
*
|
|
618
|
+
* Sample coords map `width × height` linearly onto the tree's
|
|
619
|
+
* `settings.lowerBound..upperBound` rectangle (cell-centred), so the
|
|
620
|
+
* preview honours the editor's `SampleSettings.zoom` / bounds.
|
|
621
|
+
*
|
|
622
|
+
* Throws if the named tree doesn't exist, the inline YAML fails to
|
|
623
|
+
* parse, or the tree has no terminator link.
|
|
624
|
+
*/
|
|
625
|
+
evaluateNoise(
|
|
626
|
+
tree: NoiseTreeRef,
|
|
627
|
+
width: number,
|
|
628
|
+
height: number,
|
|
629
|
+
seed: number,
|
|
630
|
+
): Float32Array;
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Enumerate every noise-node variant the engine recognises plus its
|
|
634
|
+
* param schema. Drives the editor's "Add node" palette + per-node
|
|
635
|
+
* form generation in worldgen-editor; without this, the editor would
|
|
636
|
+
* hard-code the node list and drift from the engine whenever a new
|
|
637
|
+
* generator is added.
|
|
638
|
+
*
|
|
639
|
+
* The list is static across the lifetime of the build — call once
|
|
640
|
+
* and cache the result.
|
|
641
|
+
*/
|
|
642
|
+
noiseNodeKinds(): NoiseNodeKindSpec[];
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* The ONI game build this WASM was parity-baselined against (e.g.
|
|
646
|
+
* `"737195"`).
|
|
647
|
+
*/
|
|
648
|
+
version(): string;
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
/** Discriminated union accepted by `worldgen.evaluateNoise`. */
|
|
652
|
+
export type NoiseTreeRef =
|
|
653
|
+
/** Look up `name` in the active SETTINGS' noise map (sourced from
|
|
654
|
+
* `worldgen/noise/*.yaml`). */
|
|
655
|
+
| { kind: "named"; name: string }
|
|
656
|
+
/** Parse the YAML document in isolation. */
|
|
657
|
+
| { kind: "inline"; yaml: string };
|
|
658
|
+
|
|
659
|
+
/** One entry returned by `worldgen.noiseNodeKinds()`. */
|
|
660
|
+
export interface NoiseNodeKindSpec {
|
|
661
|
+
/** Which `NoiseTree.<category>s` map this node variant lives in. */
|
|
662
|
+
category: "primitive" | "filter" | "modifier" | "transformer" | "selector" | "combiner";
|
|
663
|
+
/** Discriminator value (e.g. `"ImprovedPerlin"`, `"SumFractal"`, `"Add"`). */
|
|
664
|
+
kind: string;
|
|
665
|
+
/** Number of input links this node consumes. `0` for primitives. */
|
|
666
|
+
sources: number;
|
|
667
|
+
/** Param-form schema. Field names match the YAML field on the corresponding struct. */
|
|
668
|
+
params: NoiseNodeParam[];
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/** One field in a `NoiseNodeKindSpec.params` array. */
|
|
672
|
+
export interface NoiseNodeParam {
|
|
673
|
+
/** YAML field name (e.g. `"frequency"`, `"modifyType"`). */
|
|
674
|
+
name: string;
|
|
675
|
+
/** Scalar type the editor should render. */
|
|
676
|
+
type: "f32" | "i32" | "bool" | "enum" | "vec2" | "vec3" | "string";
|
|
677
|
+
/** Default value matching the corresponding struct's `Default` impl. */
|
|
678
|
+
default: number | string | boolean | { X: number; Y: number } | { X: number; Y: number; Z: number };
|
|
679
|
+
/** When `type === "enum"`, the allowed string values. */
|
|
680
|
+
enumValues?: string[];
|
|
681
|
+
}
|
|
682
|
+
|