# Cocos2d-x JavaScript

**URL:** https://heroiclabs.com/docs/nakama/client-libraries/cocos2d-js/
**Summary:** The official cocos2d JavaScript client handles all communication in real-time with the server. It implements all features in the server and can be used in cocos2d-x js projects. The client also comes with type definitions so it can be used via TypeScript. Learn how to setup and use the cocos2s JS client for Nakama.
**Keywords:** cocos2d-js client guide, cocos2d-js client, nakama cocos2d-js, authentication, persistence, storage, chat, matches, matchmaker, events, real-world example cocos2d-js
**Categories:** nakama, cocos2d, cocos2d-js

---


# Cocos2d-x JavaScript Client Guide

The official cocos2d JavaScript client handles all communication in real-time with the server. It implements all features in the server and can be used in cocos2d-x js projects. The client also comes with type definitions so it can be used via TypeScript.

The JavaScript client is [open source](https://github.com/heroiclabs/nakama-js) on GitHub. Please report issues and contribute code to help us improve it.

## Download

Download the latest release from the [GitHub releases page](https://github.com/heroiclabs/nakama-cocos2d-x-javascript/releases/latest) which contains the Nakama-js module with UMD module loader and polyfill library.

For upgrades you can see changes and enhancements in the [CHANGELOG](https://github.com/heroiclabs/nakama-cocos2d-x-javascript/blob/master/CHANGELOG.md/) before you update to newer versions.

## Setup

When you've [downloaded](#download) a release, extract it to your `src` folder.

Import into your `project.json`:

```json
"jsList" : [
  ...
  "src/NakamaSDK/ThirdParty/polyfill.js",
  "src/NakamaSDK/nakama-js.umd.js"
]
```

The client object is used to execute all logic against the server:

```javascript
// Default connection settings for a local Nakama server
var serverkey = "defaultkey";
var host = "127.0.0.1";
var port = "7350";
var useSSL = false;
var timeout = 7000; // ms

var client = new nakamajs.Client(serverkey, host, port, useSSL, timeout);

var client = new nakamajs.Client();
```

{{< note "important" >}}
Cocos2d does not support `await` and promises JavaScript features. You have to use promises which are provided by `polyfill` third party library.
{{< / note >}}

## Authenticate

With a client object you can authenticate against the server. You can register or login a [user](../../concepts/user-accounts/) with one of the [authenticate options](../../concepts/authentication/).

To authenticate you should follow our recommended pattern in your client code.

By default Nakama will try to create a user if it doesn't exist.

Use the following code to store the session:

```javascript
const email = "hello@example.com";
const password = "somesupersecretpassword";

client.authenticateEmail(email, password).then(function(session) {
        cc.log("Authenticated successfully. User id:", session.user_id);
        // Store session token for quick reconnects.
        cc.sys.localStorage.setItem("nakamaToken", session.token);
    },
    function(error) {
        cc.error("authenticate failed:", JSON.stringify(error));
    });
```

In the code above we use `authenticateEmail` but for other authentication options have a look at the [code examples](../../concepts/authentication/).

A __full example__ with all code above is [here](#full-example).

## Send messages

When a user has been authenticated a session is used to connect with the server. You can then send messages for all the different features in the server.

This could be to [add friends](../../concepts/friends/), join [groups](../../concepts/groups/), or submit scores in [leaderboards](../../concepts/leaderboards/). You can also execute remote code on the server via [RPC](../../server-framework/introduction/#functionality).

The server also provides a [storage engine](../../concepts/storage/collections/) to keep save games and other records owned by users. We'll use storage to introduce how messages are sent.

```javascript
const objects = [{
  "collection": "collection",
  "key": "key1",
  "value": {"jsonKey": "jsonValue"}
}, {
  "collection": "collection",
  "key": "key2",
  "value": {"jsonKey": "jsonValue"}
}];
client.writeStorageObjects(session, objects)
  .then(function(storageWriteAck) {
        cc.log("Storage write was successful:", JSON.stringify(storageWriteAck));
    },
    function(error) {
        cc.error("Storage write failed:", JSON.stringify(error));
    });
```

Have a look at other sections of documentation for more code examples.

## Real-time data exchange

You can connect to the server over a real-time WebSocket connection to send and receive [chat messages](../../concepts/chat/), get [notifications](../../concepts/notifications/), and [matchmake](../../concepts/multiplayer/matchmaker/) into a [multiplayer match](../../concepts/multiplayer/relayed/). You can also execute remote code on the server via [RPC](../../server-framework/introduction/#functionality).

You first need to create a real-time socket to the server:

```javascript
const useSSL = false;
const verboseLogging = false;
const createStatus = false;    // set `true` to send presence events to subscribed users.
const socket = client.createSocket(useSSL, verboseLogging);
var session = ""; // obtained by authentication.
socket.connect(session, createStatus)
  .then(
        function() {
            cc.log("connected");
        },
        function(error) {
            cc.error("connect failed:", JSON.stringify(error));
        }
    );
```

Then proceed to join a chat channel and send a message:

```javascript
socket.onchannelmessage = function (channelMessage) {
  cc.log("Received chat message:", JSON.stringify(channelMessage));
};

const channelId = "pineapple-pizza-lovers-room";
const persistence = false;
const hidden = false;

socket.joinChat(channelId, 1, persistence, hidden).then(
      function(response) {
          cc.log("Successfully joined channel:", response.channel.id);
          sendChatMessage(response.channel.id);
      },
      function(error) {
          cc.error("join channel failed:", JSON.stringify(error));
      }
  );

function sendChatMessage(channelId) {
  socket.writeChatMessage(channelId, {"message": "Pineapple doesn't belong on a pizza!"}).then(
      function(messageAck) {
          cc.log("Successfully sent chat message:", JSON.stringify(messageAck));
      },
      function(error) {
          cc.error("send message failed:", JSON.stringify(error));
      }
  );
}
```

You can find more information about the various chat features available [here](../../concepts/chat/).

## Handle events

A client socket has event listeners which are called on various events received from the server.

```javascript
socket.ondisconnect = function (event) {
  cc.log("Disconnected from the server. Event:", JSON.stringify(event));
};
socket.onnotification = function (notification) {
  cc.log("Received notification:", JSON.stringify(notification));
};
socket.onchannelpresence = function (presence) {
  cc.log("Received presence update:", JSON.stringify(presence));
};
socket.onchannelmessage = function (message) {
  cc.log("Received new chat message:", JSON.stringify(message));
};
socket.onmatchdata = function (matchdata) {
  cc.log("Received match data: ", JSON.stringify(matchdata));
};
socket.onmatchpresence = function (matchpresence) {
  cc.log("Received match presence update:", JSON.stringify(matchpresence));
};
socket.onmatchmakermatched = function (matchmakerMatched) {
  cc.log("Received matchmaker update:", JSON.stringify(matchmakerMatched));
};
socket.onstatuspresence = function (statusPresence) {
  cc.log("Received status presence update:", JSON.stringify(statusPresence));
};
socket.onstreampresence = function (streamPresence) {
  cc.log("Received stream presence update:", JSON.stringify(streamPresence));
};
socket.onstreamdata = function (streamdata) {
  cc.log("Received stream data:", JSON.stringify(streamdata));
};
```

Some events only need to be implemented for the features you want to use.

| Callbacks | Description |
| 
--------- | ----------- |
| onDisconnect | Received when the client is disconnected from the server. |
| onNotification | Receives live [in-app notifications](../../concepts/notifications/) sent from the server. |
| onChannelMessage | Receives [real-time chat](../../concepts/chat/) messages sent by other users. |
| onChannelPresence | Receives join and leave events within [chat](../../concepts/chat/). |
| onMatchState | Receives [real-time multiplayer](../../concepts/multiplayer/relayed/) match data. |
| onMatchPresence | Receives join and leave events within [real-time multiplayer](../../concepts/multiplayer/relayed/). |
| onMatchmakerMatched | Received when the [matchmaker](../../concepts/multiplayer/matchmaker/) has found a suitable match. |
| onStatusPresence | Receives status updates when subscribed to a user [status feed](../../concepts/status/). |
| onStreamPresence | Receives [stream](../../server-framework/streams/) join and leave event. |
| onStreamState | Receives [stream](../../server-framework/streams/) data sent by the server. |

## Logs and errors

The [server](../../getting-started/configuration/#log) and the client can generate logs which are helpful to debug code. To log all messages sent by the client you can enable `verbose` when you build a `client`.

```javascript
const verboseLogging = true;
const useSSL = false;
var client = new nakamajs.Client("defaultkey");
client.verbose = verboseLogging;
socket = client.createSocket(useSSL, verboseLogging);
```

---

## Full example

An example class used to manage a session with the cocos2d-x JavaScript client.

```javascript
var client = new nakamajs.Client("defaultkey");
var currentSession = null;

function storeSession(session) {
  cc.sys.localStorage.setItem("nakamaToken", session.token);
  cc.log("Session stored.");
}

function getSessionFromStorage() {
  return cc.sys.localStorage.getItem("nakamaToken");
}

function restoreSessionOrAuthenticate() {
const email = "hello@example.com";
  const password = "somesupersecretpassword";
  var session = null;
  try {
    var sessionString = getSessionFromStorage();
    if (sessionString && sessionString !== "") {
      session = nakamajs.Session.restore(sessionString);
      var currentTimeInSec = new Date() / 1000;
      if (!session.isexpired(currentTimeInSec)) {
        cc.log("Restored session. User ID: ", session.user_id);
        return Promise.resolve(session);
      }
    }

    return new Promise(function(resolve, reject) {
      client.authenticateEmail(email, password)
        .then(function(session) {
            storeSession(session);
            cc.log("Authenticated successfully. User ID:", session.user_id);
            resolve(session);
          },
          function(error) {
            cc.error("authenticate failed:", JSON.stringify(error));
            reject(error);
          });
    });
  } catch(e) {
    cc.log("An error occurred while trying to restore session or authenticate user:", JSON.stringify(e));
    return Promise.reject(e);
  }
}

restoreSessionOrAuthenticate().then(function(session) {
  currentSession = session;
  return client.writeStorageObjects(currentSession, [{
    "collection": "collection",
    "key": "key1",
    "value": {"jsonKey": "jsonValue"}
  }]);
}).then(function(writeAck) {
  cc.log("Storage write was successful - ack:", JSON.stringify(writeAck));
}).catch(function(e) {
  cc.log("An error occurred:", JSON.stringify(e));
});
```
