@daneren2005/shared-memory-physics 1.6.1 → 1.6.3

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/README.md CHANGED
@@ -328,12 +328,11 @@ frame instead, by blending between the two positions physics published either si
328
328
  render = prev + (current - prev) * alpha
329
329
  ```
330
330
 
331
- Every position it writes is therefore one the simulation actually produced - somewhere on the segment between
332
- two real ones, never a guess past the end of one. There is nothing to tune and no case where it draws something
333
- that did not happen: an entity that stopped against a wall is drawn easing into the wall and stopping, and one
334
- that turned a corner is drawn turning the corner rather than carrying on into its old heading for a frame and
335
- being snapped back. The cost is **one step of latency, always** - what is on screen is where the world was a
336
- step ago.
331
+ Normally every position it writes lies on the latest simulation segment. If worker scheduling lets several
332
+ publications overtake rendering, it coalesces the unfinished path from the current render position to the latest
333
+ transform while preserving all published simulated time. That can cut across intermediate turns whose segments
334
+ were overwritten, but it never extrapolates past the simulation and never teleports to a replacement segment's
335
+ start. The cost is at least one step of latency - plus any time the worker itself falls behind.
337
336
 
338
337
  ```ts
339
338
  import { InterpolationSystem, PhysicsSystem } from '@daneren2005/shared-memory-physics';
@@ -346,7 +345,9 @@ world.loadEntity({ x: 0, y: 0, width: 10, height: 10, velocityX: 100, interpolat
346
345
 
347
346
  It takes no configuration and is not wired to the physics system. Everything it needs - the two positions, how
348
347
  much simulated time lies between them, and whether that pair is new - is published into the block by whichever
349
- run wrote it, so a game that retunes `deltaBetweenRuns` mid-flight is followed with nothing told to this system.
348
+ run wrote it. Physics marks that publication dirty before changing either endpoint and stamps it complete only
349
+ after both are ready, so rendering holds its previous position for a frame if it catches the worker mid-write.
350
+ A game that retunes `deltaBetweenRuns` mid-flight is followed with nothing told to this system.
350
351
 
351
352
  Then draw from `interpolation` instead of `transform`, keeping the size and facing where they have always been:
352
353
 
@@ -381,9 +382,10 @@ the accumulator says "0.3 of the way into the new step" while the block still ho
381
382
  entity is drawn 0.3 along a segment it was drawn 0.96 along last frame. Backwards, then a lurch forward, on
382
383
  every step.
383
384
 
384
- For the same reason each run publishes **how much simulated time it covered** rather than that being assumed to
385
- be the step: a run that comes back late leaves more than a step's worth banked, and the next one covers two at
386
- once. Dividing that segment by the step would draw it at double speed.
385
+ For the same reason physics publishes both **how much simulated time the latest run covered** and a cumulative
386
+ total. A run that comes back late can cover several steps, then be replaced by a normal step before rendering has
387
+ finished drawing it. Interpolation takes the difference in cumulative time and adds it to its remaining render
388
+ timeline, so no overwritten duration turns into a forward jump.
387
389
 
388
390
  Ordering against the physics system is only a preference - after it means a step is picked up on the frame it
389
391
  happened rather than the one after, which is one frame of latency and nothing else.
@@ -480,7 +482,7 @@ spot, as above.
480
482
 
481
483
  ### The cost
482
484
 
483
- 32 bytes per interpolated entity, three extra writes per entity per physics step, and a per-frame pass of one
485
+ 44 bytes per interpolated entity, four extra writes per entity per physics step, and a per-frame pass of one
484
486
  lerp per entity on the main thread - order 0.2ms at 10,000 entities. An entity without the component pays
485
487
  nothing at all. `forceMainThread: false` plus a `getWorker` moves the pass to a worker for worlds large enough
486
488
  that it shows up in a profile, at the price of the render position being one frame stale; because consumers only
@@ -11,6 +11,9 @@ export interface InterpolationComponent {
11
11
  syncedTick: number;
12
12
  duration: number;
13
13
  tick: number;
14
+ totalDuration: number;
15
+ syncedDuration: number;
16
+ remainingDuration: number;
14
17
  }
15
18
  export interface InterpolationConfig {
16
19
  interpolate?: boolean;
@@ -25,7 +28,10 @@ export declare const INTERPOLATION_PROGRESS_INDEX = 4;
25
28
  export declare const INTERPOLATION_SYNCED_TICK_INDEX = 5;
26
29
  export declare const INTERPOLATION_DURATION_INDEX = 6;
27
30
  export declare const INTERPOLATION_TICK_INDEX = 7;
28
- export declare const INTERPOLATION_SIZE = 8;
31
+ export declare const INTERPOLATION_TOTAL_DURATION_INDEX = 8;
32
+ export declare const INTERPOLATION_SYNCED_DURATION_INDEX = 9;
33
+ export declare const INTERPOLATION_REMAINING_DURATION_INDEX = 10;
34
+ export declare const INTERPOLATION_SIZE = 11;
29
35
  export declare const interpolationDefinition: ComponentDefinition<InterpolationComponent, Float32Array, InterpolationConfig>;
30
36
  export interface SnappableEntity {
31
37
  components: {
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@ export { default as bouncinessDefinition } from './components/bounciness-compone
17
17
  export { BOUNCINESS_INDEX, BOUNCINESS_SIZE, } from './components/bounciness-component';
18
18
  export type { BouncinessComponent, BouncinessConfig, } from './components/bounciness-component';
19
19
  export { default as interpolationDefinition, snapEntity, startSpawnInterpolation } from './components/interpolation-component';
20
- export { INTERPOLATION_X_INDEX, INTERPOLATION_Y_INDEX, INTERPOLATION_PREV_X_INDEX, INTERPOLATION_PREV_Y_INDEX, INTERPOLATION_PROGRESS_INDEX, INTERPOLATION_SYNCED_TICK_INDEX, INTERPOLATION_DURATION_INDEX, INTERPOLATION_TICK_INDEX, INTERPOLATION_SIZE, } from './components/interpolation-component';
20
+ export { INTERPOLATION_X_INDEX, INTERPOLATION_Y_INDEX, INTERPOLATION_PREV_X_INDEX, INTERPOLATION_PREV_Y_INDEX, INTERPOLATION_PROGRESS_INDEX, INTERPOLATION_SYNCED_TICK_INDEX, INTERPOLATION_DURATION_INDEX, INTERPOLATION_TICK_INDEX, INTERPOLATION_TOTAL_DURATION_INDEX, INTERPOLATION_SYNCED_DURATION_INDEX, INTERPOLATION_REMAINING_DURATION_INDEX, INTERPOLATION_SIZE, } from './components/interpolation-component';
21
21
  export type { InterpolationComponent, InterpolationConfig, SnappableEntity, SpawnableEntity, SpawnInterpolationOptions, } from './components/interpolation-component';
22
22
  export { physicsRegistry } from './components/registry';
23
23
  export type { PhysicsComponents, PhysicsUpdateComponents, InterpolationComponents, InterpolationUpdateComponents, } from './components/registry';