npm package: @onmuga/sdk
Description: SDK for the Onmuga multi-player game platform
Latest version: 0.0.7

# @onmuga/sdk

Onmuga client SDK

## Quick Start

### Installation

#### Using script tag

```html
<script src="https://unpkg.com/@onmuga/sdk@0.0.7"></script>
```

The SdkClient will be available as `window.onmuga.SdkClient`

#### Using npm

Install the npm package

```shell
npm install --save @onmuga/sdk
```

Load into your project

```js
// Using ES6 imports
import SdkClient from '@onmuga/sdk';

// Or, using require
var SdkClient = require('@onmuga/sdk');
```

### Getting Started

```js
// Initialize the SDK client for your game
const sdk = new SdkClient({
  apiKey: 'YOUR_API_KEY_HERE',
  game: 'yourgame',
});

sdk.on('gameStateChanged', (stateKey, state) => {
  // Re-render your app with new game state
});

sdk.on('usersChanged', (users) => {
  // You may want to re-render your user list here
  users.forEach(user => {
    // user == {
    //   connected: true,
    //   id: "ly3YHy5GZ9Pw",
    //   username: "foo"
    // }
  });
});

// Check if a username exists already from a previous sesssion
let username = sdk.getUsername();

if (!username) {
  username = window.prompt('Select a username');
  sdk.setUsername(username);
}

// Up to you to decide on how room IDs are stored in URL, then extract them appropriately
let roomId = getRoomFromUrl(window.location);
if (!roomId) {
  roomId = window.prompt('Enter a room ID or leave blank to create a new room');
}

if (!roomId) {
  sdk.createRoom(username).then(onJoinRoom);
} else {
  sdk.joinRoom(roomId, username).then(onJoinRoom);
}

function onJoinRoom(response) {
    console.log(`Joined room ${response.roomId}`);

    // We'll update game state here for illustrative purposes
    sdk.updateGameState('default', {
        ...sdk.getGameState('default'),
        newestUser: username,
    });
}
```

## API Reference

#### `new SdkClient(options)`
Constructs a new SDK client. Your game should likely just contain one global instance of this.

`options`
- `apiKey` - Onmuga platform public API key provided to you (string, required)
- `game` - Lowercase idenitifer for your game e.g. "battle-snake" (string, required)

#### `sdk.getRoom(): string|null`

Return the room ID that the user is currently connected to

#### `sdk.getUsername(): string|null`

Return the current user's username (set via `joinRoom` or `setUsername`)

#### `sdk.setUsername(username: string): Promise`

Update the current user's username.

Returns a promise that will be rejected with an Error if the username was rejected for any reason.

#### `sdk.getUserId(): string|null`

Return the user ID associated with the user when they joined the room

#### `sdk.getUsers(): User[]`

Return the users in the current room. Each `User` has the following properties:

- `id` - string
- `username` - string
- `connected` - boolean, whether the user is currently connected

#### `sdk.getUserById(id: string): User|undefined`

Return the specified `User` if they exist in the room. See `getUsers` for `User` shape.

#### `sdk.createRoom(username?: string): Promise`

Creates a new room, and adds the current user. 

If username is not provided, the sdk will try using (1) any username from a previous `setUsername(...)` call, (2) username from a previous session, or (3) an auto-generated username like "RedSloth4".

Returns a promise that will be rejected in case of an error.

#### `sdk.checkRoom(roomId: string): Promise<{success: boolean}>`

Checks if a room with the given ID exists

Returns a promise that resolves to an object with the following properties:
- `success` - boolean, `true` if room exists, `false` otherwise

#### `sdk.joinRoom(roomId: string, username?: string): Promise`

Joins the specified room.

If username is not provided, the sdk will try using (1) any username from a previous `setUsername(...)` call, (2) username from a previous session, or (3) an auto-generated username like "RedSloth4".

Returns a promise that will be rejected in case of an error joining the room.

#### `sdk.getAllGameStates(): Object`

Your game can have multiple states associated with it, each keyed by a unique string. This allows you to surgically update certain aspects of your game, without constantly re-rendering the whole game when the game state changes.

The schema of each state object is fully controlled by the developer.

#### `sdk.getGameState(stateKey: string): Object`

Return a specific game state object. The schema of these state objects is fully controlled by the developer.

`stateKey` - The game state object to retrieve

#### `sdk.updateGameState(stateKey: string, state: Object): Promise`

Update the game state for the specific key. State is a plain javascript object that the developer has full control over.

The server will then emit a `gameStateChanged` event for all users in the room.

Returns a promise that will be rejected in case of an error.

#### `sdk.joinRoom(roomId: string, username?: string): Promise`

Joins the specified room.

If username is not provided, it will use any username set in a previous session, or by an earlier `setUsername` call.

Returns a promise that will be rejected in case of an error joining the room.

#### `sdk.on(eventName: string, callback: fn)`

Listen to events emitted by the SDK, see event reference below

Callback may be passed data associated with the event

#### `sdk.once(eventName: string, callback: fn)`

Listen to an event one time – immediately removing the listener afterwards.

#### `sdk.off(eventName: string, callback: fn)`

Remove the specified listener for the specified event

#### `sdk.broadcast(eventName: string, data?: JsonSerializable): Promise`

Broadcast an arbitrary event (i.e. `playerCheated`) to every other user in the game. You can use `sdk.on` to listen for these messages.

Returns a promise that will be rejected in case of an error.

#### `sdk.message(userId: string, eventName: string, data?: JsonSerializable): Promise`

Broadcast an arbitrary event (i.e. `playerCheated`) to a specific user in the game.

Returns a promise that will be rejected in case of an error.

#### `sdk.now(): number`

Sometimes in games you may need to compare timestamps generated on different players devices (for example, to figure out which player took an action first). This can be problematic because the system clock on some player's devices is occasionally a couple minutes fast or slow.

Instead of using a native JS `Date`, you should use the `now()` method. This returns a unix epoch timestamp that is roughly synchronized to server time and will help achieve consistency across clients.

#### `sdk.serverToClientTime(serverTime): number`

Converts a timestamp returned by `now()` back into a timestamp that can be compared with the clients system time.

## Event Reference

You can listen to these events using `sdk.on/off(...)`

#### `gameStateChanged`

The game state was updated by some user in the room (possibly the current user!)

Listeners are invoked with the following arguments:
- `stateKey: string` - The state key associated with this game state (e.g. `'default'`)
- `gameState: object` - The updated game state object
- `prevState: object` - The previous game state object held by the client, useful for comparison
- `sourceUserId: string` - ID of the user who triggered this state update

#### `usersChanged`

The list of users in the room has changed, either users joined or left or their metadata changed.

Listeners are passed an array of `User` objects (see `getUsers()` above for shape)

#### `invalidApiKey`

Will be emitted if the API key you used to construct `SdkClient` is invalid, or if the current hostname is unsupported.