# Using Lobby

> Use Cloud Code and Lobby service together to trigger server-side actions when players join lobbies.

You can use Lobby and Cloud Code together to define common triggers in games. Consider the situation where a game lobby is ready to start a match. You could trigger the following script in response to a game lobby becoming ready. This example also features integration with [Remote Config](/remote-config.md).

Before you follow this example, enable both Lobby and Cloud Code through the [Unity Dashboard](https://cloud.unity.com), and follow the steps to install the required SDKs. [Create a lobby](/lobby/create-a-lobby.md) in your project using service authentication, and note its [ID](https://cloud-code-sdk-documentation.cloud.unity3d.com/lobby/v1.0/lobby). You can do this through Cloud Code (check examples for [Unity Lobby](../how-to-guides/unity-services-integration#using-the-unity-lobby-sdk)).

The following example gives the script two parameters: the service ID used to create the lobby, and the lobby ID. We get the lobby and then update it with several changes to its metadata. These changes are:

* Locking the lobby so new players can no longer join.
* Constructing a random “player order” for the game by using the lobby’s player IDs.
* Randomly choosing a map for the game by using the `LOBBY_CURRENT_MAPS` config defined in Remote Config. The script returns a basic Boolean that indicates success or failure.

###### JavaScript

```js
const _ = require("lodash-4.17");
const { LobbyApi, DataObjectVisibilityEnum } = require("@unity-services/lobby-1.2");
const { SettingsApi } = require("@unity-services/remote-config-1.1");

module.exports = async ({ params, context, logger }) => {
  const { serviceId, lobbyId } = params;
  const { projectId, environmentId, playerId } = context;
  const lobbyApi = new LobbyApi(context);
  const remoteConfig = new SettingsApi(context);

  try {
    const { data: lobby } = await lobbyApi.getLobby(lobbyId, serviceId);
    return setUpGame(remoteConfig, projectId, environmentId, serviceId, lobbyApi, logger, lobby);
  } catch (err) {
    logger.error(`Failed to set up lobby: ${err.response.data.detail}`);
    return false;
  }
};

// Updates a lobby to set up for the start of a game, including reading a value from Remote Config to randomly assign to the lobby.
async function setUpGame(remoteConfig, projectId, environmentId, serviceId, lobbyApi, logger, lobby) {
  let playerIds = [];
  for (let i = 0; i < lobby.players.length; i++) {
    playerIds.push(lobby.players[i].id);
  }

  // Generate a turn order for the game by shuffling the player IDs.
  _.shuffle(playerIds);

  // Load all of the maps that are currently configured as available in Remote Config and pick a random one for this game.
  let maps = getCurrentMapsFromRemoteConfig(remoteConfig, projectId, environmentId);
  if (maps == null) {
    throw "Maps loaded from Remote Config are null.";
  }
  let gameMap = _.sample(maps);

  try {
    const updateResponse = await lobbyApi.updateLobby(lobby.id, serviceId, null, {
      isLocked: true, // Lock the lobby so that new players cannot join.
      hostId: playerIds[0], // Transfer host ownership from the service to one of the players.
      data: {
        playerOrder: {
          value: playerIds.toString(),
          visibility: DataObjectVisibilityEnum.Member, // Set the visibility of the player order so that only lobby members can access it.
        },
        map: {
          value: gameMap,
          visibility: DataObjectVisibilityEnum.Public, // Set the visibility of the game map so that anyone who views the lobby can access it.
        },
      },
    });

    return true;
  } catch (err) {
    throw err;
  }

  return lobbyUpdateSuccess;
}

// Loads the Remote Config JSON value for LOBBY_CURRENT_MAPS and returns the array of maps inside of it.
// If the JSON is invalid, the return value is null.
async function getCurrentMapsFromRemoteConfig(remoteConfig, projectId, environmentId) {
  const currentMapsId = "LOBBY_CURRENT_MAPS";
  const remoteConfigResponse = await remoteConfig.assignSettingsGet(projectId, environmentId, "settings", [currentMapsId]);

  let mapsJSON = remoteConfigResponse?.data?.configs?.settings?.[currentMapsId];
  if (!mapsJSON || !mapsJSON.maps || mapsJSON.maps.length == 0) {
    return null;
  }

  return mapsJSON.maps;
}

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   serviceId: { type: "String", required: true },
//   lobbyId: { type: "String", required: true },
// };
```

> **Note:**
>
> If you are using Unity Editor to manage your scripts, you can uncomment the code at the bottom of the script to declare the required `serviceId` and `lobbyId` parameters in-script.
> To learn more about how to manage in-script parameters, refer to Modify script parameters within the [Unity Editor](../how-to-guides/write-scripts/unity-editor#modify-script-parameters).

The Remote Config JSON here has a simple structure, but you can extend this example configuration to achieve more fine-grained control over your game. Likewise, there are a number of different triggers for Cloud Code that you might want to consider in addition to game setup, for example:

* Triggering on lobby creation to adjust metadata values and sanitize strings.
* Using Cloud Save player data to filter a player’s query results, approve/deny a join, and set metadata.
* Using Economy data to set player or lobby metadata.
