lecodes-cli 0.18.0 → 0.18.2

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 (62) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +2013 -564
  3. package/package.json +4 -4
  4. package/runtime/scene-harness.json +1 -1
  5. package/runtime/sdk/core/Aspect.ts +512 -255
  6. package/runtime/sdk/core/compWrite.ts +42 -0
  7. package/runtime/sdk/core/fields.ts +1 -1
  8. package/runtime/sdk/core/time.ts +81 -0
  9. package/runtime/sdk/g2/Camera2D.ts +8 -1
  10. package/runtime/sdk/g2/CharacterController2D.ts +253 -53
  11. package/runtime/sdk/g2/Node2D.ts +80 -10
  12. package/runtime/sdk/g2/OneWay2D.ts +66 -0
  13. package/runtime/sdk/g2/Physics2D.ts +240 -30
  14. package/runtime/sdk/g2/Scene2D.ts +33 -1
  15. package/runtime/sdk/g2/Shape2D.ts +218 -22
  16. package/runtime/sdk/g2/Trigger2D.ts +42 -12
  17. package/runtime/sdk/g2/groups2d.ts +106 -0
  18. package/runtime/sdk/g2/loop.ts +15 -4
  19. package/runtime/sdk/gl/Camera.ts +40 -1
  20. package/runtime/sdk/gl/CameraPlace.ts +52 -51
  21. package/runtime/sdk/gl/CharacterController.ts +184 -56
  22. package/runtime/sdk/gl/Gearbox.ts +212 -0
  23. package/runtime/sdk/gl/Geometry.ts +70 -9
  24. package/runtime/sdk/gl/Light.ts +64 -2
  25. package/runtime/sdk/gl/Lightmap.ts +179 -0
  26. package/runtime/sdk/gl/Material.ts +25 -0
  27. package/runtime/sdk/gl/Mesh.ts +6 -23
  28. package/runtime/sdk/gl/Model.ts +16 -2
  29. package/runtime/sdk/gl/Node.ts +119 -39
  30. package/runtime/sdk/gl/Physics.ts +75 -24
  31. package/runtime/sdk/gl/Scene.ts +161 -5
  32. package/runtime/sdk/gl/Shape.ts +42 -3
  33. package/runtime/sdk/gl/Trigger.ts +45 -50
  34. package/runtime/sdk/gl/Vehicle.ts +276 -322
  35. package/runtime/sdk/gl/Wheel.ts +240 -0
  36. package/runtime/sdk/gl/scenarios.ts +4 -30
  37. package/runtime/sdk/gl/state.ts +6 -6
  38. package/runtime/sdk/inject.ts +186 -171
  39. package/runtime/sdk/runtime/device.ts +102 -1
  40. package/runtime/sdk/scene/defineScene.ts +108 -53
  41. package/runtime/sdk/scene/gizmos.ts +31 -11
  42. package/runtime/sdk/scene/material.ts +188 -0
  43. package/runtime/sdk-types.json +1 -1
  44. package/runtime/sdk/compile/aspectMacro.ts +0 -42
  45. package/runtime/sdk/compile/assetIconMacro.ts +0 -384
  46. package/runtime/sdk/compile/assetMacro.ts +0 -45
  47. package/runtime/sdk/compile/assetName.ts +0 -50
  48. package/runtime/sdk/compile/bundler.ts +0 -252
  49. package/runtime/sdk/compile/compileProject.ts +0 -129
  50. package/runtime/sdk/compile/detectEntry.ts +0 -128
  51. package/runtime/sdk/compile/fontMacro.ts +0 -459
  52. package/runtime/sdk/compile/fontRegistry.ts +0 -78
  53. package/runtime/sdk/compile/header.ts +0 -67
  54. package/runtime/sdk/compile/index.ts +0 -85
  55. package/runtime/sdk/compile/libraryImports.ts +0 -52
  56. package/runtime/sdk/compile/liteMaterial.ts +0 -247
  57. package/runtime/sdk/compile/sceneEditor.ts +0 -78
  58. package/runtime/sdk/compile/serverSplit.ts +0 -233
  59. package/runtime/sdk/compile/serverTypes.ts +0 -227
  60. package/runtime/sdk/compile/sfnt.ts +0 -98
  61. package/runtime/sdk/compile/shaderTargets.ts +0 -42
  62. package/runtime/sdk/compile/sourcemap.ts +0 -25
@@ -98,6 +98,8 @@ export class Shape extends Aspect<"shape", Node> {
98
98
  onDetach(): void {
99
99
  if (this._bodyId) { _creator.physicsRemoveBody(this._bodyId); this._bodyId = 0 }
100
100
  if (this._shapeId) { _creator.physicsDestroyShape(this._shapeId); this._shapeId = 0 }
101
+ this.node._xf = 0
102
+ this.node._xfKind = 0
101
103
  }
102
104
 
103
105
  /** Re-configuring (`node.aspect(Shape, { origin })`) rebuilds the geometry when a dimension, the
@@ -206,14 +208,20 @@ export class Shape extends Aspect<"shape", Node> {
206
208
 
207
209
  // ---- body/shape lifetime --------------------------------------------------------------------
208
210
 
209
- /** @internal Physics/Trigger take over: drop the pick body and hand back the shape id. */
211
+ /** @internal Physics/Trigger/CharacterController/Vehicle take over: drop the pick body and hand back
212
+ * the shape id. The node's transform owner goes with the body (the new owner sets its own). */
210
213
  _claim(): number {
211
214
  if (this._bodyId) { _creator.physicsRemoveBody(this._bodyId); this._bodyId = 0 }
215
+ this.node._xf = 0
216
+ this.node._xfKind = 0
212
217
  return this._shapeId
213
218
  }
214
- /** @internal Physics/Trigger report the body they created, so Shape owns its lifetime + pickability. */
219
+ /** @internal Physics/Trigger report the body they created, so Shape owns its lifetime + pickability.
220
+ * 0 = they are detaching and no longer own it. */
215
221
  _ownBody(bodyId: number): void {
216
222
  this._bodyId = bodyId
223
+ this.node._xf = bodyId // route node.position writes to the body (see Node._setOwnedPosition)
224
+ this.node._xfKind = bodyId ? 2 : 0
217
225
  if (!this.raycast && bodyId) _creator.physicsSetPickable(bodyId, false)
218
226
  }
219
227
  /** @internal restore a pick-only body when Physics/Trigger detach but the Shape remains. */
@@ -223,6 +231,10 @@ export class Shape extends Aspect<"shape", Node> {
223
231
 
224
232
  private _createPickBody(): void {
225
233
  this._bodyId = _creator.physicsCreateBody(this.node.id, this._shapeId, 0, 0, false, /*pickOnly*/ true)
234
+ // Route position writes here too: the pick body is a static snapshot, so without this a moved node
235
+ // would keep taking its clicks at the old place.
236
+ this.node._xf = this._bodyId
237
+ this.node._xfKind = this._bodyId ? 2 : 0
226
238
  if (!this.raycast && this._bodyId) _creator.physicsSetPickable(this._bodyId, false)
227
239
  }
228
240
 
@@ -235,18 +247,45 @@ export class Shape extends Aspect<"shape", Node> {
235
247
  private _rebuild(): void {
236
248
  if (!this._shapeId) return // never attached, or a build without physics
237
249
  const previous = this._shapeId
250
+ const previousSig = this._sig
238
251
  const id = this._build()
239
252
  if (!id) return // build failed — keep what works
253
+
254
+ // A CharacterController owns its shape and can REFUSE the swap: standing up under a pipe doesn't
255
+ // fit. Nothing is half-applied on refusal, so the fix is to stay UNCOMMITTED — leave `_sig` on the
256
+ // old geometry, and the next `node.aspect(Shape, …)` with the same dimensions sees a difference
257
+ // and tries again. That retry is the headroom test, and it is exact (the real capsule, not a ray).
258
+ const charId = this.node._xfKind === 1 ? this.node._xf : 0
259
+ if (charId) {
260
+ if (_creator.characterSetShape?.(charId, id)) {
261
+ this._shapeId = id
262
+ this._resizeRefused = false
263
+ _creator.physicsDestroyShape(previous)
264
+ } else {
265
+ _creator.physicsDestroyShape(id) // drop what we just built; the old collider stays live
266
+ this._sig = previousSig
267
+ this._resizeRefused = !!_creator.characterSetShape
268
+ if (!_creator.characterSetShape) {
269
+ console.warn(`Shape: this host can't resize a live CharacterController — "${this.node.name}" keeps its current collider`)
270
+ }
271
+ }
272
+ return
273
+ }
274
+
240
275
  this._shapeId = id
241
276
  if (this._bodyId) {
242
277
  if (_creator.physicsSetBodyShape) _creator.physicsSetBodyShape(this._bodyId, id, true)
243
278
  else console.warn("Shape: this host can't re-shape a live body — the new dimensions apply from the next attach")
244
279
  } else {
245
- console.warn(`Shape: "${this.node.name}"'s geometry is owned by a CharacterController / Vehicle — re-attach it to pick up the new dimensions`)
280
+ console.warn(`Shape: "${this.node.name}"'s geometry is owned by a Vehicle — re-attach it to pick up the new dimensions`)
246
281
  }
247
282
  _creator.physicsDestroyShape(previous)
248
283
  }
249
284
 
285
+ /** @internal True while a requested resize has been refused — the fields say one thing, the engine
286
+ * is still using another. Surfaced as `controller.resizing`. */
287
+ _resizeRefused = false
288
+
250
289
  private _build(): number {
251
290
  this._autoOrigin = null
252
291
  this._sig = this._signature()
@@ -1,50 +1,45 @@
1
- // A trigger zone, as an aspect on a 3D Node. Requires a Shape (its geometry); creates a static SENSOR
2
- // body from it, so a physics body overlapping the zone fires the node's 'enter' / 'exit' events
3
- // instead of colliding. A trigger does not block movement, and is still pointer-pickable.
4
- //
5
- // const goal = new Mesh(box(), material)
6
- // .aspect(Shape, { box: [1, 2, 1] })
7
- // .aspect(Trigger)
8
- // goal.addEventListener('enter', other => win(other))
9
- // goal.addEventListener('exit', other => …)
10
-
11
- import { Aspect } from "../core/Aspect"
12
- import { cx, cy, cz, type Vec3Like } from "../math/vec"
13
- import { Shape } from "./Shape"
14
- import { ensurePhysicsEvents } from "./physicsEvents"
15
- import type { Node } from "./Node"
16
-
17
- export class Trigger extends Aspect<"trigger", Node> {
18
- static readonly aspect = "trigger"
19
-
20
- private _bodyId = 0
21
- /** Native body id (0 if no physics support). */
22
- get id(): number { return this._bodyId }
23
-
24
- onAttach(): void {
25
- if (!_creator.physicsHasSupport || !_creator.physicsHasSupport()) return
26
- const shape = this.node.get(Shape)
27
- if (!shape) {
28
- throw new Error("Trigger requires a Shape aspect — add it first: node.aspect(Shape, {…}).aspect(Trigger)")
29
- }
30
- const shapeId = shape._claim()
31
- this._bodyId = _creator.physicsCreateBody(this.node.id, shapeId, 0 /* static */, 0, true /* sensor */, false)
32
- shape._ownBody(this._bodyId)
33
- ensurePhysicsEvents() // routes overlap events → the node's 'enter' / 'exit'
34
- }
35
-
36
- onDetach(): void {
37
- if (this._bodyId) { _creator.physicsRemoveBody(this._bodyId); this._bodyId = 0 }
38
- const shape = this.node.get(Shape)
39
- if (shape) {
40
- shape._ownBody(0) // the Shape held OUR body id — forget it, or its own detach removes it twice (native crash)
41
- shape._recreatePickBody()
42
- }
43
- }
44
-
45
- /** Reposition the trigger zone to a world point. */
46
- moveTo(p: Vec3Like): this {
47
- if (this._bodyId) _creator.physicsSetBodyPosition(this._bodyId, cx(p), cy(p), cz(p))
48
- return this
49
- }
50
- }
1
+ // A trigger zone, as an aspect on a 3D Node. Requires a Shape (its geometry); creates a static SENSOR
2
+ // body from it, so a physics body overlapping the zone fires the node's 'enter' / 'exit' events
3
+ // instead of colliding. A trigger does not block movement, and is still pointer-pickable.
4
+ //
5
+ // const goal = new Mesh(box(), material)
6
+ // .aspect(Shape, { box: [1, 2, 1] })
7
+ // .aspect(Trigger)
8
+ // goal.addEventListener('enter', other => win(other))
9
+ // goal.addEventListener('exit', other => …)
10
+
11
+ import { Aspect } from "../core/Aspect"
12
+ import { Shape } from "./Shape"
13
+ import { ensurePhysicsEvents } from "./physicsEvents"
14
+ import type { Node } from "./Node"
15
+
16
+ export class Trigger extends Aspect<"trigger", Node> {
17
+ static readonly aspect = "trigger"
18
+
19
+ private _bodyId = 0
20
+ /** Native body id (0 if no physics support). */
21
+ get id(): number { return this._bodyId }
22
+
23
+ onAttach(): void {
24
+ if (!_creator.physicsHasSupport || !_creator.physicsHasSupport()) return
25
+ const shape = this.node.get(Shape)
26
+ if (!shape) {
27
+ throw new Error("Trigger requires a Shape aspect — add it first: node.aspect(Shape, {…}).aspect(Trigger)")
28
+ }
29
+ const shapeId = shape._claim()
30
+ this._bodyId = _creator.physicsCreateBody(this.node.id, shapeId, 0 /* static */, 0, true /* sensor */, false)
31
+ shape._ownBody(this._bodyId)
32
+ ensurePhysicsEvents() // routes overlap events → the node's 'enter' / 'exit'
33
+ }
34
+
35
+ onDetach(): void {
36
+ if (this._bodyId) { _creator.physicsRemoveBody(this._bodyId); this._bodyId = 0 }
37
+ const shape = this.node.get(Shape)
38
+ if (shape) {
39
+ shape._ownBody(0) // the Shape held OUR body id — forget it, or its own detach removes it twice (native crash)
40
+ shape._recreatePickBody()
41
+ }
42
+ }
43
+
44
+ // No moveTo(): `node.position = p` moves the node AND the sensor body it owns (see Node._xf).
45
+ }