Unity
How to integrate the Unity plugin.
Last updated
How to integrate the Unity plugin.
Last updated
You can use this plugin for Mobile Unity games - at the moment we support Android and iOS
Get it on the Unity Asset Store!
To obtain the plugin please connect with us.
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.
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 (EDM4U) - it should be installed for the plugin to work correctly, otherwise you will need to provide all the dependencies manually. 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):
You can explore our API demo, filling the public key field with your public key generated at https://client.escs.io (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).
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:
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)
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.
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.
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.
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:
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):
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:
They are enabled by default, but make sure that you haven't unchecked them.
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:
To support escs video chat and streaming on android platform, you need to define several properties in player settings in Scripting Define Symbols:
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 defineESCS_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:
For iOS you need to use the same External Dependency Manager for Unity 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.
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.
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
It is very easy to integrate ESCS plugin into your game code.
We splitted these instructions into steps to make it easier to follower. Please complete each step before running your code.
First you need to initialize your plugin.
To start using your plugin you need first initialize it:
where:
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
- url for the player's ESCS service. It is https://player.escs.io
for production environment
OnEscsInit
- callback delegate when init is completed; you can omit it.
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:
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?
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
Call this right after you initialize the escs service and before player interacts with escs:
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, can be empty)
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.
where EscsSetStartPayload 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)
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:
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)
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.
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) :
where
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:
roundId
- roundId of just started game round in the escs.
tournamentId
- tournamentId of active tournament for which the round was created for
status
- round status. "active" for just created round
playerId
- escs playerId
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:
where
score
- game score parameter - accepts an object with Serializable annotation; the names of properties should be defined in game dashboard at 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:
roundId
- roundId of just progressed game round
progressId
- id of just sent progress object
When the round of your game has ended, just call EndGame()
with score parameter:
where
score
- game score parameter - accepts an object with Serializable annotation; the names of properties should be defined in game dashboard at client.escs.io, 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:
roundId
- roundId of just ended game round
tournamentId
- tournamentId of active tournament for which the round was ended
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 like ESL or influencers/streamers can create tournaments and drive players into your game.
You can integrate more deeply with escs. Read optional steps to know more.