@smoregg/sdk 0.1.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/dist/cjs/components/DirectionPad.cjs +68 -0
- package/dist/cjs/components/DirectionPad.cjs.map +1 -0
- package/dist/cjs/components/DirectionPad.module.css.cjs +12 -0
- package/dist/cjs/components/DirectionPad.module.css.cjs.map +1 -0
- package/dist/cjs/components/HoldButton.cjs +57 -0
- package/dist/cjs/components/HoldButton.cjs.map +1 -0
- package/dist/cjs/components/HoldButton.module.css.cjs +12 -0
- package/dist/cjs/components/HoldButton.module.css.cjs.map +1 -0
- package/dist/cjs/components/SwipeArea.cjs +58 -0
- package/dist/cjs/components/SwipeArea.cjs.map +1 -0
- package/dist/cjs/components/SwipeArea.module.css.cjs +12 -0
- package/dist/cjs/components/SwipeArea.module.css.cjs.map +1 -0
- package/dist/cjs/components/TapButton.cjs +58 -0
- package/dist/cjs/components/TapButton.cjs.map +1 -0
- package/dist/cjs/components/TapButton.module.css.cjs +12 -0
- package/dist/cjs/components/TapButton.module.css.cjs.map +1 -0
- package/dist/cjs/context/RoomProvider.cjs +118 -0
- package/dist/cjs/context/RoomProvider.cjs.map +1 -0
- package/dist/cjs/hooks/useExternalGames.cjs +49 -0
- package/dist/cjs/hooks/useExternalGames.cjs.map +1 -0
- package/dist/cjs/hooks/useGameHost.cjs +135 -0
- package/dist/cjs/hooks/useGameHost.cjs.map +1 -0
- package/dist/cjs/hooks/useGamePlayer.cjs +75 -0
- package/dist/cjs/hooks/useGamePlayer.cjs.map +1 -0
- package/dist/cjs/iframe/index.cjs +508 -0
- package/dist/cjs/iframe/index.cjs.map +1 -0
- package/dist/cjs/index.cjs +32 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs +33 -0
- package/dist/cjs/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs.map +1 -0
- package/dist/cjs/server/index.cjs +45 -0
- package/dist/cjs/server/index.cjs.map +1 -0
- package/dist/cjs/transport/DirectTransport.cjs +23 -0
- package/dist/cjs/transport/DirectTransport.cjs.map +1 -0
- package/dist/cjs/transport/PostMessageTransport.cjs +72 -0
- package/dist/cjs/transport/PostMessageTransport.cjs.map +1 -0
- package/dist/cjs/transport/protocol.cjs +10 -0
- package/dist/cjs/transport/protocol.cjs.map +1 -0
- package/dist/esm/components/DirectionPad.js +66 -0
- package/dist/esm/components/DirectionPad.js.map +1 -0
- package/dist/esm/components/DirectionPad.module.css.js +8 -0
- package/dist/esm/components/DirectionPad.module.css.js.map +1 -0
- package/dist/esm/components/HoldButton.js +55 -0
- package/dist/esm/components/HoldButton.js.map +1 -0
- package/dist/esm/components/HoldButton.module.css.js +8 -0
- package/dist/esm/components/HoldButton.module.css.js.map +1 -0
- package/dist/esm/components/SwipeArea.js +56 -0
- package/dist/esm/components/SwipeArea.js.map +1 -0
- package/dist/esm/components/SwipeArea.module.css.js +8 -0
- package/dist/esm/components/SwipeArea.module.css.js.map +1 -0
- package/dist/esm/components/TapButton.js +56 -0
- package/dist/esm/components/TapButton.js.map +1 -0
- package/dist/esm/components/TapButton.module.css.js +8 -0
- package/dist/esm/components/TapButton.module.css.js.map +1 -0
- package/dist/esm/context/RoomProvider.js +109 -0
- package/dist/esm/context/RoomProvider.js.map +1 -0
- package/dist/esm/hooks/useExternalGames.js +47 -0
- package/dist/esm/hooks/useExternalGames.js.map +1 -0
- package/dist/esm/hooks/useGameHost.js +133 -0
- package/dist/esm/hooks/useGameHost.js.map +1 -0
- package/dist/esm/hooks/useGamePlayer.js +73 -0
- package/dist/esm/hooks/useGamePlayer.js.map +1 -0
- package/dist/esm/iframe/index.js +502 -0
- package/dist/esm/iframe/index.js.map +1 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js +29 -0
- package/dist/esm/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js.map +1 -0
- package/dist/esm/server/index.js +43 -0
- package/dist/esm/server/index.js.map +1 -0
- package/dist/esm/transport/DirectTransport.js +21 -0
- package/dist/esm/transport/DirectTransport.js.map +1 -0
- package/dist/esm/transport/PostMessageTransport.js +70 -0
- package/dist/esm/transport/PostMessageTransport.js.map +1 -0
- package/dist/esm/transport/protocol.js +7 -0
- package/dist/esm/transport/protocol.js.map +1 -0
- package/dist/types/components/DirectionPad.d.ts +21 -0
- package/dist/types/components/DirectionPad.d.ts.map +1 -0
- package/dist/types/components/HoldButton.d.ts +22 -0
- package/dist/types/components/HoldButton.d.ts.map +1 -0
- package/dist/types/components/IframeGameBridge.d.ts +40 -0
- package/dist/types/components/IframeGameBridge.d.ts.map +1 -0
- package/dist/types/components/SwipeArea.d.ts +19 -0
- package/dist/types/components/SwipeArea.d.ts.map +1 -0
- package/dist/types/components/TapButton.d.ts +19 -0
- package/dist/types/components/TapButton.d.ts.map +1 -0
- package/dist/types/components/index.d.ts +8 -0
- package/dist/types/components/index.d.ts.map +1 -0
- package/dist/types/context/RoomProvider.d.ts +69 -0
- package/dist/types/context/RoomProvider.d.ts.map +1 -0
- package/dist/types/context/index.d.ts +3 -0
- package/dist/types/context/index.d.ts.map +1 -0
- package/dist/types/dev/DevSimulator.d.ts +31 -0
- package/dist/types/dev/DevSimulator.d.ts.map +1 -0
- package/dist/types/dev/index.d.ts +2 -0
- package/dist/types/dev/index.d.ts.map +1 -0
- package/dist/types/hooks/index.d.ts +4 -0
- package/dist/types/hooks/index.d.ts.map +1 -0
- package/dist/types/hooks/useExternalGames.d.ts +32 -0
- package/dist/types/hooks/useExternalGames.d.ts.map +1 -0
- package/dist/types/hooks/useGameHost.d.ts +40 -0
- package/dist/types/hooks/useGameHost.d.ts.map +1 -0
- package/dist/types/hooks/useGamePlayer.d.ts +17 -0
- package/dist/types/hooks/useGamePlayer.d.ts.map +1 -0
- package/dist/types/iframe/IframeRoomProvider.d.ts +31 -0
- package/dist/types/iframe/IframeRoomProvider.d.ts.map +1 -0
- package/dist/types/iframe/index.d.ts +18 -0
- package/dist/types/iframe/index.d.ts.map +1 -0
- package/dist/types/iframe/vanilla.d.ts +40 -0
- package/dist/types/iframe/vanilla.d.ts.map +1 -0
- package/dist/types/index.d.ts +34 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/server/createGameRelay.d.ts +26 -0
- package/dist/types/server/createGameRelay.d.ts.map +1 -0
- package/dist/types/server/index.d.ts +3 -0
- package/dist/types/server/index.d.ts.map +1 -0
- package/dist/types/transport/DirectTransport.d.ts +14 -0
- package/dist/types/transport/DirectTransport.d.ts.map +1 -0
- package/dist/types/transport/PostMessageTransport.d.ts +20 -0
- package/dist/types/transport/PostMessageTransport.d.ts.map +1 -0
- package/dist/types/transport/index.d.ts +6 -0
- package/dist/types/transport/index.d.ts.map +1 -0
- package/dist/types/transport/protocol.d.ts +50 -0
- package/dist/types/transport/protocol.d.ts.map +1 -0
- package/dist/types/transport/types.d.ts +14 -0
- package/dist/types/transport/types.d.ts.map +1 -0
- package/dist/types/types.d.ts +33 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/umd/smore-sdk-iframe.umd.js +511 -0
- package/dist/umd/smore-sdk-iframe.umd.js.map +1 -0
- package/dist/umd/smore-sdk-iframe.umd.min.js +2 -0
- package/dist/umd/smore-sdk-iframe.umd.min.js.map +1 -0
- package/dist/umd/smore-sdk.umd.js +709 -0
- package/dist/umd/smore-sdk.umd.js.map +1 -0
- package/dist/umd/smore-sdk.umd.min.js +2 -0
- package/dist/umd/smore-sdk.umd.min.js.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var RoomProvider = require('../context/RoomProvider.cjs');
|
|
5
|
+
|
|
6
|
+
function useGameHost(config) {
|
|
7
|
+
const { gameId, onInput, onStateRequest, onPlayerLeave, onPlayerDisconnect, onPlayerReconnect, listeners } = config;
|
|
8
|
+
const hostRoom = RoomProvider.useHostRoom();
|
|
9
|
+
const transport = RoomProvider.useTransport();
|
|
10
|
+
const onInputRef = react.useRef(onInput);
|
|
11
|
+
const onStateRequestRef = react.useRef(onStateRequest);
|
|
12
|
+
const onPlayerLeaveRef = react.useRef(onPlayerLeave);
|
|
13
|
+
const onPlayerDisconnectRef = react.useRef(onPlayerDisconnect);
|
|
14
|
+
const onPlayerReconnectRef = react.useRef(onPlayerReconnect);
|
|
15
|
+
react.useEffect(() => {
|
|
16
|
+
onInputRef.current = onInput;
|
|
17
|
+
}, [onInput]);
|
|
18
|
+
react.useEffect(() => {
|
|
19
|
+
onStateRequestRef.current = onStateRequest;
|
|
20
|
+
}, [onStateRequest]);
|
|
21
|
+
react.useEffect(() => {
|
|
22
|
+
onPlayerLeaveRef.current = onPlayerLeave;
|
|
23
|
+
}, [onPlayerLeave]);
|
|
24
|
+
react.useEffect(() => {
|
|
25
|
+
onPlayerDisconnectRef.current = onPlayerDisconnect;
|
|
26
|
+
}, [onPlayerDisconnect]);
|
|
27
|
+
react.useEffect(() => {
|
|
28
|
+
onPlayerReconnectRef.current = onPlayerReconnect;
|
|
29
|
+
}, [onPlayerReconnect]);
|
|
30
|
+
react.useEffect(() => {
|
|
31
|
+
if (!transport || !onInputRef.current) return;
|
|
32
|
+
const registeredEvents = [];
|
|
33
|
+
const inputMap = onInputRef.current;
|
|
34
|
+
for (const key of Object.keys(inputMap)) {
|
|
35
|
+
const eventName = `${gameId}:${key}`;
|
|
36
|
+
const handler = (data) => {
|
|
37
|
+
const currentHandler = onInputRef.current?.[key];
|
|
38
|
+
if (currentHandler) {
|
|
39
|
+
currentHandler(data?.sessionId ?? data?.playerId, data);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
transport.on(eventName, handler);
|
|
43
|
+
registeredEvents.push({ event: eventName, handler });
|
|
44
|
+
}
|
|
45
|
+
return () => {
|
|
46
|
+
for (const { event, handler } of registeredEvents) {
|
|
47
|
+
transport.off(event, handler);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}, [gameId, transport]);
|
|
51
|
+
react.useEffect(() => {
|
|
52
|
+
if (!transport) return;
|
|
53
|
+
const handler = (data) => {
|
|
54
|
+
const stateFn = onStateRequestRef.current;
|
|
55
|
+
if (!stateFn) return;
|
|
56
|
+
const gameState = stateFn(data.requesterId);
|
|
57
|
+
transport.emit("game:state-response", {
|
|
58
|
+
targetSessionId: data.requesterId,
|
|
59
|
+
gameState: {
|
|
60
|
+
gameId,
|
|
61
|
+
...gameState
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
transport.on("game:state-request", handler);
|
|
66
|
+
return () => {
|
|
67
|
+
transport.off("game:state-request", handler);
|
|
68
|
+
};
|
|
69
|
+
}, [transport, gameId]);
|
|
70
|
+
react.useEffect(() => {
|
|
71
|
+
if (!transport) return;
|
|
72
|
+
const onLeft = (data) => {
|
|
73
|
+
onPlayerLeaveRef.current?.(data?.sessionId ?? data?.playerId);
|
|
74
|
+
};
|
|
75
|
+
const onDisconnected = (data) => {
|
|
76
|
+
onPlayerDisconnectRef.current?.(data?.sessionId ?? data?.playerId);
|
|
77
|
+
};
|
|
78
|
+
const onReconnected = (data) => {
|
|
79
|
+
onPlayerReconnectRef.current?.(data?.sessionId ?? data?.playerId);
|
|
80
|
+
};
|
|
81
|
+
transport.on("room:player-left", onLeft);
|
|
82
|
+
transport.on("room:player-disconnected", onDisconnected);
|
|
83
|
+
transport.on("room:player-reconnected", onReconnected);
|
|
84
|
+
return () => {
|
|
85
|
+
transport.off("room:player-left", onLeft);
|
|
86
|
+
transport.off("room:player-disconnected", onDisconnected);
|
|
87
|
+
transport.off("room:player-reconnected", onReconnected);
|
|
88
|
+
};
|
|
89
|
+
}, [transport]);
|
|
90
|
+
const listenersRef = react.useRef(listeners);
|
|
91
|
+
listenersRef.current = listeners;
|
|
92
|
+
react.useEffect(() => {
|
|
93
|
+
if (!transport || !listenersRef.current) return;
|
|
94
|
+
const entries = Object.entries(listenersRef.current);
|
|
95
|
+
const handlers = entries.map(([event, handler]) => {
|
|
96
|
+
transport.on(event, handler);
|
|
97
|
+
return () => {
|
|
98
|
+
transport.off(event, handler);
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
return () => handlers.forEach((fn) => fn());
|
|
102
|
+
}, [transport, listeners]);
|
|
103
|
+
const broadcast = react.useCallback(
|
|
104
|
+
(event, data) => {
|
|
105
|
+
transport?.emit(event, data);
|
|
106
|
+
},
|
|
107
|
+
[transport]
|
|
108
|
+
);
|
|
109
|
+
const sendToPlayer = react.useCallback(
|
|
110
|
+
(sessionId, event, data) => {
|
|
111
|
+
transport?.emit("game:state-to-player", {
|
|
112
|
+
targetSessionId: sessionId,
|
|
113
|
+
gameId,
|
|
114
|
+
event,
|
|
115
|
+
state: data
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
[transport, gameId]
|
|
119
|
+
);
|
|
120
|
+
const emitGameOver = react.useCallback(
|
|
121
|
+
(results) => {
|
|
122
|
+
transport?.emit("room:game-over", { gameId, results });
|
|
123
|
+
},
|
|
124
|
+
[transport, gameId]
|
|
125
|
+
);
|
|
126
|
+
return {
|
|
127
|
+
room: hostRoom,
|
|
128
|
+
broadcast,
|
|
129
|
+
sendToPlayer,
|
|
130
|
+
emitGameOver
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
exports.useGameHost = useGameHost;
|
|
135
|
+
//# sourceMappingURL=useGameHost.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useGameHost.cjs","sources":["../../../src/hooks/useGameHost.ts"],"sourcesContent":["/**\n * useGameHost - Host-side game hook for the S'MORE SDK\n *\n * Provides host game developers with:\n * - Automatic room state access (via useHostRoom context)\n * - Input listening (dedicated socket events)\n * - Broadcasting to all/specific players\n * - Game over emission\n * - Player lifecycle callbacks\n *\n * Internally uses Transport abstraction so the same API works over\n * Socket.IO (bundled games) or postMessage (iframe games).\n */\nimport { useEffect, useCallback, useRef } from 'react';\nimport { useHostRoom } from '../context/RoomProvider';\nimport { useTransport } from '../context/RoomProvider';\nimport type { HostRoomState } from '../context/RoomProvider';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype InputHandler = (playerId: string, data?: any) => void;\n\nexport interface UseGameHostConfig {\n /** Unique game identifier (e.g. 'fibbage', 'wasd') */\n gameId: string;\n\n /**\n * Map of action names to handler functions.\n * Listens directly on socket for `{gameId}:{key}` events.\n */\n onInput?: Record<string, InputHandler>;\n\n /**\n * Called when a player requests game state (e.g. after returning from background).\n * Return the current game state object to send back to that player.\n */\n onStateRequest?: (playerId: string) => Record<string, any>;\n\n /** Called when a player leaves the room. */\n onPlayerLeave?: (playerId: string) => void;\n\n /** Called when a player disconnects (may reconnect). */\n onPlayerDisconnect?: (playerId: string) => void;\n\n /** Called when a previously disconnected player reconnects. */\n onPlayerReconnect?: (playerId: string) => void;\n\n /**\n * Generic socket event listeners (for server broadcasts the host needs to receive).\n * Keys are full event names, values are handler functions.\n */\n listeners?: Record<string, (data: any) => void>;\n}\n\nexport interface UseGameHostReturn {\n /** Current room state from HostRoomProvider context. */\n room: HostRoomState;\n\n /** Broadcast an event to all players via the host socket. */\n broadcast: (event: string, data: any) => void;\n\n /** Send state/event to a specific player by sessionId. */\n sendToPlayer: (sessionId: string, event: string, data: any) => void;\n\n /** Emit game-over with optional results payload. */\n emitGameOver: (results?: any) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\nexport function useGameHost(config: UseGameHostConfig): UseGameHostReturn {\n const { gameId, onInput, onStateRequest, onPlayerLeave, onPlayerDisconnect, onPlayerReconnect, listeners } = config;\n\n const hostRoom = useHostRoom();\n const transport = useTransport();\n\n // Stable refs to avoid stale closures in listeners\n const onInputRef = useRef(onInput);\n const onStateRequestRef = useRef(onStateRequest);\n const onPlayerLeaveRef = useRef(onPlayerLeave);\n const onPlayerDisconnectRef = useRef(onPlayerDisconnect);\n const onPlayerReconnectRef = useRef(onPlayerReconnect);\n\n useEffect(() => { onInputRef.current = onInput; }, [onInput]);\n useEffect(() => { onStateRequestRef.current = onStateRequest; }, [onStateRequest]);\n useEffect(() => { onPlayerLeaveRef.current = onPlayerLeave; }, [onPlayerLeave]);\n useEffect(() => { onPlayerDisconnectRef.current = onPlayerDisconnect; }, [onPlayerDisconnect]);\n useEffect(() => { onPlayerReconnectRef.current = onPlayerReconnect; }, [onPlayerReconnect]);\n\n // -------------------------------------------------------------------------\n // Dedicated input listeners (transport events)\n // -------------------------------------------------------------------------\n useEffect(() => {\n if (!transport || !onInputRef.current) return;\n\n const registeredEvents: Array<{ event: string; handler: (...args: any[]) => void }> = [];\n\n // For each handler key, listen on transport for \"{gameId}:{key}\"\n const inputMap = onInputRef.current;\n for (const key of Object.keys(inputMap)) {\n const eventName = `${gameId}:${key}`;\n const handler = (data: any) => {\n const currentHandler = onInputRef.current?.[key];\n if (currentHandler) {\n currentHandler(data?.sessionId ?? data?.playerId, data);\n }\n };\n transport.on(eventName, handler);\n registeredEvents.push({ event: eventName, handler });\n }\n\n return () => {\n for (const { event, handler } of registeredEvents) {\n transport.off(event, handler);\n }\n };\n }, [gameId, transport]);\n\n // -------------------------------------------------------------------------\n // State request handler\n // -------------------------------------------------------------------------\n useEffect(() => {\n if (!transport) return;\n\n const handler = (data: { requesterId: string }) => {\n const stateFn = onStateRequestRef.current;\n if (!stateFn) return;\n\n const gameState = stateFn(data.requesterId);\n transport.emit('game:state-response', {\n targetSessionId: data.requesterId,\n gameState: {\n gameId,\n ...gameState,\n },\n });\n };\n\n transport.on('game:state-request', handler);\n return () => {\n transport.off('game:state-request', handler);\n };\n }, [transport, gameId]);\n\n // -------------------------------------------------------------------------\n // Player lifecycle listeners\n // -------------------------------------------------------------------------\n useEffect(() => {\n if (!transport) return;\n\n const onLeft = (data: any) => {\n onPlayerLeaveRef.current?.(data?.sessionId ?? data?.playerId);\n };\n const onDisconnected = (data: any) => {\n onPlayerDisconnectRef.current?.(data?.sessionId ?? data?.playerId);\n };\n const onReconnected = (data: any) => {\n onPlayerReconnectRef.current?.(data?.sessionId ?? data?.playerId);\n };\n\n transport.on('room:player-left', onLeft);\n transport.on('room:player-disconnected', onDisconnected);\n transport.on('room:player-reconnected', onReconnected);\n\n return () => {\n transport.off('room:player-left', onLeft);\n transport.off('room:player-disconnected', onDisconnected);\n transport.off('room:player-reconnected', onReconnected);\n };\n }, [transport]);\n\n // -------------------------------------------------------------------------\n // Generic listeners\n // -------------------------------------------------------------------------\n const listenersRef = useRef(listeners);\n listenersRef.current = listeners;\n\n useEffect(() => {\n if (!transport || !listenersRef.current) return;\n const entries = Object.entries(listenersRef.current);\n const handlers = entries.map(([event, handler]) => {\n transport.on(event, handler);\n return () => { transport.off(event, handler); };\n });\n return () => handlers.forEach(fn => fn());\n }, [transport, listeners]);\n\n // -------------------------------------------------------------------------\n // Actions\n // -------------------------------------------------------------------------\n\n const broadcast = useCallback(\n (event: string, data: any) => {\n transport?.emit(event, data);\n },\n [transport],\n );\n\n const sendToPlayer = useCallback(\n (sessionId: string, event: string, data: any) => {\n transport?.emit('game:state-to-player', {\n targetSessionId: sessionId,\n gameId,\n event,\n state: data,\n });\n },\n [transport, gameId],\n );\n\n const emitGameOver = useCallback(\n (results?: any) => {\n transport?.emit('room:game-over', { gameId, results });\n },\n [transport, gameId],\n );\n\n return {\n room: hostRoom,\n broadcast,\n sendToPlayer,\n emitGameOver,\n };\n}\n"],"names":["useHostRoom","useTransport","useRef","useEffect","useCallback"],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var RoomProvider = require('../context/RoomProvider.cjs');
|
|
5
|
+
|
|
6
|
+
function useGamePlayer(config) {
|
|
7
|
+
const room = RoomProvider.usePlayerRoom();
|
|
8
|
+
const transport = RoomProvider.useTransport();
|
|
9
|
+
const { isConnected } = room;
|
|
10
|
+
const { gameId, listeners } = config;
|
|
11
|
+
const [gameState, setGameState] = react.useState(null);
|
|
12
|
+
const listenersRef = react.useRef(listeners);
|
|
13
|
+
listenersRef.current = listeners;
|
|
14
|
+
react.useEffect(() => {
|
|
15
|
+
if (!transport || !listenersRef.current) return;
|
|
16
|
+
const cleanups = [];
|
|
17
|
+
Object.entries(listenersRef.current).forEach(([event, handler]) => {
|
|
18
|
+
transport.on(event, handler);
|
|
19
|
+
cleanups.push(() => transport.off(event, handler));
|
|
20
|
+
});
|
|
21
|
+
return () => cleanups.forEach((fn) => fn());
|
|
22
|
+
}, [transport, listeners]);
|
|
23
|
+
react.useEffect(() => {
|
|
24
|
+
if (!transport) return;
|
|
25
|
+
const handler = (state) => {
|
|
26
|
+
if (state.gameId !== gameId) return;
|
|
27
|
+
setGameState(state);
|
|
28
|
+
};
|
|
29
|
+
transport.on("game:state-response", handler);
|
|
30
|
+
return () => {
|
|
31
|
+
transport.off("game:state-response", handler);
|
|
32
|
+
};
|
|
33
|
+
}, [transport, gameId]);
|
|
34
|
+
react.useEffect(() => {
|
|
35
|
+
if (!transport) return;
|
|
36
|
+
const handler = (data) => {
|
|
37
|
+
if (data.gameId !== gameId) return;
|
|
38
|
+
setGameState(data.state);
|
|
39
|
+
};
|
|
40
|
+
transport.on("game:state-to-player", handler);
|
|
41
|
+
return () => {
|
|
42
|
+
transport.off("game:state-to-player", handler);
|
|
43
|
+
};
|
|
44
|
+
}, [transport, gameId]);
|
|
45
|
+
react.useEffect(() => {
|
|
46
|
+
if (!transport) return;
|
|
47
|
+
const handler = () => {
|
|
48
|
+
if (!document.hidden) {
|
|
49
|
+
transport.emit("game:request-state", { gameId });
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
document.addEventListener("visibilitychange", handler);
|
|
53
|
+
return () => document.removeEventListener("visibilitychange", handler);
|
|
54
|
+
}, [transport, gameId]);
|
|
55
|
+
const emit = react.useCallback((event, data, callback) => {
|
|
56
|
+
if (!transport) return;
|
|
57
|
+
if (callback) {
|
|
58
|
+
transport.emit(event, data, callback);
|
|
59
|
+
} else {
|
|
60
|
+
transport.emit(event, data);
|
|
61
|
+
}
|
|
62
|
+
}, [transport]);
|
|
63
|
+
const sendTapInput = react.useCallback((action) => {
|
|
64
|
+
if (!transport) return;
|
|
65
|
+
transport.emit(`${gameId}:${action}`);
|
|
66
|
+
}, [transport, gameId]);
|
|
67
|
+
const sendHoldInput = react.useCallback((action, type) => {
|
|
68
|
+
if (!transport) return;
|
|
69
|
+
transport.emit(`${gameId}:${action}:${type}`);
|
|
70
|
+
}, [transport, gameId]);
|
|
71
|
+
return { room, emit, sendTapInput, sendHoldInput, isConnected, gameState };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
exports.useGamePlayer = useGamePlayer;
|
|
75
|
+
//# sourceMappingURL=useGamePlayer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useGamePlayer.cjs","sources":["../../../src/hooks/useGamePlayer.ts"],"sourcesContent":["import { useEffect, useCallback, useState, useRef } from 'react';\nimport { usePlayerRoom } from '../context/RoomProvider';\nimport { useTransport } from '../context/RoomProvider';\nimport type { PlayerRoomState } from '../context/RoomProvider';\n\nexport interface UseGamePlayerConfig {\n gameId: string;\n listeners?: Record<string, (data: any) => void>;\n}\n\nexport interface UseGamePlayerReturn {\n room: PlayerRoomState;\n emit: (event: string, data?: any, callback?: (response: any) => void) => void;\n /** Emit a tap input: sends `{gameId}:{action}` event */\n sendTapInput: (action: string) => void;\n /** Emit a hold input: sends `{gameId}:{action}:{type}` event */\n sendHoldInput: (action: string, type: 'START' | 'END') => void;\n isConnected: boolean;\n gameState: Record<string, any> | null;\n}\n\nexport function useGamePlayer(config: UseGamePlayerConfig): UseGamePlayerReturn {\n const room = usePlayerRoom();\n const transport = useTransport();\n const { isConnected } = room;\n const { gameId, listeners } = config;\n const [gameState, setGameState] = useState<Record<string, any> | null>(null);\n const listenersRef = useRef(listeners);\n listenersRef.current = listeners;\n\n // Transport listeners\n useEffect(() => {\n if (!transport || !listenersRef.current) return;\n const cleanups: (() => void)[] = [];\n Object.entries(listenersRef.current).forEach(([event, handler]) => {\n transport.on(event, handler);\n cleanups.push(() => transport.off(event, handler));\n });\n return () => cleanups.forEach(fn => fn());\n }, [transport, listeners]);\n\n // Reconnection: game:state-response\n useEffect(() => {\n if (!transport) return;\n const handler = (state: any) => {\n if (state.gameId !== gameId) return;\n setGameState(state);\n };\n transport.on('game:state-response', handler);\n return () => { transport.off('game:state-response', handler); };\n }, [transport, gameId]);\n\n // game:state-to-player (Host push)\n useEffect(() => {\n if (!transport) return;\n const handler = (data: { gameId: string; state: any }) => {\n if (data.gameId !== gameId) return;\n setGameState(data.state);\n };\n transport.on('game:state-to-player', handler);\n return () => { transport.off('game:state-to-player', handler); };\n }, [transport, gameId]);\n\n // Visibility change\n useEffect(() => {\n if (!transport) return;\n const handler = () => {\n if (!document.hidden) {\n transport.emit('game:request-state', { gameId });\n }\n };\n document.addEventListener('visibilitychange', handler);\n return () => document.removeEventListener('visibilitychange', handler);\n }, [transport, gameId]);\n\n // API\n const emit = useCallback((event: string, data?: any, callback?: (response: any) => void) => {\n if (!transport) return;\n if (callback) {\n transport.emit(event, data, callback);\n } else {\n transport.emit(event, data);\n }\n }, [transport]);\n\n const sendTapInput = useCallback((action: string) => {\n if (!transport) return;\n transport.emit(`${gameId}:${action}`);\n }, [transport, gameId]);\n\n const sendHoldInput = useCallback((action: string, type: 'START' | 'END') => {\n if (!transport) return;\n transport.emit(`${gameId}:${action}:${type}`);\n }, [transport, gameId]);\n\n return { room, emit, sendTapInput, sendHoldInput, isConnected, gameState };\n}\n"],"names":["usePlayerRoom","useTransport","useState","useRef","useEffect","useCallback"],"mappings":"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"}
|