@series-inc/rundot-syncplay 5.26.0-beta.9 → 5.27.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.
- package/core/native/physics/physics.cpp +129 -3
- package/core/native/physics/physics.hpp +1 -1
- package/core/physics.d.ts +1 -0
- package/core/scripts/build-wasm-physics.mjs +1 -1
- package/core/src/physics/index.mjs +20 -9
- package/core/src/physics/physics-wasm-module.generated.mjs +4 -4
- package/dist/authority-room.d.ts +10 -0
- package/dist/authority-room.js +11 -0
- package/dist/browser.d.ts +5 -5
- package/dist/browser.js +3 -3
- package/dist/creator.d.ts +4 -4
- package/dist/creator.js +2 -2
- package/dist/dev-authority-room.js +8 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -3
- package/dist/input-authority.d.ts +8 -0
- package/dist/input-authority.js +13 -0
- package/dist/networked-client.d.ts +8 -0
- package/dist/networked-client.js +8 -0
- package/dist/node.d.ts +2 -0
- package/dist/node.js +1 -0
- package/dist/physics3d-voxel.d.ts +23 -1
- package/dist/physics3d-voxel.js +138 -0
- package/dist/physics3d.d.ts +26 -0
- package/dist/physics3d.js +187 -1
- package/dist/runtime-room-metadata.d.ts +47 -0
- package/dist/runtime-room-metadata.js +84 -0
- package/dist/session-snapshot.d.ts +24 -0
- package/dist/session-snapshot.js +24 -0
- package/package.json +4 -3
package/dist/authority-room.d.ts
CHANGED
|
@@ -179,6 +179,8 @@ export interface AuthorityRoomNetcodeStats {
|
|
|
179
179
|
readonly confirmedThrough: number;
|
|
180
180
|
/** Ticks in which each slot's input had to be substituted (cumulative). */
|
|
181
181
|
readonly substitutedTicksBySlot: Readonly<Record<number, number>>;
|
|
182
|
+
/** Slots with a seated player. Empty slots substitute every tick by design. */
|
|
183
|
+
readonly occupiedSlots: readonly number[];
|
|
182
184
|
readonly clientStats: Readonly<Record<number, AuthorityRoomClientNetStats>>;
|
|
183
185
|
/** Command requests dropped for seat, size, rate, sequence, or stale generation. */
|
|
184
186
|
readonly rejectedCommands: number;
|
|
@@ -239,6 +241,14 @@ export interface DeterministicAuthorityRoom {
|
|
|
239
241
|
* ticks, so this is idempotent.
|
|
240
242
|
*/
|
|
241
243
|
onPlayerReconnected(playerId: string): void;
|
|
244
|
+
/**
|
|
245
|
+
* A player's transport dropped and their seat entered the host's grace
|
|
246
|
+
* window. The slot stays reserved and keeps being substituted, so release
|
|
247
|
+
* the input they were holding — otherwise a player who drops mid-movement
|
|
248
|
+
* keeps moving until the grace window expires. Safe to call for a player
|
|
249
|
+
* with no slot (spectator, unknown id).
|
|
250
|
+
*/
|
|
251
|
+
onPlayerDisconnected(playerId: string): void;
|
|
242
252
|
/** Advance the authority by one server tick and broadcast newly-confirmed frames. */
|
|
243
253
|
onTick(): void;
|
|
244
254
|
/**
|
package/dist/authority-room.js
CHANGED
|
@@ -351,6 +351,11 @@ export function createDeterministicAuthorityRoom(transport, config) {
|
|
|
351
351
|
sendCatchUpTo(playerId, plan, 'join');
|
|
352
352
|
return true;
|
|
353
353
|
}
|
|
354
|
+
function onPlayerDisconnected(playerId) {
|
|
355
|
+
const slot = slotByPlayer.get(playerId);
|
|
356
|
+
if (slot !== undefined)
|
|
357
|
+
authority.neutralizeSlot(slot);
|
|
358
|
+
}
|
|
354
359
|
function onPlayerReconnected(playerId) {
|
|
355
360
|
// A spectator reconnect is a full re-greet: its timeline may have forked
|
|
356
361
|
// arbitrarily far and it holds no slot the redundancy window protects.
|
|
@@ -779,6 +784,10 @@ export function createDeterministicAuthorityRoom(transport, config) {
|
|
|
779
784
|
// departed player's input; their slot stays reserved because `assignedSlots` never decreases,
|
|
780
785
|
// so the authority substitutes for it rather than handing the number to a new joiner.
|
|
781
786
|
const slot = slotByPlayer.get(playerId);
|
|
787
|
+
// The slot stays reserved and keeps being substituted (see above), so
|
|
788
|
+
// release the departing player's last held input.
|
|
789
|
+
if (slot !== undefined)
|
|
790
|
+
authority.neutralizeSlot(slot);
|
|
782
791
|
slotByPlayer.delete(playerId);
|
|
783
792
|
if (slot !== undefined)
|
|
784
793
|
secretAuthority?.onPlayerLeft(playerId, slot);
|
|
@@ -853,6 +862,7 @@ export function createDeterministicAuthorityRoom(transport, config) {
|
|
|
853
862
|
onPlayerSecretMessage,
|
|
854
863
|
onPlayerLeave,
|
|
855
864
|
onPlayerReconnected,
|
|
865
|
+
onPlayerDisconnected,
|
|
856
866
|
onTick,
|
|
857
867
|
snapshot() {
|
|
858
868
|
return {
|
|
@@ -899,6 +909,7 @@ export function createDeterministicAuthorityRoom(transport, config) {
|
|
|
899
909
|
return {
|
|
900
910
|
confirmedThrough: authority.confirmedThrough,
|
|
901
911
|
substitutedTicksBySlot: Object.fromEntries(substitutedTicksBySlot),
|
|
912
|
+
occupiedSlots: [...slotByPlayer.values()].sort((a, b) => a - b),
|
|
902
913
|
clientStats: Object.fromEntries(clientNetStatsBySlot),
|
|
903
914
|
rejectedCommands,
|
|
904
915
|
rejectedReconfigures,
|
package/dist/browser.d.ts
CHANGED
|
@@ -24,8 +24,8 @@ export { createNetworkedSyncplayClient, prepareNetworkedSyncplayTransport } from
|
|
|
24
24
|
export { createSyncplayRunner } from './runner.js';
|
|
25
25
|
export { fbm2D, hash2, hashUint32, valueNoise1D, valueNoise2D } from './noise.js';
|
|
26
26
|
export { circleCastDeterministicPhysics2D, createDeterministicPhysicsWorld2D, nearestDeterministicPhysicsHit2D, queryDeterministicPhysicsAabb2D, queryDeterministicPhysicsShapeOverlap2D, raycastAllDeterministicPhysics2D, raycastDeterministicPhysics2D, stepDeterministicPhysicsWorld2D } from './physics2d.js';
|
|
27
|
-
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
28
|
-
export { cookDeterministicVoxelChunkCollider3D } from './physics3d-voxel.js';
|
|
27
|
+
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
28
|
+
export { cookDeterministicVoxelChunkCollider3D, raycastDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
29
29
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
30
30
|
export { createDeterministicCosmeticPhysicsWorld3D, setDeterministicCosmeticPhysicsAuthoritativeBodyProxies3D, stepDeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
|
31
31
|
export { stepDeterministicVehicle3D } from './physics3d-vehicle.js';
|
|
@@ -35,7 +35,7 @@ export { createDeterministicDescriptorBinarySchema, generateSchemaBinarySource,
|
|
|
35
35
|
export { createDeterministicBinarySerializer, deterministicDslMaxPlayers, parseDeterministicSchemaDsl, stableDeterministicDslSchemaJson } from './schema-dsl-binary.js';
|
|
36
36
|
export { createSyncplaySession } from './sdk-session.js';
|
|
37
37
|
export { createSessionFromPromotionSnapshot, exportPromotionSnapshot } from './session-promotion.js';
|
|
38
|
-
export { base64ToBytes, bytesToBase64, createSnapshotTransferCollector, createSnapshotTransferFromBytes, decodeDeterministicStateSnapshot, DEFAULT_MAX_SNAPSHOT_BYTES, DEFAULT_SNAPSHOT_CHUNK_SIZE, deterministicRoomDescriptorHash, encodeDeterministicStateSnapshot } from './session-snapshot.js';
|
|
38
|
+
export { base64ToBytes, bytesToBase64, createSnapshotTransferCollector, createSnapshotTransferFromBytes, decodeDeterministicStateSnapshot, DEFAULT_MAX_SNAPSHOT_BYTES, DEFAULT_SNAPSHOT_CHUNK_SIZE, deterministicRoomDescriptorHash, encodeDeterministicStateSnapshot, MAX_JSON_ESCAPE_EXPANSION, SNAPSHOT_CHUNK_ENVELOPE_OVERHEAD_BYTES } from './session-snapshot.js';
|
|
39
39
|
export { decodeDeterministicSessionMessage, deterministicSessionWireVersion, encodeDeterministicSessionMessage } from './session-wire.js';
|
|
40
40
|
export { createDeterministicSignalBus } from './signals.js';
|
|
41
41
|
export { createDeterministicSparseSet } from './sparse-set.js';
|
|
@@ -65,8 +65,8 @@ export type { CookedDeterministicNavmesh, DeterministicNavmeshAgent, Determinist
|
|
|
65
65
|
export type { ConfirmedSyncplayPresentationFrame, KinetixRuntimeFactory, NetworkedClientTransport, NetworkedSyncplayClient, NetworkedSyncplayClientInputDelayOptions, NetworkedSyncplayClientNetStats, NetworkedSyncplayClientOptions, NetworkedSyncplayClientPacingOptions, NetworkedSyncplayPreparationOptions, NetworkedSyncplaySessionDescriptor, NetworkedSyncplaySlotPresence, PreparedNetworkedSyncplayTransport, SyncplayPredictionMode, SyncplayRemoteInputPrediction } from './networked-client.js';
|
|
66
66
|
export type { SyncplayRunner, SyncplayRunnerConfig, SyncplayRunnerConnectionEvent, SyncplayRunnerOccupancy, SyncplayRunnerOfflineOptions, SyncplayRunnerPresentation, SyncplayRunnerSnapshot, SyncplayRunnerStatus, SyncplayRunnerTransport } from './runner.js';
|
|
67
67
|
export type { DeterministicBodyKind, DeterministicContactEvent2D, DeterministicContactEventType, DeterministicPhysicsAabbQuery2D, DeterministicPhysicsActivePair2D, DeterministicPhysicsBody2D, DeterministicPhysicsCircleCastQuery2D, DeterministicPhysicsConstraint2D, DeterministicPhysicsHit2D, DeterministicPhysicsQueryOptions2D, DeterministicPhysicsRaycastQuery2D, DeterministicPhysicsShape2D, DeterministicPhysicsShapeOverlapQuery2D, DeterministicPhysicsStepOptions2D, DeterministicPhysicsStepResult2D, DeterministicPhysicsWorld2D } from './physics2d.js';
|
|
68
|
-
export type { DeterministicContactCacheEntry3D, DeterministicJointCacheEntry3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D } from './physics3d.js';
|
|
69
|
-
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D } from './physics3d-voxel.js';
|
|
68
|
+
export type { DeterministicContactCacheEntry3D, DeterministicJointCacheEntry3D, DeterministicKinematicPose3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D } from './physics3d.js';
|
|
69
|
+
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D, DeterministicVoxelRayHit3D } from './physics3d-voxel.js';
|
|
70
70
|
export type { DeterministicAuthoritativeBodyProxy3D, DeterministicCosmeticPhysicsBody3D, DeterministicCosmeticPhysicsStepOptions3D, DeterministicCosmeticPhysicsStepResult3D, DeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
|
71
71
|
export type { DeterministicPhysicsJoint3D } from './physics3d-joints.js';
|
|
72
72
|
export type { DeterministicVehicle3D, DeterministicVehicleImpulse3D, DeterministicVehicleInput3D, DeterministicVehicleStepOptions3D, DeterministicVehicleStepResult3D, DeterministicVehicleWheel3D, DeterministicVehicleWheelTelemetry3D } from './physics3d-vehicle.js';
|
package/dist/browser.js
CHANGED
|
@@ -25,8 +25,8 @@ export { createNetworkedSyncplayClient, prepareNetworkedSyncplayTransport } from
|
|
|
25
25
|
export { createSyncplayRunner } from './runner.js';
|
|
26
26
|
export { fbm2D, hash2, hashUint32, valueNoise1D, valueNoise2D } from './noise.js';
|
|
27
27
|
export { circleCastDeterministicPhysics2D, createDeterministicPhysicsWorld2D, nearestDeterministicPhysicsHit2D, queryDeterministicPhysicsAabb2D, queryDeterministicPhysicsShapeOverlap2D, raycastAllDeterministicPhysics2D, raycastDeterministicPhysics2D, stepDeterministicPhysicsWorld2D } from './physics2d.js';
|
|
28
|
-
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
29
|
-
export { cookDeterministicVoxelChunkCollider3D } from './physics3d-voxel.js';
|
|
28
|
+
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
29
|
+
export { cookDeterministicVoxelChunkCollider3D, raycastDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
30
30
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
31
31
|
export { createDeterministicCosmeticPhysicsWorld3D, setDeterministicCosmeticPhysicsAuthoritativeBodyProxies3D, stepDeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
|
32
32
|
export { stepDeterministicVehicle3D } from './physics3d-vehicle.js';
|
|
@@ -36,7 +36,7 @@ export { createDeterministicDescriptorBinarySchema, generateSchemaBinarySource,
|
|
|
36
36
|
export { createDeterministicBinarySerializer, deterministicDslMaxPlayers, parseDeterministicSchemaDsl, stableDeterministicDslSchemaJson } from './schema-dsl-binary.js';
|
|
37
37
|
export { createSyncplaySession } from './sdk-session.js';
|
|
38
38
|
export { createSessionFromPromotionSnapshot, exportPromotionSnapshot } from './session-promotion.js';
|
|
39
|
-
export { base64ToBytes, bytesToBase64, createSnapshotTransferCollector, createSnapshotTransferFromBytes, decodeDeterministicStateSnapshot, DEFAULT_MAX_SNAPSHOT_BYTES, DEFAULT_SNAPSHOT_CHUNK_SIZE, deterministicRoomDescriptorHash, encodeDeterministicStateSnapshot } from './session-snapshot.js';
|
|
39
|
+
export { base64ToBytes, bytesToBase64, createSnapshotTransferCollector, createSnapshotTransferFromBytes, decodeDeterministicStateSnapshot, DEFAULT_MAX_SNAPSHOT_BYTES, DEFAULT_SNAPSHOT_CHUNK_SIZE, deterministicRoomDescriptorHash, encodeDeterministicStateSnapshot, MAX_JSON_ESCAPE_EXPANSION, SNAPSHOT_CHUNK_ENVELOPE_OVERHEAD_BYTES } from './session-snapshot.js';
|
|
40
40
|
export { decodeDeterministicSessionMessage, deterministicSessionWireVersion, encodeDeterministicSessionMessage } from './session-wire.js';
|
|
41
41
|
export { createDeterministicSignalBus } from './signals.js';
|
|
42
42
|
export { createDeterministicSparseSet } from './sparse-set.js';
|
package/dist/creator.d.ts
CHANGED
|
@@ -12,12 +12,12 @@ export type { RecordedChecksum, RecordedCommandFrame, RecordedDebugEvent, Record
|
|
|
12
12
|
export type { ReplayRuntimeFactory, ReplayVerificationConfig, ReplayVerificationExecution } from './replay.js';
|
|
13
13
|
export type { SyncplaySession, SyncplaySessionPolicy } from './sdk-session.js';
|
|
14
14
|
export type { InstantReplayInputFrame, InstantReplayResult, InstantReplayRunner, InstantReplayRunnerOptions, InstantReplayRunOptions, RunInstantReplayOptions, } from './instant-replay.js';
|
|
15
|
-
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D, } from './physics3d.js';
|
|
16
|
-
export { cookDeterministicVoxelChunkCollider3D } from './physics3d-voxel.js';
|
|
15
|
+
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D, } from './physics3d.js';
|
|
16
|
+
export { cookDeterministicVoxelChunkCollider3D, raycastDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
17
17
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
18
18
|
export { stepDeterministicVehicle3D } from './physics3d-vehicle.js';
|
|
19
|
-
export type { DeterministicContactCacheEntry3D, DeterministicJointCacheEntry3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D, } from './physics3d.js';
|
|
20
|
-
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D } from './physics3d-voxel.js';
|
|
19
|
+
export type { DeterministicContactCacheEntry3D, DeterministicJointCacheEntry3D, DeterministicKinematicPose3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D, } from './physics3d.js';
|
|
20
|
+
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D, DeterministicVoxelRayHit3D } from './physics3d-voxel.js';
|
|
21
21
|
export type { DeterministicPhysicsJoint3D } from './physics3d-joints.js';
|
|
22
22
|
export type { DeterministicVehicle3D, DeterministicVehicleImpulse3D, DeterministicVehicleInput3D, DeterministicVehicleStepOptions3D, DeterministicVehicleStepResult3D, DeterministicVehicleWheel3D, DeterministicVehicleWheelTelemetry3D, } from './physics3d-vehicle.js';
|
|
23
23
|
export type { DeterministicPhysicsMaterial } from './deterministic-primitives.js';
|
package/dist/creator.js
CHANGED
|
@@ -9,7 +9,7 @@ export { runSyncplaySynctest } from './synctest.js';
|
|
|
9
9
|
// create/step/edit, impulses, queries, vehicles, and voxel-chunk collider
|
|
10
10
|
// cooking. Cosmetic physics, KCC (movement3d), and the destruction-cert runner
|
|
11
11
|
// stay off it — the first two are not requested, the third reads wall clock.
|
|
12
|
-
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D, } from './physics3d.js';
|
|
13
|
-
export { cookDeterministicVoxelChunkCollider3D } from './physics3d-voxel.js';
|
|
12
|
+
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D, } from './physics3d.js';
|
|
13
|
+
export { cookDeterministicVoxelChunkCollider3D, raycastDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
14
14
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
15
15
|
export { stepDeterministicVehicle3D } from './physics3d-vehicle.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createDeterministicAuthorityRoom, } from './authority-room.js';
|
|
2
|
-
import { SYSTEM_MSG_RECONNECTED } from '@series-inc/rundot-game-sdk/mp-server';
|
|
2
|
+
import { SYSTEM_MSG_DISCONNECTED, SYSTEM_MSG_RECONNECTED } from '@series-inc/rundot-game-sdk/mp-server';
|
|
3
3
|
import { createHash, createPrivateKey, generateKeyPairSync, randomBytes, sign } from 'node:crypto';
|
|
4
4
|
import { validateSyncplaySecretSystemsConfig } from './secret-config.js';
|
|
5
5
|
import { assertKinetixRuntimeIdentity, kinetixSessionConfigDigest, } from '@series-inc/rundot-syncplay/core/runtime';
|
|
@@ -138,6 +138,13 @@ export class DevSyncplayAuthorityRoom {
|
|
|
138
138
|
this.room.onPlayerReconnected(playerId);
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
|
+
// The dev server already emits this on socket loss. Handle it so local
|
|
142
|
+
// play matches production: a player who drops mid-movement stops instead
|
|
143
|
+
// of having their held input repeated through the grace window.
|
|
144
|
+
if (msgType === SYSTEM_MSG_DISCONNECTED) {
|
|
145
|
+
this.room.onPlayerDisconnected(playerId);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
141
148
|
if (msgType === SECRET_MSG_TYPE) {
|
|
142
149
|
const envelope = typeof data === 'string' ? data : JSON.stringify(data);
|
|
143
150
|
this.room.onPlayerSecretMessage(playerId, envelope);
|
package/dist/index.d.ts
CHANGED
|
@@ -27,8 +27,8 @@ export { createNetworkedSyncplayClient, prepareNetworkedSyncplayTransport } from
|
|
|
27
27
|
export { createSyncplayRunner } from './runner.js';
|
|
28
28
|
export { fbm2D, hash2, hashUint32, valueNoise1D, valueNoise2D } from './noise.js';
|
|
29
29
|
export { circleCastDeterministicPhysics2D, createDeterministicPhysicsWorld2D, nearestDeterministicPhysicsHit2D, queryDeterministicPhysicsAabb2D, queryDeterministicPhysicsShapeOverlap2D, raycastAllDeterministicPhysics2D, raycastDeterministicPhysics2D, stepDeterministicPhysicsWorld2D } from './physics2d.js';
|
|
30
|
-
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
31
|
-
export { cookDeterministicVoxelChunkCollider3D } from './physics3d-voxel.js';
|
|
30
|
+
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
31
|
+
export { cookDeterministicVoxelChunkCollider3D, raycastDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
32
32
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
33
33
|
export { runDeterministicPhysics3DDestructionCert } from './physics3d-destruction-cert.js';
|
|
34
34
|
export { createDeterministicCosmeticPhysicsWorld3D, setDeterministicCosmeticPhysicsAuthoritativeBodyProxies3D, stepDeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
|
@@ -44,7 +44,7 @@ export { withRuntimeDeterminismGuards } from './runtime-guards.js';
|
|
|
44
44
|
export { createDeterministicDescriptorBinarySchema, generateSchemaBinarySource, generateSchemaTypes, proveSchemaBinaryRoundTrip } from './schema-codegen.js';
|
|
45
45
|
export { createDeterministicBinarySerializer, deterministicDslMaxPlayers, parseDeterministicSchemaDsl, stableDeterministicDslSchemaJson } from './schema-dsl-binary.js';
|
|
46
46
|
export { createSyncplaySession } from './sdk-session.js';
|
|
47
|
-
export { base64ToBytes, bytesToBase64, createSnapshotTransferCollector, createSnapshotTransferFromBytes, decodeDeterministicStateSnapshot, DEFAULT_MAX_SNAPSHOT_BYTES, DEFAULT_SNAPSHOT_CHUNK_SIZE, deterministicRoomDescriptorHash, encodeDeterministicStateSnapshot } from './session-snapshot.js';
|
|
47
|
+
export { base64ToBytes, bytesToBase64, createSnapshotTransferCollector, createSnapshotTransferFromBytes, decodeDeterministicStateSnapshot, DEFAULT_MAX_SNAPSHOT_BYTES, DEFAULT_SNAPSHOT_CHUNK_SIZE, deterministicRoomDescriptorHash, encodeDeterministicStateSnapshot, MAX_JSON_ESCAPE_EXPANSION, SNAPSHOT_CHUNK_ENVELOPE_OVERHEAD_BYTES } from './session-snapshot.js';
|
|
48
48
|
export { decodeDeterministicSessionMessage, deterministicSessionWireVersion, encodeDeterministicSessionMessage } from './session-wire.js';
|
|
49
49
|
export { createDeterministicSignalBus } from './signals.js';
|
|
50
50
|
export { createDeterministicSparseSet } from './sparse-set.js';
|
|
@@ -77,8 +77,8 @@ export type { CookedDeterministicNavmesh, DeterministicNavmeshAgent, Determinist
|
|
|
77
77
|
export type { ConfirmedSyncplayPresentationFrame, KinetixRuntimeFactory, NetworkedClientTransport, NetworkedSyncplayClient, NetworkedSyncplayClientInputDelayOptions, NetworkedSyncplayClientNetStats, NetworkedSyncplayClientOptions, NetworkedSyncplayClientPacingOptions, NetworkedSyncplayPreparationOptions, NetworkedSyncplaySessionDescriptor, PreparedNetworkedSyncplayTransport, SyncplayPredictionMode, SyncplayRemoteInputPrediction } from './networked-client.js';
|
|
78
78
|
export type { SyncplayRunner, SyncplayRunnerConfig, SyncplayRunnerConnectionEvent, SyncplayRunnerOccupancy, SyncplayRunnerOfflineOptions, SyncplayRunnerPresentation, SyncplayRunnerSnapshot, SyncplayRunnerStatus, SyncplayRunnerTransport } from './runner.js';
|
|
79
79
|
export type { DeterministicBodyKind, DeterministicContactEvent2D, DeterministicContactEventType, DeterministicPhysicsAabbQuery2D, DeterministicPhysicsBody2D, DeterministicPhysicsCircleCastQuery2D, DeterministicPhysicsConstraint2D, DeterministicPhysicsHit2D, DeterministicPhysicsQueryOptions2D, DeterministicPhysicsRaycastQuery2D, DeterministicPhysicsShape2D, DeterministicPhysicsShapeOverlapQuery2D, DeterministicPhysicsStepOptions2D, DeterministicPhysicsStepResult2D, DeterministicPhysicsWorld2D } from './physics2d.js';
|
|
80
|
-
export type { DeterministicContactCacheEntry3D, DeterministicJointCacheEntry3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D } from './physics3d.js';
|
|
81
|
-
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D } from './physics3d-voxel.js';
|
|
80
|
+
export type { DeterministicContactCacheEntry3D, DeterministicJointCacheEntry3D, DeterministicKinematicPose3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D } from './physics3d.js';
|
|
81
|
+
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D, DeterministicVoxelRayHit3D } from './physics3d-voxel.js';
|
|
82
82
|
export type { DeterministicDestructionCertOptions, DeterministicDestructionCertResult } from './physics3d-destruction-cert.js';
|
|
83
83
|
export type { DeterministicAuthoritativeBodyProxy3D, DeterministicCosmeticPhysicsBody3D, DeterministicCosmeticPhysicsStepOptions3D, DeterministicCosmeticPhysicsStepResult3D, DeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
|
84
84
|
export type { DeterministicPhysicsJoint3D } from './physics3d-joints.js';
|
package/dist/index.js
CHANGED
|
@@ -28,8 +28,8 @@ export { createNetworkedSyncplayClient, prepareNetworkedSyncplayTransport } from
|
|
|
28
28
|
export { createSyncplayRunner } from './runner.js';
|
|
29
29
|
export { fbm2D, hash2, hashUint32, valueNoise1D, valueNoise2D } from './noise.js';
|
|
30
30
|
export { circleCastDeterministicPhysics2D, createDeterministicPhysicsWorld2D, nearestDeterministicPhysicsHit2D, queryDeterministicPhysicsAabb2D, queryDeterministicPhysicsShapeOverlap2D, raycastAllDeterministicPhysics2D, raycastDeterministicPhysics2D, stepDeterministicPhysicsWorld2D } from './physics2d.js';
|
|
31
|
-
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
32
|
-
export { cookDeterministicVoxelChunkCollider3D } from './physics3d-voxel.js';
|
|
31
|
+
export { applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
32
|
+
export { cookDeterministicVoxelChunkCollider3D, raycastDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
33
33
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
34
34
|
export { runDeterministicPhysics3DDestructionCert } from './physics3d-destruction-cert.js';
|
|
35
35
|
export { createDeterministicCosmeticPhysicsWorld3D, setDeterministicCosmeticPhysicsAuthoritativeBodyProxies3D, stepDeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
|
@@ -45,7 +45,7 @@ export { withRuntimeDeterminismGuards } from './runtime-guards.js';
|
|
|
45
45
|
export { createDeterministicDescriptorBinarySchema, generateSchemaBinarySource, generateSchemaTypes, proveSchemaBinaryRoundTrip } from './schema-codegen.js';
|
|
46
46
|
export { createDeterministicBinarySerializer, deterministicDslMaxPlayers, parseDeterministicSchemaDsl, stableDeterministicDslSchemaJson } from './schema-dsl-binary.js';
|
|
47
47
|
export { createSyncplaySession } from './sdk-session.js';
|
|
48
|
-
export { base64ToBytes, bytesToBase64, createSnapshotTransferCollector, createSnapshotTransferFromBytes, decodeDeterministicStateSnapshot, DEFAULT_MAX_SNAPSHOT_BYTES, DEFAULT_SNAPSHOT_CHUNK_SIZE, deterministicRoomDescriptorHash, encodeDeterministicStateSnapshot } from './session-snapshot.js';
|
|
48
|
+
export { base64ToBytes, bytesToBase64, createSnapshotTransferCollector, createSnapshotTransferFromBytes, decodeDeterministicStateSnapshot, DEFAULT_MAX_SNAPSHOT_BYTES, DEFAULT_SNAPSHOT_CHUNK_SIZE, deterministicRoomDescriptorHash, encodeDeterministicStateSnapshot, MAX_JSON_ESCAPE_EXPANSION, SNAPSHOT_CHUNK_ENVELOPE_OVERHEAD_BYTES } from './session-snapshot.js';
|
|
49
49
|
export { decodeDeterministicSessionMessage, deterministicSessionWireVersion, encodeDeterministicSessionMessage } from './session-wire.js';
|
|
50
50
|
export { createDeterministicSignalBus } from './signals.js';
|
|
51
51
|
export { createDeterministicSparseSet } from './sparse-set.js';
|
|
@@ -83,6 +83,14 @@ export interface InputAuthority {
|
|
|
83
83
|
* frontier; a no-op at or below the current earliest retained tick.
|
|
84
84
|
*/
|
|
85
85
|
pruneConfirmedBefore(tick: number): void;
|
|
86
|
+
/**
|
|
87
|
+
* Forget a slot's last confirmed input so later substitutions fall back to
|
|
88
|
+
* `neutralInput`. Call this when a slot's player disconnects or leaves: the
|
|
89
|
+
* slot stays reserved and keeps being substituted, so without this the
|
|
90
|
+
* authority repeats whatever they were holding when they dropped for the
|
|
91
|
+
* rest of the match. Out-of-roster slots are ignored.
|
|
92
|
+
*/
|
|
93
|
+
neutralizeSlot(slot: number): void;
|
|
86
94
|
stats(): InputAuthorityStats;
|
|
87
95
|
}
|
|
88
96
|
export declare function createInputAuthority(config: InputAuthorityConfig): InputAuthority;
|
package/dist/input-authority.js
CHANGED
|
@@ -185,6 +185,19 @@ export function createInputAuthority(config) {
|
|
|
185
185
|
}
|
|
186
186
|
earliestRetained = tick;
|
|
187
187
|
},
|
|
188
|
+
neutralizeSlot(slot) {
|
|
189
|
+
if (!Number.isInteger(slot) || slot < 0 || slot >= playerCount)
|
|
190
|
+
return;
|
|
191
|
+
lastConfirmedInput[slot] = config.neutralInput;
|
|
192
|
+
// Resetting the last-confirmed value is not enough on its own: clients
|
|
193
|
+
// queue ahead by `inputDelayTicks`, so a dropping player usually has
|
|
194
|
+
// future ticks already buffered. `confirmTick` reassigns
|
|
195
|
+
// `lastConfirmedInput` from any submitted input, so leaving those in
|
|
196
|
+
// place would resurrect the held input on the very next confirm.
|
|
197
|
+
for (const slots of pending.values()) {
|
|
198
|
+
slots[slot] = undefined;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
188
201
|
stats() {
|
|
189
202
|
return { confirmedTicks, substitutedInputs, droppedLateInputs, rejectedFutureInputs };
|
|
190
203
|
},
|
|
@@ -142,6 +142,14 @@ export interface NetworkedSyncplayClientNetStats {
|
|
|
142
142
|
readonly droppedConfirmedPresentationFrames: number;
|
|
143
143
|
/** Commands this client refused to send (oversized payload). */
|
|
144
144
|
readonly rejectedCommands: number;
|
|
145
|
+
/**
|
|
146
|
+
* Confirmed ticks in which THIS client's own input was substituted because it
|
|
147
|
+
* did not reach the authority in time. Monotonic within a session and reset on
|
|
148
|
+
* session-start. Counted per applied tick, so a batch of confirmations that
|
|
149
|
+
* substitutes some ticks and not the last one still reports every one — a
|
|
150
|
+
* consumer reading `confirmedPlayerPresence` alone sees only the final tick.
|
|
151
|
+
*/
|
|
152
|
+
readonly ownInputSubstitutions: number;
|
|
145
153
|
}
|
|
146
154
|
export type NetworkedSyncplaySlotPresence = 'human' | 'substituted' | 'empty' | 'unknown';
|
|
147
155
|
export interface ConfirmedSyncplayPresentationFrame<Projection> {
|
package/dist/networked-client.js
CHANGED
|
@@ -282,6 +282,7 @@ export function createNetworkedSyncplayClient(options) {
|
|
|
282
282
|
let sessionGeneration = 0;
|
|
283
283
|
let commandSequence = 0;
|
|
284
284
|
let droppedConfirmedPresentationFrames = 0;
|
|
285
|
+
let ownInputSubstitutions = 0;
|
|
285
286
|
let rejectedCommands = 0;
|
|
286
287
|
const ephemeralHandlers = new Set();
|
|
287
288
|
let pendingEphemeral;
|
|
@@ -427,6 +428,7 @@ export function createNetworkedSyncplayClient(options) {
|
|
|
427
428
|
confirmed.clear();
|
|
428
429
|
reportedTicks.length = 0;
|
|
429
430
|
lastAutoReportedTick = -1;
|
|
431
|
+
ownInputSubstitutions = 0;
|
|
430
432
|
transferCollector = createSnapshotTransferCollector(snapshotCollectorOptions);
|
|
431
433
|
outgoingTransferQueue.length = 0;
|
|
432
434
|
tickRateHz = message.tickRateHz;
|
|
@@ -912,6 +914,11 @@ export function createNetworkedSyncplayClient(options) {
|
|
|
912
914
|
for (let playerSlot = 0; playerSlot < playerCount; playerSlot += 1) {
|
|
913
915
|
lastConfirmedBySlot[playerSlot] = confInputs[playerSlot];
|
|
914
916
|
}
|
|
917
|
+
// Per APPLIED tick, not per drained batch: `confirmedPlayerPresence`
|
|
918
|
+
// latches only the last tick of a batch, so a burst that substitutes
|
|
919
|
+
// several ticks and ends on a delivered one would otherwise vanish.
|
|
920
|
+
if (slot >= 0 && confFrame.substitutedSlots.includes(slot))
|
|
921
|
+
ownInputSubstitutions += 1;
|
|
915
922
|
appliedThrough = tick;
|
|
916
923
|
confirmedPlayerPresence = classifyPresence(confFrame);
|
|
917
924
|
const presentationEligible = presentationWasLive || (freshRoomFirstFrame && tick === 0);
|
|
@@ -1232,6 +1239,7 @@ export function createNetworkedSyncplayClient(options) {
|
|
|
1232
1239
|
maxRollbackDepth,
|
|
1233
1240
|
droppedConfirmedPresentationFrames,
|
|
1234
1241
|
rejectedCommands,
|
|
1242
|
+
ownInputSubstitutions,
|
|
1235
1243
|
};
|
|
1236
1244
|
},
|
|
1237
1245
|
get generation() {
|
package/dist/node.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export { buildMerkleTree, bytesToHex, concatBytes, constantTimeEqual, createBrow
|
|
|
19
19
|
export type { SyncplaySecretAuthorityCrypto, SyncplaySecretBrowserCrypto } from './secret-crypto.js';
|
|
20
20
|
export * from './ws-frame.js';
|
|
21
21
|
export { SYNCPLAY_DETERMINISTIC_ROOM_OPTION_KEYS } from './rooms-config-keys.js';
|
|
22
|
+
export { createSyncplayRuntimePin, parseSyncplayRuntimeRoomMetadata, MAX_SYNCPLAY_SESSION_CONFIG_BYTES, } from './runtime-room-metadata.js';
|
|
23
|
+
export type { SyncplayRuntimeIdentity, SyncplayRuntimeRoomMetadata, ParsedSyncplayRuntimeRoomMetadata, SyncplayRuntimeConfigInput, } from './runtime-room-metadata.js';
|
|
22
24
|
export type { SyncplayDeterministicRoomOptionKey } from './rooms-config-keys.js';
|
|
23
25
|
export { assertCookedColliderIsRuntimeValid, cookConvexDecomposition, } from './collider-cooking.js';
|
|
24
26
|
export type { ColliderCookOptions, ColliderSourceMesh, CookedCollider, CookedColliderHull, } from './collider-cooking.js';
|
package/dist/node.js
CHANGED
|
@@ -16,6 +16,7 @@ export * from './secret-authority.js';
|
|
|
16
16
|
export { buildMerkleTree, bytesToHex, concatBytes, constantTimeEqual, createBrowserSyncplaySecretCrypto, hexToBytes, merkleLeafHash, merkleNodeHash, merkleProof, sha256Bytes, signedReceiptBytes, verifyHashChainReveal, verifyMerkleProof, verifySyncplaySignedReceipt, } from './secret-crypto.js';
|
|
17
17
|
export * from './ws-frame.js';
|
|
18
18
|
export { SYNCPLAY_DETERMINISTIC_ROOM_OPTION_KEYS } from './rooms-config-keys.js';
|
|
19
|
+
export { createSyncplayRuntimePin, parseSyncplayRuntimeRoomMetadata, MAX_SYNCPLAY_SESSION_CONFIG_BYTES, } from './runtime-room-metadata.js';
|
|
19
20
|
export { assertCookedColliderIsRuntimeValid, cookConvexDecomposition, } from './collider-cooking.js';
|
|
20
21
|
// Dev-server deterministic room class (relocated from the game SDK). A game's
|
|
21
22
|
// vite.config passes this to rundotMultiplayerPlugin({ deterministicRoomClass }).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DeterministicPhysicsShape3D } from './physics3d.js';
|
|
1
|
+
import type { DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsShape3D } from './physics3d.js';
|
|
2
2
|
export interface DeterministicVoxelChunk3D {
|
|
3
3
|
readonly dimX: number;
|
|
4
4
|
readonly dimY: number;
|
|
@@ -8,9 +8,31 @@ export interface DeterministicVoxelChunk3D {
|
|
|
8
8
|
/** Row-major occupancy: occupancy[x + dimX * (y + dimY * z)]; non-zero = solid. */
|
|
9
9
|
readonly occupancy: readonly (0 | 1)[];
|
|
10
10
|
}
|
|
11
|
+
export interface DeterministicVoxelRayHit3D {
|
|
12
|
+
readonly hit: boolean;
|
|
13
|
+
readonly distance: number;
|
|
14
|
+
readonly voxelX: number;
|
|
15
|
+
readonly voxelY: number;
|
|
16
|
+
readonly voxelZ: number;
|
|
17
|
+
readonly point: {
|
|
18
|
+
readonly x: number;
|
|
19
|
+
readonly y: number;
|
|
20
|
+
readonly z: number;
|
|
21
|
+
};
|
|
22
|
+
readonly normal: {
|
|
23
|
+
readonly x: number;
|
|
24
|
+
readonly y: number;
|
|
25
|
+
readonly z: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
11
28
|
export type DeterministicVoxelCompoundShape3D = Extract<DeterministicPhysicsShape3D, {
|
|
12
29
|
readonly type: 'compound';
|
|
13
30
|
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Amanatides & Woo 3D Digital Differential Analyzer (DDA) fast voxel grid raycaster.
|
|
33
|
+
* Marches through chunk cells in O(distance) directly over the occupancy bitset.
|
|
34
|
+
*/
|
|
35
|
+
export declare function raycastDeterministicVoxelChunk3D(chunk: DeterministicVoxelChunk3D, query: DeterministicPhysicsRaycastQuery3D): DeterministicVoxelRayHit3D | undefined;
|
|
14
36
|
/**
|
|
15
37
|
* Deterministic greedy box merge: scan z→y→x ascending and grow each unconsumed
|
|
16
38
|
* solid cell into the largest box along +x, then +y, then +z. A solid n³ chunk
|
package/dist/physics3d-voxel.js
CHANGED
|
@@ -1,3 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Amanatides & Woo 3D Digital Differential Analyzer (DDA) fast voxel grid raycaster.
|
|
3
|
+
* Marches through chunk cells in O(distance) directly over the occupancy bitset.
|
|
4
|
+
*/
|
|
5
|
+
export function raycastDeterministicVoxelChunk3D(chunk, query) {
|
|
6
|
+
const { dimX, dimY, dimZ, cellSize, occupancy } = chunk;
|
|
7
|
+
if (cellSize <= 0 || occupancy.length !== dimX * dimY * dimZ) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
const dirLen = Math.hypot(query.dx, query.dy, query.dz);
|
|
11
|
+
if (dirLen <= 1e-12) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const dx = query.dx / dirLen;
|
|
15
|
+
const dy = query.dy / dirLen;
|
|
16
|
+
const dz = query.dz / dirLen;
|
|
17
|
+
const maxDistance = query.maxDistance;
|
|
18
|
+
if (maxDistance < 0) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const ox = query.x / cellSize;
|
|
22
|
+
const oy = query.y / cellSize;
|
|
23
|
+
const oz = query.z / cellSize;
|
|
24
|
+
let tMin = 0;
|
|
25
|
+
let tMax = maxDistance / cellSize;
|
|
26
|
+
let enterNormal = { x: 0, y: 0, z: 0 };
|
|
27
|
+
const axes = [
|
|
28
|
+
{ o: ox, d: dx, min: 0, max: dimX, nx: 1, ny: 0, nz: 0 },
|
|
29
|
+
{ o: oy, d: dy, min: 0, max: dimY, nx: 0, ny: 1, nz: 0 },
|
|
30
|
+
{ o: oz, d: dz, min: 0, max: dimZ, nx: 0, ny: 0, nz: 1 },
|
|
31
|
+
];
|
|
32
|
+
for (const axis of axes) {
|
|
33
|
+
if (Math.abs(axis.d) < 1e-12) {
|
|
34
|
+
if (axis.o < axis.min || axis.o > axis.max) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
let t1 = (axis.min - axis.o) / axis.d;
|
|
40
|
+
let t2 = (axis.max - axis.o) / axis.d;
|
|
41
|
+
let n1 = { x: -axis.nx, y: -axis.ny, z: -axis.nz };
|
|
42
|
+
if (t1 > t2) {
|
|
43
|
+
const temp = t1;
|
|
44
|
+
t1 = t2;
|
|
45
|
+
t2 = temp;
|
|
46
|
+
n1 = { x: axis.nx, y: axis.ny, z: axis.nz };
|
|
47
|
+
}
|
|
48
|
+
if (t1 > tMin) {
|
|
49
|
+
tMin = t1;
|
|
50
|
+
enterNormal = n1;
|
|
51
|
+
}
|
|
52
|
+
if (t2 < tMax) {
|
|
53
|
+
tMax = t2;
|
|
54
|
+
}
|
|
55
|
+
if (tMin > tMax) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (ox >= 0 && ox < dimX && oy >= 0 && oy < dimY && oz >= 0 && oz < dimZ) {
|
|
61
|
+
tMin = 0;
|
|
62
|
+
}
|
|
63
|
+
const startX = ox + dx * tMin;
|
|
64
|
+
const startY = oy + dy * tMin;
|
|
65
|
+
const startZ = oz + dz * tMin;
|
|
66
|
+
let currentX = Math.floor(startX);
|
|
67
|
+
let currentY = Math.floor(startY);
|
|
68
|
+
let currentZ = Math.floor(startZ);
|
|
69
|
+
currentX = Math.max(0, Math.min(dimX - 1, currentX));
|
|
70
|
+
currentY = Math.max(0, Math.min(dimY - 1, currentY));
|
|
71
|
+
currentZ = Math.max(0, Math.min(dimZ - 1, currentZ));
|
|
72
|
+
const stepX = dx > 0 ? 1 : dx < 0 ? -1 : 0;
|
|
73
|
+
const stepY = dy > 0 ? 1 : dy < 0 ? -1 : 0;
|
|
74
|
+
const stepZ = dz > 0 ? 1 : dz < 0 ? -1 : 0;
|
|
75
|
+
const tDeltaX = stepX !== 0 ? Math.abs(1 / dx) : Infinity;
|
|
76
|
+
const tDeltaY = stepY !== 0 ? Math.abs(1 / dy) : Infinity;
|
|
77
|
+
const tDeltaZ = stepZ !== 0 ? Math.abs(1 / dz) : Infinity;
|
|
78
|
+
let tMaxX = stepX > 0 ? (currentX + 1 - ox) / dx : stepX < 0 ? (currentX - ox) / dx : Infinity;
|
|
79
|
+
let tMaxY = stepY > 0 ? (currentY + 1 - oy) / dy : stepY < 0 ? (currentY - oy) / dy : Infinity;
|
|
80
|
+
let tMaxZ = stepZ > 0 ? (currentZ + 1 - oz) / dz : stepZ < 0 ? (currentZ - oz) / dz : Infinity;
|
|
81
|
+
let currentNormal = enterNormal;
|
|
82
|
+
let hitDistanceGrid = tMin;
|
|
83
|
+
while (currentX >= 0 && currentX < dimX && currentY >= 0 && currentY < dimY && currentZ >= 0 && currentZ < dimZ) {
|
|
84
|
+
const cellIndex = currentX + dimX * (currentY + dimY * currentZ);
|
|
85
|
+
if (occupancy[cellIndex] === 1) {
|
|
86
|
+
const worldDistance = hitDistanceGrid * cellSize;
|
|
87
|
+
if (worldDistance > maxDistance) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const hitPoint = {
|
|
91
|
+
x: query.x + dx * worldDistance,
|
|
92
|
+
y: query.y + dy * worldDistance,
|
|
93
|
+
z: query.z + dz * worldDistance,
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
hit: true,
|
|
97
|
+
distance: worldDistance,
|
|
98
|
+
voxelX: currentX,
|
|
99
|
+
voxelY: currentY,
|
|
100
|
+
voxelZ: currentZ,
|
|
101
|
+
point: hitPoint,
|
|
102
|
+
normal: currentNormal,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (tMaxX < tMaxY) {
|
|
106
|
+
if (tMaxX < tMaxZ) {
|
|
107
|
+
hitDistanceGrid = tMaxX;
|
|
108
|
+
tMaxX += tDeltaX;
|
|
109
|
+
currentX += stepX;
|
|
110
|
+
currentNormal = { x: -stepX, y: 0, z: 0 };
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
hitDistanceGrid = tMaxZ;
|
|
114
|
+
tMaxZ += tDeltaZ;
|
|
115
|
+
currentZ += stepZ;
|
|
116
|
+
currentNormal = { x: 0, y: 0, z: -stepZ };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
if (tMaxY < tMaxZ) {
|
|
121
|
+
hitDistanceGrid = tMaxY;
|
|
122
|
+
tMaxY += tDeltaY;
|
|
123
|
+
currentY += stepY;
|
|
124
|
+
currentNormal = { x: 0, y: -stepY, z: 0 };
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
hitDistanceGrid = tMaxZ;
|
|
128
|
+
tMaxZ += tDeltaZ;
|
|
129
|
+
currentZ += stepZ;
|
|
130
|
+
currentNormal = { x: 0, y: 0, z: -stepZ };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (hitDistanceGrid > tMax) {
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
1
139
|
/**
|
|
2
140
|
* Deterministic greedy box merge: scan z→y→x ascending and grow each unconsumed
|
|
3
141
|
* solid cell into the largest box along +x, then +y, then +z. A solid n³ chunk
|
package/dist/physics3d.d.ts
CHANGED
|
@@ -202,6 +202,23 @@ export interface DeterministicPhysicsDetailedHit3D extends DeterministicPhysicsH
|
|
|
202
202
|
readonly point: Point3D;
|
|
203
203
|
readonly normal: Point3D;
|
|
204
204
|
readonly penetration: number;
|
|
205
|
+
readonly childIndex?: number;
|
|
206
|
+
}
|
|
207
|
+
export interface DeterministicKinematicPose3D {
|
|
208
|
+
readonly id: string;
|
|
209
|
+
readonly x: number;
|
|
210
|
+
readonly y: number;
|
|
211
|
+
readonly z: number;
|
|
212
|
+
readonly rx?: number;
|
|
213
|
+
readonly ry?: number;
|
|
214
|
+
readonly rz?: number;
|
|
215
|
+
readonly orientation?: DeterministicPhysicsQuaternion3D;
|
|
216
|
+
readonly vx?: number;
|
|
217
|
+
readonly vy?: number;
|
|
218
|
+
readonly vz?: number;
|
|
219
|
+
readonly angularVelX?: number;
|
|
220
|
+
readonly angularVelY?: number;
|
|
221
|
+
readonly angularVelZ?: number;
|
|
205
222
|
}
|
|
206
223
|
export interface DeterministicPhysicsScheduledQuery3D {
|
|
207
224
|
readonly id: string;
|
|
@@ -363,6 +380,15 @@ export interface DeterministicPhysicsWorldEdit3D {
|
|
|
363
380
|
* inside each edit list.
|
|
364
381
|
*/
|
|
365
382
|
export declare function applyDeterministicWorldEdit3D(world: DeterministicPhysicsWorld3D, edit: DeterministicPhysicsWorldEdit3D): DeterministicPhysicsWorld3D;
|
|
383
|
+
/**
|
|
384
|
+
* Fast batch update of kinematic body transforms and velocities without
|
|
385
|
+
* allocating Set instances or re-sorting world bodies. Wakes touching dynamic
|
|
386
|
+
* bodies across active contact pairs. If linear velocity (vx, vy, vz) is omitted
|
|
387
|
+
* and dtTicks (> 0) is supplied, linear velocity is derived as (newPos - oldPos) / dtTicks.
|
|
388
|
+
*/
|
|
389
|
+
export declare function setDeterministicKinematicPoses3D(world: DeterministicPhysicsWorld3D, poses: readonly DeterministicKinematicPose3D[], options?: {
|
|
390
|
+
readonly dtTicks?: number;
|
|
391
|
+
}): DeterministicPhysicsWorld3D;
|
|
366
392
|
/**
|
|
367
393
|
* Apply a deterministic impulse to a body (linear + angular via lever arm),
|
|
368
394
|
* waking the body and its contact island. Returns a new canonical world.
|