Skip to content

Cloud Code

The Cloud Code feature of ChilliConnect allows you to define and run your own custom server logic using Javascript. Cloud code scripts can be called directly from your game, run on a schedule or called externally so that you can integrate ChilliConnect with other systems.

Creating Scripts

From the Game View, select the Cloud Code menu option to view a list of Scripts you have already created. Creating the your script can be done with the top right "Add Script" button. For all Script types the following field are required:

Name A recognizable name for your script, displayed on the script list.
Key The Key used to uniquely identify the Script.
Type The Type of the Script

The types of script available in ChilliConnect are summarized below:

API Scripts called directly from your game using the RunScript method of the SDK
Scheduled Scripts that automatically run in the background on a set schedule
External Scripts that can be called from external systems
Photon Callback Scripts designed to be used with ChilliConnects Photon integration
Event Scripts automatically triggered by ChilliConnect on certain events
Module Scripts used to share re-usable code between other scripts
Support Scripts designed to interact with individual player accounts through the ChilliConnect Dashboard

API Scripts

API scripts are scripts called directly from your game using the Run Script method. For API scripts, you can also specify what parameters the script should accept from the game:

Each parameter has the following properties:

Name This is a list of parameters that will be available to your Script when triggered. There is a maximum of 10.
Type String, Numeric, Boolean, JSON or Any - which determines the data type validation that ChilliConnect will perform upon each request. The Required toggle validates that parameter was passed in the request.
Required Selecting required will validate that parameter was passed in the request.

API Script Parameters can be accessed through the ChilliConnect.Request object as named properties. For example, to access a parameter named ExperienceLevel in your Script:

var level = ChilliConnect.Request.ExperienceLevel;

Note that parameters are case sensitive.

Scheduled Scripts

Scheduled scripts are run automatically by ChilliConnect either hourly, daily or weekly:

Hourly The script runs every hour, at the minute specified.
Daily The script runs every day, at the time specified.
Weekly The script runs once a week day, on the specified day and time.

Scheduled scripts are limited to a run time of 10 minutes. When viewing details of a script, Scheduled scripts will provide an additional "Schedule" tab that can be used to view the configured schedule for the script, last run time, last run duration and next scheduled run:

Scheduled scripts are executed without a player context set. If you want to modify a player account, be sure to set the player context from your script.

External Scripts

External scripts can be invoked from a public URL and do not require a player to be logged in to your game. External scripts are designed to allow you to integrate ChilliConnect with other systems. External scripts require no additional configuration options.

External scripts are accessible from https://connect.chilliconnect.com/1.0/external/{your-app-token}/{script-key}. To see the Url for your specific script, check the URL tab from the script view:

Unlike regular API scripts, External scripts can access further information about the HTTP request (including headers, method and post data) as well as have greater control over the format of the returned response.

To access data relating the HTTP request that invoked the script, you can use the ChilliConnect.External.Request object:

/**
 * Gets the URL of the request 
 */
var url = ChilliConnect.External.Request.getUrl();

/**
 * Gets the HTTP method of the request ("GET", "POST", etc.)
 */
var method = ChilliConnect.External.Request.getMethod();

/**
 * Gets a query parameter from the request
 */
var name = ChilliConnect.External.Request.getQueryParam("name");

By default, any response directly returned from the script will be JSON encoded, set as the response body, the Content-Type header set to application/json and the response status code set to 200. For example, the code:

return { "PlayerName" : "Test" };

Will return the HTTP response:

HTTP/1.1 200
Content-Type: application/json

{"PlayerName":"Test"}

This allows you to simply return the result of an existing ChilliConnect API call directly from your script as JSON:

return ChilliConnectSDK.Leaderboards.getScores("SCORES")

If you want more control of the HTTP response from an external script, you can use the ChilliConnect.External.Response object to specify the return code, body and headers. For example:

var response = ChilliConnect.External.Response;
response.setStatus(401);
response.setBody("<invalid/>");
response.addHeader("Content-Type", "application/xml");

return response;

The calls to the response object can also be chained:

return ChilliConnect.External.Response.setStatus(401)
    .setBody("<invalid/>")
    .addHeader("Content-Type", "application/xml");

The full documentation for ChilliConnect.External.Request and ChilliConnect.External.Response is below:

ChilliConnect.External.Request
Method Description
getUrl() Returns the Url the http request was made to.
getMethod() Returns the Http method used to invoke the external script.
getJson() Returns the JSON decoded version of the http response body.
getHeader( name ) Returns the value of the HTTP response header specific by name.
hasHeader( name ) Returns a boolean indicating wether or not the specified header was set in the HTTP response.
getHeaders() Returns all HTTP response headers as a Javascript Object.
getQueryParam( name ) Returns the value of the query parameter specified by name.
hasQueryParam( name ) Returns a boolean indicating whether or not the specified query parameter exists.
getQueryParams() Returns all query parameters as a Javascript Object.
getPostParam( name ) Returns the value of the post parameter specified by name.
hasPostParam( name ) Returns a boolean indicating whether or not the specified post parameter exists.
getPostParams() Returns all post parameters as a Javascript Object.
ChilliConnect.External.Response
Method Description
setStatus( code ) Sets the HTTP status code of the response.
setBody( body ) Sets the raw body of the request. If no Content-Type header has previously been set, this method will default to text/plain
setJson( json ) Sets the raw body of the request to the JSON encoded representation of the supplied json parameter. Will also set the Content-Type header to application/json
addHeader( name, value ) Adds a header to the request.
removeHeader( name ) Removes a header from the request.
addHeaders( headers ) Adds multiple headers to the the request. headers should be a Javascript Object where the property keys are the header names and the property values the header values. For example:
var request = ChilliConnect.Http.Request.addHeaders( {
    "Content-Type" : "text/xml",
    "X-Token" : "sometoken"
});
clearHeaders() Removes all previously set headers.

Like Scheduled scripts, external scripts are executed without a player context set. If you want to modify a player account, be sure to set the player context from your script.

Photon Callback Scripts

Photon Callbacks are a special type of external script that is designed to be used with Photon WebHooks. When creating a Photon Callback, you must also specify the specific Photon WebHook method. For more details, see our Photon Documentation.

Event Scripts

Event scripts allow you invoke custom logic on certain events in ChilliConnect. There are two general categories of events that are supported, API Events and System Events.

API Events

API Events are triggered when a specific ChilliConnect API method is called. This is useful in situations when you want to execute some custom logic after an API call has been successful - for example, when a new player is created, add them to a mailing list. API Event scripts are only executed after external API calls (not from Cloud Code calls) and are always executed under the context of the player that made the call. API Event scripts have access to the full request and response data from ChilliConnect via the ChilliConnect.Event.Request and ChilliConnect.Event.Response properties.

For example, the below script can be configured to run after the AsyncMultiplayer.submitTurn call to send out a Push Notification to the next player to take a turn.

/**
 * Get the updated match from the Request data
 */
var updatedMatchId = ChilliConnect.Event.Request.MatchID;

ChilliConnect.Logger.info( "Turn submitted for match:" + updatedMatchId );

/**
 * Get the updated match data from the Response data
 */ 
var updatedMatch = ChilliConnect.Event.Response.Match;

var ChilliConnectSDK = ChilliConnect.getSdk("2.0.0");

/**
 * Check updated state if match is still in progress
 */ 
var updatedState = updatedMatch.State;
if (updatedState == "IN_PROGRESS") { 

    /**
     * Get the next player
     */ 
    var nextPlayer = updatedMatch.CurrentTurn.PlayersWaitingFor[0].ChilliConnectID;

    ChilliConnectSDK.PushNotifications.sendToChilliConnectIds( 
        [nextPlayer], "It's your turn!", null, "Match Updated");

    ChilliConnectSDK.Logger.info( "Sent Push Notification to Player:" + nextPlayer);
}

API Event scripts are run asynchronously, so there may be a short delay between the API call being completed and the script being executed. API Event scripts will also only be run when the request is successful.

System Events

System Events are triggered based on background actions in ChilliConnect that are not the result of a direct API call. Currently, System Events are used to run custom logic when Asynchronous Multiplayer matches are about to or have timed out. The below events are provided:

Match Waiting Timed Out A match in the WAITING state has been timed out.
Match Waiting Timing Out A match in the WAITING state is about to be timed out.
Match Turn Timed Out A match in the IN_PROGRESS state has been timed out.
Match Turn Timing Out A match in the IN_PROGRESS state is about to be timed out.

For more details and code samples on these events, see the Asynchronous Multiplayer documentation

Module Scripts

Module scripts allow you to share code between multiple cloud scripts. Module scripts can be defined as JavaScript or as C#. In both cases, modules are loaded using the CommonJS module format. Note that before a module can be included in a script, it's code must first be published.

JavaScript Modules

JavaScript modules are defined much like other Cloud Code types by typing or pasting code in to the provided editor. The ChilliConnect object is not available within JavaScript modules, but can be passed in from your outer script to the module if required. Modules can be include using their Key. For example, if the below module code was added under a key LEADERBOARD_UTILS:

module.exports = {

    getTopScore : function (chilliConnect, leaderboardKey) {
        var scores = chilliConnect.Leaderboards.getScores(leaderboardKey);
        if ( scores.Total === 0 ) {
            return null;
        }

        return scores.Scores[0].Score;
    }
}

Other scripts could use the module like so:

var utils = require("leaderboard_utils");
return utils.getTopScore(ChilliConnect, "Test");

C# Modules

C# modules work differently to JavaScript modules. Rather than typing or pasting in code via the Dashboard, you instead upload one or more C# files that are then compiled and converted to JavaScript by ChilliConnect. You can include C# modules just as if they were JavaScript modules. For example, consider the below 2 C# source files:

Enums.cs

namespace RockPaperScissors
{
    namespace Enums
    {
        public enum Move
        {
            Rock,
            Paper,
            Scissors,
        };

        public enum Result
        {
            PlayerOneWin,
            PlayerTwoWin,
            Draw
        }

        public static class Extension
        {
            public static bool Beats(this Move move, Move other)
            {
                if (move == Move.Paper)
                {
                    return other == Move.Rock;
                }

                if (move == Move.Scissors)
                {
                    return other == Move.Paper;
                }

                if (move == Move.Rock)
                {
                    return other == Move.Scissors;
                }

                return false;
            }
        }
    }
}

Game.cs

using RockPaperScissors.Enums;
using System;

namespace RockPaperScissors
{    
    public class Game
    {
        public Result run(string player1Move, string player2Move)
        {
            Move player1 = (Move)Enum.Parse(typeof(Move), player1Move);
            Move player2 = (Move)Enum.Parse(typeof(Move), player2Move);

            if (player1 == player2)
            {
                return Result.Draw;
            }

            if (player1.Beats(player2))
            {
                return Result.PlayerOneWin;
            }

            return Result.PlayerTwoWin;
        }
    }
}

These can be uploaded to ChilliConnect by adding a new C# module and then selecting the "Upload Code" button:

From the resulting window, you can then press "Select Source Files" to open a file upload dialog that supports multi-select:

Once the code has been uploaded and compiled, you can then select "Publish" to make the code available to other scripts. Assuming the above code was added with the module key RPS, it could be called from another Cloud Code Script using the below code:

try {

    //Load C# Module
    var rps = require('rps');

    //Instantiate C# class
    var game = new rps.RockPaperScissors.Game();

    var result = game.run(
        ChilliConnect.Request.PlayerOneMove, 
        ChilliConnect.Request.PlayerTwoMove);

    if (result===rps.RockPaperScissors.Enums.Result.PlayerOneWin) {
        return "Player One Wins!";
    }

    if (result===rps.RockPaperScissors.Enums.Result.PlayerTwoWin) {
        return "Player Two Wins!";
    }

    return "Draw!";
}
catch(e) {
    return e.toString();
}

C# modules must be self-contained - each source class must only reference classes that are either part of the same module upload, or reference the .NET standard library.

If working in Unity, C# modules allow you to re-use code between your game and ChilliConnect. This is especially useful when you are wanting to implement server authoritative checks on both the client and within ChilliConnect. For example, you might want to have a validation method that checks leaderboard scores are within a certain range - using C# modules, you could run this code on both the client and ChilliConnect.

Support Scripts

Support scripts can be useful for fixing issues with individual player accounts, for example gifting currency or economy item. Support Scripts cannot be called directly from your game, only through the Player Details or the Code Details page. For running the script for a player see the Player Management documentation Parameters are defined and accessed the same way as with API scripts.

ScriptingAddSupport

Editor

The browser-based editor will show you syntax errors as well as providing JavaScript auto-complete. Expand and use the Params list in the top-right corner of the editor. Click on a parameter to insert it in the correct format at the current position of the cursor. Each new Script is created with an example to enable a quick start and how to call the ChilliConnect Cloud Code API.

ScriptingEditor

Once you are ready to start using your Script , select "Publish". For API scripts, publishing will create a read-only version of your Script that will be accessible by it's Key when calling Run Script. For Scheduled scripts, the first execution of the script will be scheduled.

You are able to continue working on your Script by editing the "Working Copy" version - and when ready Publish again which will supersede the previously published version. ChilliConnect stores a Working Copy, and up to 10 read-only versions of each Script.

Using the ChilliConnect API

From Cloud Code Scripts you can invoke any other ChilliConnect method, making Cloud Code ideal for extending ChilliConnect and adding your own custom functionality around existing endpoints. Methods are exposed via their module on the object returned from the ChilliConnect.getSdk method. For example, to call the Set Player Data method from a Cloud Code script, use the below code:

var ChilliConnectSDK = ChilliConnect.getSdk("2.0.0");
ChilliConnectSDK.CloudData.setPlayerData( "SOMEKEY", { "Value": "Test" } );

Combining different ChilliConnect methods using Cloud Code is extremely powerful and allows you to write server authoritative, custom functionality very quickly. As a basic example, the below script rewards the player with a random amount of in-game currency based on a Catalog Meta Data definition.


var ChilliConnectSDK = ChilliConnect.getSdk("2.0.0");

/**
 * COIN_CHEST is an Catalog Meta Data definition that is in the following
 * format:
 * 
 * {
 *   "Rewards": [
 *       5,
 *       10,
 *       100,
 *       500
 *   ]
 * }
 */
var chestConfigs = ChilliConnectSDK.Catalog.getMetadataDefinitions("COIN_CHEST");
if ( !chestConfigs || chestConfigs.length < 1) {
    return { "Error" : "Could not find meta data definition" };
}

/** 
 * Get the Meta Data part from the list of definitions 
 */
var rewards = chestConfigs.Items[0].CustomData.Rewards;

/** 
 * Assign the reward randomly based on one of the items 
 */
var rewardAmount = rewards[Math.floor(Math.random() * rewards.length)];

/** 
 * Add the reward to the players currency balance 
 */
ChilliConnectSDK.Economy.addCurrencyBalance( "COINS", rewardAmount )

/** 
 * Return the rewarded amount plus the new balance 
 */
return { 
    "Reward" : rewardAmount, 
    "Balances" : ChilliConnectSDK.Economy.getCurrencyBalance( ["COINS"] ) 
};

Methods will throw the same exceptions and return the same responses as they do when called via an SDK. There is a dedicated Cloud Script area of the API documentation that describes how to call each method from a Cloud Code script. From here, you can simply copy and paste the provided method signature in to your script to get started:

ScriptingDetails

Player Context

By default, API Scripts are executed under the context of the currently logged in player. Scheduled and External scripts are executed with no player context. In order to enable more complex scripts that can manipulate other player accounts, you can use the ChilliConnect.PlayerAccounts.AsPlayer method to run a callback function under a different player context. For example, the below script can be used to send a Push Notification to the player at the top of a leaderboard when their score is beaten:

var LeaderboardKey = "SCORES";

var error = null;
var topPlayer = null;
var addScoreResponse = null;

var ChilliConnectSDK = ChilliConnect.getSdk("2.0.0"); 

try {

    /**
     * Check if there is an existing top score and if there is, store the ChilliConnectID
     */
    var scores = ChilliConnectSDK.Leaderboards.getScores( LeaderboardKey );
    if ( scores.Total > 0 ) {
        topPlayer = scores.Scores[0].ChilliConnectID;
    }

    /**
     * Add the new score as usual
     */
    addScoreResponse = ChilliConnectSDK.Leaderboards.addScore( ChilliConnect.Request.Score, LeaderboardKey );

    var playerDetails = ChilliConnectSDK.PlayerAccounts.getPlayerDetails();

    /**
     * If the new score is top, and there was a previous score...
     */ 
    if ( addScoreResponse.GlobalRank === 1 && topPlayer !== null && playerDetails.ChilliConnectID !=topPlayer ) {

        /**
         * Send the displaced player a Push Notification
         */ 
        ChilliConnectSDK.PlayerAccounts.asPlayer( topPlayer, 
            function() {
                ChilliConnectSDK.PushNotifications.sendToPlayer( "{ 'message': 'Your top score was beaten!' } " );
            }
        );
    }

}
catch( e ) {
    error = e;
}

return {
    "Success"   : error === null,
    "Error"     : error,
    "Response"  : addScoreResponse
}

Modifying Arrays

Due to the way Script API responses are returned to Cloud Code arrays should be assigned to a local variable in order to be modified. See the example below:

var collectionKey = "MAPS";
var objectId = "56413f2a-c1f5-11e6-b05f-0a3391dcf55d";

var ChilliConnectSDK = ChilliConnect.getSdk("2.0.0"); 

/**
 * Returns
 * {...
 *      "Value" : {...
 *          "AvailableTo" : [ "Aztec", "Ocean" ]
 *      ...}
 * ...}
 */
var maps = ChilliConnectSDK.CloudData.queryCollection( collectionKey, "ObjectID = ':myObjectId'", { "myObjectId" : objectId });

if ( maps.Total == 1 ) {
    var mapAvailability = maps.Objects[0].Value.AvailableTo;

    //manipulate the array
    mapAvailability.push("Medieval");

    //update the Collection Object with the new array
    var mapUpdate = { "AvailableTo" : mapAvailability };
    ChilliConnectSDK.CloudData.updateCollectionObject( collectionKey, objectId, mapUpdate );
}

Underscore.js

ChilliConnect also provides access to the Underscore.js library within Cloud Code scripts. Underscore.js provides a long list of useful functional programming helpers that can simplify many common tasks when working in Javascript. As an example, the countBy method can be used in a single line script to return the total number of items grouped by type that a player owns:

return _.countBy( ChilliConnectSDK.Economy.getInventory().Items, function( item ) { return item.Key; } );

This would return:

{
 "Output": {
  "KEY": 24,
  "SHIELD": 17,
  "SWORD": 19
 }
}

Full documentation is available on the Underscore.js website.

Http Requests

In addition to calling the existing ChilliConnect API methods, Cloud Code scripts can also make external Http requests through the ChilliConnect.Http module. A new Http request object can be created by accessing the ChilliConnect.Http.Request property:

var request = ChilliConnect.Http.Request;

The request object can then be used to set headers, body and post parameters of the request:

/*
 * Set raw body
 */
request.setBody("<somebody>");

/*
 * Add a header
 */
request.addHeader("Content-Type", "application/xml");

/*
 * Set Post Parameter
 */
request.addPostParam("playerId", "SomeID");

/*
 * Set Query Parameter
 */
request.addQueryParam("platform", "ChilliConnect");

All methods that modify the request will also return the Request instance so calls can be chained:

var request = ChilliConnect.Http.Request.setBody("<somebody>")
    .addHeader("Content-Type", "application/xml")
    .addQueryParam("platform", "ChilliConnect");

To send the request, you can then call get, post, put or delete methods:

/*
 * Send HTTP get request
 */
var response = request.get("https://www.chilliconnect.com");

Requests return a response object, that can be used to retrieve information about the result of the request:

/* 
 * Get response Http status code 
 */
var status = response.getStatus();

/* 
 * Get the Content-Type of the response 
 */
var type = response.getHeader('Content-Type');

/* 
 * Get the body of the response 
 */
var type = response.getBody();

The full documentation for the Request and Response objects is described below

Http Request
Method Description
setBody( body ) Sets the raw body of the request. If no Content-Type header has previously been set, this method will default to text/plain
setJson( json ) Sets the raw body of the request to the JSON encoded representation of the supplied json parameter. Will also set the Content-Type header to application/json
addHeader( name, value ) Adds a header to the request.
removeHeader( name ) Removes a header from the request.
addHeaders( headers ) Adds multiple headers to the the request. headers should be a Javascript Object where the property keys are the header names and the property values the header values. For example:
var request = ChilliConnect.Http.Request.addHeaders( {
    "Content-Type" : "text/xml",
    "X-Token" : "sometoken"
});
clearHeaders() Removes all previously set headers.
addQueryParam( name, value ) Adds a query parameter that will be appended to the final request URL.
removeQueryParam( name, value ) Removes a query parameter from the request.
addQueryParams( queryParams ) Adds multiple query parameters to the request. queryParams should be a Javascript Object where the property keys are the parameter names and the property values the parameter values. For example:
var request = ChilliConnect.Http.Request.addQueryParams( {
    "platform" : "chilliconnect",
    "rating" : 10
});
clearQueryParams( queryParams ) Removes all previously set query params.
addPostParam( name, value ) Adds a post parameter to the request. If no Content-Type is explicitly set, adding a post parameter will cause the Content-Type to be set to application/x-www-form-urlencoded.
removePostParam( name ) Removes a post parameter from the request.
addPostParams( postParams ) Adds multiple post parameters to the the request. postParams should be a Javascript Object where the property keys are the parameter names and the property values the parameter values. For example:
var request = ChilliConnect.Http.Request.addPostParams( {
    "platform" : "chilliconnect",
    "rating" : 10
})
clearHeaders() Removes all previously set post parameters.
Http Response
Method Description
getBody() Returns the raw body of the http response as a string.
getJson() Returns the JSON decoded version of the http response body.
getStatus() Returns the HTTP status code of the response.
getHeader( name ) Returns the value of the HTTP response header specific by name.
hasHeader( name ) Returns a boolean indicating wether or not the specified header was set in the HTTP response.
getHeaders() Returns all HTTP response headers as a Javascript Object.

HTTP requests that result in a 4xx or 5xx response will return a normally populated ChilliConnect.Http.Response object with details.

HTTP requests made from Cloud Code Scripts may return a 9101 exception under the following circumstances;

  • Timeout
  • Connection timeout
  • Too many redirects

Details may be found in the data parameter of the exception.

In addition a 9102 exception may be thrown if a body and post parameters are attempted to be set on the same request, and a 9103 if a script attempts to call ChilliConnect.

Logging

All ChilliConnect Scripts have access to a Logger that helps development and debugging.

var score = ChilliConnectSDK.Leaderboards.getScore("AAA_LEADERBOARD")
ChilliConnect.Logger.info(score);

There are four log levels available; info, warn, error and debug. Logs for the last 24 hours can be found listed in the "Logs" tab from the script view. Scheduled scripts will automatically log when they start and end, as well as any exceptions or output returned from the script.

Note logs generated by a dashboard run are not persisted.

Error Handling

The ChilliConnect Scripting API in normal execution may return exceptions to your Script. For example the PlayerStorageWriteConflict:

var previousWriteLock = ChilliConnect.Request.PreviousWriteLock;
var level = ChilliConnect.Request.Level;

var ChilliConnectSDK = ChilliConnect.getSdk("2.0.0");

try {
    var newWriteLock = ChilliConnectSDK.CloudData.setPlayerData("ExperienceLevel", level, previousWriteLock);
}
catch(e)
{
    if(e.isChilliConnectError === true && e.code === 7001){
        ChilliConnect.Logger.error('WriteLockConflict');
        ChilliConnect.Logger.error(e.message);
        ChilliConnect.Logger.error(e.data);
    } else {
        ChilliConnect.Logger.error(e);
    }

    return { 'Success': false };
}

return { 'Success': true, 'WriteLock': newWriteLock };

The e.isChilliConnectError signifies the exception being from the API. For other exceptions such as if the Script does not compile this will be false.

Testing

The Run tab enables you to simulate a Run Script call to test your Script before publishing.

Parameter values can be supplied as defined in the Script configuration. For API scripts, the Player is the ChilliConnectID that the Run Script will be executed as. To create a test Player select the "Generate" just below. Note: To accurately simulate the Run Script call actions defined in the script will be executed for real, therefore it is important to use a Player set-up for testing purposes.

Upon selecting "Run" the request will be initiated and the Request, Response and Logs panels will be populated.

Working With Dates

Many ChilliConnect API calls accept dates or return dates. When calling API methods from CloudCode, dates will be returned as simple strings but can be parsed in to a JavaScript Date object to be manipulated. Date objects can also be converted to ISO-8601 date strings that can be provided to the ChilliConnect API.

For example, the below code shows the players last login time could be stored in player data, using JavaScript Date objects:

try {

/** Get current server time */    
var currentTime = new Date();

var lastLoginTime = null;

var ChilliConnectSDK = ChilliConnect.getSdk("2.0.0");

/** Load last login time from player data if set */
var playerData = ChilliConnectSDK.CloudData.getPlayerData(['LastLogin']);
if (playerData.Values.length > 0 ) {

    /** Player data value is returned as string, convert to date object */
    var lastLoginString = playerData.Values[0].Value;

    /** Can provided ChilliConnect dates to the Date constructor to parse */
    lastLoginTime = new Date(lastLoginString);
}
else {
    lastLoginTime = currentTime;
}

/** Update player last login time - toISOString() on the Date object will return a 
string that can be used as a ChilliConnect date. */
ChilliConnectSDK.CloudData.setPlayerData('LastLogin', currentTime.toISOString());

var milliSecondsDifference = currentTime - lastLoginTime;

}
catch( e)
{
    ChilliConnect.Logger.error("Error:" + e );
}

return { "CurrentTime" : currentTime.toISOString(), "LastLoginTime" : lastLoginTime.toISOString(), "DifferenceInMs" : milliSecondsDifference };

Troubleshooting

For security reasons, unexpected errors in Cloud Code are not exposed to end players. To make development and debugging of Cloud Code scripts easier, we recommend wrapping your scripts within a try/catch block and logging any unexpected errors using the ChilliConnect.Logger.error method:

try {
    var a ="test";

    //this will cause an error
    a.something();
}
catch( e ) {
    ChilliConnect.Logger.error(e.toString());
    return { "Error": true }
}

When executing this script through the test runner, the Logs panel will now show the below error: