@jgengine/core 0.11.0 → 0.13.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/CHANGELOG.md +52 -0
- package/dist/ai/populationDirector.d.ts +103 -0
- package/dist/ai/populationDirector.js +190 -0
- package/dist/ai/pursuit.d.ts +56 -0
- package/dist/ai/pursuit.js +53 -0
- package/dist/authoring.d.ts +1 -1
- package/dist/authoring.js +1 -1
- package/dist/combat/effects.d.ts +11 -4
- package/dist/combat/effects.js +24 -17
- package/dist/combat/magazine.d.ts +13 -0
- package/dist/combat/magazine.js +27 -0
- package/dist/combat/vfxPresets.d.ts +176 -0
- package/dist/combat/vfxPresets.js +74 -0
- package/dist/combat/weaponFire.d.ts +114 -0
- package/dist/combat/weaponFire.js +96 -0
- package/dist/combat.d.ts +5 -2
- package/dist/combat.js +4 -1
- package/dist/devtools/controls.d.ts +38 -0
- package/dist/devtools/controls.js +181 -0
- package/dist/devtools/devtools.d.ts +5 -197
- package/dist/devtools/devtools.js +38 -774
- package/dist/devtools/discover.d.ts +32 -0
- package/dist/devtools/discover.js +240 -0
- package/dist/devtools/fallbackSeams.d.ts +50 -0
- package/dist/devtools/fallbackSeams.js +111 -0
- package/dist/devtools/frame.d.ts +15 -0
- package/dist/devtools/frame.js +247 -0
- package/dist/devtools/logs.d.ts +15 -0
- package/dist/devtools/logs.js +86 -0
- package/dist/devtools/overrides.d.ts +16 -0
- package/dist/devtools/overrides.js +66 -0
- package/dist/devtools/types.d.ts +212 -0
- package/dist/devtools/types.js +1 -0
- package/dist/devtools/urlFlags.d.ts +22 -0
- package/dist/devtools/urlFlags.js +62 -0
- package/dist/economy/auctionBook.d.ts +122 -0
- package/dist/economy/auctionBook.js +213 -0
- package/dist/economy/priceHistory.d.ts +44 -0
- package/dist/economy/priceHistory.js +89 -0
- package/dist/economy/unlockPoints.d.ts +92 -0
- package/dist/economy/unlockPoints.js +103 -0
- package/dist/editor/commandApply.d.ts +5 -0
- package/dist/editor/commandApply.js +755 -0
- package/dist/editor/commands.d.ts +48 -3
- package/dist/editor/commands.js +40 -754
- package/dist/editor/directives.d.ts +94 -0
- package/dist/editor/directives.js +206 -0
- package/dist/editor/document.d.ts +37 -2
- package/dist/editor/document.js +422 -6
- package/dist/editor/entityCatalog.d.ts +42 -0
- package/dist/editor/entityCatalog.js +101 -0
- package/dist/editor/environment.d.ts +74 -0
- package/dist/editor/environment.js +169 -0
- package/dist/editor/index.d.ts +26 -1
- package/dist/editor/index.js +8 -1
- package/dist/editor/minimap.d.ts +31 -0
- package/dist/editor/minimap.js +73 -0
- package/dist/editor/streamer.d.ts +66 -0
- package/dist/editor/streamer.js +68 -0
- package/dist/editor/types.d.ts +143 -0
- package/dist/editor/world.d.ts +136 -0
- package/dist/editor/world.js +303 -0
- package/dist/game/breeding.d.ts +161 -0
- package/dist/game/breeding.js +181 -0
- package/dist/game/cameraConfig.d.ts +451 -0
- package/dist/game/cameraConfig.js +1 -0
- package/dist/game/clipRoles.d.ts +51 -0
- package/dist/game/clipRoles.js +142 -0
- package/dist/game/defineGame.d.ts +16 -9
- package/dist/game/defineGame.js +14 -6
- package/dist/game/defineSystem.d.ts +2 -0
- package/dist/game/defineSystem.js +2 -0
- package/dist/game/events.d.ts +28 -0
- package/dist/game/partAnimation.d.ts +78 -0
- package/dist/game/partAnimation.js +147 -0
- package/dist/game/playableGame.d.ts +72 -440
- package/dist/game/playableGame.js +1 -1
- package/dist/game/progression.d.ts +35 -0
- package/dist/game/progression.js +22 -1
- package/dist/game/quest.js +1 -3
- package/dist/game/tribe.d.ts +184 -0
- package/dist/game/tribe.js +432 -0
- package/dist/gameplay.d.ts +3 -1
- package/dist/gameplay.js +3 -1
- package/dist/inventory/encumbrance.d.ts +69 -0
- package/dist/inventory/encumbrance.js +68 -0
- package/dist/inventory/inventoryModel.d.ts +24 -8
- package/dist/inventory/inventoryModel.js +47 -8
- package/dist/item/durability.js +1 -3
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +48 -1
- package/dist/movement/movementModel.d.ts +15 -1
- package/dist/movement/movementModel.js +33 -15
- package/dist/movement/playerMovement.js +102 -2
- package/dist/multiplayer/combatSnapshot.js +13 -8
- package/dist/multiplayer/presenceModel.d.ts +2 -0
- package/dist/multiplayer/presenceModel.js +8 -0
- package/dist/physics/drivableVehicle.d.ts +2 -0
- package/dist/physics/drivableVehicle.js +1 -1
- package/dist/physics/flightDynamics.d.ts +82 -0
- package/dist/physics/flightDynamics.js +165 -0
- package/dist/physics/gravityField.d.ts +25 -0
- package/dist/physics/gravityField.js +41 -0
- package/dist/physics/kinematicVehicle.d.ts +87 -0
- package/dist/physics/kinematicVehicle.js +193 -11
- package/dist/physics/physicsWorld.d.ts +26 -0
- package/dist/physics/physicsWorld.js +109 -117
- package/dist/physics/vehicleObstacles.d.ts +44 -0
- package/dist/physics/vehicleObstacles.js +115 -0
- package/dist/random/rng.d.ts +4 -1
- package/dist/random/rng.js +4 -1
- package/dist/runtime/adapter.d.ts +13 -0
- package/dist/runtime/adapter.js +13 -0
- package/dist/runtime/context/combat.d.ts +51 -0
- package/dist/runtime/context/combat.js +131 -0
- package/dist/runtime/context/combatFx.js +15 -5
- package/dist/runtime/context/deathLoot.d.ts +30 -0
- package/dist/runtime/context/deathLoot.js +39 -0
- package/dist/runtime/context/player.d.ts +48 -0
- package/dist/runtime/context/player.js +125 -0
- package/dist/runtime/context/scene.d.ts +60 -0
- package/dist/runtime/context/scene.js +329 -0
- package/dist/runtime/context/snapshotCodecs.d.ts +12 -0
- package/dist/runtime/context/snapshotCodecs.js +26 -0
- package/dist/runtime/descriptors/baseline.js +26 -3
- package/dist/runtime/descriptors/features.d.ts +5 -0
- package/dist/runtime/descriptors/features.js +20 -2
- package/dist/runtime/gameContext.d.ts +2 -428
- package/dist/runtime/gameContext.js +133 -500
- package/dist/runtime/gameContextTypes.d.ts +500 -0
- package/dist/runtime/gameContextTypes.js +1 -0
- package/dist/runtime/headlessRunner.d.ts +17 -2
- package/dist/runtime/headlessRunner.js +15 -0
- package/dist/runtime/hostPolicy.d.ts +51 -0
- package/dist/runtime/hostPolicy.js +68 -0
- package/dist/runtime/hostedGameRunner.d.ts +3 -1
- package/dist/runtime/hostedGameRunner.js +1 -0
- package/dist/runtime/hostedWorldSession.d.ts +3 -1
- package/dist/runtime/hostedWorldSession.js +1 -0
- package/dist/runtime/worldSnapshot.d.ts +13 -1
- package/dist/runtime/worldSnapshot.js +15 -3
- package/dist/scene/assetCatalog.d.ts +7 -0
- package/dist/scene/assetSpace.js +1 -3
- package/dist/scene/authoredTriggers.d.ts +50 -0
- package/dist/scene/authoredTriggers.js +114 -0
- package/dist/scene/builtinSceneKinds.js +8 -3
- package/dist/scene/colliders.d.ts +79 -0
- package/dist/scene/colliders.js +170 -0
- package/dist/scene/collisionMesh.d.ts +94 -0
- package/dist/scene/collisionMesh.js +699 -0
- package/dist/scene/companion.d.ts +147 -0
- package/dist/scene/companion.js +193 -0
- package/dist/scene/entityStats.d.ts +7 -9
- package/dist/scene/entityStats.js +19 -15
- package/dist/scene/sceneKinds.d.ts +16 -0
- package/dist/scene/sceneKinds.js +4 -0
- package/dist/scene/sceneRaycast.js +15 -0
- package/dist/stats/spawnLevelStats.d.ts +110 -0
- package/dist/stats/spawnLevelStats.js +140 -0
- package/dist/stats/statModifiers.d.ts +16 -0
- package/dist/stats/statModifiers.js +30 -1
- package/dist/stats/statPool.d.ts +70 -0
- package/dist/stats/statPool.js +62 -0
- package/dist/store/changeSignal.d.ts +3 -0
- package/dist/store/changeSignal.js +2 -0
- package/dist/store/observableKeyedStore.d.ts +2 -0
- package/dist/store/observableKeyedStore.js +1 -0
- package/dist/survival/decayMeter.js +1 -3
- package/dist/survival/regionHealth.js +1 -3
- package/dist/ui/hudLayout.d.ts +5 -0
- package/dist/ui/hudLayout.js +17 -1
- package/dist/ui/panelModel.d.ts +120 -0
- package/dist/ui/panelModel.js +168 -0
- package/dist/ui.d.ts +1 -0
- package/dist/ui.js +1 -0
- package/dist/world/authoredEntities.d.ts +29 -0
- package/dist/world/authoredEntities.js +29 -0
- package/dist/world/authoredObjects.d.ts +15 -1
- package/dist/world/authoredObjects.js +13 -1
- package/dist/world/authoredSpawn.d.ts +39 -0
- package/dist/world/authoredSpawn.js +37 -0
- package/dist/world/buildSockets.d.ts +152 -0
- package/dist/world/buildSockets.js +188 -0
- package/dist/world/buildingLots.d.ts +84 -0
- package/dist/world/buildingLots.js +119 -0
- package/dist/world/buildings.d.ts +6 -0
- package/dist/world/cityBlocks.d.ts +152 -0
- package/dist/world/cityBlocks.js +670 -0
- package/dist/world/cityContent.d.ts +77 -0
- package/dist/world/cityContent.js +261 -0
- package/dist/world/cityGenerator.d.ts +41 -0
- package/dist/world/cityGenerator.js +58 -0
- package/dist/world/cityGeometry.d.ts +114 -0
- package/dist/world/cityGeometry.js +573 -0
- package/dist/world/cityKind.d.ts +314 -0
- package/dist/world/cityKind.js +1578 -0
- package/dist/world/environmentSummary.js +57 -1
- package/dist/world/features.d.ts +53 -5
- package/dist/world/features.js +15 -3
- package/dist/world/grassKind.js +2 -2
- package/dist/world/markers.d.ts +50 -4
- package/dist/world/markers.js +49 -0
- package/dist/world/massing.js +1 -1
- package/dist/world/minimapBake.d.ts +78 -0
- package/dist/world/minimapBake.js +208 -0
- package/dist/world/minimapTrack.d.ts +17 -0
- package/dist/world/minimapTrack.js +22 -0
- package/dist/world/place.d.ts +166 -0
- package/dist/world/place.js +96 -0
- package/dist/world/placeAsset.js +3 -1
- package/dist/world/poleLineKind.d.ts +40 -0
- package/dist/world/poleLineKind.js +97 -0
- package/dist/world/polyline.js +9 -2
- package/dist/world/resourceNode.d.ts +109 -0
- package/dist/world/resourceNode.js +140 -0
- package/dist/world/roads.d.ts +19 -2
- package/dist/world/roads.js +60 -3
- package/dist/world/scatter.js +2 -20
- package/dist/world/streetGenerator.d.ts +159 -0
- package/dist/world/streetGenerator.js +684 -0
- package/dist/world/streets.d.ts +103 -1
- package/dist/world/streets.js +273 -0
- package/dist/world/terraform.js +58 -88
- package/dist/world/terrain.d.ts +65 -1
- package/dist/world/terrain.js +119 -2
- package/dist/world.d.ts +14 -5
- package/dist/world.js +12 -3
- package/package.json +1 -1
- package/skills/game-design/SKILL.md +28 -0
- package/skills/game-design/agents/openai.yaml +4 -0
- package/skills/game-design/references/application-playbook.md +170 -0
- package/skills/game-design/references/field-guide.md +288 -0
- package/skills/jgengine/SKILL.md +8 -4
- package/skills/jgengine/api.md +182 -81
- package/skills/jgengine/capabilities.md +104 -2
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-combat/SKILL.md +19 -1
- package/skills/jgengine-combat/api.md +75 -2
- package/skills/jgengine-combat/capabilities.md +61 -1
- package/skills/jgengine-combat/recipes/portable-damage-effects.md +197 -0
- package/skills/jgengine-combat/recipes/portable-runtime-state.md +154 -0
- package/skills/jgengine-combat/recipes/portable-stat-pools.md +122 -0
- package/skills/jgengine-combat/recipes/portable-weapon-plumbing.md +156 -0
- package/skills/jgengine-combat/recipes/visible-attacks.md +81 -0
- package/skills/jgengine-combat/reference.md +33 -4
- package/skills/jgengine-gameplay/SKILL.md +8 -0
- package/skills/jgengine-gameplay/api.md +182 -26
- package/skills/jgengine-gameplay/capabilities.md +96 -2
- package/skills/jgengine-gameplay/recipes/portable-xp-leveling.md +168 -0
- package/skills/jgengine-gameplay/reference-systems.md +10 -5
- package/skills/jgengine-world/SKILL.md +13 -0
- package/skills/jgengine-world/api.md +453 -21
- package/skills/jgengine-world/capabilities.md +112 -2
- package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
- package/skills/jgengine-world/reference.md +43 -4
- package/skills/jgengine/reference-cartridge.md +0 -72
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { Aabb, Vec2 } from "../world/geometry.js";
|
|
2
|
+
import type { EditorDirective, EditorDirectiveKind, EditorDocument, EditorPopulationDirective, EditorScatterDirective } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* The deterministic materializer for scene {@link EditorDirective}s — the bake side of the
|
|
5
|
+
* bake/patch seam in #985. A directive is one authored line ("scatter rocks across the north
|
|
6
|
+
* ridge"); this expands it into many placements with **stable per-instance ids** (`<directiveId>#
|
|
7
|
+
* <index>`) so a sparse overlay can hand-tweak or delete individual instances by id without every
|
|
8
|
+
* re-materialize orphaning those edits. Fully deterministic: same directive + seed + region ⇒ the
|
|
9
|
+
* same field, every time (safe for verify/CI). Built on the existing `scatter` primitive.
|
|
10
|
+
*/
|
|
11
|
+
/** One materialized placement from a directive — grounded XZ, deterministic scale/yaw, stable id. */
|
|
12
|
+
export interface MaterializedInstance {
|
|
13
|
+
/** Stable id `<directiveId>#<index>` — the key an overlay patches or deletes. */
|
|
14
|
+
id: string;
|
|
15
|
+
/** The directive that minted this instance. */
|
|
16
|
+
directiveId: string;
|
|
17
|
+
kind: EditorDirectiveKind;
|
|
18
|
+
/** What to place: a `scatter` directive's catalog asset, or a `population` directive's species id. */
|
|
19
|
+
asset: string;
|
|
20
|
+
x: number;
|
|
21
|
+
z: number;
|
|
22
|
+
/** Vertical offset in meters (0 unless an overlay sets it); grounding on terrain stays the caller's job. */
|
|
23
|
+
y: number;
|
|
24
|
+
rotationY: number;
|
|
25
|
+
scale: number;
|
|
26
|
+
}
|
|
27
|
+
/** A resolved directive footprint: the XZ bounds to scatter within, plus an optional clip polygon. */
|
|
28
|
+
export interface DirectiveFootprint {
|
|
29
|
+
area: Aabb;
|
|
30
|
+
polygon?: Vec2[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolves the footprint a directive fills: an explicit `area`, else the footprint of the named
|
|
34
|
+
* `region` — a scatter/closed path (as a clip polygon) or a volume (its XZ AABB). Null when neither
|
|
35
|
+
* is present or the region id does not resolve.
|
|
36
|
+
* @capability world-directives resolve a directive's region footprint from the scene document
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveDirectiveFootprint(doc: EditorDocument, directive: EditorDirective): DirectiveFootprint | null;
|
|
39
|
+
/**
|
|
40
|
+
* Materializes a scatter directive into deterministic catalog-prop placements across its footprint,
|
|
41
|
+
* clipped to the region polygon when one is present. Per-instance scale and yaw derive from the
|
|
42
|
+
* directive id + seed + point index, so ids are stable across re-materializes.
|
|
43
|
+
* @capability world-directives materialize a scatter directive into placements
|
|
44
|
+
*/
|
|
45
|
+
export declare function materializeScatterDirective(directive: EditorScatterDirective, footprint: DirectiveFootprint): MaterializedInstance[];
|
|
46
|
+
/**
|
|
47
|
+
* Materializes a population directive into deterministic mob spawn placements: at most `cap` of each
|
|
48
|
+
* weighted species, distributed across the footprint. Each placement carries a stable id and its
|
|
49
|
+
* species id in `asset`, ready to feed `ctx.scene.entity.spawn` / `ai/populationDirector`.
|
|
50
|
+
* @capability world-directives materialize a population directive into spawns
|
|
51
|
+
*/
|
|
52
|
+
export declare function materializePopulationDirective(directive: EditorPopulationDirective, footprint: DirectiveFootprint): MaterializedInstance[];
|
|
53
|
+
/**
|
|
54
|
+
* Materializes one directive against a document, resolving its footprint first. Returns an empty
|
|
55
|
+
* list when the region does not resolve.
|
|
56
|
+
* @capability world-directives materialize one scene directive into instances
|
|
57
|
+
*/
|
|
58
|
+
export declare function materializeDirective(doc: EditorDocument, directive: EditorDirective): MaterializedInstance[];
|
|
59
|
+
/** A per-instance hand-tweak over a materialized directive, keyed by the minted instance id. */
|
|
60
|
+
export interface DirectiveInstancePatch {
|
|
61
|
+
/** Override the placement's XZ position. */
|
|
62
|
+
position?: {
|
|
63
|
+
x: number;
|
|
64
|
+
z: number;
|
|
65
|
+
};
|
|
66
|
+
/** Override the vertical offset. */
|
|
67
|
+
y?: number;
|
|
68
|
+
scale?: number;
|
|
69
|
+
rotationY?: number;
|
|
70
|
+
/** Remove this instance from the materialized set. */
|
|
71
|
+
deleted?: boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A sparse overlay over one directive's materialized instances — the "nudge *that one* rock" answer.
|
|
75
|
+
* Hand-edits are keyed by the stable instance id the materializer mints, so they survive re-bakes.
|
|
76
|
+
*/
|
|
77
|
+
export interface EditorDirectiveOverlay {
|
|
78
|
+
/** The directive id whose instances this overlay patches. */
|
|
79
|
+
over: string;
|
|
80
|
+
patches: Record<string, DirectiveInstancePatch>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Applies a directive overlay to its materialized instances: patched fields override, `deleted`
|
|
84
|
+
* drops the instance. Instances with no patch pass through untouched.
|
|
85
|
+
* @capability world-directives apply a sparse overlay over materialized directive instances
|
|
86
|
+
*/
|
|
87
|
+
export declare function applyDirectiveOverlay(instances: readonly MaterializedInstance[], overlay: EditorDirectiveOverlay): MaterializedInstance[];
|
|
88
|
+
/**
|
|
89
|
+
* Materializes every directive on a document into one flat instance list, applying each directive's
|
|
90
|
+
* overlay (matched by `over` === directive id) as it goes. The bulk-content counterpart to
|
|
91
|
+
* `resolveAuthoredObjects` / `resolveScatter`: games and headless tests read the same list.
|
|
92
|
+
* @capability world-directives materialize all scene directives with their overlays
|
|
93
|
+
*/
|
|
94
|
+
export declare function materializeDirectives(doc: EditorDocument, overlays?: readonly EditorDirectiveOverlay[]): MaterializedInstance[];
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { scatter } from "../world/scatter.js";
|
|
2
|
+
import { pointInPolygon, polygonBounds } from "../world/scatterRegion.js";
|
|
3
|
+
function hash(text) {
|
|
4
|
+
let h = 2166136261 >>> 0;
|
|
5
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
6
|
+
h ^= text.charCodeAt(i);
|
|
7
|
+
h = Math.imul(h, 16777619);
|
|
8
|
+
}
|
|
9
|
+
return (h >>> 0) / 4294967296;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolves the footprint a directive fills: an explicit `area`, else the footprint of the named
|
|
13
|
+
* `region` — a scatter/closed path (as a clip polygon) or a volume (its XZ AABB). Null when neither
|
|
14
|
+
* is present or the region id does not resolve.
|
|
15
|
+
* @capability world-directives resolve a directive's region footprint from the scene document
|
|
16
|
+
*/
|
|
17
|
+
export function resolveDirectiveFootprint(doc, directive) {
|
|
18
|
+
if (directive.area !== undefined) {
|
|
19
|
+
const { min, max } = directive.area;
|
|
20
|
+
return { area: { minX: min[0], minZ: min[1], maxX: max[0], maxZ: max[1] } };
|
|
21
|
+
}
|
|
22
|
+
if (directive.region === undefined)
|
|
23
|
+
return null;
|
|
24
|
+
const path = doc.paths.find((p) => p.id === directive.region);
|
|
25
|
+
if (path !== undefined && path.points.length >= 3) {
|
|
26
|
+
const polygon = path.points.map((point) => [point.x, point.z]);
|
|
27
|
+
const area = polygonBounds(polygon);
|
|
28
|
+
if (area === null)
|
|
29
|
+
return null;
|
|
30
|
+
return { area, polygon };
|
|
31
|
+
}
|
|
32
|
+
const volume = doc.volumes.find((v) => v.id === directive.region);
|
|
33
|
+
if (volume !== undefined) {
|
|
34
|
+
const half = volume.halfExtents !== undefined
|
|
35
|
+
? { x: volume.halfExtents.x, z: volume.halfExtents.z }
|
|
36
|
+
: volume.radius !== undefined
|
|
37
|
+
? { x: volume.radius, z: volume.radius }
|
|
38
|
+
: null;
|
|
39
|
+
if (half === null)
|
|
40
|
+
return null;
|
|
41
|
+
return {
|
|
42
|
+
area: {
|
|
43
|
+
minX: volume.center.x - half.x,
|
|
44
|
+
minZ: volume.center.z - half.z,
|
|
45
|
+
maxX: volume.center.x + half.x,
|
|
46
|
+
maxZ: volume.center.z + half.z,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
function scatterSeed(directive) {
|
|
53
|
+
return `${directive.id}:${directive.seed ?? directive.id}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Materializes a scatter directive into deterministic catalog-prop placements across its footprint,
|
|
57
|
+
* clipped to the region polygon when one is present. Per-instance scale and yaw derive from the
|
|
58
|
+
* directive id + seed + point index, so ids are stable across re-materializes.
|
|
59
|
+
* @capability world-directives materialize a scatter directive into placements
|
|
60
|
+
*/
|
|
61
|
+
export function materializeScatterDirective(directive, footprint) {
|
|
62
|
+
if (directive.density <= 0)
|
|
63
|
+
return [];
|
|
64
|
+
const seed = scatterSeed(directive);
|
|
65
|
+
const points = scatter({
|
|
66
|
+
area: footprint.area,
|
|
67
|
+
density: directive.density,
|
|
68
|
+
minDistance: directive.minSpacing ?? 0,
|
|
69
|
+
jitter: directive.jitter ?? 1,
|
|
70
|
+
seed,
|
|
71
|
+
});
|
|
72
|
+
const minScale = directive.minScale ?? 1;
|
|
73
|
+
const maxScale = directive.maxScale ?? 1;
|
|
74
|
+
const minYaw = directive.minYaw ?? 0;
|
|
75
|
+
const maxYaw = directive.maxYaw ?? Math.PI * 2;
|
|
76
|
+
const out = [];
|
|
77
|
+
for (const point of points) {
|
|
78
|
+
if (footprint.polygon !== undefined && !pointInPolygon([point.x, point.z], footprint.polygon))
|
|
79
|
+
continue;
|
|
80
|
+
const scaleRoll = hash(`${seed}:scale:${point.index}`);
|
|
81
|
+
const yawRoll = hash(`${seed}:yaw:${point.index}`);
|
|
82
|
+
out.push({
|
|
83
|
+
id: `${directive.id}#${point.index}`,
|
|
84
|
+
directiveId: directive.id,
|
|
85
|
+
kind: "scatter",
|
|
86
|
+
asset: directive.asset,
|
|
87
|
+
x: point.x,
|
|
88
|
+
z: point.z,
|
|
89
|
+
y: 0,
|
|
90
|
+
rotationY: minYaw + (maxYaw - minYaw) * yawRoll,
|
|
91
|
+
scale: minScale + (maxScale - minScale) * scaleRoll,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
function pickSpecies(available, roll) {
|
|
97
|
+
const total = available.reduce((sum, s) => sum + Math.max(0, s.weight ?? 1), 0);
|
|
98
|
+
if (total <= 0)
|
|
99
|
+
return available[0];
|
|
100
|
+
let acc = roll * total;
|
|
101
|
+
for (const species of available) {
|
|
102
|
+
acc -= Math.max(0, species.weight ?? 1);
|
|
103
|
+
if (acc <= 0)
|
|
104
|
+
return species;
|
|
105
|
+
}
|
|
106
|
+
return available[available.length - 1];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Materializes a population directive into deterministic mob spawn placements: at most `cap` of each
|
|
110
|
+
* weighted species, distributed across the footprint. Each placement carries a stable id and its
|
|
111
|
+
* species id in `asset`, ready to feed `ctx.scene.entity.spawn` / `ai/populationDirector`.
|
|
112
|
+
* @capability world-directives materialize a population directive into spawns
|
|
113
|
+
*/
|
|
114
|
+
export function materializePopulationDirective(directive, footprint) {
|
|
115
|
+
const remaining = new Map();
|
|
116
|
+
for (const species of directive.species) {
|
|
117
|
+
remaining.set(species.id, Math.max(0, (remaining.get(species.id) ?? 0) + species.cap));
|
|
118
|
+
}
|
|
119
|
+
const total = [...remaining.values()].reduce((sum, cap) => sum + cap, 0);
|
|
120
|
+
if (total <= 0)
|
|
121
|
+
return [];
|
|
122
|
+
const seed = scatterSeed(directive);
|
|
123
|
+
const points = scatter({ area: footprint.area, count: total, minDistance: 0, seed });
|
|
124
|
+
const out = [];
|
|
125
|
+
for (const point of points) {
|
|
126
|
+
if (footprint.polygon !== undefined && !pointInPolygon([point.x, point.z], footprint.polygon))
|
|
127
|
+
continue;
|
|
128
|
+
const available = directive.species.filter((s) => (remaining.get(s.id) ?? 0) > 0);
|
|
129
|
+
if (available.length === 0)
|
|
130
|
+
break;
|
|
131
|
+
const picked = pickSpecies(available, hash(`${seed}:species:${point.index}`));
|
|
132
|
+
remaining.set(picked.id, (remaining.get(picked.id) ?? 0) - 1);
|
|
133
|
+
out.push({
|
|
134
|
+
id: `${directive.id}#${point.index}`,
|
|
135
|
+
directiveId: directive.id,
|
|
136
|
+
kind: "population",
|
|
137
|
+
asset: picked.id,
|
|
138
|
+
x: point.x,
|
|
139
|
+
z: point.z,
|
|
140
|
+
y: 0,
|
|
141
|
+
rotationY: hash(`${seed}:yaw:${point.index}`) * Math.PI * 2,
|
|
142
|
+
scale: 1,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Materializes one directive against a document, resolving its footprint first. Returns an empty
|
|
149
|
+
* list when the region does not resolve.
|
|
150
|
+
* @capability world-directives materialize one scene directive into instances
|
|
151
|
+
*/
|
|
152
|
+
export function materializeDirective(doc, directive) {
|
|
153
|
+
const footprint = resolveDirectiveFootprint(doc, directive);
|
|
154
|
+
if (footprint === null)
|
|
155
|
+
return [];
|
|
156
|
+
return directive.kind === "scatter"
|
|
157
|
+
? materializeScatterDirective(directive, footprint)
|
|
158
|
+
: materializePopulationDirective(directive, footprint);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Applies a directive overlay to its materialized instances: patched fields override, `deleted`
|
|
162
|
+
* drops the instance. Instances with no patch pass through untouched.
|
|
163
|
+
* @capability world-directives apply a sparse overlay over materialized directive instances
|
|
164
|
+
*/
|
|
165
|
+
export function applyDirectiveOverlay(instances, overlay) {
|
|
166
|
+
const out = [];
|
|
167
|
+
for (const instance of instances) {
|
|
168
|
+
const patch = overlay.patches[instance.id];
|
|
169
|
+
if (patch === undefined) {
|
|
170
|
+
out.push(instance);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (patch.deleted === true)
|
|
174
|
+
continue;
|
|
175
|
+
out.push({
|
|
176
|
+
...instance,
|
|
177
|
+
x: patch.position?.x ?? instance.x,
|
|
178
|
+
z: patch.position?.z ?? instance.z,
|
|
179
|
+
y: patch.y ?? instance.y,
|
|
180
|
+
scale: patch.scale ?? instance.scale,
|
|
181
|
+
rotationY: patch.rotationY ?? instance.rotationY,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return out;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Materializes every directive on a document into one flat instance list, applying each directive's
|
|
188
|
+
* overlay (matched by `over` === directive id) as it goes. The bulk-content counterpart to
|
|
189
|
+
* `resolveAuthoredObjects` / `resolveScatter`: games and headless tests read the same list.
|
|
190
|
+
* @capability world-directives materialize all scene directives with their overlays
|
|
191
|
+
*/
|
|
192
|
+
export function materializeDirectives(doc, overlays) {
|
|
193
|
+
const directives = doc.directives ?? [];
|
|
194
|
+
if (directives.length === 0)
|
|
195
|
+
return [];
|
|
196
|
+
const overlayByDirective = new Map((overlays ?? []).map((overlay) => [overlay.over, overlay]));
|
|
197
|
+
const out = [];
|
|
198
|
+
for (const directive of directives) {
|
|
199
|
+
let instances = materializeDirective(doc, directive);
|
|
200
|
+
const overlay = overlayByDirective.get(directive.id);
|
|
201
|
+
if (overlay !== undefined)
|
|
202
|
+
instances = applyDirectiveOverlay(instances, overlay);
|
|
203
|
+
out.push(...instances);
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type EditorGridLayer } from "./grid.js";
|
|
2
|
-
import type { EditorCatalogData, EditorCatalogDefinition, EditorCatalogEntry, EditorCollection, EditorDocument, EditorFragmentContent, EditorLayersInput, EditorMarker, EditorNote, EditorPath, EditorPrefab, EditorTerrain, EditorVolume } from "./types.js";
|
|
2
|
+
import type { EditorCatalogData, EditorCatalogDefinition, EditorCatalogEntry, EditorCollection, EditorDirective, EditorDocument, EditorEnvironment, EditorFragmentContent, EditorLayersInput, EditorMarker, EditorMinimapBake, EditorNote, EditorPath, EditorPrefab, EditorTerrain, EditorVolume } from "./types.js";
|
|
3
3
|
/** Spread-ready non-placeable fields preserved across document rebuilds. @internal */
|
|
4
4
|
export declare function editorDocumentExtras(doc: EditorDocument): {
|
|
5
5
|
prefabs: EditorPrefab[];
|
|
@@ -8,6 +8,9 @@ export declare function editorDocumentExtras(doc: EditorDocument): {
|
|
|
8
8
|
grids?: EditorGridLayer[];
|
|
9
9
|
terrain?: EditorTerrain;
|
|
10
10
|
ui?: EditorDocument["ui"];
|
|
11
|
+
directives?: EditorDirective[];
|
|
12
|
+
minimap?: EditorMinimapBake;
|
|
13
|
+
environment?: EditorEnvironment;
|
|
11
14
|
};
|
|
12
15
|
/** Builds a fresh, empty editor document to start authoring a scene from scratch.
|
|
13
16
|
* @internal
|
|
@@ -71,10 +74,29 @@ export declare function findEditorCatalogEntry(doc: EditorDocument, catalogId: s
|
|
|
71
74
|
* @capability editor-catalogs Seed scene-document catalogs from game-exported schemas.
|
|
72
75
|
*/
|
|
73
76
|
export declare function seedEditorCatalogs(doc: EditorDocument, definitions: readonly EditorCatalogDefinition[]): EditorDocument;
|
|
74
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* True when an object carries a per-object `locked` flag (hierarchy lock toggle).
|
|
79
|
+
* Collection membership is checked separately by {@link isEditorObjectLocked}.
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
export declare function isEditorObjectSelfLocked(doc: EditorDocument, id: string): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* True when an object is a member of any locked collection (production group lock).
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
export declare function isEditorObjectCollectionLocked(doc: EditorDocument, id: string): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* True when an object id is locked for edit — either its own `locked` flag or membership in a
|
|
90
|
+
* locked collection. Blocks move/delete via session mutations.
|
|
75
91
|
* @internal
|
|
76
92
|
*/
|
|
77
93
|
export declare function isEditorObjectLocked(doc: EditorDocument, id: string): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* True when an object carries `hidden: true` — omitted from editor viewport overlays and picking
|
|
96
|
+
* while remaining in the hierarchy and document.
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
export declare function isEditorObjectHidden(doc: EditorDocument, id: string): boolean;
|
|
78
100
|
/**
|
|
79
101
|
* Extracts the selected ids into a prefab fragment centered on their own bounds centroid, so the
|
|
80
102
|
* same prefab reinserts consistently regardless of where in the scene (or which game) it lands.
|
|
@@ -85,6 +107,19 @@ export declare function createPrefabFragment(doc: EditorDocument, ids: readonly
|
|
|
85
107
|
* @internal
|
|
86
108
|
*/
|
|
87
109
|
export declare function findEditorMarker(doc: EditorDocument, id: string): EditorMarker | undefined;
|
|
110
|
+
/** Looks up a marker by id and throws when it is absent — for scene contracts where a
|
|
111
|
+
* missing marker is an authoring error to surface loudly, not a runtime branch to handle.
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
export declare function requireEditorMarker(doc: EditorDocument, id: string): EditorMarker;
|
|
115
|
+
/** A marker's world position as an `[x, y, z]` tuple — the shared shape gameplay tables read.
|
|
116
|
+
* @internal
|
|
117
|
+
*/
|
|
118
|
+
export declare function editorMarkerPosition(marker: EditorMarker): readonly [x: number, y: number, z: number];
|
|
119
|
+
/** A marker's ground position as an `[x, z]` tuple, dropping the vertical axis.
|
|
120
|
+
* @internal
|
|
121
|
+
*/
|
|
122
|
+
export declare function editorMarkerXZ(marker: EditorMarker): readonly [x: number, z: number];
|
|
88
123
|
/** Looks up a volume by id in an editor document.
|
|
89
124
|
* @internal
|
|
90
125
|
*/
|