@remix-gg/sdk 0.4.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 +423 -0
- package/dist/index.d.ts +192 -0
- package/dist/index.js +220 -0
- package/dist/index.js.map +10 -0
- package/dist/index.min.js +220 -0
- package/dist/index.min.js.map +10 -0
- package/dist/index.mjs +188 -0
- package/dist/index.mjs.map +10 -0
- package/package.json +24 -0
package/README.md
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
# Remix SDK
|
|
2
|
+
|
|
3
|
+
The Remix SDK enables game developers to integrate their HTML5 games with the Remix platform through a simple messaging interface.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install the SDK using your preferred package manager:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @remix-gg/sdk
|
|
11
|
+
# or
|
|
12
|
+
bun install @remix-gg/sdk
|
|
13
|
+
# or
|
|
14
|
+
yarn add @remix-gg/sdk
|
|
15
|
+
# or
|
|
16
|
+
pnpm add @remix-gg/sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
When you upload game code to Remix, a script tag to reference the SDK will automatically be added to your game code. The SDK will be accessible from `window.RemixSDK`.
|
|
20
|
+
|
|
21
|
+
## Example Implementation
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { sdk } from '@remix-gg/sdk'
|
|
25
|
+
import type { GameState, Player } from '@remix-gg/sdk'
|
|
26
|
+
|
|
27
|
+
class MyGame {
|
|
28
|
+
sdk = sdk
|
|
29
|
+
player: Player
|
|
30
|
+
gameState: GameState | null = null
|
|
31
|
+
isMuted: boolean = true
|
|
32
|
+
|
|
33
|
+
// some example values that correlate to items purchased by boosting
|
|
34
|
+
canSaveGame: boolean = false
|
|
35
|
+
hasSuperSkin: boolean = false
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
// attach the sdk to the Game class to we can reference it easily
|
|
39
|
+
this.sdk = window.RemixSDK
|
|
40
|
+
|
|
41
|
+
// Setup event listeners
|
|
42
|
+
this.setupEventListeners()
|
|
43
|
+
|
|
44
|
+
// Initialize your game
|
|
45
|
+
this.initialize()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private async setupEventListeners() {
|
|
49
|
+
// Listen for play again events
|
|
50
|
+
this.sdk.onPlayAgain(() => {
|
|
51
|
+
this.resetGame()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// Listen for mute state changes
|
|
55
|
+
this.sdk.onToggleMute((data) => {
|
|
56
|
+
this.isMuted = data.isMuted
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// Listen for purchase completions (optional)
|
|
60
|
+
this.sdk.onPurchaseComplete(() => {
|
|
61
|
+
this.checkPurchasedItems()
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private async initialize() {
|
|
66
|
+
// wait for the sdk to get game information from Remix
|
|
67
|
+
await this.sdk.ready()
|
|
68
|
+
|
|
69
|
+
// get information the game uses from the SDK
|
|
70
|
+
this.player = this.sdk.player
|
|
71
|
+
this.gameState = this.sdk.gameState
|
|
72
|
+
|
|
73
|
+
// check which items the user has already purchased
|
|
74
|
+
this.checkPurchasedItems()
|
|
75
|
+
|
|
76
|
+
//... start the game logic
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private checkPurchasedItems() {
|
|
80
|
+
// check the identifier for each item to see if the user has purchased it
|
|
81
|
+
|
|
82
|
+
if (this.sdk.hasItem('save-game')) {
|
|
83
|
+
this.canSaveGame = true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (this.sdk.hasItem('super-skin')) {
|
|
87
|
+
this.hasSuperSkin = true
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private async purchaseItem(itemId: string) {
|
|
92
|
+
// trigger the boost UI and then check for new items after
|
|
93
|
+
await this.sdk.purchase({ item: itemId })
|
|
94
|
+
this.checkPurchasedItems()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private gameOver(finalScore: number) {
|
|
98
|
+
//
|
|
99
|
+
this.sdk.singlePlayer.actions.gameOver({ score: finalScore })
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private saveGame() {
|
|
103
|
+
// return unless the user has purchased the 'save-game' item
|
|
104
|
+
// see checkPurchasedItems
|
|
105
|
+
if (!this.canSaveGame) return
|
|
106
|
+
|
|
107
|
+
// push game state updates to save progress for the user
|
|
108
|
+
const gameState: GameState = this.getCurrentGameState();
|
|
109
|
+
this.sdk.singlePlayer.actions.saveGameState({ gameState })
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private triggerHapticFeedback() {
|
|
113
|
+
this.sdk.hapticFeedback()
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
## API Reference
|
|
120
|
+
|
|
121
|
+
### Properties and Getters
|
|
122
|
+
|
|
123
|
+
#### `sdk.ready(): Promise<GameInfo>`
|
|
124
|
+
|
|
125
|
+
This function will return when the SDK has recieved all the game information from Remix. You should await the call to this function before getting info from the SDK (sdk.player, sdk.gameState, etc)
|
|
126
|
+
|
|
127
|
+
#### `sdk.isReady: boolean`
|
|
128
|
+
|
|
129
|
+
Check if the SDK has received game info and is ready. More often, you will just await the call to `sdk.ready()`, but you may use this value if you prefer.
|
|
130
|
+
|
|
131
|
+
#### `sdk.player: Player | undefined`
|
|
132
|
+
|
|
133
|
+
Get the current player object.
|
|
134
|
+
|
|
135
|
+
#### `sdk.players: Player[] | undefined`
|
|
136
|
+
|
|
137
|
+
Get the list of all players in the game. This is useful for multiplayer games. In multiplayer games, it is essential that you use the `players` array so you can report scores with the associated player ids and notify players it is there turn.
|
|
138
|
+
|
|
139
|
+
#### `sdk.gameState: GameState | null | undefined`
|
|
140
|
+
|
|
141
|
+
Get the current game state. This will be `null` when there is no existing GameState for this game and user.
|
|
142
|
+
|
|
143
|
+
#### `sdk.purchasedItems: string[]`
|
|
144
|
+
|
|
145
|
+
Get the list of item IDs that the current player has purchased. This is a read-only property that reflects the `purchasedItems` array from the current player's `GameInfo`.
|
|
146
|
+
|
|
147
|
+
#### `sdk.storeItems: StoreItem[]`
|
|
148
|
+
|
|
149
|
+
Get the list of purchasable store items available for the current game session.
|
|
150
|
+
|
|
151
|
+
#### `sdk.hasItem(item: string): boolean`
|
|
152
|
+
|
|
153
|
+
Check if the current player has purchased a specific item.
|
|
154
|
+
|
|
155
|
+
Parameters:
|
|
156
|
+
- `item`: The item identifier to check (string)
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
- `true` if the player has purchased the item, `false` otherwise
|
|
160
|
+
|
|
161
|
+
#### `sdk.getStoreItem(slug: string): StoreItem | undefined`
|
|
162
|
+
|
|
163
|
+
Get a specific store item by slug.
|
|
164
|
+
|
|
165
|
+
Parameters:
|
|
166
|
+
- `slug`: The store item slug to look up (string)
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
- The matching `StoreItem` object when found, otherwise `undefined`
|
|
170
|
+
|
|
171
|
+
#### `sdk.gameInfo: GameInfo | undefined`
|
|
172
|
+
|
|
173
|
+
Get the current `GameInfo` object. This is all the data passed into the game from Remix. It is recommended that you use the other functions to access the specific data you need instead of pulling data out of this large object.
|
|
174
|
+
|
|
175
|
+
#### `sdk.hapticFeedback()`
|
|
176
|
+
|
|
177
|
+
Call this method to trigger haptic feedback on supported devices. Use this for important game events like collisions, achievements, or other significant player interactions.
|
|
178
|
+
|
|
179
|
+
#### Best Practices for Haptic Feedback
|
|
180
|
+
|
|
181
|
+
- Use haptic feedback sparingly to avoid overwhelming the player
|
|
182
|
+
- Reserve haptic feedback for meaningful interactions and achievements
|
|
183
|
+
- Consider using it for:
|
|
184
|
+
- Collisions with obstacles
|
|
185
|
+
- Collecting power-ups
|
|
186
|
+
- Completing levels
|
|
187
|
+
- Achieving high scores
|
|
188
|
+
- Important game events
|
|
189
|
+
|
|
190
|
+
#### `sdk.purchase({ item: string }) => Promise<{ success: boolean }>`
|
|
191
|
+
|
|
192
|
+
Call this function to initiate a purchase for an in-game item. This method sends a purchase request to the Remix platform and returns a promise that resolves with the purchase result. Make sure the `item` identifier matches an item you have added to your game using the [Remix](https://remix.gg) web app.
|
|
193
|
+
|
|
194
|
+
Parameters:
|
|
195
|
+
- `item`: The identifier of the item to purchase (string)
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
- A promise that resolves with `{ success: boolean }` indicating whether the purchase was successful
|
|
199
|
+
|
|
200
|
+
The purchase flow works as follows:
|
|
201
|
+
1. Call `purchase({ item: 'item-id' })` to initiate the purchase
|
|
202
|
+
2. The platform handles the purchase transaction (payment processing, etc.)
|
|
203
|
+
3. The promise resolves with `{ success: true }` if the purchase succeeds, or `{ success: false }` if it fails
|
|
204
|
+
4. You can also listen for `purchase_complete` events using `sdk.onPurchaseComplete()` for additional handling
|
|
205
|
+
|
|
206
|
+
**Important**: The `purchasedItems` array in `GameInfo` will be automatically updated after a successful purchase, and you can check item ownership using `sdk.hasItem(item)` or `sdk.purchasedItems`.
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
### Single Player Actions
|
|
210
|
+
|
|
211
|
+
#### `sdk.singlePlayer.actions.gameOver({ score: number })`
|
|
212
|
+
|
|
213
|
+
Call this method when the game is over to report the final score.
|
|
214
|
+
|
|
215
|
+
Parameters:
|
|
216
|
+
|
|
217
|
+
- `score`: The player's final score (number)
|
|
218
|
+
|
|
219
|
+
#### `sdk.singlePlayer.actions.saveGameState({ gameState: Record<string, unknown> })`
|
|
220
|
+
|
|
221
|
+
Call this method when you wish to persist game state for the user. This will enable users to save their progress in a
|
|
222
|
+
game between play sessions.
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
### Multi-Player Actions
|
|
226
|
+
|
|
227
|
+
Muliplayer has the same actions as singlePlayer with 2 updates and 1 addition. It is important to note that YOU
|
|
228
|
+
MUST use the `gameInfo` data from the response to `ready()` in order to accurately report scores with player ids when the game ends.
|
|
229
|
+
|
|
230
|
+
#### `sdk.multiplayer.actions.gameOver({ scores: { playerId: string; score: number }[] })`
|
|
231
|
+
|
|
232
|
+
Call this method with the game is over to report the final scores.
|
|
233
|
+
|
|
234
|
+
Parameters:
|
|
235
|
+
|
|
236
|
+
- `scores`: The playerId and score for each player in the game.
|
|
237
|
+
|
|
238
|
+
#### `sdk.multiplayer.actions.saveGameState({ gameState: Record<string, unknown>; alertUserIds: string[] })`
|
|
239
|
+
|
|
240
|
+
Call this method when a player action should update the shared game state for all players. If your game has a concept of turns as most do, you must include the `alertUserIds` list with the id(s) of the player(s) that should be alerted it is their turn.
|
|
241
|
+
|
|
242
|
+
Parameters:
|
|
243
|
+
|
|
244
|
+
- `gameState`: A Record object containing your game state. The shape of the game state is open to the game creator's discretion.
|
|
245
|
+
- `alertUserIds`: A list of player ids to alert on this game state update. Typically this will be a list of length 1 containing the id of the player who is next to act, but different games may need to alert multiple players.
|
|
246
|
+
|
|
247
|
+
#### `sdk.multiplayer.actions.refuteGameState({ gameStateId: string })`
|
|
248
|
+
|
|
249
|
+
Call this method when your game client has determined an incoming game state is invalid. It is not strictly required that your game validates game state updates, but it should. Putting game state validation logic in your game client means that bad actors attempting to push unfair updates are invalidated by good actors running valid implementations of your game.
|
|
250
|
+
|
|
251
|
+
Parameters:
|
|
252
|
+
|
|
253
|
+
- `gameStateId`: The id from the `game_state_updated` event that the game client is refutting.
|
|
254
|
+
|
|
255
|
+
#### `sdk.multiplayer.actions.purchase({ item: string }) => Promise<{ success: boolean }>`
|
|
256
|
+
|
|
257
|
+
Same as the single player `purchase` method. Call this method to initiate a purchase for an in-game item in multiplayer games. See the single player purchase documentation above for details.
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
Here is an example function that handles update and refute game state for a Chess game:
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
handleGameStateUpdate({ gameState }) {
|
|
264
|
+
if (!gameState) return;
|
|
265
|
+
|
|
266
|
+
const { id, gameState: { moves } } = gameState;
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
this.chess.reset();
|
|
270
|
+
if (moves?.length > 0) {
|
|
271
|
+
for (const move of moves) {
|
|
272
|
+
this.chess.move(move);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
this.renderBoard();
|
|
276
|
+
this.updateStatus();
|
|
277
|
+
this.updateMoveHistory();
|
|
278
|
+
this.updateCapturedPieces();
|
|
279
|
+
} catch (error) {
|
|
280
|
+
// game state is invalid, refuting this game state update
|
|
281
|
+
this.sdk.multiplayer.actions.refuteGameState({ gameStateId: id });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Events
|
|
287
|
+
|
|
288
|
+
The SDK provides both generic event listeners and specific typed listener methods. We recommend using the specific listener methods for better type safety and clarity.
|
|
289
|
+
|
|
290
|
+
#### Event Listeners
|
|
291
|
+
|
|
292
|
+
##### `sdk.onPlayAgain(callback: () => void)`
|
|
293
|
+
|
|
294
|
+
Register a callback function that is called when the player wants to play again.
|
|
295
|
+
|
|
296
|
+
##### `sdk.onToggleMute(callback: (data: { isMuted: boolean }) => void)`
|
|
297
|
+
|
|
298
|
+
Register a callback function that is called when receiving mute state changes.
|
|
299
|
+
|
|
300
|
+
Parameters:
|
|
301
|
+
- `callback`: Function that receives `{ isMuted: boolean }` indicating the current mute state
|
|
302
|
+
|
|
303
|
+
##### `sdk.onGameStateUpdated(callback: (data: { id: string, gameState: Record<string, unknown> } | null) => void)`
|
|
304
|
+
|
|
305
|
+
Register a callback function that is called when there is an update to the game state. This is essential for multiplayer games to receive state updates from other players.
|
|
306
|
+
|
|
307
|
+
Parameters:
|
|
308
|
+
- `callback`: Function that receives the game state update data, or `null` if the game state is cleared
|
|
309
|
+
|
|
310
|
+
##### `sdk.onGameInfo(callback: (data: GameInfo) => void)`
|
|
311
|
+
|
|
312
|
+
Register a callback function that is called when game information is received. This is typically called automatically when the game initializes, but you can listen for updates.
|
|
313
|
+
|
|
314
|
+
Parameters:
|
|
315
|
+
- `callback`: Function that receives the `GameInfo` object
|
|
316
|
+
|
|
317
|
+
##### `sdk.onPurchaseComplete(callback: (data: { success: boolean }) => void)`
|
|
318
|
+
|
|
319
|
+
Register a callback function that is called when a purchase completes. This can be used for additional handling beyond the promise returned by `purchase()`. It returns the same value as awaiting the call to `purchase()`, but sometimes users may boost your game without your game triggering the `purchase` function.
|
|
320
|
+
|
|
321
|
+
Parameters:
|
|
322
|
+
- `callback`: Function that receives `{ success: boolean }` indicating whether the purchase succeeded
|
|
323
|
+
|
|
324
|
+
## TypeScript Support
|
|
325
|
+
|
|
326
|
+
The SDK is written in TypeScript and includes full type definitions.
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
## Example Multiplayer Implementation
|
|
330
|
+
|
|
331
|
+
Multiplayer game development is not yet available to all users, but the SDK supports it. Watch the Remix Discord for announcements about
|
|
332
|
+
multiplayer game support.
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
import { sdk } from '@remix-gg/sdk'
|
|
336
|
+
import type { GameState, Player } from '@remix-gg/sdk'
|
|
337
|
+
|
|
338
|
+
class Game {
|
|
339
|
+
sdk = sdk
|
|
340
|
+
gameState: GameState
|
|
341
|
+
player: Player
|
|
342
|
+
players: Player[]
|
|
343
|
+
|
|
344
|
+
constructor() {
|
|
345
|
+
this.sdk = window.RemixSDK
|
|
346
|
+
|
|
347
|
+
// Initialize your game
|
|
348
|
+
this.initialize()
|
|
349
|
+
|
|
350
|
+
// Setup event listeners
|
|
351
|
+
this.setupEventListeners()
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
private setupEventListeners() {
|
|
355
|
+
// Listen for play again events
|
|
356
|
+
this.sdk.onPlayAgain(() => {
|
|
357
|
+
this.resetGame()
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
// Listen for mute state changes
|
|
361
|
+
this.sdk.onToggleMute((data) => {
|
|
362
|
+
this.setMuted(data.isMuted)
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
// Listen for game state updates (essential for multiplayer)
|
|
366
|
+
this.sdk.onGameStateUpdated((data) => {
|
|
367
|
+
const { id, gameState } = data
|
|
368
|
+
const newGameStateIsValid = this.validateGameState(gameState);
|
|
369
|
+
|
|
370
|
+
if (newGameStateIsValid) {
|
|
371
|
+
this.gameState = gameState
|
|
372
|
+
} else {
|
|
373
|
+
sdk.multiplayer.actions.refuteGameState({ gameStateId: id });
|
|
374
|
+
}
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
// Listen for purchase completions (optional)
|
|
378
|
+
sdk.onPurchaseComplete((data) => {
|
|
379
|
+
if (data.success) {
|
|
380
|
+
this.handlePurchaseSuccess()
|
|
381
|
+
}
|
|
382
|
+
})
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private async initialize() {
|
|
386
|
+
await this.sdk.ready()
|
|
387
|
+
|
|
388
|
+
this.gameState = this.sdk.gameState
|
|
389
|
+
this.player = this.sdk.player
|
|
390
|
+
this.players = this.sdk.players
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private saveGameState(gameState: Record<string, unknown>, nextTurnPlayerId: string) {
|
|
394
|
+
sdk.multiplayer.actions.saveGameState({
|
|
395
|
+
gameState,
|
|
396
|
+
alertUserIds: [nextTurnPlayerId],
|
|
397
|
+
})
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private gameOver(scores: { playerId: string, score: number }[]) {
|
|
401
|
+
sdk.multiplayer.actions.gameOver({ scores })
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
private async purchaseItem(itemId: string) {
|
|
405
|
+
try {
|
|
406
|
+
const result = await sdk.multiplayer.actions.purchase({ item: itemId })
|
|
407
|
+
if (result.success) {
|
|
408
|
+
console.log(`Successfully purchased ${itemId}`)
|
|
409
|
+
// Item is now available via sdk.hasItem(itemId) or sdk.purchasedItems
|
|
410
|
+
// The purchasedItems array is automatically updated for all players
|
|
411
|
+
} else {
|
|
412
|
+
console.log(`Purchase failed for ${itemId}`)
|
|
413
|
+
}
|
|
414
|
+
} catch (error) {
|
|
415
|
+
console.error('Purchase error:', error)
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## License
|
|
422
|
+
|
|
423
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
FarcadeSDK: typeof sdk;
|
|
4
|
+
RemixSDK: typeof sdk;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
type ViewContext = 'feed' | 'full_screen' | 'challenge' | 'tournament';
|
|
8
|
+
type GameState = Record<string, unknown>;
|
|
9
|
+
type Player = {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
purchasedItems: string[];
|
|
13
|
+
imageUrl?: string;
|
|
14
|
+
};
|
|
15
|
+
type StoreItem = {
|
|
16
|
+
slug: string;
|
|
17
|
+
name: string;
|
|
18
|
+
itemType?: string;
|
|
19
|
+
bitsCost?: number | null;
|
|
20
|
+
description?: string | null;
|
|
21
|
+
iconUrl?: string | null;
|
|
22
|
+
tier?: number | null;
|
|
23
|
+
};
|
|
24
|
+
type GameInfo = {
|
|
25
|
+
players: Player[];
|
|
26
|
+
player: Player;
|
|
27
|
+
storeItems?: StoreItem[];
|
|
28
|
+
viewContext: ViewContext;
|
|
29
|
+
initialGameState: {
|
|
30
|
+
id: string;
|
|
31
|
+
gameState: GameState;
|
|
32
|
+
} | null;
|
|
33
|
+
};
|
|
34
|
+
type ReadyEvent = {
|
|
35
|
+
type: 'ready';
|
|
36
|
+
data: undefined;
|
|
37
|
+
};
|
|
38
|
+
type PlayAgainEvent = {
|
|
39
|
+
type: 'play_again';
|
|
40
|
+
data: undefined;
|
|
41
|
+
};
|
|
42
|
+
type SinglePlayerGameOverEvent = {
|
|
43
|
+
type: 'game_over';
|
|
44
|
+
data: {
|
|
45
|
+
score: number;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
type MultiplayerGameOverEvent = {
|
|
49
|
+
type: 'multiplayer_game_over';
|
|
50
|
+
data: {
|
|
51
|
+
scores: {
|
|
52
|
+
playerId: string;
|
|
53
|
+
score: number;
|
|
54
|
+
}[];
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
type HapticFeedbackEvent = {
|
|
58
|
+
type: 'haptic_feedback';
|
|
59
|
+
data: undefined;
|
|
60
|
+
};
|
|
61
|
+
type ToggleMuteEvent = {
|
|
62
|
+
type: 'toggle_mute';
|
|
63
|
+
data: {
|
|
64
|
+
isMuted: boolean;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
type GameErrorEvent = {
|
|
68
|
+
type: 'error';
|
|
69
|
+
data: {
|
|
70
|
+
message: string;
|
|
71
|
+
source?: string;
|
|
72
|
+
lineno?: number;
|
|
73
|
+
colno?: number;
|
|
74
|
+
error?: Error;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
type GameInfoEvent = {
|
|
78
|
+
type: 'game_info';
|
|
79
|
+
data: GameInfo;
|
|
80
|
+
};
|
|
81
|
+
type MultiplayerSaveGameStateEvent = {
|
|
82
|
+
type: 'multiplayer_save_game_state';
|
|
83
|
+
data: {
|
|
84
|
+
gameState: GameState;
|
|
85
|
+
alertUserIds?: string[];
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
type GameStateUpdatedEvent = {
|
|
89
|
+
type: 'game_state_updated';
|
|
90
|
+
data: {
|
|
91
|
+
id: string;
|
|
92
|
+
gameState: GameState;
|
|
93
|
+
} | null;
|
|
94
|
+
};
|
|
95
|
+
type RefuteGameStateEvent = {
|
|
96
|
+
type: 'refute_game_state';
|
|
97
|
+
data: {
|
|
98
|
+
gameStateId: string;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
type SaveGameStateEvent = {
|
|
102
|
+
type: 'save_game_state';
|
|
103
|
+
data: {
|
|
104
|
+
gameState: GameState;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
type PurchaseEvent = {
|
|
108
|
+
type: 'purchase';
|
|
109
|
+
data: {
|
|
110
|
+
item: string;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
type PurchaseCompleteEvent = {
|
|
114
|
+
type: 'purchase_complete';
|
|
115
|
+
data: {
|
|
116
|
+
success: boolean;
|
|
117
|
+
item?: string;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
type GameEvent = PlayAgainEvent | SinglePlayerGameOverEvent | ReadyEvent | HapticFeedbackEvent | ToggleMuteEvent | GameErrorEvent | SaveGameStateEvent | RefuteGameStateEvent | GameInfoEvent | GameStateUpdatedEvent | MultiplayerGameOverEvent | MultiplayerSaveGameStateEvent | PurchaseEvent | PurchaseCompleteEvent;
|
|
121
|
+
type GameEventMessage<T extends GameEvent['type']> = {
|
|
122
|
+
type: 'game_event';
|
|
123
|
+
event: Extract<GameEvent, {
|
|
124
|
+
type: T;
|
|
125
|
+
}>;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Messages from the game host to the game client
|
|
129
|
+
*/
|
|
130
|
+
type IncomingGameEvent = GameEventMessage<'play_again' | 'toggle_mute' | 'game_info' | 'game_state_updated' | 'purchase_complete'>;
|
|
131
|
+
type OutgoingGameEvent = GameEventMessage<'game_over' | 'ready' | 'haptic_feedback' | 'error' | 'save_game_state' | 'refute_game_state' | 'multiplayer_game_over' | 'multiplayer_save_game_state' | 'purchase'>;
|
|
132
|
+
type EventCallback = (data: unknown) => void;
|
|
133
|
+
declare class FarcadeSDK {
|
|
134
|
+
private isClient;
|
|
135
|
+
private target;
|
|
136
|
+
private eventListeners;
|
|
137
|
+
private readyPromiseResolve;
|
|
138
|
+
private purchasePromiseResolve;
|
|
139
|
+
private _gameInfo?;
|
|
140
|
+
private _gameState?;
|
|
141
|
+
constructor();
|
|
142
|
+
on(eventType: IncomingGameEvent['event']['type'], callback: EventCallback): void;
|
|
143
|
+
off(eventType: IncomingGameEvent['event']['type'], callback: EventCallback): void;
|
|
144
|
+
onPlayAgain(callback: () => void): void;
|
|
145
|
+
onToggleMute(callback: (data: ToggleMuteEvent['data']) => void): void;
|
|
146
|
+
onGameStateUpdated(callback: (data: GameStateUpdatedEvent['data']) => void): void;
|
|
147
|
+
onGameInfo(callback: (data: GameInfoEvent['data']) => void): void;
|
|
148
|
+
onPurchaseComplete(callback: (data: PurchaseCompleteEvent['data']) => void): void;
|
|
149
|
+
setTarget(target: Window): void;
|
|
150
|
+
get purchasedItems(): string[];
|
|
151
|
+
get storeItems(): StoreItem[];
|
|
152
|
+
get gameInfo(): GameInfo | undefined;
|
|
153
|
+
get gameState(): GameState | null | undefined;
|
|
154
|
+
get players(): Player[] | undefined;
|
|
155
|
+
get player(): Player | undefined;
|
|
156
|
+
get isReady(): boolean;
|
|
157
|
+
ready: () => Promise<GameInfo>;
|
|
158
|
+
purchase: (data: PurchaseEvent["data"]) => Promise<PurchaseCompleteEvent["data"]>;
|
|
159
|
+
reportError: (data: GameErrorEvent["data"]) => void;
|
|
160
|
+
hapticFeedback: () => void;
|
|
161
|
+
hasItem: (item: string) => boolean;
|
|
162
|
+
getStoreItem: (slug: string) => StoreItem | undefined;
|
|
163
|
+
singlePlayer: {
|
|
164
|
+
actions: {
|
|
165
|
+
ready: () => Promise<GameInfo>;
|
|
166
|
+
hapticFeedback: () => void;
|
|
167
|
+
reportError: (data: GameErrorEvent["data"]) => void;
|
|
168
|
+
purchase: (data: PurchaseEvent["data"]) => Promise<PurchaseCompleteEvent["data"]>;
|
|
169
|
+
gameOver: (data: SinglePlayerGameOverEvent["data"]) => void;
|
|
170
|
+
saveGameState: (data: SaveGameStateEvent["data"]) => void;
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
multiplayer: {
|
|
174
|
+
actions: {
|
|
175
|
+
gameOver: (data: MultiplayerGameOverEvent["data"]) => void;
|
|
176
|
+
refuteGameState: (data: RefuteGameStateEvent["data"]) => void;
|
|
177
|
+
saveGameState: (data: MultiplayerSaveGameStateEvent["data"]) => void;
|
|
178
|
+
ready: () => Promise<GameInfo>;
|
|
179
|
+
hapticFeedback: () => void;
|
|
180
|
+
reportError: (data: GameErrorEvent["data"]) => void;
|
|
181
|
+
purchase: (data: PurchaseEvent["data"]) => Promise<PurchaseCompleteEvent["data"]>;
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
private emit;
|
|
185
|
+
private handleMessage;
|
|
186
|
+
private sendMessage;
|
|
187
|
+
private handleGlobalError;
|
|
188
|
+
private handleUnhandledRejection;
|
|
189
|
+
}
|
|
190
|
+
declare const sdk: FarcadeSDK;
|
|
191
|
+
|
|
192
|
+
export { FarcadeSDK, type GameErrorEvent, type GameEvent, type GameEventMessage, type GameInfo, type GameInfoEvent, type GameState, type GameStateUpdatedEvent, type HapticFeedbackEvent, type IncomingGameEvent, type MultiplayerGameOverEvent, type MultiplayerSaveGameStateEvent, type OutgoingGameEvent, type PlayAgainEvent, type Player, type PurchaseCompleteEvent, type PurchaseEvent, type ReadyEvent, type RefuteGameStateEvent, type SaveGameStateEvent, type SinglePlayerGameOverEvent, type StoreItem, type ToggleMuteEvent, type ViewContext, sdk };
|