MINIPLAY C2S UNITY API
APIs for casual & social games

Preface:

Please help us improving it by reporting us any bugs or suggestions to [email protected], we put our best efforts in order to make life easier for you and the other developers, and your help will be greatly appreciated.

In this document we’ll dig into the UNITY API for connecting to our services from any UNITY game running within a WEBGL container. Please refer to the MINIPLAY APIs OVERVIEW document first if you haven’t read it yet, knowledge of the concepts explained there is required.

This documentation it’s in beta state (only for selected developers), we do not even intend to release the final documentation in this format. Please help us improving it by reporting us any bugs or suggestions to [email protected], we put our best efforts in order to make life easier for you and the other developers, and your help will be greatly appreciated.

1. Introduction

The UNITY API allows your game to connect to our services in both read & write modes, right from the user browser. In case of internal games (those that run inside our site sandbox, be them hosted by us or by you under a custom URL) the API provides your game interoperability with our site as well, (i.e.: opening the login dialog, a scoreboard, purchase items, maximize the game...). In case of external games not running on our websites, the API automatically detects them and provides methods to allow your users authenticate by using their Miniplay account, that’s what we call Miniplay connect*, we’ll talk about it later (although other methods designed for internal interoperability will be disabled).

* You must ask for permission if you want to use this API in an external site so we enable Miniplay connect for you

2. Supported builds & versions

Since our UNITY API heavily relies on our underlying Javascript API and requires Application.ExternalCall() to access it, only WEBGL builds are supported.

Please refer to the Server 2 Server REST API if you need to connect with our API from other type of builds, just be noticed you must provide the user access token and your API key has to be hardcoded in your game, which can be a security vulnerability.

Unity version support: 5.3+

3. API Loading

  • 1. Download and import our unitypackage file into your Unity project.

  • 2. Our API is modeled as a Singleton object that will be initialized when the first instance is generated, so, you just need to get it when you need to access to the API:

    LeChuckAPI lechuck = LeChuckAPI.getInstance();

  • 3. Please be noticed that the lechuck API not only has to load our JS API under the hood (which is done automatically) It also has to make some asynchronous calls prior being ready for action, so you should try to initialize as soon as possible to avoid any unnecessary waits. To do that, just call it in any of your first-running scripts or attach the InitLeChuckAPI script to the first gameobject that appears in your game (i.e. your camera)

  • 4. Once ready, every API call will be at your disposal at the lechuck.api object.

Important: Since Unity 2020+ the HTML template has been changed and the JavaScript window.unityInstance object is no longer present automatically and cannot be detected by our API. You must explicitly modify the index.html file to add the reference to the instance inside the createUnityInstance() returned promise:

createUnityInstance(canvas, config).then((unityInstance) => { window.unityInstance = unityInstance; // Make the unityInstance global (lechuck api tries to find it at window.unityInstance) });

3.1 API Initialization

Our API needs to perform a few asynchronous calls before being ready to use. An onReady method allows you to dispatch a custom action when it becomes ready. If it’s already ready, the action will be dispatched right away. Please take a look at this sample MonoBehaviour:

For games not hosted by us, running either within in an iframe or completely external, the API must be loaded in the head section of your HTML.

public LeChuckAPI lechuck; void Start () { // Load API print("Waiting for LeChuck API onReady event..."); lechuck = LeChuckAPI.getInstance(); lechuck.api.onReady(onLeChuckAPIReady); } void onLeChuckAPIReady(bool simulationMode, LeChuckAPI.Api.Info apiInfo, LeChuckAPI.Api.User currentUser) { print("LeChuck API ready! "+apiInfo.unityApiVersion+" "+(simulationMode ? "(Simulation mode)":"")); if (currentUser.isGuest) { print("Logged user: Guest"); } else { print("Logged user: " + currentUser.uid); } // >>>> You can perform API CALLS now! Any future access to it will have it ready <<<<< }

3.2 API modes

The API can run in either production or simulation mode, it automatically decides which one to use.

Simulation mode

Running in the editor or in non WebGL environments. All calls will return predefined-simulated responses. A flag on all API calls let you decide whether you want a success or a failure response. This allows you to test your game somewhat like if it was running in production (although it has some limitations)

To check if the API is running under simulation mode you can use the method:
lechuck.api.isSimulationMode();

Production mode

Running in a WebGL environment and with access to our JS API. To avoid having to hardcode all the API parameters (game id, api id, user token…) into your game, they are pulled automatically from the game url query string by our JS API. If it’s not present, it will assume an apiId=0 and all calls which requires permissions will fail.

To check if the API has successfully received the parameters, you can test if the apiId is not 0:
lechuck.api.apiInfo.apiId!=0

If your game is running inside our sandbox, it’s also hosted by us, and it has the API enabled, it will be automatically loaded, so, you can skip this chapter.

3.3 Options

There are some options that can be set up before the API get’s ready:

LeChuckAPI lechuck = LeChuckAPI.getInstance(); lechuck.api.debug = true; // Show debug messages in unity console lechuck.api.debugMethodCalls = true; // Debug all api method calls lechuck.api.getDemoUserInSimulationMode = true; // Get a demo user instead of a guest user if it's in simulation mode?

3.4 JS to Unity messaging

To send the responses from our JS API to our Unity API, the JS API needs to have access to the Unity game instance, which is automatically created by the Unity WebGL Builder at window.gameInstance. This is how we detect if we have access to it:

if (!gameInstance) { // Find unity game instance if (window.hasOwnProperty("gameInstance")) { gameInstance = window['gameInstance']; } }

Plase make sure your gameInstance is reachable with window.gameInstance or with window.unityInstance

3.5 API Demo unity project

For your convenience, you can download our sample project which makes use of some of the most interesting API features.

3.6 Integrating the API into a sample game

In this video we show how easy is to import a sample game into an empty project and integrate the LeChuckAPI into it.

4. API features

The lechuck.api object gives acces to the following features. All methods returning LeChuckAPIResponse are asynchronous and their response will be provided to an Action callback:

* For simplicity, all object types are simplified here, i.e: Info => LeChuckAPI.Api.Info

  • STATUS
  • EVENTS
  • ENVIRONMENT
  • USER
  • STATS
  • SHARING & CHALLENGES
  • IN GAME ADS
  • ITEMS - VIRTUAL GOODS

5. STATUS

The status module gives information about the API status and current loaded configuration.

5.1 bool isReady()

Is the Api ready for action? if not, all api calls will fail.

5.2 bool isSimulationMode()

Is the Api working in simulation mode?

5.3 Info apiInfo

Contains information about the current configuration

public class Info { public string unityApiVersion; /* UNITY API VERSION */ public string apiVersion; /* JS API Version */ public string apiId; /* Game API ID */ public string locale; /* Site locale: en_US */ public string localeLang; /* Site lang: en */ public bool isExternal; /* Is the game not running in our site? */ public bool isInternal; /* Is the game running in our site? */ public bool isMobile; /* Is playing on our mobile site? */ public string site; /* Site url: http://www.minijuegos.com/ */ }

6. EVENTS

The events module allows you to register a handful set of custom listeners, just provide your callback function as a parameter and it will be automatically called. You can register as much listeners as you want, even of the same type.

6.1 void onReady(Action<bool, Info, User> callback)

Executes it when the API is connected and the user is authenticated. This is when you can start doing things with the API. Refer to API Initialization for a complete working sample:

lechuck.api.onReady((isSimulationMode, apiInfo, currentUser) => {});

6.2 void onPlayerResize(Action callback, float autoTriggerInSimulationModeSeconds = 0f)

Executes it when the game player within our site has been resized, to test it in simulation mode you can provide the number of seconds when you want it to be automatically triggered, send 0f for no auto trigger:

lechuck.api.onPlayerResize(() => { print("Player resized event!"); });

6.3 void onUserDisconnect(Action callback, float autoTriggerInSimulationModeSeconds = 0f)

Executes it when the game player within our site has been resized, to test it in simulation mode you can provide the number of seconds when you want it to be automatically triggered, send 0f for no auto trigger:

lechuck.api.onUserDisconnect(() => { print("Player disconnected event!"); });

7. ENVIRONMENT

The environment module allows you to interact with the game environment, in other words, to communicate with our site. This module is disabled for external games.

7.1 LeChuckAPIResponse getSize(Action<Size> callback)

Gets the player size, our game page allows certain games to have a maximize button which changes it’s size.

7.2 LeChuckAPIResponse showComments()

Scrolls to the comments section.

7.3 LeChuckAPIResponse showControls()

Scrolls to the controls section.

7.4 LeChuckAPIResponse showDescription()

Scrolls to the description section.

7.5 LeChuckAPIResponse showAchievements()

Opens the game achievements or navigate to them if they’re already opened.

8. USER

Allows you to manage the current logged user when your game is running within our site game page.

Please see the document 01 - MINIPLAY APIs OVERVIEW, APPENDIX 6. Handling guests users for more information.

8.1 User currentUser                              User currentUser()

Access to the current logged user object.

public class User { public string errorMessage; public string errorType; public bool success; public string id; /* user id */ public string uid; /* user uid */ public int level; /* user level */ public string avatar; /* user avatar url 96x96 */ public string avatarBig; /* user avatar url big 256x256 */ public string avatarMini; /* user avatar url small 32x32 */ public string avatarBody; /* user avatar url body 160x220 */ public string avatarAlpha; /* user avatar url in png 96x96 */ public string profile; /* user profile url */ public bool isGuest; /* is it a guest user? */ }

8.2 LeChuckAPIResponse getCurrentUserFriends(Action<UserFriends> callback, int limit = 20, int fromTimestamp = 0, bool simulationSuccess = true)

This is probably the most important list for game developers. Gets the subscriptions list of the logged user (who he/she follows), ordered by descending timestamp, can be easily paginated by using the timestamps. Every user in the list will contain the timestamp property corresponding to the millisecond timestamp when the event occurred (in this case, the subscription of the user)

public class UserFriends { public bool success; public string errorType; public string errorMessage; public UserFriend[] friends; } public class UserFriend { public string id; /* user id */ public string uid; /* user uid */ public int level; /* user level */ public string avatar; /* user avatar url 96x96 */ public string avatarBig; /* user avatar url big 256x256 */ public string avatarMini; /* user avatar url small 32x32 */ public string avatarBody; /* user avatar url body 160x220 */ public string avatarAlpha; /* user avatar url in png 96x96 */ public string profile; /* user profile url */ public int timestamp; /* millisecond timestamp friendship date? */ public bool isInstalled; /* has played the game? */ }

8.3 LeChuckAPIResponse getUser(Action<User> callback, int userId, bool simulationSuccess = true)

Access to an user detail object

public class User { public string errorMessage; public string errorType; public bool success; public string id; /* user id */ public string uid; /* user uid */ public int level; /* user level */ public string avatar; /* user avatar url 96x96 */ public string avatarBig; /* user avatar url big 256x256 */ public string avatarMini; /* user avatar url small 32x32 */ public string avatarBody; /* user avatar url body 160x220 */ public string avatarAlpha; /* user avatar url in png 96x96 */ public string profile; /* user profile url */ public bool isGuest; /* is it a guest user? */ }

8.4 LeChuckAPIResponse login()

Opens the login modal window in our site.

8.5 LeChuckAPIResponse register()

Opens the register modal window in our site.

9. STATS

We will provide you the stat_uid when we create them but they will also be listed in your development sandbox, among a bunch of interesting tools :)

For more info, please take a look at our MiniPlay social competition document.

9.1 LeChuckAPIResponse putStat(Action<StatPut> callback, string statUid, int value, bool simulationSuccess = true)

Writes an user stat, i.e. score. Please notice that no decimal point is allowed, in that case, if you need more precision, you can multiply it for 10, 100, 1000… and round the value, to later divide it by the same amount when getting the stored value.

public class StatPut { public string errorMessage; public string errorType; public bool success; public int value; public string uid; }

Here’s a small example:

lechuck.api.putStat( (statPut) => { if (statPut.success) { print("Stat " + statPut.uid + " saved value: "+statPut.value); } else { print("Failed to put stat " + statPut.uid + " value: "+statPut.errorMessage); } }, "points", 100, true /* Return a success response if running in simulation mode, param will be ignored on non-simulation mode */ );

9.2 LeChuckAPIResponse putStatLowPriority(Action<StatPut> callback, string statUid, int value, int minElapsedSeconds = 20, bool simulationSuccess = true)

Like 9.1 it also writes an user stat, but this would be sent with low-priority. It’s used to send non-important, intermediate stats while the user is playing which are incremented many times, i.e. a score or the number of kills.

By sending the stat with low priority constantly, you allow us to create fun achievements that will be unlocked while the user is playing instead if waiting for the level-finish (or for the player’s death) when you usually submit the user final score. This method automatically handles the sampling rate provided and ignores multiple writes of the same statUid to avoid spamming the API.

We recommend you to send intermediate stats as low priority while the user is playing and the same stat as high priority (with the standard putStat method) when the user has completed the level.

If you handle it by yourself or your writes won’t spam the api you can ignore this method and send standard puts.

Here’s a small example that will send the stat once every 20 seconds, even if it’s called multiple times (i.e, in an update() method) Please notice that low priority stats don’t allow callbacks:

lechuck.api.putStatLowPriority("points", 25, 20 /* Only send the stat if the last write was +20 seconds ago */);

* Please try not to use less than 10 second sampling rates.

9.3 LeChuckAPIResponse getStat(Action<StatGet> callback, string statUid, bool simulationSuccess = true)

Gets an user stat, i.e. score.

public class StatGet { public string errorMessage; public string errorType; public bool success; public int value; public string uid; public long timestamp; }

Gets an user stat, i.e. score.

lechuck.api.getStat((statGet) => { if (statGet.success) { print("Stat " + statGet.uid + " value: "+statGet.value+" "+statGet.timestamp); } else { print("Failed to retrieve stat " + statGet.uid + ": "+statGet.errorMessage); } }, "points", false /* Return a success response if running in simulation mode, param will be ignored on non-simulation mode */);

10. SHARING & CHALLENGES

We will provide you the stat_uid when we create them but they will also be listed in your development sandbox, among a bunch of interesting tools :)

For more info, please take a look at our MiniPlay social competition document.

9.1 LeChuckAPIResponse share(Action<Share> callback, int[] userIds = null, bool simulationSuccess = true)

Opens the share game modal window, it allows the user to share it on major social networks and with it’s miniplay friends. You can provide the userIds of some of the miniplay user friends to automatically share it with them. Set to null to allow the user to choose them manually.

public class Share{ public bool success; public int[] users; }

9.2 LeChuckAPIResponse challenge(Action<Challenge> callback, int[] userIds = null, bool allowAdd = true, bool allowMultiUser = true, string customParametersJsonObjectAsString = "{\"customParameters\":false}", bool simulationSuccess = true)

Opens the challenge modal window, it allows the user to challenge their friends in miniplay. A challenge is a special kind of private message which includes a link to your game and a custom GET payload provided by you. Ii.e. you can generate a challengeID in your game and let the user share it with one or many friends, once they click on the message they receive, they will access to your game with that parameter included, so you can start a new game so they can play together.

public class Challenge { public bool success; public int[] users; public string customParameters; /* Custom json string provided */ }

11. IN GAME ADS

11.1 LeChuckAPIResponse showInterlevelAd(Action<InterlevelAd> callback, string tagUrl = "", bool autoPause = true, bool simulationSuccess = true)

Shows an interlevel video AD. It's not guaranteed that a video ad will be shown. In case a video is shown a close button will appear after 10 seconds. Please make sure to:

  • Provide a proper adTagURL (if empty a demo adTagURL will be used) Contact us to request one.
  • Do not use the demo adTagURL in production
  • Provide valid callbacks. onPlayCallback: An ad is being played. onEndedOKCallback:
    An ad has been played. onEndedKOCallback: An ad could not be played.
  • Pause your game and stop all audio on the onPlayCallback event.
  • Focus your game and resume it on the onEndedOKCallback & onEndedKOCallback events.

Some demo ad (no monetization, do not use it on production):

lechuck.api.showInterlevelAd((interlevelAd) => { print("InterlevelAd event received: "+interlevelAd.adEvent); }, "" /* VAST TagUrl provided by us (empty for demo ad) */, true /* Auto PAUSE Game */, true );

11.2 Video Rewards

This module allow you to give the user some virtual items or rewards in exchange for watching a video ad. This is a multi-step process:

  • 1. Check if the user has a campaign available
  • 2. If the user has campaign available, let the user know to allow him claim the reward (i.e. a button)
  • 3. Show the campaign when the user and reward him when it completes
  • 4. Cool down as much time as you want and go back to Step 1.

Please notice this is not available by default, please contact us to request this feature.

By default, demo campaigns with no monetization will be returned, contact us once you're ready for production in order to activate your game.

11.2.1 LeChuckAPIResponse videoRewardHasCampaigns( string vrAppKey, Action callbackOk, Action callbackKo, bool simulationSuccess = true)

Check if the user has any video reward campaign available.

ASYNCHRONOUS. It may take a few seconds to complete.

Some demo ad (no monetization, do not use it on production):

lechuck.api.videoRewardHasCampaigns("YOUR_APPKEY", () => { print("The user has a video reward campaign available"); }, () => { print("The user doesn't have a video reward campaign available"); }, true );

11.2.2 LeChuckAPIResponse videoRewardShowAd( Action callbackOpen, Action callbackClose, Action callbackComplete, bool autoPause = true, bool simulationSuccess = true)

Shows the video reward campaign if its available. If there are no campaigns available, nothing will happen and callback close will be called (without callback open)

ASYNCHRONOUS. Only call it after the videoRewardHasCampaigns callbackOk.

Some demo ad (no monetization, do not use it on production):

lechuck.api.videoRewardShowAd("YOUR_APPKEY", () => { print("The video has been opened, game has been paused"); }, () => { print("The video has been closed, game will be resumed"); }, () => { print("The video reward has been claimed... give it to the user!"); }, true, true );

12. ITEMS - VIRTUAL GOODS

The item module allows you access the inventory of items bought by the user for your game and to initiate the purchase workflow right from within your game.

12.1 LeChuckAPIResponse itemDetail(Action<ItemDetail> callback, string itemUid, bool simulationSuccess = true)

Retrieves an item configuration.

lechuck.api.itemDetail((itemDetail) => { if (itemDetail.success) { print("Item found: " + itemDetail.item.uid + " => " + JsonUtility.ToJson(itemDetail)); } else { print("Item not found: "+itemDetail.errorMessage + " " + JsonUtility.ToJson(itemDetail)); } }, "test", true);

12.2 LeChuckAPIResponse itemList(Action<ItemList> callback, bool simulationSuccess = true)

Retrieves the list of configured items for the game.

lechuck.api.itemDetail((itemDetail) => { if (itemDetail.success) { print("Item found: " + itemDetail.item.uid + " => " + JsonUtility.ToJson(itemDetail)); } else { print("Item not found: "+itemDetail.errorMessage + " " + JsonUtility.ToJson(itemDetail)); } }, "test", true);

12.3 LeChuckAPIResponse itemStock(Action<ItemDetail> callback, string itemUid, bool simulationSuccess = true)

Retrieves the item stock owned by an user.

lechuck.api.itemStock((itemStock) => { if (itemStock.success) { print("Item found: " + itemStock.item.uid + " => STOCK " + itemStock.stock); } else { print("Unable to get stock: "+itemStock.errorMessage + " " + JsonUtility.ToJson(itemStock)); } }, "test", true);

12.4 LeChuckAPIResponse itemBuy(Action<ItemPurchaseList> callback, string itemUid, int qty, bool simulationSuccess = true)

Initiates the purchase items with Minicoins workflow (fully handled by us). The items uids are available on your development sandbox, as well as some interesting stuff (like an item reset tool or a log). On your development game all items are free, on the production game they’re paid, please contact us in order to define and configure the items along with their price, there’s no limit of items that can be configured.

Once the item has been purchased (or cancelled) a response object is sent to your callback.

lechuck.api.itemBuy((itemPurchaseList) => { if (itemPurchaseList.success) { print("Items purchased:"); foreach (LeChuckAPI.Api.ItemPurchase item in itemPurchaseList.items) { print("- "+item.uid+" => PURCHASED "+item.qty+" => CURRENT STOCK "+item.stock); } } else { print("Unable to buy: "+itemPurchaseList.errorMessage + " " + JsonUtility.ToJson(itemPurchaseList)); } }, "test", 1, true /* Return a success response if running in simulation mode, param will be ignored on non-simulation mode */);

12.5 LeChuckAPIResponse itemBuyDynamic(Action<ItemPurchaseList> callback, int priceInMinicoins, string title, string customIconUrl, string customData, bool simulationSuccess = true)

If it’s available for your game, it initiates the purchase of a dynamic item with Minicoins workflow (fully handled by us). Dynamic items allow you to sell any kind of item at any cost. Please notice that dynamic items have no stock, all purchases are auto consumed and current stock will be 0 always. You shouldn’t use this unless you’ve integrated server-to server callbacks to validate the item purchase.

lechuck.api.itemBuyDynamic((itemPurchaseList) => { if (itemPurchaseList.success) { print("Items purchased:"); foreach (LeChuckAPI.Api.ItemPurchase item in itemPurchaseList.items) { print("- "+item.uid+" => PURCHASED "+item.qty+" => CURRENT STOCK "+item.stock+" => PAYLOAD: "+item.dynamic_payload); } } else { print("Unable to buy: "+itemPurchaseList.errorMessage + " " + JsonUtility.ToJson(itemPurchaseList)); } }, 100, "My custom item", null, "CUSTOMDATA", true);

12.6 LeChuckAPIResponse itemConsume(Action<ItemConsume> callback, string itemUid, int qty bool simulationSuccess = true)

Consumes (decrements) the item stock for an user.

lechuck.api.itemConsume((itemConsume) => { if (itemConsume.success) { print("Item consumed!: " + itemConsume.uid + " => "+ itemConsume.qty +" UNITS => NEW STOCK " + itemConsume.new_stock); } else { print("Unable to consume: "+itemConsume.errorMessage + " " + JsonUtility.ToJson(itemConsume)); } }, "test", 1, true);

Do you have questions or want to report some bugs? please contact us at [email protected]