@jgengine/core 0.18.0 → 0.19.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 +265 -2
- package/dist/ai/decisionGraph.d.ts +96 -0
- package/dist/ai/decisionGraph.js +212 -0
- package/dist/ai/groupAssist.d.ts +10 -0
- package/dist/ai/groupAssist.js +11 -0
- package/dist/ai/mobBrainGraph.d.ts +3 -0
- package/dist/ai/mobBrainGraph.js +25 -0
- package/dist/ai/pursuit.d.ts +1 -1
- package/dist/ai/pursuit.js +1 -1
- package/dist/ai/tacticalQueries.d.ts +30 -0
- package/dist/ai/tacticalQueries.js +45 -0
- package/dist/ai/threat.d.ts +8 -0
- package/dist/ai/threat.js +10 -0
- package/dist/anim/animGraph.d.ts +155 -0
- package/dist/anim/animGraph.js +414 -0
- package/dist/anim/boneTexture.d.ts +55 -0
- package/dist/anim/boneTexture.js +43 -0
- package/dist/anim/footPlacement.d.ts +57 -0
- package/dist/anim/footPlacement.js +67 -0
- package/dist/anim/ikSolver.d.ts +51 -0
- package/dist/anim/ikSolver.js +124 -0
- package/dist/anim/locomotionGraph.d.ts +35 -0
- package/dist/anim/locomotionGraph.js +62 -0
- package/dist/assets/spriteAtlas.d.ts +21 -0
- package/dist/assets/spriteAtlas.js +103 -0
- package/dist/audio/audioFalloff.d.ts +12 -0
- package/dist/audio/doppler.d.ts +21 -0
- package/dist/audio/doppler.js +32 -0
- package/dist/audio/engineLayers.d.ts +83 -0
- package/dist/audio/engineLayers.js +115 -0
- package/dist/combat/abilityKit.d.ts +1 -0
- package/dist/combat/abilityKit.js +1 -0
- package/dist/combat/death.d.ts +7 -0
- package/dist/combat/shotOrigin.d.ts +6 -0
- package/dist/combat/shotOrigin.js +6 -0
- package/dist/combat/weaponFeedback.d.ts +36 -0
- package/dist/combat/weaponFeedback.js +42 -0
- package/dist/combat/weaponHandling.d.ts +161 -0
- package/dist/combat/weaponHandling.js +202 -0
- package/dist/combat/weaponPresentation.d.ts +115 -0
- package/dist/combat/weaponPresentation.js +96 -0
- package/dist/devtools/warnOnce.d.ts +8 -0
- package/dist/devtools/warnOnce.js +18 -0
- package/dist/economy/currency.d.ts +16 -2
- package/dist/economy/currency.js +55 -14
- package/dist/economy/wallet.d.ts +5 -4
- package/dist/economy/wallet.js +8 -4
- package/dist/editor/commandApply.js +1 -0
- package/dist/editor/commands.d.ts +4 -1
- package/dist/editor/document.d.ts +2 -1
- package/dist/editor/document.js +92 -1
- package/dist/editor/environment.d.ts +3 -0
- package/dist/editor/environment.js +24 -0
- package/dist/editor/index.d.ts +4 -2
- package/dist/editor/index.js +1 -1
- package/dist/editor/types.d.ts +20 -0
- package/dist/faction/reputation.d.ts +6 -0
- package/dist/faction/reputation.js +11 -0
- package/dist/game/cameraConfig.d.ts +59 -1
- package/dist/game/chat.d.ts +22 -1
- package/dist/game/chat.js +48 -19
- package/dist/game/controlGate.d.ts +6 -0
- package/dist/game/controlGate.js +30 -1
- package/dist/game/defineGame.d.ts +10 -1
- package/dist/game/events.d.ts +14 -1
- package/dist/game/lootTable.d.ts +4 -0
- package/dist/game/lootTable.js +16 -0
- package/dist/game/pixelPerfect.d.ts +25 -0
- package/dist/game/pixelPerfect.js +29 -0
- package/dist/game/playableGame.d.ts +167 -6
- package/dist/game/systemRuntime.js +6 -1
- package/dist/game/toasts.d.ts +8 -0
- package/dist/game/toasts.js +7 -0
- package/dist/game/vfxInstance.d.ts +9 -0
- package/dist/game/vfxInstance.js +12 -1
- package/dist/game/viewports.d.ts +43 -0
- package/dist/game/viewports.js +46 -0
- package/dist/game/worldItem.d.ts +5 -1
- package/dist/game/worldItem.js +0 -1
- package/dist/input/actionBindings.d.ts +17 -2
- package/dist/input/actionBindings.js +24 -11
- package/dist/input/actionContexts.d.ts +45 -0
- package/dist/input/actionContexts.js +113 -0
- package/dist/input/axisInput.d.ts +4 -0
- package/dist/input/axisInput.js +4 -0
- package/dist/input/axisShaper.d.ts +73 -0
- package/dist/input/axisShaper.js +105 -0
- package/dist/input/gamepadModel.d.ts +79 -0
- package/dist/input/gamepadModel.js +108 -0
- package/dist/input/haptics.d.ts +50 -0
- package/dist/input/haptics.js +74 -0
- package/dist/input/inputBuffer.d.ts +40 -0
- package/dist/input/inputBuffer.js +59 -0
- package/dist/input/lookChannel.d.ts +10 -0
- package/dist/input/lookChannel.js +6 -0
- package/dist/input/pointer.d.ts +2 -0
- package/dist/input/pointer.js +4 -0
- package/dist/item/affix.d.ts +6 -0
- package/dist/item/affix.js +6 -0
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +196 -1
- package/dist/movement/characterController.d.ts +76 -0
- package/dist/movement/characterController.js +216 -0
- package/dist/movement/freeFlight.d.ts +119 -0
- package/dist/movement/freeFlight.js +294 -0
- package/dist/movement/glideModel.d.ts +3 -0
- package/dist/movement/glideModel.js +6 -0
- package/dist/movement/grappleSwing.d.ts +2 -0
- package/dist/movement/grappleSwing.js +5 -1
- package/dist/movement/movementModel.d.ts +39 -0
- package/dist/movement/movementModel.js +62 -19
- package/dist/movement/movementProbe.d.ts +51 -0
- package/dist/movement/movementProbe.js +119 -0
- package/dist/movement/playerMovement.d.ts +30 -3
- package/dist/movement/playerMovement.js +304 -7
- package/dist/movement/serverStep.d.ts +5 -0
- package/dist/movement/serverStep.js +6 -0
- package/dist/movement/solidObstacles.d.ts +39 -8
- package/dist/movement/solidObstacles.js +71 -6
- package/dist/movement/voxelController.js +7 -7
- package/dist/multiplayer/poseSyncGate.d.ts +3 -1
- package/dist/multiplayer/poseSyncGate.js +9 -1
- package/dist/multiplayer/presenceContract.d.ts +6 -0
- package/dist/multiplayer/presenceModel.d.ts +2 -0
- package/dist/multiplayer/presenceModel.js +11 -0
- package/dist/nav/navFromEnvironment.d.ts +9 -3
- package/dist/nav/navFromEnvironment.js +18 -12
- package/dist/nav/navMesh.d.ts +74 -0
- package/dist/nav/navMesh.js +570 -0
- package/dist/physics/aircraftDynamics.d.ts +390 -0
- package/dist/physics/aircraftDynamics.js +704 -0
- package/dist/physics/boatDynamics.d.ts +116 -0
- package/dist/physics/boatDynamics.js +160 -0
- package/dist/physics/drivableVehicle.d.ts +22 -8
- package/dist/physics/drivableVehicle.js +4 -2
- package/dist/physics/flightDynamics.d.ts +29 -4
- package/dist/physics/flightDynamics.js +28 -5
- package/dist/physics/handlingProbe.d.ts +249 -0
- package/dist/physics/handlingProbe.js +606 -0
- package/dist/physics/kinematicVehicle.d.ts +37 -2
- package/dist/physics/kinematicVehicle.js +15 -0
- package/dist/physics/physicsBackend.d.ts +203 -0
- package/dist/physics/physicsBackend.js +49 -0
- package/dist/physics/physicsBackendConformance.d.ts +27 -0
- package/dist/physics/physicsBackendConformance.js +151 -0
- package/dist/physics/physicsWorldBackend.d.ts +45 -0
- package/dist/physics/physicsWorldBackend.js +518 -0
- package/dist/physics/vehicleBackendLink.d.ts +49 -0
- package/dist/physics/vehicleBackendLink.js +102 -0
- package/dist/physics/vehicleDynamics.d.ts +374 -0
- package/dist/physics/vehicleDynamics.js +737 -0
- package/dist/physics/worldColliders.d.ts +13 -0
- package/dist/physics/worldColliders.js +128 -0
- package/dist/puzzle/cellGrid.d.ts +15 -9
- package/dist/puzzle/cellGrid.js +13 -9
- package/dist/random/rng.d.ts +12 -1
- package/dist/random/rng.js +20 -3
- package/dist/render/environment.d.ts +23 -0
- package/dist/render/environment.js +1 -0
- package/dist/render/lookPreset.d.ts +19 -6
- package/dist/render/lookPreset.js +56 -4
- package/dist/render/postProcessing.d.ts +40 -1
- package/dist/render/postProcessing.js +1 -1
- package/dist/render/sprite2d.d.ts +38 -0
- package/dist/render/sprite2d.js +40 -0
- package/dist/runtime/adapter.d.ts +20 -1
- package/dist/runtime/adapter.js +8 -1
- package/dist/runtime/cameraDirector.d.ts +17 -3
- package/dist/runtime/cameraDirector.js +25 -0
- package/dist/runtime/commandInput.d.ts +52 -0
- package/dist/runtime/commandInput.js +71 -0
- package/dist/runtime/commandRunner.d.ts +39 -7
- package/dist/runtime/commandRunner.js +35 -5
- package/dist/runtime/context/combat.d.ts +1 -0
- package/dist/runtime/context/combat.js +2 -1
- package/dist/runtime/context/deathLoot.d.ts +2 -0
- package/dist/runtime/context/deathLoot.js +1 -0
- package/dist/runtime/gameContext.js +18 -1
- package/dist/runtime/gameContextTypes.d.ts +33 -7
- package/dist/runtime/gameRuntime.d.ts +23 -5
- package/dist/runtime/gameRuntime.js +21 -4
- package/dist/runtime/headlessRunner.d.ts +10 -0
- package/dist/runtime/headlessRunner.js +26 -8
- package/dist/runtime/hostPolicy.d.ts +3 -2
- package/dist/runtime/hostPolicy.js +8 -10
- package/dist/runtime/hostedGameRunner.js +34 -6
- package/dist/runtime/hostedWorldSession.d.ts +12 -16
- package/dist/runtime/hostedWorldSession.js +29 -6
- package/dist/runtime/hostedWorldStore.d.ts +20 -0
- package/dist/runtime/hostedWorldStore.js +1 -0
- package/dist/runtime/inputRecorder.d.ts +30 -0
- package/dist/runtime/inputRecorder.js +59 -0
- package/dist/runtime/inputSnapshot.d.ts +14 -0
- package/dist/runtime/inputSnapshot.js +11 -0
- package/dist/runtime/localPlayers.d.ts +73 -0
- package/dist/runtime/localPlayers.js +119 -0
- package/dist/runtime/poseInterpolation.d.ts +36 -0
- package/dist/runtime/poseInterpolation.js +91 -0
- package/dist/runtime/prediction.d.ts +45 -0
- package/dist/runtime/prediction.js +62 -0
- package/dist/runtime/simContext.d.ts +45 -0
- package/dist/runtime/simContext.js +65 -0
- package/dist/runtime/simLoop.d.ts +52 -0
- package/dist/runtime/simLoop.js +72 -0
- package/dist/runtime/simSnapshot.d.ts +32 -0
- package/dist/runtime/simSnapshot.js +60 -0
- package/dist/runtime/snapshot.d.ts +8 -0
- package/dist/runtime/snapshotBuffer.d.ts +33 -0
- package/dist/runtime/snapshotBuffer.js +58 -0
- package/dist/runtime/transport.d.ts +41 -2
- package/dist/runtime/transport.js +7 -1
- package/dist/runtime/worldChunks.d.ts +2 -0
- package/dist/runtime/worldChunks.js +14 -0
- package/dist/runtime/worldProjection.d.ts +9 -0
- package/dist/runtime/worldProjection.js +17 -1
- package/dist/runtime/worldSnapshot.d.ts +6 -0
- package/dist/runtime/worldSnapshot.js +3 -0
- package/dist/scene/behaviorRuntime.d.ts +29 -1
- package/dist/scene/behaviorRuntime.js +71 -4
- package/dist/scene/behaviors.d.ts +12 -1
- package/dist/scene/builtinSceneKinds.js +10 -0
- package/dist/scene/sceneKinds.d.ts +9 -0
- package/dist/scene/vehicleSeat.d.ts +5 -1
- package/dist/scene/vehicleSeat.js +5 -1
- package/dist/sensor/concealment.d.ts +6 -0
- package/dist/sensor/concealment.js +8 -0
- package/dist/sensor/freezeMonitor.d.ts +6 -0
- package/dist/sensor/freezeMonitor.js +8 -0
- package/dist/sensor/perception.d.ts +70 -0
- package/dist/sensor/perception.js +189 -0
- package/dist/sensor/recordingBuffer.d.ts +3 -0
- package/dist/sensor/recordingBuffer.js +8 -0
- package/dist/session/roundState.d.ts +4 -0
- package/dist/session/roundState.js +11 -0
- package/dist/settings/frameRateLimit.d.ts +16 -0
- package/dist/settings/frameRateLimit.js +37 -0
- package/dist/settings/graphicsProfile.d.ts +21 -0
- package/dist/settings/graphicsProfile.js +48 -0
- package/dist/settings/graphicsSettings.d.ts +40 -0
- package/dist/settings/graphicsSettings.js +81 -0
- package/dist/settings/settingsModel.d.ts +9 -1
- package/dist/settings/settingsModel.js +10 -0
- package/dist/stats/eventMeter.d.ts +1 -1
- package/dist/stats/eventMeter.js +1 -1
- package/dist/time/accrueSince.d.ts +10 -0
- package/dist/time/accrueSince.js +9 -0
- package/dist/time/rateWindow.d.ts +16 -0
- package/dist/time/rateWindow.js +14 -0
- package/dist/time/serverTick.d.ts +21 -3
- package/dist/time/serverTick.js +14 -13
- package/dist/vfx/feedbackMixer.d.ts +61 -0
- package/dist/vfx/feedbackMixer.js +106 -0
- package/dist/vfx/particleDirector.d.ts +68 -0
- package/dist/vfx/particleDirector.js +81 -0
- package/dist/visibility/simulationCulling.d.ts +8 -1
- package/dist/visibility/simulationCulling.js +7 -0
- package/dist/visibility/spatialIndex.d.ts +21 -0
- package/dist/visibility/spatialIndex.js +16 -0
- package/dist/world/authoredSolids.d.ts +46 -0
- package/dist/world/authoredSolids.js +75 -0
- package/dist/world/buildingGenerator.js +2 -2
- package/dist/world/buildingKit.d.ts +3 -1
- package/dist/world/buildings.d.ts +46 -2
- package/dist/world/buildings.js +53 -3
- package/dist/world/cityContent.js +103 -25
- package/dist/world/cityKind.d.ts +139 -0
- package/dist/world/cityKind.js +367 -16
- package/dist/world/features.d.ts +56 -3
- package/dist/world/features.js +13 -2
- package/dist/world/footprintGrid.d.ts +7 -0
- package/dist/world/footprintGrid.js +16 -0
- package/dist/world/interiors.d.ts +1 -0
- package/dist/world/interiors.js +5 -3
- package/dist/world/lod.d.ts +6 -0
- package/dist/world/lod.js +8 -0
- package/dist/world/placement.d.ts +7 -0
- package/dist/world/placement.js +2 -0
- package/dist/world/placementController.d.ts +1 -1
- package/dist/world/placementController.js +7 -0
- package/dist/world/raceCircuit.d.ts +168 -0
- package/dist/world/raceCircuit.js +797 -0
- package/dist/world/terraform.d.ts +8 -0
- package/dist/world/terraform.js +7 -0
- package/dist/world/terrain.d.ts +5 -1
- package/dist/world/terrain.js +5 -0
- package/dist/world/territory.d.ts +97 -0
- package/dist/world/territory.js +182 -0
- package/dist/world/walls.d.ts +7 -0
- package/dist/world/walls.js +7 -0
- package/dist/world/worldSolids.d.ts +84 -0
- package/dist/world/worldSolids.js +240 -0
- package/dist/world.d.ts +5 -3
- package/dist/world.js +4 -2
- package/package.json +1 -1
- package/skills/ce-handoff/SKILL.md +2 -2
- package/skills/game-design/SKILL.md +11 -1
- package/skills/jgengine/SKILL.md +9 -5
- package/skills/jgengine/api.md +205 -101
- package/skills/jgengine/capabilities.md +56 -0
- package/skills/jgengine/recipes/minimal-game.md +3 -0
- package/skills/jgengine-combat/SKILL.md +5 -0
- package/skills/jgengine-combat/api.md +138 -103
- package/skills/jgengine-combat/capabilities.md +29 -1
- package/skills/jgengine-combat/recipes/weapon-feel.md +50 -0
- package/skills/jgengine-gameplay/SKILL.md +10 -0
- package/skills/jgengine-gameplay/api.md +501 -453
- package/skills/jgengine-gameplay/capabilities.md +36 -0
- package/skills/jgengine-gameplay/reference-systems.md +4 -0
- package/skills/jgengine-world/SKILL.md +21 -3
- package/skills/jgengine-world/api.md +1172 -625
- package/skills/jgengine-world/capabilities.md +229 -3
- package/skills/jgengine-world/recipes/character-animation.md +39 -0
- package/skills/jgengine-world/recipes/controls.md +44 -0
- package/skills/jgengine-world/recipes/flight-feel.md +76 -0
- package/skills/jgengine-world/recipes/npc-senses.md +43 -0
- package/skills/jgengine-world/recipes/vehicle-feel.md +85 -0
- package/skills/jgengine-world/reference.md +31 -2
- package/skills/jgengine-world/visibility.md +112 -0
|
@@ -262,5 +262,13 @@ export interface TerraformBrush {
|
|
|
262
262
|
config(): Required<Omit<TerraformBrushConfig, "surface">> & {
|
|
263
263
|
surface: string | undefined;
|
|
264
264
|
};
|
|
265
|
+
/** The retunable brush settings; the terrain keeps its own `snapshot()`. */
|
|
266
|
+
snapshot(): TerraformBrushState;
|
|
267
|
+
restore(next: TerraformBrushState): void;
|
|
268
|
+
}
|
|
269
|
+
/** Plain JSON state of a {@link TerraformBrush}. */
|
|
270
|
+
export interface TerraformBrushState {
|
|
271
|
+
radius: number;
|
|
272
|
+
strength: number;
|
|
265
273
|
}
|
|
266
274
|
export declare function createTerraformBrush(terrain: Pick<EditableTerrain, "apply">, config?: TerraformBrushConfig): TerraformBrush;
|
package/dist/world/terraform.js
CHANGED
|
@@ -787,5 +787,12 @@ export function createTerraformBrush(terrain, config = {}) {
|
|
|
787
787
|
config() {
|
|
788
788
|
return { radius, strength, falloff, surface };
|
|
789
789
|
},
|
|
790
|
+
snapshot() {
|
|
791
|
+
return { radius, strength };
|
|
792
|
+
},
|
|
793
|
+
restore(next) {
|
|
794
|
+
radius = next.radius;
|
|
795
|
+
strength = next.strength;
|
|
796
|
+
},
|
|
790
797
|
};
|
|
791
798
|
}
|
package/dist/world/terrain.d.ts
CHANGED
|
@@ -203,9 +203,13 @@ export interface ResolvedTerrainDetailMaterial {
|
|
|
203
203
|
tint: number;
|
|
204
204
|
}
|
|
205
205
|
/** A {@link TerrainDetailConfig} with every field resolved to a concrete value — the shape the shell's detail material consumes. */
|
|
206
|
-
export type ResolvedTerrainDetail = Required<Omit<TerrainDetailConfig, "waterLevel" | "material">> & {
|
|
206
|
+
export type ResolvedTerrainDetail = Required<Omit<TerrainDetailConfig, "waterLevel" | "material" | "sweeps">> & {
|
|
207
207
|
waterLevel: number;
|
|
208
208
|
material?: ResolvedTerrainDetailMaterial;
|
|
209
|
+
sweeps: {
|
|
210
|
+
dry: readonly [number, number, number];
|
|
211
|
+
wet: readonly [number, number, number];
|
|
212
|
+
};
|
|
209
213
|
};
|
|
210
214
|
/** Fill a `TerrainDetailConfig` with defaults; `waterLevel` falls back to the terrain's own water level.
|
|
211
215
|
* @internal
|
package/dist/world/terrain.js
CHANGED
|
@@ -475,6 +475,7 @@ const DEFAULT_TERRAIN_DETAIL = {
|
|
|
475
475
|
macroScale: 45,
|
|
476
476
|
roughness: 0.9,
|
|
477
477
|
strength: 1,
|
|
478
|
+
sweeps: { dry: [1.14, 1.05, 0.76], wet: [0.78, 1.0, 0.86] },
|
|
478
479
|
};
|
|
479
480
|
const DEFAULT_TERRAIN_MATERIAL_REPEAT = 4;
|
|
480
481
|
const DEFAULT_TERRAIN_MATERIAL_STRENGTH = 1;
|
|
@@ -493,6 +494,10 @@ export function resolveTerrainDetail(config, terrainWaterLevel = 0) {
|
|
|
493
494
|
macroScale: config.macroScale ?? DEFAULT_TERRAIN_DETAIL.macroScale,
|
|
494
495
|
roughness: config.roughness ?? DEFAULT_TERRAIN_DETAIL.roughness,
|
|
495
496
|
strength: clamp01(config.strength ?? DEFAULT_TERRAIN_DETAIL.strength),
|
|
497
|
+
sweeps: {
|
|
498
|
+
dry: config.sweeps?.dry ?? DEFAULT_TERRAIN_DETAIL.sweeps.dry,
|
|
499
|
+
wet: config.sweeps?.wet ?? DEFAULT_TERRAIN_DETAIL.sweeps.wet,
|
|
500
|
+
},
|
|
496
501
|
waterLevel: config.waterLevel ?? terrainWaterLevel,
|
|
497
502
|
...(config.material === undefined
|
|
498
503
|
? {}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { GameRuntimeSnapshot } from "../runtime/snapshot.js";
|
|
2
|
+
import type { Aabb } from "./geometry.js";
|
|
3
|
+
/** Integer cell coordinates used for ownership on the ground plane. */
|
|
4
|
+
export type TerritoryCell = {
|
|
5
|
+
x: number;
|
|
6
|
+
z: number;
|
|
7
|
+
};
|
|
8
|
+
/** Cell size, foreign-owner gap, growth price, currency and starter-grant policy. */
|
|
9
|
+
export type TerritoryPolicy = {
|
|
10
|
+
gapCells?: number;
|
|
11
|
+
cellSize?: number;
|
|
12
|
+
chunkSize?: number;
|
|
13
|
+
currency?: string;
|
|
14
|
+
price?: (ownedCount: number) => number;
|
|
15
|
+
starterBlock?: number;
|
|
16
|
+
nowMs?: number;
|
|
17
|
+
};
|
|
18
|
+
/** Atomic claim outcome with the replacement snapshot and total charge. */
|
|
19
|
+
export type TerritoryResult = {
|
|
20
|
+
ok: true;
|
|
21
|
+
snapshot: GameRuntimeSnapshot;
|
|
22
|
+
cost: number;
|
|
23
|
+
} | {
|
|
24
|
+
ok: false;
|
|
25
|
+
reason: "territory.blocked" | "territory.unaffordable";
|
|
26
|
+
};
|
|
27
|
+
/** Read-only footprint quote or a blocked/insufficient-balance rejection. */
|
|
28
|
+
export type TerritoryPlan = {
|
|
29
|
+
ok: true;
|
|
30
|
+
cells: TerritoryCell[];
|
|
31
|
+
cost: number;
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
reason: "territory.blocked" | "territory.unaffordable";
|
|
35
|
+
};
|
|
36
|
+
/** Host-owned snapshot access used by the territory facade. */
|
|
37
|
+
export interface TerritoryStorage {
|
|
38
|
+
get(): GameRuntimeSnapshot;
|
|
39
|
+
set(snapshot: GameRuntimeSnapshot): void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Persisted chunk key containing one territory cell.
|
|
43
|
+
* @capability territory-cell-chunk Map ownership cells to persisted world chunks.
|
|
44
|
+
*/
|
|
45
|
+
export declare function territoryChunkKey(cell: TerritoryCell, policy?: TerritoryPolicy): string;
|
|
46
|
+
/**
|
|
47
|
+
* Exact chunks needed to validate a footprint and its foreign-owner gap.
|
|
48
|
+
* @capability territory-read-scope Load the footprint and foreign-owner gap without scanning the world.
|
|
49
|
+
*/
|
|
50
|
+
export declare function territoryChunkKeys(cells: readonly TerritoryCell[], policy?: TerritoryPolicy): string[];
|
|
51
|
+
/**
|
|
52
|
+
* Owner of a loaded cell; hosts load the target and gap neighborhood before evaluating claims.
|
|
53
|
+
* @capability territory-owner-query Read a loaded land cell owner for authoritative placement checks.
|
|
54
|
+
*/
|
|
55
|
+
export declare function territoryOwnerOf(snapshot: GameRuntimeSnapshot, cell: TerritoryCell, policy?: TerritoryPolicy): string | null;
|
|
56
|
+
/**
|
|
57
|
+
* Cells touched by a placement, excluding cells that only touch its outer edge.
|
|
58
|
+
* @capability territory-footprint Resolve exactly the ownership cells touched by a placement footprint.
|
|
59
|
+
*/
|
|
60
|
+
export declare function territoryFootprintCells(bounds: Aabb, cellSize?: number): TerritoryCell[];
|
|
61
|
+
/** Price and validate a footprint without mutating or charging; reuse for placement previews. */
|
|
62
|
+
export declare function planFootprintClaims(snapshot: GameRuntimeSnapshot, userId: string, footprint: readonly TerritoryCell[], policy?: TerritoryPolicy): TerritoryPlan;
|
|
63
|
+
/** Atomically buy every unowned footprint cell, leaving the input untouched on failure. */
|
|
64
|
+
export declare function claimTerritory(snapshot: GameRuntimeSnapshot, userId: string, cells: readonly TerritoryCell[], policy?: TerritoryPolicy): TerritoryResult;
|
|
65
|
+
/**
|
|
66
|
+
* Placement transaction: rejected object placement also rolls back territory and its charge.
|
|
67
|
+
* @capability territory-placement Purchase footprint cells atomically with object placement.
|
|
68
|
+
*/
|
|
69
|
+
export declare function placeWithTerritory(snapshot: GameRuntimeSnapshot, userId: string, bounds: Aabb, policy: TerritoryPolicy, place: (snapshot: GameRuntimeSnapshot) => {
|
|
70
|
+
ok: true;
|
|
71
|
+
snapshot: GameRuntimeSnapshot;
|
|
72
|
+
} | {
|
|
73
|
+
ok: false;
|
|
74
|
+
reason: string;
|
|
75
|
+
}): {
|
|
76
|
+
ok: true;
|
|
77
|
+
snapshot: GameRuntimeSnapshot;
|
|
78
|
+
cost: number;
|
|
79
|
+
} | {
|
|
80
|
+
ok: false;
|
|
81
|
+
reason: string;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Snapshot-backed territory facade with host-owned storage and live policy.
|
|
85
|
+
* @capability territory-ownership Claim, release and query land through host-owned snapshot storage.
|
|
86
|
+
*/
|
|
87
|
+
export declare function createTerritory(storage: TerritoryStorage, policy?: () => TerritoryPolicy): {
|
|
88
|
+
snapshot: () => GameRuntimeSnapshot;
|
|
89
|
+
restore: (snapshot: GameRuntimeSnapshot) => void;
|
|
90
|
+
ownerOf: (cell: TerritoryCell) => string | null;
|
|
91
|
+
canUse: (userId: string, cell: TerritoryCell) => boolean;
|
|
92
|
+
claim(userId: string, cells: readonly TerritoryCell[]): TerritoryResult;
|
|
93
|
+
release(userId: string, cell: TerritoryCell): boolean;
|
|
94
|
+
grantStarter(userId: string, center: TerritoryCell): TerritoryResult;
|
|
95
|
+
};
|
|
96
|
+
/** Snapshot-backed claim, release, owner and starter-grant operations. */
|
|
97
|
+
export type Territory = ReturnType<typeof createTerritory>;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { chunkKeyAt, updateChunk } from "../runtime/worldChunks.js";
|
|
2
|
+
function checked(policy) {
|
|
3
|
+
if (policy.nowMs !== undefined && !Number.isFinite(policy.nowMs))
|
|
4
|
+
throw new RangeError("Invalid territory timestamp");
|
|
5
|
+
const gapCells = policy.gapCells ?? 0, cellSize = policy.cellSize ?? 1, chunkSize = policy.chunkSize ?? 64;
|
|
6
|
+
if (!Number.isSafeInteger(gapCells) || gapCells < 0 || gapCells > 128 || !Number.isFinite(cellSize) || cellSize <= 0 || !Number.isFinite(chunkSize) || chunkSize <= 0)
|
|
7
|
+
throw new RangeError("Invalid territory policy");
|
|
8
|
+
return { gapCells, cellSize, chunkSize };
|
|
9
|
+
}
|
|
10
|
+
function key(cell) {
|
|
11
|
+
if (!Number.isSafeInteger(cell.x) || !Number.isSafeInteger(cell.z))
|
|
12
|
+
throw new RangeError("Invalid territory cell");
|
|
13
|
+
return `${cell.x},${cell.z}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Persisted chunk key containing one territory cell.
|
|
17
|
+
* @capability territory-cell-chunk Map ownership cells to persisted world chunks.
|
|
18
|
+
*/
|
|
19
|
+
export function territoryChunkKey(cell, policy = {}) {
|
|
20
|
+
key(cell);
|
|
21
|
+
const { cellSize, chunkSize } = checked(policy);
|
|
22
|
+
return chunkKeyAt([cell.x * cellSize, 0, cell.z * cellSize], chunkSize);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Exact chunks needed to validate a footprint and its foreign-owner gap.
|
|
26
|
+
* @capability territory-read-scope Load the footprint and foreign-owner gap without scanning the world.
|
|
27
|
+
*/
|
|
28
|
+
export function territoryChunkKeys(cells, policy = {}) {
|
|
29
|
+
const { gapCells } = checked(policy);
|
|
30
|
+
const chunks = new Set();
|
|
31
|
+
if (cells.length * (2 * gapCells + 1) ** 2 > 1_000_000)
|
|
32
|
+
throw new RangeError("Territory neighborhood is too large");
|
|
33
|
+
for (const cell of cells) {
|
|
34
|
+
key(cell);
|
|
35
|
+
for (let x = cell.x - gapCells; x <= cell.x + gapCells; x++) {
|
|
36
|
+
for (let z = cell.z - gapCells; z <= cell.z + gapCells; z++)
|
|
37
|
+
chunks.add(territoryChunkKey({ x, z }, policy));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return [...chunks];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Owner of a loaded cell; hosts load the target and gap neighborhood before evaluating claims.
|
|
44
|
+
* @capability territory-owner-query Read a loaded land cell owner for authoritative placement checks.
|
|
45
|
+
*/
|
|
46
|
+
export function territoryOwnerOf(snapshot, cell, policy = {}) {
|
|
47
|
+
return snapshot.chunks[territoryChunkKey(cell, policy)]?.territory?.[key(cell)] ?? null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Cells touched by a placement, excluding cells that only touch its outer edge.
|
|
51
|
+
* @capability territory-footprint Resolve exactly the ownership cells touched by a placement footprint.
|
|
52
|
+
*/
|
|
53
|
+
export function territoryFootprintCells(bounds, cellSize = 1) {
|
|
54
|
+
if (!Number.isFinite(cellSize) || cellSize <= 0 || !Object.values(bounds).every(Number.isFinite) || bounds.maxX <= bounds.minX || bounds.maxZ <= bounds.minZ)
|
|
55
|
+
throw new RangeError("Invalid territory footprint");
|
|
56
|
+
const cells = [];
|
|
57
|
+
const minX = Math.floor(bounds.minX / cellSize), maxX = Math.ceil(bounds.maxX / cellSize) - 1;
|
|
58
|
+
const minZ = Math.floor(bounds.minZ / cellSize), maxZ = Math.ceil(bounds.maxZ / cellSize) - 1;
|
|
59
|
+
if ((maxX - minX + 1) * (maxZ - minZ + 1) > 65536)
|
|
60
|
+
throw new RangeError("Territory footprint is too large");
|
|
61
|
+
for (let x = minX; x <= maxX; x++)
|
|
62
|
+
for (let z = minZ; z <= maxZ; z++)
|
|
63
|
+
cells.push({ x, z });
|
|
64
|
+
return cells;
|
|
65
|
+
}
|
|
66
|
+
/** Price and validate a footprint without mutating or charging; reuse for placement previews. */
|
|
67
|
+
export function planFootprintClaims(snapshot, userId, footprint, policy = {}) {
|
|
68
|
+
const { gapCells } = checked(policy);
|
|
69
|
+
if (footprint.length * (2 * gapCells + 1) ** 2 > 1_000_000)
|
|
70
|
+
throw new RangeError("Territory neighborhood is too large");
|
|
71
|
+
const player = snapshot.players[userId];
|
|
72
|
+
if (!player)
|
|
73
|
+
return { ok: false, reason: "territory.blocked" };
|
|
74
|
+
const cells = [], seen = new Set();
|
|
75
|
+
let cost = 0;
|
|
76
|
+
const owned = Number(player.territoryOwnedCount ?? 0);
|
|
77
|
+
if (!Number.isSafeInteger(owned) || owned < 0)
|
|
78
|
+
throw new RangeError("Invalid territory owned count");
|
|
79
|
+
for (const cell of footprint) {
|
|
80
|
+
const cellKey = key(cell);
|
|
81
|
+
if (seen.has(cellKey))
|
|
82
|
+
continue;
|
|
83
|
+
seen.add(cellKey);
|
|
84
|
+
const owner = territoryOwnerOf(snapshot, cell, policy);
|
|
85
|
+
if (owner === userId)
|
|
86
|
+
continue;
|
|
87
|
+
if (owner !== null)
|
|
88
|
+
return { ok: false, reason: "territory.blocked" };
|
|
89
|
+
for (let x = cell.x - gapCells; x <= cell.x + gapCells; x++)
|
|
90
|
+
for (let z = cell.z - gapCells; z <= cell.z + gapCells; z++) {
|
|
91
|
+
const neighbor = territoryOwnerOf(snapshot, { x, z }, policy);
|
|
92
|
+
if (neighbor !== null && neighbor !== userId)
|
|
93
|
+
return { ok: false, reason: "territory.blocked" };
|
|
94
|
+
}
|
|
95
|
+
const price = policy.price?.(owned + cells.length) ?? 0;
|
|
96
|
+
if (!Number.isFinite(price) || price < 0)
|
|
97
|
+
throw new RangeError("Invalid territory price");
|
|
98
|
+
cost += price;
|
|
99
|
+
if (!Number.isFinite(cost))
|
|
100
|
+
throw new RangeError("Invalid territory cost");
|
|
101
|
+
cells.push(cell);
|
|
102
|
+
}
|
|
103
|
+
if (cost > 0 && (!policy.currency || (player.economy[policy.currency] ?? 0) < cost))
|
|
104
|
+
return { ok: false, reason: "territory.unaffordable" };
|
|
105
|
+
return { ok: true, cells, cost };
|
|
106
|
+
}
|
|
107
|
+
/** Atomically buy every unowned footprint cell, leaving the input untouched on failure. */
|
|
108
|
+
export function claimTerritory(snapshot, userId, cells, policy = {}) {
|
|
109
|
+
const plan = planFootprintClaims(snapshot, userId, cells, policy);
|
|
110
|
+
if (!plan.ok)
|
|
111
|
+
return plan;
|
|
112
|
+
let next = snapshot;
|
|
113
|
+
for (const [index, cell] of plan.cells.entries())
|
|
114
|
+
next = updateChunk(next, territoryChunkKey(cell, policy), chunk => ({
|
|
115
|
+
...chunk,
|
|
116
|
+
territory: { ...chunk.territory, [key(cell)]: userId },
|
|
117
|
+
territoryReceipts: { ...chunk.territoryReceipts, [key(cell)]: { claimedAt: policy.nowMs ?? 0, costPaid: policy.price?.(Number(snapshot.players[userId]?.territoryOwnedCount ?? 0) + index) ?? 0 } },
|
|
118
|
+
}));
|
|
119
|
+
if (plan.cells.length === 0)
|
|
120
|
+
return { ok: true, snapshot, cost: 0 };
|
|
121
|
+
const player = snapshot.players[userId];
|
|
122
|
+
next = { ...next, players: { ...next.players, [userId]: { ...player, territoryOwnedCount: Number(player.territoryOwnedCount ?? 0) + plan.cells.length, ownedTerritoryChunkKeys: [...new Set([...(player.ownedTerritoryChunkKeys ?? []), ...plan.cells.map(cell => territoryChunkKey(cell, policy))])], economy: policy.currency ? { ...player.economy, [policy.currency]: (player.economy[policy.currency] ?? 0) - plan.cost } : player.economy } }, dirty: { ...next.dirty, players: [...new Set([...next.dirty.players, userId])] } };
|
|
123
|
+
return { ok: true, snapshot: next, cost: plan.cost };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Placement transaction: rejected object placement also rolls back territory and its charge.
|
|
127
|
+
* @capability territory-placement Purchase footprint cells atomically with object placement.
|
|
128
|
+
*/
|
|
129
|
+
export function placeWithTerritory(snapshot, userId, bounds, policy, place) {
|
|
130
|
+
const claimed = claimTerritory(snapshot, userId, territoryFootprintCells(bounds, policy.cellSize), policy);
|
|
131
|
+
if (!claimed.ok)
|
|
132
|
+
return claimed;
|
|
133
|
+
const placed = place(claimed.snapshot);
|
|
134
|
+
return placed.ok ? { ...placed, cost: claimed.cost } : placed;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Snapshot-backed territory facade with host-owned storage and live policy.
|
|
138
|
+
* @capability territory-ownership Claim, release and query land through host-owned snapshot storage.
|
|
139
|
+
*/
|
|
140
|
+
export function createTerritory(storage, policy = () => ({})) {
|
|
141
|
+
return {
|
|
142
|
+
snapshot: () => storage.get(),
|
|
143
|
+
restore: (snapshot) => storage.set(snapshot),
|
|
144
|
+
ownerOf: (cell) => territoryOwnerOf(storage.get(), cell, policy()),
|
|
145
|
+
canUse: (userId, cell) => territoryOwnerOf(storage.get(), cell, policy()) === userId,
|
|
146
|
+
claim(userId, cells) {
|
|
147
|
+
const result = claimTerritory(storage.get(), userId, cells, policy());
|
|
148
|
+
if (result.ok)
|
|
149
|
+
storage.set(result.snapshot);
|
|
150
|
+
return result;
|
|
151
|
+
},
|
|
152
|
+
release(userId, cell) {
|
|
153
|
+
const snapshot = storage.get(), config = policy();
|
|
154
|
+
if (territoryOwnerOf(snapshot, cell, config) !== userId || !snapshot.players[userId])
|
|
155
|
+
return false;
|
|
156
|
+
let next = updateChunk(snapshot, territoryChunkKey(cell, config), chunk => {
|
|
157
|
+
const territory = { ...chunk.territory }, territoryReceipts = { ...chunk.territoryReceipts };
|
|
158
|
+
delete territory[key(cell)];
|
|
159
|
+
delete territoryReceipts[key(cell)];
|
|
160
|
+
return { ...chunk, territory, territoryReceipts };
|
|
161
|
+
});
|
|
162
|
+
const player = next.players[userId];
|
|
163
|
+
next = { ...next, players: { ...next.players, [userId]: { ...player, territoryOwnedCount: Math.max(0, Number(player.territoryOwnedCount ?? 0) - 1), ownedTerritoryChunkKeys: (player.ownedTerritoryChunkKeys ?? []).filter(chunkKey => chunkKey !== territoryChunkKey(cell, config) || Object.values(next.chunks[chunkKey]?.territory ?? {}).includes(userId)) } }, dirty: { ...next.dirty, players: [...new Set([...next.dirty.players, userId])] } };
|
|
164
|
+
storage.set(next);
|
|
165
|
+
return true;
|
|
166
|
+
},
|
|
167
|
+
grantStarter(userId, center) {
|
|
168
|
+
const config = policy(), width = config.starterBlock ?? 3;
|
|
169
|
+
if (!Number.isSafeInteger(width) || width < 1 || width > 128)
|
|
170
|
+
throw new RangeError("Invalid starter block");
|
|
171
|
+
const snapshot = storage.get();
|
|
172
|
+
if (Number(snapshot.players[userId]?.territoryOwnedCount ?? 0) > 0)
|
|
173
|
+
return { ok: true, snapshot, cost: 0 };
|
|
174
|
+
const startX = center.x - Math.floor(width / 2), startZ = center.z - Math.floor(width / 2);
|
|
175
|
+
const cells = territoryFootprintCells({ minX: startX, minZ: startZ, maxX: startX + width, maxZ: startZ + width });
|
|
176
|
+
const result = claimTerritory(snapshot, userId, cells, { ...config, price: () => 0 });
|
|
177
|
+
if (result.ok)
|
|
178
|
+
storage.set(result.snapshot);
|
|
179
|
+
return result;
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
package/dist/world/walls.d.ts
CHANGED
|
@@ -50,6 +50,11 @@ export interface SurfacePaintStore {
|
|
|
50
50
|
}
|
|
51
51
|
/** @internal */
|
|
52
52
|
export declare function createSurfacePaint(): SurfacePaintStore;
|
|
53
|
+
/** Plain JSON state of a {@link WallDrawTool}: the drawn points and whether the loop is closed. */
|
|
54
|
+
export interface WallDrawToolState {
|
|
55
|
+
points: Vec2[];
|
|
56
|
+
closed: boolean;
|
|
57
|
+
}
|
|
53
58
|
export interface WallDrawTool {
|
|
54
59
|
addPoint(point: Vec2, snap?: number): Vec2;
|
|
55
60
|
undo(): void;
|
|
@@ -60,6 +65,8 @@ export interface WallDrawTool {
|
|
|
60
65
|
isClosed(): boolean;
|
|
61
66
|
footprint(): EnclosedFootprint | null;
|
|
62
67
|
roof(config?: RoofConfig): RoofPlan | null;
|
|
68
|
+
snapshot(): WallDrawToolState;
|
|
69
|
+
restore(next: WallDrawToolState): void;
|
|
63
70
|
}
|
|
64
71
|
/** @internal */
|
|
65
72
|
export declare function createWallDrawTool(config?: {
|
package/dist/world/walls.js
CHANGED
|
@@ -220,6 +220,13 @@ export function createWallDrawTool(config = {}) {
|
|
|
220
220
|
const fp = this.footprint();
|
|
221
221
|
return fp === null ? null : autoRoof(fp, roofConfig);
|
|
222
222
|
},
|
|
223
|
+
snapshot() {
|
|
224
|
+
return { points: pts.map((point) => [point[0], point[1]]), closed };
|
|
225
|
+
},
|
|
226
|
+
restore(next) {
|
|
227
|
+
pts = next.points.map((point) => [point[0], point[1]]);
|
|
228
|
+
closed = next.closed;
|
|
229
|
+
},
|
|
223
230
|
};
|
|
224
231
|
}
|
|
225
232
|
/** @internal */
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { GeneratedBuilding } from "./buildings.js";
|
|
2
|
+
import type { EnvironmentWorldFeature } from "./features.js";
|
|
3
|
+
import type { Aabb } from "./geometry.js";
|
|
4
|
+
import type { WallSegment } from "./walls.js";
|
|
5
|
+
/** One solid box in world space: the collision half of generated or authored world geometry. */
|
|
6
|
+
export interface WorldSolid {
|
|
7
|
+
center: readonly [number, number, number];
|
|
8
|
+
halfExtents: readonly [number, number, number];
|
|
9
|
+
/** Yaw about `center`, radians, in the engine's `rotationY` convention. Default `0`. */
|
|
10
|
+
rotationY?: number;
|
|
11
|
+
}
|
|
12
|
+
/** Serializable contents of a {@link WorldSolids}: every layer's solids by layer id. */
|
|
13
|
+
export interface WorldSolidsState {
|
|
14
|
+
layers: Record<string, readonly WorldSolid[]>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Static collision for world geometry that is not a scene object: generated buildings, studio
|
|
18
|
+
* volumes like `city`, wall runs. Solids live in named layers so a feature can replace or drop its
|
|
19
|
+
* own set without touching the rest. `solidObstaclesNear` (player and NPC movement),
|
|
20
|
+
* `syncWorldColliders` (physics backends) and `populateNavGridFromSolids` all read this one store.
|
|
21
|
+
*/
|
|
22
|
+
export interface WorldSolids {
|
|
23
|
+
/** Replace a layer's solids; an empty list removes the layer. */
|
|
24
|
+
set(layer: string, solids: readonly WorldSolid[]): void;
|
|
25
|
+
remove(layer: string): void;
|
|
26
|
+
/** Run several `set`/`remove` calls as one change: one index rebuild, one notification. */
|
|
27
|
+
batch(apply: () => void): void;
|
|
28
|
+
/** Solids in one layer, empty when absent. */
|
|
29
|
+
layer(layer: string): readonly WorldSolid[];
|
|
30
|
+
layers(): readonly string[];
|
|
31
|
+
/** Every solid whose world AABB overlaps `min`..`max`. Bounded by a uniform XZ hash grid. */
|
|
32
|
+
inBox(min: readonly [number, number, number], max: readonly [number, number, number]): WorldSolid[];
|
|
33
|
+
/** Every solid in every layer. */
|
|
34
|
+
all(): WorldSolid[];
|
|
35
|
+
count(): number;
|
|
36
|
+
/** Bumps on every change; cheap cache key for consumers. */
|
|
37
|
+
version(): number;
|
|
38
|
+
subscribe(listener: () => void): () => void;
|
|
39
|
+
snapshot(): WorldSolidsState;
|
|
40
|
+
restore(state: WorldSolidsState): void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Yaw-expanded world AABB of an oriented solid box.
|
|
44
|
+
* @capability world-solid-bounds world AABB and nav footprint of a world solid
|
|
45
|
+
*/
|
|
46
|
+
export declare function worldSolidBounds(solid: WorldSolid): {
|
|
47
|
+
min: [number, number, number];
|
|
48
|
+
max: [number, number, number];
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* XZ footprint of a solid's world AABB, for 2D consumers such as nav grids.
|
|
52
|
+
* @capability world-solid-bounds world AABB and nav footprint of a world solid
|
|
53
|
+
*/
|
|
54
|
+
export declare function worldSolidFootprint(solid: WorldSolid): Aabb;
|
|
55
|
+
/**
|
|
56
|
+
* A store of static world solids in named layers.
|
|
57
|
+
* @capability world-solids collision for generated and authored world geometry (buildings, city lots, walls)
|
|
58
|
+
*/
|
|
59
|
+
export declare function createWorldSolids(options?: {
|
|
60
|
+
cellSize?: number;
|
|
61
|
+
}): WorldSolids;
|
|
62
|
+
/**
|
|
63
|
+
* One solid per generated building: its `bounds` footprint turned by `rotationY` about `center`,
|
|
64
|
+
* from the ground under its center up through its floors. `groundHeight` defaults to flat `0`.
|
|
65
|
+
* @capability world-solids-from-data derive collision boxes from generated buildings and wall runs
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildingSolids(buildings: readonly GeneratedBuilding[], groundHeight?: (x: number, z: number) => number): WorldSolid[];
|
|
68
|
+
/**
|
|
69
|
+
* Solids for every `structures` descriptor on an environment feature, skipping any marked `solid: false`.
|
|
70
|
+
* @capability world-solids-from-data derive collision boxes from generated buildings and wall runs
|
|
71
|
+
*/
|
|
72
|
+
export declare function structureSolids(world: EnvironmentWorldFeature, groundHeight?: (x: number, z: number) => number): WorldSolid[];
|
|
73
|
+
/** Wall height, thickness and base for {@link wallSolids}. */
|
|
74
|
+
export interface WallSolidOptions {
|
|
75
|
+
height: number;
|
|
76
|
+
thickness: number;
|
|
77
|
+
/** Ground height under a point; the wall stands on it at each segment's midpoint. Default flat `0`. */
|
|
78
|
+
groundHeight?: (x: number, z: number) => number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* One oriented solid per wall segment (see `wallSegments` in `world/walls`).
|
|
82
|
+
* @capability world-solids-from-data derive collision boxes from generated buildings and wall runs
|
|
83
|
+
*/
|
|
84
|
+
export declare function wallSolids(segments: readonly WallSegment[], options: WallSolidOptions): WorldSolid[];
|