# Use case sample: Send a push message to the player whose score was beaten

> Send a push message to a player whose leaderboard score was beaten by another player.

The use case sample demonstrates how to use Triggers to send a push message to a player whose score was beaten in a leaderboard. The sample uses the `score-submitted` event from the [Leaderboards service](/leaderboards.md).

> **Note:**
>
> You can only use [push messages](/cloud-code/modules/how-to-guides/push-messages.md) with Cloud Code modules.

## Prerequisites

You must first create a service account with required access roles and configure the [UGS CLI](https://services.docs.unity.com/guides/ugs-cli/latest/general/get-started/install-the-cli/).

### Authenticate using a Service Account

Before you can call the Triggers service, you must authenticate using a Service Account.

1. Navigate to the [Unity Dashboard](https://cloud.unity.com).
2. Select **Administration** > **Service Accounts**.
3. Select the **New** button and enter a name and description for the Service Account.
4. Select **Create**.

Add Product roles and create a key:

1. Select **Manage product roles**.
2. Add the following roles to the Service Account:
   * From the LiveOps dropdown, select **Triggers Configuration Editor**, **Triggers Configuration Viewer**, and **Leaderboards Admin**.
   * From the Admin dropdown, select **Unity Environments Viewer**.
3. Select **Save**.
4. Select **Add Key**.
5. Encode the **Key ID** and **Secret key** using base64 encoding. The format is “key\_id:secret\_key”. Note this value down.

For more information, refer to [Authentication](../../authentication).

### Configure the UGS CLI

Follow the steps below to get stated with the UGS CLI:

1. [Install the UGS CLI](https://services.docs.unity.com/guides/ugs-cli/latest/general/get-started/install-the-cli/).

2. Configure your Project ID and Environment as such:
   `ugs config set project-id <your-project-id>`
   `ugs config set environment-name <your-environment-name>`

3. Authenticate using the Service account you created earlier. Refer to [Get Authenticated](https://services.docs.unity.com/guides/ugs-cli/latest/general/get-started/get-authenticated/).

## Set up Leaderboards

To follow this sample, you should create a leaderboard.

You can use the UGS CLI to deploy the following `leaderboard.lb` file. It defines a leaderboard with ascending sort order and keeps the best score.

Run the `new-file` command to create a leaderboard configuration locally:

```bash
ugs leaderboards new-file leaderboard
```

The file name corresponds to the leaderboard ID. Update the `leaderboard.lb` file with the following configuration:

```json
{
  "$schema": "https://ugs-config-schemas.unity3d.com/v1/leaderboards.schema.json",
  "SortOrder": "asc",
  "UpdateType": "keepBest",
  "Name": "leaderboard"
}
```

Deploy the file using the UGS CLI tool:

```bash
ugs deploy leaderboard.lb
```

Now that you have created a leaderboard, you can add scores to it.

### Optional: Add scores to the leaderboard

You can run the following Cloud Code script to add scores to the leaderboard from the [Unity Dashboard.](https://cloud.unity.com)
Make sure to select the **Generate** icon to regenerate the Player ID token on every test run to generate a score for a new player.

#### JavaScript

```javascript
const { LeaderboardsApi } = require("@unity-services/leaderboards-1.1");
const _ = require("lodash-4.17");

module.exports = async ({ params, context, logger }) => {
  const leaderboardsApi = new LeaderboardsApi({ accessToken: context.accessToken });
  const leaderboardID = "leaderboard";

  var randomScore = _.random(1, 100);
  try {
    await leaderboardsApi.addLeaderboardPlayerScore(context.projectId, leaderboardID, context.playerId, { score: randomScore });
  } catch (err) {
    logger.error("Failed to add score to the leaderboard", { "error.message": err.message });
  }
};
```

## Examine the `score-submitted` event

The Leaderboards service emits a `score-submitted` event when a new score is submitted to a leaderboard. The event payload looks like this:

```json
{
  "leaderboardId": "leaderboard",
  "updatedTime": "2019-08-24T14:15:22Z",
  "playerId": "5drhidte8XgD4658j2eHtSljIAzd",
  "playerName": "Jane Doe",
  "rank": 42,
  "score": 120.3,
  "tier": "gold"
}
```

The event passes the event payload to Cloud Code as parameters.

Refer to [Leaderboards: Score Submitted](../../manage-events/supported-ugs-events#score-submitted) for more information.

## Set up Cloud Code

Define a module endpoint that sends a push message to the player whose score was beaten.

Create a `SendPushNotification` module function with contents as below:

```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Unity.Services.CloudCode.Apis;
using Unity.Services.CloudCode.Core;
using Unity.Services.CloudCode.Shared;

namespace LeaderboardsNotification;

public class LeaderboardsNotification
{
    private readonly ILogger<LeaderboardsNotification> _logger;

    public LeaderboardsNotification(ILogger<LeaderboardsNotification> logger)
    {
        _logger = logger;
    }

    [CloudCodeFunction("SendPlayerMessage")]
    public async Task SendPlayerMessage(IExecutionContext context, IGameApiClient gameApiClient, IPushClient pushClient, string playerId, string playerName,
        string leaderboardId, double score)
    {
        try
        {
            var closestPlayers = await gameApiClient.Leaderboards.GetLeaderboardScoresPlayerRangeAsync(context,
                context.ServiceToken, new Guid(context.ProjectId), leaderboardId, playerId, 1);

            if (closestPlayers.Data.Results.Count != 0)
            {
                var player = closestPlayers.Data.Results[^1];
                string message =
                    $"The player {playerName} has just beaten your score of {player.Score} on the {leaderboardId} leaderboard by {score-player.Score} points!";

                await pushClient.SendPlayerMessageAsync(context, message, "Information", player.PlayerId);
            }
        }
        catch (ApiException e)
        {
            _logger.LogError("Failed to send push notification to player {playerId}. Error: {Error}", playerId, e.Message);
            throw new Exception($"Failed to send push notification to player {playerId}. Error: {e.Message}");
        }
    }
}


public class ModuleConfig : ICloudCodeSetup
{
    public void Setup(ICloudCodeConfig config)
    {
        config.Dependencies.AddSingleton<IPushClient>(PushClient.Create());
        config.Dependencies.AddSingleton<IGameApiClient>(GameApiClient.Create());
    }
}
```

Deploy the module.

Refer to [Deploying Hello World](/cloud-code/scripts/getting-started.md#deploying-hello-world) to learn how to deploy a module.

> **Note:**
>
> If you are deploying the module using the UGS CLI, don't forget to add additional Service Account role of `Cloud Code Editor`.

## Configure a trigger

To connect your Cloud Code resource to the Leaderboards `score-submitted` event, create a trigger. The trigger executes the Cloud Code module when the event is fired, for example, every time a new score is submitted.

Run the `new-file` command to create a trigger configuration locally:

```bash
ugs triggers new-file triggers-config
```

Update the `triggers-config.tr` file with the following configuration:

```json
{
  "$schema": "https://ugs-config-schemas.unity3d.com/v1/triggers.schema.json",
  "Configs": [
    {
      "Name": "score-beaten-message",
      "EventType": "com.unity.services.leaderboards.score-submitted.v1",
      "ActionUrn": "urn:ugs:cloud-code:LeaderboardsNotification/SendPlayerMessage",
      "ActionType": "cloud-code"
    }
  ]
}
```

Deploy the configuration using the UGS CLI tool:

```bash
ugs deploy triggers-config.tr
```

A successful response is similar to the following:

```text
Deployed:
    triggers-config.tr
```

The sample trigger executes your Cloud Code module function when a player signs up.

## Validate the result

To validate the result, you can set up a Unity project that subscribes to push messages and use the [Cloud Code script you created earlier](#optional:-add-scores-to-the-leaderboard) to submit a new score to the leaderboard.

### Prerequisites

To subscribe to push messages, you need to install the Cloud Code SDK and link your [Unity Gaming Services project](/cloud/projects.md) to the Unity Editor.

#### Link project

Link your [Unity Gaming Services project](/cloud/projects.md) with the Unity Editor. You can find your UGS project ID in the [Unity Dashboard](https://cloud.unity.com).

1. In Unity Editor, select **Edit** > **Project Settings** > **Services**.

2. Link your project.
   If your project doesn't have a Unity project ID:

   1. Select **Create a Unity Project ID** > **Organizations**, then select an organization from the dropdown.
   2. Select **Create project ID**.

   If you have an existing Unity project ID:

   1. Select **Use an existing Unity project ID**.
   2. Select an organization and a project from the dropdowns.
   3. Select **Link project ID**.

Your Unity Project ID appears, and the project is now linked to Unity services. You can also access your project ID in a Unity Editor script using `UnityEditor.CloudProjectSettings.projectId`.

#### SDK installation

To install the latest Cloud Code package for Unity Editor:

1. In the Unity Editor, open **Window** > **Package Manager**.
2. In the Package Manager, select the **Unity Registry** list view.
3. Search for `com.unity.services.cloudcode`, or locate the Cloud Code package in the list.
4. Select the package, then select **Install**.

> **Note:**
>
> Check [Unity - Manual: Package Manager window](https://docs.unity3d.com/Manual/upm-ui.html) to familiarize yourself with the Unity Package Manager interface.

> **Note:**
>
> You can subscribe to messages with Cloud Code SDK versions 2.4.0+.

### Create a `Monobehaviour` script

To subscribe to player-level messages, set up a `Monobehaviour` script.
Refer to [Send push messages](/cloud-code/modules/how-to-guides/push-messages.md) for more information.

You can use the sample code below for your `MonoBehaviour` script:

```csharp
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Unity.Services.Authentication;
using Unity.Services.CloudCode;
using Unity.Services.CloudCode.Subscriptions;
using Unity.Services.Core;
using UnityEngine;

namespace CloudCode
{
	public class CloudCodePushExample : MonoBehaviour
	{
    	async void Start()
        {
            await UnityServices.InitializeAsync();
            await AuthenticationService.Instance.SignInAnonymouslyAsync();
            Debug.Log(AuthenticationService.Instance.PlayerId);
            await SubscribeToPlayerMessages();
        }

        // This method creates a subscription to player messages and logs out the messages received,
        // the state changes of the connection, when the player is kicked and when an error occurs.
        Task SubscribeToPlayerMessages()
        {
            // Register callbacks, which are triggered when a player message is received
            var callbacks = new SubscriptionEventCallbacks();

            callbacks.MessageReceived += @event =>
            {
                Debug.Log(DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK"));
                Debug.Log($"Got player subscription Message: {JsonConvert.SerializeObject(@event, Formatting.Indented)}");
            };

            callbacks.ConnectionStateChanged += @event =>
            {
                Debug.Log($"Got player subscription ConnectionStateChanged: {JsonConvert.SerializeObject(@event, Formatting.Indented)}");
            };

            callbacks.Kicked += () =>
            {
                Debug.Log($"Got player subscription Kicked");
            };

            callbacks.Error += @event =>
            {
                Debug.Log($"Got player subscription Error: {JsonConvert.SerializeObject(@event, Formatting.Indented)}");
            };

            return CloudCodeService.Instance.SubscribeToPlayerMessagesAsync(callbacks);
        }
	}
}
```

The first time you run the `Monobehaviour` script, it logs a player ID. You can modify your [Cloud Code script](#optional:-add-scores-to-the-leaderboard) to submit a score for the specified ID to add the player to the leaderboard.

Run the script again to generate scores for the leaderboard.

You should encounter a push message sent when your player score is beaten in the Unity Editor:

```yaml
Got player subscription Message:
  {
    "data_base64": <BASE64-ENCODED-DATA>,
    "time": "2023-09-19T10:26:40.436878688Z",
    "message": "The player AdjacentMowingToga#7 has just beaten your score of 120.3 on the my-leaderboard leaderboard by 51.3 points!",
    "specversion": "1.0",
    "id": <ID>,
    "source": "https://cloud-code.service.api.unity.com",
    "type": "com.unity.services.cloud-code.push.v1",
    "projectid": <PROJECT-ID>,
    "environmentid": <ENVIRONMENT-ID>,
    "correlationid": <CORRELATION-ID>,
    "messagetype": "Information",
  }
```
