Basic multiplayer with oAuth

Initialization

To start using your plugin you need first initialize it:

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

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

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()

Registering in-game player id and metadata:

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

EscsService.registerInGamePlayerId(playerId, playerMetadata)

Forcefully open escs view

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

EscsService.openEscsView()

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

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)

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

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

{
  "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:

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

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

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
}

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.

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.

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)
    }
}

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:

<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

  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. 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:

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

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

where

  • 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)

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"
		}
	]
}

Last updated