@carverjs/multiplayer 0.0.1
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/dist/NetworkManager-DrKM2tEx.d.mts +369 -0
- package/dist/NetworkManager-nvVAOr1O.d.ts +369 -0
- package/dist/chunk-3KT73N2S.mjs +655 -0
- package/dist/chunk-3KT73N2S.mjs.map +1 -0
- package/dist/chunk-EO3YNPRQ.mjs +817 -0
- package/dist/chunk-EO3YNPRQ.mjs.map +1 -0
- package/dist/chunk-UD6FDZMX.mjs +581 -0
- package/dist/chunk-UD6FDZMX.mjs.map +1 -0
- package/dist/firebase-CPu87KA0.d.ts +100 -0
- package/dist/firebase-PE6MxGdJ.d.mts +100 -0
- package/dist/index.d.mts +316 -0
- package/dist/index.d.ts +316 -0
- package/dist/index.js +3817 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1743 -0
- package/dist/index.mjs.map +1 -0
- package/dist/strategy.d.mts +7 -0
- package/dist/strategy.d.ts +7 -0
- package/dist/strategy.js +619 -0
- package/dist/strategy.js.map +1 -0
- package/dist/strategy.mjs +11 -0
- package/dist/strategy.mjs.map +1 -0
- package/dist/sync.d.mts +212 -0
- package/dist/sync.d.ts +212 -0
- package/dist/sync.js +845 -0
- package/dist/sync.js.map +1 -0
- package/dist/sync.mjs +11 -0
- package/dist/sync.mjs.map +1 -0
- package/dist/transport.d.mts +159 -0
- package/dist/transport.d.ts +159 -0
- package/dist/transport.js +1274 -0
- package/dist/transport.js.map +1 -0
- package/dist/transport.mjs +19 -0
- package/dist/transport.mjs.map +1 -0
- package/dist/types-5LHBOW08.d.mts +74 -0
- package/dist/types-5LHBOW08.d.ts +74 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +1 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +73 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { S as SignalingStrategy, a as StrategyConfig } from './types-5LHBOW08.js';
|
|
4
|
+
export { F as FirebaseStrategyConfig, M as MqttStrategyConfig, P as PeerMetadata, R as RoomAnnouncement } from './types-5LHBOW08.js';
|
|
5
|
+
import { k as NetworkManager, U as UseRoomOptions, l as ConnectionState, R as Room, m as CarverMultiplayerError, C as CarverTransport, n as UseLobbyOptions, o as RoomConfig, P as Player, c as RoomState, p as UseMultiplayerOptions, N as NetworkQuality, j as SyncMode, E as EntityState } from './NetworkManager-nvVAOr1O.js';
|
|
6
|
+
export { b as CarverChannel, q as CarverErrorCode, a as ChannelOptions, f as EntityState2D, g as EntityState3D, h as EventPacket, I as InputPacket, J as JoinOptions, M as MultiplayerContextValue, i as SnapshotPacket, T as TransportConfig } from './NetworkManager-nvVAOr1O.js';
|
|
7
|
+
export { F as FirebaseStrategy, M as MqttStrategy } from './firebase-CPu87KA0.js';
|
|
8
|
+
|
|
9
|
+
interface MultiplayerContextValue {
|
|
10
|
+
appId: string;
|
|
11
|
+
strategy: SignalingStrategy;
|
|
12
|
+
iceServers?: RTCIceServer[];
|
|
13
|
+
networkManager: NetworkManager;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface MultiplayerProviderProps {
|
|
17
|
+
/**
|
|
18
|
+
* Unique application identifier. Used to namespace rooms across the
|
|
19
|
+
* signaling network so different games don't interfere.
|
|
20
|
+
*/
|
|
21
|
+
appId: string;
|
|
22
|
+
/**
|
|
23
|
+
* Signaling strategy configuration. Defaults to MQTT (free public brokers).
|
|
24
|
+
*
|
|
25
|
+
* ```tsx
|
|
26
|
+
* // Free (MQTT, zero config)
|
|
27
|
+
* <MultiplayerProvider appId="my-game">
|
|
28
|
+
*
|
|
29
|
+
* // Firebase (your own project)
|
|
30
|
+
* <MultiplayerProvider
|
|
31
|
+
* appId="my-game"
|
|
32
|
+
* strategy={{ type: 'firebase', databaseURL: 'https://my-project.firebaseio.com' }}
|
|
33
|
+
* >
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
strategy?: StrategyConfig;
|
|
37
|
+
/**
|
|
38
|
+
* ICE servers (STUN + TURN). Defaults to public Google/Cloudflare STUN.
|
|
39
|
+
*
|
|
40
|
+
* To add your own TURN server (e.g. Cloudflare TURN):
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <MultiplayerProvider
|
|
43
|
+
* appId="my-game"
|
|
44
|
+
* iceServers={[
|
|
45
|
+
* { urls: 'stun:stun.cloudflare.com:3478' },
|
|
46
|
+
* { urls: 'turn:turn.cloudflare.com:3478', username: '...', credential: '...' },
|
|
47
|
+
* ]}
|
|
48
|
+
* >
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
iceServers?: RTCIceServer[];
|
|
52
|
+
children: ReactNode;
|
|
53
|
+
}
|
|
54
|
+
declare function MultiplayerProvider({ appId, strategy: strategyConfig, iceServers, children, }: MultiplayerProviderProps): react.FunctionComponentElement<react.ProviderProps<MultiplayerContextValue | null>>;
|
|
55
|
+
|
|
56
|
+
interface MultiplayerBridgeProps {
|
|
57
|
+
children: ReactNode;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Bridges the MultiplayerContext from the parent React tree into an R3F Canvas.
|
|
61
|
+
*
|
|
62
|
+
* R3F's `<Canvas>` uses a separate React reconciler, so React contexts from the
|
|
63
|
+
* parent tree are not automatically available inside the Canvas. This component
|
|
64
|
+
* reads the MultiplayerContext value from the parent tree and re-provides it
|
|
65
|
+
* inside the Canvas, making all CarverJS multiplayer hooks work seamlessly.
|
|
66
|
+
*
|
|
67
|
+
* Place `<MultiplayerBridge>` as a direct child of `<Game>`, wrapping `<World>`
|
|
68
|
+
* and all scene content that uses multiplayer hooks.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```tsx
|
|
72
|
+
* <MultiplayerProvider appId="my-game">
|
|
73
|
+
* <Game mode="2d">
|
|
74
|
+
* <MultiplayerBridge>
|
|
75
|
+
* <World>
|
|
76
|
+
* <MyScene />
|
|
77
|
+
* </World>
|
|
78
|
+
* </MultiplayerBridge>
|
|
79
|
+
* </Game>
|
|
80
|
+
* </MultiplayerProvider>
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function MultiplayerBridge({ children }: MultiplayerBridgeProps): react.FunctionComponentElement<react.ProviderProps<MultiplayerContextValue | null>> | react.DOMElement<react.DOMAttributes<Element>, Element>;
|
|
84
|
+
|
|
85
|
+
interface UseRoomReturn {
|
|
86
|
+
roomId: string | null;
|
|
87
|
+
connectionState: ConnectionState;
|
|
88
|
+
isHost: boolean;
|
|
89
|
+
hostId: string | null;
|
|
90
|
+
selfId: string | null;
|
|
91
|
+
room: Room | null;
|
|
92
|
+
error: CarverMultiplayerError | null;
|
|
93
|
+
join: (roomId: string, options?: {
|
|
94
|
+
password?: string;
|
|
95
|
+
}) => Promise<void>;
|
|
96
|
+
leave: () => void;
|
|
97
|
+
setReady: (ready: boolean) => void;
|
|
98
|
+
setMetadata: (meta: Record<string, unknown>) => void;
|
|
99
|
+
setRoomMetadata: (meta: Record<string, unknown>) => void;
|
|
100
|
+
transport: CarverTransport | null;
|
|
101
|
+
}
|
|
102
|
+
declare function useRoom(roomId?: string, options?: UseRoomOptions): UseRoomReturn;
|
|
103
|
+
|
|
104
|
+
interface UseLobbyReturn {
|
|
105
|
+
rooms: Room[];
|
|
106
|
+
isLoading: boolean;
|
|
107
|
+
error: CarverMultiplayerError | null;
|
|
108
|
+
refresh: () => void;
|
|
109
|
+
createRoom: (config: RoomConfig) => Promise<string>;
|
|
110
|
+
}
|
|
111
|
+
declare function useLobby(options?: UseLobbyOptions): UseLobbyReturn;
|
|
112
|
+
|
|
113
|
+
interface UsePlayersReturn {
|
|
114
|
+
players: Player[];
|
|
115
|
+
self: Player | null;
|
|
116
|
+
host: Player | null;
|
|
117
|
+
count: number;
|
|
118
|
+
allReady: boolean;
|
|
119
|
+
getPlayer: (peerId: string) => Player | undefined;
|
|
120
|
+
}
|
|
121
|
+
declare function usePlayers(): UsePlayersReturn;
|
|
122
|
+
|
|
123
|
+
interface UseHostReturn {
|
|
124
|
+
kick: (peerId: string, reason?: string) => void;
|
|
125
|
+
transferHost: (peerId: string) => void;
|
|
126
|
+
setRoomState: (state: RoomState) => void;
|
|
127
|
+
setMaxPlayers: (n: number) => void;
|
|
128
|
+
lockRoom: () => void;
|
|
129
|
+
unlockRoom: () => void;
|
|
130
|
+
}
|
|
131
|
+
declare function useHost(): UseHostReturn;
|
|
132
|
+
|
|
133
|
+
interface UseMultiplayerReturn {
|
|
134
|
+
isActive: boolean;
|
|
135
|
+
networkQuality: NetworkQuality;
|
|
136
|
+
tick: number;
|
|
137
|
+
serverTick: number;
|
|
138
|
+
drift: number;
|
|
139
|
+
syncEngine: SyncMode;
|
|
140
|
+
}
|
|
141
|
+
declare function useMultiplayer(options?: UseMultiplayerOptions): UseMultiplayerReturn;
|
|
142
|
+
|
|
143
|
+
interface UseNetworkEventsReturn<T extends {
|
|
144
|
+
[K in keyof T]: unknown;
|
|
145
|
+
} = Record<string, unknown>> {
|
|
146
|
+
sendEvent: <K extends keyof T & string>(type: K, payload: T[K], target?: string) => void;
|
|
147
|
+
broadcast: <K extends keyof T & string>(type: K, payload: T[K]) => void;
|
|
148
|
+
onEvent: <K extends keyof T & string>(type: K, callback: (data: T[K], peerId: string) => void) => () => void;
|
|
149
|
+
}
|
|
150
|
+
declare function useNetworkEvents<T extends {
|
|
151
|
+
[K in keyof T]: unknown;
|
|
152
|
+
} = Record<string, unknown>>(options?: {
|
|
153
|
+
hostValidation?: boolean;
|
|
154
|
+
}): UseNetworkEventsReturn<T>;
|
|
155
|
+
|
|
156
|
+
interface UseNetworkStateReturn {
|
|
157
|
+
/** Host only. Create a networked entity and broadcast its existence to all peers. */
|
|
158
|
+
spawn: (id: string, initialState: EntityState) => void;
|
|
159
|
+
/** Host only. Remove a networked entity and broadcast removal to all peers. */
|
|
160
|
+
despawn: (id: string) => void;
|
|
161
|
+
/** Client sends a spawn request to the host, who validates and spawns if the id is not taken. */
|
|
162
|
+
requestSpawn: (id: string, config: Record<string, unknown>) => void;
|
|
163
|
+
/** Read the current state of a networked entity by id. */
|
|
164
|
+
getState: (id: string) => EntityState | undefined;
|
|
165
|
+
/** Write a partial update to a networked entity. Host-authoritative: only the host may call this. */
|
|
166
|
+
setState: (id: string, partialState: Partial<EntityState>) => void;
|
|
167
|
+
/** Reactive map of all current networked entity states. */
|
|
168
|
+
entities: Map<string, EntityState>;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Phase 4.4 – Advanced escape-hatch hook for direct networked entity management.
|
|
172
|
+
*
|
|
173
|
+
* Provides host-authoritative spawn / despawn, client requestSpawn,
|
|
174
|
+
* and direct state read / write over a reliable+ordered data channel.
|
|
175
|
+
*/
|
|
176
|
+
declare function useNetworkState(): UseNetworkStateReturn;
|
|
177
|
+
|
|
178
|
+
interface DebugOverlayOptions {
|
|
179
|
+
position?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
180
|
+
/** Keyboard key used to toggle visibility (default: "F3") */
|
|
181
|
+
keyboardToggle?: string;
|
|
182
|
+
}
|
|
183
|
+
interface DebugStats {
|
|
184
|
+
tick: number;
|
|
185
|
+
serverTick: number;
|
|
186
|
+
drift: number;
|
|
187
|
+
/** Per-peer latency map or a single average value */
|
|
188
|
+
latencyMs: Map<string, number> | number;
|
|
189
|
+
/** Packet-loss rate in the range 0-1 */
|
|
190
|
+
packetLossRate: number;
|
|
191
|
+
/** Inbound bandwidth in bytes / second */
|
|
192
|
+
bandwidthIn: number;
|
|
193
|
+
/** Outbound bandwidth in bytes / second */
|
|
194
|
+
bandwidthOut: number;
|
|
195
|
+
networkQuality: "good" | "degraded" | "poor";
|
|
196
|
+
peerCount: number;
|
|
197
|
+
isHost: boolean;
|
|
198
|
+
syncMode: string;
|
|
199
|
+
}
|
|
200
|
+
declare class DebugOverlay {
|
|
201
|
+
private el;
|
|
202
|
+
private visible;
|
|
203
|
+
private lastHTML;
|
|
204
|
+
private readonly keyboardToggle;
|
|
205
|
+
private readonly handleKey;
|
|
206
|
+
constructor(options?: DebugOverlayOptions);
|
|
207
|
+
update(stats: DebugStats): void;
|
|
208
|
+
show(): void;
|
|
209
|
+
hide(): void;
|
|
210
|
+
toggle(): void;
|
|
211
|
+
destroy(): void;
|
|
212
|
+
private positionStyles;
|
|
213
|
+
private formatLatency;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
interface NetworkSimulatorOptions {
|
|
217
|
+
/** Additional one-way latency in milliseconds (default 0) */
|
|
218
|
+
latencyMs?: number;
|
|
219
|
+
/** Packet drop rate, 0-1 (default 0) */
|
|
220
|
+
packetLoss?: number;
|
|
221
|
+
/** Random jitter +/- milliseconds (default 0) */
|
|
222
|
+
jitterMs?: number;
|
|
223
|
+
}
|
|
224
|
+
interface SimulatorStats {
|
|
225
|
+
sentCount: number;
|
|
226
|
+
droppedCount: number;
|
|
227
|
+
avgLatencyMs: number;
|
|
228
|
+
}
|
|
229
|
+
declare class NetworkSimulator {
|
|
230
|
+
private latencyMs;
|
|
231
|
+
private packetLoss;
|
|
232
|
+
private jitterMs;
|
|
233
|
+
private sentCount;
|
|
234
|
+
private droppedCount;
|
|
235
|
+
private latencySum;
|
|
236
|
+
/** Active timeout handles so we can cancel them on destroy() */
|
|
237
|
+
private pending;
|
|
238
|
+
constructor(options?: NetworkSimulatorOptions);
|
|
239
|
+
/** Update simulation parameters at runtime. */
|
|
240
|
+
setOptions(options: Partial<NetworkSimulatorOptions>): void;
|
|
241
|
+
/**
|
|
242
|
+
* Wrap an existing send function so that every call goes through the
|
|
243
|
+
* simulated network conditions (latency, jitter, packet loss).
|
|
244
|
+
*/
|
|
245
|
+
wrapSend<T>(originalSend: (data: T, target?: string | string[]) => void): (data: T, target?: string | string[]) => void;
|
|
246
|
+
/** Current statistics snapshot. */
|
|
247
|
+
get stats(): SimulatorStats;
|
|
248
|
+
/** Cancel all pending delayed sends and clean up. */
|
|
249
|
+
destroy(): void;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
interface InterestManagerOptions {
|
|
253
|
+
/** Spatial hash cell size in world units. Default: 50 */
|
|
254
|
+
cellSize?: number;
|
|
255
|
+
/** Default relevance radius around a client's position. Default: 200 */
|
|
256
|
+
defaultRadius?: number;
|
|
257
|
+
/** Entity ids/names that are always sent to every client. */
|
|
258
|
+
alwaysRelevant?: string[];
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Spatial-hash-grid area-of-interest filter.
|
|
262
|
+
*
|
|
263
|
+
* Runs on the host side. Each tick the host feeds the full entity map via
|
|
264
|
+
* `updateEntities`, then queries per-client relevance with
|
|
265
|
+
* `getRelevantEntities` (or creates a single filter callback via
|
|
266
|
+
* `createFilter` for `HostAuthority.setInterestFilter`).
|
|
267
|
+
*/
|
|
268
|
+
declare class InterestManager {
|
|
269
|
+
/** cell-key -> set of entity ids occupying that cell */
|
|
270
|
+
private _cells;
|
|
271
|
+
/** entity id -> last-known 3D position */
|
|
272
|
+
private _entityPositions;
|
|
273
|
+
private _cellSize;
|
|
274
|
+
private _defaultRadius;
|
|
275
|
+
private _alwaysRelevant;
|
|
276
|
+
constructor(options?: InterestManagerOptions);
|
|
277
|
+
/**
|
|
278
|
+
* Rebuild the spatial hash from the authoritative entity map.
|
|
279
|
+
* Called once per host tick before any relevance queries.
|
|
280
|
+
*/
|
|
281
|
+
updateEntities(entities: Map<string, EntityState>): void;
|
|
282
|
+
/**
|
|
283
|
+
* Return the set of entity ids relevant to a single client.
|
|
284
|
+
*
|
|
285
|
+
* Relevance is the *union* of:
|
|
286
|
+
* 1. Entities whose cell overlaps the client's bounding sphere
|
|
287
|
+
* 2. Entities in the `alwaysRelevant` set
|
|
288
|
+
* 3. Entities owned by this client
|
|
289
|
+
*/
|
|
290
|
+
getRelevantEntities(clientPosition: {
|
|
291
|
+
x: number;
|
|
292
|
+
y: number;
|
|
293
|
+
z?: number;
|
|
294
|
+
}, clientId: string, owners: Map<string, string>, overrideRadius?: number): Set<string>;
|
|
295
|
+
/**
|
|
296
|
+
* Build a filter callback compatible with
|
|
297
|
+
* `HostAuthority.setInterestFilter`.
|
|
298
|
+
*
|
|
299
|
+
* The returned function closes over a single relevance pass for every
|
|
300
|
+
* known client so that per-entity filtering during broadcast is a cheap
|
|
301
|
+
* `Set.has` lookup.
|
|
302
|
+
*
|
|
303
|
+
* @param clientPositions peerId -> position of that client's camera/player
|
|
304
|
+
* @param owners entityId -> ownerPeerId
|
|
305
|
+
*/
|
|
306
|
+
createFilter(clientPositions: Map<string, {
|
|
307
|
+
x: number;
|
|
308
|
+
y: number;
|
|
309
|
+
z?: number;
|
|
310
|
+
}>, owners: Map<string, string>): (entityId: string, peerId: string) => boolean;
|
|
311
|
+
/** Remove all data from the grid. */
|
|
312
|
+
clear(): void;
|
|
313
|
+
private _cellKey;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export { CarverMultiplayerError, CarverTransport, ConnectionState, DebugOverlay, type DebugOverlayOptions, type DebugStats, EntityState, InterestManager, type InterestManagerOptions, MultiplayerBridge, MultiplayerProvider, type MultiplayerProviderProps, NetworkQuality, NetworkSimulator, type NetworkSimulatorOptions, Player, Room, RoomConfig, RoomState, SignalingStrategy, StrategyConfig, SyncMode, UseLobbyOptions, UseMultiplayerOptions, UseRoomOptions, useHost, useLobby, useMultiplayer, useNetworkEvents, useNetworkState, usePlayers, useRoom };
|