@forgeax/engine-physics-rapier3d 0.1.20 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,11 +1,39 @@
1
1
  import { defineSystem, FixedTime, componentDefinition, Disabled, FixedUpdate } from '@forgeax/engine-ecs';
2
- import { createWorldProjection } from '@forgeax/engine-ecs/projection';
2
+ import { componentId } from '@forgeax/engine-ecs/internal';
3
+ import { readStructuralEvidence } from '@forgeax/engine-ecs/projection';
3
4
  import { vec3, quat, mat4 } from '@forgeax/engine-math';
4
5
  import { CollidingEntities, PhysicsError, PHYSICS_ERROR_HINTS, CharacterController, rigidBodyTypeFromF32, RigidBody, Collider, colliderShapeFromF32, RIGID_BODY_TYPE_STATIC, registerPhysicsComponents, PhysicsSet } from '@forgeax/engine-physics';
5
6
  import { ChildOf } from '@forgeax/engine-scene';
6
7
  import { PhysicsError as PhysicsError$1 } from '@forgeax/engine-types';
7
8
 
8
9
  // src/rapier-physics-world-3d.ts
10
+ function createPhysicsChangeQueries(world, components) {
11
+ return components.map((component) => {
12
+ const result = world.query({ changed: [component] });
13
+ if (!result.ok) throw result.error;
14
+ return { component, query: result.value };
15
+ });
16
+ }
17
+ function drainPhysicsChangeQueries(queries) {
18
+ for (const entry of queries) {
19
+ for (const _span of entry.query.spans().unwrap()) {
20
+ }
21
+ }
22
+ }
23
+ function ensurePhysicsDelta(deltas, entity) {
24
+ let delta = deltas.get(entity);
25
+ if (delta === void 0) {
26
+ delta = {
27
+ transformChanged: false,
28
+ colliderChanged: false,
29
+ rigidBodyChanged: false,
30
+ characterControllerChanged: false,
31
+ characterControllerStructureChanged: false
32
+ };
33
+ deltas.set(entity, delta);
34
+ }
35
+ return delta;
36
+ }
9
37
  var DEG_TO_RAD = Math.PI / 180;
10
38
  function applyKccTuning(ctrl, cc) {
11
39
  ctrl.setMaxSlopeClimbAngle(cc.maxSlopeClimbDeg * DEG_TO_RAD);
@@ -403,7 +431,11 @@ var RapierPhysicsWorld3D = class {
403
431
  if (physicsRowIsStatic(row)) transformlessStatic.add(row.entity);
404
432
  continue;
405
433
  }
406
- const descriptor = readPhysicsSyncDescriptor(row, state.transformComponent);
434
+ const descriptor = readPhysicsSyncDescriptor(
435
+ row,
436
+ state.transformComponent,
437
+ state.globalTransformComponent
438
+ );
407
439
  if (descriptor !== void 0) descriptors.push(descriptor);
408
440
  }
409
441
  this.resetForFullReconcile(transformlessStatic);
@@ -415,6 +447,9 @@ var RapierPhysicsWorld3D = class {
415
447
  descriptor.collider
416
448
  );
417
449
  }
450
+ drainPhysicsChangeQueries(state.changeQueries);
451
+ state.structuralCursor = readStructuralEvidence(state.world, state.structuralCursor).cursor;
452
+ state.structureEpoch = state.world.getStructureEpoch();
418
453
  state.initialized = true;
419
454
  }
420
455
  reconcilePhysicsDelta(state, entity, delta) {
@@ -431,7 +466,11 @@ var RapierPhysicsWorld3D = class {
431
466
  this.reconcileTransformlessCompatibility(entity, physicsRowIsStatic(row));
432
467
  return;
433
468
  }
434
- const descriptor = readPhysicsSyncDescriptor(row, state.transformComponent);
469
+ const descriptor = readPhysicsSyncDescriptor(
470
+ row,
471
+ state.transformComponent,
472
+ state.globalTransformComponent
473
+ );
435
474
  if (descriptor === void 0) {
436
475
  this.removeEntity(entity);
437
476
  return;
@@ -449,12 +488,14 @@ var RapierPhysicsWorld3D = class {
449
488
  const finalOffset = descriptor.characterControllerOffset;
450
489
  if (!descriptor.hasCharacterController) {
451
490
  this.removeKccController(entity);
452
- } else if (hadCachedReceipt && (delta.characterControllerRemoved || finalOffset === void 0 || !Object.is(cachedOffset, finalOffset))) {
491
+ } else if (hadCachedReceipt && (finalOffset === void 0 || !Object.is(cachedOffset, finalOffset))) {
453
492
  this.removeKccController(entity);
454
493
  if (finalOffset !== void 0) this.ensureKcc(entity, finalOffset);
455
494
  }
456
495
  }
457
- if (!delta.transformChanged && !delta.characterControllerRemoved) return;
496
+ if (!delta.transformChanged && !(delta.characterControllerStructureChanged && !descriptor.hasCharacterController)) {
497
+ return;
498
+ }
458
499
  const bodyType = rigidBodyTypeFromF32(descriptor.rigidBody.type);
459
500
  if (bodyType === "static") {
460
501
  this.syncAuthoredPose(entity, descriptor.transform, descriptor.collider, "static");
@@ -463,29 +504,37 @@ var RapierPhysicsWorld3D = class {
463
504
  }
464
505
  }
465
506
  /** @internal ECS system bridge; consumers should register PhysicsSyncBackend. */
466
- _syncFromEcs(world, transformComponent) {
507
+ _syncFromEcs(world, transformComponent, globalTransformComponent = world.components.resolve("GlobalTransform")) {
467
508
  this.assertActive("syncFromEcs");
509
+ if (globalTransformComponent === void 0) return;
468
510
  let state = this.syncState;
469
- if (state === void 0 || state.world !== world || state.transformComponent !== transformComponent) {
511
+ if (state === void 0 || state.world !== world || state.transformComponent !== transformComponent || state.globalTransformComponent !== globalTransformComponent) {
470
512
  const queryResult = world.query({
471
513
  read: [Collider],
472
- optional: [transformComponent, RigidBody, CharacterController, ChildOf]
514
+ optional: [
515
+ transformComponent,
516
+ globalTransformComponent,
517
+ RigidBody,
518
+ CharacterController,
519
+ ChildOf
520
+ ]
473
521
  });
474
522
  if (!queryResult.ok) return;
475
523
  state = {
476
524
  world,
477
525
  transformComponent,
526
+ globalTransformComponent,
478
527
  query: queryResult.value,
479
- projection: createWorldProjection(world, {
480
- components: [
481
- transformComponent,
482
- Collider,
483
- RigidBody,
484
- CharacterController,
485
- ChildOf,
486
- Disabled
487
- ]
488
- }),
528
+ changeQueries: createPhysicsChangeQueries(world, [
529
+ transformComponent,
530
+ globalTransformComponent,
531
+ Collider,
532
+ RigidBody,
533
+ CharacterController,
534
+ ChildOf
535
+ ]),
536
+ structuralCursor: readStructuralEvidence(world, 0).cursor,
537
+ structureEpoch: world.getStructureEpoch(),
489
538
  initialized: false
490
539
  };
491
540
  this.syncState = state;
@@ -494,46 +543,64 @@ var RapierPhysicsWorld3D = class {
494
543
  this.fullReconcilePhysicsState(state);
495
544
  return;
496
545
  }
497
- const evidence = state.projection.poll();
498
- if (evidence.status === "rebuild") {
499
- this.fullReconcilePhysicsState(state);
500
- return;
501
- }
502
- if (evidence.changes.length === 0) return;
503
546
  const deltas = /* @__PURE__ */ new Map();
504
- for (const change of evidence.changes) {
505
- let delta = deltas.get(change.entity);
506
- if (delta === void 0) {
507
- delta = {
508
- transformChanged: false,
509
- colliderChanged: false,
510
- rigidBodyChanged: false,
511
- characterControllerChanged: false,
512
- characterControllerRemoved: false
513
- };
514
- deltas.set(change.entity, delta);
515
- }
516
- if (change.kind === "entity-removed") continue;
517
- if (change.component === void 0) {
547
+ if (state.structureEpoch !== world.getStructureEpoch()) {
548
+ const structural = readStructuralEvidence(world, state.structuralCursor);
549
+ state.structuralCursor = structural.cursor;
550
+ state.structureEpoch = world.getStructureEpoch();
551
+ if (structural.status === "overflow") {
518
552
  this.fullReconcilePhysicsState(state);
519
553
  return;
520
554
  }
521
- if (change.component === transformComponent) {
522
- delta.transformChanged = true;
523
- } else if (change.component === Collider) {
524
- delta.colliderChanged = true;
525
- } else if (change.component === RigidBody) {
526
- delta.rigidBodyChanged = true;
527
- } else if (change.component === CharacterController) {
528
- delta.characterControllerChanged = true;
529
- if (change.kind === "component-removed") delta.characterControllerRemoved = true;
530
- } else if (change.component === ChildOf) {
531
- delta.transformChanged = true;
532
- } else if (change.component !== Disabled) {
533
- this.fullReconcilePhysicsState(state);
534
- return;
555
+ const transformId = componentId(transformComponent);
556
+ const globalTransformId = componentId(globalTransformComponent);
557
+ const colliderId = componentId(Collider);
558
+ const rigidBodyId = componentId(RigidBody);
559
+ const characterControllerId = componentId(CharacterController);
560
+ const childOfId = componentId(ChildOf);
561
+ const disabledId = componentId(Disabled);
562
+ for (const evidence of structural.events) {
563
+ const id = evidence.componentId;
564
+ if (evidence.kind !== "spawn" && evidence.kind !== "despawn" && id !== transformId && id !== globalTransformId && id !== colliderId && id !== rigidBodyId && id !== characterControllerId && id !== childOfId && id !== disabledId) {
565
+ continue;
566
+ }
567
+ const delta = ensurePhysicsDelta(deltas, evidence.entity);
568
+ if (evidence.kind === "spawn" || evidence.kind === "despawn") {
569
+ delta.transformChanged = true;
570
+ delta.colliderChanged = true;
571
+ delta.rigidBodyChanged = true;
572
+ delta.characterControllerChanged = true;
573
+ delta.characterControllerStructureChanged = true;
574
+ } else if (id === transformId || id === globalTransformId || id === childOfId) {
575
+ delta.transformChanged = true;
576
+ } else if (id === colliderId || id === disabledId) {
577
+ delta.colliderChanged = true;
578
+ } else if (id === rigidBodyId) {
579
+ delta.rigidBodyChanged = true;
580
+ } else if (id === characterControllerId) {
581
+ delta.characterControllerChanged = true;
582
+ delta.characterControllerStructureChanged = true;
583
+ }
584
+ }
585
+ }
586
+ for (const entry of state.changeQueries) {
587
+ for (const span of entry.query.spans().unwrap()) {
588
+ for (const rawEntity of span.entities) {
589
+ const entity = rawEntity;
590
+ const delta = ensurePhysicsDelta(deltas, entity);
591
+ if (entry.component === transformComponent || entry.component === globalTransformComponent || entry.component === ChildOf) {
592
+ delta.transformChanged = true;
593
+ } else if (entry.component === Collider) {
594
+ delta.colliderChanged = true;
595
+ } else if (entry.component === RigidBody) {
596
+ delta.rigidBodyChanged = true;
597
+ } else if (entry.component === CharacterController) {
598
+ delta.characterControllerChanged = true;
599
+ }
600
+ }
535
601
  }
536
602
  }
603
+ if (deltas.size === 0) return;
537
604
  for (const [entity, delta] of deltas) this.reconcilePhysicsDelta(state, entity, delta);
538
605
  }
539
606
  /**
@@ -763,13 +830,14 @@ function physicsRowIsStatic(row) {
763
830
  const rigidBody = row.get(RigidBody);
764
831
  return rigidBody !== void 0 && rigidBodyTypeFromF32(rigidBody.type) === "static";
765
832
  }
766
- function readPhysicsSyncDescriptor(row, transformComponent) {
833
+ function readPhysicsSyncDescriptor(row, transformComponent, globalTransformComponent) {
767
834
  const transformData = row.get(transformComponent);
835
+ const globalTransformData = row.get(globalTransformComponent);
768
836
  const colliderData = row.get(Collider);
769
837
  if (transformData === void 0 || colliderData === void 0) return void 0;
770
- const useWorldPose = row.has(ChildOf) && hasReadableWorldPose(transformData.world);
838
+ const useWorldPose = row.has(ChildOf) && hasReadableWorldPose(globalTransformData?.world);
771
839
  if (useWorldPose) {
772
- poseScratchWorld.set(transformData.world.subarray(0, 16));
840
+ poseScratchWorld.set(globalTransformData.world);
773
841
  mat4.decompose(poseScratchPosition, poseScratchRotation, poseScratchScale, poseScratchWorld);
774
842
  } else {
775
843
  poseScratchPosition[0] = transformData.pos[0] ?? 0;
@@ -853,7 +921,8 @@ var PhysicsSyncBackend = defineSystem({
853
921
  after: ["propagateTransformsFixed"],
854
922
  fn: (world) => {
855
923
  const transformComponent = resolveTransform(world);
856
- if (transformComponent === void 0) return;
924
+ const globalTransformComponent = world.components.resolve("GlobalTransform");
925
+ if (transformComponent === void 0 || globalTransformComponent === void 0) return;
857
926
  let pw;
858
927
  try {
859
928
  pw = world.getResource("PhysicsWorld");
@@ -861,7 +930,7 @@ var PhysicsSyncBackend = defineSystem({
861
930
  return;
862
931
  }
863
932
  pw.applyPendingTeleports();
864
- pw._syncFromEcs(world, transformComponent);
933
+ pw._syncFromEcs(world, transformComponent, globalTransformComponent);
865
934
  }
866
935
  });
867
936
  var PhysicsStepSimulation = defineSystem({