Skip to content

Activities Dedicated Server Flow

kandelon edited this page Mar 8, 2018 · 1 revision

An approach to creating and running an Activity Occurrence. This flow relies on a dedicated 3rd game server(s) making calls with limited permission. This is accomplished by giving the server it's own user account, having it authenticate and run the game as the "host", without being a player itself. In this example we also cover allowing users to join a game already in progress and style a flow where the game is constantly running new rounds. The 3rd party server is tasked with reporting game results and starting up a new occurrence for each round (unless simply running one never ending occurrence with no final scores).

Table of Contents

Overview

General Flow

We will be creating an occurrence as the user "redwidgetuser1", who in this scenario we will pretend is being used by a 3rd party server set up by a group of users. The server will set the status straight into "PLAYING" without any players, and then "redwidgetuser2", "redwidgetuser3" and "redwidgetuser4" will find and join the game. Redwidgetuser3 will leave part way into the game. The round will end and report the results. Immediately afterwards the server will create the next occurrence and the remaining users will join it to continue playing. This flow lends itself to a an ongoing action game like a first person shooter where "clans" might set up their own customer servers that continually run games while players browse a server list and jump in and out at will.

Setup and Settings

  • Create an Activity with appropriate settings. In addition to setting up game specific needs (min/max players. join_in_play, custom settings, etc) set these as follows to prevent deviation from this flow (if more than one flow is supported, or some deviations are intended, set settings here to allow for the loosest of those):
    • results_trust: "host". This will prevent other users from reporting their own results so only the host server (or admins) can.
    • custom_launch_address_allowed: true. This will allow the host to injecting their own game server address.
    • host_status_control: true. This will allow the host from changing the game status after it launches.
    • host_option: "non_player". This will allow users (including servers) to start their own games as host, without require them to also be a participant in the game.
    • min_players: 0 to allow the game to "start" without any players connected when the server first comes up.
    • join_in_play: true. Allows users to join the game even when the status is PLAYING.
    • leave_in_play: true. Allows users to leave the game even when the status is PLAYING.
    • boot_in_play: true. Allows host to boot/ban player from the game even when the status is PLAYING.
  • The 3rd party server will need to register a user account, possibly tagged as a server to allow filtering, and get Authenticated using that account and handle token expiration gracefully by re-authenticating.

Flow Diagram

Activity Trusted Server Flow

Example Calls

The following calls simulate the flow described above. Each could be called in sequence as described, though some might be called multiple times in practice if more than 1 player joins the game or settings are changed repeatedly, etc.

Creating an Occurrence

The host server, "redwidgetuser1" in this case, makes the call to create the occurrence and lists itself as "host" to prevent being added as a player. It also sets the status to "PLAYING" right in the initial call as it is ready for players to connect and play immediately. API Documentation

POST [YOUR_URL]/activity-occurrences

request body:

{
  "activity_id": 1,
  "core_settings": {
    "boot_in_play": true,
    "custom_launch_address": "123.456.78.90",
    "host_status_control": true,
    "join_in_play": true,
    "leave_in_play": true,
    "min_players": 0,
    "max_players": 4,
    "non_host_status_control": false,
    "results_trust": "host"
  },
  "host": 3,
  "settings": [
    {
      "key": "difficulty",
      "value": "easy"
    }
  ],
  "simulated": false,
  "status": "PLAYING",
  "users": [
  ]
}

response:

{
    "id": 5,
    "activity_id": 1,
    "event_id": null,
    "challenge_activity_id": null,
    "created_date": 1519316384,
    "start_date": null,
    "updated_date": 1519316384,
    "status": "PLAYING",
    "core_settings": {
      "boot_in_play": true,
      "custom_launch_address": "123.456.78.90",
      "host_status_control": true,
      "join_in_play": true,
      "leave_in_play": true,
      "min_players": 0,
      "max_players": 4,
      "non_host_status_control": false,
      "results_trust": "host"
    },
    "settings": [
        {
            "key": "difficulty",
            "key_name": "Difficulty Level",
            "value": "easy",
            "value_name": "easy"
        }
    ],
    "reward_status": "pending",
    "users": [
    ],
    "entitlement": null,
    "simulated": false,
    "bans": [],
    "host": {
      "id": 3,
      "display_name": "Red Widget User 1",
      "avatar_url": null,
      "username": "redwidgetuser1"
    }
}

Listing Occurrences

Users can then list the playing games for the activity to find one to join.

API Documentation

GET [YOUR_URL]/activity-occurrences?filter_activity=1&filter_status=PLAYING&size=10&page=1

response:

{
    "content": [
        {
            "id": 5,
            "activity_id": 1,
            "event_id": null,
            "challenge_activity_id": null,
            "created_date": 1519316442,
            "start_date": null,
            "updated_date": 1519316442,
            "status": "PLAYING",
            "core_settings": {
              "boot_in_play": true,
              "custom_launch_address": "123.456.78.90",
              "host_status_control": true,
              "join_in_play": true,
              "leave_in_play": true,
              "min_players": 0,
              "max_players": 4,
              "non_host_status_control": false,
              "results_trust": "host"
            },
            "settings": [
                {
                    "key": "difficulty",
                    "key_name": "Difficulty Level",
                    "value": "easy",
                    "value_name": "easy"
                }
            ],
            "reward_status": "pending",
            "users": [
            ],
            "entitlement": null,
            "simulated": false,
            "bans": [],
            "host": {
              "id": 3,
              "display_name": "Red Widget User 1",
              "avatar_url": null,
              "username": "redwidgetuser1"
            }
        }
    ],
    "last": true,
    "total_elements": 1,
    "total_pages": 1,
    "sort": null,
    "first": true,
    "number_of_elements": 1,
    "size": 10,
    "number": 0
}

Joining an Occurrence

A user, "redwidgetuser2" in this case, chooses to join the game and connects to the server immediately afterwards as the status is already "PLAYING". If adding oneself (ACTIVITIES_ADMIN permission required to add others) the request body is optional. "redwidgetuser3" and "redwidgetuser4" join in this way as well.

API Documentation

POST [YOUR_URL]/activity-occurrences/5/users

response:

{
    "user": {
        "id": 5,
        "display_name": "Red Widget User 2",
        "avatar_url": null,
        "username": "redwidgetuser2"
    },
    "joined_date": 1519318791,
    "left_date": null,
    "status": "present",
    "host": false,
    "metric": null
}

Leaving an occurrence

redwidgetuser3 and is done for the night and decides to leave the game.

API Documentation

DELETE [YOUR_URL]/activity-occurrences/5/users/me

no body for request or response if successful

Booting from an occurrence

redwidgetuser4 hard disconnects from the game, so the server boots them to make room.

API Documentation

DELETE [YOUR_URL]/activity-occurrences/5/users/6

no body for request or response if successful

Reporting Results

When the round is over, the server calls to end the occurrence and report player scores. It can then immediately go back to "creating an occurrence" to start the next round and the already connected user "redwidgetuser2" can join the new round's occurrence to continue playing. If there are no rounds or scores but rather endless play, this step is unneeded.

API Documentation

POST [YOUR_URL]/activity-occurrences/5/results

request body:

{
  "users": [
    {
      "score": 11,
      "user_id": 4
    }
  ]
}

response:

{
    "users": [
        {
            "rank": 1,
            "user": {
                "id": 4,
                "display_name": "Red Widget User 2",
                "avatar_url": null,
                "username": "redwidgetuser2"
            },
            "score": 11,
            "updated_date": 1519333078,
            "item_rewards": null,
            "currency_rewards": null,
            "tags": null,
            "ties": 1
        }
    ]
}
Clone this wiki locally