@forgeax/engine-physics-rapier3d 0.1.32 → 0.1.34

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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state-reconcile.unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-reconcile.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/state-reconcile.unit.test.ts"],"names":[],"mappings":""}
package/dist/index.mjs CHANGED
@@ -1,38 +1,19 @@
1
1
  import { defineSystem, FixedTime, componentDefinition, Disabled, FixedUpdate } from '@forgeax/engine-ecs';
2
- import { componentId } from '@forgeax/engine-ecs/internal';
3
- import { readStructuralEvidence } from '@forgeax/engine-ecs/projection';
2
+ import { createStateProjection } from '@forgeax/engine-ecs/projection';
4
3
  import { vec3, quat, mat4 } from '@forgeax/engine-math';
5
4
  import { CollidingEntities, DerivedPhysicsError, cloneDerivedPhysicsInput, validateMassProperties, DERIVED_PHYSICS_LIMITS, estimateDerivedPhysicsInputBytes, preserveCenterOfMassVelocity, PhysicsError, PHYSICS_ERROR_HINTS, CharacterController, rigidBodyTypeFromF32, RigidBody, Collider, colliderShapeFromF32, RIGID_BODY_TYPE_STATIC, registerPhysicsComponents, PhysicsSet } from '@forgeax/engine-physics';
6
5
  import { ChildOf } from '@forgeax/engine-scene';
7
6
  import { err, ok, PhysicsError as PhysicsError$1 } from '@forgeax/engine-types';
8
7
 
9
8
  // 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;
9
+ function samePhysicsValue(left, right) {
10
+ if (Object.is(left, right)) return true;
11
+ if (left === void 0 || right === void 0 || left === null || right === null || typeof left !== "object" || typeof right !== "object")
12
+ return false;
13
+ const a = left;
14
+ const b = right;
15
+ const keys = Object.keys(a);
16
+ return keys.length === Object.keys(b).length && keys.every((key) => samePhysicsValue(a[key], b[key]));
36
17
  }
37
18
  var DEG_TO_RAD = Math.PI / 180;
38
19
  function applyKccTuning(ctrl, cc) {
@@ -2038,61 +2019,6 @@ var RapierPhysicsWorld3D = class {
2038
2019
  }
2039
2020
  this.removeKccController(entity);
2040
2021
  }
2041
- resetForFullReconcile(transformlessStatic) {
2042
- for (const entity of [...this.entityMap.keys()]) {
2043
- if (transformlessStatic.has(entity) && this.isCommittedFixedBody(entity)) {
2044
- this.removeKccController(entity);
2045
- continue;
2046
- }
2047
- this.removeEntity(entity);
2048
- }
2049
- }
2050
- fullReconcilePhysicsState(state) {
2051
- const descriptors = [];
2052
- const transformlessStatic = /* @__PURE__ */ new Set();
2053
- const committedDerived = this.derivedBodies.size > 0 ? this.captureDerivedPhysicsState() : void 0;
2054
- for (const query of state.queries)
2055
- for (const row of query) {
2056
- if (!row.has(state.transformComponent)) {
2057
- if (physicsRowIsStatic(row)) transformlessStatic.add(row.entity);
2058
- continue;
2059
- }
2060
- const descriptor = readPhysicsSyncDescriptor(
2061
- row,
2062
- state.transformComponent,
2063
- state.globalTransformComponent
2064
- );
2065
- if (descriptor !== void 0) descriptors.push(descriptor);
2066
- }
2067
- this.resetForFullReconcile(transformlessStatic);
2068
- for (const descriptor of descriptors) {
2069
- this.ensureBody(
2070
- descriptor.entity,
2071
- descriptor.transform,
2072
- descriptor.rigidBody,
2073
- descriptor.collider
2074
- );
2075
- }
2076
- if (committedDerived !== void 0) {
2077
- const restorableBodies = committedDerived.bodies.filter(
2078
- (body) => this.entityMap.has(body.entity) && !this.derivedBodies.has(body.entity)
2079
- );
2080
- if (restorableBodies.length > 0) {
2081
- const restorable = Object.freeze({
2082
- ...committedDerived,
2083
- bodies: Object.freeze(restorableBodies)
2084
- });
2085
- const restored = this.restoreDerivedPhysicsState(restorable);
2086
- if (!restored.ok) {
2087
- this.invalidateDerivedShapeCandidates("full-reconcile-restore-failed");
2088
- }
2089
- }
2090
- }
2091
- drainPhysicsChangeQueries(state.changeQueries);
2092
- state.structuralCursor = readStructuralEvidence(state.world, state.structuralCursor).cursor;
2093
- state.structureEpoch = state.world.getStructureEpoch();
2094
- state.initialized = true;
2095
- }
2096
2022
  reconcilePhysicsDelta(state, entity, delta) {
2097
2023
  const row = state.queries.map((query) => query.at(entity)).find((entry) => entry !== void 0);
2098
2024
  if (row === void 0) {
@@ -2218,83 +2144,64 @@ var RapierPhysicsWorld3D = class {
2218
2144
  transformComponent,
2219
2145
  globalTransformComponent,
2220
2146
  queries: [queryResult.value, bodyQuery.value],
2221
- changeQueries: createPhysicsChangeQueries(world, [
2222
- transformComponent,
2223
- globalTransformComponent,
2224
- Collider,
2225
- RigidBody,
2226
- CharacterController,
2227
- ChildOf
2228
- ]),
2229
- structuralCursor: readStructuralEvidence(world, 0).cursor,
2230
- structureEpoch: world.getStructureEpoch(),
2231
- initialized: false
2147
+ projection: createStateProjection(
2148
+ world,
2149
+ [
2150
+ transformComponent,
2151
+ globalTransformComponent,
2152
+ Collider,
2153
+ RigidBody,
2154
+ CharacterController,
2155
+ ChildOf,
2156
+ Disabled
2157
+ ],
2158
+ [Collider, RigidBody]
2159
+ ),
2160
+ accepted: /* @__PURE__ */ new Map()
2232
2161
  };
2233
2162
  this.syncState = state;
2234
2163
  }
2235
- if (!state.initialized) {
2236
- this.fullReconcilePhysicsState(state);
2237
- return;
2238
- }
2239
- const deltas = /* @__PURE__ */ new Map();
2240
- if (state.structureEpoch !== world.getStructureEpoch()) {
2241
- const structural = readStructuralEvidence(world, state.structuralCursor);
2242
- state.structuralCursor = structural.cursor;
2243
- state.structureEpoch = world.getStructureEpoch();
2244
- if (structural.status === "overflow") {
2245
- this.fullReconcilePhysicsState(state);
2246
- return;
2164
+ const batch = state.projection.read();
2165
+ const updates = [];
2166
+ for (const index of batch.indices) {
2167
+ const entity = state.projection.entity(index);
2168
+ const previous = state.accepted.get(index);
2169
+ if (previous !== void 0 && previous.entity !== entity) this.removeEntity(previous.entity);
2170
+ if (entity === void 0) {
2171
+ updates.push({ index, descriptor: void 0 });
2172
+ continue;
2247
2173
  }
2248
- const transformId = componentId(transformComponent);
2249
- const globalTransformId = componentId(globalTransformComponent);
2250
- const colliderId = componentId(Collider);
2251
- const rigidBodyId = componentId(RigidBody);
2252
- const characterControllerId = componentId(CharacterController);
2253
- const childOfId = componentId(ChildOf);
2254
- const disabledId = componentId(Disabled);
2255
- for (const evidence of structural.events) {
2256
- const id = evidence.componentId;
2257
- if (evidence.kind !== "spawn" && evidence.kind !== "despawn" && id !== transformId && id !== globalTransformId && id !== colliderId && id !== rigidBodyId && id !== characterControllerId && id !== childOfId && id !== disabledId) {
2258
- continue;
2259
- }
2260
- const delta = ensurePhysicsDelta(deltas, evidence.entity);
2261
- if (evidence.kind === "spawn" || evidence.kind === "despawn") {
2262
- delta.transformChanged = true;
2263
- delta.colliderChanged = true;
2264
- delta.rigidBodyChanged = true;
2265
- delta.characterControllerChanged = true;
2266
- delta.characterControllerStructureChanged = true;
2267
- } else if (id === transformId || id === globalTransformId || id === childOfId) {
2268
- delta.transformChanged = true;
2269
- } else if (id === colliderId || id === disabledId) {
2270
- delta.colliderChanged = true;
2271
- } else if (id === rigidBodyId) {
2272
- delta.rigidBodyChanged = true;
2273
- } else if (id === characterControllerId) {
2274
- delta.characterControllerChanged = true;
2275
- delta.characterControllerStructureChanged = true;
2276
- }
2174
+ let row;
2175
+ for (const query of state.queries) {
2176
+ row = query.at(entity);
2177
+ if (row !== void 0) break;
2277
2178
  }
2278
- }
2279
- for (const entry of state.changeQueries) {
2280
- for (const span of entry.query.spans().unwrap()) {
2281
- for (const rawEntity of span.entities) {
2282
- const entity = rawEntity;
2283
- const delta = ensurePhysicsDelta(deltas, entity);
2284
- if (entry.component === transformComponent || entry.component === globalTransformComponent || entry.component === ChildOf) {
2285
- delta.transformChanged = true;
2286
- } else if (entry.component === Collider) {
2287
- delta.colliderChanged = true;
2288
- } else if (entry.component === RigidBody) {
2289
- delta.rigidBodyChanged = true;
2290
- } else if (entry.component === CharacterController) {
2291
- delta.characterControllerChanged = true;
2292
- }
2293
- }
2179
+ if (row === void 0) {
2180
+ this.removeEntity(entity);
2181
+ updates.push({ index, descriptor: void 0 });
2182
+ continue;
2294
2183
  }
2184
+ const descriptor = readPhysicsSyncDescriptor(
2185
+ row,
2186
+ transformComponent,
2187
+ globalTransformComponent
2188
+ );
2189
+ const prior = previous?.entity === entity ? previous : void 0;
2190
+ const delta = {
2191
+ transformChanged: !samePhysicsValue(prior?.transform, descriptor?.transform),
2192
+ colliderChanged: descriptor === void 0 ? state.projection.changed(entity, Collider) : !samePhysicsValue(prior?.collider, descriptor.collider),
2193
+ rigidBodyChanged: descriptor === void 0 ? state.projection.changed(entity, RigidBody) : !samePhysicsValue(prior?.rigidBody, descriptor.rigidBody),
2194
+ characterControllerChanged: prior?.characterControllerOffset !== descriptor?.characterControllerOffset || prior?.hasCharacterController !== descriptor?.hasCharacterController,
2195
+ characterControllerStructureChanged: prior?.hasCharacterController !== descriptor?.hasCharacterController
2196
+ };
2197
+ this.reconcilePhysicsDelta(state, entity, delta);
2198
+ updates.push({ index, descriptor: descriptor ?? (this.hasBody(entity) ? prior : void 0) });
2199
+ }
2200
+ batch.accept();
2201
+ for (const { index, descriptor } of updates) {
2202
+ if (descriptor === void 0) state.accepted.delete(index);
2203
+ else state.accepted.set(index, descriptor);
2295
2204
  }
2296
- if (deltas.size === 0) return;
2297
- for (const [entity, delta] of deltas) this.reconcilePhysicsDelta(state, entity, delta);
2298
2205
  }
2299
2206
  /**
2300
2207
  * Remove an entity's cached KCC and unregister it from the Rapier world