@usions/sdk 2.1.5 → 2.10.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/README.md +118 -0
- package/package.json +6 -3
- package/src/browser.js +2658 -124
- package/src/modules/backend-channel.js +76 -0
- package/src/modules/core.js +61 -0
- package/src/modules/game-core.js +4 -0
- package/src/modules/game-direct.js +45 -0
- package/src/modules/game-methods.js +107 -1
- package/src/modules/game-netcode.js +346 -0
- package/src/modules/game-proxy.js +4 -0
- package/src/modules/game-socket.js +4 -0
- package/src/modules/index.js +13 -0
- package/src/modules/leaderboard.js +46 -0
- package/src/modules/lobby.js +103 -0
- package/src/modules/matchmaking.js +61 -0
- package/src/modules/misc.js +4 -0
- package/src/modules/netcode/binary.js +113 -0
- package/src/modules/netcode/delta.js +236 -0
- package/src/modules/netcode/index.js +41 -0
- package/src/modules/netcode/interpolation.js +235 -0
- package/src/modules/netcode/lagcomp.js +104 -0
- package/src/modules/netcode/lockstep.js +103 -0
- package/src/modules/netcode/mesh-network.js +103 -0
- package/src/modules/netcode/mesh.js +188 -0
- package/src/modules/netcode/netsim.js +77 -0
- package/src/modules/netcode/ping.js +69 -0
- package/src/modules/netcode/prediction.js +113 -0
- package/src/modules/netcode/sender.js +102 -0
- package/src/modules/netcode/webtransport.js +195 -0
- package/src/modules/wallet.js +5 -1
- package/types/index.d.ts +463 -0
package/types/index.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export interface UsionConfig {
|
|
|
16
16
|
theme?: 'light' | 'dark';
|
|
17
17
|
language?: string;
|
|
18
18
|
socketUrl?: string;
|
|
19
|
+
/** HTTP/3 WebTransport endpoint for direct-mode games (lowest latency). */
|
|
20
|
+
webTransportUrl?: string;
|
|
19
21
|
roomId?: string;
|
|
20
22
|
playerIds?: string[];
|
|
21
23
|
serviceId?: string;
|
|
@@ -213,6 +215,16 @@ export interface GameModule {
|
|
|
213
215
|
requestRematch(): void;
|
|
214
216
|
forfeit(): Promise<{ success: boolean; error?: string }>;
|
|
215
217
|
|
|
218
|
+
// Persisted state — survives iframe unmount/remount.
|
|
219
|
+
// Keyed by (player_id, room_id) in localStorage. Schema is up to the game.
|
|
220
|
+
saveState<T = any>(state: T): boolean;
|
|
221
|
+
loadState<T = any>(): T | null;
|
|
222
|
+
clearState(): void;
|
|
223
|
+
|
|
224
|
+
// Forward a debug snapshot to the parent. Rendered as a top-right
|
|
225
|
+
// overlay over the iframe when the host page is opened with `?debug=1`.
|
|
226
|
+
debug(payload: Record<string, any>): void;
|
|
227
|
+
|
|
216
228
|
// Event handlers
|
|
217
229
|
onJoined(callback: (data: GameJoinResult) => void): void;
|
|
218
230
|
onPlayerJoined(callback: (data: PlayerJoinedData) => void): void;
|
|
@@ -231,6 +243,400 @@ export interface GameModule {
|
|
|
231
243
|
|
|
232
244
|
// Generic event listener
|
|
233
245
|
on(event: string, callback: (data: any) => void): void;
|
|
246
|
+
|
|
247
|
+
// ─── Netcode helpers (low-latency realtime) ──────────────────
|
|
248
|
+
// JSON state delta compression.
|
|
249
|
+
diff(prev: any, next: any): any | undefined;
|
|
250
|
+
patch(base: any, delta: any): any;
|
|
251
|
+
/** Round numeric fields to a fixed precision (snapshot compression). */
|
|
252
|
+
quantize<T = any>(value: T, precision?: number): T;
|
|
253
|
+
/** Compact binary codec (use on direct/mesh transports). */
|
|
254
|
+
encode(value: any): Uint8Array;
|
|
255
|
+
decode(buf: ArrayBuffer | Uint8Array): any;
|
|
256
|
+
|
|
257
|
+
/** Snapshot interpolation buffer (adaptive buffer + capped extrapolation). */
|
|
258
|
+
createInterpolation(opts?: InterpolationOptions): SnapshotInterpolation;
|
|
259
|
+
/** Client-side prediction + reconciliation + error smoothing. */
|
|
260
|
+
createPredictor<S = any, I = any>(opts: PredictorOptions<S, I>): Predictor<S, I>;
|
|
261
|
+
/** Fixed-rate outbound coalescer (defaults to sending via game.realtime). */
|
|
262
|
+
createSender(opts?: SenderOptions): Coalescer;
|
|
263
|
+
/** Sequence-guarded, delta-compressed snapshot sender. Pair with createSnapshotReceiver. */
|
|
264
|
+
createSnapshotSender(opts?: SnapshotSenderOptions): SnapshotSender;
|
|
265
|
+
/** Receiver for createSnapshotSender (drops stale/out-of-order frames). */
|
|
266
|
+
createSnapshotReceiver(opts?: SnapshotReceiverOptions): SnapshotReceiver;
|
|
267
|
+
/** One-line WebRTC P2P (2-peer) setup; signaling over realtime. */
|
|
268
|
+
createMesh(opts: MeshOptions): MeshConnection;
|
|
269
|
+
/** N-peer full mesh; signaling routed per-peer over realtime. */
|
|
270
|
+
createMeshNetwork(opts?: MeshNetworkOptions): MeshNetwork;
|
|
271
|
+
/** WebTransport (HTTP/3) connection — lowest-latency client-server datagrams. */
|
|
272
|
+
createWebTransport(opts?: WebTransportOptions): WebTransportConnection;
|
|
273
|
+
/** Declarative replication (host): mutate the object, it auto-syncs. */
|
|
274
|
+
replicate<T = any>(obj: T, opts?: ReplicateOptions): Replicated<T>;
|
|
275
|
+
/** Declarative replication (client): receive + (optionally) interpolate. */
|
|
276
|
+
replica<S = any>(opts?: ReplicaOptions): Replica<S>;
|
|
277
|
+
/** Server-side lag compensation (history + rewind) for fair hit-resolution. */
|
|
278
|
+
createLagCompensator(opts?: LagCompensatorOptions): LagCompensator;
|
|
279
|
+
/** Deterministic lockstep (inputs-only sim + free replays). */
|
|
280
|
+
createLockstep(opts: LockstepOptions): Lockstep;
|
|
281
|
+
/** Inject latency/jitter/loss locally to test under bad networks (null = off). */
|
|
282
|
+
simulateNetwork(opts: NetworkSimOptions | null): NetworkSim | void;
|
|
283
|
+
|
|
284
|
+
/** Measure round-trip time once (single outstanding probe); ms or null. */
|
|
285
|
+
ping(): Promise<number | null>;
|
|
286
|
+
/** Latest smoothed round-trip time in ms (null until first ping). */
|
|
287
|
+
getRtt(): number | null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ─── Netcode toolkit ──────────────────────────────────────────────
|
|
291
|
+
|
|
292
|
+
export interface NetcodeEntity {
|
|
293
|
+
id: string | number;
|
|
294
|
+
[key: string]: any;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export interface Snapshot {
|
|
298
|
+
id?: string;
|
|
299
|
+
time?: number;
|
|
300
|
+
state: NetcodeEntity[] | { [group: string]: NetcodeEntity[] };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export interface InterpolationOptions {
|
|
304
|
+
/** Expected snapshot rate; sets the default buffer (default 20). */
|
|
305
|
+
serverFps?: number;
|
|
306
|
+
/** Fixed interpolation delay in ms (default ≈ 3 server frames). */
|
|
307
|
+
bufferMs?: number;
|
|
308
|
+
/** Grow the buffer with measured jitter (Source cl_interp_ratio style). */
|
|
309
|
+
adaptive?: boolean;
|
|
310
|
+
/** Adaptive buffer clamps. */
|
|
311
|
+
minBufferMs?: number;
|
|
312
|
+
maxBufferMs?: number;
|
|
313
|
+
/** Max forward extrapolation on buffer underrun, ms (0 = off; Source caps ~250). */
|
|
314
|
+
extrapolationMs?: number;
|
|
315
|
+
/** Render against snapshot.time (server clock domain) instead of arrival time. */
|
|
316
|
+
serverTime?: boolean;
|
|
317
|
+
/** Snapshot history depth (default 120). */
|
|
318
|
+
maxSize?: number;
|
|
319
|
+
/** Clock source override (default Date.now). */
|
|
320
|
+
now?: () => number;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export class SnapshotInterpolation {
|
|
324
|
+
constructor(opts?: InterpolationOptions);
|
|
325
|
+
getBufferMs(): number;
|
|
326
|
+
setBufferMs(ms: number): void;
|
|
327
|
+
getJitter(): number;
|
|
328
|
+
add(snapshot: Snapshot | NetcodeEntity[] | { [group: string]: NetcodeEntity[] }): void;
|
|
329
|
+
/** Interpolated entities for the render instant, or null if no data yet. */
|
|
330
|
+
calc(keys: string, group?: string): NetcodeEntity[] | null;
|
|
331
|
+
vault: Vault;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export class Vault {
|
|
335
|
+
constructor(maxSize?: number);
|
|
336
|
+
add(snapshot: { time: number; state: any }): void;
|
|
337
|
+
readonly size: number;
|
|
338
|
+
setMaxSize(n: number): void;
|
|
339
|
+
latest(): { time: number; state: any } | null;
|
|
340
|
+
clear(): void;
|
|
341
|
+
straddle(time: number): [any, any];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export interface PredictorSmoothOptions {
|
|
345
|
+
keys?: string | string[];
|
|
346
|
+
rate?: number;
|
|
347
|
+
snapTo?: number;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export interface PredictorOptions<S = any, I = any> {
|
|
351
|
+
apply: (state: S, input: I) => S;
|
|
352
|
+
initialState?: S;
|
|
353
|
+
/** Smoothly blend correction errors instead of snapping (Overwatch style). */
|
|
354
|
+
smooth?: PredictorSmoothOptions | string;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export class Predictor<S = any, I = any> {
|
|
358
|
+
constructor(opts: PredictorOptions<S, I>);
|
|
359
|
+
readonly state: S;
|
|
360
|
+
readonly pending: Array<{ seq: number; input: I }>;
|
|
361
|
+
readonly lastSeq: number;
|
|
362
|
+
predict(input: I): { seq: number; state: S };
|
|
363
|
+
reconcile(serverState: S, ackedSeq: number): S;
|
|
364
|
+
/** Render state: corrected + decaying error offset. Call once per frame. */
|
|
365
|
+
view(rate?: number): S;
|
|
366
|
+
reset(state?: S): void;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export interface CoalescerOptions {
|
|
370
|
+
hz?: number;
|
|
371
|
+
onFlush: (entries: Array<{ type: string; data: any }>) => void;
|
|
372
|
+
autoStart?: boolean;
|
|
373
|
+
setInterval?: (fn: () => void, ms: number) => any;
|
|
374
|
+
clearInterval?: (handle: any) => void;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export class Coalescer {
|
|
378
|
+
constructor(opts: CoalescerOptions);
|
|
379
|
+
readonly running: boolean;
|
|
380
|
+
/** Latest-wins: only the newest data for `type` is sent next flush. */
|
|
381
|
+
queue(type: string, data: any): void;
|
|
382
|
+
/** Buffered: every value for `type` is kept and sent next flush. */
|
|
383
|
+
append(type: string, data: any): void;
|
|
384
|
+
drain(): Array<{ type: string; data: any }>;
|
|
385
|
+
flush(): void;
|
|
386
|
+
start(): void;
|
|
387
|
+
stop(): void;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export interface SenderOptions {
|
|
391
|
+
hz?: number;
|
|
392
|
+
autoStart?: boolean;
|
|
393
|
+
send?: (type: string, data: any) => void;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export interface SnapshotSenderOptions extends SenderOptions {
|
|
397
|
+
/** realtime action_type to send under (default 'state'). */
|
|
398
|
+
channel?: string;
|
|
399
|
+
/** Use delta compression with periodic keyframes (default true). */
|
|
400
|
+
delta?: boolean;
|
|
401
|
+
/** Send a full keyframe every N deltas so lost deltas self-heal (default 30). */
|
|
402
|
+
keyframeEvery?: number;
|
|
403
|
+
/** Quantize numeric fields to this many decimals before diffing. */
|
|
404
|
+
precision?: number;
|
|
405
|
+
/** Binary-encode the wire payload: true (built-in) or a custom encoder. */
|
|
406
|
+
encode?: boolean | ((payload: any) => any);
|
|
407
|
+
/** Auto-read state each tick from this getter (basis for game.replicate). */
|
|
408
|
+
source?: () => any;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export interface ReplicateOptions extends SnapshotSenderOptions {}
|
|
412
|
+
|
|
413
|
+
export interface Replicated<T = any> {
|
|
414
|
+
state: T;
|
|
415
|
+
flush(): void;
|
|
416
|
+
start(): void;
|
|
417
|
+
stop(): void;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export interface ReplicaOptions {
|
|
421
|
+
channel?: string;
|
|
422
|
+
decode?: boolean | ((buf: any) => any);
|
|
423
|
+
/** Interpolation keys ('x y') or an InterpolationOptions object to smooth entities. */
|
|
424
|
+
interpolate?: string | InterpolationOptions;
|
|
425
|
+
keys?: string;
|
|
426
|
+
group?: string;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export interface Replica<S = any> {
|
|
430
|
+
readonly state: S;
|
|
431
|
+
view(): any;
|
|
432
|
+
onChange(cb: (state: S) => void): void;
|
|
433
|
+
stop(): void;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export interface NetworkSimOptions {
|
|
437
|
+
latencyMs?: number;
|
|
438
|
+
jitterMs?: number;
|
|
439
|
+
lossPct?: number;
|
|
440
|
+
dupPct?: number;
|
|
441
|
+
setTimeout?: (fn: () => void, ms: number) => any;
|
|
442
|
+
clearTimeout?: (handle: any) => void;
|
|
443
|
+
random?: () => number;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export class NetworkSim {
|
|
447
|
+
constructor(opts?: NetworkSimOptions);
|
|
448
|
+
latencyMs: number; jitterMs: number; lossPct: number; dupPct: number;
|
|
449
|
+
set(opts: NetworkSimOptions): NetworkSim;
|
|
450
|
+
wrap<F extends (...args: any[]) => any>(fn: F): F;
|
|
451
|
+
flush(): void;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export interface LockstepOptions {
|
|
455
|
+
playerId: string;
|
|
456
|
+
players: string[];
|
|
457
|
+
step: (frame: number, inputs: Record<string, any>) => void;
|
|
458
|
+
send?: (msg: { frame: number; playerId: string; input: any }) => void;
|
|
459
|
+
inputDelay?: number;
|
|
460
|
+
idleInput?: any;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export class Lockstep {
|
|
464
|
+
constructor(opts: LockstepOptions);
|
|
465
|
+
readonly frame: number;
|
|
466
|
+
readonly players: string[];
|
|
467
|
+
submit(input: any): number;
|
|
468
|
+
receive(msg: { frame: number; playerId: string; input: any }): void;
|
|
469
|
+
tick(): number;
|
|
470
|
+
isStalled(): boolean;
|
|
471
|
+
getReplay(): Array<{ frame: number; inputs: Record<string, any> }>;
|
|
472
|
+
static replay(log: Array<{ frame: number; inputs: Record<string, any> }>, step: (frame: number, inputs: Record<string, any>) => void): void;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export interface LagCompensatorOptions {
|
|
476
|
+
historyMs?: number;
|
|
477
|
+
maxSize?: number;
|
|
478
|
+
now?: () => number;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export class LagCompensator {
|
|
482
|
+
constructor(opts?: LagCompensatorOptions);
|
|
483
|
+
readonly size: number;
|
|
484
|
+
record(entities: Array<{ id: string | number; [k: string]: any }>, time?: number): void;
|
|
485
|
+
rewind(time: number, keys?: string[]): Record<string, any>;
|
|
486
|
+
rewindForClient(rttMs: number, interpBufferMs: number, opts?: { maxRewindMs?: number; keys?: string[] }): Record<string, any>;
|
|
487
|
+
clear(): void;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export interface SnapshotSender {
|
|
491
|
+
send(state: any): void;
|
|
492
|
+
flush(): void;
|
|
493
|
+
start(): void;
|
|
494
|
+
stop(): void;
|
|
495
|
+
reset(): void;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
export interface SnapshotReceiverOptions {
|
|
499
|
+
/** Binary-decode incoming payloads: true (built-in) or a custom decoder. */
|
|
500
|
+
decode?: boolean | ((buf: any) => any);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export interface SnapshotReceiver {
|
|
504
|
+
/** Apply a message from the sender; returns the reconstructed state. */
|
|
505
|
+
receive<S = any>(msg: any): S;
|
|
506
|
+
readonly state: any;
|
|
507
|
+
readonly stats: { appliedSeq: number; baseSeq: number; dropped: number };
|
|
508
|
+
reset(): void;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
export interface PingMeterOptions {
|
|
512
|
+
alpha?: number;
|
|
513
|
+
now?: () => number;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export class PingMeter {
|
|
517
|
+
constructor(opts?: PingMeterOptions);
|
|
518
|
+
readonly rtt: number | null;
|
|
519
|
+
readonly latency: number | null;
|
|
520
|
+
readonly jitter: number;
|
|
521
|
+
readonly last: number | null;
|
|
522
|
+
begin(): number;
|
|
523
|
+
end(id: number): number | null;
|
|
524
|
+
sample(rttMs: number): number | null;
|
|
525
|
+
reset(): void;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export interface IceServerConfig {
|
|
529
|
+
stun?: string;
|
|
530
|
+
turn?: string;
|
|
531
|
+
turnUsername?: string;
|
|
532
|
+
turnCredential?: string;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
export interface MeshOptions {
|
|
536
|
+
role: 'host' | 'guest';
|
|
537
|
+
/** realtime action_type used for signaling (default 'signal'). */
|
|
538
|
+
signalChannel?: string;
|
|
539
|
+
iceServers?: RTCIceServer[];
|
|
540
|
+
/** Drop stale/out-of-order frames on the unreliable channel (default true). */
|
|
541
|
+
sequenced?: boolean;
|
|
542
|
+
/** Recover via ICE restart on connection failure (host; default true). */
|
|
543
|
+
autoReconnect?: boolean;
|
|
544
|
+
maxRestarts?: number;
|
|
545
|
+
RTCPeerConnection?: typeof RTCPeerConnection;
|
|
546
|
+
setTimeout?: (fn: () => void, ms: number) => any;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
export class MeshConnection {
|
|
550
|
+
constructor(opts: MeshOptions & { sendSignal: (payload: any) => void });
|
|
551
|
+
/** Build an iceServers array with optional TURN relay. */
|
|
552
|
+
static iceServers(cfg?: IceServerConfig): RTCIceServer[];
|
|
553
|
+
readonly connected: boolean;
|
|
554
|
+
readonly role: 'host' | 'guest';
|
|
555
|
+
onOpen: (() => void) | null;
|
|
556
|
+
onMessage: ((data: any, channel: 'unreliable' | 'reliable') => void) | null;
|
|
557
|
+
onClose: (() => void) | null;
|
|
558
|
+
onError: ((err: any) => void) | null;
|
|
559
|
+
onStateChange: ((state: string) => void) | null;
|
|
560
|
+
start(): Promise<void>;
|
|
561
|
+
handleSignal(payload: any): Promise<void>;
|
|
562
|
+
send(data: any): boolean;
|
|
563
|
+
sendReliable(data: any): boolean;
|
|
564
|
+
close(): void;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export interface MeshNetworkOptions {
|
|
568
|
+
selfId?: string;
|
|
569
|
+
signalChannel?: string;
|
|
570
|
+
iceServers?: RTCIceServer[];
|
|
571
|
+
sequenced?: boolean;
|
|
572
|
+
autoReconnect?: boolean;
|
|
573
|
+
RTCPeerConnection?: typeof RTCPeerConnection;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export class MeshNetwork {
|
|
577
|
+
constructor(opts: MeshNetworkOptions & { selfId: string; sendSignal: (toPeerId: string, payload: any) => void });
|
|
578
|
+
readonly selfId: string;
|
|
579
|
+
readonly peerIds: string[];
|
|
580
|
+
readonly connectedCount: number;
|
|
581
|
+
peer(peerId: string): MeshConnection | null;
|
|
582
|
+
addPeer(peerId: string): Promise<MeshConnection | null>;
|
|
583
|
+
setRoster(peerIds: string[]): Promise<void>;
|
|
584
|
+
removePeer(peerId: string): void;
|
|
585
|
+
handleSignal(fromPeerId: string, payload: any): Promise<void>;
|
|
586
|
+
send(peerId: string, data: any): boolean;
|
|
587
|
+
sendReliable(peerId: string, data: any): boolean;
|
|
588
|
+
broadcast(data: any): void;
|
|
589
|
+
broadcastReliable(data: any): void;
|
|
590
|
+
onPeerOpen: ((peerId: string) => void) | null;
|
|
591
|
+
onPeerClose: ((peerId: string) => void) | null;
|
|
592
|
+
onMessage: ((peerId: string, data: any, channel: 'unreliable' | 'reliable') => void) | null;
|
|
593
|
+
onError: ((peerId: string, err: any) => void) | null;
|
|
594
|
+
close(): void;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
export interface WebTransportOptions {
|
|
598
|
+
/** https:// HTTP/3 endpoint (defaults to Usion.config.webTransportUrl). */
|
|
599
|
+
url?: string;
|
|
600
|
+
/** For self-signed dev certificates. */
|
|
601
|
+
serverCertificateHashes?: Array<{ algorithm: string; value: BufferSource }>;
|
|
602
|
+
/** Drop stale/out-of-order datagrams (default true). */
|
|
603
|
+
sequenced?: boolean;
|
|
604
|
+
/** Injectable WebTransport constructor (tests). */
|
|
605
|
+
WebTransport?: any;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
export class WebTransportConnection {
|
|
609
|
+
constructor(opts: WebTransportOptions & { url: string });
|
|
610
|
+
readonly connected: boolean;
|
|
611
|
+
onOpen: (() => void) | null;
|
|
612
|
+
onMessage: ((data: any, channel: 'datagram' | 'reliable') => void) | null;
|
|
613
|
+
onClose: (() => void) | null;
|
|
614
|
+
onError: ((err: any) => void) | null;
|
|
615
|
+
connect(): Promise<void>;
|
|
616
|
+
/** Send over the unreliable datagram channel (sequenced). */
|
|
617
|
+
send(data: any): boolean;
|
|
618
|
+
/** Send over the reliable ordered stream. */
|
|
619
|
+
sendReliable(data: any): boolean;
|
|
620
|
+
close(): void;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
export interface NetcodeModule {
|
|
624
|
+
SnapshotInterpolation: typeof SnapshotInterpolation;
|
|
625
|
+
Vault: typeof Vault;
|
|
626
|
+
Predictor: typeof Predictor;
|
|
627
|
+
Coalescer: typeof Coalescer;
|
|
628
|
+
PingMeter: typeof PingMeter;
|
|
629
|
+
MeshConnection: typeof MeshConnection;
|
|
630
|
+
MeshNetwork: typeof MeshNetwork;
|
|
631
|
+
WebTransportConnection: typeof WebTransportConnection;
|
|
632
|
+
NetworkSim: typeof NetworkSim;
|
|
633
|
+
Lockstep: typeof Lockstep;
|
|
634
|
+
LagCompensator: typeof LagCompensator;
|
|
635
|
+
diff(prev: any, next: any): any | undefined;
|
|
636
|
+
patch(base: any, delta: any): any;
|
|
637
|
+
quantize<T = any>(value: T, precision?: number): T;
|
|
638
|
+
encode(value: any): Uint8Array;
|
|
639
|
+
decode(buf: ArrayBuffer | Uint8Array): any;
|
|
234
640
|
}
|
|
235
641
|
|
|
236
642
|
// ─── Results ────────────────────────────────────────────────────
|
|
@@ -306,6 +712,10 @@ export interface UsionSDK {
|
|
|
306
712
|
|
|
307
713
|
// Sharing
|
|
308
714
|
share(contentType: 'audio' | 'image' | 'video' | 'text' | 'mixed', data: ShareData): void;
|
|
715
|
+
shareToFeed(contentType: 'text' | 'image' | 'video' | 'audio' | 'mixed', data: {
|
|
716
|
+
text?: string;
|
|
717
|
+
media?: Array<{ type: 'image' | 'video' | 'audio'; url: string; thumbnailUrl?: string; width?: number; height?: number; duration?: number }>;
|
|
718
|
+
}): Promise<{ success: boolean; postId?: string; shareUrl?: string }>;
|
|
309
719
|
|
|
310
720
|
// Logging
|
|
311
721
|
log(msg: string): void;
|
|
@@ -332,6 +742,59 @@ export interface UsionSDK {
|
|
|
332
742
|
chat: ChatModule;
|
|
333
743
|
bot: BotModule;
|
|
334
744
|
game: GameModule;
|
|
745
|
+
lobby: LobbyModule;
|
|
746
|
+
leaderboard: LeaderboardModule;
|
|
747
|
+
matchmaking: MatchmakingModule;
|
|
748
|
+
netcode: NetcodeModule;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
export interface Match { roomId: string; players: string[]; serviceId?: string; }
|
|
752
|
+
|
|
753
|
+
export interface MatchmakingModule {
|
|
754
|
+
/** Join the quick-match queue; resolves when paired with online strangers. */
|
|
755
|
+
find(serviceId?: string, opts?: { size?: number }): Promise<Match>;
|
|
756
|
+
/** Leave the queue / stop waiting. */
|
|
757
|
+
cancel(): Promise<any>;
|
|
758
|
+
/** Called whenever a match is found. */
|
|
759
|
+
onMatch(cb: (match: Match) => void): void;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
export interface LeaderboardEntry {
|
|
763
|
+
user_id: string;
|
|
764
|
+
name?: string | null;
|
|
765
|
+
avatar?: string | null;
|
|
766
|
+
score: number;
|
|
767
|
+
rank: number;
|
|
768
|
+
is_me: boolean;
|
|
769
|
+
metadata?: any;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
export interface LeaderboardModule {
|
|
773
|
+
/** Submit a score (best is kept per the service's order config). Opt-in per game. */
|
|
774
|
+
submit(score: number, metadata?: any, opts?: { serviceId?: string }): Promise<{ success: boolean; score: number; best: number; rank: number; updated: boolean }>;
|
|
775
|
+
/** Leaderboard of people you've messaged (plus you). */
|
|
776
|
+
friends(opts?: { serviceId?: string; limit?: number }): Promise<LeaderboardEntry[]>;
|
|
777
|
+
/** Global top N. */
|
|
778
|
+
top(opts?: { serviceId?: string; limit?: number }): Promise<LeaderboardEntry[]>;
|
|
779
|
+
/** Your own score + global rank. */
|
|
780
|
+
me(opts?: { serviceId?: string }): Promise<{ score: number | null; rank: number | null; total: number; metadata?: any }>;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
export interface LobbyMember { id: string; name?: string; ready: boolean; }
|
|
784
|
+
export interface LobbyState { code: string | null; host: string | null; status: string | null; members: LobbyMember[]; }
|
|
785
|
+
|
|
786
|
+
export interface LobbyModule {
|
|
787
|
+
readonly state: LobbyState;
|
|
788
|
+
onUpdate(cb: (state: { code: string; host: string; status: string; members: LobbyMember[] }) => void): void;
|
|
789
|
+
onStarted(cb: (data: { room_id: string; by: string; player_ids?: string[] }) => void): void;
|
|
790
|
+
create(opts?: { maxPlayers?: number; public?: boolean }): Promise<{ code: string }>;
|
|
791
|
+
join(code: string): Promise<{ code: string }>;
|
|
792
|
+
leave(): Promise<void>;
|
|
793
|
+
setReady(ready?: boolean): Promise<any>;
|
|
794
|
+
allReady(): boolean;
|
|
795
|
+
isHost(): boolean;
|
|
796
|
+
start(roomId: string): Promise<any>;
|
|
797
|
+
queue(serviceId: string, opts?: { conversationId?: string }): Promise<any>;
|
|
335
798
|
}
|
|
336
799
|
|
|
337
800
|
declare const Usion: UsionSDK;
|