@usions/sdk 2.2.0 → 2.11.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 +3 -2
- package/src/browser.js +2554 -122
- package/src/modules/backend-channel.js +76 -0
- package/src/modules/cloud.js +67 -0
- package/src/modules/core.js +6 -0
- package/src/modules/game-core.js +4 -0
- package/src/modules/game-direct.js +45 -0
- package/src/modules/game-netcode.js +346 -0
- package/src/modules/game-socket.js +4 -0
- package/src/modules/index.js +15 -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/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/types/index.d.ts +449 -0
package/README.md
CHANGED
|
@@ -121,6 +121,91 @@ Usion.game.disconnect()
|
|
|
121
121
|
Usion.game.isConnected() // boolean
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
+
### Netcode (low-latency realtime toolkit)
|
|
125
|
+
|
|
126
|
+
Zero-dependency, transport-agnostic helpers for smooth, lossless multiplayer.
|
|
127
|
+
They work across all connection modes (platform / direct / proxy) and both
|
|
128
|
+
platforms. Adopt incrementally. Full guide: [`docs/realtime-netcode.md`](../../docs/realtime-netcode.md).
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
// 1. Snapshot interpolation — smooth rendering, absorbs jitter & packet loss
|
|
132
|
+
const interp = Usion.game.createInterpolation({ serverFps: 20 });
|
|
133
|
+
Usion.game.onRealtime((m) => { if (m.action_type === 'state') interp.add(m.action_data); });
|
|
134
|
+
function render() {
|
|
135
|
+
const players = interp.calc('x y angle(deg)'); // entities at "now - bufferMs"
|
|
136
|
+
if (players) draw(players);
|
|
137
|
+
requestAnimationFrame(render);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 2. Sequence-guarded, delta-compressed snapshot sender (cuts bandwidth + flood)
|
|
141
|
+
const snap = Usion.game.createSnapshotSender({ hz: 20, channel: 'state', precision: 2 });
|
|
142
|
+
loop(() => snap.send(world));
|
|
143
|
+
// receiver (drops stale/out-of-order frames; never patches the wrong base):
|
|
144
|
+
const rx = Usion.game.createSnapshotReceiver();
|
|
145
|
+
let world = {};
|
|
146
|
+
Usion.game.onRealtime((m) => { if (m.action_type === 'state') world = rx.receive(m.action_data); });
|
|
147
|
+
|
|
148
|
+
// 3. Client-side prediction + reconciliation + smooth error blending
|
|
149
|
+
const p = Usion.game.createPredictor({ apply: (s, i) => move(s, i), initialState, smooth: { keys: 'x y' } });
|
|
150
|
+
const { seq } = p.predict(input); // apply locally, send seq
|
|
151
|
+
Usion.game.onStateUpdate((s) => p.reconcile(s.game_state.me, s.game_state.ackSeq));
|
|
152
|
+
function render() { draw(p.view()); requestAnimationFrame(render); } // blended, no snaps
|
|
153
|
+
|
|
154
|
+
// 4. WebRTC peer-to-peer (UDP) — escapes TCP head-of-line blocking
|
|
155
|
+
const mesh = Usion.game.createMesh({
|
|
156
|
+
role: amHost ? 'host' : 'guest',
|
|
157
|
+
iceServers: Usion.netcode.MeshConnection.iceServers({ turn: 'turn:host:3478', turnUsername: 'u', turnCredential: 'p' }),
|
|
158
|
+
});
|
|
159
|
+
mesh.onMessage = (d) => applyRemote(d);
|
|
160
|
+
await mesh.start();
|
|
161
|
+
mesh.send({ x, y }); // unreliable + unordered + sequenced (drops stale)
|
|
162
|
+
mesh.sendReliable({ event }); // ordered, must-arrive
|
|
163
|
+
|
|
164
|
+
// 4b. N-player mesh
|
|
165
|
+
const net = Usion.game.createMeshNetwork();
|
|
166
|
+
await net.setRoster(allPlayerIds);
|
|
167
|
+
net.onMessage = (peerId, d) => applyRemote(peerId, d);
|
|
168
|
+
net.broadcast({ x, y });
|
|
169
|
+
|
|
170
|
+
// 4c. WebTransport (HTTP/3) — lowest-latency client-server (no TCP HOL blocking)
|
|
171
|
+
const wt = Usion.game.createWebTransport({ url: 'https://game.example.com:4433/wt' });
|
|
172
|
+
wt.onMessage = (m, ch) => { if (ch === 'datagram') applyState(m); };
|
|
173
|
+
await wt.connect();
|
|
174
|
+
wt.send(stateBytes); // UDP-like datagram (unreliable, sequenced)
|
|
175
|
+
wt.sendReliable({ event }); // reliable stream
|
|
176
|
+
// (server: use the open-source @fails-components/webtransport Node HTTP/3 server)
|
|
177
|
+
|
|
178
|
+
// 4d. Declarative replication — mutate a plain object, it auto-syncs (host)
|
|
179
|
+
const world = Usion.game.replicate({ players: [] }, { channel: 'world', hz: 20, precision: 2 });
|
|
180
|
+
world.state.players.push({ id: myId, x: 0, y: 0 }); // just mutate it
|
|
181
|
+
// client:
|
|
182
|
+
const remote = Usion.game.replica({ channel: 'world', interpolate: { keys: 'x y', group: 'players' } });
|
|
183
|
+
function render() { draw(remote.view()); requestAnimationFrame(render); }
|
|
184
|
+
|
|
185
|
+
// 4e. Test under a bad network locally (latency / jitter / loss)
|
|
186
|
+
Usion.game.simulateNetwork({ latencyMs: 120, jitterMs: 30, lossPct: 5 });
|
|
187
|
+
Usion.game.simulateNetwork(null); // off
|
|
188
|
+
|
|
189
|
+
// 4f. Deterministic lockstep (inputs-only sim + free replays) — MOBA/RTS
|
|
190
|
+
const ls = Usion.game.createLockstep({ playerId: myId, players, step: (frame, inputs) => sim(frame, inputs) });
|
|
191
|
+
gameLoop(() => { ls.submit(localInput); ls.tick(); });
|
|
192
|
+
// replay later: Usion.netcode.Lockstep.replay(ls.getReplay(), sim);
|
|
193
|
+
|
|
194
|
+
// 4g. Server-side lag compensation (server rewind) — fair hits across pings
|
|
195
|
+
const lag = Usion.game.createLagCompensator({ historyMs: 1000 });
|
|
196
|
+
serverTick(() => lag.record(allEntities)); // each tick
|
|
197
|
+
function onShot(shooter, ray) { const past = lag.rewindForClient(shooter.rtt, shooter.interpMs); resolveHit(ray, past); }
|
|
198
|
+
|
|
199
|
+
// 5. Telemetry, delta + binary helpers
|
|
200
|
+
await Usion.game.ping(); Usion.game.getRtt(); // ms
|
|
201
|
+
const d = Usion.game.diff(prev, next); const next2 = Usion.game.patch(prev, d);
|
|
202
|
+
const bytes = Usion.game.encode(state); const back = Usion.game.decode(bytes);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Also available directly: `Usion.netcode.{ SnapshotInterpolation, Predictor,
|
|
206
|
+
Coalescer, PingMeter, MeshConnection, MeshNetwork, diff, patch, quantize,
|
|
207
|
+
encode, decode }`.
|
|
208
|
+
|
|
124
209
|
### Utility
|
|
125
210
|
|
|
126
211
|
```javascript
|
|
@@ -130,6 +215,39 @@ Usion.exit() // Close the mini-app
|
|
|
130
215
|
Usion.log(message) // Debug log
|
|
131
216
|
```
|
|
132
217
|
|
|
218
|
+
### Leaderboard (opt-in per game)
|
|
219
|
+
|
|
220
|
+
Enable on the service (`leaderboard: { enabled: true, order: 'desc' }`), then:
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
await Usion.leaderboard.submit(1500, { level: 3 }); // best score is kept
|
|
224
|
+
const friends = await Usion.leaderboard.friends(); // people you've messaged + you
|
|
225
|
+
const top = await Usion.leaderboard.top({ limit: 20 });// global top
|
|
226
|
+
const me = await Usion.leaderboard.me(); // { score, rank, total }
|
|
227
|
+
// entry: { user_id, name, avatar, score, rank, is_me, metadata }
|
|
228
|
+
```
|
|
229
|
+
`friends()` is scoped to users you've chatted with (your conversations) plus
|
|
230
|
+
yourself. Works in standalone *and* embedded games (rides the backend channel).
|
|
231
|
+
|
|
232
|
+
### Matchmaking (play with online strangers)
|
|
233
|
+
|
|
234
|
+
Pair players who don't know each other into a game:
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
const match = await Usion.matchmaking.find(); // resolves when matched
|
|
238
|
+
// match = { roomId, players, serviceId }
|
|
239
|
+
await Usion.game.connect();
|
|
240
|
+
await Usion.game.join(match.roomId);
|
|
241
|
+
|
|
242
|
+
// while waiting you can stop:
|
|
243
|
+
Usion.matchmaking.cancel();
|
|
244
|
+
// or react to matches:
|
|
245
|
+
Usion.matchmaking.onMatch(({ roomId, players }) => { /* ... */ });
|
|
246
|
+
```
|
|
247
|
+
`find({ size })` controls party size (default 2). Works standalone *and*
|
|
248
|
+
embedded (rides the backend channel). Pair this with `Usion.lobby` for
|
|
249
|
+
invite-a-friend, and `Usion.matchmaking` for quick-match with strangers.
|
|
250
|
+
|
|
133
251
|
## TypeScript
|
|
134
252
|
|
|
135
253
|
Full type declarations included:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usions/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Usion Mini App SDK for iframe games and services",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/modules/index.js",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"build": "rollup -c",
|
|
27
27
|
"build:copy": "npm run build && cp src/browser.js ../../web/public/usion-sdk.js && cp src/browser.js ../../microservices/shared/usion-sdk.js",
|
|
28
28
|
"watch": "rollup -c --watch",
|
|
29
|
-
"test": "npm run build && vitest run"
|
|
29
|
+
"test": "npm run build && vitest run",
|
|
30
|
+
"prepublishOnly": "npm run build && vitest run"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"rollup": "^4.0.0",
|