@jgengine/core 0.6.0 → 0.8.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.
Files changed (330) hide show
  1. package/CHANGELOG.md +214 -2
  2. package/README.md +2 -0
  3. package/dist/ai/crowd.d.ts +36 -0
  4. package/dist/ai/crowd.js +213 -0
  5. package/dist/ai/jobBoard.d.ts +49 -0
  6. package/dist/ai/jobBoard.js +155 -0
  7. package/dist/ai/spawnDirector.d.ts +61 -0
  8. package/dist/ai/spawnDirector.js +162 -0
  9. package/dist/ai/threat.d.ts +25 -0
  10. package/dist/ai/threat.js +67 -0
  11. package/dist/anim/easing.d.ts +14 -0
  12. package/dist/anim/easing.js +55 -0
  13. package/dist/audio/audioFalloff.d.ts +38 -0
  14. package/dist/audio/audioFalloff.js +32 -0
  15. package/dist/behaviour/behaviour.d.ts +136 -0
  16. package/dist/behaviour/behaviour.js +388 -0
  17. package/dist/board/laneBoard.d.ts +63 -0
  18. package/dist/board/laneBoard.js +114 -0
  19. package/dist/board/timelineBoard.d.ts +36 -0
  20. package/dist/board/timelineBoard.js +70 -0
  21. package/dist/cards/cardPile.d.ts +64 -0
  22. package/dist/cards/cardPile.js +175 -0
  23. package/dist/cards/modifierPipeline.d.ts +33 -0
  24. package/dist/cards/modifierPipeline.js +48 -0
  25. package/dist/combat/abilityKit.d.ts +47 -0
  26. package/dist/combat/abilityKit.js +139 -0
  27. package/dist/combat/animationState.d.ts +47 -0
  28. package/dist/combat/animationState.js +101 -0
  29. package/dist/combat/attackTags.d.ts +14 -0
  30. package/dist/combat/attackTags.js +26 -0
  31. package/dist/combat/breakMeters.d.ts +32 -0
  32. package/dist/combat/breakMeters.js +51 -0
  33. package/dist/combat/comboString.d.ts +35 -0
  34. package/dist/combat/comboString.js +59 -0
  35. package/dist/combat/death.d.ts +8 -0
  36. package/dist/combat/death.js +5 -2
  37. package/dist/combat/defensiveWindow.d.ts +34 -0
  38. package/dist/combat/defensiveWindow.js +66 -0
  39. package/dist/combat/downed.d.ts +35 -0
  40. package/dist/combat/downed.js +104 -0
  41. package/dist/combat/effects.d.ts +12 -1
  42. package/dist/combat/effects.js +31 -19
  43. package/dist/combat/hitReaction.d.ts +23 -0
  44. package/dist/combat/hitReaction.js +20 -0
  45. package/dist/combat/projectiles.d.ts +42 -5
  46. package/dist/combat/projectiles.js +98 -12
  47. package/dist/combat/resistance.d.ts +13 -0
  48. package/dist/combat/resistance.js +46 -0
  49. package/dist/combat/telegraph.d.ts +31 -0
  50. package/dist/combat/telegraph.js +51 -0
  51. package/dist/commands/commandRegistry.d.ts +1 -1
  52. package/dist/commands/commandRegistry.js +2 -1
  53. package/dist/crafting/crop.d.ts +59 -0
  54. package/dist/crafting/crop.js +181 -0
  55. package/dist/crafting/production.d.ts +64 -0
  56. package/dist/crafting/production.js +130 -0
  57. package/dist/crafting/recipe.d.ts +62 -0
  58. package/dist/crafting/recipe.js +101 -0
  59. package/dist/data/dataSource.d.ts +26 -0
  60. package/dist/data/dataSource.js +93 -0
  61. package/dist/data/devProxy.d.ts +11 -0
  62. package/dist/data/devProxy.js +38 -0
  63. package/dist/data/fetchJson.d.ts +20 -0
  64. package/dist/data/fetchJson.js +43 -0
  65. package/dist/data/jsonDataSource.d.ts +4 -0
  66. package/dist/data/jsonDataSource.js +6 -0
  67. package/dist/devtools/devtools.d.ts +157 -0
  68. package/dist/devtools/devtools.js +484 -0
  69. package/dist/devtools/transformTunables.d.ts +14 -0
  70. package/dist/devtools/transformTunables.js +38 -0
  71. package/dist/economy/sharedWallet.d.ts +28 -0
  72. package/dist/economy/sharedWallet.js +62 -0
  73. package/dist/economy/techTree.d.ts +40 -0
  74. package/dist/economy/techTree.js +66 -0
  75. package/dist/game/chat.d.ts +66 -0
  76. package/dist/game/chat.js +165 -0
  77. package/dist/game/cosmetics.d.ts +25 -0
  78. package/dist/game/cosmetics.js +51 -0
  79. package/dist/game/defineGame.d.ts +10 -2
  80. package/dist/game/defineGame.js +2 -1
  81. package/dist/game/events.d.ts +87 -0
  82. package/dist/game/levelSequence.d.ts +44 -0
  83. package/dist/game/levelSequence.js +78 -0
  84. package/dist/game/lootFilter.d.ts +33 -0
  85. package/dist/game/lootFilter.js +48 -0
  86. package/dist/game/ping.d.ts +67 -0
  87. package/dist/game/ping.js +86 -0
  88. package/dist/game/playableGame.d.ts +516 -8
  89. package/dist/game/playableGame.js +6 -1
  90. package/dist/game/progression.d.ts +1 -0
  91. package/dist/game/progression.js +23 -2
  92. package/dist/game/race.d.ts +100 -0
  93. package/dist/game/race.js +236 -0
  94. package/dist/game/runDraft.d.ts +34 -0
  95. package/dist/game/runDraft.js +97 -0
  96. package/dist/game/social.d.ts +69 -0
  97. package/dist/game/social.js +138 -0
  98. package/dist/game/spawnPoints.d.ts +19 -0
  99. package/dist/game/spawnPoints.js +23 -0
  100. package/dist/game/worldItem.d.ts +95 -0
  101. package/dist/game/worldItem.js +138 -0
  102. package/dist/input/actionBindings.d.ts +10 -0
  103. package/dist/input/actionBindings.js +14 -0
  104. package/dist/input/axisInput.d.ts +43 -0
  105. package/dist/input/axisInput.js +70 -0
  106. package/dist/input/gestureSurface.d.ts +31 -0
  107. package/dist/input/gestureSurface.js +120 -0
  108. package/dist/input/pointer.d.ts +69 -0
  109. package/dist/input/pointer.js +65 -0
  110. package/dist/input/touchScheme.d.ts +83 -0
  111. package/dist/input/touchScheme.js +115 -0
  112. package/dist/interaction/contextMenu.d.ts +30 -0
  113. package/dist/interaction/contextMenu.js +22 -0
  114. package/dist/interaction/qte.d.ts +20 -0
  115. package/dist/interaction/qte.js +24 -0
  116. package/dist/interaction/skillCheck.d.ts +20 -0
  117. package/dist/interaction/skillCheck.js +26 -0
  118. package/dist/inventory/shapedGrid.d.ts +56 -0
  119. package/dist/inventory/shapedGrid.js +176 -0
  120. package/dist/inventory/storageTier.d.ts +52 -0
  121. package/dist/inventory/storageTier.js +77 -0
  122. package/dist/item/affix.d.ts +54 -0
  123. package/dist/item/affix.js +115 -0
  124. package/dist/item/durability.d.ts +51 -0
  125. package/dist/item/durability.js +78 -0
  126. package/dist/item/modularItem.d.ts +46 -0
  127. package/dist/item/modularItem.js +75 -0
  128. package/dist/meta/changelog.d.ts +1 -1
  129. package/dist/meta/changelog.js +71 -1
  130. package/dist/movement/dash.d.ts +37 -0
  131. package/dist/movement/dash.js +65 -0
  132. package/dist/movement/movementModel.d.ts +36 -3
  133. package/dist/movement/movementModel.js +81 -5
  134. package/dist/movement/voxelController.d.ts +61 -0
  135. package/dist/movement/voxelController.js +229 -0
  136. package/dist/multiplayer/chatContract.d.ts +42 -0
  137. package/dist/multiplayer/chatContract.js +57 -0
  138. package/dist/multiplayer/combatSnapshot.d.ts +45 -0
  139. package/dist/multiplayer/combatSnapshot.js +89 -0
  140. package/dist/multiplayer/identity.d.ts +13 -0
  141. package/dist/multiplayer/identity.js +20 -0
  142. package/dist/multiplayer/lagCompensation.d.ts +43 -0
  143. package/dist/multiplayer/lagCompensation.js +154 -0
  144. package/dist/multiplayer/matchmaking.d.ts +33 -0
  145. package/dist/multiplayer/matchmaking.js +60 -0
  146. package/dist/multiplayer/poseSyncGate.d.ts +1 -0
  147. package/dist/multiplayer/poseSyncGate.js +13 -1
  148. package/dist/multiplayer/presenceModel.d.ts +3 -0
  149. package/dist/multiplayer/presenceModel.js +15 -1
  150. package/dist/multiplayer/simultaneousCommit.d.ts +34 -0
  151. package/dist/multiplayer/simultaneousCommit.js +53 -0
  152. package/dist/multiplayer/voiceContract.d.ts +44 -0
  153. package/dist/multiplayer/voiceContract.js +108 -0
  154. package/dist/nav/navConstrain.d.ts +14 -0
  155. package/dist/nav/navConstrain.js +26 -0
  156. package/dist/nav/navFromEnvironment.d.ts +11 -0
  157. package/dist/nav/navFromEnvironment.js +16 -0
  158. package/dist/nav/navGrid.d.ts +56 -0
  159. package/dist/nav/navGrid.js +265 -0
  160. package/dist/nav/pathFollow.d.ts +31 -0
  161. package/dist/nav/pathFollow.js +69 -0
  162. package/dist/physics/ballisticSweep.d.ts +18 -0
  163. package/dist/physics/ballisticSweep.js +49 -0
  164. package/dist/physics/buoyancy.d.ts +49 -0
  165. package/dist/physics/buoyancy.js +112 -0
  166. package/dist/physics/carryable.d.ts +46 -0
  167. package/dist/physics/carryable.js +110 -0
  168. package/dist/physics/damageZones.d.ts +56 -0
  169. package/dist/physics/damageZones.js +107 -0
  170. package/dist/physics/forceVolume.d.ts +48 -0
  171. package/dist/physics/forceVolume.js +119 -0
  172. package/dist/physics/physicsWorld.d.ts +124 -2
  173. package/dist/physics/physicsWorld.js +493 -41
  174. package/dist/physics/ragdoll.d.ts +49 -0
  175. package/dist/physics/ragdoll.js +103 -0
  176. package/dist/physics/spatialGrid.d.ts +41 -0
  177. package/dist/physics/spatialGrid.js +143 -0
  178. package/dist/physics/structure.d.ts +83 -0
  179. package/dist/physics/structure.js +0 -0
  180. package/dist/physics/traversal.d.ts +75 -0
  181. package/dist/physics/traversal.js +138 -0
  182. package/dist/physics/vehicleBody.d.ts +99 -0
  183. package/dist/physics/vehicleBody.js +233 -0
  184. package/dist/puzzle/cellGrid.d.ts +26 -0
  185. package/dist/puzzle/cellGrid.js +110 -0
  186. package/dist/puzzle/fallingPiece.d.ts +24 -0
  187. package/dist/puzzle/fallingPiece.js +51 -0
  188. package/dist/random/nameGen.d.ts +18 -0
  189. package/dist/random/nameGen.js +35 -0
  190. package/dist/random/rng.d.ts +2 -0
  191. package/dist/random/rng.js +23 -0
  192. package/dist/runtime/adapter.d.ts +35 -0
  193. package/dist/runtime/adapter.js +37 -1
  194. package/dist/runtime/cameraDirector.d.ts +10 -0
  195. package/dist/runtime/cameraDirector.js +25 -0
  196. package/dist/runtime/gameContext.d.ts +107 -3
  197. package/dist/runtime/gameContext.js +253 -7
  198. package/dist/runtime/hostPersistence.d.ts +39 -0
  199. package/dist/runtime/hostPersistence.js +54 -0
  200. package/dist/runtime/inputSnapshot.d.ts +7 -0
  201. package/dist/runtime/inputSnapshot.js +12 -0
  202. package/dist/runtime/motionIntents.d.ts +25 -0
  203. package/dist/runtime/motionIntents.js +25 -0
  204. package/dist/runtime/persistenceScope.d.ts +32 -0
  205. package/dist/runtime/persistenceScope.js +64 -0
  206. package/dist/runtime/transport.d.ts +32 -0
  207. package/dist/scene/autoTarget.d.ts +15 -0
  208. package/dist/scene/autoTarget.js +54 -0
  209. package/dist/scene/behaviors.d.ts +13 -1
  210. package/dist/scene/behaviors.js +3 -0
  211. package/dist/scene/captureCheck.d.ts +7 -0
  212. package/dist/scene/captureCheck.js +11 -0
  213. package/dist/scene/entityStore.d.ts +9 -1
  214. package/dist/scene/entityStore.js +25 -2
  215. package/dist/scene/form.d.ts +40 -0
  216. package/dist/scene/form.js +56 -0
  217. package/dist/scene/mount.d.ts +62 -0
  218. package/dist/scene/mount.js +107 -0
  219. package/dist/scene/movementSpeed.d.ts +35 -0
  220. package/dist/scene/movementSpeed.js +20 -0
  221. package/dist/scene/objectQuery.d.ts +18 -0
  222. package/dist/scene/objectQuery.js +108 -0
  223. package/dist/scene/objectStore.d.ts +11 -0
  224. package/dist/scene/objectStore.js +109 -4
  225. package/dist/scene/paintLayer.d.ts +15 -0
  226. package/dist/scene/paintLayer.js +53 -0
  227. package/dist/scene/possession.d.ts +30 -0
  228. package/dist/scene/possession.js +51 -0
  229. package/dist/scene/roster.d.ts +25 -0
  230. package/dist/scene/roster.js +57 -0
  231. package/dist/scene/selection.d.ts +30 -0
  232. package/dist/scene/selection.js +38 -0
  233. package/dist/scene/spatial.d.ts +21 -0
  234. package/dist/scene/spatial.js +63 -1
  235. package/dist/scene/stationClaim.d.ts +43 -0
  236. package/dist/scene/stationClaim.js +109 -0
  237. package/dist/sensor/concealment.d.ts +21 -0
  238. package/dist/sensor/concealment.js +63 -0
  239. package/dist/sensor/freezeMonitor.d.ts +17 -0
  240. package/dist/sensor/freezeMonitor.js +35 -0
  241. package/dist/sensor/frustumSensor.d.ts +60 -0
  242. package/dist/sensor/frustumSensor.js +104 -0
  243. package/dist/sensor/hiddenStateProbe.d.ts +31 -0
  244. package/dist/sensor/hiddenStateProbe.js +40 -0
  245. package/dist/sensor/recordingBuffer.d.ts +29 -0
  246. package/dist/sensor/recordingBuffer.js +61 -0
  247. package/dist/sensor/revealQuery.d.ts +22 -0
  248. package/dist/sensor/revealQuery.js +36 -0
  249. package/dist/session/contestedChannel.d.ts +36 -0
  250. package/dist/session/contestedChannel.js +100 -0
  251. package/dist/session/extraction.d.ts +54 -0
  252. package/dist/session/extraction.js +108 -0
  253. package/dist/session/ring.d.ts +36 -0
  254. package/dist/session/ring.js +88 -0
  255. package/dist/session/roles.d.ts +6 -0
  256. package/dist/session/roles.js +32 -0
  257. package/dist/session/roundState.d.ts +79 -0
  258. package/dist/session/roundState.js +158 -0
  259. package/dist/stats/accumulatorMeter.d.ts +31 -0
  260. package/dist/stats/accumulatorMeter.js +81 -0
  261. package/dist/stats/eventMeter.d.ts +34 -0
  262. package/dist/stats/eventMeter.js +76 -0
  263. package/dist/stats/rollCheck.d.ts +15 -0
  264. package/dist/stats/rollCheck.js +15 -0
  265. package/dist/survival/decayMeter.d.ts +59 -0
  266. package/dist/survival/decayMeter.js +95 -0
  267. package/dist/survival/moodle.d.ts +48 -0
  268. package/dist/survival/moodle.js +91 -0
  269. package/dist/survival/regionHealth.d.ts +72 -0
  270. package/dist/survival/regionHealth.js +129 -0
  271. package/dist/tactics/fallingGrid.d.ts +62 -0
  272. package/dist/tactics/fallingGrid.js +158 -0
  273. package/dist/tactics/predictiveQuery.d.ts +34 -0
  274. package/dist/tactics/predictiveQuery.js +44 -0
  275. package/dist/tactics/snapshot.d.ts +18 -0
  276. package/dist/tactics/snapshot.js +65 -0
  277. package/dist/tactics/surface.d.ts +52 -0
  278. package/dist/tactics/surface.js +135 -0
  279. package/dist/tactics/tacticalGrid.d.ts +68 -0
  280. package/dist/tactics/tacticalGrid.js +261 -0
  281. package/dist/time/beatClock.d.ts +40 -0
  282. package/dist/time/beatClock.js +73 -0
  283. package/dist/time/simClock.d.ts +25 -1
  284. package/dist/time/simClock.js +28 -3
  285. package/dist/turn/commit.d.ts +27 -0
  286. package/dist/turn/commit.js +72 -0
  287. package/dist/turn/intent.d.ts +14 -0
  288. package/dist/turn/intent.js +29 -0
  289. package/dist/turn/turnLoop.d.ts +60 -0
  290. package/dist/turn/turnLoop.js +223 -0
  291. package/dist/world/buildPermissions.d.ts +47 -0
  292. package/dist/world/buildPermissions.js +134 -0
  293. package/dist/world/carve.d.ts +105 -0
  294. package/dist/world/carve.js +175 -0
  295. package/dist/world/connectors.d.ts +40 -0
  296. package/dist/world/connectors.js +67 -0
  297. package/dist/world/envField.d.ts +71 -0
  298. package/dist/world/envField.js +96 -0
  299. package/dist/world/environmentSummary.d.ts +53 -0
  300. package/dist/world/environmentSummary.js +129 -0
  301. package/dist/world/features.d.ts +87 -6
  302. package/dist/world/features.js +52 -2
  303. package/dist/world/fog.d.ts +40 -0
  304. package/dist/world/fog.js +137 -0
  305. package/dist/world/gridInstances.d.ts +13 -0
  306. package/dist/world/gridInstances.js +22 -0
  307. package/dist/world/markers.d.ts +52 -0
  308. package/dist/world/markers.js +96 -0
  309. package/dist/world/minimap.d.ts +42 -0
  310. package/dist/world/minimap.js +72 -0
  311. package/dist/world/placedStructureStore.d.ts +39 -0
  312. package/dist/world/placedStructureStore.js +95 -0
  313. package/dist/world/placementController.d.ts +69 -0
  314. package/dist/world/placementController.js +153 -0
  315. package/dist/world/realm.d.ts +61 -0
  316. package/dist/world/realm.js +66 -0
  317. package/dist/world/support.d.ts +27 -0
  318. package/dist/world/support.js +75 -0
  319. package/dist/world/terraform.d.ts +54 -0
  320. package/dist/world/terraform.js +186 -0
  321. package/dist/world/terrain.d.ts +23 -1
  322. package/dist/world/terrain.js +64 -1
  323. package/dist/world/voxelField.d.ts +54 -0
  324. package/dist/world/voxelField.js +241 -0
  325. package/dist/world/walls.d.ts +61 -0
  326. package/dist/world/walls.js +221 -0
  327. package/dist/world/weather.d.ts +92 -0
  328. package/dist/world/weather.js +169 -0
  329. package/llms.txt +4102 -0
  330. package/package.json +3 -2
@@ -0,0 +1,105 @@
1
+ import { type TerrainField } from "./terrain.js";
2
+ import type { WorldBounds } from "./features.js";
3
+ export declare const EMPTY_VOXEL = 0;
4
+ export interface VoxelMaterial {
5
+ /** Cell value stored in the grid; 0 is reserved for empty. */
6
+ id: number;
7
+ name: string;
8
+ /** A carve tool's strength must reach this to remove the material — hard rock resists a weak drill. Default 0 (anything digs it). */
9
+ strength: number;
10
+ /** Debris/harvest hint carried through to game code; the engine only tallies removed cells by id. */
11
+ drop?: string;
12
+ }
13
+ export type VoxelMaterialTable = Readonly<Record<number, VoxelMaterial>>;
14
+ export interface VoxelVolumeConfig {
15
+ /** Grid resolution in cells: [nx, ny, nz]. */
16
+ dims: readonly [number, number, number];
17
+ /** World position of the min corner of cell [0,0,0]. Default [0,0,0]. */
18
+ origin?: readonly [number, number, number];
19
+ /** World-space edge length of one cubic cell. Default 1. */
20
+ scale?: number;
21
+ /** Material id every cell starts as. Default 1 (a solid volume waiting to be dug). */
22
+ fill?: number;
23
+ /** Strength lookup by material id; carve honours it against a tool strength. */
24
+ materials?: VoxelMaterialTable;
25
+ }
26
+ export interface CarveOp {
27
+ /** Sphere centre in world coordinates. */
28
+ center: readonly [number, number, number];
29
+ /** Sphere radius in world units. */
30
+ radius: number;
31
+ /** Only cells whose material `strength` is ≤ this are removed. Default Infinity (dig anything). */
32
+ toolStrength?: number;
33
+ }
34
+ export interface DepositOp {
35
+ center: readonly [number, number, number];
36
+ radius: number;
37
+ /** Material id to fill empty cells with (Engineer platform / Astroneer terrain add). */
38
+ material: number;
39
+ }
40
+ /**
41
+ * A runtime-editable dense voxel grid — the carve/deposit op behind destructible dig worlds (Deep
42
+ * Rock Galactic tunnels, Astroneer terrain). Cells hold a material id (0 = empty); `carve` clears a
43
+ * sphere of solid cells that a tool is strong enough to break and returns how many it removed (feed
44
+ * that to a loot roll), `deposit` fills a sphere with a material. World↔cell mapping is `origin`+`scale`.
45
+ */
46
+ export declare class VoxelVolume {
47
+ readonly nx: number;
48
+ readonly ny: number;
49
+ readonly nz: number;
50
+ readonly scale: number;
51
+ readonly origin: readonly [number, number, number];
52
+ private readonly cells;
53
+ private readonly materials;
54
+ private solidCount;
55
+ constructor(config: VoxelVolumeConfig);
56
+ get solid(): number;
57
+ private index;
58
+ inBounds(ix: number, iy: number, iz: number): boolean;
59
+ get(ix: number, iy: number, iz: number): number;
60
+ set(ix: number, iy: number, iz: number, material: number): void;
61
+ worldToCell(x: number, y: number, z: number): readonly [number, number, number];
62
+ solidAtWorld(x: number, y: number, z: number): boolean;
63
+ private strengthOf;
64
+ private forEachCellInSphere;
65
+ /** Clear every solid cell in the sphere the tool can break; returns the number removed. */
66
+ carve(op: CarveOp): number;
67
+ /** Fill every empty cell in the sphere with `material`; returns the number filled. */
68
+ deposit(op: DepositOp): number;
69
+ }
70
+ export interface CraterOp {
71
+ /** Crater centre (x, z in world units). */
72
+ x: number;
73
+ z: number;
74
+ radius: number;
75
+ /** How deep the bowl cuts at its centre. */
76
+ depth: number;
77
+ }
78
+ export interface MoundOp {
79
+ x: number;
80
+ z: number;
81
+ radius: number;
82
+ /** How high the mound rises at its centre. */
83
+ height: number;
84
+ }
85
+ /**
86
+ * A `TerrainField` you can write craters and mounds into at runtime — the height-field side of
87
+ * destructible terrain (Helldivers 2 explosion craters, engineer-deposited berms). Wraps a base field
88
+ * and layers smooth radial deformations on top, so `sampleHeight` (and therefore ground-snap,
89
+ * collision, and the shell's terrain mesh) all read the deformed surface. `carve` digs a bowl,
90
+ * `deposit` raises a mound.
91
+ */
92
+ export declare class CarvableField implements TerrainField {
93
+ readonly bounds?: WorldBounds;
94
+ readonly waterLevel?: number;
95
+ readonly sampleNormal: TerrainField["sampleNormal"];
96
+ private readonly base;
97
+ private readonly edits;
98
+ constructor(base: TerrainField);
99
+ get editCount(): number;
100
+ sampleHeight(x: number, z: number): number;
101
+ carve(op: CraterOp): void;
102
+ deposit(op: MoundOp): void;
103
+ clear(): void;
104
+ }
105
+ export declare function carvableTerrain(base: TerrainField): CarvableField;
@@ -0,0 +1,175 @@
1
+ import { withNormal } from "./terrain.js";
2
+ export const EMPTY_VOXEL = 0;
3
+ /**
4
+ * A runtime-editable dense voxel grid — the carve/deposit op behind destructible dig worlds (Deep
5
+ * Rock Galactic tunnels, Astroneer terrain). Cells hold a material id (0 = empty); `carve` clears a
6
+ * sphere of solid cells that a tool is strong enough to break and returns how many it removed (feed
7
+ * that to a loot roll), `deposit` fills a sphere with a material. World↔cell mapping is `origin`+`scale`.
8
+ */
9
+ export class VoxelVolume {
10
+ nx;
11
+ ny;
12
+ nz;
13
+ scale;
14
+ origin;
15
+ cells;
16
+ materials;
17
+ solidCount = 0;
18
+ constructor(config) {
19
+ this.nx = Math.max(1, Math.floor(config.dims[0]));
20
+ this.ny = Math.max(1, Math.floor(config.dims[1]));
21
+ this.nz = Math.max(1, Math.floor(config.dims[2]));
22
+ this.scale = config.scale ?? 1;
23
+ this.origin = config.origin ?? [0, 0, 0];
24
+ this.materials = config.materials ?? {};
25
+ this.cells = new Uint16Array(this.nx * this.ny * this.nz);
26
+ const fill = config.fill ?? 1;
27
+ if (fill !== EMPTY_VOXEL) {
28
+ this.cells.fill(fill);
29
+ this.solidCount = this.cells.length;
30
+ }
31
+ }
32
+ get solid() {
33
+ return this.solidCount;
34
+ }
35
+ index(ix, iy, iz) {
36
+ return (iz * this.ny + iy) * this.nx + ix;
37
+ }
38
+ inBounds(ix, iy, iz) {
39
+ return ix >= 0 && ix < this.nx && iy >= 0 && iy < this.ny && iz >= 0 && iz < this.nz;
40
+ }
41
+ get(ix, iy, iz) {
42
+ if (!this.inBounds(ix, iy, iz))
43
+ return EMPTY_VOXEL;
44
+ return this.cells[this.index(ix, iy, iz)];
45
+ }
46
+ set(ix, iy, iz, material) {
47
+ if (!this.inBounds(ix, iy, iz))
48
+ return;
49
+ const at = this.index(ix, iy, iz);
50
+ const prev = this.cells[at];
51
+ if (prev === material)
52
+ return;
53
+ if (prev === EMPTY_VOXEL)
54
+ this.solidCount += 1;
55
+ else if (material === EMPTY_VOXEL)
56
+ this.solidCount -= 1;
57
+ this.cells[at] = material;
58
+ }
59
+ worldToCell(x, y, z) {
60
+ return [
61
+ Math.floor((x - this.origin[0]) / this.scale),
62
+ Math.floor((y - this.origin[1]) / this.scale),
63
+ Math.floor((z - this.origin[2]) / this.scale),
64
+ ];
65
+ }
66
+ solidAtWorld(x, y, z) {
67
+ const [ix, iy, iz] = this.worldToCell(x, y, z);
68
+ return this.get(ix, iy, iz) !== EMPTY_VOXEL;
69
+ }
70
+ strengthOf(material) {
71
+ return this.materials[material]?.strength ?? 0;
72
+ }
73
+ forEachCellInSphere(center, radius, visit) {
74
+ const s = this.scale;
75
+ const [cx, cy, cz] = this.worldToCell(center[0], center[1], center[2]);
76
+ const reach = Math.ceil(radius / s) + 1;
77
+ const r2 = radius * radius;
78
+ for (let iz = cz - reach; iz <= cz + reach; iz += 1) {
79
+ for (let iy = cy - reach; iy <= cy + reach; iy += 1) {
80
+ for (let ix = cx - reach; ix <= cx + reach; ix += 1) {
81
+ if (!this.inBounds(ix, iy, iz))
82
+ continue;
83
+ const wx = this.origin[0] + (ix + 0.5) * s;
84
+ const wy = this.origin[1] + (iy + 0.5) * s;
85
+ const wz = this.origin[2] + (iz + 0.5) * s;
86
+ const dx = wx - center[0];
87
+ const dy = wy - center[1];
88
+ const dz = wz - center[2];
89
+ if (dx * dx + dy * dy + dz * dz <= r2)
90
+ visit(ix, iy, iz);
91
+ }
92
+ }
93
+ }
94
+ }
95
+ /** Clear every solid cell in the sphere the tool can break; returns the number removed. */
96
+ carve(op) {
97
+ const tool = op.toolStrength ?? Number.POSITIVE_INFINITY;
98
+ let removed = 0;
99
+ this.forEachCellInSphere(op.center, op.radius, (ix, iy, iz) => {
100
+ const m = this.get(ix, iy, iz);
101
+ if (m === EMPTY_VOXEL)
102
+ return;
103
+ if (this.strengthOf(m) > tool)
104
+ return;
105
+ this.set(ix, iy, iz, EMPTY_VOXEL);
106
+ removed += 1;
107
+ });
108
+ return removed;
109
+ }
110
+ /** Fill every empty cell in the sphere with `material`; returns the number filled. */
111
+ deposit(op) {
112
+ let filled = 0;
113
+ this.forEachCellInSphere(op.center, op.radius, (ix, iy, iz) => {
114
+ if (this.get(ix, iy, iz) !== EMPTY_VOXEL)
115
+ return;
116
+ this.set(ix, iy, iz, op.material);
117
+ filled += 1;
118
+ });
119
+ return filled;
120
+ }
121
+ }
122
+ function bowl(t) {
123
+ const s = t * t * (3 - 2 * t);
124
+ return s;
125
+ }
126
+ /**
127
+ * A `TerrainField` you can write craters and mounds into at runtime — the height-field side of
128
+ * destructible terrain (Helldivers 2 explosion craters, engineer-deposited berms). Wraps a base field
129
+ * and layers smooth radial deformations on top, so `sampleHeight` (and therefore ground-snap,
130
+ * collision, and the shell's terrain mesh) all read the deformed surface. `carve` digs a bowl,
131
+ * `deposit` raises a mound.
132
+ */
133
+ export class CarvableField {
134
+ bounds;
135
+ waterLevel;
136
+ sampleNormal;
137
+ base;
138
+ edits = [];
139
+ constructor(base) {
140
+ this.base = base;
141
+ if (base.bounds !== undefined)
142
+ this.bounds = base.bounds;
143
+ if (base.waterLevel !== undefined)
144
+ this.waterLevel = base.waterLevel;
145
+ this.sampleNormal = withNormal((x, z) => this.sampleHeight(x, z));
146
+ }
147
+ get editCount() {
148
+ return this.edits.length;
149
+ }
150
+ sampleHeight(x, z) {
151
+ let h = this.base.sampleHeight(x, z);
152
+ for (let i = 0; i < this.edits.length; i += 1) {
153
+ const e = this.edits[i];
154
+ const dx = x - e.x;
155
+ const dz = z - e.z;
156
+ const d = Math.sqrt(dx * dx + dz * dz);
157
+ if (d >= e.radius)
158
+ continue;
159
+ h += e.delta * bowl(1 - d / e.radius);
160
+ }
161
+ return h;
162
+ }
163
+ carve(op) {
164
+ this.edits.push({ x: op.x, z: op.z, radius: op.radius, delta: -op.depth });
165
+ }
166
+ deposit(op) {
167
+ this.edits.push({ x: op.x, z: op.z, radius: op.radius, delta: op.height });
168
+ }
169
+ clear() {
170
+ this.edits.length = 0;
171
+ }
172
+ }
173
+ export function carvableTerrain(base) {
174
+ return new CarvableField(base);
175
+ }
@@ -0,0 +1,40 @@
1
+ export type ConnectorVec3 = readonly [number, number, number];
2
+ export interface ConnectorSocket {
3
+ id: string;
4
+ type: string;
5
+ offset: ConnectorVec3;
6
+ accepts?: readonly string[];
7
+ }
8
+ export interface ConnectorPieceDef {
9
+ kind: string;
10
+ sockets: readonly ConnectorSocket[];
11
+ }
12
+ export interface PlacedPiece {
13
+ id: string;
14
+ kind: string;
15
+ position: ConnectorVec3;
16
+ rotationY: number;
17
+ }
18
+ export interface WorldSocket {
19
+ pieceId: string;
20
+ socket: ConnectorSocket;
21
+ position: ConnectorVec3;
22
+ }
23
+ export interface SnapResult {
24
+ socketId: string;
25
+ targetPieceId: string;
26
+ targetSocketId: string;
27
+ position: ConnectorVec3;
28
+ rotationY: number;
29
+ distance: number;
30
+ }
31
+ export interface SnapOptions {
32
+ snapDistance?: number;
33
+ rotationY?: number;
34
+ }
35
+ export declare function socketsCompatible(a: ConnectorSocket, b: ConnectorSocket): boolean;
36
+ export declare function socketWorldPosition(socket: ConnectorSocket, origin: ConnectorVec3, rotationY: number): ConnectorVec3;
37
+ export declare function worldSockets(def: ConnectorPieceDef, piece: PlacedPiece): WorldSocket[];
38
+ export type ConnectorRegistry = (kind: string) => ConnectorPieceDef | null;
39
+ export declare function collectWorldSockets(registry: ConnectorRegistry, pieces: readonly PlacedPiece[]): WorldSocket[];
40
+ export declare function snapToNearest(registry: ConnectorRegistry, placed: readonly PlacedPiece[], movingDef: ConnectorPieceDef, cursor: ConnectorVec3, options?: SnapOptions): SnapResult | null;
@@ -0,0 +1,67 @@
1
+ export function socketsCompatible(a, b) {
2
+ const aAccepts = a.accepts ?? [a.type];
3
+ const bAccepts = b.accepts ?? [b.type];
4
+ return aAccepts.includes(b.type) && bAccepts.includes(a.type);
5
+ }
6
+ function rotateY(offset, rotationY) {
7
+ if (rotationY === 0)
8
+ return offset;
9
+ const cos = Math.cos(rotationY);
10
+ const sin = Math.sin(rotationY);
11
+ return [offset[0] * cos + offset[2] * sin, offset[1], -offset[0] * sin + offset[2] * cos];
12
+ }
13
+ export function socketWorldPosition(socket, origin, rotationY) {
14
+ const rotated = rotateY(socket.offset, rotationY);
15
+ return [origin[0] + rotated[0], origin[1] + rotated[1], origin[2] + rotated[2]];
16
+ }
17
+ export function worldSockets(def, piece) {
18
+ return def.sockets.map((socket) => ({
19
+ pieceId: piece.id,
20
+ socket,
21
+ position: socketWorldPosition(socket, piece.position, piece.rotationY),
22
+ }));
23
+ }
24
+ export function collectWorldSockets(registry, pieces) {
25
+ const out = [];
26
+ for (const piece of pieces) {
27
+ const def = registry(piece.kind);
28
+ if (def === null)
29
+ continue;
30
+ for (const world of worldSockets(def, piece))
31
+ out.push(world);
32
+ }
33
+ return out;
34
+ }
35
+ export function snapToNearest(registry, placed, movingDef, cursor, options = {}) {
36
+ const snapDistance = options.snapDistance ?? 1.5;
37
+ const rotationY = options.rotationY ?? 0;
38
+ const targets = collectWorldSockets(registry, placed);
39
+ let best = null;
40
+ for (const socket of movingDef.sockets) {
41
+ const socketWorld = socketWorldPosition(socket, cursor, rotationY);
42
+ for (const target of targets) {
43
+ if (!socketsCompatible(socket, target.socket))
44
+ continue;
45
+ const distance = Math.hypot(socketWorld[0] - target.position[0], socketWorld[1] - target.position[1], socketWorld[2] - target.position[2]);
46
+ if (distance > snapDistance)
47
+ continue;
48
+ if (best !== null && distance >= best.distance)
49
+ continue;
50
+ const localRotated = rotateY(socket.offset, rotationY);
51
+ const position = [
52
+ target.position[0] - localRotated[0],
53
+ target.position[1] - localRotated[1],
54
+ target.position[2] - localRotated[2],
55
+ ];
56
+ best = {
57
+ socketId: socket.id,
58
+ targetPieceId: target.pieceId,
59
+ targetSocketId: target.socket.id,
60
+ position,
61
+ rotationY,
62
+ distance,
63
+ };
64
+ }
65
+ }
66
+ return best;
67
+ }
@@ -0,0 +1,71 @@
1
+ import type { TerrainField } from "./terrain.js";
2
+ /** A sky-occluding footprint — a roof, dense canopy, a cave mouth. `shade` 0..1 = fraction of sky blocked. */
3
+ export interface OccluderRect {
4
+ x: number;
5
+ z: number;
6
+ w: number;
7
+ d: number;
8
+ shade?: number;
9
+ }
10
+ /** A localized warmth source — campfire, forge, geothermal vent. */
11
+ export interface HeatSource {
12
+ x: number;
13
+ z: number;
14
+ radius: number;
15
+ /** Degrees added at the center, falling to 0 at `radius`. */
16
+ strength: number;
17
+ }
18
+ export type ShadeProvider = readonly OccluderRect[] | ((x: number, z: number) => number);
19
+ export type ScalarField = number | ((x: number, z: number, time: number) => number);
20
+ export interface EnvironmentFieldConfig {
21
+ /** Game-seconds per day; drives the sun-elevation cycle. Default matches the sim clock day. */
22
+ dayLength?: number;
23
+ /** Temperature at sea level under a noon sun with no weather. Default 20. */
24
+ baseTemperature?: number;
25
+ /** Degrees colder at deep night vs noon. Default 12. */
26
+ nightDrop?: number;
27
+ /** Degrees lost per world-height unit above `seaLevel` (altitude lapse). Default 0. */
28
+ altitudeLapse?: number;
29
+ seaLevel?: number;
30
+ /** Terrain field used to look up ground altitude when a caller omits `y`. */
31
+ terrain?: TerrainField;
32
+ /** Rain/precipitation intensity 0..1 at a position — from a weather state. Default 0. */
33
+ rain?: ScalarField;
34
+ /** Sky occluders (structures, canopy) that block sun and shelter from rain. */
35
+ occluders?: ShadeProvider;
36
+ /** Campfires and other warmth emitters. */
37
+ heatSources?: readonly HeatSource[];
38
+ /** Minimum ambient light at night (moonlight floor), 0..1. Default 0.05. */
39
+ ambientFloor?: number;
40
+ /** Per-position base-temperature offset (biome map). Added to `baseTemperature`. */
41
+ temperatureAt?: (x: number, z: number) => number;
42
+ }
43
+ export interface EnvironmentSample {
44
+ /** Degrees (game units). */
45
+ temperature: number;
46
+ /** 0..1 surface wetness. */
47
+ wetness: number;
48
+ /** 0..1 direct sun/sky exposure — full sun open sky = 1, deep shade/night = 0. */
49
+ lightExposure: number;
50
+ /** 0..1 overall light level for spawn gating — includes ambient/moonlight. */
51
+ ambientLight: number;
52
+ /** Under an occluder (roof/canopy) enough to shelter from rain. */
53
+ sheltered: boolean;
54
+ }
55
+ export interface EnvironmentField {
56
+ sample(x: number, z: number, time: number, y?: number): EnvironmentSample;
57
+ temperature(x: number, z: number, time: number, y?: number): number;
58
+ wetness(x: number, z: number, time: number): number;
59
+ lightExposure(x: number, z: number, time: number): number;
60
+ ambientLight(x: number, z: number, time: number): number;
61
+ /** Sun elevation -1..1 (1 = noon overhead, 0 = horizon, negative = night). */
62
+ sunElevation(time: number): number;
63
+ }
64
+ /**
65
+ * A sampleable environment field: read temperature, wetness, sun/sky exposure, and
66
+ * ambient light at any world position and time. Built on the same renderer-free footing
67
+ * as terrain/wind/water so meters, spawn gating, and damage-in-sunlight read the world
68
+ * the shell renders — no three.js. Instantaneous and pure (no accumulation); stateful
69
+ * build-up belongs to a decay meter reading this field.
70
+ */
71
+ export declare function createEnvironmentField(config?: EnvironmentFieldConfig): EnvironmentField;
@@ -0,0 +1,96 @@
1
+ import { SECONDS_PER_GAME_DAY } from "../time/gameClock.js";
2
+ function clamp01(value) {
3
+ return value < 0 ? 0 : value > 1 ? 1 : value;
4
+ }
5
+ function resolveScalar(field, x, z, time) {
6
+ return typeof field === "function" ? field(x, z, time) : field;
7
+ }
8
+ function pointInRect(rect, x, z) {
9
+ return (x >= rect.x - rect.w / 2 &&
10
+ x <= rect.x + rect.w / 2 &&
11
+ z >= rect.z - rect.d / 2 &&
12
+ z <= rect.z + rect.d / 2);
13
+ }
14
+ function resolveShade(provider, x, z) {
15
+ if (provider === undefined)
16
+ return 0;
17
+ if (typeof provider === "function")
18
+ return clamp01(provider(x, z));
19
+ let shade = 0;
20
+ for (const rect of provider) {
21
+ if (pointInRect(rect, x, z))
22
+ shade = Math.max(shade, rect.shade ?? 1);
23
+ }
24
+ return shade;
25
+ }
26
+ /**
27
+ * A sampleable environment field: read temperature, wetness, sun/sky exposure, and
28
+ * ambient light at any world position and time. Built on the same renderer-free footing
29
+ * as terrain/wind/water so meters, spawn gating, and damage-in-sunlight read the world
30
+ * the shell renders — no three.js. Instantaneous and pure (no accumulation); stateful
31
+ * build-up belongs to a decay meter reading this field.
32
+ */
33
+ export function createEnvironmentField(config = {}) {
34
+ const dayLength = config.dayLength !== undefined && config.dayLength > 0 ? config.dayLength : SECONDS_PER_GAME_DAY;
35
+ const baseTemperature = config.baseTemperature ?? 20;
36
+ const nightDrop = config.nightDrop ?? 12;
37
+ const altitudeLapse = config.altitudeLapse ?? 0;
38
+ const seaLevel = config.seaLevel ?? 0;
39
+ const ambientFloor = clamp01(config.ambientFloor ?? 0.05);
40
+ const heatSources = config.heatSources ?? [];
41
+ const sunElevation = (time) => {
42
+ const dayFraction = ((time % dayLength) + dayLength) % dayLength / dayLength;
43
+ return Math.sin((dayFraction - 0.25) * 2 * Math.PI);
44
+ };
45
+ const heatAt = (x, z) => {
46
+ let heat = 0;
47
+ for (const source of heatSources) {
48
+ const distance = Math.hypot(x - source.x, z - source.z);
49
+ if (distance >= source.radius)
50
+ continue;
51
+ heat += source.strength * (1 - distance / source.radius);
52
+ }
53
+ return heat;
54
+ };
55
+ const rainAt = (x, z, time) => config.rain === undefined ? 0 : clamp01(resolveScalar(config.rain, x, z, time));
56
+ const wetness = (x, z, time) => {
57
+ const shade = resolveShade(config.occluders, x, z);
58
+ return clamp01(rainAt(x, z, time) * (1 - shade));
59
+ };
60
+ const lightExposure = (x, z, time) => {
61
+ const shade = resolveShade(config.occluders, x, z);
62
+ const daylight = Math.max(0, sunElevation(time));
63
+ const cloud = 1 - rainAt(x, z, time) * 0.6;
64
+ return clamp01(daylight * cloud * (1 - shade));
65
+ };
66
+ const ambientLight = (x, z, time) => {
67
+ const shade = resolveShade(config.occluders, x, z);
68
+ const daylight = clamp01(sunElevation(time) * 0.5 + 0.5);
69
+ const sky = ambientFloor + (1 - ambientFloor) * daylight;
70
+ return clamp01(sky * (1 - shade * 0.75));
71
+ };
72
+ const temperature = (x, z, time, y) => {
73
+ const altitude = y ?? config.terrain?.sampleHeight(x, z) ?? seaLevel;
74
+ const daylight = clamp01(sunElevation(time) * 0.5 + 0.5);
75
+ const base = baseTemperature + (config.temperatureAt?.(x, z) ?? 0);
76
+ const lapse = altitudeLapse * Math.max(0, altitude - seaLevel);
77
+ const wetChill = wetness(x, z, time) * 4;
78
+ return base - nightDrop * (1 - daylight) - lapse - wetChill + heatAt(x, z);
79
+ };
80
+ return {
81
+ sample(x, z, time, y) {
82
+ return {
83
+ temperature: temperature(x, z, time, y),
84
+ wetness: wetness(x, z, time),
85
+ lightExposure: lightExposure(x, z, time),
86
+ ambientLight: ambientLight(x, z, time),
87
+ sheltered: resolveShade(config.occluders, x, z) >= 0.5,
88
+ };
89
+ },
90
+ temperature,
91
+ wetness,
92
+ lightExposure,
93
+ ambientLight,
94
+ sunElevation,
95
+ };
96
+ }
@@ -0,0 +1,53 @@
1
+ import { type GeneratedBuilding } from "./buildings.js";
2
+ import type { BuildingEnvironmentDescriptor, EnvironmentWorldFeature, WorldBounds } from "./features.js";
3
+ import type { Aabb } from "./geometry.js";
4
+ export declare function resolveStructureBuildings(descriptor: BuildingEnvironmentDescriptor): GeneratedBuilding[];
5
+ export interface TerrainHeightStats {
6
+ min: number;
7
+ max: number;
8
+ mean: number;
9
+ finite: boolean;
10
+ }
11
+ export interface TerrainSummary {
12
+ bounds: WorldBounds;
13
+ height: TerrainHeightStats;
14
+ waterLevel?: number;
15
+ }
16
+ export interface StructureSummary {
17
+ style: string;
18
+ requested: number;
19
+ buildings: number;
20
+ parts: number;
21
+ bounds: Aabb;
22
+ }
23
+ export interface VegetationSummary {
24
+ area: WorldBounds;
25
+ density: number;
26
+ }
27
+ export interface WaterSummary {
28
+ level: number;
29
+ bounds: WorldBounds;
30
+ }
31
+ export interface WeatherSummary {
32
+ kind: "rain" | "snow";
33
+ density: number;
34
+ }
35
+ export interface EnvironmentCounts {
36
+ terrain: number;
37
+ structureGroups: number;
38
+ buildings: number;
39
+ buildingParts: number;
40
+ vegetationFields: number;
41
+ waterBodies: number;
42
+ weatherSystems: number;
43
+ }
44
+ export interface EnvironmentSummary {
45
+ terrain?: TerrainSummary;
46
+ structures: readonly StructureSummary[];
47
+ vegetation: readonly VegetationSummary[];
48
+ water: readonly WaterSummary[];
49
+ weather: readonly WeatherSummary[];
50
+ counts: EnvironmentCounts;
51
+ isEmpty: boolean;
52
+ }
53
+ export declare function summarizeEnvironment(feature: EnvironmentWorldFeature): EnvironmentSummary;