# Introduction

Welcome to the escs. Here you will find some general words about the escs and how you can use it.

### Fun with ESCS ✨

**escs** is short for **Embedded Social and Competition Services**. \
What started as an esports platform has evolved into a **decentralized distribution network** and **publishing platform** for games.

A simple escs integration does three things:

1. **Adds a Competition Hub to your game**\
   Players and you can run tournaments and events, with built-in social features.
2. **Gets your game discovered** \
   Your game becomes connected to the escs distribution network of digital platforms and creators - reaching **billions of players**.
3. **Unlocks a new revenue stream**\
   escs gives you half of everything escs makes through partnerships, entry fees, sponsoring.

escs is designed with developers in mind - integration aims to be extremely easy. \
Basic integration can be done in 15 minutes.&#x20;

***

**Integration steps.**

1. **Register and create your game** in escs developer dashboard.
   1. Use our sandbox demo environment for the first steps: [https://client.demo.escs.io](https://client.demo.escs.io/)
   2. When everything works smoothly move to the prod at [https://client.escs.io](https://client.escs.io/)
2. **Choose the plugin** for your game engine (select it from the left-hand menu) and follow the integration instructions.

That’s it — you’re ready to go.

We’re trying to keep the system convenient, flexible, and powered by that rare artifact known as **“common sense.”** \
Still, we know perfection is a myth (like a bug-free release). \
If anything is unclear or you spot an opportunity to improve the docs, please tell us here: [https://support.escs.io](https://support.escs.io/).


# Integration - step 1

Create and register your game.

We are assuming that you are starting with the sandbox on the demo environment.\
When you are ready to move to the production just apply the same instructions: essentially you will be removing the word "demo" from the urls and endpoints, like instead of "api.demo.escs.io" you will use "api.escs.io". Find our more information here: [Moving to production](https://app.gitbook.com/o/-MBTzNswyYG20uBURMs7/s/-MAfYp0johoPRZW2PhVp/~/edit/~/changes/108/general/moving-to-production).

[client.demo.escs.io](https://client.demo.escs.io/) is your main entry point. \
Here you can register games, create and edit competitions, view stats, manage your account and more.

## Registration.

1. Go to the [client.demo.escs.io](https://client.demo.escs.io/) and create your account.
2. After the login you see this friendly introduction:

![Friendly introduction](/files/5eTVXpjQo05xAOnNmmFQ)

## Creating a game

The information you enter here is important since it will be shown to your players.

<figure><img src="/files/J7jekNvC2BS6X7Xr37sM" alt=""><figcaption><p>Please complete this form and press "Create app".</p></figcaption></figure>

Choose "Public tournament", enter the name and description of the game. \
When you are done, click "Create app" button.&#x20;

Now you probably see something like this screen (just without the logo  - we did not add it). \
If not - something is terribly wrong and all is lost.

<figure><img src="/files/iPv7T6DY5nJ2fCZ7POix" alt=""><figcaption><p>Click the tab "Scores"</p></figcaption></figure>

Now click the tab "Scores" and setup your first game score: the basic metric that measures how good your players are in your awesome game. For example, in Tetris it's points. "Sort" defines if higher values are better (choose "Desc" for that) or lower values are better (choose "Asc" for that). Score name is shown to the players.  You can have as many scores as you want. Define just one for now.&#x20;

<figure><img src="/files/BCi2Gwj8nWrz6nCe3J9r" alt=""><figcaption><p>Define your fist score as in the example. Choose "Default"</p></figcaption></figure>

When you are done, click "Save" button.&#x20;

Now click "Referrals" in the top menu.

<figure><img src="/files/2BrDH8o8B654Sx4AggpM" alt=""><figcaption><p>Click "Referrals" and create your first referral.</p></figcaption></figure>

Click "Add new referral" , enter any name and press "Create"

<figure><img src="/files/yj2SHb3fwso2G6gKeTDK" alt=""><figcaption><p>Like here.</p></figcaption></figure>

Go back to "Apps" and click "View details" on your game.

<figure><img src="/files/zUBVFVFeIyS9NmdMVr8O" alt=""><figcaption><p>Click"View details".</p></figcaption></figure>

Now click "VIEWS" tab and create your first view.

<figure><img src="/files/h4bl38lmMiXJY2gFHIA9" alt=""><figcaption><p>Click "VIEWS" tab and click "Create view!</p></figcaption></figure>

Enter any name you want. Don't change the game. Choose the referral that you just created. Choose the integration type that corresponds to your game. Leave everything else as it is for now. You can change it later. Then click "Submit".

<figure><img src="/files/N0qaoDRj2DQbQ4m0mv9Y" alt=""><figcaption><p>Enter parameters similar to the screenshot and click "Submit"</p></figcaption></figure>

The result should look something like on the screenshot below. You need the public key and the player\_base\_url for your integration in the next step.

<figure><img src="/files/9N5jUb7LsM9SVOWadfk9" alt=""><figcaption><p>The important information is in the JS field in the parenthesis.</p></figcaption></figure>

Copy your **public key** and the **player\_base\_url** and go to the ["Integration - Step 2"](/integration-step-2).


# Integration - step 2

Choosing and integrating plugin.

escs is plugin based. We are providing plugins for different game engines and all you have to do is to integrate our plugin.

## Connect plugin to the project.

Locate plugin for your game engine in the menu on the left and follow instructions there on how to download and connect it to your project.

{% hint style="info" %}
If you do not see a plugin for your game engine, please write us a message. We are constantly developing new plugins and are happy to help you.
{% endhint %}

Here you will find generic description on how to integrate plugins. For specific instructions go to the instructions for your game engine on the left.

## Set up the plugin.

For the escs to work properly with your game you need to do 3 simple things:&#x20;

* initialize the system at the start of your game (after that all the socialization features are immediately available)
* let the escs know when the user starts an actual game or start the game when escs let's you know about that.
* let the escs know when the user ends the game and sends the user's score to the escs.

At the start of your game, as early as possible, call the method `invokeManaged()` of the plugin. Invoke takes public key from step 1 as a parameter, which you must submit (this is example for JS/ReactNative plugin, please refer to appropriate plugin section for config parameters):

```
service.invokeManaged({
    public_key: '3dd48bec-2e82-4826-8757-fc14d872882d',
    base_url: 'https://api.escs.io',
    player_base_url: 'https://37b35a72-f8d9-48ca-8cd1-e6690c23637c.player.escs.io',
    analyticsEnv: 'stage'
})
```

When a user starts an actual game, just before the game starts, call method `startGame()` or register a callback as described in your plugin section .

```
service.startGame()
```

When the game ends, call the method `endGame(points)` - instead of points send an actual score that the user got in the game.

```
service.endGame(1378)
```

{% hint style="info" %}
You can define units for the score and more in the client.escs.io.&#x20;
{% endhint %}

This completes the basic integration. \
Now when you start your game, you'll find an escs symbol inside it and all the services that escs has to offer.

Where to go from here, besides the description of the specific instructions for your plugin? \
Read about the tournament series [here](https://docs.escs.io/tournament-series/your-first-tournament-series).


# Unity

How to integrate the Unity plugin.

You can use this plugin for Mobile Unity games - at the moment we support Android and iOS

**Get it on the Unity** [**Asset Store**](https://assetstore.unity.com/packages/tools/utilities/escs-for-unity-plugin-real-time-connections-for-your-game-263629)**!**

## Connecting plugin to your project.

{% hint style="info" %}
Unity plugin is currently for native devices only - it means that you won't be able to see plugin working in Unity Editor "Play" mode. However you can use device emulators to run the game and see plugin in action there. We are planning to add Editor functionality and Windows plugin as well in the future.
{% endhint %}

It's very easy to add our plugin to your Unity project - just drop our plugin folder into **./Assets/Plugins** (don't forget to create **Plugins** folder if you don't have one yet). The only prerequisite is [**External Dependency Manager for Unity**](https://github.com/googlesamples/unity-jar-resolver) (EDM4U) **- it should be installed for the plugin to work correctly,** otherwise you will need to provide all the dependencies manuall&#x79;**.** Just use the latest version (1.2.179 at the moment). The configuration of the EDM4U is listed for each platform below.

Right after adding our plugin for the first time to your project, you will be greeted with welcome window like this (if you somehow miss it, you can open it using Window -> ESCS Plugin):

<figure><img src="/files/E8vyQXjV0nkgsljkZFcO" alt=""><figcaption><p>ESCS welcome window</p></figcaption></figure>

You can explore our API demo, filling the public key field with your public key generated at [https://client.demo.escs.io](https://client.demo.escs.io/) (<https://client.escs.io> on production) (or you can just click "Open ESCS Dashboard") and then clicking "Open example scene". Example will use public key that you entered in that field. **Please install TMPro** (Text Mesh Pro) Essentials beforehand (Window -> TextMesh Pro -> Import TMP Essential Resources).

{% hint style="info" %}
**Note:** if you don't import TMPro before opening the scene, Unity will automatically ask you to do that, and you may encounter error (right after importing TMPro) like this:
{% endhint %}

<figure><img src="/files/2yy83kCCEQVwaTR7Q4KM" alt=""><figcaption><p>Importing errors that you can safely ignore</p></figcaption></figure>

{% hint style="info" %}
You can safely ignore it and continue (press Play in editor and it will go away), it is due to opening scene before you have TMPro Essentials installed. To avoid this error install TMPro Essentials beforehand (Window -> TextMesh Pro -> Import TMP Essential Resources)
{% endhint %}

Exploring our demo scene, note that our code assumes that **your game's score type** (created in <https://client.escs.io>) **is named "points"**, otherwise you won't get results sent from the demo.&#x20;

#### Android

Unfortunately, we provide out-of-the-box integration only for **Unity 2022** and higher. If you are still using Unity 2021, you have to manually update your gradle scripts to support android's `compileSdk 33 / targetSdk 33` (you have to do that anyway since it is now a requirement for Google Play Store). This restriction is due to new Android permissions model for capturing device screen, introduced in Android SDK 33. The code required to support this change, will not compile using older versions of sdk, gradle and android gradle plugin.&#x20;

{% hint style="info" %}
To use Android Unity plugin you need to use compileSdk 33 or higher in your gradle build. For Unity 2022 the change is trivial - you can update the version manually in your custom gradle template or using Target API Level = 33 in your unity project settings.
{% endhint %}

Because Android build system heavily relies on package dependency management and Unity does't really support it out of the box, we need 3rd party dependency managements solution added. If you are working on a big project, chances are that you are already use it, otherwise please import following package:

{% embed url="<https://github.com/googlesamples/unity-jar-resolver>" %}

This is officially supported by google package manager for Unity. Just download latest .unitypackage file from the repository and drag and drop it into your assets folder, it will automatically install itself. We recommend you to allow it to automatically resolve dependencies, otherwise you can do it manually from the Assets menu (after installing aforementioned package):&#x20;

![Resolving dependencies for Android ](/files/-MD_k0fnqOuUpLDClT83)

Due to known issue (<https://github.com/googlesamples/unity-jar-resolver/issues/591>) in dependency resolver, the standard download artifacts phase may fail or resolve incorrect versions of libraries. We advise to use these settings for Android resolving:

<figure><img src="/files/8NQdpaJXvdwZwLFAwWFW" alt="" width="375"><figcaption><p>Advised android resolver settings </p></figcaption></figure>

They are enabled by default, but make sure that you haven't unchecked them.&#x20;

{% hint style="info" %}
Note, that for these settings to work you have to enable custom main gradle template and gradle settings template in Unity Player Settings, as shown below:

![](/files/D32SbUOXZDtTlWSoNrmR)
{% endhint %}

#### Supporting video chat and streaming on Android

To support escs video chat and streaming on android platform, you need to define several properties in player settings in Scripting Define Symbols:

![Android define symbols required for video chat and streaming](/files/-MlGWUOwaCck-Jb3ZZFY)

These symbols will allow build post-process script to add specific code in Android Manifest and main activity to support video chat and  streaming.

For video chat you need 2 following define symbols:

`ESCS_ANDROID_ENABLE_CAMERA;ESCS_ANDROID_ENABLE_MICROPHONE`

separated by semicolon. If you are targeting Android API 29 or higher, then you also need to define`ESCS_ANDROID_API29_STREAMING` symbol, otherwise the app will crash upon receiving user's permission to record screen when streaming is starting, so in total you will need to define 3 symbols:

`ESCS_ANDROID_ENABLE_CAMERA;ESCS_ANDROID_ENABLE_MICROPHONE;ESCS_ANDROID_API29_STREAMING`

If you have highly customized Android Manifest and/or UnityPlayerActivity, then auto-generation may fail and you have to add following code manually to support notifications and streaming:

```java
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    EscsAndroidUnityPlugin.onActivityResult(requestCode, resultCode, data);
}

@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    EscsAndroidUnityPlugin.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
```

#### iOS

For iOS you need to use the same [**External Dependency Manager for Unity**](https://github.com/googlesamples/unity-jar-resolver) as for Android, it will generate pods project. Be aware that we use `use_frameworks!` param in resulting pod file. However you can live without the resolver if you put required dependency manually. Internally the Escs Plugin uses `SDWebImageWebPCoder` (<https://github.com/SDWebImage/SDWebImageWebPCoder>) which in turn uses `SDWebImage`, so you need to manually link those libraries if you don't want to use pods and dependency resolver.

{% hint style="info" %}
**Important!** We do not currently support static linking because of Google WebRTC is shipped only as dynamically linked pod, so be sure that you **uncheck "Link frameworks statically"** in External Dependency Manager configuration, otherwise you might encounter errors when starting your game, saying that WebRTC framework is not found.

<img src="/files/FkQllIecPiCPdfDY9WIQ" alt="" data-size="original">
{% endhint %}

Be advised that you will not be able to use bitcode (because we have dependency on Google WebRTC which does not come with bitcode support). Also our framework is FAT framework, so it comes with both x86\_64 and arm64 architectures. We provide built-in script for removing unused architectures when exporting build to iOS targets, so you don't need to worry about that, unless you already have one present in your build config. Then you just have to delete extra one.

When building for iOS you might encounter an **error** saying something like this:\
`Undefined symbols for architecture arm64: "_CallRegisterIngamePlayerId", referenced from: _EscsIosUnityPlugin_CallRegisterIngamePlayerId_m3865D0F13C4088A49DC16A615D13760E27353033 in Bulk_Assembly-CSharp-firstpass_0.o (maybe you meant: _EscsIosUnityPlugin_CallRegisterIngamePlayerId_m3865D0F13C4088A49DC16A615D13760E27353033) ld: symbol(s) not found for architecture arm64`

In that case you might need to supply additional parameters to your linker. Go to your build target > **Build Settings > Linking > Other Linker Flags** and add the following line: `-Wl,-undefined,dynamic_lookup`

## Integrating plugin into your game.

It is very easy to integrate ESCS plugin into your game code.&#x20;

We splitted these instructions into steps to make it easier to follower. Please complete each step before running your code.

{% hint style="info" %}
Make sure you completed the [Integration - step 1](https://docs.escs.io/integration-step-1) before you proceed.
{% endhint %}

### Step 1, which enables all the socialization features

First you need to initialize your plugin.&#x20;

#### Initialization

To start using your plugin you need first initialize it:

```csharp
using EscsUnity.Core;

EscsUnityPlugin.Invoke(
        string public_key, 
        string base_url, 
        string player_base_url, 
        InvokeDelegate OnEscsInit);
```

where:&#x20;

* **`public_key`**- a key that you've obtained in the step 1 of the integration guide, like `"fee91a27-2b87-45f8-8ca4-0b317707806q"`
* **`base_url`** - url for the core ESCS service. It is `https://api.escs.io` for production environment
* **`player_base_url`** - the URL for the view you created in the [first step of the integration](https://docs.escs.io/integration-step-1), like this one `https://37b35a72-f8d9-48ca-8cd1-e6690c23637c.player.demo.escs.io`  (without "demo" on production)
* **`OnEscsInit`**- callback delegate when init is completed; you can omit it.&#x20;

**IMPORTANT! Although you can call Invoke several times, you should do it only once, otherwise behaviour is undefined.**

Delegate method signature is following:

`public delegate void InvokeDelegate (string status, string gameId, string tournamentId);`

where:&#x20;

* `status`  - string "initialized" for fully initialized escs, or some error message, or empty string
* `gameId` - gameId of configured game or empty string
* `tournamentId` - tournamentId of current active tournament or empty string

That's it! \
Now your players can chat, video chat or stream. Awesome, right?

### Step 2, which enables eSports

escs takes care of the organization of competitions. For this to work, escs just need to let you know when to start a game and in return you need to let escs know player's score after the end of the game. Additionally, if your game is a true multiplayer game, you should let escs know your in-game player ids for the proper matchmaking

#### Registering in-game player id and metadata:

&#x20;Call this right after you initialize the escs service and before player interacts with escs:

```csharp
EscsUnityPlugin.RegisterIngamePlayerId(playerId, ingameMetadata);
```

where:&#x20;

* **playerId** - your ingame player id (**string**). It will be passed along with OnGameSetStart callback when the game set will start
* **ingameMetadata** - your ingame metadata for this player (**string, can be empty**)

#### Start Game

Now let's start the game.

Whenever escs starts a tournament and therefore initiates a game for the player, escs let's you know that you need to start the game. For this purpose escs provides **OnGameSetStart** callback.\
When it is called - this is the moment when you should start your game or create lobby and await for players to join it. \
Here is how you can register it.

```csharp
EscsUnityPlugin.SetGameSetStartCallback(onSetStart);
//...
public void OnSetStart(EscsSetStartPayload p) { 
    Debug.Log("set started - players: ");
    foreach(EscsTeam team in p.teams) {
        Debug.Log("team: ");
        foreach(EscsParticipant particip in team.members) {
            Debug.Log(particip.username);
        }
    }
}
```

where **EscsSetStartPayload** contains:&#x20;

* **setId** - setId of started set (**string**)&#x20;
* **tournamentId** - tournamentId of the set (**string**)&#x20;
* **matchId** - matchId of the set (**string**)&#x20;
* **roundId** - roundId of the set (this is in fact id of the set "results") (**string**)&#x20;
* **globalMetadata** - metadata string that can be set in the game dashboard (**string**)&#x20;
* **setEndTimeUnix** - game's set latest end time in unix time (**int**)
* **teams** - array of **EscsTeam** objects. Each **EscsTeam** has array of **EscsParticipant**, which in turn contains:&#x20;

  * **playerId** - escs player id (**string**)&#x20;
  * **ingamePlayerId** - registered in-game player id via registerInGamePlayerId (**string**)&#x20;
  * **username** - user's escs username (**string**)&#x20;
  * **firstName** - user's escs first name (**string**)&#x20;
  * **lastName** - user's escs last name (**string**)&#x20;
  * **avatar** - user's escs avatar image url (**string**)&#x20;
  * **ingameMetadata** - in-game metadata that was registered via **RegisterInGamePlayerId** (**string**)

From all this parameters the most important one for you is the **roundId**, which you will be using to send the score of the game back to the escs.&#x20;

You should use **ingamePlayerIds** to start the game for the right players (relevant only if your game is a multiplayer game).

Additionally, you might find it useful to send scores of some of the games to the escs, that are not part of the tournament, for example for the World Top Today or ELO calculations. \
In this case you may call the `StartGame()`method to let the escs know of the start of the game (call it only for the games where you are not using **OnGameSetStart** callback to start the game) :

```csharp
EscsUnityPlugin.StartGame(StartGameDelegate OnStartGame);
```

where&#x20;

* **`OnStartGame`** - callback delegate when startGame has obtained round info (you can omit it) with following signature:

`public delegate void StartGameDelegate (string roundId, string tournamentId, string status, string playerId);`

where:&#x20;

* `roundId`  - roundId of just started game round in the escs.&#x20;
* `tournamentId`- tournamentId of active tournament for which the round was created for
* `status`- round status. "active" for just created round
* `playerId`- escs playerId

#### Progress Game (Optional)

During gameplay, you can send progress of the players, this will allow advanced insights into your gameplay and ability to see their scores and score graphs in streaming view. Call  `ProgressGame()` with score parameter:

```csharp
[Serializable]
public class GameScoreExample {
    public double points;
    public double points_extra;
}
...
public void OnProgressGame(string progressId, string roundId) {
    Debug.Log(roundId);
    Debug.Log(progressId);
}
...
GameScoreExample score = new GameScoreExample();

score.points = Mathf.Ceil(UnityEngine.Random.Range(0.1f, 100.0f));
score.points_extra = Mathf.Ceil(UnityEngine.Random.Range(0.1f, 100.0f));

EscsUnityPlugin.ProgressGame(score, OnProgressGame);
```

where&#x20;

* **`score`** - game score parameter - accepts an object with Serializable annotation; the names of properties should be defined in game dashboard at [client.escs.io](https://client.escs.io), the type of each is **double**
* **`OnProgressGame`** - callback delegate when progressGame has obtained round info (you can omit it) with following signature:

`public delegate void ProgressGameDelegate(string progressId, string roundId);`

where:&#x20;

* `roundId`  - roundId of just progressed game round
* `progressId`- id of just sent progress object

#### End Game

When the round of your game has ended, just call  `EndGame()` with score parameter:

```csharp
[Serializable]
public class GameScoreExample {
    public double points;
    public double points_extra;
}
...
public void OnEndGame(string roundId, string tournamentId, string status, string playerId) {
    Debug.Log(roundId);
    Debug.Log(status);
}
...
GameScoreExample score = new GameScoreExample();

score.points = Mathf.Ceil(UnityEngine.Random.Range(0.1f, 100.0f));
score.points_extra = Mathf.Ceil(UnityEngine.Random.Range(0.1f, 100.0f));

EscsUnityPlugin.EndGame(score, OnEndGame);
```

where&#x20;

* **`score`** - game score parameter - accepts an object with Serializable annotation; the names of properties should be defined in game dashboard at [client.demo.escs.io](https://client.demo.escs.io/) ([client.escs.io](https://client.escs.io) on production), the type of each is **double**
* **`OnEndGame`**  - callback delegate when startGame has obtained round info (you can omit it) with following signature:

`public delegate void EndGameDelegate (string roundId, string tournamentId, string status, string playerId);`

where:&#x20;

* `roundId`  - roundId of just ended game round
* `tournamentId`- tournamentId of active tournament for which the round was ended&#x20;
* `status`- round status. "ended" for just ended round
* `playerId`- escs playerId

Now you are done! Your game is now a competition platform. \
Go and create tournaments in the dashboard, your players can create tournaments inside the game and 3rd party organizers can create tournaments and drive players into your game.

You can integrate more deeply with escs. Read [optional steps](/plugins/unity/optional-steps) to know more.


# Optional steps

Describes additional steps that you can use to customize your integration with the escs

### ESCS ready callback

When you get the callback from **EscsUnityPlugin.Invoke**, this means that plugin is ready to work and can show UI. But this does not mean that you can already use every ESCS feature, as some components require more time to hook up. Most of the time you don't need to worry about it, but in some cases it is not what you want (e.g. your game loads from deep link and you want to show tournament/wager inside ESCS, so you might want to disable your game UI until ESCS is able to show full info). To remedy this problem, we provide additional callback:

```csharp
    EscsUnityPlugin.SetEscsReadyCallback((success) => {
        Debug.Log("Escs is ready!");
    });
```

Receiving this callback means that ESCS is fully ready to receive and perform any supported actions.

### Hiding ESCS button

Most of the time you will not want to show the ESCS button during the actual game, to not mess with the gameplay, for example user can accidentally touch it and almost full-screen webview will show up. To hide or show button you can use the following methods:

```csharp
EscsUnityPlugin.HideEscsButton();
EscsUnityPlugin.ShowEscsButton();
```

### Opening ESCS view programmatically

Sometimes you might prefer to implement you own customized button for opening escs in style of your game and with full control of its position. For such cases you can hide escs button altogether (like shown above) and open Escs with your own button using following method:

```csharp
EscsUnityPlugin.OpenEscsView();
```

### Notifications/Announcements

There are situations, when ESCS needs to show announcements or notifications - for example to promote your game's upcoming championship. ESCS will open its full WebView automatically to show notification's content, if it's needed. To be able to show these, not interrupting your gameplay and at the times that are not disruptive for the player, please call these methods:

```csharp
   EscsUnityPlugin.MaybeShowNotifications();
   EscsUnityPlugin.MaybeShowAnnouncements();
```

There's internal logic in the plugin to decide whether it needs to show actual notification and announcement, but you should place these calls whenever you feel that interruption with ESCS WebView window is okay for user experience.&#x20;

***Please note*** that it does **not** mean that user will see notification or announcement **every time** you call these methods. We are trying for those to be as subtle and fluent as possible for end user. Their names imply that notification/announcement just **maybe** will be shown.

### Changing the default button position

There are situations when it is not suitable for your UI to have our ESCS button at the default top center area. Then you can change that (remember, that user actually can drag the button anywhere on the screen he wants)

`SetButtonDefaultPositionAbsolute()` will set button position in absolute coordinates from left upper corner of the app.

```csharp
   EscsUnityPlugin.SetButtonDefaultPositionAbsolute(float x, float y);
```

where

* x - x coordinate
* y - y coordinate

`SetButtonDefaultPositionRelative()` will set button position in relative coordinates from center horizontally and top vertically of the app. That is, if you set **0, 0** coordinates the button will be shown in the **x: (device width)/2  y: 0.**&#x20;

The coordinate system here is from **-0.5 to 0.5** for `xPart` : where **-0.5** means most left side of device and **0.5** - right side and **0** is dead center. For `yPart` it is from **0 to 1** where **0** is top of the screen and **1** is the bottom.

```csharp
  EscsUnityPlugin.SetButtonDefaultPositionRelative(float xPart, float yPart);
```

**NOTE! Both these methods are setting default button position for only the first game start. You should call them immediately after calling Invoke (not in the initialization handler).**

### Getting in-game rewards

To receive the list of in-game rewards that particular player has (you can set those rewards as string fields in your game dashboard - for winning matches and so on) you can use the following method:

```csharp
EscsUnityPlugin.GetIngameRewards(OnGetRewards);
//...
public void OnGetRewards(EscsIngameRewards rewards) {
    Debug.Log("onGetRewards callback");

    foreach(EscsRewardPayload p in rewards.data) {
        Debug.Log(p.rewardData);
    }
}

```

where:&#x20;

* **`OnGetRewards`**- callback delegate when GetIngameRewards has rewards info, with following signature:

`public delegate void EscsGetIngameRewardsDelegate (EscsIngameRewards rewards);`

where: `EscsIngameRewards is object with follwing fields:`

* int **count** - amount of rewards
* **EscsRewardPayload**\[] **data** - array of **EscsRewardPayload** objects, which contain:
  * string **id -** id of the reward
  * string **rewardData -** reward data **-** the string that you set in the game dashboard
  * string **tournamentId -** tournament id where the reward was obtained

## Multiplayer

### Overview

We support multiplayer games with different types of matches, matchmaking and so on. To be able to use this feature, you need to follow these steps:&#x20;

* Implement several callbacks in you game, which will be called in response to player's engagement with multiplayer tournament

{% hint style="info" %}
How to do a backend-to-backend integration (receive callbacks and further information on your backend) is described at the end of this page.
{% endhint %}

Currently we provide 4 such callbacks:

* **OnGameSetStart** callback - is called when a game set is started by escs backend. We already described this one in the basic integration section.&#x20;

{% hint style="info" %}
What is a "set"?&#x20;

Matches in a escs have a very flexible structure to accommodate all the possible needs. But think of them as of matches in tennis Grand Slam tournaments. \
So a match consists of one or more sets. And a set consists of one game between the match participants: the time between the game start or on OnGameSetStart callback and the call of the EndGame() method.&#x20;

Now depending on the the game mode in your game, you might want to decide to let players actually play more then one game in a set - it is entirely your decision and you control it by deciding when to call the EndGame() method. \
For example, in a game of Tetris you could let players play just one game before calling the EndGame() method or you can let them play 3 games and call the EndGame() method after the 3rd game, sending to the escs the cumulated score of all 3 games.\
How do you let the players and tournament organizers know about these details? \
This is what the **game mode** is for. Read more about it here.

A game between players can be a multiplayer game or a single player game. It can be a real multiplayer (e.g. they, for example, race each other on track in a racing game or are participating in a deathmatch 1vs1 or 2vs2 and so on), or just a single player, meaning that they all play their own single player games (like solving puzzles and the one who solves it faster is the winner). \
In the OnGameSetStart callback you will receive information about players that are playing this set, teams that players are in (i.e. 2vs2 game), metadata that is supplied with the player (supplied by registerInGamePlayerId) and global metadata that is set in the game dashboard.
{% endhint %}

* **OnGameSetEnd** callback - is called when each player in the set has finished their game. this might be not necessary the same moment you end your multiplayer game - it is called when the escs backend processed all game end events from each participating player and saved their corresponding scores. You will receive **matchId** and **setId** as parameters
* **OnMatchStart** callback - is called when multiplayer match has started. Usually you will get this event right before getting **OnGameSetStart**. Each match consists of several game sets. You will receive **matchId** as parameter of this callback.
* **OnMatchEnd** callback - is called when multiplayer match has ended. That is when all the sets in the match has been played or timeout occurred. You will receive **matchId** as parameter of this callback

The following diagram may be helpful for understanding about aforementioned events:

![](/files/-MMHglMU0wyrPPD2Fb_z)

To utilize these events you should register in-game player id after the initializing escs service, as described in the basic integration.\
Just to have everything in one place you'll find below once again the description of registering the in-game player id and of the OnGameSetStart event callback.

### Registering in-game player id and metadata:

```csharp
EscsUnityPlugin.RegisterIngamePlayerId(playerId, ingameMetadata);
```

where:&#x20;

* **playerId** - your ingame player id (**string**). It will be passed along with OnGameSetStart callback when the game set will start
* **ingameMetadata** - your ingame metadata for this player (**string**)

### Setting player metadata to use in tournament settings:

```csharp
EscsUnityPlugin.SetPlayerMeta(EscsPlayerParams[] quali, EscsPlayerParams[] generalParams, EscsSetPlayerMetaDelegate handler);
```

where:&#x20;

* **quali** - parameters for qualification
* **generalParams** - general parameters for any tournament setting
* **handler** - callback with results of setting the parameters; true means parameters were set successfully&#x20;

### Register OnGameSetStart event callback

```csharp
EscsUnityPlugin.SetGameSetStartCallback(OnSetStart);
//...
public void OnSetStart(EscsSetStartPayload p) { 
    Debug.Log("set started - players: ");
    foreach(EscsTeam team in p.teams) {
        Debug.Log("team: ");
        foreach(EscsParticipant particip in team.members) {
            Debug.Log(particip.username);
        }
    }
}
```

where **EscsSetStartPayload** contains:&#x20;

* **setId** - setId of started set (**string**)&#x20;
* **tournamentId** - tournamentId of the set (**string**)&#x20;
* **matchId** - matchId of the set (**string**)&#x20;
* **roundId** - roundId of the set (this is in fact id of the set "results") (**string**)&#x20;
* **globalMetadata** - metadata string that can be set in the game dashboard (**string**)&#x20;
* **setEndTimeUnix** - game's set latest end time in unix time (**int**)
* **teams** - array of **EscsTeam** objects. Each **EscsTeam** has array of **EscsParticipant**, which in turn contains:&#x20;

  * **playerId** - escs player id (**string**)&#x20;
  * **ingamePlayerId** - registered in-game player id via registerInGamePlayerId (**string**)&#x20;
  * **username** - user's escs username (**string**)&#x20;
  * **firstName** - user's escs first name (**string**)&#x20;
  * **lastName** - user's escs last name (**string**)&#x20;
  * **avatar** - user's escs avatar image url (**string**)&#x20;
  * **ingameMetadata** - in-game metadata that was registered via **RegisterInGamePlayerId** (**string**)

  Thus, when playing, for example, 2vs2 game mode, you will have 2 **EscsTeam** objects in teams array, each containing 2 **EscsParticipant**. If playing 1vs1, then you will have 2 **EscsTeam** objects each holding just 1 **EscsParticipant**, i.e. 2 teams with 1 player only for each.

### Register OnGameSetEnd event callback

```csharp
EscsUnityPlugin.SetGameSetEndCallback(OnSetEnd);
// ...
public void OnSetEnd(string setId, string matchId) { 
    Dedug.Log("set ended: " + setId + "\n of match: " + matchId);
}
```

where:

* **setId** - setId of finished set (**string**)&#x20;
* **matchId** - matchId of the set (**string**)

### Register OnMatchStart event callback

```csharp
EscsUnityPlugin.SetMatchStartCallback (OnMatchStart);
// ...
public void OnMatchStart(string matchId) { 
    Dedug.Log("match started: " + matchId);
}
```

where:&#x20;

* where **matchId** - is **matchId** of the match that started (**string**)

### Register OnMatchEnd event callback

```csharp
EscsUnityPlugin.SetMatchEndCallback (OnMatchEnd);
// ...
public void OnMatchEnd(string matchId) { 
    Dedug.Log("match ended: " + matchId);
}
```

where:&#x20;

* where **matchId** - is **matchId** of the match that has ended (**string**)

### OAuth integration for fast user registration

1. Create the oAuth app as described here: [Using escs OAuth for sign in](/using-escs-oauth-for-sign-in)
2. Implement the callback to send the access token to escs as described below.&#x20;

#### Supporting user login using the game account (oAuth-like)

You can use our option for user game profile integration and allow your users to log in to our system without requiring them to manually create an escs account. Then the user will see an additional button **"log in using %game\_name% account"** on the main escs screen. In order to support this, first, you need to follow the required steps in the client dashboard and set up the necessary fields as described in the corresponding docs section: [Using escs OAuth for sign in](/using-escs-oauth-for-sign-in). Note that you will also need to create an additional endpoint in your game's backend for the account system for verifying tokens. After this you will only need to implement one callback in your game:&#x20;

```csharp
EscsUnityPlugin.SetGameUserProfilePermissionsCallback((permissions, respond) => {
    Debug.Log("Unity got permissions request with following options:");
    foreach( var x in permissions) Debug.Log( x.ToString());
    //...
    respond(testToken1, acceptedPermissionList);
});
```

where&#x20;

* **`permissions`** - list of requested profile permissions (***string***), for example \["email", "id"]
* **`respond`** - a function that is used to respond to this profile permissions request; you may want to ask the user to accept the requested permissions list in a dialog, or allow them to select only some of them; such dialog, if any, you should create and present to the user by yourself; when the user responded to it, you can use **respond** function to send user's choices to escs:
  * **`testToken1`** - user access token, which will be used by escs backend to obtain profile information from your game's backend (***string***)
  * **`acceptedPermissionList`** - here you supply permissions that the user accepted, if any **(*****list of strings)***, i.e.: `var acceptedPermissionList = new string[] {"grantedPermission1", "grantedPermission2"}` the permission strings should correspond to those that you have received in the **`permissions`** list

### Deeplink integration

Deeplink integration allows you to process ESCS-related deeplinks in your app. Other websites and apps can connect to the ESCS and drive users directly into your game via a deeplink. For the integration and seamless user experience this step is required and is highly recommended.

{% hint style="info" %}
**We highly recommend to implement the deeplink integration!**
{% endhint %}

ESCS will generate deep links using provided url scheme and domain, i.e.:  [gamescheme://some/path/?escsplayer](gamescheme://some/path/?escsplayer=)[=%escs-specific-urlencoded-part%](https://yourgame.com/some/path/?escsplayer=%escs-specific-urlencoded-part%). This also could be your android app link/ios universal link. So when creating a link for tournaments/wagers inside your game, ESCS will just append the "?escsplayer=" parameter to the url you have entered in escs dev console in your app settings.

<figure><img src="/files/INfNoZqBB6rBgw1x5H6u" alt=""><figcaption><p>Deep link setting in ESCS dashboard's Advanced options</p></figcaption></figure>

In the field you should enter something like [gamescheme://some/path](gamescheme://some/path/?escsplayer=) for simple deeplink or <https://yourgame.com/some/path> for app/universal link - where the **some/path** is any path inside your application that you can process. After this setup, you can use&#x20;

```csharp
EscsUnityPlugin.FollowDeepLink(param)
```

method to pass the value of url parameter called "**escsplayer**" ([%escs-specific-urlencoded-part%](https://yourgame.com/some/path?escsplayer=%escs-specific-urlencoded-part%) in the example above). You can provide it in urlencoded format, i.e. raw string that is passed in escsplayer param, escs will decode it correctly. How you extract the parameter value from the url is left to your game's implementation detail, but that should be fairly easy. You can get an example code of extracting the parameter in the SampleScenes/EscsDemoDeeplink.cs in our Unity plugin.

{% hint style="info" %}
Note that you have to manually perform deeplink integration according to Unity platform that you chose as a target. Please refer to Unity docs: <https://docs.unity3d.com/2022.3/Documentation/Manual/deep-linking.html>
{% endhint %}

This will trigger escs service to process that deeplink and automatically show relevant info in our overlay. If the user decides to take action with shown info, your game will receive the data about the match it needs to create using our standard APIs described in previous sections  (i.e. **OnGameSetStart** and other relevant callbacks) and no additional implementation is required

### Performing actions before allowing users to join a tournament

If you wish to perform certain actions when a user wants to join any tournament (i.e. show ads, etc.), you can use the following callback – the plugin will call it when the user presses the ***"I'm in"*** button on the main escs tournament page. To let the user join the tournament, you should call **resolve(true)** method, or **resolve(false)** to deny this possibility.

***NOTE:*** in order for this callback to be activated, you should set up this option in the client dashboard as shown below

```
// Some code
```

When creating a tournament series for your game select the "**Show Ads on "I'm in**" checkbox as shown below to activate additional actions before the user can join a tournament.

<figure><img src="/files/2I5TuG2r0X3Ce6oDtIIt" alt=""><figcaption><p>To activate this option select the "Show Ads on "I'm in" checkbox.</p></figcaption></figure>

### Backend Integration

#### Starting the game

When players click on the "Press Ready" (or "Play") button, escs sends you the event to start the game - OnGameSetStart.

To receive the event on your backend enter the corresponding endpoint in the [client.demo.escs.io](https://client.demo.escs.io/) ([client.escs.io ](https://client.escs.io/) on production) dashboard in the edit game information section. <br>

<figure><img src="/files/8LaK9VvthqWHivOsklmf" alt=""><figcaption></figcaption></figure>

escs sends the event in the following format:

```
{
	"opcode": 7,
	"gameId": "some_game_id",
	"payload": {
		"setId": "some_set_id",
		"matchId": "some_match_id",
		"tournamentId": "some_tournament_id",
		"setEndTimeUnix": 123123123,
		"participants": [
			[
				{
					"playerId": "some_player_id",
					"ingamePlayerId": "some_ingame_player_id",
					"ingameMetadata": "some_ingame_metadata",
					"username": "some_username",
					"firstName": "some_first_name",
					"lastName": "some_last_name",
					"roundId": "some_round_id"
				}
			],
			[
				{
					"playerId": "some_player_id",
					"ingamePlayerId": "some_ingame_player_id",
					"ingameMetadata": "some_ingame_metadata",
					"username": "some_username",
					"firstName": "some_first_name",
					"lastName": "some_last_name",
					"roundId": "some_round_id"
				}
			]
		]
	}
}
```

If you are using your backend to receive this event, then OnGameSetStart callback in the game client will be triggered only after your backend responded with 200.

When the tournament ends, escs send a corresponding event to the same endpoint in the following format:

```
{
  "opcode": 28,
  "gameId": "some_game_id",
  "payload": {
    "pipelineId": "some_pipeline_id",
    "tournamentId": "some_tournament_id"
  }
}
```

If you want to get player's tournament rewards, you should get them after you receive the tournament end event as described here.

#### Ending the game

After the game ends send the results via POST to escs API endpoint <https://api.demo.escs.io/rpc/SetRoundResult> (without "demo" on production).

```
{
  "id": "some_random_string",
  "params": {
      "context": {
            "type": "BY_GAME_SECRET_KEY",
            "gameId": "some_game_id",
            "secretKey": "some_secret_key"
      },
      "roundId": "some_round_id",
      "points": {
            "identifier_1": 123,
            "identifier_2": 456,
            "identifier_3": 789
      }
  }
}
```

#### How to get a list of tournament participants

Just call the following endpoint POST /v2/tournament-participant/get with the following parameters:

```
{
	"filters": {
		"offset": 0,
		"limit": 50,
		"conditions": {
			"tournamentId": {
				"$eq": "some_tournament_id"
			},
			"status": {
				"$eq": "READY_TO_PARTICIPATE"
			}
		}
	}
}			
```

Example of the response:

```
{
	"count": 1,
	"rows": [
		{
			"_id": "some_id",
			"tournamentId": "some_tournament_id",
			"data": {
				"type": "SOLO",
				"playerId": "some_player_id"
			},
			"metadata": {},
			"status": "READY_TO_PARTICIPATE",
			"createdAt": "some_date",
			"updatedAt": "some_date"
		}
	]
}
```

#### How to get the players and their tournament rewards&#x20;

Just call the following endpoint POST /v2/ingame-rewards/get with the following parameters:

```
{
	"context": {
		"type": "BY_GAME_SECRET_KEY",
		"gameId": "some_game_id",
		"secretKey": "some_secret_key"
	},
	"filters": {
		"conditions": {
			"tournamentId": {
				"$eq": "some_tournament_id"
			}
		}
	}
}
```

Example of the response:

```
{
	"count": 1,
	"rows": [
		{
                        "_id": "some_id",
			"playerId": "some_player_id",
			"gameId": "some_game_id",
			"tournamentId": "some_tournament_id",
			"rewardData": "any_string",
			"metadata": {},
                        "createdAt": "some_date",
                        "updatedAt": "some_date"
		}
	]
}
```

#### How to get player's rewards from the tournaments

Just call the following endpoint POST /v2/ingame-rewards/get with the following parameters:

```
{
	"context": {
		"type": "BY_GAME_SECRET_KEY",
		"gameId": "some_game_id",
		"secretKey": "some_secret_key"
	},
	"filters": {
		"conditions": {
			"metadata.ingamePlayerId": {
				"$eq": "some_ingame_player_id"
			}
		}
	}
}
```

Example of the response:

```
{
	"count": 1,
	"rows": [
		{
                        "_id": "some_id",
			"playerId": "some_player_id",
			"gameId": "some_game_id",
			"tournamentId": "some_tournament_id",
			"rewardData": "any_string",
			"metadata": {},
                        "createdAt": "some_date",
                        "updatedAt": "some_date"
		}
	]
}
```


# JS

How to integrate the javascript plugin.

You can use this plugin for all browser-based games.

## Connecting plugin to your project.

To obtain the plugin please connect with us.

If you are using react, then just import these:

```javascript
import { service, ESCSButton, ESCSWebView } from '@escs/react-escs-plugin' 
import '@escs/react-escs-plugin/dist/styles.css'
```

You can use ESCSButton and ESCSWebView as your regular react components in JSX like this:

```jsx
<ESCSWebView></ESCSWebView>
<ESCSButton visible={true}></ESCSButton>
```

Otherwise, if you are using plain vanilla js or any other js framework, you need to use vanilla js imports:

```javascript
import { service, renderReact } from '@escs/react-escs-plugin' 
import '@escs/react-escs-plugin/dist/styles.css'
```

Then in your main js file you need to initialize react render:

```javascript
renderReact('app', callback);
```

and in your callback you can instantiate two ESCS components:

```javascript
window.Loader.load("ESCSButton", {
    visible: true
}, divEscsButton, () => {
    console.log("ESCSButton Loaded");
});

window.Loader.load("ESCSWebView", null, divEscsWebView, () => {
    console.log("ESCSWebView Loaded");
});
```

where firstContainer and secondContainer are your DOM elements, where Escs Button and Escs WebView will be rendered

Also, for your convenience, you can inject service in the global window scope, to be able to access it in all parts of your game:

```javascript
window.escsService = service;
```

## Integrating plugin into your game.

### Initialization

To start using your plugin you need first initialize it:

```javascript
service.invokeManaged({
    public_key: '3dd48bec-2e82-4826-8757-fc14d872882d',
    base_url: 'https://api.demo.escs.io',
    player_base_url: 'https://37b35a72-f8d9-48ca-8cd1-e6690c23637c.player.demo.escs.io',
    analyticsEnv: 'prod'
})
```

where:

* **`public_key`** - a key that you've obtained in the step 1 of the integration guide
* **`base_url`** - url for the core ESCS service. It is <https://api.escs.io> for production environment
* **`player_base_url`** - the URL for the view you created in the [first step of the integration](https://docs.escs.io/integration-step-1), like this one `https://37b35a72-f8d9-48ca-8cd1-e6690c23637c.player.demo.escs.io` (without "demo" on production)
* **`analyticsEnv`**- environment to use for analytics reporting

### Start/End Game

After that you are all set and ready to use ESCS functionality. To start a game's round, just call `startGame()` method:

```javascript
service.startGame()
```

When the round of your game has ended, just call `endGame(score)` with score parameter:

```javascript
service.endGame({ points: 150.0, points_extra: 2.0)})
```

Score is an object, fields names should be defined in game dashboard at [client.escs.io](https://client.escs.io), and the values should be of **double** type.

Probably you would like some additional layer of security sending game results to a server, so you can use encrypted transfer (using symmetric cryptographic key):

```
service.endGameEncrypted(key, score);
```

where **key** - is a function, that returns a string key when called. This key you should obtain in your client dashboard described in [Anti-Cheat services](/anti-cheat-services#encryption) - look up the "front secret key".

We recommend to obfuscate your key and not store it as a value - that is why `endGameEncrypted` is expecting a function, not a value. For example, you can obfuscate string values here: [https://anseki.github.io/gnirts](https://anseki.github.io/gnirts/)

## Optional steps

### Hiding ESCS button

Most of the time you will not want to show the ESCS button during the actual game, to not mess with the gameplay, for example user can accidentally touch it and almost full-screen webview will show up. To hide the button you can use its `visible` property. For React.js this would be:

```jsx
<ESCSButton visible={false}></ESCSButton>
```

And for vanilla js a bit more verbose:

```javascript
        window.Loader.load(
            "ESCSButton",
            { visible: false },
            divEscsButton,
            () => console.log("[ESCSButton Disabled]")
        )
```

### Notifications/Announcements

There are situations, when ESCS needs to show announcements or notifications - for example to promote your game's upcoming championship, or ask user to add credit card, because his/her trial is about to expire. ESCS will open its full WebView automatically to show notification's content, if it's needed. To be able to show these, not interrupting your gameplay and at the times that are not interruptive for user, please call these methods:

```javascript
   service.maybeShowAnnouncements()
   service.maybeShowNotifications()
```

There's internal logic in the plugin to decide whether it needs to show actual notification and announcement, but you should place these calls whenever you feel that interruption with ESCS WebView window is okay for user experience.

***Please note*** that it does **not** mean that user will see notification or announcement **every time** you call these methods. We are trying for those to be as subtle and fluent as possible for end user. Their names imply that notification/announcement just **maybe** will be shown.

### Additional Considerations

You might want to use some custom tracking within ESCS plugin, to bind you user to ESCS's user sessions and see how your championship is going. To use it set your custom tracking params like this:

```javascript
escsService.setTrackingParams({param1: "value1", param2: "value2"})
```

Then these parameters will travel through ESCS analytics with the user session.

There are often situation when you want to respond somehow to the ESCS service state. You can use `getStatus()` method:

```javascript
service.getStatus()
```

which will return object like this:

```javascript
{
    loggedIn, // true / false
    initialized, // true / false
    subscription, //active subscription object
    gameId, //game id sting
    userSessionId, //internal ESCS session string
    gameName, //your game name in ESCS 
    trackingParams //tracking params that you set using setTrackingParams
}
```

### Getting in-game rewards

To receive the list of in-game rewards that particular player has (you can set those rewards as string fields in your game dashboard - for winning matches and so on) you can use the following method:

```javascript
const rewards = await service.getIngameRewards()
console.log("rewards", rewards)

```

which will return object like this:

```javascript
{
    count, // number of rewards, integer
    data: [ //array of reward objects
        {
            _id, // id of the reward, string
            rewardData, // string representation of reward (you set it in dashboard)
            tournamentId //tournament id where it was received by player
        //...
    ]
}
```

## Multiplayer

### Overview

We support multiplayer games with different types of matches, matchmaking and so on. To be able to use this feature, you need to follow these steps:

* Create multiplayer tournament in the game dashboard
* Implement several callbacks in you game, which will be called in response to player's engagement with multiplayer tournament

Currently we provide 4 such callbacks:

* **OnGameSetStart** callback - is called when a game set is started by escs backend. This is moment when you should start your game or create lobby and await for players to join it. What is a "set"? It's just one multiplayer game that several players are playing simultaneously. It can be real multiplayer (e.g. they, for example, race each other on track in a racing game or are participating in a deathmatch 1vs1 or 2vs2 and so on), or even "singleplayer", meaning that they all play their own singleplayer game (like solving puzzles and the one who solves it faster is the winner). In this callback you will receive information about players that are playing this set, teams that players are in (i.e. 2vs2 game), metadata that is supplied with the player (supplied by **registerInGamePlayerId**) and global metadata that is set in the game dashboard
* **OnGameSetEnd** callback - is called when each player in the set has finished their game. this might be not necessary the same moment you end your multiplayer game - it is called when the escs backend processed all game end events from each participating player and saved their corresponding scores. You will receive **matchId** and **setId** as parameters
* **OnMatchStart** callback - is called when multiplayer match has started. Usually you will get this event right before getting **OnGameSetStart**. Each match consists of several game sets. You will receive **matchId** as parameter of this callback.
* **OnMatchEnd** callback - is called when multiplayer match has ended. That is when all the sets in the match has been played or timeout occurred. You will receive **matchId** as parameter of this callback

The following diagram may be helpful for understanding about aforementioned events:

![](/files/-MMHglMU0wyrPPD2Fb_z)

To utilize these events you should call following methods after initializing escs service:

### Registering in-game player id and metadata:

```csharp
service.registerInGamePlayerId("playerId", "ingameMetadata")
```

where:

* **playerId** - your ingame player id (**string**). It will be passed along with OnGameSetStart callback when the game set will start
* **ingameMetadata** - your ingame metadata for this player (**string**)

### Register OnGameSetStart event callback

```javascript
service.registerGameSetStartCallback( payload => {
    console.log("setStartCallback", payload) 
})
```

where **payload** contains fields:

```csharp
{
    setId, //setId of started set (string) 
    tournamentId, //tournamentId of the set (string) 
    matchId, //matchId of the set (string) 
    roundId, //roundId of the set (this is in fact id of the set "results") (string) 
    globalMetadata, //metadata string that can be set in the game dashboard (string) 
    setEndTimeUnix, //game set latest end time in unix time
    participants: 
    [    //array of "team" arrays (so it's array of arrays)
        [        //Each team has array of participants, which in turn contains:
            {
                playerId, //escs player id (string) 
                ingamePlayerId, //registered in-game player id via registerInGamePlayerId (string) 
                username, //user's escs username (string) 
                firstName, //user's escs first name (string) 
                lastName, // user's escs last name (string) 
                avatar, // user's escs avatar image url (string) 
                ingameMetadata // in-game metadata that was registered via RegisterInGamePlayerId (string)
            },
        //... more participants, if any
        ],
    //... more teams, if any
    ]
}
```

*More explanation on **participants** array of arrays:* Each sub-array is considered a "team". So if the game is 2vs2, then you will get array of 2 arrays, each having 2 objects inside. Those 2 arrays are 2 teams with 2 players each. In case of 1vs1 game, you will receive an array of 2 arrays, each having 1 object inside - thus each team contains only one player.

### Register OnGameSetEnd event callback

```csharp
service.registerGameSetEndCallback( async payload => {
    console.log("setEndCallback", payload) 
})
```

where **payload** object contains fields:

```csharp
{
    setId,     // setId of finished set (string) 
    matchId     // matchId of the set (string)
}
```

### Register OnMatchStart event callback

```javascript
service.registerMatchStartCallback( payload => {
    console.log("matchStartCallback", payload) 
})
```

where **payload** object contains fields:

```csharp
{
    matchId // matchId of the match that started (string)
}
```

### Register OnMatchEnd event callback

```csharp
service.registerMatchEndCallback( payload => {
    console.log("matchEndCallback", payload) 
})
```

where **payload** object contains fields:

```csharp
{
    matchId // matchId of the match that has ended (string)
}
```

### Backend Integration

#### Starting the game

When players click on the "Press Ready" (or "Play") button, escs sends you the event to start the game - OnGameSetStart.

To receive the event on your backend enter the corresponding endpoint in the [client.demo.escs.io](https://client.demo.escs.io/) ([client.escs.io ](https://client.escs.io/)on production) dashboard in the edit game information section.<br>

<figure><img src="/files/8LaK9VvthqWHivOsklmf" alt=""><figcaption></figcaption></figure>

escs sends the event in the following format:

```
{
	"opcode": 7,
	"gameId": "some_game_id",
	"payload": {
		"setId": "some_set_id",
		"matchId": "some_match_id",
		"tournamentId": "some_tournament_id",
		"setEndTimeUnix": 123123123,
		"participants": [
			[
				{
					"playerId": "some_player_id",
					"ingamePlayerId": "some_ingame_player_id",
					"ingameMetadata": "some_ingame_metadata",
					"username": "some_username",
					"firstName": "some_first_name",
					"lastName": "some_last_name",
					"roundId": "some_round_id"
				}
			],
			[
				{
					"playerId": "some_player_id",
					"ingamePlayerId": "some_ingame_player_id",
					"ingameMetadata": "some_ingame_metadata",
					"username": "some_username",
					"firstName": "some_first_name",
					"lastName": "some_last_name",
					"roundId": "some_round_id"
				}
			]
		]
	}
}
```

If you are using your backend to receive this event, then OnGameSetStart callback in the game client will be triggered only after your backend responded with 200.

When the tournament ends, escs send a corresponding event to the same endpoint in the following format:

```
{
  "opcode": 28,
  "gameId": "some_game_id",
  "payload": {
    "pipelineId": "some_pipeline_id",
    "tournamentId": "some_tournament_id"
  }
}
```

If you want to get player's tournament rewards, you should get them after you receive the tournament end event as described here.

#### Ending the game

After the game ends send the results via POST to escs API endpoint <https://api.demo.escs.io/rpc/SetRoundResult> (without "demo" on production).

```
{
  "id": "some_random_string",
  "params": {
      "context": {
            "type": "BY_GAME_SECRET_KEY",
            "gameId": "some_game_id",
            "secretKey": "some_secret_key"
      },
      "roundId": "some_round_id",
      "points": {
            "identifier_1": 123,
            "identifier_2": 456,
            "identifier_3": 789
      }
  }
}
```

#### How to get a list of tournament participants

Just call the following endpoint POST /v2/tournament-participant/get with the following parameters:

```
{
	"filters": {
		"offset": 0,
		"limit": 50,
		"conditions": {
			"tournamentId": {
				"$eq": "some_tournament_id"
			},
			"status": {
				"$eq": "READY_TO_PARTICIPATE"
			}
		}
	}
}			
```

Example of the response:

```
{
	"count": 1,
	"rows": [
		{
			"_id": "some_id",
			"tournamentId": "some_tournament_id",
			"data": {
				"type": "SOLO",
				"playerId": "some_player_id"
			},
			"metadata": {},
			"status": "READY_TO_PARTICIPATE",
			"createdAt": "some_date",
			"updatedAt": "some_date"
		}
	]
}
```

#### How to get the players and their tournament rewards

Just call the following endpoint POST /v2/ingame-rewards/get with the following parameters:

```
{
	"context": {
		"type": "BY_GAME_SECRET_KEY",
		"gameId": "some_game_id",
		"secretKey": "some_secret_key"
	},
	"filters": {
		"conditions": {
			"tournamentId": {
				"$eq": "some_tournament_id"
			}
		}
	}
}
```

Example of the response:

```
{
	"count": 1,
	"rows": [
		{
                        "_id": "some_id",
			"playerId": "some_player_id",
			"gameId": "some_game_id",
			"tournamentId": "some_tournament_id",
			"rewardData": "any_string",
			"metadata": {},
                        "createdAt": "some_date",
                        "updatedAt": "some_date"
		}
	]
}
```

#### How to get player's rewards from the tournaments

Just call the following endpoint POST /v2/ingame-rewards/get with the following parameters:

```
{
	"context": {
		"type": "BY_GAME_SECRET_KEY",
		"gameId": "some_game_id",
		"secretKey": "some_secret_key"
	},
	"filters": {
		"conditions": {
			"metadata.ingamePlayerId": {
				"$eq": "some_ingame_player_id"
			}
		}
	}
}
```

Example of the response:

```
{
	"count": 1,
	"rows": [
		{
                        "_id": "some_id",
			"playerId": "some_player_id",
			"gameId": "some_game_id",
			"tournamentId": "some_tournament_id",
			"rewardData": "any_string",
			"metadata": {},
                        "createdAt": "some_date",
                        "updatedAt": "some_date"
		}
	]
}
```

### OAuth integration

1. Create the OAuth app as described here: [Using escs OAuth for sign in](/using-escs-oauth-for-sign-in)
2. Implement the callback to send the access token to escs as described below.

#### Supporting user login using the game account (OAuth-like)

You can use our option for user game profile integration and allow your users to log in to our system without requiring them to manually create an escs account. Then the user will see an additional button **"log in using %game\_name% account"** on the main escs screen. In order to support this, first, you need to follow the required steps in the client dashboard and set up the necessary fields as described in the corresponding docs section: [Using escs OAuth for sign in](/using-escs-oauth-for-sign-in). Note that you will also need to create an additional endpoint in your game's backend for the account system for verifying tokens. After this you will only need to implement one callback in your game:

```javascript
service.setOnRequestGameUserProfilePermissions((options, respond) => {
    console.log("[GAME LOG] onRequestGameUserProfilePermissions", options)
    respond( 
        'yourAccessToken',
        ['profile', 'email'] //or any of the requested options
    )
})
```

where

* **`options`**- list of requested profile permissions (***string***), for example \["email", "id"]
* **`respond`**- a function that is used to respond to this profile permissions request; you may want to ask the user to accept the requested permissions list in a dialog, or allow them to select only some of them; such dialog, if any, you should be created and presented to the user by yourself; when the user responds to it, you can use **respond** function to send user's choices to escs:
  * **`yourAccessToken`** - user access token, which will be used by escs backend to obtain profile information from your game's backend (***string***)
  * **`['profile', 'email']`** - here you supply permissions that the user accepted, if any **(*****array of strings).*** The permission strings should correspond to those that you have received in the **`options`** list

### Deeplink integration

Deeplink integration allows you to process ESCS-related deeplinks in your app. We provide wagers integration, and for them to work this step is required.

In case of web application, the "deeplink" becomes just normal (i.e. http) link to your game, but with additional parameter, i.e.: <https://yourgame.com/some/path/?escsplayer=%escs-specific-urlencoded-part%>. So when creating a link for tournaments/wagers inside your game, ESCS will just append the "?escsplayer=" parameter to the url you have entered in escs dev console in your app settings.

<figure><img src="/files/INfNoZqBB6rBgw1x5H6u" alt=""><figcaption><p>Deep link setting in ESCS dashboard's Advanced options</p></figcaption></figure>

In the field you should enter something like <https://yourgame.com/some/path> - where the path is any path for your web application. After this setup, you can use

```javascript
escsService.followDeeplink( string ) 
```

method to pass the value of url parameter called "**escsplayer**" ([%escs-specific-urlencoded-part%](https://yourgame.com/some/path?escsplayer=%escs-specific-urlencoded-part%) in the example above). How you extract the parameter value from the url is left to your game's implementation detail, but that should be fairly easy. You can provide it in urlencoded format, i.e. raw string that is passed in escsplayer param, escs will decode it correctly. This will trigger escs service to process that deeplink and automatically show relevant info in our overlay. If the user decides to take action with shown info, your game will receive the data about the match it needs to create using our standard APIs described in previous sections (i.e. **OnGameSetStart** and other relevant callbacks) and no additional implementation is required


# React Native

How to integrate the React Native plugin.

You can use this plugin for all React Native games.

## Connecting plugin to your project.

To obtain the plugin please connect with us.

Then just import these:

```javascript
import { service } from "react-native-ecsc-plugin";
import ESCSbutton from "react-native-ecsc-plugin/components/button";
import ESCSWebview from "react-native-ecsc-plugin/components/webView"; 
```

You can use ESCSButton and ESCSWebView as your regular react components in JSX like this:

```jsx
<ESCSWebView></ESCSWebView>
<ESCSButton visible={true}></ESCSButton>
```

## Integrating plugin into your game.

### Initialization

To start using your plugin you need first initialize it:

```javascript
service.invokeManaged({
    public_key: '3dd48bec-2e82-4826-8757-fc14d872882d',
    base_url: 'https://api.demo.escs.io',
    player_base_url: 'https://37b35a72-f8d9-48ca-8cd1-e6690c23637c.player.demo.escs.io',
    analyticsEnv: 'prod'
})
```

where:&#x20;

* **`public_key`** - a key that you've obtained in the step 1 of the integration guide
* **`base_url`** - url for the core ESCS service. It is <https://api.escs.io> for production environment
* **`player_base_url`** -  the URL for the view you created in the [first step of the integration](https://docs.escs.io/integration-step-1), like this one `https://37b35a72-f8d9-48ca-8cd1-e6690c23637c.player.demo.escs.io`  (without "demo" on production)
* **`analyticsEnv`**- environment to use for analytics reporting

### Start/End Game

After that you are all set and ready to use ESCS functionality. To start a game's round, just call `startGame()` method:

```javascript
service.startGame()
```

When the round of your game has ended, just call  `endGame()` with score parameter:

```javascript
service.endGame(score)
```

Probably you would like some additional layer of security sending game results to a server, so you can use encrypted transfer (using symmetric cryptographic key):

```
service.endGameEncrypted(key, avgTime);
```

where **key** - is a function, that returns a string key when called. This key you should obtain in your client dashboard described in [Anti-Cheat services](/anti-cheat-services#encryption) - look up the "front secret key".

We recommend to obfuscate your key and not store it as a value - that is why `endGameEncrypted` is expecting a function, not a value. For example, you can obfuscate string values here: <https://anseki.github.io/gnirts/>

## Optional steps

### Hiding ESCS button

Most of the time you will not want to show the ESCS button during the actual game, to not mess with the gameplay, for example user can accidentally touch it and almost full-screen webview will show up. To hide the button you can use its `visible` property.

```jsx
<ESCSButton visible={false}></ESCSButton>
```

### Notifications/Announcements

There are situations, when ESCS needs to show announcements or notifications - for example to promote your game's upcoming championship, or ask user to add credit card, because his/her trial is about to expire. ESCS will open its full WebView automatically to show notification's content, if it's needed. To be able to show these, not interrupting your gameplay and at the times that are not interruptive for user, please call these methods:

```javascript
   service.maybeShowAnnouncements()
   service.maybeShowNotifications()
```

There's internal logic in the plugin to decide whether it needs to show actual notification and announcement, but you should place these calls whenever you feel that interruption with ESCS WebView window is okay for user experience.&#x20;

***Please note*** that it does **not** mean that user will see notification or announcement **every time** you call these methods. We are trying for those to be as subtle and fluent as possible for end user. Their names imply that notification/announcement just **maybe** will be shown.

### Additional Considerations

There are often situation when you want to respond somehow to the ESCS service state. You can use `getStatus()` method:

```javascript
service.getStatus()
```

which will return object like this:

```javascript
{
    loggedIn, // true / false
    initialized, // true / false
    subscription, //active subscription object
}
```

### Logging out

Sometimes you want to log out the user out of the ESCS programmatically, for example when the user logs out of the game. You can use the following call for this:

```
service.sendEvent("requestUserLogout", "true")
```


# Android native

How to integrate the android native plugin.

You can use this plugin for all android games.

## Connecting plugin to your project.

To obtain the plugin please connect with us.

## Integrating plugin into your game.

It is very easy to integrate ESCS plugin into your game code

First you need to initialize your plugin.&#x20;

### Initialization

To start using your plugin you need first initialize it:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
        EscsService.initialize(
            EscsServiceConfig(
                public_key,        // String
                base_url,          // String
                player_base_url    // String 
            ), 
            applicationContext,    // Context,
            invokeCallback         // (status: EscsInitResult, 
                                   //     gameId: String, 
                                   //         tournamentId: String) -> Unit
        ) -> Unit
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.initialize(
    new EscsServiceConfig(
        public_key, //String
        base_url, //String
        player_base_url //String
    ), 
    getApplicationContext(),
    (status, gameId, tournamentId) -> {
                        //... process result
                        return Unit.INSTANCE;
                    }
);
```

{% endtab %}
{% endtabs %}

where:&#x20;

* **`public_key`**- a key that you've obtained in the step 1 of the integration guide, like `"fee91a27-2b87-45f8-8ca4-0b317707806q"`
* **`base_url`** - url for the core ESCS service. It is <https://api.escs.io> for production environment and [https://api.demo.escs.io](https://api.demo.escs.io/) for the demo environment.
* **`player_base_url`** - the URL for the view you created in the [first step of the integration](https://docs.escs.io/integration-step-1), like this one `https://37b35a72-f8d9-48ca-8cd1-e6690c23637c.player.demo.escs.io`  (without "demo" on production)
* **`invokeCallback`**- callback when init is completed; you can omit it.&#x20;

Callback lambda parameters are following:

* `status`  - enum **EscsInitResult** which can be&#x20;

  ```
  SUCCESS,
  FAILURE,
  NOT_INITIALIZED,
  NETWORK_ERROR
  ```
* `gameId` - gameId string of configured game or empty string
* `tournamentId` - tournamentId string of current active tournament or empty string

{% hint style="info" %}
**Note** that callback is telling you that plugin initialization is successful, but it does not mean that any supported function of ESCS will be performed right away. Some things (mainly deep link and events system) need to hook up later and until then plugin will queue your calls until everything is set up. Normally you don't need to worry about it, as this takes only a couple of seconds, but in rare cases you might want to indicate this in your UI. For this purposes take a look at [ESCS ready callback](#getting-escs-ready-callback).
{% endhint %}

Then you need to attach UI components into your activity (the button and the webview):

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val viewGroup =
    window.decorView.findViewById(android.R.id.content) as ViewGroup

val btn = EscsButton(layoutInflater, viewGroup, applicationContext)
btn.attach()

val wv = EscsWebView(layoutInflater, viewGroup, applicationContext)
wv.attach()
```

{% endtab %}

{% tab title="Java" %}

```java
ViewGroup viewGroup = getWindow()
                        .getDecorView()
                        .findViewById(android.R.id.content);

EscsWebView escsWebView = new EscsWebView(getLayoutInflater(), 
                        viewGroup, 
                        getApplicationContext());
            
escsWebView.attach();

EscsButton escsButton = new EscsButton(getLayoutInflater(), 
                        viewGroup, 
                        getApplicationContext());
escsButton.attach();
```

{% endtab %}
{% endtabs %}

Don't forget to clean up on destroying your activity:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
override fun onDestroy() {
    btn.detach()
    wv.detach()
    EscsService.finish()
    super.onDestroy()
}
```

{% endtab %}

{% tab title="Java" %}

```java
escsWebView.detach();
escsButton.detach();
EscsService.INSTANCE.finish();
```

{% endtab %}
{% endtabs %}

### Start/End Game

After that you are all set and ready to use ESCS functionality. To start a game's round, just call `startGame()` method:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.startGame { 
  // process start round callback
  Log.i("MyGame", it?.toString() ?: "no round received")
} 

```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.startGame(round -> {
    Log.i("MyGame", round != null ? round.toString() : "no round received");
    return Unit.INSTANCE;
});
```

{% endtab %}
{% endtabs %}

where&#x20;

* **round** - class instance with following fields:
* `_id`  - roundId of just started game round
* `tournamentId`- tournamentId of active tournament for which the round was created for
* `status`- round status. "active" for just created round
* `playerId`- escs playerId

When the round of your game has ended, just call  `endGame()` with score parameter:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.endGame( Score(
      mapOf("points" to (count ?: 0.0), "points_extra" to (count1 ?: 0.0))
     )
 ) { //Score takes map as parameter
    Log.i("MyGame", it?.toString() ?: "no round received")
}
```

{% endtab %}

{% tab title="Java" %}

```java

Map<String, Double> scoreMap = new HashMap<>();
scoreMap.put("score", 149.0);
scoreMap.put("score_extra", 3.0);

EscsService.INSTANCE.endGame(new Score(scoreMap), round -> { 
    Log.i("MyGame", round != null ? round.toString() : "no round received");
    return Unit.INSTANCE;
});
```

{% endtab %}
{% endtabs %}

where&#x20;

* **`score`** - game score parameter - accepts a map of string key and double value; the names of keys should be defined in game dashboard at [client.escs.io](https://client.escs.io)
* **`round`** - class instance with following fields:
* `_id`  - roundId of just ended game round
* `tournamentId`- tournamentId of active tournament for which the round was ended&#x20;
* `status`- round status. "ended" for just ended round
* `playerId`- escs playerId

## Optional steps

### Sending Game Progress

If you want send game score as your player progresses through game, for example in case gameplay is abruptly stopped or you want to see score progression graphs when players are streaming their gameplay, just call  `progressGame()` with score parameter:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.progressGame( Score(
      mapOf("points" to (count ?: 0.0), "points_extra" to (count1 ?: 0.0))
     )
 ) { //Score takes map as parameter
    Log.i("MyGame", it?.roundId?.toString() ?: "no progress received")
}
```

{% endtab %}

{% tab title="Java" %}

```java

Map<String, Double> scoreMap = new HashMap<>();
scoreMap.put("score", 149.0);
scoreMap.put("score_extra", 3.0);

EscsService.INSTANCE.endGame(new Score(scoreMap), roundProgress -> { 
    Log.i("MyGame", roundProgress != null ? round._id.toString() : "no progress received");
    return Unit.INSTANCE;
});
```

{% endtab %}
{% endtabs %}

where&#x20;

* **`score`** - game score parameter - accepts a map of string key and double value; the names of keys should be defined in game dashboard at [client.escs.io](https://client.escs.io)
* **`roundProgress`** - class instance with following fields:
* `_id`  - id of just sent progress object
* `roundId`-  roundId of just progressed game round

### ESCS ready callback

When you get the callback from [initialize](#initialization), this means that plugin is ready to work and can show UI. But this does not mean that you can already use every ESCS feature, as some components require more time to hook up. Most of the time you don't need to worry about it, but in some cases it is not what you want (e.g. your game loads from deep link and you want to show tournament/wager inside ESCS, so you might want to disable your game UI until ESCS is able to show full info). To remedy this problem, we provide additional callback:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerEscsReadyCallback {
    Log.d("ESCS", "escs is ready!")
}
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerEscsReadyCallback ( () -> {
            Log.d("ESCS", "escs is ready!")
        });
```

{% endtab %}
{% endtabs %}

Receiving this callback means that ESCS is fully ready to receive and perform any supported actions.

### Hiding ESCS button

Most of the time you will not want to show the ESCS button during the actual game, to not mess with the gameplay, for example user can accidentally touch it and almost full-screen webview will show up. To hide or show button you can use following methods:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
escsButton.setVisible(View.GONE)
escsButton.setVisible(View.VISIBLE)
```

{% endtab %}

{% tab title="Java" %}

```java
escsButton.setVisible(View.GONE);
escsButton.setVisible(View.VISIBLE);
```

{% endtab %}
{% endtabs %}

### Opening ESCS view programmatically

Sometimes you might prefer to implement you own customized button for opening Escs in style of your game and with full control of its position. For such cases you can hide Escs button altogether (like shown above) and open Escs with your own button using following method:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.openEscsView()
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.openEscsView();
```

{% endtab %}
{% endtabs %}

### Notifications/Announcements

There are situations, when ESCS needs to show announcements or notifications - for example to promote your game's upcoming championship, or ask user to add credit card, because his/her trial is about to expire. ESCS will open its full WebView automatically to show notification's content, if it's needed. To be able to show these, not interrupting your gameplay and at the times that are not interruptive for user, please call these methods:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.maybeShowNotifications()
EscsService.maybeShowAnnouncements()
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.maybeShowNotifications();
EscsService.INSTANCE.maybeShowAnnouncements();
```

{% endtab %}
{% endtabs %}

There's internal logic in the plugin to decide whether it needs to show actual notification and announcement, but you should place these calls whenever you feel that interruption with ESCS WebView window is okay for user experience.&#x20;

***Please note*** that it does **not** mean that user will see notification or announcement **every time** you call these methods. We are trying for those to be as subtle and fluent as possible for end user. Their names imply that notification/announcement just **maybe** will be shown.

### Changing default button position

There are situations when it is not suitable for your UI to have our ESCS button at  default top center area. Then you can change that (remember, that user actually can drag the button anywhere on the screen he wants)

`setDefaultPositionAbsolute()` will set button position in absolute coordinates from left upper corner of the app.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
btn.setDefaultPositionAbsolute(50f, //x
                                50f) //y
```

{% endtab %}

{% tab title="Java" %}

```java
escsButton.setDefaultPositionAbsolute(50f,  //x
                                      50f); //y
```

{% endtab %}
{% endtabs %}

where

* x - x coordinate
* y - y coordinate

`setDefaultPositionRelative()` will set button position in relative coordinates from center horizontally and top vertically of the app. That is, if you set **0, 0** coordinates the button will be shown in the **x: (device width)/2  y: 0.**&#x20;

The coordinate system here is from **-0.5 to 0.5** for `xPart` : where **-0.5** means most left side of device and **0.5** - right side and **0** is dead center. For `yPart` it is from **0 to 1** where **0** is top of the screen and **1** is the bottom.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
btn.setDefaultPositionRelative(0.5f, //xPart
                               0.5f) //yPart
```

{% endtab %}

{% tab title="Java" %}

```java
escsButton.setDefaultPositionRelative(0.5f,  //xPart
                                      0.5f); //yPart
```

{% endtab %}
{% endtabs %}

### Getting in-game rewards

To receive the list of in-game rewards that particular player has (you can set those rewards as string fields in your game dashboard - for winning matches and so on) you can use the following method:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.getInGameRewards {
    Log.i("ESCS", "rewards: ${it.data.foldIndexed("") { index, acc, rewardPayload -> "${acc}\n ${index.toString()} ${rewardPayload?.rewardData}" }}");
}
```

where argument in the lambda is object of type **InGameRewards**:&#x20;

* **`count`** - amount of rewards player has (***integer***)
* **`data`** - list of **RewardPayload** objects:
  * **`_id`** - id of reward (***string***)
  * **`rewardData`** - ***string*** representation of rewards (which you set in the dashboard)
  * **`tournamentId`** - id of tournament it was received by player (***string***)
    {% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.getInGameRewards(rewards -> {
            Log.i("ESCS", "rewards " + (rewards != null ? rewards.toString() : " no rewards received"));
        });
```

where argument in the lambda is object of type **InGameRewards:**

* **`getCount()`** - amount of rewards player has (***integer***)
* **`getData()`** - list of **RewardPayload** objects:
  * **`get_id()`** - id of reward (***string***)
  * **`getRewardData()`** - ***string*** representation of rewards (which you set in the dashboard)
  * **`getTournamentId()`** - id of tournament it was received by player (***string***)
    {% endtab %}
    {% endtabs %}

### Supporting user login using the game account (OAuth-like)

You can use our option for user game profile integration and allow your users to log in to our system without requiring them to manually create an escs account. Then the user will see an additional button **"log in using %game\_name% account"** on the main escs screen. In order to support this, first, you need to follow the required steps in the client dashboard and set up the necessary fields as described in the corresponding docs section: [Using escs OAuth for sign in](/using-escs-oauth-for-sign-in). Note that you will also need to create an additional endpoint in your game's backend for the account system for verifying tokens. After this you will only need to implement one callback in your game:&#x20;

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerGameUserProfilePermissionsCallback { list, respond ->
    Log.i("ESCS", "requested profile permissions: ${list.toString()}")

    //...
    respond(token, acceptedPermissionList)
    //...
}
```

where&#x20;

* **`list`** - list of requested profile permissions (***string***), for example \["email", "id"]
* **`respond`** - a function that is used to respond to this profile permissions request; you may want to ask the user to accept the requested permissions list in a dialog, or allow them to select only some of them; such dialog, if any, you should create and present to the user by yourself; when the user responded to it, you can use **respond** function to send user's choices to escs:
  * **`token`** - user access token, which will be used by escs backend to obtain profile information from your game's backend (***string***)
  * **`acceptedPermissionList`** - here you supply permissions that the user accepted, if any **(*****list of strings)***&#x20;
    {% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerGameUserProfilePermissionsCallback((list, respond) -> {
    Log.i("ESCS", "requested profile permissions: " + String.join(", ", list));
    
    //...
    respond.invoke(token, acceptedPermissionList);
    //...
    
    return Unit.INSTANCE;
});
```

where&#x20;

* **`list`** - list of requested profile permissions (***string***), for example \["email", "id"]
* **`respond`** - a function that is used to respond to this profile permissions request; you may want to ask the user to accept requested permissions list in a dialog, or allow to select only some of them; such dialog, if any, you should create and present to user by yourself; when the user responded to it, you can use **respond** function to send user's choices to escs:
  * **`token`** - user access token, which will be used by escs backend to obtain profile information from your game's backend (***string***)
  * **`acceptedPermissionList`** - here you supply permissions that user accepted, if any (***list of strings)***&#x20;
    {% endtab %}
    {% endtabs %}

### Performing actions before allowing users to join a tournament

If you wish to perform certain actions when a user wants to join any tournament (i.e. show ads, etc.), you can use the following callback – the plugin will call it when the user presses the ***"I'm in"*** button on the main escs tournament page. To let the user join the tournament, you should call **resolve(true)** method, or **resolve(false)** to deny this possibility.

***NOTE:*** in order for this callback to be activated, you should set up this option in the client dashboard as shown below

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerPlayerRequestJoinTournamentCallback { resolve ->
    Log.i("ESCS", "player wants to join tournament")
    //... perform showing ads or any other action
    //... you may store resolve function for later use outside the callback
    resolve(true) // allow the user to join the tournament
}
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerPlayerRequestJoinTournamentCallback ( (resolve) -> {
    Log.i("ESCS", "player wants to join tournament");
    //... perform showing ads or any other action
    //... you may store resolve function for later use outside the callback
    resolve.invoke(true); // allow the user to join the tournament
    return Unit.INSTANCE;
});
```

{% endtab %}
{% endtabs %}

When creating a tournament series for your game select the "Show Ads on "I'm in" checkbox as shown below to activate additional actions before the user can join a tournament.

![To activate this option select the "Show Ads on "I'm in" checkbox.](/files/DNqp1S5GFe5ircgf2TSB)

### Handling configuration changes (rotation)

If your app is recreating activity on config changes, then you don't need to do anything. If you are handling configuration changes by yourself, then you also have to pass config changes events to escs plugin. Here's how to do it:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    escsButton.onConfigurationChanged(newConfig)
    escsWebView.onConfigurationChanged(newConfig)
}
```

{% endtab %}

{% tab title="Java" %}

```java
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    escsButton.onConfigurationChanged(newConfig);
    escsWebView.onConfigurationChanged(newConfig);
}
```

{% endtab %}
{% endtabs %}

### Video chat/streaming integration

In order for your app to support escs' video chat and streaming capabilities you need to call back the plugin in some key lifecycle areas of your app. This is required so that plugin can receive audio and camera permission's result and also request screen recoding for streaming.  If your app also overrides these methods, just add call the escs methods before your own processing.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String>, grantResults: IntArray
) {
    EscsService.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    data?.let {
        EscsService.onActivityResult(requestCode, resultCode, data)
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    EscsService.INSTANCE.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

public static void onActivityResult(int requestCode, int resultCode, Intent data) {
    EscsService.INSTANCE.onActivityResult(requestCode, resultCode, data);
}
```

{% endtab %}
{% endtabs %}

Also, for our video chat and streaming to be able to use fullscreen functionality, you need to add following attributes to the activity that will host Escs UI elements in **AndroidManifest.xml**:

<pre class="language-xml"><code class="lang-xml"><strong>&#x3C;activity android:name=".YourActivityName" android:configChanges="orientation|screenSize" />
</strong></code></pre>

#### Supporting streaming with API level 29+

With API 29 and higher Android became more strict with permissions and background services. If your app targets **compileSdkVersion 29** and/or **targetSdkVersion 29** or higher you need to add the following to your **AndroidManifest.xml** inside **Application** node:

```markup
<service
    android:name="androidx.work.impl.foreground.SystemForegroundService"
    android:foregroundServiceType="mediaProjection"
    tools:node="replace" />
```

This directive will register a foreground service for streaming integration. Note that otherwise the app will crash when user gives permission for screen recoding. If your app targets API less than 29, then you don't need anything.

### Deeplink integration

Deeplink integration allows you to process ESCS-related deeplinks in your app. We provide wagers integration, and for them to work this step is required.

ESCS will generate deep links using provided url scheme and domain, i.e.:  [gamescheme://some/path/?escsplayer](gamescheme://some/path/?escsplayer=)[=%escs-specific-urlencoded-part%](https://yourgame.com/some/path/?escsplayer=%escs-specific-urlencoded-part%). This also could be your android app link. So when creating a link for tournaments/wagers inside your game, ESCS will just append the "?escsplayer=" parameter to the url you have entered in escs dev console in your app settings.

<figure><img src="/files/INfNoZqBB6rBgw1x5H6u" alt=""><figcaption><p>Deep link setting in ESCS dashboard's Advanced options</p></figcaption></figure>

In the field you should enter something like [gamescheme://some/path](gamescheme://some/path/?escsplayer=) for simple deeplink or <https://yourgame.com/some/path> for app link - where the **some/path** is any path inside your application that you can process. After this setup, you can use&#x20;

```kotlin
EscsService.followDeepLink(param)
```

method to pass the value of url parameter called "**escsplayer**" ([%escs-specific-urlencoded-part%](https://yourgame.com/some/path?escsplayer=%escs-specific-urlencoded-part%) in the example above). You can provide it in urlencoded format, i.e. raw string that is passed in escsplayer param, escs will decode it correctly. How you extract the parameter value from the url is left to your game's implementation detail, but that should be fairly easy.

{% hint style="info" %}
Note that still have to manually implement the adnroid's deeplink/app link handling. Please refer to docs: <https://developer.android.com/training/app-links/deep-linking>
{% endhint %}

This will trigger escs service to process that deeplink and automatically show relevant info in our overlay. If the user decides to take action with shown info, your game will receive the data about the match it needs to create using our standard APIs described in previous sections  (i.e. **OnGameSetStart** and other relevant callbacks) and no additional implementation is required.

## Multiplayer

### Overview

We support multiplayer games with different types of matches, matchmaking and so on. To be able to use this feature, you need to follow these steps:&#x20;

* Create multiplayer tournament in the game dashboard
* Implement several callbacks in you game, which will be called in response to player's engagement with multiplayer tournament

Currently we provide 4 such callbacks:

* **OnGameSetStart** callback - is called when a game set is started by escs backend. This is moment when you should start your game or create lobby and await for players to join it. What is a "set"? It's just one multiplayer game that several players are playing simultaneously. It can be real multiplayer (e.g. they, for example, race each other on track in a racing game or are participating in a deathmatch 1vs1 or 2vs2 and so on), or even "singleplayer", meaning that they all play their own singleplayer game (like solving puzzles and the one who solves it faster is the winner). In this callback you will receive information about players that are playing this set, teams that players are in (i.e. 2vs2 game), metadata that is supplied with the player (supplied by **registerInGamePlayerId**) and global metadata that is set in the game dashboard
* **OnGameSetEnd** callback - is called when each player in the set has finished their game. this might be not necessary the same moment you end your multiplayer game - it is called when the escs backend processed all game end events from each participating player and saved their corresponding scores. You will receive **matchId** and **setId** as parameters
* **OnMatchStart** callback - is called when multiplayer match has started. Usually you will get this event right before getting **OnGameSetStart**. Each match consists of several game sets. You will receive **matchId** as parameter of this callback.
* **OnMatchEnd** callback - is called when multiplayer match has ended. That is when all the sets in the match has been played or timeout occurred. You will receive **matchId** as parameter of this callback

The following diagram may be helpful for understanding about aforementioned events:

![](/files/-MMHglMU0wyrPPD2Fb_z)

To utilize these events you can call methods described below.

### Registering in-game player id and metadata:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerInGamePlayerId(playerId, playerMetadata)
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerInGamePlayerId(playerId, ingameMetadata);
```

{% endtab %}
{% endtabs %}

where:&#x20;

* **playerId** - your ingame player id (**string**). It will be passed along with **OnGameSetStart** callback when the game set will start
* **ingameMetadata** - your ingame metadata for this player (**string**)

### Minimal multiplayer setup

In order to create minimal trivial multiplayer setup, you will just need to register [OnGameSetStart ](/plugins/android-native#register-ongamesetstart-event-callback)event. Starting a game in response to this event and it's parameters is enough to use multiplayer features of escs.

### Register OnGameSetStart event callback

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerGameSetStartCallback { data ->
    Log.i("ESCS", "Set started: ${data.setId}, round: ${data.roundId}, players: ${data.participants[0][0].username} ${data.participants[1][0].username}")
}
```

where **data** is **GameSetStartData** object:

* **setId** - setId of started set (**string**)
* **tournamentId** - tournamentId of the set (**string**)
* **matchId** - matchId of the set (**string**)
* **roundId** - roundId of the set (this is in fact id of the set "results") (**string**)
* **globalMetadata** - metadata string that can be set in the game dashboard (**string**)
* **setEndTimeUnix** - game's set max end time in unix time
* **pariticipants** - list of lists of **Participant.** *Each sub-list is considered a "team". So if the game is 2vs2, then you will get list of 2 lists, each having 2 objects inside. Those 2 lists are 2 lists with 2 players each. In case of 1vs1 game, you will receive a list of 2 lists, each having 1 object inside - thus the team contains only one player.* **Participant** object consists of:
  * **playerId** - escs player id (**string**)
  * **ingamePlayerId** - registered in-game player id via **registerInGamePlayerId** (**string**)
  * **username** - user's escs username (**string**)
  * **firstName** - user's escs first name (**string**)
  * **lastName** - user's escs last name (**string**)
  * **avatar** - user's escs avatar image url (**string**)
  * **ingameMetadata** - in-game metadata that was registered via registerInGamePlayerId (**string**)
    {% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerGameSetStartCallback(gameSetStartData -> {
    Log.i("ESCS", "gameSetStartData " + (gameSetStartData != null ? gameSetStartData.toString() : " no gameSetStartData received"));
    return Unit.INSTANCE;
});
```

where **data** is **GameSetStartData** object:

* **getSetId()** - setId of started set (**string**)
* **getTournamentId()** - tournamentId of the set (**string**)
* **getMatchId()** - matchId of the set (**string**)
* **getRoundId()** - roundId of the set (this is in fact id of the set "results") (**string**)
* **getGlobalMetadata()** - metadata string that can be set in the game dashboard (**string**)
* **getSetEndTimeUnix()** - game's set max end time in unix time (**long**)
* **getPariticipants()** - list of lists of **Participant.** *Each sub-list is considered a "team". So if the game is 2vs2, then you will get list of 2 lists, each having 2 objects inside. Those 2 lists are 2 lists with 2 players each. In case of 1vs1 game, you will receive a list of 2 lists, each having 1 object inside - thus the team contains only one player.* **Participant** object consists of:
  * **getPlayerId()** - escs player id (**string**)
  * **getIngamePlayerId()** - registered in-game player id via **registerInGamePlayerId** (**string**)
  * **getUsername()** - user's escs username (**string**)
  * **getFirstName()** - user's escs first name (**string**)
  * **getLastName()** - user's escs last name (**string**)
  * **getAvatar()** - user's escs avatar image url (**string**)
  * **getIngameMetadata()** - in-game metadata that was registered via registerInGamePlayerId (**string**)
    {% endtab %}
    {% endtabs %}

### Register OnGameSetEnd event callback

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerGameSetEndCallback {
    Log.i("ESCS", "Set ended: ${it.setId} of match ${it.matchId}" )
}
```

where argument of lambda is **GameSetEndData** object:&#x20;

* **setId** - setId of finished set (**string**)
* **matchId** - matchId of the set (**string**)
  {% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerGameSetEndCallback(gameSetEndData -> {
  Log.i("ESCS", "gameSetEndData " + (gameSetEndData != null ? gameSetEndData.toString() : " no gameSetEndData received"));
  return Unit.INSTANCE;
});
```

where argument of lambda is **GameSetEndData** object:&#x20;

* **getSetId()** - setId of finished set (**string**)
* **getMatchId()** - matchId of the set (**string**)
  {% endtab %}
  {% endtabs %}

### Register OnMatchStart event callback

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerMatchStartCallback {
    Log.i("ESCS", "Match started: ${it.matchId}" )
}
```

where argument of lambda is **GameMatchStartData** object:

* **matchId** - is **matchId** of the match that started (**string**)
  {% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerMatchStartCallback(matchStartData -> {
    Log.i("ESCS", "matchStartData " + (matchStartData != null ? matchStartData.toString() : " no matchStartData received"));
    return Unit.INSTANCE;
});
```

where argument of lambda is **GameMatchStartData** object:

* **getMatchId()** - is **matchId** of the match that started (**string**)
  {% endtab %}
  {% endtabs %}

### Register OnMatchEnd event callback

{% tabs %}
{% tab title="Kotlin" %}

```objectivec
EscsService.registerMatchEndCallback {
    Log.i("ESCS", "Match ended: ${it.matchId}" )
}
```

where argument of lambda is **GameMatchStartData** object:

* **matchId** - is **matchId** of the match that just ended(**string**)
  {% endtab %}

{% tab title="Java" %}

```objectivec
EscsService.INSTANCE.registerMatchEndCallback(matchEndData -> {
    Log.i("ESCS", "matchEndData " + (matchEndData != null ? matchEndData.toString() : " no matchEndData received"));
    return Unit.INSTANCE;
});
```

where argument of lambda is **GameMatchStartData** object:

* **getMatchId()** - is **matchId** of the match that just ended(**string**)
  {% endtab %}
  {% endtabs %}


# Basic multiplayer with OAuth

### Initialization

To start using your plugin you need first initialize it:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
        EscsService.invokeManaged(
            EscsServiceConfig(
                public_key,        // String
                base_url,          // String
                player_base_url    // String 
            ), 
            applicationContext,    // Context,
            invokeCallback         // (status: String, 
                                   //     gameId: String, 
                                   //         tournamentId: String) -> Unit
        ) -> Unit
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.invokeManaged(
    new EscsServiceConfig(
        public_key, //String
        base_url, //String
        player_base_url //String
    ), 
    getApplicationContext(),
    (status, gameId, tournamentId) -> {
                        //... process result
                        return Unit.INSTANCE;
                    }
);
```

{% endtab %}
{% endtabs %}

Then you need to attach UI components into your activity (the button and the webview):

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val viewGroup =
    window.decorView.findViewById(android.R.id.content) as ViewGroup

val btn = EscsButton(layoutInflater, viewGroup, applicationContext)
btn.attach()

val wv = EscsWebView(layoutInflater, viewGroup, applicationContext)
wv.attach()
```

{% endtab %}

{% tab title="Java" %}

```java
ViewGroup viewGroup = getWindow()
                        .getDecorView()
                        .findViewById(android.R.id.content);

EscsWebView escsWebView = new EscsWebView(getLayoutInflater(), 
                        viewGroup, 
                        getApplicationContext());
            
escsWebView.attach();

EscsButton escsButton = new EscsButton(getLayoutInflater(), 
                        viewGroup, 
                        getApplicationContext());
escsButton.attach();
```

{% endtab %}
{% endtabs %}

### Registering in-game player id and metadata:

So that we can tell you for which players you have to start the game:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerInGamePlayerId(playerId, playerMetadata)
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerInGamePlayerId(playerId, ingameMetadata);
```

{% endtab %}
{% endtabs %}

### Forcefully open escs view

You can use this to open escs main view programmatically, not requiring the user to tap the button

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.openEscsView()
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.openEscsView();
```

{% endtab %}
{% endtabs %}

### Starting the game

When players click on the "Press Ready" button, escs sends you the event to start the game.\
escs can send it to your game client and to your backend.\
\
To receive the event in the game client register OnGameSetStart event callback

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerGameSetStartCallback { data ->
    Log.i("ESCS", "Set started: ${data.setId}, round: ${data.roundId}, players: ${data.participants[0][0].username} ${data.participants[1][0].username}")
}
```

where **data** is **GameSetStartData** object:

* **setId** - setId of started set (**string**)
* **tournamentId** - tournamentId of the set (**string**)
* **matchId** - matchId of the set (**string**)
* **roundId** - roundId of the set (this is in fact id of the set "results") (**string**)
* **globalMetadata** - metadata string that can be set in the game dashboard (**string**)
* **setEndTimeUnix** - game's set max end time in unix time
* **pariticipants** - list of lists of **Participant.** *Each sub-list is considered a "team". So if the game is 2vs2, then you will get list of 2 lists, each having 2 objects inside. Those 2 lists are 2 lists with 2 players each. In case of 1vs1 game, you will receive a list of 2 lists, each having 1 object inside - thus the team contains only one player.* **Participant** object consists of:
  * **playerId** - escs player id (**string**)
  * **ingamePlayerId** - registered in-game player id via **registerInGamePlayerId** (**string**)
  * **username** - user's escs username (**string**)
  * **firstName** - user's escs first name (**string**)
  * **lastName** - user's escs last name (**string**)
  * **avatar** - user's escs avatar image url (**string**)
  * **ingameMetadata** - in-game metadata that was registered via registerInGamePlayerId (**string**)
    {% endtab %}
    {% endtabs %}

To receive the event on your backend enter the corresponding endpoint in the client.escs.io dashboard in the edit game information section. <br>

![](/files/hiCynH11I1dA4x9mq9ly)

escs sends the event in the following format:

```
{
	"opcode": 7,
	"gameId": "some_game_id",
	"payload": {
		"setId": "some_set_id",
		"matchId": "some_match_id",
		"tournamentId": "some_tournament_id",
		"setEndTimeUnix": 123123123,
		"participants": [
			[
				{
					"playerId": "some_player_id",
					"ingamePlayerId": "some_ingame_player_id",
					"ingameMetadata": "some_ingame_metadata",
					"username": "some_username",
					"firstName": "some_first_name",
					"lastName": "some_last_name",
					"roundId": "some_round_id"
				}
			],
			[
				{
					"playerId": "some_player_id",
					"ingamePlayerId": "some_ingame_player_id",
					"ingameMetadata": "some_ingame_metadata",
					"username": "some_username",
					"firstName": "some_first_name",
					"lastName": "some_last_name",
					"roundId": "some_round_id"
				}
			]
		]
	}
}
```

If you are using your backend to receive this event, then OnGameSetStart callback in the game client will be triggered only after your backend responded with 200.

When the tournament ends escs send a corresponding event to the same endpoint in the following format:

```
{
  "opcode": 28,
  "gameId": "some_game_id",
  "payload": {
    "pipelineId": "some_pipeline_id",
    "tournamentId": "some_tournament_id"
  }
}
```

If you want to get player's tournament rewards, you should get them after you receive the tournament end event as described here&#x20;

### Ending the game

After the game ends send the results via POST to escs API endpoint <https://api.escs.io/rpc/SetRoundResult> (<https://api.demo.escs.io/rpc/SetRoundResult> on demo environment)

```
{
  "id": "some_random_string",
  "params": {
      "context": {
            "type": "BY_GAME_SECRET_KEY",
            "gameId": "some_game_id",
            "secretKey": "some_secret_key"
      },
      "roundId": "some_round_id",
      "points": {
            "identifier_1": 123,
            "identifier_2": 456,
            "identifier_3": 789
      }
  }
}
```

### Clean Up

Don't forget to clean up on destroying your activity:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
override fun onDestroy() {
    btn.detach()
    wv.detach()
    EscsService.finish()
    super.onDestroy()
}
```

{% endtab %}

{% tab title="Java" %}

```java
escsWebView.detach();
escsButton.detach();
EscsService.INSTANCE.finish();
```

{% endtab %}
{% endtabs %}

### Performing actions before allowing users to join a tournament

If you wish to perform certain actions when a user wants to join any tournament (i.e. show ads, etc.), you can use the following callback – the plugin will call it when the user presses the ***"I'm in"*** button on the main escs tournament page. To let the user join the tournament, you should call **resolve(true)** method, or **resolve(false)** to deny this possibility.

***NOTE:*** in order for this callback to be activated, you should set up this option in the client dashboard as shown below

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerPlayerRequestJoinTournamentCallback { resolve ->
    Log.i("ESCS", "player wants to join tournament")
    //... perform showing ads or any other action
    //... you may store resolve function for later use outside the callback
    resolve(true) // allow the user to join the tournament
}
```

{% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerPlayerRequestJoinTournamentCallback ( (resolve) -> {
    Log.i("ESCS", "player wants to join tournament");
    //... perform showing ads or any other action
    //... you may store resolve function for later use outside the callback
    resolve.invoke(true); // allow the user to join the tournament
    return Unit.INSTANCE;
});
```

{% endtab %}
{% endtabs %}

When creating a tournament series for your game select the "Show Ads on "I'm in" checkbox as shown below to activate additional actions before the user can join a tournament.

![To activate this option select the "Show Ads on "I'm in" checkbox.](/files/DNqp1S5GFe5ircgf2TSB)

### Video chat/streaming integration

In order for your app to support escs' video chat and streaming capabilities you need to call back the plugin in some key lifecycle areas of your app. This is required so that plugin can receive audio and camera permission's result and also request screen recoding for streaming.  If your app also overrides these methods, just add call the escs methods before your own processing.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String>, grantResults: IntArray
) {
    EscsService.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    data?.let {
        EscsService.onActivityResult(requestCode, resultCode, data)
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    EscsService.INSTANCE.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

public static void onActivityResult(int requestCode, int resultCode, Intent data) {
    EscsService.INSTANCE.onActivityResult(requestCode, resultCode, data);
}
```

{% endtab %}
{% endtabs %}

***NOTE***: You will also need to add microphone, audio and camera permissions to your AndroidManifest.xml, for example:

```
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

<uses-feature
    android:name="android.hardware.camera"
    android:required="true" />
<uses-feature
    android:name="android.hardware.microphone"
    android:required="true" />
```

#### Supporting streaming with API level 29+

With API 29 and higher Android became more strict with permissions and background services. If your app targets **compileSdkVersion 29** and/or **targetSdkVersion 29** or higher you need to add the following to your **AndroidManifest.xml** inside **Application** node:

```markup
<service
    android:name="androidx.work.impl.foreground.SystemForegroundService"
    android:foregroundServiceType="mediaProjection"
    tools:node="replace" />
```

This directive will register a foreground service for streaming integration. Note that otherwise the app will crash when user gives permission for screen recoding. If your app targets API less than 29, then you don't need anything.

### OAuth integration for fast user registration

1. Create the oAuth app as described here: [Using escs OAuth for sign in](/using-escs-oauth-for-sign-in)
2. Implement the callback to send the access token to escs as described below.&#x20;

#### Supporting user login using the game account (oAuth-like)

You can use our option for user game profile integration and allow your users to log in to our system without requiring them to manually create an escs account. Then the user will see an additional button **"log in using %game\_name% account"** on the main escs screen. In order to support this, first, you need to follow the required steps in the client dashboard and set up the necessary fields as described in the corresponding docs section: [Using escs OAuth for sign in](/using-escs-oauth-for-sign-in). Note that you will also need to create an additional endpoint in your game's backend for the account system for verifying tokens. After this you will only need to implement one callback in your game:&#x20;

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
EscsService.registerGameUserProfilePermissionsCallback { list, respond ->
    Log.i("ESCS", "requested profile permissions: ${list.toString()}")

    //...
    respond(token, acceptedPermissionList)
    //...
}
```

where&#x20;

* **`list`** - list of requested profile permissions (***string***), for example \["email", "id"]
* **`respond`** - a function that is used to respond to this profile permissions request; you may want to ask the user to accept the requested permissions list in a dialog, or allow them to select only some of them; such dialog, if any, you should create and present to the user by yourself; when the user responded to it, you can use **respond** function to send user's choices to escs:
  * **`token`** - user access token, which will be used by escs backend to obtain profile information from your game's backend (***string***)
  * **`acceptedPermissionList`** - here you supply permissions that the user accepted, if any **(*****list of strings)***
    {% endtab %}

{% tab title="Java" %}

```java
EscsService.INSTANCE.registerGameUserProfilePermissionsCallback((list, respond) -> {
    Log.i("ESCS", "requested profile permissions: " + String.join(", ", list));
    
    //...
    respond.invoke(token, acceptedPermissionList);
    //...
    
    return Unit.INSTANCE;
});
```

where&#x20;

* **`list`** - list of requested profile permissions (***string***), for example \["email", "id"]
* **`respond`** - a function that is used to respond to this profile permissions request; you may want to ask the user to accept requested permissions list in a dialog, or allow to select only some of them; such dialog, if any, you should create and present to user by yourself; when the user responded to it, you can use **respond** function to send user's choices to escs:
  * **`token`** - user access token, which will be used by escs backend to obtain profile information from your game's backend (***string***)
  * **`acceptedPermissionList`** - here you supply permissions that user accepted, if any (***list of strings)***&#x20;
    {% endtab %}
    {% endtabs %}

### How to get a list of tournament participants

Just call the following endpoint POST /v2/tournament-participant/get with the following parameters:

```
{
	"filters": {
		"offset": 0,
		"limit": 50,
		"conditions": {
			"tournamentId": {
				"$eq": "some_tournament_id"
			},
			"status": {
				"$eq": "READY_TO_PARTICIPATE"
			}
		}
	}
}			
```

Example of the response:

```
{
	"count": 1,
	"rows": [
		{
			"_id": "some_id",
			"tournamentId": "some_tournament_id",
			"data": {
				"type": "SOLO",
				"playerId": "some_player_id"
			},
			"metadata": {},
			"status": "READY_TO_PARTICIPATE",
			"createdAt": "some_date",
			"updatedAt": "some_date"
		}
	]
}
```

### How to get the players and their tournament rewards&#x20;

Just call the following endpoint POST /v2/ingame-rewards/get with the following parameters:

```
{
	"context": {
		"type": "BY_GAME_SECRET_KEY",
		"gameId": "some_game_id",
		"secretKey": "some_secret_key"
	},
	"filters": {
		"conditions": {
			"tournamentId": {
				"$eq": "some_tournament_id"
			}
		}
	}
}
```

Example of the response:

```
{
	"count": 1,
	"rows": [
		{
                        "_id": "some_id",
			"playerId": "some_player_id",
			"gameId": "some_game_id",
			"tournamentId": "some_tournament_id",
			"rewardData": "any_string",
			"metadata": {},
                        "createdAt": "some_date",
                        "updatedAt": "some_date"
		}
	]
}
```

### How to get player's rewards from the tournaments

Just call the following endpoint POST /v2/ingame-rewards/get with the following parameters:

```
{
	"context": {
		"type": "BY_GAME_SECRET_KEY",
		"gameId": "some_game_id",
		"secretKey": "some_secret_key"
	},
	"filters": {
		"conditions": {
			"metadata.ingamePlayerId": {
				"$eq": "some_ingame_player_id"
			}
		}
	}
}
```

Example of the response:

```
{
	"count": 1,
	"rows": [
		{
                        "_id": "some_id",
			"playerId": "some_player_id",
			"gameId": "some_game_id",
			"tournamentId": "some_tournament_id",
			"rewardData": "any_string",
			"metadata": {},
                        "createdAt": "some_date",
                        "updatedAt": "some_date"
		}
	]
}
```


# iOS native

How to integrate the iOS native plugin.

You can use this plugin for all ios games.

## Connecting plugin to your project manually

To obtain the plugin please connect with us.

Link it manually to your project. To do that, go to your Target's `General` tab in Xcode and under section "`Frameworks, Libraries and Embedded Content`" press `+`, then locate downloaded framework and add it. Don't forget to choose "embed & sign". Also, you will need to load and link manually <https://github.com/SDWebImage/SDWebImageWebPCoder> and it's dependencies too, because we use it internally. Once you finish, that's it!

## Connecting plugin to your project using CocoaPods (recommended)

Add escs pod in Podfile

and then run `pod update`

And that's it! Now you are ready to use it

## Removing unused targets

Because provided framework is a "fat framework" you may run into issues when uploading to Appstore because apple rejects simulator architectures in binaries. To remedy this issue, you need to add script action which will remove it upon build.

Under “Build Phases” select “Add Run Script” and copy the contents of below script

```bash
echo "Target architectures: $ARCHS"

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
echo $(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")

FRAMEWORK_TMP_PATH="$FRAMEWORK_EXECUTABLE_PATH-tmp"

# remove simulator's archs if location is not simulator's directory
case "${TARGET_BUILD_DIR}" in
*"iphonesimulator")
    echo "No need to remove archs"
    ;;
*)
    if $(lipo "$FRAMEWORK_EXECUTABLE_PATH" -verify_arch "i386") ; then
    lipo -output "$FRAMEWORK_TMP_PATH" -remove "i386" "$FRAMEWORK_EXECUTABLE_PATH"
    echo "i386 architecture removed"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_TMP_PATH" "$FRAMEWORK_EXECUTABLE_PATH"
    fi
    if $(lipo "$FRAMEWORK_EXECUTABLE_PATH" -verify_arch "x86_64") ; then
    lipo -output "$FRAMEWORK_TMP_PATH" -remove "x86_64" "$FRAMEWORK_EXECUTABLE_PATH"
    echo "x86_64 architecture removed"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_TMP_PATH" "$FRAMEWORK_EXECUTABLE_PATH"
    fi
    ;;
esac

echo "Completed for executable $FRAMEWORK_EXECUTABLE_PATH"
echo $(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")

done
```

## Integrating plugin into your game.

It is very easy to integrate ESCS plugin into your game code

First you need to initialize your plugin.&#x20;

### Initialization

To start using your plugin you need first initialize it:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
#import <EscsIosPluginFramework/EscsIosPluginFramework-Swift.h>

EscsService* service;
service = [[EscsService alloc] init];

EscsServiceConfigObjC* config = [[EscsServiceConfigObjC alloc] init];
config.publicKey = @"public_key";
config.playerBaseUrl = @"player_base_url";
config.baseUrl = @"base_url";
config.autoReconnect = true/false;
    
UIViewController* serviceController = [service initializeWithConfig:config 
callback:^(BOOL status, NSString * _Nonnull gameId, NSString * _Nonnull tournamentId) {
    NSLog(@"%@", gameId);
}];
```

{% endtab %}

{% tab title="Swift" %}

```swift
import EscsIosPluginFramework

let service = EscsService()
let config = EscsServiceConfig(publicKey: "public_key", 
    baseUrl: "base_url",
    playerBaseUrl: "player_base_url",
    autoReconnect: true/false) //default: true

let controller = service.initialize(
    config) { 
        status, gameid, tournamentid in
            print(status)
        }
```

{% endtab %}
{% endtabs %}

where:&#x20;

* **`public_key`**- a key that you've obtained in the step 1 of the integration guide, like `"fee91a27-2b87-45f8-8ca4-0b317707806q"`
* **`base_url`** - url for the core ESCS service. It is <https://api.escs.io> for production environment and [https://api.demo.escs.io](https://api.demo.escs.io/) for demo environment.
* **`player_base_url`** - the URL for the view you created in the [first step of the integration](https://docs.escs.io/integration-step-1), like this one `https://37b35a72-f8d9-48ca-8cd1-e6690c23637c.player.demo.escs.io`  (without "demo" on production)
* **`autoReconnect` -** tells plugin whether you want to wait for network connection to become available if it isn't, or return with failed initialization immediately; default is **true** - i.e. plugin will try to initialize until network is available
* **`callback`** - callback when init is completed; you can omit it.&#x20;

Callback parameters are following:

* `status`  - boolean: true for successfully initialized escs or false otherwise
* `gameId` - gameId string of configured game or empty string
* `tournamentId` - tournamentId string of current active tournament or empty string

After this you need to attach this ViewController to your view hierarchy:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[[self view] addSubview: serviceController.view];
[self addChildViewController: serviceController];
[serviceController didMoveToParentViewController: self];
```

{% endtab %}

{% tab title="Swift" %}

```swift
view.addSubview(controller.view)
addChild(controller)
controller.didMove(toParent: self)
```

{% endtab %}
{% endtabs %}

### Start/End Game

After that you are all set and ready to use ESCS functionality. To start a game's round, just call `startGameWithCallback`:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
 [service startGameWithCallback:^(NSString * _Nonnull roundId, NSString * _Nonnull tournamentId, NSString * _Nonnull status, NSString * _Nonnull playerId) {
     NSLog(@"%@", roundId);
 }];

```

{% endtab %}

{% tab title="Swift" %}

```swift
service.startGame { roundId, tournamentId, status, playerId in
    print(roundId)
}
```

{% endtab %}
{% endtabs %}

where&#x20;

* `roundId`  - roundId of just started game round
* `tournamentId`- tournamentId of active tournament for which the round was created for
* `status`- round status. "active" for just created round
* `playerId`- escs playerId

When the round of your game has ended, just call  `endGameWithScore` with score parameter:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
NSDictionary<NSString *, NSNumber *> *result = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithDouble:[input.text doubleValue]], @"points1", nil];

[service endGameWithScore: result callback:^(NSString * _Nonnull roundId, NSString * _Nonnull tournamendId, NSString * _Nonnull status, NSString * _Nonnull playerId) {
    NSLog(@"ended round: %@ playerId: %@ status:%@", roundId, playerId, status);
}];
```

{% endtab %}

{% tab title="Swift" %}

```swift
//score takes double as parameter
service.endGame(score: ["points1": 150.0]) { roundId, tournamentId, status, playerId in
    print(roundId)
}
```

{% endtab %}
{% endtabs %}

where&#x20;

* **`result`** - game score parameter - game score parameter - accepts a dictionary of string key and double value; the names of keys should be defined in game dashboard at [client.escs.io](https://client.escs.io)

and callback:

* `roundId`  - roundId of just ended game round
* `tournamentId`- tournamentId of active tournament for which the round was ended&#x20;
* `status`- round status. "ended" for just ended round
* `playerId`- escs playerId

## Optional steps

### ESCS ready callback

When you get the callback from [initialize](#initialization), this means that plugin is ready to work and can show UI. But this does not mean that you can already use every ESCS feature, as some components require more time to hook up. Most of the time you don't need to worry about it, but in some cases it is not what you want (e.g. your game loads from deep link and you want to show tournament/wager inside ESCS, so you might want to disable your game UI until ESCS is able to show full info). To remedy this problem, we provide additional callback:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnEscsReadyCallbackWithCallback:^(BOOL ready) {
        NSLog(@"escs is ready!");
    }];
```

{% endtab %}

{% tab title="Swift" %}

```kotlin
service?.registerOnEscsReadyCallback { s in //s: boolean
            print("escs is ready!: ", s)
        }
```

{% endtab %}
{% endtabs %}

Receiving this callback means that ESCS is fully ready to receive and perform any supported actions.

### Hiding ESCS button

### Sending Game Progress

If you want send game score as your player progresses through game, for example in case gameplay is abruptly stopped or you want to see score progression graphs when players are streaming their gameplay, just call  `progressGame()` with score parameter:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
NSDictionary<NSString *, NSNumber *> *result = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithDouble:[input.text doubleValue]], @"points1", nil];

[service progressGameWithScore: progress callback:^(NSString * _Nonnull roundId, NSString * _Nonnull progressId) {
    NSLog(@"progressed round: %@ progressId: %@", roundId, progressId);
}];
```

{% endtab %}

{% tab title="Swift" %}

```swift
//progressId score takes double as parameter
service.progressGame(score: ["points1": 150.0]) { roundId, progressId in
    print(roundId)
}
```

{% endtab %}
{% endtabs %}

where&#x20;

* **`progress`**- game score parameter - game score parameter - accepts a dictionary of string key and double value; the names of keys should be defined in game dashboard at [client.escs.io](https://client.escs.io)

and callback:

* `progressId` - id of just sent progress object
* `roundId`-  roundId of just progressed game round

### Hiding ESCS button

Most of the time you will not want to show the ESCS button during the actual game, to not mess with the gameplay, for example user can accidentally touch it and almost full-screen webview will show up. To hide or show button you can use following call:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service setButtonVisibilityWithVisible: visible ];  //visible: BOOL
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.setButtonVisibility(visible: false) //or true
```

{% endtab %}
{% endtabs %}

### Opening ESCS view programmatically

Sometimes you might prefer to implement you own customized button for opening Escs in style of your game and with full control of its position. For such cases you can hide Escs button altogether (like shown above) and open Escs with your own button using following method:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service openEscsView]; 
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.openEscsView()
```

{% endtab %}
{% endtabs %}

### Notifications/Announcements

There are situations, when ESCS needs to show announcements or notifications - for example to promote your game's upcoming championship, or ask user to add credit card, because his/her trial is about to expire. ESCS will open its full WebView automatically to show notification's content, if it's needed. To be able to show these, not interrupting your gameplay and at the times that are not interruptive for user, please call:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service maybeShowNotifications];
[service maybeShowAnnouncemens];
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.maybeShowAnnouncemens()
service.maybeShowNotifications()
```

{% endtab %}
{% endtabs %}

There's internal logic in the plugin to decide whether it needs to show actual notification and announcement, but you should place these calls whenever you feel that interruption with ESCS WebView window is okay for user experience.&#x20;

***Please note*** that it does **not** mean that user will see notification or announcement **every time** you call these methods. We are trying for those to be as subtle and fluent as possible for end user. Their names imply that notification/announcement just **maybe** will be shown.

### Changing default button position

There are situations when it is not suitable for your UI to have our ESCS button at  default top center area. Then you can change that (remember, that user actually can drag the button anywhere on the screen he wants)

`setButtonDefaultPositionAbsoluteWithX` will set button position in absolute coordinates from left upper corner of the app.

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service setButtonDefaultPositionAbsoluteWithX:x y:y];
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.setButtonDefaultPositionAbsolute(x: 50.0, y: 50.0)
```

{% endtab %}
{% endtabs %}

where

* x - x coordinate (float)
* y - y coordinate (float)

`setButtonDefaultPositionRelativeWithXPart`will set button position in relative coordinates from center horizontally and top vertically of the app. That is, if you set **0, 0** coordinates the button will be shown in the **x: (device width)/2  y: 0.**&#x20;

The coordinate system here is from **-0.5 to 0.5** for `xPart` : where **-0.5** means most left side of device and **0.5** - right side and **0** is dead center. For `yPart` it is from **0 to 1** where **0** is top of the screen and **1** is the bottom.

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service setButtonDefaultPositionRelativeWithXPart:xPart yPart:yPart]; 
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.setButtonDefaultPositionRelative(xPart: 0.5, yPart: 0.5)
```

{% endtab %}
{% endtabs %}

### Getting in-game rewards

To receive the list of in-game rewards that particular player has (you can set those rewards as string fields in your game dashboard - for winning matches and so on) you can use the following method:

{% tabs %}
{% tab title="Objective-C" %}

```bash
[service getIngameRewardsObjCWithCallback:^(NSInteger count, NSArray<RewardPayloadObjC *> * _Nonnull rewards) {
    //...your callback code here
}];
```

where:&#x20;

* **count** - amount of rewards player has (***integer***)
* **rewards** - array of **RewardPayloadObjC** objects:
  * **\_id** - id of reward (***string***)
  * **rewardData** - ***string*** representation of rewards (which you set in the dashboard)
  * **tournamentId** - id of tournamnt it was received by player (***string***)
    {% endtab %}

{% tab title="Swift" %}

```
service.getIngameRewards(callback: { rewards in
    print(rewards)
})
```

where:

* **rewards** - **InGameRewards** struct, which has fields:
  * **count** - amount of rewards player has (***Int***)
  * **data** - array of **RewardPayload**s, which consists of:
    * **\_id** - id of reward (***String***)
    * **rewardData** - representation of rewards (which you set in the dashboard) (***string***)
    * **tournamentId** - id of tournamnt it was received by player (***String***)
      {% endtab %}
      {% endtabs %}

### Supporting video chat and streaming

In order to support escs video chat and streaming capabilities, you need to add two keys to I**nfo.plist** of your app, for user's prompts when requesting camera and mic recording:

![](/files/-MjF9OYrYDRE_2DWD_e0)

## Deeplink integration

Deeplink integration allows you to process ESCS-related deeplinks in your app. We provide wagers integration, and for them to work this step is required.

ESCS will generate deep links using provided url scheme and domain, i.e.:  [gamescheme://some/path/?escsplayer](gamescheme://some/path/?escsplayer=)[=%escs-specific-urlencoded-part%](https://yourgame.com/some/path/?escsplayer=%escs-specific-urlencoded-part%). This also could be your ios universal link. So when creating a link for tournaments/wagers inside your game, ESCS will just append the "?escsplayer=" parameter to the url you have entered in escs dev console in your app settings.

<figure><img src="/files/INfNoZqBB6rBgw1x5H6u" alt=""><figcaption><p>Deep link setting in ESCS dashboard's Advanced options</p></figcaption></figure>

In the field you should enter something like [gamescheme://some/path](gamescheme://some/path/?escsplayer=) for simple deeplink or <https://yourgame.com/some/path> for universal link - where the **some/path** is any path inside your application that you can process. After this setup, you can use&#x20;

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service followDeepLinkWithLink:param];
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.followDeepLink(link:param)
```

{% endtab %}
{% endtabs %}

method to pass the value of url parameter called "**escsplayer**" ([%escs-specific-urlencoded-part%](https://yourgame.com/some/path?escsplayer=%escs-specific-urlencoded-part%) in the example above). You can provide it in urlencoded format, i.e. raw string that is passed in escsplayer param, escs will decode it correctly. How you extract the parameter value from the url is left to your game's implementation detail, but that should be fairly easy.

{% hint style="info" %}
Note that still have to manually implement the iOS deeplink/universal link handling. Please refer to docs: <https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app>
{% endhint %}

This will trigger escs service to process that deeplink and automatically show relevant info in our overlay. If the user decides to take action with shown info, your game will receive the data about the match it needs to create using our standard APIs described in previous sections  (i.e. **OnGameSetStart** and other relevant callbacks) and no additional implementation is required

## Multiplayer

### Overview

We support multiplayer games with different types of matches, matchmaking and so on. To be able to use this feature, you need to follow these steps:&#x20;

* Create multiplayer tournament in the game dashboard
* Implement several callbacks in you game, which will be called in response to player's engagement with multiplayer tournament

Currently we provide 4 such callbacks:

* **OnGameSetStart** callback - is called when a game set is started by escs backend. This is moment when you should start your game or create lobby and await for players to join it. What is a "set"? It's just one multiplayer game that several players are playing simultaneously. It can be real multiplayer (e.g. they, for example, race each other on track in a racing game or are participating in a deathmatch 1vs1 or 2vs2 and so on), or even "singleplayer", meaning that they all play their own singleplayer game (like solving puzzles and the one who solves it faster is the winner). In this callback you will receive information about players that are playing this set, teams that players are in (i.e. 2vs2 game), metadata that is supplied with the player (supplied by **registerInGamePlayerId**) and global metadata that is set in the game dashboard
* **OnGameSetEnd** callback - is called when each player in the set has finished their game. this might be not necessary the same moment you end your multiplayer game - it is called when the escs backend processed all game end events from each participating player and saved their corresponding scores. You will receive **matchId** and **setId** as parameters
* **OnMatchStart** callback - is called when multiplayer match has started. Usually you will get this event right before getting **OnGameSetStart**. Each match consists of several game sets. You will receive **matchId** as parameter of this callback.
* **OnMatchEnd** callback - is called when multiplayer match has ended. That is when all the sets in the match has been played or timeout occurred. You will receive **matchId** as parameter of this callback

The following diagram may be helpful for understanding about aforementioned events:

![](/files/-MMHglMU0wyrPPD2Fb_z)

To utilize these events you should call following methods after initializing escs service:

### Registering in-game player id and metadata:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerInGamePlayerIdWithId:playerId ingameMetadata:ingameMetadata];
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.registerInGamePlayerId(id: playerId,ingameMetadata: ingameMetadata)
```

{% endtab %}
{% endtabs %}

where:&#x20;

* **playerId** - your ingame player id (**string**). It will be passed along with OnGameSetStart callback when the game set will start
* **ingameMetadata** - your ingame metadata for this player (**string**)

### Register OnGameSetStart event callback

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnGameSetStartCallbackObjCWithCallback:
                    ^(NSString * _Nonnull setId, 
                    NSString * _Nonnull tournamentId, 
                    NSString * _Nonnull matchId, 
                    NSString * _Nonnull roundId, 
                    NSString * _Nonnull globalMetadata, 
                    NSArray<NSArray<ParticipantObjC *> *> * _Nonnull participants
                    NSInteger setEndTimeUnix) { 
              //... your callback code here
 }];
```

where:

* **setId** - setId of started set (**string**)
* **tournamentId** - tournamentId of the set (**string**)
* **matchId** - matchId of the set (**string**)
* **roundId** - roundId of the set (this is in fact id of the set "results") (**string**)
* **globalMetadata** - metadata string that can be set in the game dashboard (**string**)
* **pariticipants** - array of arrays of **ParticipantObjC.** *Each sub-array is considered a "team". So if the game is 2vs2, then you will get array of 2 arrays, each having 2 objects inside. Those 2 arrays are 2 teams with 2 players each. In case of 1vs1 game, you will receive an array of 2 arrays, each having 1 object inside - thus the team contains only one player.* **ParticipantObjC** object consists of:
  * **playerId** - escs player id (**string**)
  * **ingamePlayerId** - registered in-game player id via **registerInGamePlayerId** (**string**)
  * **username** - user's escs username (**string**)
  * **firstName** - user's escs first name (**string**)
  * **lastName** - user's escs last name (**string**)
  * **avatar** - user's escs avatar image url (**string**)
  * **ingameMetadata** - in-game metadata that was registered via registerInGamePlayerId (**string**)
* **setEndTimeUnix** - latest end time of the set in unix time (**NSInteger**)
  {% endtab %}

{% tab title="Swift" %}

```swift
service.registerOnGameSetStartCallback(callback: { payload in
            print(payload)
})
```

where:&#x20;

* **payload** - **OnGameSetStartPayload** struct which contains:
  * **setId** - setId of started set (**string**)

  * **tournamentId** - tournamentId of the set (**string**)

  * **matchId** - matchId of the set (**string**)

  * **roundId** - roundId of the set (this is in fact id of the set "results") (**string**)

  * **globalMetadata** - metadata string that can be set in the game dashboard (**string**)

  * **pariticipants** - array of arrays of **Participant** structs( i.e. `[[Participant]?]?`)

    *Each sub-array is considered a "team". So if the game is 2vs2, then you will get array of 2 arrays, each having 2 objects inside (i.e.* `[ [ participant1, participant2] , [participant3, participant4] ]`*). Those 2 arrays are 2 teams with 2 players each. In case of 1vs1 game, you will receive an array of 2 arrays, each having 1 object inside (i.e.* `[ [ participant1] , [participant2] ]`*- thus the team contains only one player.*

    &#x20;Each **Participant** struct consists of:

    * **playerId** - escs player id (**string**)
    * **ingamePlayerId** - registered in-game player id via **registerInGamePlayerId** (**string**)
    * **username** - user's escs username (**string**)
    * **firstName** - user's escs first name (**string**)
    * **lastName** - user's escs last name (**string**)
    * **avatar** - user's escs avatar image url (**string**)
    * **ingameMetadata** - in-game metadata that was registered via registerInGamePlayerId (**string**)

  * **setEndTimeUnix** - latest end time of the set in unix time (**int**)
    {% endtab %}
    {% endtabs %}

### Register OnGameSetEnd event callback

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnGameSetEndCallbackObjCWithCallback:
^(NSString * _Nonnull setId, 
NSString * _Nonnull matchId) {
    // ... your callback code here
    }]; 
```

where:&#x20;

* **setId** - setId of finished set (**string**)
* **matchId** - matchId of the set (**string**)
  {% endtab %}

{% tab title="Swift" %}

```swift
service.registerOnGameSetEndCallback { payload in
    print(payload)           
}
```

where **payload** is **OnGameSetEndPayload** struct containing follwing fields:

* **setId** - setId of finished set (**string**)
* **matchId** - matchId of the set (**string**)
  {% endtab %}
  {% endtabs %}

### Register OnMatchStart event callback

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnGameMatchStartCallbackObjCWithCallback:
                                ^(NSString * _Nonnull matchId) {
        // ... your callback code here
    }];
```

where **matchId** - is **matchId** of the match that started (**string**)
{% endtab %}

{% tab title="Swift" %}

```
service.registerOnGameMatchStartCallback { payload in
        print(payload)
}
```

where **payload** is **OnMatchStartPayload** struct, containing just one field - **matchId** of the match that started (**string**)
{% endtab %}
{% endtabs %}

### Register OnMatchEnd event callback

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnGameMatchEndCallbackObjCWithCallback:
                ^(NSString * _Nonnull matchId) {
    // ... your callback code here
}]; 
```

where **matchId** - is **matchId** of the match that ended (**string**)
{% endtab %}

{% tab title="Swift" %}

```swift
service.registerOnGameMatchEndCallback { payload in
        print(payload)
}
```

where **payload** is **OnMatchEndPayload** struct, containing just one field - **matchId** of the match that ended (**string**)
{% endtab %}
{% endtabs %}


# JS WatchThis

WatchThis is a subset of escs services to provide easy drop-in social features for your app, like videochat, event sync between participants and so on.

## Connecting plugin to your project.

To obtain the plugin please connect with us.

Then you can import it in your js project's package.json dependency section:

```
"@escs/react-escs-plugin": "https://username@bitbucket.org/repo_name"
```

If you are using react, then just import these:

```javascript
import { service, ESCSButton, ESCSWebView } from '@escs/react-escs-plugin' 
import '@escs/react-escs-plugin/dist/styles.css'
```

You can use ESCSButton and ESCSWebView as your regular react components in JSX like this:

```jsx
<ESCSWebView></ESCSWebView>
<ESCSButton visible={true}></ESCSButton>
```

Otherwise, if you are using plain vanilla js or any other js framework, you need to use vanilla js imports:

```javascript
import { service, renderReact } from '@escs/react-escs-plugin' 
import '@escs/react-escs-plugin/dist/styles.css'
```

Then in your main js file you need to initialize react render:&#x20;

```javascript
renderReact('app', callback);
```

Where 'app' is the id of the root DOM element.

and in your callback you can instantiate two ESCS WatchThis components:

```javascript
window.Loader.load("ESCSButton", {
    visible: true
}, divEscsButton, () => {
    console.log("ESCSButton Loaded");
});

window.Loader.load("ESCSWebView", null, divEscsWebView, () => {
    console.log("ESCSWebView Loaded");
});
```

where **divEscsButton** and **divEscsWebView** are your DOM elements, where Escs Button and Escs WebView will be rendered

Also, for your convenience, you can inject service in the global window scope, to be able to access it in all parts of your game:

```javascript
window.escsService = service;
```

After this all you need is to initialize the plugin to get WatchThis overlay in your app.

### Initialization

To start using your plugin you need first initialize it:

```javascript
service.invokeManaged({
    public_key: 'XXXX-XXXX',
    base_url: 'https://example1.com',
    player_base_url: 'https://example2.com',
    analyticsEnv: 'prod'
})
```

where:&#x20;

* **`public_key`** - a key that you've obtained from us
* **`base_url`** - url for the core ESCS service. You can obtain it from us
* **`player_base_url`** - url for the player's ESCS service. You can obtain it from us
* **`analyticsEnv`**- environment to use for analytics reporting

## Sending shared events for party participants

It's very easy to send shared stream of events between party participants. All the events send from any of the participant's app instance will be broadcasted to everyone in the party:

```javascript
service.sendEvent(eventName, eventParams);
```

where **eventName** is string and **eventParams** is an object containing params for that event.

To subscribe to an event stream coming from each participant you can use this method:

```javascript
service.addEventListener(eventName, params => {
    console.log("[event log]:", eventName, params)			    
 });
```

where again **eventName** is the name of the event you want to listen for and **params** are params send along with it. Thus using these two methods you can easily sync any state between all the participants in your party.


# Pragma.gg

### Prepare your environment.

1. Merge our branch into your pragma.gg repository. Our custom services are located in 5-ext folder.
2. The only change to existing pragma codebase is changing visibility modifier in AccountDao to access necessary info about users in our custom services.

### Working with custom services

1. The main classes to work with are **AuthCodeService** and **ExternalMatchmakingService**.
2. **AuthCodeService** provides OAuth-like functionality for pragma - it issues one-time codes for user profile data and allows third-party services to access profile information on behalf of user (via one-time codes). This service is used to integrate Pragma account system and Escs account system together. You will need to set up Escs OAuth application as described [here](/using-escs-oauth-for-sign-in). In this scenario Pragma is going to act as "provider" for Escs accounts system. &#x20;
3. **ExternalMatchmakingService** provides means for Pragma players to enter a match that is created by Escs platform. High level process of match creation will be described later.
4. Custom services provided by escs are used to communicate both with escs platform and with pragma itself (e.g. internal services)
5. For our matchmaking to work you also have to use escs' **matchmaking plugin, party plugin and match end plugin/dependent job**. These pieces all work together and if you omit one of them, other will not work too.

### Configuration

1. To configure these services you need additional entries in your pragma yaml config. Here is an example:

```yaml
social:
  serviceConfigs:
    AccountDaoConfig:
      databaseConfig:
        driver: "MYSQLDB"
        hostPortSchema:
          "localhost:3306/local_social_account"
        username: "superuser"
        password: "password"
    AuthCodeServiceConfig:
      authCodeTTL: 300
      authCodeApplicationId: "applicationId"
      authCodeApplicationSecret: "applicationSecret"
      maxCacheSize: 1000
      dbCleanInterval: 10
    AuthCodeDaoConfig:
      databaseConfig:
        driver: "MYSQLDB"
        hostPortSchema:
          "localhost:3306/local_social_account"
        username: "superuser"
        password: "password"
```

&#x20;**AccountDaoConfig** - please enter your datasource parameters for account store. This should be the same as for default pragma services.

**AuthCodeServiceConfig** - specific values for AuthCodeService.

* **authCodeTTL** - amount of seconds for access code to be valid
* **authCodeApplicationId** - app id provided by escs platform [here ](/using-escs-oauth-for-sign-in)
* **authCodeApplicationSecret** - secret provided by escs platform [here ](/using-escs-oauth-for-sign-in)
* **maxCacheSize** - size of in-memory cache for auth codes (per service per node, all codes are also always stored in db)
* **dbCleanInterval** - interval to clean db of expired codes in minutes

**AuthCodeDaoConfig -** please enter data source parameters to store auth codes. Could be the same instance that uses pragma.gg

```yaml
game:
  serviceConfigs:
    MatchmakingDaoConfig:
      databaseConfig:
        driver: "MYSQLDB"
        username: "superuser"
        password: "password"
        hostPortSchema: "localhost:3306/escs_matchmaking"
    ExternalMatchmakingServiceConfig:
      cleanInterval: 10
    EscsResultsServiceConfig:
      url: "https://api.escs.io/rpc/SetRoundResult"
      secret: "secret"
      gameId: "gameId"
  pluginConfigs:
    MatchmakingService.matchmakingPlugin:
      class: "matchmaking.escs.ExternalMatchmakingFillPartyPlugin"
    MatchLifecycleService.matchEndPlugin:
      class: "matchlifecycle.escs.DefaultEscsMatchEndPlugin"
    PartyService.partyPlugin:
      class: "matchmaking.escs.ExternalMatchmakingPartyPlugin"      
```

**MatchmakingDaoConfig** - please enter data source parameters to store matchmaking info from escs platform. Could be the same instance that uses pragma.gg

**ExternalMatchmakingServiceConfig**

* **cleanInterval** - interval to clean db of expired matchmaking info in minutes

**EscsResultsServiceConfig**

* **url -** please enter url as provided in the yaml code snippet (or contact us to use staging intances for testing purposes); this is url of our platform to receive match results
* **secret** and **gameId -** provide info from your game setup on this screen: [escs client](https://client.escs.io/) -> Apps -> your game :&#x20;

  <figure><img src="/files/gJ5eAVltaQtiB86Jpq43" alt=""><figcaption></figcaption></figure>

  **pluginConfigs** -[ use the values ](#user-content-fn-1)[^1]provided in the yaml code snippet.[^1] These classes are important for our matchmaking to work. If you have your own custom matchmaking and you want to support both escs and your own matchmaking, then you need to wrap our classes inside yours and distinguish matchmaking by Pragma queue keys (as described here: <https://pragma.gg/docs/concepts/multiplayer/matchmaking/matchmaking-key-concepts#matchmaking-queues>)

### Required protobufs

There are couple of required additions to global protobufs that you might want to be aware of (they should automatically be merged when getting mentioned git branch)

1. ```protobuf
   message ExtMatchmakingParty {
   ```

   ```
       .matchmaking.escs.SetStartPayload escs_matchmaking_info = 10001;
   }
   ```

   This data is required to correctly assemble parties with escs data.
2. ```protobuf
   enum ExtError {
   ```

   ```
       option (unreal_enum_name) = "ExtError";

       UNKNOWN_EXT_ERROR = 0;
       //  === EXTENSIONS (10001+) ===
       AUTH_CODE_NOT_FOUND = 10001;
       AUTH_CODE_EXPIRED = 10002;
       ESCS_CANNOT_CREATE_PARTY = 10003;
       ESCS_CANNOT_JOIN_PARTY = 10004;
       ESCS_MATCHMAKING_ERROR = 10005;
       ESCS_PARTY_NOT_FOUND = 10006;
   }
   ```

   This is required to produce specific service errors.

### AuthCodeService

Provides 2 endpoints: **AuthCodeRpc.AuthCodeV1Request** on social player backend and **AuthCodeRpc.GetPlayerWithAuthCodeV1Request** on social partner backend. **GetPlayerWithAuthCodeV1Request** lets escs to access pragma's player information to bind/create escs account. You don't need to use it, escs already took care of it. You only need to configure escs account in client.escs.io like described [here](/using-escs-oauth-for-sign-in).&#x20;

<figure><img src="/files/sh3L5DG9LgEJ6ItJaYde" alt=""><figcaption></figcaption></figure>

For **Game api url** use your social partner pragma backend address and append **/v1/rpc** to it like this: [https://your-backend.com/v1/rpc](https://98f0-78-10-84-184.ngrok-free.app/v1/rpc).&#x20;

For **Request Type** and **RPC type** use values provided on the screenshot. **Auth token** should be generated by pragma backend and pasted in specified field. You can generate it in pragma web dashboard.

**Note:** you may need to add your backend to escs account system allowed hosts at [account.escs.io](https://account.escs.io) -> developer -> edit app.

#### How to use **AuthCodeService**

The general flow is described [here](/using-escs-oauth-for-sign-in). **AuthCodeService тут** is playing the role of "your backend" in provided flow. To use it in game you have to let player to perform some kind of action, which leads to question "Do you want to let ESCS access your profile information?". If user answered yes, you can generate one-time access code and provide it to ESCS plugin in your game. Another option is to integrate with Escs plugin of your specific game engine and implement OnUserProfileRequested callback. This callback is called when a user is clicking "use game account to log in" inside escs overlay. You can get one-time code either using plain pragma rpc or via generated Unreal/Unity wrappers. Please refer to corresponding section for Unreal Escs plugin / Pragma integration. To use plain rpc you need to issue a request of form:

```json
{
    "requestId": 1,
    "type": "AuthCodeRpc.AuthCodeV1Request",
    "payload": {
        "playerId": "any string"
    }
}
```

to pragma social player backend **/v1/rpc** endpoint. This will return access code that escs platform can use to access user profile data:

```json
{
    "sequenceNumber": 0,
    "response": {
        "requestId": 1,
        "type": "AuthCodeRpc.AuthCodeV1Response",
        "payload": {
            "authCode": "c29c7043-16dc-4860-bd93-6bb2b360d2c4"
        }
    }
}
```

Now you can pass this **authCode** to escs plugin. After that escs will get user's profile data from your pragma backend and link it to existing or new escs account. After that your players are ready to use tournaments and other features of escs!

### **ExternalMatchmakingService**

Provides several endpoints that you are going to use in your game and some endpoints for escs platform to pass data about matches. Below are simple diagrams describing how **ExternalMatchmakingService** is working to create matches for escs platform. We'll break it into 2 phases. The queueing phase and matchmaking phase.

1. **Queueing phase:**

<figure><img src="/files/IW2QAqELbr8hakU0wdiX" alt=""><figcaption><p><strong>Queueing phase</strong></p></figcaption></figure>

* At given time (as per tournament settings and setup in Escs client dashboard) escs platform issues "set start" events. What is called in escs "a set" is one round of gameplay, i.e. "match" in Pragma. This event is received both by escs plugin that integrated in game (could be android, ios, desktop plugins, unity, unreal and so on) and also by escs custom services in pragma backend.
* Escs pragma custom service records that information and is ready for players to join.
* Players after receiving set start event should call RPC **ExternalMatchmakingRpc.QueueForMatchmakingV1Request**. This will automatically create party if needed and join the player if party for this match is already created. If you're using plain json then the request is in the following form (note that it should be issued for pragma game backend):&#x20;

```postman_json
{
    "requestId": 1,
    "type": "ExternalMatchmakingRpc.QueueForMatchmakingV1Request",
    "payload": {
    }
}
```

* Upon successful request players are going to receive status QUEUED. At this point, player is awaiting for other players in a match to join his party.
* When all players that are needed for the match to start are QUEUED, each is going to receive **PartyIsCompleteForMatchmakingV1Notification** from pragma backend. This notification ends queueing phase.

2. **Matchmaking phase:**

<figure><img src="/files/GaZZ0EXKcqECNIq8XC6z" alt=""><figcaption><p><strong>Matchmaking phase</strong></p></figcaption></figure>

* After receiving **PartyIsCompleteForMatchmakingV1Notification** from pragma backend the party leader (party leader would be the first player that entered the flow, all others just join this party) can enter matchmaking using regular pragma matchmaking tools: i.e. issuing **EnterMatchmakingV1** rpc. Note that every player should be in **READY** state for matchmaking to start.
* Escs **ExternalMatchmakingFillPartyPlugin** checks the party for integrity and that it has all required info for starting a match and recording results.
* Normal matchmaking proceeds with determining available game servers capacity etc. and issuing match start on your game backend with determined players as usual - no escs-specific logic is required.
* when the match ends, pragma receives **MatchEndV4 request.** This in turn triggers escs match end plugin and match end job. You can use your own plugin, just add escs-specific **SendResultsToEscsMatchEndDependentJob** to the list of jobs. It will require **EscsResultsTransformerPlugin -** this is the place where you should transform your own matchEnd results to pairs of key-value metrics that escs platform accepts. It should implement the single method **transform(ext: ExtPlayerMatchEnd) : Map\<String, Double>** which takes you game specific ExtPlayerMatchEnd type and returns map of key-value for escs.
* **SendResultsToEscsMatchEndDependentJob** automatically sends the transformed results to escs. At this point results are successfully received and processed and next stage of tournament should run, or the tournament ends.

### Working with match (set) info from escs platform

When configuring escs tournaments in dashboard, there are several parameters that you can specify for your game to receive. Some are metadata that is only understandable to your game, and there is also data that is created by escs to describe the set.

You can access this data in your matchmaking party ext proto:&#x20;

```protobuf
message ExtMatchmakingParty {
    .matchmaking.escs.SetStartPayload escs_matchmaking_info = 10001;
}
```

Wherever you can access **ExtMatchmakingParty** object (that would be party plugins or match starting code), you can also access all escs-specific data too. **SetStartPayload** has the following structure:

* **setId** - setId of started set (**string**)
* **tournamentId** - tournamentId of the set (**string**)
* **matchId** - matchId of the set (**string**)
* **setEndTimeUnix** - game's set max end time in unix time (i.e. time when the set will be ended forcefully even if players still have no game outcome; you should send any game results before this time and end the game session)&#x20;
* **pariticipants** - list of **Participant.** *Each participant contains list of* **Player***.* **Player** object consists of:
  * **playerId** - escs player id (**string**)
  * **ingamePlayerId** - registered in-game player id via **registerInGamePlayerId** (**string**)
  * **username** - user's escs username (**string**)
  * **firstName** - user's escs first name (**string**)
  * **lastName** - user's escs last name (**string**)
  * **ingameMetadata** - in-game metadata that was registered via registerInGamePlayerId (**string**) and global metadata from tournament dashboard
  * **roundId** - roundId of the set (this is in fact id of the set "results") (**string**)

[^1]: where?&#x20;


# Unreal

You can use this plugin for desktop Unreal games - at the moment we support only Windows platform.

## Connecting plugin to your project.

1. Put **TIPlugin** in your plugins directory.&#x20;

**TIPlugin** consists of ESCS\_Subsysem subsystem classes and windows dll libraries, as well as escs plugin-specific executables.&#x20;

2. Add dependencies to your **\*Build.cs** file of your Unreal project.&#x20;

```csharp
		PublicDependencyModuleNames.AddRange(new string[] { "Core",
			"CoreUObject", 
			"Engine", 
			"InputCore", 
			"TIPlugin" // <--- add this
		});
```

3. Re-generate Visual Studio project with aforementioned changes (right-click unreal project file)

<figure><img src="/files/B4hoB644Kfp9uk6c1Af4" alt=""><figcaption></figcaption></figure>

4. You're ready to go! Now you have **ESCS\_SubSystem** available for you. You can either use it in code or in blueprints. Later sections mainly describe how to use it in source code, but you can easily use it in your blueprints, just search for ESCS\_Subsystem there.

## Integrating plugin into your game.

Basic integration needs just few lines of code. After this, you have all the socialization features, but not multiplayer tournaments.

In your main controller class add the following in the **BeginPlay** method:

<pre class="language-cpp"><code class="lang-cpp">void AAPC_TutorialPlayerController::BeginPlay()
{
<strong>	//...
</strong>	auto* escs = GetGameInstance()->GetSubsystem &#x3C;UESCS_SubSystem>();
	
	escs->PluginCreate();
	
	escs->PluginSetFrontendPath("");
	
	escs->PluginSetFrontendEnvVar(TEXT("ESCS_ENVIRONMENT"), "prod");
	escs->PluginSetFrontendEnvVar(TEXT("ESCS_GAME_PUBLIC_KEY"), "your-game-public-key");
	
	auto result = escs->PluginStart();
	
	UE_LOG(LogTemp, Display, TEXT("ESCS -- init result: %d"), result);
	//...
}

void AAPC_TutorialPlayerController::Destroyed()
{
	auto* escs = GetGameInstance()->GetSubsystem &#x3C;UESCS_SubSystem>();
	escs->PluginDestroy();
}
</code></pre>

Here you can see the Escs subsystem being utilized. Before you invoke any methods, you need to call **PluginCreate()**. Don't forget to **PluginDestroy()** on controller destruction.

* **PluginSetFrontendPath()** - this is path to Escs frontend executable. It is located by default at \TIPlugin\Source\ThirdParty\TIPluginLibrary\x64\escs-desktop-frontend. This path could be either relative to current executable or absolute
* **PluginSetFrontendEnvVar()** - call to set environment for plugin. Two required pieces are the environment name - in our case it's Prod, and you game public key. How to obtain public key string please refer to [this](/integration-step-1).
* **PluginStart()** - starts plugin, at this point you are going to see the "escs ball" in your ui.

This is basic set up to have Escs UI integrated into you game. However, to support tournaments and OAuth integration, you need more steps, listed below.

## Multiplayer

### Overview

We support multiplayer games with different types of matches, matchmaking and so on. To be able to use this feature, you need to follow these steps:&#x20;

* Create multiplayer tournament in the game dashboard
* Implement several callbacks in you game, which will be called in response to player's engagement with multiplayer tournament

Currently we provide 1 such callback:

* **OnGameSetStart** callback - is called when a game set is started by escs backend. This is moment when you should start your game or create lobby and await for players to join it. What is a "set"? It's just one multiplayer game that several players are playing simultaneously. It can be real multiplayer (e.g. they, for example, race each other on track in a racing game or are participating in a deathmatch 1vs1 or 2vs2 and so on), or even "singleplayer", meaning that they all play their own singleplayer game (like solving puzzles and the one who solves it faster is the winner). In this callback you will receive information about players that are playing this set, teams that players are in (i.e. 2vs2 game), metadata that is supplied with the player (supplied by **registerInGamePlayerId**) and global metadata that is set in the game dashboard

**Currently unsupported callbacks (will be added in future releases):**

* **OnGameSetEnd** callback - is called when each player in the set has finished their game. this might be not necessary the same moment you end your multiplayer game - it is called when the escs backend processed all game end events from each participating player and saved their corresponding scores. You will receive **matchId** and **setId** as parameters
* **OnMatchStart** callback - is called when multiplayer match has started. Usually you will get this event right before getting **OnGameSetStart**. Each match consists of several game sets. You will receive **matchId** as parameter of this callback.
* **OnMatchEnd** callback - is called when multiplayer match has ended. That is when all the sets in the match has been played or timeout occurred. You will receive **matchId** as parameter of this callback

The following diagram may be helpful for understanding about aforementioned events:

![](/files/-MMHglMU0wyrPPD2Fb_z)

To utilize these events you can call methods described below.

```cpp
void AAPC_TutorialPlayerController::BeginPlay()
{	
	//...
	escs->BindPlugin_on_round_started_request(escs);

	FScriptDelegate roundDelegate;
	roundDelegate.BindUFunction(this, "RoundStarted");

	escs->OnCallBack_plugin_on_round_started_request.Add(
		roundDelegate
	);
	//...
}
		
void AAPC_TutorialPlayerController::RoundStarted(FString roundId)
{
	//here start your game session accordingly
	//...
	//get results of your game into variable metrics_value
	auto* escs = GetGameInstance()->GetSubsystem <UESCS_SubSystem>();
	auto res = escs->PluginEmitRoundStartedResponse("your metrics name", metrics_value);
}
```

Here we can see the event of set start in action. Upon game completion, you should get your game metrics (for example points, score, frags etc.) into **PluginEmitRoundStartedResponse.** You can check how to set up metrics names in escs dashboard [here](/integration-step-1).

For your game to function properly with escs you need to tell escs what ingame player id you are using in current session. This could be done using following methods:

```cpp
escs->BindPlugin_on_get_ingame_player_id_request(escs);
FScriptDelegate playerDelegate;
playerDelegate.BindUFunction(this, "GetPlayerId");

escs->OnCallBack_plugin_on_get_ingame_player_id_request.Add(
	playerDelegate
);

void AAPC_TutorialPlayerController::GetPlayerId()
{
	//here get your player's game id to bind to current game session 
	//(this will associate current escs playuer with given ingame playerID)
	auto* escs = GetGameInstance()->GetSubsystem <UESCS_SubSystem>();
	auto res = escs->PluginEmitGetIngamePlayerIdResponse("your player id");
}
```

Given player ids of all the players that are goin to participate in match will be sent to your game backend in OnGameSetStart callback. Please refer [here ](/plugins/android-native/basic-multiplayer-with-oauth)and [here ](/plugins/pragma.gg)to read about backend integration.&#x20;

**NOTE:** you have to **PluginEmitGetIngamePlayerIdResponse** before game set starts. We recommend calling it right after your user logins or changes credentials in your game.

### OAuth integration

1. Create the oAuth app as described here: [Using escs OAuth for sign in](/using-escs-oauth-for-sign-in)
2. Implement the callback to send the access token to escs as described below.&#x20;

#### Supporting user login using the game account (oAuth-like)

You can use our option for user game profile integration and allow your users to log in to our system without requiring them to manually create an escs account. Then the user will see an additional button **"log in using %game\_name% account"** on the main escs screen. In order to support this, first, you need to follow the required steps in the client dashboard and set up the necessary fields as described in the corresponding docs section: [Using escs OAuth for sign in](/using-escs-oauth-for-sign-in). Note that you will also need to create an additional endpoint in your game's backend for the account system for verifying tokens. If you are using pragma.gg for backend, you can read how to use escs custom services for that [here](/plugins/pragma.gg). After this you will only need to implement one callback in your game:&#x20;

```cpp

//...
escs->BindPlugin_on_get_oauth_onetime_token_request(escs);

FScriptDelegate tokenDelegate;
tokenDelegate.BindUFunction(this, "ReturnToken");

escs->OnCallBack_plugin_on_get_oauth_onetime_token_request.Add(
	tokenDelegate
	);
//...

		
void AAPC_TutorialPlayerController::ReturnToken()
{
	//here get your one-time code from your backend
	//if you're using pragma.gg please refer to corresponding section
	auto* escs = GetGameInstance()->GetSubsystem <UESCS_SubSystem>();
	auto res = escs->PluginEmitGetOauthOnetimeTokenResponse("your one-time token");
}
```


# Your first tournament series

Create a tournament series for your game.

Everybody (almost) loves competitions. \
Tournaments are fun and an important part of the escs. \
Instead of creating new tournaments over and over, escs lets you create tournament series: tournaments that run automated in fixed predefined timeframes.\
Let's create your first tournament series.\
Got to your game in the client.escs.io and press the "Create tournament series" button.

![Press the "Create tournament series" button](/files/nsRjqZZngef2PubgrUIw)

You should see something like this now:

![Template for ceating a tournament series. Do not be afraid. :)](/files/vYlvRfYWfDKjRlOYHp0J)

Let's fill just what's necessary. \
\
**Max set duration** - please enter in minutes how long one game can last (or how long you would like to allow it to last). This is important for tournament scheduling.\
\
Now please open  **"Advanced match settings"** on the right and find the field **"Penalty points"**

![Find the field "Penalty points"](/files/Jyos3hVv6sbe7ZJZb0xz)

If a player does not attend the game or just leaves the game during the tournament, this player needs to be penalized: his score for this game must be something that definitely makes him loose this game. Enter the value for this score in this field. For example, for Tetris it would be -1 or any negative number.

Now scroll down to the "General information" section.

![Let's fill the "General information"](/files/rqpKy5J7EZc3V7e5zmWJ)

Let's fill the "General information".

**Tournament name** - enter how do you want to call tournaments in this series. Players will see this name.

**Description** - put in a few words your message to the players here. Players will see the description as well.

**Starting time and date** - decide when the first tournament will start: pick the date and the time. This represents the starting point for this tournament series.\
The time you see here is the time in your time zone. \
Players will see the time in their respective time zones.&#x20;

**Duration** - how long should a single tournament last? You can enter days,  hours, minutes, seconds.

**Frequency** - how often should tournaments start? You can enter a number in days here. Frequency must be greater than duration - you cannot have several tournaments in one tournament series running in parallel. (But you can have as many tournament series as you want)\
\
Once set up, tournament series goes indefinitely - a starting point, duration, and frequency define all the tournaments.

Now press the "Create tournament series" button.\
Tournament series is now created and you see something like this under the information about your game:

![](/files/jFvnB8MyWsLIMBhquClQ)

Tournaments will run now automatically, everything is taken care of. Open escs inside your game - you immediately see the newly created tournament series there. Players can register and play.

The newly created tournament series is a bracket tournament, which will run until just one player is left - the winner. Read more about stages, modes, game modes etc. in the next sections.


# Game mode and scores.

You really need to understand this.

You already created your first score when added your game to the escs:

![You created here your first score.](/files/ogxB0WvrlpCirMQVnx4E)

Now let think a bit more about this.&#x20;

Only you know what scores make sense for your game and what scores should be used for the organization of the tournaments. The scores you define here is your way to know others about what it is possible. In the exactly same way as you defined your first score, you can define as many scores as you want. Everybody who wants to organize a tournament will be able to choose from these scores. You just have to submit them in the endGame() method. If you want for some score not to be available to the general public select the non public checkbox.&#x20;

### Game mode

Please take a look now at the Advanced game settings. Specifically at the game mode section.

![Take a good look at the game mode section.](/files/iCPDtjEztw99y3hnPuQh)

As with a game score, you know best which games mode of your game are best suited for the tournaments and competitive play. You can define here as many game modes as you want. Tournament organizers can then choose between individual game modes to set up tournaments. Again the non public checkbox allows you to hide game modes from a general public.

Let's go through the individual fields in the game mode form.

**Mode type**: this field actually tells whether this game mode in your game is a real multiplayer mode or a single player mode.

**Name**: give a meaningful name to the game mode.

**Description**: human readable description of the game mode as you would write in your game.

**Max set duration**: how long you think one set in this game mode should maximally last. It is an upper limit.

**Minimum participants in set**: the minimum number of participants that is required to start this game mode.

**Maximum participants in set**: the maximum or desired number of participants that is allowed for this game mode.

**Penalty points**: if a player does not attend the game or just leaves the game during the tournament, this player needs to be penalized. His score for this game must be something that definitely makes him loose this game. Enter such a value for this score that makes in sense in this game mode. For example, for Tetris it would be -1 or any negative number.

**Set parameters**: here you can enter any additional parameters that your game needs to start a game in this game mode. These parameters will be transferred to the game before each match. These parameters must be in a format that your game understands. They can define a particular map or set of items or literally anything you want. Just your game needs understand them.


# Matches, Sets, Points

Everything you always wanted to know.

Matches in a escs have a very flexible structure to accommodate all the possible needs. \
But think of them as of matches in tennis Grand Slam tournaments. \
So a match consists of one or more sets. And a set consists of one game between the match participants: the time between the game start and the time when the game sent scores to the escs.

Now depending on the the game mode in your game, you might want to decide to let players actually play more then one game in a set - it is entirely your decision and you control it by deciding when to sent the scores to the escs. \
For example, in a game of Tetris you could let players play just one game before sending the scores to the escs or  you can let them play 3 games and send the scores after the 3rd game, sending to the escs the cumulated score of all 3 games.\
How do you let the players and tournament organizers know about these details? \
This is what the **game mode** is for. Read more about it in the game mode section.

A game between players can be a multiplayer game or a single player game. It can be a real multiplayer (e.g. they, for example, race each other on track in a racing game or are participating in a deathmatch 1vs1 or 2vs2 and so on), or just a single player, meaning that they all play their own single player games (like solving puzzles and the one who solves it faster is the winner).&#x20;

You can define the match structure for each tournament stage individually in the Advanced Match Settings. The question marks on the right side of each field contain helpful information.

![Advanced match settings](/files/bJGFDzDLL7gmYuuhvvtS)

First of all, in the match template you can choose one of the predefined match structures: Best of 1, Best of 3, Best of 5. You probably heard of them

Then you can decide if the match is going to be a multiplayer match or a single player match. It means following. In a multiplayer match escs will let the game know who is playing against whom, so if the game is real multiplayer game it can start a match for a matched participants. In a single player match escs does not send participants data to the game - just the participant's data that is actually playing on the device. \
Whether escs matches a player against other players depends purely on the stage mode (brackets, free for all, etc), player's amount in a set. \
This can create interesting structures.&#x20;

{% hint style="info" %}
Whether a player is then actually playing against other players in the game or plays a single player game depends only on the game itself.
{% endhint %}

Define minimum players in a set and players in a set. The latter parameter means that escs tries always to match this number of participants in a match. The minimum players in a set parameter tells escs how many players are needed at least to start a set (or a game). escs will create matches with at least that number of participants.

The next two important parameters are maximum number of sets in a match and the match end condition. For example, in a tennis best of 5 match the maximum number of sets is 5. After that the match definitely ends. And the match end condition is 3: as soon as one of the players won 3 sets, this players wins a match. In that example of a tennis match, each player gets awarded one match point for winning one set. Please set these conditions so that they make sense.

Now in the case of the escs you can decide to award players different number of set points for winning a set: you define in the match points field. Default values a like in tennis. Enter the values in the coma separated format. After the end of the set players are sorted by the actual points they scored in the game and the first player gets the first number of match points and so force. In case of a draw in game points, players are moved one place down.

You can also omit the match points entirely - in this case the points scored in the game a count as a match points.

Match points are accumulated during the match: how they are accumulated is defined by the match points aggregate parameter. Choose here what makes most sense for your tournament and game.

Match points are not stored between different tournament stages or tournaments. After the end of the match players are sorted by earned match points and get tournament points: in an exactly the same way as match points you can define the tournament points in the tournament points field.\
Tournament points are stored between the stages and are accumulated during the tournament. Based on the tournament points at the end of the tournament you can define the winner of the tournament.

If you omit tournament points match points are counted as a tournament points.

So if you omit tournament points and match points then the actual game points are counted as a tournament points. This makes the structure very flexible and allows you to create the tournaments that perfectly fit your game.

Set parameters are described in the game mode section.

Wait time for the player defines how much time the player has to press the ready button. If player does not press the ready button in that time, the player looses this set and gets awarded penalty points (status Ret. in standings).


# Tournament structures

Everything about the tournament series and the tournament structures.

In the integration guide, you saw how to create a tournament series.

Tournament series are designed to be set up once and then run indefinitely until you decide to stop them.&#x20;

After you created a tournament series, you can edit certain parameters - go to the "Games", select a game, and then click on the replace button. &#x20;

{% hint style="info" %}
You can also pause the tournament series or replace it with a new one. \
Those actions are irreversible - your current tournament series will be deleted.
{% endhint %}

Each tournament series consists of tournaments.

Now each tournament consists of one or more stages that you create when you create a tournament series.&#x20;

Think of each stage as of a small tournament, because each stage can be defined absolutely independent of one another.

Each stage consists on one or more rounds: depending on the stage mode.

Example of the stage modes are: brackets, round robin.

For each stage you can define how long it should go when to end the stage in the advanced stage settings. Now you do not need to go there  - when you select a stage mode all the settings are populated with default parameters, which are sufficient for most cases.&#x20;

For example, stage with a bracket mode usually goes until 1 player is left.&#x20;


# Anti-Cheat services

We are aware of the cheaters and we are developing services that can help you.

## Backend-to-backend security.

In case your game has it's own backend, which receives the game scores, from the game frontend, you can use following escs endpoint for validation of the game results.

```
PUT /tournaments/:tournamentId/rounds/:roundId/game-server-confirmation
```

In case your backend considers the score and the game to be valid, send to this endpoint following body:

```
{ 
    isValid: true; 
    score: number; 
}
```

Our system will make another check, matching the score received in that body with the score that was received from the game frontend. \
\
If your backend considers the game and the score to be invalid, send the following body to the same endpoint:

```
{ 
    isValid: false; 
}
```

In case there is a mismatch between the scores or the system received "false", the game and the score will be invalidated.\
\
As you noticed, you need "tournamentId" and "roundId" to use this endpoint.

When you call startGame() in the plugin, successful call returns a response like this

```
{
   "status":"active",
   "isDeleted":false,
   "_id":"5f158727c9e95137883b8b96",
   "playerId":"5f158719c9e95137883b8b7c",
   "tournamentId":"5f0f7c60c9e95137883b55cc",
   "createdAt":"2020-07-20T11:59:35.491Z",
   "updatedAt":"2020-07-20T11:59:35.491Z",
   "__v":0
}
```

where "\_id" is your roundId and "tournamentId" is ... well, your tournamentId.

In case you send "false" to the endpoint, the score of the player for that round will be invalidated and not counted toward the results.

## Encryption

You can choose to secure communication between your client and escs backend, as well as between your backend and escs backend (see endpoint above).&#x20;

For that please click on the "Games" in the top menu, then select your game and click "Edit game information". You will see something like this:

&#x20;

![](/files/-MFBjzh2YK1lmya7a9su)

Click on "Generate secret" to secure the communication between your game's backend and escs endpoint above.

Add the generated secret to the header of the PUT request above

```
 headers
 {
        'escs-game-secret-key': GENERATED_SECRET
 }
```

Click on "Generate encryption key" to encrypt the communication between your game's client and escs backend above.

You will use the encryption key with the endGame method - please see the corresponding plugin description for the details.

We are constantly expanding our anti-cheat protection - new features will appear here.


# Using escs OAuth for sign in

How to do backend to backend player profile integration

The goal is to offer the best possible user experience for the players. \
Therefore it would be great if we could skip the escs registration process for players.\
It is possible if you have a backend, where you have your playe&#x72;**'**&#x73; profile data - so if you know your players.

In this case, you can integrate directly with our OAuth service and eliminate the need for the players to go through the registration process in the escs in order to play in tournaments and socialize.

The integration is extremely simple - you have to create an OAuth app (basically press 2 buttons) and make one method call in your backend.

### Integration steps

Go to the main game screen in client.escs.io and press the "Create oAuth App" button - like in the screenshot below

![Press the "Create oAuth App" button](/files/oCEZuab6NNMxLAsUDSRW)

The screen below opens. \
You can leave the App name as it is and enter some text in the description.\
Leave the "Secret key" field blank as well - we will create it for you automatically.\ <mark style="color:red;">**Do not lose this key. Store it somewhere safe! It cannot be recovered if lost.**</mark>\
\
In the Game API Url field, enter the endpoint, where the escs account system will get the player's profile data, using the access token that you will send - read the next part about this.\
This endpoint must validate the access token and respond with the profile data.

![Fill in the fields and press the "Create App" button.](/files/gFYzHhEbZTqtr7ToDtlK)

Press the "Create App" button. You get the following response:

![Copy and save the keys! You cannot recover them later.](/files/HQYzuK4nAT8qLjdeYsgl)

You need to save and copy the keys above: the secret key and the application id. You cannot recover them later.

After that, you can proceed to the "Supporting user login using the game account" section for your plugin. And please read about the "Access token" below.

### **Access token**

escs gets the access token from the game via the corresponding plugin. When a user wants to log into escs using their game account, they press the corresponding button on the escs main screen, and then you will receive a callback in your game, where you can show some permissions request dialog to user and obtain the access token from your game backend. This token along with the list of permissions should be sent to the escs plugin.\
&#x20;\
How the game gets this access token from your backend is completely up to you.&#x20;

After that, the escs backend will receive the aforementioned data and ask your game's API endpoint for actual user profile data. To obtain a player's profile escs account system sends to Game API Url the following POST request:

```
export interface Request {
  code: string;
  secretKey: string;
  applicationId: string;
}
```

where the **code** is the access token that your game sent to the escs and secretKey is the generated key from the client dashboard.\
\
escs expects a response in the following format:

```
export interface Response {
  _id: string;
  email?: string;
  username?: string;
}
```

where **email** and **username** are the player's data.

For a better understanding of access token and user's game profile data flow you can use the following diagram:

![Principal diagram of integration flow](/files/CVMDXET2JXalt2Kek7L9)


# Using escs OAuth for automated user sign in in your GameHub

The goal is to offer the best possible user experience.\
You can skip the escs registration flow and sign users in to GameHub with their existing account credentials.\
\
The integration is simple. You create an OAuth app and make one method call in your app.

### Integration steps

Go to [client.demo.escs.io](https://client.demo.escs.io/) and create a temporary game as described in [Integration - step 1](/integration-step-1).\
**You only need to create the app. No further setup is required.**

Then open the game settings and press **Create oAuth App**, as shown below.

<figure><img src="/files/2fwEGo0ZlDPF3MtSDOxD" alt=""><figcaption></figcaption></figure>

The following screen opens.\
You can keep the default app name and enter any description.\
Leave the **Secret key** field blank. It is created automatically.\ <mark style="color:red;">**Do not lose this key. Store it somewhere safe! It cannot be recovered if lost.**</mark>\
\
In **Game API URL**, enter the endpoint where the escs account system can fetch the player's profile data by using the access token you send.\
This endpoint must validate the access token and respond with the profile data.

![Fill in the fields and press the "Create App" button.](/files/gFYzHhEbZTqtr7ToDtlK)

Press **Create App**. You will get the following response:

![Copy and save the keys! You cannot recover them later.](/files/HQYzuK4nAT8qLjdeYsgl)

Save both keys shown above: the secret key and the application ID.\
You cannot recover them later.

Then continue with the **Access token** section below.

### **Access token**

escs receives the access token from your app through the corresponding post message, as described in the GameHub integration guide.\
\
How your app gets this access token from your backend is up to you.

After that, the escs backend uses that data to request the actual user profile from your API endpoint.\
To get a user's profile, the escs account system sends the following POST request to **Game API URL**:

```
export interface Request {
  code: string;
  secretKey: string;
  applicationId: string;
}
```

Here, `code` is the access token your app sent to escs, and `secretKey` is the generated key from the client dashboard.\
\
escs expects a response in the following format:

```
export interface Response {
  _id: string;
  email?: string;
  username?: string;
}
```

Here, `email` and `username` contain the player's data.\
\
After that, the player is signed in.


# Moving to production

How to move from the demo environment to the production environment.

This is a very simple process.

Create your game in the production developer dashboard <https://client.escs.io>.

Follow the steps from the [Integration - step 1](https://app.gitbook.com/o/-MBTzNswyYG20uBURMs7/s/-MAfYp0johoPRZW2PhVp/~/edit/~/changes/108/integration-step-1).

Then in all the API calls change api.demo.escs.io to api.escs.io.

After you finished the process go to "Settings" in the developer dashboard and submit your game for the moderation. As soon as your game is published you will have all the functionality available.

<figure><img src="/files/Vz7iKL37IIx4CJOSq4Ti" alt=""><figcaption><p>Press "Publish" to submit your game for the moderation.</p></figcaption></figure>

Please pay attention to the checkbox "Show in organizer portal": activating this checkbox makes your game visible in the [organizer.escs.io](https://organizer.escs.io) and makes it possible to any influencer or player to organize automated tournaments for their communities. This is your additional revenue stream.

Also, please pay attention to the checkbox "Can be integrated into paid tournaments". This checkbox is activated by default and enables wagering in your game through the eligible partners. Another additional revenue stream for you!

<figure><img src="/files/UOa0msHT5NkAmh6MRmQZ" alt=""><figcaption></figcaption></figure>


