@bitmagic/world-forger 0.1.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/dist/artifact-types.d.ts +295 -0
- package/dist/artifact-types.d.ts.map +1 -0
- package/dist/artifact-types.js +17 -0
- package/dist/artifact-types.js.map +1 -0
- package/dist/forge-constants.d.ts +106 -0
- package/dist/forge-constants.d.ts.map +1 -0
- package/dist/forge-constants.js +111 -0
- package/dist/forge-constants.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +26 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +14 -0
- package/dist/log.js.map +1 -0
- package/dist/pipeline/archetype-skips.d.ts +57 -0
- package/dist/pipeline/archetype-skips.d.ts.map +1 -0
- package/dist/pipeline/archetype-skips.js +51 -0
- package/dist/pipeline/archetype-skips.js.map +1 -0
- package/dist/pipeline/artifact-store.d.ts +4 -0
- package/dist/pipeline/artifact-store.d.ts.map +1 -0
- package/dist/pipeline/artifact-store.js +10 -0
- package/dist/pipeline/artifact-store.js.map +1 -0
- package/dist/pipeline/asset-catalog.d.ts +27 -0
- package/dist/pipeline/asset-catalog.d.ts.map +1 -0
- package/dist/pipeline/asset-catalog.js +47 -0
- package/dist/pipeline/asset-catalog.js.map +1 -0
- package/dist/pipeline/create-level-archetypes.d.ts +45 -0
- package/dist/pipeline/create-level-archetypes.d.ts.map +1 -0
- package/dist/pipeline/create-level-archetypes.js +197 -0
- package/dist/pipeline/create-level-archetypes.js.map +1 -0
- package/dist/pipeline/deps.d.ts +72 -0
- package/dist/pipeline/deps.d.ts.map +1 -0
- package/dist/pipeline/deps.js +2 -0
- package/dist/pipeline/deps.js.map +1 -0
- package/dist/pipeline/errors.d.ts +10 -0
- package/dist/pipeline/errors.d.ts.map +1 -0
- package/dist/pipeline/errors.js +13 -0
- package/dist/pipeline/errors.js.map +1 -0
- package/dist/pipeline/forged-work-store.d.ts +46 -0
- package/dist/pipeline/forged-work-store.d.ts.map +1 -0
- package/dist/pipeline/forged-work-store.js +69 -0
- package/dist/pipeline/forged-work-store.js.map +1 -0
- package/dist/pipeline/index.d.ts +36 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +36 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/job-types.d.ts +145 -0
- package/dist/pipeline/job-types.d.ts.map +1 -0
- package/dist/pipeline/job-types.js +2 -0
- package/dist/pipeline/job-types.js.map +1 -0
- package/dist/pipeline/level-registry.d.ts +57 -0
- package/dist/pipeline/level-registry.d.ts.map +1 -0
- package/dist/pipeline/level-registry.js +108 -0
- package/dist/pipeline/level-registry.js.map +1 -0
- package/dist/pipeline/model-types.d.ts +51 -0
- package/dist/pipeline/model-types.d.ts.map +1 -0
- package/dist/pipeline/model-types.js +2 -0
- package/dist/pipeline/model-types.js.map +1 -0
- package/dist/pipeline/persist-level.d.ts +82 -0
- package/dist/pipeline/persist-level.d.ts.map +1 -0
- package/dist/pipeline/persist-level.js +201 -0
- package/dist/pipeline/persist-level.js.map +1 -0
- package/dist/pipeline/place-and-persist-level.d.ts +83 -0
- package/dist/pipeline/place-and-persist-level.d.ts.map +1 -0
- package/dist/pipeline/place-and-persist-level.js +405 -0
- package/dist/pipeline/place-and-persist-level.js.map +1 -0
- package/dist/pipeline/request-id.d.ts +7 -0
- package/dist/pipeline/request-id.d.ts.map +1 -0
- package/dist/pipeline/request-id.js +10 -0
- package/dist/pipeline/request-id.js.map +1 -0
- package/dist/pipeline/spawn-points.d.ts +47 -0
- package/dist/pipeline/spawn-points.d.ts.map +1 -0
- package/dist/pipeline/spawn-points.js +100 -0
- package/dist/pipeline/spawn-points.js.map +1 -0
- package/dist/pipeline/starter-scatter.d.ts +34 -0
- package/dist/pipeline/starter-scatter.d.ts.map +1 -0
- package/dist/pipeline/starter-scatter.js +49 -0
- package/dist/pipeline/starter-scatter.js.map +1 -0
- package/dist/pipeline/storage-types.d.ts +48 -0
- package/dist/pipeline/storage-types.d.ts.map +1 -0
- package/dist/pipeline/storage-types.js +19 -0
- package/dist/pipeline/storage-types.js.map +1 -0
- package/dist/pipeline/transport-types.d.ts +35 -0
- package/dist/pipeline/transport-types.d.ts.map +1 -0
- package/dist/pipeline/transport-types.js +2 -0
- package/dist/pipeline/transport-types.js.map +1 -0
- package/dist/pipeline/voxelize-level.d.ts +24 -0
- package/dist/pipeline/voxelize-level.d.ts.map +1 -0
- package/dist/pipeline/voxelize-level.js +63 -0
- package/dist/pipeline/voxelize-level.js.map +1 -0
- package/dist/pipeline/world-json-source.d.ts +78 -0
- package/dist/pipeline/world-json-source.d.ts.map +1 -0
- package/dist/pipeline/world-json-source.js +2 -0
- package/dist/pipeline/world-json-source.js.map +1 -0
- package/dist/pipeline/world-json-types.d.ts +104 -0
- package/dist/pipeline/world-json-types.d.ts.map +1 -0
- package/dist/pipeline/world-json-types.js +15 -0
- package/dist/pipeline/world-json-types.js.map +1 -0
- package/dist/terrain-height-grid.d.ts +45 -0
- package/dist/terrain-height-grid.d.ts.map +1 -0
- package/dist/terrain-height-grid.js +50 -0
- package/dist/terrain-height-grid.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { requireArtifact } from './artifact-store.js';
|
|
2
|
+
import { forgeRequestId } from './request-id.js';
|
|
3
|
+
import { isCladdingModule, isSkippedArchetype, moduleOverBudgetNote, skipNote, structuralSkipNote, } from './archetype-skips.js';
|
|
4
|
+
import { buildLevelPersistModifications } from './persist-level.js';
|
|
5
|
+
import { buildSpawnPointEntries } from './spawn-points.js';
|
|
6
|
+
import { planStarterScatterRemoval } from './starter-scatter.js';
|
|
7
|
+
import { ASSET_LOD0_VOXEL_BUDGET, SPAWN_CLEARANCE_M, WATER_SURFACE_Y } from '../forge-constants.js';
|
|
8
|
+
/** Instance placements per BATCH_PLACE_VOXEL_OBJECTS message. */
|
|
9
|
+
const PLACEMENT_BATCH_SIZE = 200;
|
|
10
|
+
const PLACEMENT_TIMEOUT_MS = 2 * 60 * 1000;
|
|
11
|
+
/** `skippedNames` are archetypes that never baked — they are not in the world, so
|
|
12
|
+
* listing them here would contradict the note that says they were dropped. */
|
|
13
|
+
function describeForge(forge, skippedNames) {
|
|
14
|
+
const objectLines = forge.objectSummaries
|
|
15
|
+
.filter((o) => !skippedNames.has(o.name))
|
|
16
|
+
.map((o) => {
|
|
17
|
+
const detail = o.kind === 'level'
|
|
18
|
+
? `collider=${o.collider}${o.smooth ? ', smooth surface' : ''}`
|
|
19
|
+
: `library asset, ${o.instances} instance${o.instances === 1 ? '' : 's'}${o.collider === 'none' ? ', decoration' : ''}`;
|
|
20
|
+
return ` - ${o.name} (${o.kind}): ${o.triangles.toLocaleString()} tris, ${detail}`;
|
|
21
|
+
})
|
|
22
|
+
.join('\n');
|
|
23
|
+
const markerLines = forge.markers.length > 0
|
|
24
|
+
? `\nMarkers (world coordinates for game logic):\n${forge.markers
|
|
25
|
+
.map((m) => ` - ${m.name}: (${m.world.x.toFixed(1)}, ${m.world.y.toFixed(1)}, ${m.world.z.toFixed(1)})`)
|
|
26
|
+
.join('\n')}`
|
|
27
|
+
: '';
|
|
28
|
+
return `Objects:\n${objectLines}${markerLines}`;
|
|
29
|
+
}
|
|
30
|
+
/** Place all instances via the engine's batch-place path, in chunks. */
|
|
31
|
+
async function placeInstances(deps, placements) {
|
|
32
|
+
const placedInstances = [];
|
|
33
|
+
for (let i = 0; i < placements.length; i += PLACEMENT_BATCH_SIZE) {
|
|
34
|
+
const batch = placements.slice(i, i + PLACEMENT_BATCH_SIZE);
|
|
35
|
+
const requestId = forgeRequestId('place');
|
|
36
|
+
const result = await deps.transport.sendAndWait({
|
|
37
|
+
type: 'BATCH_PLACE_VOXEL_OBJECTS',
|
|
38
|
+
requestId,
|
|
39
|
+
objects: batch.map((p) => ({
|
|
40
|
+
asset_name: p.archetype,
|
|
41
|
+
position: p.position,
|
|
42
|
+
rotation: { x: 0, y: p.rotationYDeg, z: 0 },
|
|
43
|
+
scale: { x: p.scale, y: p.scale, z: p.scale },
|
|
44
|
+
// The forge computed exact world-space ground heights on the NEW
|
|
45
|
+
// terrain; a placement raycast would hit the OLD terrain (the new
|
|
46
|
+
// level loads only after the session's reload).
|
|
47
|
+
force_position: true,
|
|
48
|
+
...(p.collision ? {} : { collision: false }),
|
|
49
|
+
// Loose props (wrecks, barrels): individual dynamic bodies that settle
|
|
50
|
+
// under gravity and sleep — not batched static instances. An authored
|
|
51
|
+
// mass beats the engine's bounding-box estimate.
|
|
52
|
+
...(p.dynamic ? { dynamic: true } : {}),
|
|
53
|
+
...(p.dynamic && p.mass !== undefined ? { mass: p.mass } : {}),
|
|
54
|
+
})),
|
|
55
|
+
}, 'BATCH_VOXEL_OBJECTS_PLACED', PLACEMENT_TIMEOUT_MS);
|
|
56
|
+
if (!result || !Array.isArray(result.results)) {
|
|
57
|
+
throw new Error(`Placing instances ${i + 1}-${i + batch.length} failed or timed out`);
|
|
58
|
+
}
|
|
59
|
+
const instances = result.instances;
|
|
60
|
+
if (instances)
|
|
61
|
+
placedInstances.push(...instances);
|
|
62
|
+
deps.logger.info({ from: i + 1, to: i + batch.length, placed: result.results.length }, 'Instance batch placed');
|
|
63
|
+
}
|
|
64
|
+
return placedInstances;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Reconcile placed instances against the assets actually being written, so a dangling `assetId`
|
|
68
|
+
* can never make the strict validator discard the WHOLE level at session cleanup (which surfaces
|
|
69
|
+
* as a reported "success" over an empty world). An instance whose `assetId` is not among the
|
|
70
|
+
* written assets is recovered by archetype name (carried on the instance's `type`) when a
|
|
71
|
+
* same-named asset exists; otherwise it is dropped. Pure + exported for unit testing.
|
|
72
|
+
*/
|
|
73
|
+
export function reconcileInstancesToAssets(placedInstances, writableAssetIds, assetIdByName) {
|
|
74
|
+
let remapped = 0;
|
|
75
|
+
let dropped = 0;
|
|
76
|
+
const instances = placedInstances.flatMap((instance) => {
|
|
77
|
+
const assetId = String(instance.assetId ?? '');
|
|
78
|
+
// No asset reference at all → not a dangling ref; leave it untouched.
|
|
79
|
+
if (!assetId || writableAssetIds.has(assetId))
|
|
80
|
+
return [instance];
|
|
81
|
+
const byName = assetIdByName.get(String(instance.type ?? ''));
|
|
82
|
+
if (byName) {
|
|
83
|
+
remapped++;
|
|
84
|
+
return [{ ...instance, assetId: byName }];
|
|
85
|
+
}
|
|
86
|
+
dropped++;
|
|
87
|
+
return [];
|
|
88
|
+
});
|
|
89
|
+
return { instances, remapped, dropped };
|
|
90
|
+
}
|
|
91
|
+
// ---- Dungeon atmosphere -------------------------------------------------------------
|
|
92
|
+
/** Fog starts this close and is opaque by `FAR` — a corridor you cannot see the end of. */
|
|
93
|
+
const DUNGEON_FOG_NEAR_M = 6;
|
|
94
|
+
const DUNGEON_FOG_FAR_M = 55;
|
|
95
|
+
/** Fog is the primary wall colour darkened this far: the room's own stone, receding. */
|
|
96
|
+
const DUNGEON_FOG_DARKEN = 0.35;
|
|
97
|
+
/** Multipliers on the engine's daylight defaults (see `LightingConfig`): near-zero sun,
|
|
98
|
+
* a trace of sky-derived ambient, a dim skybox — the fixture lights do the lighting. */
|
|
99
|
+
const DUNGEON_SUN_INTENSITY = 0.03;
|
|
100
|
+
/**
|
|
101
|
+
* Sky-derived ambient. `LightingConfig` documents 0.02–0.15 for dark interiors;
|
|
102
|
+
* a dungeon sits in the UPPER half of that band. At 0.08 the walls read (they
|
|
103
|
+
* catch the fixtures' direct light) but the floors — lit only by the ambient
|
|
104
|
+
* term, since a wall torch's cone barely reaches them — rendered near-black in
|
|
105
|
+
* both verified forges. Going lower is not "moodier", it is unreadable.
|
|
106
|
+
*/
|
|
107
|
+
const DUNGEON_ENVIRONMENT_INTENSITY = 0.13;
|
|
108
|
+
const DUNGEON_SKYBOX_INTENSITY = 0.1;
|
|
109
|
+
function darkenHex(hex, factor) {
|
|
110
|
+
const v = parseInt(hex.slice(1), 16);
|
|
111
|
+
const channel = (shift) => Math.max(0, Math.min(255, Math.round(((v >> shift) & 0xff) * factor)))
|
|
112
|
+
.toString(16)
|
|
113
|
+
.padStart(2, '0');
|
|
114
|
+
return `#${channel(16)}${channel(8)}${channel(0)}`;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The per-level atmosphere a dungeon needs to read as one: without it the
|
|
118
|
+
* engine keeps every scene at full daylight and the torch lights are invisible.
|
|
119
|
+
* Fog colour is DERIVED from the plan's own palette (the primary wall material,
|
|
120
|
+
* darkened) rather than a fixed grey, so an ice crypt and a lava mine recede
|
|
121
|
+
* into their own stone; a plan whose every material glows falls back to its
|
|
122
|
+
* first material, which still tracks the theme. Exported for testing.
|
|
123
|
+
*/
|
|
124
|
+
export function buildDungeonAtmosphere(plan) {
|
|
125
|
+
const structural = plan.materials.filter((m) => m.emissive === undefined);
|
|
126
|
+
const wall = structural.find((m) => m.role === 'wallPrimary') ?? structural[0] ?? plan.materials[0];
|
|
127
|
+
return {
|
|
128
|
+
fogConfig: {
|
|
129
|
+
enabled: true,
|
|
130
|
+
color: darkenHex(wall.color, DUNGEON_FOG_DARKEN),
|
|
131
|
+
near: DUNGEON_FOG_NEAR_M,
|
|
132
|
+
far: DUNGEON_FOG_FAR_M,
|
|
133
|
+
},
|
|
134
|
+
lightingConfig: {
|
|
135
|
+
sunIntensity: DUNGEON_SUN_INTENSITY,
|
|
136
|
+
environmentIntensity: DUNGEON_ENVIRONMENT_INTENSITY,
|
|
137
|
+
skyboxIntensity: DUNGEON_SKYBOX_INTENSITY,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Place the archetype instances and build the world.json modifications that
|
|
143
|
+
* install the level (level asset record, archetype assets, instances, level
|
|
144
|
+
* URL, spawn). The host applies what this returns.
|
|
145
|
+
*/
|
|
146
|
+
export async function placeAndPersistLevel(store, deps) {
|
|
147
|
+
const input = await requireArtifact(store, 'input');
|
|
148
|
+
const forge = await requireArtifact(store, 'forge');
|
|
149
|
+
const archetypeAssets = await requireArtifact(store, 'archetype-assets');
|
|
150
|
+
const bake = await requireArtifact(store, 'level-bake');
|
|
151
|
+
// Skip markers — failed or GLB-less archetypes, structural modules included —
|
|
152
|
+
// have no asset for their instances to reference. Drop those placements before
|
|
153
|
+
// asking the browser to place them.
|
|
154
|
+
const skippedNames = new Set(archetypeAssets.filter(isSkippedArchetype).map((s) => s.name));
|
|
155
|
+
const placements = skippedNames.size === 0
|
|
156
|
+
? forge.placements
|
|
157
|
+
: forge.placements.filter((p) => !skippedNames.has(p.archetype));
|
|
158
|
+
if (skippedNames.size > 0) {
|
|
159
|
+
deps.logger.warn({ jobId: store.jobId, skipped: [...skippedNames], droppedPlacements: forge.placements.length - placements.length }, 'Archetypes skipped at bake time — their instances are dropped, the level keeps everything else');
|
|
160
|
+
}
|
|
161
|
+
// Place the archetype instances from the library (exact world-space transforms).
|
|
162
|
+
const placedInstances = await placeInstances(deps, placements);
|
|
163
|
+
const movement = await store.get('platformer-movement');
|
|
164
|
+
const persistedAsset = {
|
|
165
|
+
...bake.bakedRecord,
|
|
166
|
+
id: input.assetId ?? bake.bakedRecord.id,
|
|
167
|
+
name: input.name,
|
|
168
|
+
sourceGlbUrl: forge.glbUrl,
|
|
169
|
+
prompt: input.prompt,
|
|
170
|
+
// The user's request in their own words — the `prompt` above is the
|
|
171
|
+
// orchestrator's paraphrase. Kept on the record so later agents (and
|
|
172
|
+
// re-forges) can check the level against what the user actually asked for.
|
|
173
|
+
...(input.originalUserPrompt ? { worldForgerUserPrompt: input.originalUserPrompt } : {}),
|
|
174
|
+
// The validated scene spec — kept on the record so the level can be
|
|
175
|
+
// re-forged/edited later without re-designing from scratch.
|
|
176
|
+
worldForgerSpec: forge.spec,
|
|
177
|
+
// World-space gameplay anchors (spawn + named markers).
|
|
178
|
+
worldForgerMarkers: {
|
|
179
|
+
playerStart: forge.playerStart.world,
|
|
180
|
+
named: forge.markers.map((m) => ({ name: m.name, ...m.world })),
|
|
181
|
+
},
|
|
182
|
+
// Declared runtime behaviors (ski lifts, elevators, doors) with world-resolved anchors.
|
|
183
|
+
// For a platformer journey this also carries the spine + gate + collectibleSpawns/npcSpawns
|
|
184
|
+
// features (kind-tagged) whose world-resolved points + params drive runtime placement.
|
|
185
|
+
worldForgerFeatures: forge.gameplayFeatures,
|
|
186
|
+
// Platformer movement contract (absent for ski/race/city): the kit the level is guaranteed
|
|
187
|
+
// completable with. The coding agent MUST configure the character to `effective`.
|
|
188
|
+
...(movement ? { worldForgerMovement: movement } : {}),
|
|
189
|
+
};
|
|
190
|
+
// Outdoors the player is dropped onto the surface from SPAWN_CLEARANCE_M up
|
|
191
|
+
// so the capsule falls onto it. A dungeon instead authors the spawn AT the
|
|
192
|
+
// entrance cell's true floor Y (clearance 0, see dressing.ts "FLOOR TRUTH")
|
|
193
|
+
// — the engine seats the capsule on the floor beneath a configured interior
|
|
194
|
+
// spawn itself (a bounded downward search), so lifting it first would only
|
|
195
|
+
// place it above the floor.
|
|
196
|
+
const clearanceM = forge.spec.dungeon ? 0 : SPAWN_CLEARANCE_M;
|
|
197
|
+
const spawn = {
|
|
198
|
+
x: forge.playerStart.world.x,
|
|
199
|
+
y: forge.playerStart.world.y + clearanceM,
|
|
200
|
+
z: forge.playerStart.world.z,
|
|
201
|
+
};
|
|
202
|
+
// Unified typed spawn points: player_0 = the canonical start (PlayerLoader), all
|
|
203
|
+
// player entries = multiplayer spread (spaced along the designed route), npc entries
|
|
204
|
+
// = the plan's designed encounters for the coding agent to realize.
|
|
205
|
+
const spawnPoints = buildSpawnPointEntries({
|
|
206
|
+
playerStart: forge.playerStart.world,
|
|
207
|
+
clearanceM,
|
|
208
|
+
playerStartYaw: forge.playerStartYaw,
|
|
209
|
+
features: forge.gameplayFeatures,
|
|
210
|
+
});
|
|
211
|
+
// Guarantee referential integrity BEFORE persisting: every placed instance must reference an
|
|
212
|
+
// asset we are about to write, or the strict validator rejects the ENTIRE world.json at session
|
|
213
|
+
// cleanup and the level silently never lands (reported "success", empty world). Divergence happens
|
|
214
|
+
// when an archetype gets voxelized more than once and the two bakes get different browser-minted
|
|
215
|
+
// ids — e.g. a slow CREATE_ASSET_FROM_GLB_URL that retries, or a stale same-named asset left in the
|
|
216
|
+
// editor by a prior failed run: the browser resolves the placement's name to one id while
|
|
217
|
+
// `archetype-assets` recorded the other. The instance's `type` is the archetype name, so recover the
|
|
218
|
+
// correct id by name where we can; drop only the truly orphaned. Losing a few props beats discarding
|
|
219
|
+
// the whole city.
|
|
220
|
+
// A partial-failure resume (e.g. a GCS 429 dropping an archetype-progress write) can leave a hole
|
|
221
|
+
// in the ordered archetype-assets array — guard so we never write an undefined asset either.
|
|
222
|
+
// A dungeon's light fixtures EMIT: the archetype's asset record carries the
|
|
223
|
+
// `light` payload EnvironmentLightSystem reads, so every placed instance
|
|
224
|
+
// becomes a torch/brazier/crystal without a per-instance light entry.
|
|
225
|
+
// A skip marker is a placeholder, not an asset record — it holds its archetype's index
|
|
226
|
+
// so the ordered array stays aligned, and must never reach world.json.
|
|
227
|
+
const lightConfigs = forge.dungeonLightConfigs ?? {};
|
|
228
|
+
const validArchetypeAssets = archetypeAssets
|
|
229
|
+
.filter((a) => !!a && !isSkippedArchetype(a))
|
|
230
|
+
.map((a) => {
|
|
231
|
+
const light = lightConfigs[String(a.name ?? '')];
|
|
232
|
+
return light === undefined ? a : { ...a, light };
|
|
233
|
+
});
|
|
234
|
+
const writableAssetIds = new Set([
|
|
235
|
+
String(persistedAsset.id),
|
|
236
|
+
...validArchetypeAssets.map((a) => String(a.id)),
|
|
237
|
+
]);
|
|
238
|
+
const assetIdByName = new Map(validArchetypeAssets.map((a) => [String(a.name ?? ''), String(a.id)]));
|
|
239
|
+
// Dungeon doors and key pickups reference a BAKED archetype for their visual:
|
|
240
|
+
// one leaf model per animation style (`DoorLeaf_hinge`…), one shard per key.
|
|
241
|
+
// Without the id the engine falls back to a box mesh, so the ids are injected
|
|
242
|
+
// here — this is the first point where both the defs and the baked asset ids
|
|
243
|
+
// exist. `levelId` is injected by the persist builder.
|
|
244
|
+
const dungeonDoors = (forge.dungeonDoors ?? []).map((d) => {
|
|
245
|
+
const assetId = assetIdByName.get(`DoorLeaf_${d.animation}`);
|
|
246
|
+
return { ...d, ...(assetId ? { assetId } : {}) };
|
|
247
|
+
});
|
|
248
|
+
const dungeonKeyItems = (forge.dungeonKeyItems ?? []).map((k) => {
|
|
249
|
+
const assetId = assetIdByName.get(`KeyItem_${k.keyId}`);
|
|
250
|
+
return { ...k, ...(assetId ? { assetId } : {}) };
|
|
251
|
+
});
|
|
252
|
+
const { instances: reconciledInstances, remapped: remappedInstances, dropped: droppedInstances } = reconcileInstancesToAssets(placedInstances, writableAssetIds, assetIdByName);
|
|
253
|
+
if (remappedInstances || droppedInstances) {
|
|
254
|
+
deps.logger.warn({ jobId: store.jobId, remappedInstances, droppedInstances, placed: placedInstances.length }, 'Reconciled forged instances against written assets — dangling assetId refs would otherwise fail validation and discard the whole level');
|
|
255
|
+
}
|
|
256
|
+
// The forged level REPLACES the template's terrain, so the starter template's scattered
|
|
257
|
+
// trees/rocks are now orphans: `placeOnTerrain` re-snaps them onto the forged surface off in
|
|
258
|
+
// the origin corner, and their six library assets can't be removed in the creator while an
|
|
259
|
+
// instance still references them. Strip both — but only the untouched starter scatter, never
|
|
260
|
+
// anything the AI placed from those assets. Prepended to the write below so the removals land
|
|
261
|
+
// before the level's own upserts.
|
|
262
|
+
const starterScatter = planStarterScatterRemoval(await deps.worldJson.readForStarterScatterPlan());
|
|
263
|
+
if (starterScatter.objectIds.length > 0 || starterScatter.assetIds.length > 0) {
|
|
264
|
+
deps.logger.info({ jobId: store.jobId, objects: starterScatter.objectIds.length, assets: starterScatter.assetIds.length }, 'Stripping starter-template trees/rocks left behind by the discarded template level');
|
|
265
|
+
}
|
|
266
|
+
const removedObjectIds = new Set(starterScatter.objectIds);
|
|
267
|
+
const removedAssetIds = new Set(starterScatter.assetIds);
|
|
268
|
+
const starterScatterRemovals = [
|
|
269
|
+
...(removedObjectIds.size > 0
|
|
270
|
+
? [{
|
|
271
|
+
type: 'removeRoot',
|
|
272
|
+
path: ['environmentObjects'],
|
|
273
|
+
predicate: (o) => removedObjectIds.has(String(o.id ?? '')),
|
|
274
|
+
}]
|
|
275
|
+
: []),
|
|
276
|
+
...(removedAssetIds.size > 0
|
|
277
|
+
? [{
|
|
278
|
+
type: 'removeRoot',
|
|
279
|
+
path: ['assets'],
|
|
280
|
+
predicate: (a) => removedAssetIds.has(String(a.id ?? '')),
|
|
281
|
+
}]
|
|
282
|
+
: []),
|
|
283
|
+
];
|
|
284
|
+
// Level-native persist (multi-level registry): the forge targets a LEVEL
|
|
285
|
+
// entry — re-forging replaces only that level's instances, the start level
|
|
286
|
+
// moves only on the game's first forge or on explicit makeStartLevel intent,
|
|
287
|
+
// legacy mirrors (voxelUrl/spawn/water — the exact pre-levels write set) are
|
|
288
|
+
// written only for the start level, reused asset records are never
|
|
289
|
+
// rewritten, and orphaned forge placeholders are purged.
|
|
290
|
+
// Coastal water rides the level's overrides; MUST be the WORLD-space value
|
|
291
|
+
// (forge.waterLevelYWorld): the bake lifts the level so its lowest point
|
|
292
|
+
// sits at world Y=0. The ?? fallback covers resumed runs whose forge
|
|
293
|
+
// artifact predates waterLevelYWorld.
|
|
294
|
+
const persistPlan = buildLevelPersistModifications({
|
|
295
|
+
existingWorldJson: await deps.worldJson.readForPersistPlan(),
|
|
296
|
+
levelAsset: persistedAsset,
|
|
297
|
+
levelName: input.name,
|
|
298
|
+
archetypeAssets: validArchetypeAssets,
|
|
299
|
+
instances: reconciledInstances,
|
|
300
|
+
spawn,
|
|
301
|
+
spawnPoints: spawnPoints,
|
|
302
|
+
playerSpawnRotationY: forge.playerStartYaw,
|
|
303
|
+
makeStartLevel: input.makeStartLevel,
|
|
304
|
+
// Two producers now: a city's water zones and a dungeon plan that floods its
|
|
305
|
+
// deepest bands. `waterLevelYWorld` already covers both; the WATER_SURFACE_Y
|
|
306
|
+
// fallback only serves resumed city artifacts that predate the field.
|
|
307
|
+
waterLevelY: forge.waterLevelYWorld
|
|
308
|
+
?? ((forge.spec.city?.zones ?? []).some((z) => z.kind === 'water') ? WATER_SURFACE_Y : null),
|
|
309
|
+
// Level-native dungeon data. A non-dungeon forge passes empty arrays, so
|
|
310
|
+
// re-forging a dungeon as plain terrain clears its stale doors/keys.
|
|
311
|
+
doors: dungeonDoors,
|
|
312
|
+
keyItems: dungeonKeyItems,
|
|
313
|
+
// A dungeon is unlit and unfogged by default — without these overrides the
|
|
314
|
+
// engine keeps the level at full daylight and the fixture lights vanish.
|
|
315
|
+
...(forge.spec.dungeon ? { levelOverrides: buildDungeonAtmosphere(forge.spec.dungeon) } : {}),
|
|
316
|
+
// The HQ regenerations in flight for this game — their placeholder assets
|
|
317
|
+
// must survive the purge. Asked for HERE, not when the host built its deps:
|
|
318
|
+
// a forge runs 30-60 minutes and a job that STARTED during it would be
|
|
319
|
+
// missing from an older snapshot, so its placeholder would be purged.
|
|
320
|
+
activeHqAssetIds: deps.hqAssetIds ? await deps.hqAssetIds() : new Set(),
|
|
321
|
+
});
|
|
322
|
+
deps.logger.info({
|
|
323
|
+
jobId: store.jobId, vwldUrl: bake.vwldUrl, spawn,
|
|
324
|
+
// Real asset count — `archetypeAssets.length` also counts skip markers, which are
|
|
325
|
+
// never written as assets (see `validArchetypeAssets` above).
|
|
326
|
+
archetypes: validArchetypeAssets.length, archetypesSkipped: skippedNames.size,
|
|
327
|
+
instances: reconciledInstances.length,
|
|
328
|
+
levelId: persistPlan.levelId, isStartLevel: persistPlan.isStartLevel,
|
|
329
|
+
purgedAssets: persistPlan.purgedAssetIds, persistNotes: persistPlan.notes,
|
|
330
|
+
}, 'Level, library assets, instances and spawn planned for world.json');
|
|
331
|
+
return {
|
|
332
|
+
summary: buildSummary(forge, bake, input, archetypeAssets),
|
|
333
|
+
modifications: [...starterScatterRemovals, ...persistPlan.modifications],
|
|
334
|
+
...(forge.terrainHeightGrid ? { terrainHeightGrid: forge.terrainHeightGrid } : {}),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
/** Assemble the rich tool summary from the forged + baked artifacts. */
|
|
338
|
+
function buildSummary(forge, bake, input, archetypeAssets) {
|
|
339
|
+
// A skipped archetype has no asset or instances and is reported as a note
|
|
340
|
+
// rather than as a library asset the caller can use.
|
|
341
|
+
const skipped = archetypeAssets.filter(isSkippedArchetype);
|
|
342
|
+
const skippedNames = new Set(skipped.map((s) => s.name));
|
|
343
|
+
const libraryAssets = forge.archetypes.flatMap((a, i) => (isSkippedArchetype(archetypeAssets[i])
|
|
344
|
+
? []
|
|
345
|
+
: [{ name: a.name, asset_id: String(archetypeAssets[i]?.id ?? ''), instances: a.instanceCount }]));
|
|
346
|
+
const featureLines = forge.gameplayFeatures.length > 0
|
|
347
|
+
? `\nGameplay features to IMPLEMENT IN CODE (the level only bakes their geometry):\n${forge.gameplayFeatures
|
|
348
|
+
.map((f) => ('widthM' in f
|
|
349
|
+
? ` - [path] ${f.name}: ${f.description} ${f.points.length} control points, `
|
|
350
|
+
+ `${f.checkpoints.length} checkpoints, start (${f.start.x.toFixed(0)},${f.start.y.toFixed(0)},${f.start.z.toFixed(0)}), `
|
|
351
|
+
+ `finish (${f.finish.x.toFixed(0)},${f.finish.y.toFixed(0)},${f.finish.z.toFixed(0)}). `
|
|
352
|
+
+ `Full data persists on the level asset record in world.json (worldForgerFeatures).`
|
|
353
|
+
: ` - [${f.kind}] ${f.name}: ${f.description} | anchors: ${f.anchors
|
|
354
|
+
.map((a) => `${a.name}(${a.x.toFixed(0)},${a.y.toFixed(0)},${a.z.toFixed(0)})`).join(', ')}`
|
|
355
|
+
// ONE line per archetype, never per instance: a level places up to ~640
|
|
356
|
+
// instances of one archetype and this string goes straight into the
|
|
357
|
+
// coding agent's prompt. The positions are already reachable — the
|
|
358
|
+
// archetype's asset id is in library_assets above, and every instance
|
|
359
|
+
// of it is in world.json environmentObjects.
|
|
360
|
+
+ (f.archetypeAnchors?.length
|
|
361
|
+
? ` | archetypes (ALL instances of each — look them up by this name in library_assets, then world.json environmentObjects): ${f.archetypeAnchors
|
|
362
|
+
.map((a) => `${a.name} x${a.instances} around (${a.centroid.x.toFixed(0)},${a.centroid.y.toFixed(0)},${a.centroid.z.toFixed(0)})`).join(', ')}`
|
|
363
|
+
: '')))
|
|
364
|
+
.join('\n')}`
|
|
365
|
+
: '';
|
|
366
|
+
// A module the bake step kept at its pinned voxel size despite overrunning its budget
|
|
367
|
+
// (see the attempt loop) is reported here rather than at bake time: `archetypeAssets` is
|
|
368
|
+
// index-aligned with `forge.archetypes` and carries the engine's own leaf count, so the
|
|
369
|
+
// note survives a resume that skipped the re-bake, exactly like the skip notes above.
|
|
370
|
+
const overBudget = forge.archetypes.flatMap((a, i) => {
|
|
371
|
+
const record = archetypeAssets[i];
|
|
372
|
+
if (!record || isSkippedArchetype(record) || !isCladdingModule(a))
|
|
373
|
+
return [];
|
|
374
|
+
const leaves = typeof record.voxelCount === 'number' ? record.voxelCount : 0;
|
|
375
|
+
const budget = a.assetVoxelOptions?.lod0Budget ?? ASSET_LOD0_VOXEL_BUDGET;
|
|
376
|
+
return leaves > budget ? [moduleOverBudgetNote(a.name, leaves, budget)] : [];
|
|
377
|
+
});
|
|
378
|
+
const allNotes = [
|
|
379
|
+
...forge.notes,
|
|
380
|
+
...skipped.map((s) => (s.structural ? structuralSkipNote(s) : skipNote(s))),
|
|
381
|
+
...overBudget,
|
|
382
|
+
...(bake.notes ?? []),
|
|
383
|
+
];
|
|
384
|
+
const noteLines = allNotes.length > 0 ? `\nNotes:\n - ${allNotes.join('\n - ')}` : '';
|
|
385
|
+
const bandLine = forge.terrainBands.length > 0
|
|
386
|
+
? `\nTerrain LOD bands: ${forge.terrainBands.map((b) => `${b.name}=+${b.lodOffset}`).join(', ')}`
|
|
387
|
+
: '';
|
|
388
|
+
return {
|
|
389
|
+
asset_id: String(input.assetId ?? bake.bakedRecord.id),
|
|
390
|
+
asset_name: input.name,
|
|
391
|
+
asset_url: bake.vwldUrl,
|
|
392
|
+
glb_url: forge.glbUrl,
|
|
393
|
+
player_start: {
|
|
394
|
+
x: forge.playerStart.world.x,
|
|
395
|
+
y: forge.playerStart.world.y,
|
|
396
|
+
z: forge.playerStart.world.z,
|
|
397
|
+
},
|
|
398
|
+
markers: forge.markers.map((m) => ({ name: m.name, x: m.world.x, y: m.world.y, z: m.world.z })),
|
|
399
|
+
library_assets: libraryAssets,
|
|
400
|
+
gameplay_features: forge.gameplayFeatures,
|
|
401
|
+
terrain_bands: forge.terrainBands,
|
|
402
|
+
message: `Generated and installed level "${forge.spec.name}" (${forge.spec.size.x}x${forge.spec.size.z}m). Player spawn moved to the designed start point. Smooth surfaces use exact trimesh physics. Props/vegetation are LIBRARY ASSETS placed as instances — any can be replaced later with a high-quality generated asset under the same name/id to upgrade all its instances.\n${describeForge(forge, skippedNames)}${featureLines}${noteLines}${bandLine}`,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
//# sourceMappingURL=place-and-persist-level.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"place-and-persist-level.js","sourceRoot":"","sources":["../../src/pipeline/place-and-persist-level.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unique transport request id for a forge step; `kind` namespaces it (omit for
|
|
3
|
+
* the level bake, whose ids predate the namespacing and are matched verbatim in
|
|
4
|
+
* saved traces).
|
|
5
|
+
*/
|
|
6
|
+
export declare function forgeRequestId(kind?: string): string;
|
|
7
|
+
//# sourceMappingURL=request-id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-id.d.ts","sourceRoot":"","sources":["../../src/pipeline/request-id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAGpD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unique transport request id for a forge step; `kind` namespaces it (omit for
|
|
3
|
+
* the level bake, whose ids predate the namespacing and are matched verbatim in
|
|
4
|
+
* saved traces).
|
|
5
|
+
*/
|
|
6
|
+
export function forgeRequestId(kind) {
|
|
7
|
+
const prefix = kind ? `${kind}-` : '';
|
|
8
|
+
return `wforge-${prefix}${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=request-id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-id.js","sourceRoot":"","sources":["../../src/pipeline/request-id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAa;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACtC,OAAO,UAAU,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACnF,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the unified `worldProfileData.spawnPoints` array for a forged level.
|
|
3
|
+
*
|
|
4
|
+
* One typed array instead of per-category ones: `player` entries are engine-
|
|
5
|
+
* consumed (first = canonical start; ALL of them feed multiplayer spread via
|
|
6
|
+
* `NetworkManager.getMultiplayerSpawnPoints`), `npc` entries carry the designed
|
|
7
|
+
* encounters (archetype/behavior in params) for game code to realize via
|
|
8
|
+
* `engine.getSpawnPoints('npc')`. The type vocabulary is open — `animal`,
|
|
9
|
+
* `vehicle`, or anything a future plan needs.
|
|
10
|
+
*/
|
|
11
|
+
import type { ResolvedFeature, ResolvedPathFeature } from '../artifact-types.js';
|
|
12
|
+
export interface SpawnPointEntry {
|
|
13
|
+
id: string;
|
|
14
|
+
type: string;
|
|
15
|
+
position: {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
z: number;
|
|
19
|
+
};
|
|
20
|
+
rotationY: number;
|
|
21
|
+
name?: string;
|
|
22
|
+
params?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
export interface BuildSpawnPointsInput {
|
|
25
|
+
/** Baked world-space player start (route floor, no clearance lift). */
|
|
26
|
+
playerStart: {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
z: number;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Y lift applied to player spawn positions (NPC points keep their floor Y).
|
|
33
|
+
* Positive outdoors (`SPAWN_CLEARANCE_M`) so the capsule drops onto the
|
|
34
|
+
* surface instead of starting embedded; ZERO for a dungeon, whose entrance
|
|
35
|
+
* Y is already the true floor — the engine seats the capsule on it directly
|
|
36
|
+
* (a bounded downward search) rather than lifting an authored point.
|
|
37
|
+
*/
|
|
38
|
+
clearanceM: number;
|
|
39
|
+
/** Spawn facing (gameplay yaw, +Z forward), or null when no path informs it. */
|
|
40
|
+
playerStartYaw: number | null;
|
|
41
|
+
/** The forge's world-resolved gameplay features (paths, npcSpawns, ...). */
|
|
42
|
+
features: Array<ResolvedFeature | ResolvedPathFeature>;
|
|
43
|
+
/** Extra multiplayer player points to place beyond the canonical start. */
|
|
44
|
+
extraPlayerPoints?: number;
|
|
45
|
+
}
|
|
46
|
+
export declare function buildSpawnPointEntries(input: BuildSpawnPointsInput): SpawnPointEntry[];
|
|
47
|
+
//# sourceMappingURL=spawn-points.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-points.d.ts","sourceRoot":"","sources":["../../src/pipeline/spawn-points.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEjF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,qBAAqB;IACpC,uEAAuE;IACvE,WAAW,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,4EAA4E;IAC5E,QAAQ,EAAE,KAAK,CAAC,eAAe,GAAG,mBAAmB,CAAC,CAAC;IACvD,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA6BD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,qBAAqB,GAAG,eAAe,EAAE,CA6EtF"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const EXTRA_PLAYER_POINTS = 3;
|
|
2
|
+
/** Arc-length spacing between successive multiplayer start points along the route. */
|
|
3
|
+
const PLAYER_SPREAD_STEP_M = 2.5;
|
|
4
|
+
/** Fallback ring radius when the level has no designed path to spread along. */
|
|
5
|
+
const PLAYER_RING_RADIUS_M = 2;
|
|
6
|
+
/** Point + forward tangent at `dist` meters (XZ arc length) along a polyline, or null past its end. */
|
|
7
|
+
function sampleAlong(points, dist) {
|
|
8
|
+
let walked = 0;
|
|
9
|
+
for (let i = 0; i + 1 < points.length; i++) {
|
|
10
|
+
const a = points[i];
|
|
11
|
+
const b = points[i + 1];
|
|
12
|
+
const seg = Math.hypot(b.x - a.x, b.z - a.z);
|
|
13
|
+
if (seg < 1e-6)
|
|
14
|
+
continue;
|
|
15
|
+
if (walked + seg >= dist) {
|
|
16
|
+
const t = (dist - walked) / seg;
|
|
17
|
+
return {
|
|
18
|
+
at: { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t, z: a.z + (b.z - a.z) * t },
|
|
19
|
+
tangent: { x: (b.x - a.x) / seg, z: (b.z - a.z) / seg },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
walked += seg;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
export function buildSpawnPointEntries(input) {
|
|
27
|
+
const entries = [];
|
|
28
|
+
const yaw = input.playerStartYaw ?? 0;
|
|
29
|
+
const lift = (p) => ({ x: p.x, y: p.y + input.clearanceM, z: p.z });
|
|
30
|
+
// ── Player starts: the canonical one plus a multiplayer spread. ──
|
|
31
|
+
entries.push({ id: 'player_0', type: 'player', name: 'Player start', position: lift(input.playerStart), rotationY: yaw });
|
|
32
|
+
// A DESIGNED spawn set ('playerSpawns' feature — freeform arenas / battle
|
|
33
|
+
// royale) wins over the derived spread: the designer placed real positions
|
|
34
|
+
// (e.g. a ring around the arena floor), so use them verbatim. Each spawn
|
|
35
|
+
// faces the centroid of the set — inward on a ring, which is where the
|
|
36
|
+
// action is. Points within a meter of the canonical start are skipped
|
|
37
|
+
// (player_0 already covers them).
|
|
38
|
+
const designed = input.features.find((f) => f.kind === 'playerSpawns' && f.points.length > 0);
|
|
39
|
+
let designedCount = 0;
|
|
40
|
+
if (designed) {
|
|
41
|
+
const cx = designed.points.reduce((s, p) => s + p.x, 0) / designed.points.length;
|
|
42
|
+
const cz = designed.points.reduce((s, p) => s + p.z, 0) / designed.points.length;
|
|
43
|
+
for (const p of designed.points) {
|
|
44
|
+
if (Math.hypot(p.x - input.playerStart.x, p.z - input.playerStart.z) < 1)
|
|
45
|
+
continue;
|
|
46
|
+
const toCenter = Math.hypot(cx - p.x, cz - p.z);
|
|
47
|
+
designedCount++;
|
|
48
|
+
entries.push({
|
|
49
|
+
id: `player_${designedCount}`, type: 'player', position: lift(p),
|
|
50
|
+
rotationY: toCenter > 0.5 ? Math.atan2(cx - p.x, cz - p.z) : yaw,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (designedCount === 0) {
|
|
55
|
+
const extras = input.extraPlayerPoints ?? EXTRA_PLAYER_POINTS;
|
|
56
|
+
// Spread along the designed route when one exists (its floor y is baked, so the
|
|
57
|
+
// points are guaranteed standable); the path nearest the start is the primary one.
|
|
58
|
+
const paths = input.features.filter((f) => f.kind === 'path' && f.points.length >= 2);
|
|
59
|
+
const primary = paths.sort((a, b) => Math.hypot(a.points[0].x - input.playerStart.x, a.points[0].z - input.playerStart.z)
|
|
60
|
+
- Math.hypot(b.points[0].x - input.playerStart.x, b.points[0].z - input.playerStart.z))[0];
|
|
61
|
+
for (let i = 1; i <= extras; i++) {
|
|
62
|
+
let entry = null;
|
|
63
|
+
const sampled = primary ? sampleAlong(primary.points, i * PLAYER_SPREAD_STEP_M) : null;
|
|
64
|
+
if (sampled) {
|
|
65
|
+
entry = {
|
|
66
|
+
id: `player_${i}`, type: 'player', position: lift(sampled.at),
|
|
67
|
+
rotationY: Math.atan2(sampled.tangent.x, sampled.tangent.z),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// No route (or it is too short): a ring around the start on the same floor.
|
|
72
|
+
const a = yaw + (i * 2 * Math.PI) / (extras + 1);
|
|
73
|
+
entry = {
|
|
74
|
+
id: `player_${i}`, type: 'player', rotationY: yaw,
|
|
75
|
+
position: lift({
|
|
76
|
+
x: input.playerStart.x + Math.sin(a) * PLAYER_RING_RADIUS_M,
|
|
77
|
+
y: input.playerStart.y,
|
|
78
|
+
z: input.playerStart.z + Math.cos(a) * PLAYER_RING_RADIUS_M,
|
|
79
|
+
}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
entries.push(entry);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// ── Designed NPC/enemy encounters (platformer journey plans). points[i] is the
|
|
86
|
+
// world-resolved position of params.spawns[i]; carry the archetype contract along. ──
|
|
87
|
+
const npcFeature = input.features.find((f) => f.kind === 'npcSpawns');
|
|
88
|
+
if (npcFeature) {
|
|
89
|
+
const spawns = (npcFeature.params?.spawns ?? []);
|
|
90
|
+
npcFeature.points.forEach((p, i) => {
|
|
91
|
+
const s = spawns[i] ?? {};
|
|
92
|
+
entries.push({
|
|
93
|
+
id: `npc_${s.id ?? i}`, type: 'npc', name: s.id, position: { x: p.x, y: p.y, z: p.z }, rotationY: 0,
|
|
94
|
+
params: { ...(s.archetype ? { archetype: s.archetype } : {}), ...(s.behavior ? { behavior: s.behavior } : {}), ...(s.count !== undefined ? { count: s.count } : {}) },
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return entries;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=spawn-points.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-points.js","sourceRoot":"","sources":["../../src/pipeline/spawn-points.ts"],"names":[],"mappings":"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"}
|