# Server Browser

This SDK is an optional starter kit for Unity users, which can be extended and customized later.

## 💡 Features

Gain access to prebuilt automated features by installing our SDK:

{% columns %}
{% column %}

* Complete Examples
* Lifecycle Management
* Capacity Management
  {% endcolumn %}

{% column width="33.33333333333333%" %}

* Filter Query Compiler
* Type Definitions (C#)
* Local Dev Testing
  {% endcolumn %}

{% column width="33.33333333333333%" %}

* Cross-Platform
* Easy to Customize
* Automated Retry
  {% endcolumn %}
  {% endcolumns %}

## ✔️ Preparation

This plugin has been tested, and supports Unity versions 2021.3.0f1+, including Unity 6 LTS.

{% hint style="success" %}
This plugin is provided 100% free of charge, under Terms and Conditions of Free Tier.
{% endhint %}

#### Requirements

<details>

<summary>Install a Git Client (for example <a href="https://git-scm.com/">git-scm</a>)</summary>

A git client is needed for Unity to download and install our Unity package automatically. You will not need to use git directly once it's installed.

</details>

#### Installation

1. Open your Unity Project,
2. Select `Window > Package Management > Package Manager` ,
3. Click the :heavy\_plus\_sign: icon and select `Add package from git URL...` ,
4. Input the URL of our SDK when prompted:

{% code title="" %}

```
https://github.com/edgegap/edgegap-unity-sdk.git
```

{% endcode %}

5. Click `Add`  and wait until installation is completed.

#### Import Samples

This package includes multiple samples, intended to be used individually (do not combine samples).

#### Verified Sources

This is the only official distribution channel for this SDK, do not trust unverified sources!

#### Update Package

Navigate to Edgegap SDK in Unity Package Manager and click `Update` .

{% hint style="warning" %}
**Imported Samples are not updated automatically!** Back up any custom property values, delete the sample scripts used in your scene currently and re-import samples.
{% endhint %}

{% hint style="info" %}
Some releases may contain breaking changes. This will be indicated by a new MAJOR version.
{% endhint %}

#### Updating to v3

This update includes many new [Server Browser](/unity/server-browser.md) utilities and examples, improves matchmaking error handling, and more. See [Release Notes](/docs/release-notes.md) for a complete list.

{% hint style="warning" %}
Unity SDK update v3 includes a few breaking changes. Please re-test your integration carefully.
{% endhint %}

## 🍀 Getting Started

This guide assumes basic knowledge of [Server Browser](/learn/server-browser.md) concepts and a running Server Browser.

{% hint style="success" %}
**We strongly recommend importing our Auto-Assign Example** to follow along code as you read this document. You can do so in `Unity Package Manager > Edgegap SDK > Samples` .
{% endhint %}

### Overview

Our SDK utilizes heavily [Dependency Injection](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection/overview#the-concept) and [Observer](https://learn.microsoft.com/en-us/dotnet/standard/events/observer-design-pattern) programming patterns.

{% hint style="info" %}
This package integrates both [Server Browser](/learn/server-browser.md) and [Matchmaking](/learn/matchmaking.md), which can be used together or separately. You may freely reuse any scripts for your own customized forks and integrations.
{% endhint %}

This package includes:

* Runtime Files - will be compiled and bundled with your client and server builds:
  * Service-Specific Utilities:
    * [#server-agent](#server-agent "mention") - a complete server integration to reuse/extend.
    * [#client-agent](#client-agent "mention") - a complete client integration to reuse/extend.
    * API functions - endpoint definitions, error handling, and logging automations.
    * Filter Compiler - strongly typed utilities for building filter queries.
  * Service-Specific DTOs[^1] - typed data containers for Server Browser API.
  * Shared Utilities - logging, HTTP, ping, observables, etc...
  * Shared DTOs[^1] - used by multiple Edgegap services to pass data around.
* Sample Files - bundled and compiled ONLY if imported in your project:
  * [#auto-assign](#auto-assign "mention") - example handlers with auto-assigned reservations,
  * [#custom-search](#custom-search "mention") - example handlers with manual instance choice.

### Server Agent

**Server Lifecycle and Capacity management** are performed by Server Agent.

Once instantiated, agent's **parent Monobehaviour (handler) must initialize the agent** and provide:

* `onMonitorUpdate`  callback - observe service health changes,
* `onInstanceUpdate`  callback - observe and react to instance and slot changes,
* `onConfirmationsUpdate`  callback - observe and react to federated authentication.

Once initialized, this agent will automatically provide validations and hook up logging observers, finishing with a single call to the monitoring API endpoint to indicate service health.

Agent's handler is expected to take control and call agent functions from this point:

* `DiscoverInstance`  to create initial Server Instance and Slots and initiate heartbeat,
* `DeleteInstance`  once the match concludes / to prevent new players from joining,
* `ConfirmReservation`  when players join, to verify their identity and slot assignment,
* `UpdateSlot`  to update slot capacity (on player joined/abandoned) or modify metadata,
* `UpdateInstance`  to modify instance metadata,
* `Status`  to verify Server Browser service health.

{% hint style="success" %}
Confirmations and Slot/Instance Updates are **queued and performed in batches by default** (Heartbeat Mode) to maximize scalability. To iterate quicker during dev testing, use Greedy Mode.
{% endhint %}

{% hint style="warning" %}
**When updating metadata, all indices must be defined.** To unset non-indexed keys, simply omit them.
{% endhint %}

The agent automatically maintains a heartbeat to keep the server discoverable while running. If the agent can't reach your server browser for several consecutive heartbeats (configurable):

* less than maximum - instance will be automatically re-discovered,
* more than maximum - instance will be automatically deleted.

When a new player connection is established, player is expected to send their reservation ID (third party player ID) to the game server using your netcode, to perform reservation confirmation.

Once `onConfirmationsUpdate`  triggers, handler must perform additional actions:

* call `UpdateSlot`  to reduce available seats for any slots with confirmed reservations,
* accept or deny connection using netcode-specific methods.

When a player abandons game, handler is expected to increase available seats for this slot.

{% hint style="info" %}
Allow a short time period for players to reconnect before abandoning in case of unexpected crashes.
{% endhint %}

### Client Agent

**Searching for instances, pagination, filtering, and reservations** are performed by Client Agent.

Once instantiated, agent's **parent Monobehaviour (handler) must initialize the agent** and provide:

* `onMonitorUpdate`  callback - observe service health changes,
* `onInstancesUpdate`  callback - observe and react to instance list changes.

Once initialized, this agent will automatically provide validations and hook up logging observers, finishing with a single call to the monitoring API endpoint to indicate service health.

Agent's handler is expected to take control and call agent functions from this point:

* `ReserveSeats`  to create a capacity reservation for a particular instance/slot or auto-assign,
* `ListInstances`  to list instances with a specific filter, ordering, cursor, and page size,
* `GetNextPage`  to fetch more instances with the current parameters (filters, etc),
* `RefreshList`  to clear cache and reload first page, or refresh with a specific cursor,
* `GetInstanceDetails`  to fetch instance metadata and slots information for a specific instance,
* `Status`  to verify Server Browser service health.

When a new player connection is established, player is expected to send their reservation ID (third party player ID) to the game server using your netcode, to perform reservation confirmation.

{% hint style="success" %}
Save connection details in client or game backend to reconnect in case of an unexpected crash.
{% endhint %}

## 🧪 Samples

Get started with samples including a complete functioning integration for both server and client.

### Auto-Assign

Utilizes auto-assigned reservations, with client specifying only policy name. Server browser chooses an instance matching policy filter and slot with sufficient seats automatically.

### Custom Search

Includes a full implementation demonstrating how to search instances and slots, hook up UI elements, and let player choose where they wish to reserve capacity manually.

## ⚙️ Customization

This SDK is meant to be extended and modified, though some modifications may be risky:

✅ Handler - safely hook up UI observers and perform minor additions or modifications,

⚠️ Agent - modify lifecycle and capacity management at your own risk,

⚠️ API - write your own integration from scratch, using cherry-picked utilities.

Handlers may observe any events emitted by Server and Client agents as described below.

{% hint style="warning" %}
Make sure to get familiar with [Server Browser In-Depth](/learn/server-browser.md) concepts before making customizations.
{% endhint %}

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

### Server Events

Server Agent emits events (actions) for parent handler to observe and consume.

{% hint style="success" %}
Read event payloads by accessing  `.Current` state of any observable. 🔴 `Error` events contain full error message delimited by a newline character after the main event message.
{% endhint %}

Preview events emitted by observable `Monitor` :

<table data-full-width="true"><thead><tr><th width="125">Action Type</th><th width="450">Event Message</th><th>Description</th></tr></thead><tbody><tr><td>🟢 <code>Update</code> </td><td><code>healthy</code></td><td>All systems OK.</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>unhealthy</code></td><td>Unexpected issue.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>get monitor failed</code></td><td>Misconfiguration or unexpected issue.</td></tr><tr><td>🟡 <code>Warn</code></td><td><code>request timeout clamped to heartbeat [{timeout}]</code></td><td>Prevents race conditions.</td></tr></tbody></table>

Preview events (actions) emitted by observable `Instance`:

<table data-full-width="true"><thead><tr><th width="125">Action Type</th><th width="450">Event Message</th><th>Description</th></tr></thead><tbody><tr><td>🟢 <code>Update</code> </td><td><code>discovered</code></td><td><a href="/pages/UkbJIQ8RFaAL5RDNZsvm#discover-instance">Instance Discovery</a> completed OK. May be triggered if instance lost connection due to temporary condition and re-discovered.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>discovery duplicate</code></td><td>Instance with this Request ID is already discovered.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>discovery failed</code></td><td>Unexpected issue with discovery.</td></tr><tr><td>🔵 <code>Notify</code></td><td><code>heartbeat ok</code></td><td>Heartbeat completed OK.</td></tr><tr><td>🟡 <code>Warn</code></td><td><code>heartbeat failed [{consecutive}/{maximum}]</code></td><td>Heartbeat failed, server couldn't reach Server Browser.</td></tr><tr><td>🔵 <code>Notify</code></td><td><code>instance update enqueued</code></td><td>Enqueued instance update for next batch (heartbeat/greedy).</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>instance updated</code></td><td>Instance metadata updated OK.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>instance update failed, enqueuing for retry</code></td><td>Instance update failed, possibly due to rate limiting or error.</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>instance deleted</code></td><td>Instance is no longer discoverable by players.</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>instance delete failed (not found)</code></td><td>Instance may have expired due to too many missed heartbeats.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>instance delete failed</code></td><td>Failed to delete Instance, possibly due to rate limiting or error.</td></tr><tr><td>🔵 <code>Notify</code></td><td><code>slot update enqueued [{slot}]</code></td><td>Enqueued slot update for next batch (heartbeat/greedy).</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>slot updated [{slot}]</code></td><td>Slot seats capacity and/or metadata updated OK.</td></tr><tr><td>🟡 <code>Warn</code></td><td><code>agent throttled concurrent slot update</code></td><td>Prevented attempt at concurrent update (race condition).</td></tr><tr><td>🔴 <code>Error</code></td><td><code>slot update failed (not found) [{slot}]</code></td><td>Slot with this name is not defined for this Instance yet.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>slot update failed (not enough seats) [{slot}]</code></td><td>Slot update tried to reduce available seats below zero.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>slot update failed, enqueuing for retry [{slot}]</code></td><td>Slot update failed, possibly due to rate limiting or error.</td></tr></tbody></table>

Preview events (actions) emitted by observable `Confirmations`:

<table data-full-width="true"><thead><tr><th width="125">Action Type</th><th width="450">Event Message</th><th>Description</th></tr></thead><tbody><tr><td>🔵 <code>Notify</code></td><td><code>enqueued [{player}]</code></td><td>Enqueued confirmation for next batch (heartbeat/greedy).</td></tr><tr><td>🟡 <code>Warn</code></td><td><code>duplicate [{player}]</code></td><td>Prevented attempt at duplicated confirmation (already queued).</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>confirmed</code></td><td>Confirmed reservations for individual slots, includes also expired and unknown player IDs for handler to resolve (accept/kick).</td></tr><tr><td>🔴 <code>Error</code></td><td><code>failed</code></td><td>Unexpected issue with confirmations. Check service status.</td></tr></tbody></table>

### Client Events

Client Agent emits events (actions) for parent handler to observe and consume.

{% hint style="success" %}
Read event payloads by accessing  `.Current` state of any observable. 🔴 `Error` events contain full error message delimited by a newline character after the main event message.
{% endhint %}

Preview events emitted by observable `Monitor` :

<table data-full-width="true"><thead><tr><th width="125">Action Type</th><th width="450">Event Message</th><th>Description</th></tr></thead><tbody><tr><td>🟢 <code>Update</code> </td><td><code>healthy</code></td><td>All systems OK.</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>unhealthy</code></td><td>Unexpected issue.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>get monitor failed</code></td><td>Misconfiguration or unexpected issue.</td></tr></tbody></table>

Preview events emitted by observable `Instances`:

<table data-full-width="true"><thead><tr><th width="125">Action Type</th><th width="450">Event Message</th><th>Description</th></tr></thead><tbody><tr><td>🔵 <code>Notify</code></td><td><code>seats reserved</code></td><td>Seat reservation OK.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>seats reservation failed (not found)</code></td><td><a data-mention href="#auto-assign">#auto-assign</a> - policy name not found (deleted or inactive). <a data-mention href="#custom-search">#custom-search</a> - instance or slot not found.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>seats reservation failed (reached capacity)</code></td><td><a data-mention href="#auto-assign">#auto-assign</a> - policy reached maximum capacity. <a data-mention href="#custom-search">#custom-search</a> - slot reached maximum capacity.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>seats reservation failed</code></td><td>Seat reservation failed, possibly invalid policy, request ID, or slot ID.</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>instance list retrieved</code></td><td>Fetched list of instances OK.</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>instance list next page retrieved</code></td><td>Fetched next page of instances OK.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>instance list last page reached</code></td><td>Failed to fetch next page, try refreshing or changing filters.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>instance list next page retrieval failed</code></td><td>Failed to fetch next page, possibly due to an invalid cursor.</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>instance details retrieved</code></td><td>Fetched details of a listed instance OK.</td></tr><tr><td>🟢 <code>Update</code> </td><td><code>instance not cached, prepending</code></td><td>Fetched details of instance outside current list.</td></tr><tr><td>🔴 <code>Error</code></td><td><code>instance details retrieval failed</code></td><td>Failed to fetch details, possibly due to invalid request ID.</td></tr></tbody></table>

[^1]: Data Transfer Object


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.edgegap.com/unity/server-browser.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
