Script structure

The main function in a Cloud Code script that acts as the entry point of the runtime takes the form of a CommonJS wrapper.

The following code snippet shows the simplest possible script:

JavaScript

module.exports = async ({ params, context, logger }) => {
  // this script does nothing
};

While this script doesn’t actually do anything, it shows the context object and asynchronous nature of the script function.

Note: A script is invalid unless it exports a CommonJS function.

Note: Script names must be unique across the project and environment, only contain letters, numbers, underscores and dashes, and not exceed 50 characters.

Context object

The context object contains these useful objects:

  • Params: This is an array of name-value pairs of the input parameters with which a script is called.

  • Context: This object provides additional context that is useful within a script:

    • projectId: The project ID to which the caller was authenticated.
    • playerId: The authenticated player ID.
    • accessToken: A JWT that can be used to call other Unity game services SDKs as the authenticated player.
    • environmentName: The name of the currently used Unity environment.
    • environmentId: The ID of the currently used Unity environment.
    • serviceToken: A JWT used to call other Unity game services SDKs as an authenticated Cloud Code user.
    • unityInstallationId: Unique identifier that identifies an installation on the client’s device. The same player can have different installationIds if they have the game installed on different devices. It is available to all Unity packages that integrate with the Services SDK Core package.
    • analyticsUserId: A unique string that identifies the player and is consistent across their subsequent play sessions for analytics purposes. It is the primary user identifier and it comes from the Core package.
    • correlationId: Unique identifier used to correlate requests.
  • Logger: An object that allows the script to log info, warnings, and errors.

JavaScript

module.exports = async ({logger}) => {
  logger.info('This message confirms that the logging client is functional!');
  logger.warning('This is a serious warning that the cheese is about to run out.');
  logger.error('Out of cheese :(');
}

Refer to the Logging documentation for more information.

Token authentication

The accessToken and serviceToken are JWTs, provided as properties of the context object.

These tokens authenticate calls to other Unity Gaming Services from Cloud Code.

Token typeOriginData accessUsage
accessTokenGenerated by the Authentication serviceRestricted to the authenticated playerThe accessToken is the JWT the Cloud Code call is authenticated with. It can be passed onto other UGS services to access data for the authenticated player
serviceTokenGenerated by Cloud CodeAllows cross-player data accessThe serviceToken is Cloud Code generated token that can be used to call out to other UGS services and interact with cross-player data

Any configured Access Control rules affect the accessToken.

Below is an example of how to use the accessToken to call the Economy SDK to get the player's inventory.

JavaScript

// Player inventory
const { InventoryApi } = require("@unity-services/economy-2.4");

module.exports = async ({params, context, logger}) => {
 const { projectId, playerId, accessToken } = context;
 const inventory = new InventoryApi({accessToken});
 const result = await inventory.getPlayerInventory({projectId, playerId});
 return result.data;
}

If you want to use serviceToken, the same script would look like this:

JavaScript

// Player inventory
const { InventoryApi } = require("@unity-services/economy-2.4");

module.exports = async ({params, context, logger}) => {
const { projectId, playerId } = context;
const inventory = new InventoryApi(context);
const result = await inventory.getPlayerInventory({projectId, playerId});
return result.data;
}

Refer to Service and access tokens for an in-depth explanation of the differences between the two tokens.

Script parameters

Script parameters can be defined outside or inside the script body.

Note: In-script parameters offer a simpler alternative to declaring parameters, but the Unity Cloud Dashboard does not currently parse in-script parameters if you try to update them without using the Deployment package.

In-script parameters

In-script parameters can be added by exporting the params object, containing each parameter name as a key, and its type as a value.

Important: You must assign the module.exports property before setting the parameters.

For example:

JavaScript

module.exports.params = { "echo" : "Boolean" }

Alternatively, if you'd like to specify that a parameter is required, you may specify an object containing both the type and required properties.

JavaScript

module.exports = async ({ params, context, logger }) => {
    return {
        "value": params["aParam"]
    };
};

module.exports.params = { "aParam" : { "type": "String", "required": true } }

By default, parameters are not required.

Both formats can be combined as desired:

JavaScript

module.exports = async ({ params, context, logger }) => {
    var value = params["echo"] ? params["aParam"] : "default";
    return {
        "value": value
    };
};

module.exports.params = {
  "echo" : "Boolean",
  "aParam" : { "type": "String", "required": true }
 }

Async/await

The main script function can be an asynchronous function. This means that a function can await promises, which enables the use of other Unity game service SDKs within the script. Check the Mozilla documentation describing promises.

A trivial example looks like the following:

JavaScript

// Player inventory
const { InventoryApi } = require("@unity-services/economy-2.4");

module.exports = async ({params, context, logger}) => {
 const { projectId, playerId } = context;
 const inventory = new InventoryApi(context);
 const result = await inventory.getPlayerInventory({projectId, playerId});
 return result.data;
}

Note: Cloud Code client-side calls are always asynchronous, with both regular (synchronous) and asynchronous scripts.

Additional packages

Your scripts can import local scripts or external packages with the import or require keywords.

Refer to the Available packages for a full list that can be imported.

JavaScript

const _ = require("lodash-4.17");

module.exports = async () => {
  return _.random(1, 6);
};

Note: Required packages must be declared outside of the exported function.

Bundling

Note: The Unity Cloud Dashboard and CLI do not currently fully support bundled scripts.

Script bundling is a feature enabled by using the Deployment package within the Unity Editor to help manage your scripts locally, unlock additional workflows and enables common functionality to be shared across multiple scripts. Refer to the JS bundles documentation for details on how to generate bundled scripts.

JavaScript

const lib = require("./lib");

module.exports = async () => {
  return lib.helloWorld();
};

module.exports.bundled = true;

Output

Script output can consist of the following types:

JavaScript

  • string
    module.exports = async () => {
      return "hello world";
    };
  • boolean
    module.exports = async () => {
      return true;
    };
  • number
    module.exports = async () => {
      return 3.14;
    };
  • object
    module.exports = async () => {
      return {
        message: "hello world",
        success: true
      };
    };

Successful responses are returned from the API as JSON with the following structure:

{
  "output": <SCRIPT OUTPUT>
}

Error output

Errors can be thrown by scripts when something causes the invocation to fail for example, a failed service request.

Catching errors within your scripts allows you to determine how the failure should be handled.

JavaScript

module.exports = async ({logger}) => {
  try {
    let result = service.call("example");
    return result;
  } catch (err) {
    logger.error("Something went wrong!", {"error.message": err.message});
    throw err;
  }
};

Error responses are returned from the API as JSON with error details containing the error type, error message and a stack trace to help identify the cause of the error.

{
  "type": "problems/invocation",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Invocation Error",
  "instance": null,
  "code": 9009,
  "details": [
      {
          "name": "ReferenceError",
          "message": "service is not defined",
          "stackTrace": [
              "at module.exports (example-test.js:1:26)"
          ]
      }
  ]
}