This document covers the
GameFabricGameServerProviderPlugin, which integrates Pragma
Engine with GameFabric for
multiplayer game server allocation. It explains configuration, region
selection, the allocation flow, GameFabric console setup, and how to run
everything locally using ngrok.
The GameFabricGameServerProviderPlugin implements
Pragma's GameServerProviderPlugin interface. When a game
instance needs a dedicated server, this plugin sends an allocation
request to GameFabric's REST API. GameFabric then finds an available
game server in the requested region. The allocated game server connects
back to Pragma to complete the handshake.
| File | Purpose |
|---|---|
GameFabricGameServerProviderPlugin.kt |
Plugin entry point, handles allocation requests with primary/fallback region logic |
GameFabricApi.kt |
HTTP client for GameFabric's allocation and ping REST endpoints |
GameFabricRegionPingCache.kt |
Caches ping server addresses so clients can measure latency to each region. Optional usage in your PartyPlugin |
gameFabricGameInstance.proto |
Protobuf definitions for ping data and allocation error payloads |
gameInstanceExt.proto |
Defines ExtAllocateGameServer with
desired_region, game_server_version, and
server_args |
The plugin is configured under
GameInstanceService.gameServerProviderPlugin in your YAML
config:
game:
pluginConfigs:
GameInstanceService.gameServerProviderPlugin:
class: "pragma.gameinstance.gamefabric.GameFabricGameServerProviderPlugin"
config:
gameFabric:
gameFabricUrl: "https://STUDIO-IDENTIFIER.gamefabric.dev"
allocatePath: "allocator/prod/us/allocate"
pingPath: "ping"
allocatorToken: "<your-bearer-token>"
gameServerZonesByProviderRegion:
us-west: "US_WEST"
eu-central-1: "EU_CENTRAL"
pragmaGamePartnerBackendAddress: "http://localhost:10100"
fallbackRegion: "us-west"
fallbackEnvironment: "prag"
fallbackArmadaSet: "sample-game-armada-set"| Field | Description |
|---|---|
gameFabric.gameFabricUrl |
Base URL for your GameFabric studio (e.g.
https://egret.gamefabric.dev) |
gameFabric.allocatePath |
REST path appended to the base URL for allocation requests |
gameFabric.pingPath |
REST path for fetching ping server addresses |
gameFabric.allocatorToken |
Bearer token for authenticating with the GameFabric allocator API |
gameFabric.gameServerZonesByProviderRegion |
Optional. Maps GameFabric region names (e.g. us-west)
to Pragma GameServerZone values (e.g.
US_WEST). Only regions present in this map are exposed to
clients for ping |
pragmaGamePartnerBackendAddress |
The address the allocated game server uses to connect back to Pragma's Game Partner Gateway |
fallbackRegion |
If the primary region allocation fails, retry in this region. Leave blank to disable fallback |
fallbackEnvironment |
Used when ExtAllocateGameServer.game_server_version is
empty. Determines which GameFabric environment to target |
fallbackArmadaSet |
Used when the armada set cannot be parsed from
game_server_version |
The game_server_version field in
ExtAllocateGameServer uses the format:
<environment>::<armadaSet>
For example: prag::sample-game-armada-set
:: is sent as the env
attribute to GameFabric.:: is sent as the armadaset
attribute.fallbackEnvironment and
fallbackArmadaSet are used instead.Note that the two attributes env and
armadaset will need to be configured on your GameFabric
AramdaSet as labels in the General
Settings area:
| Label key | Label value |
|---|---|
| allocator.nitrado.net/armadaset | sample-game-armada-set |
| allocator.nitrado.net/env | prag |
The desired_region used for allocation comes from the
ExtAllocateGameServer protobuf message, which is populated
in your custom GameInstancePlugin
implementation.
GameInstancePlugin interface has methods like
handleBackendCreateRequest and
handlePlayerCreateRequest that are called when a game
instance is being created.gameInstanceSnapshot.allocateGameServer(ext) passing an
ExtAllocateGameServer with your desired allocation
parameters.GameFabricGameServerProviderPlugin receives this
ext in startAllocationForGameInstance and reads
ext.desiredRegion as the primary region.The default
GameInstancePlugin.handleBackendCreateRequest
implementation calls:
gameInstanceSnapshot.allocateGameServer(ExtAllocateGameServer.getDefaultInstance())This means desired_region will be an empty
string. In this case, the
GameFabricGameServerProviderPlugin will directly use
fallbackRegion as the primary allocation region.
If you do not provide a region through a custom
GameInstancePlugin, you must configure
fallbackRegion in the plugin config, otherwise allocation
will fail.
To properly set the region, override the relevant handler in your
GameInstancePlugin and populate the ext:
override suspend fun handleBackendCreateRequest(
gameInstanceSnapshot: GameInstance.GameInstance,
requestExt: ExtBackendCreateRequest,
playersToAdd: List<PlayerToAdd>,
) {
playersToAdd.forEach { player ->
gameInstanceSnapshot.addPlayer(player.playerId, player.partyId, player.teamNumber)
}
val ext = ExtAllocateGameServer.newBuilder()
.setDesiredRegion("us-west") // from player ping results or matchmaking data
.setGameServerVersion("prag::sample-game-armada-set") // environment::armadaSet
.build()
gameInstanceSnapshot.allocateGameServer(ext)
}When startAllocationForGameInstance is called:
Parse identifiers from
ExtAllocateGameServer:
environment = part before :: in
game_server_version (or configured
fallbackEnvironment)armadaSet = part after :: (or configured
fallbackArmadaSet)primaryRegion = desired_region (lowercased
or configured fallbackRegion)Build the allocation request:
attributes:
{ "env": "<environment>", "armadaset": "<armadaSet>" }
(used by GameFabric to find the correct fleet)payload:
{ "GameInstanceId", "PartnerGameToken", "PartnerSocialToken", "pragmaBackendAddress", "ServerArgs" }
(forwarded to the game server as Agones annotations)Send allocation to GameFabric (primary region):
<gameFabricUrl>/<allocatePath> with
bearer token authFallback on failure:
fallbackRegion is
configured, retry with the fallback regionGameServerAllocationApplicationError containing the HTTP
response detailsGame server connects back:
pragmaBackendAddress
and partner tokens in the payloadLinkV1 to make itself
available for players to connect to it.GameFabricRegionPingCache could be used (eg: in a
PartyPlugin) to periodically fetche ping server addresses from
GameFabric so that game clients can measure latency to each region and
choose the best one.
gameServerZonesByProviderRegion
are exposed to clients.GameInstancePlugin to set the
desired_region.This is an example of environment variables configured directly on the region, therefore being inherited by all armada sets. These are set in the GameFabric console and are used by the allocator sidecar running alongside your game server:
| Type | Variable Name | Secret | Value / Key |
|---|---|---|---|
| Pod Field | ALLOC_PRIORITY |
-- | metadata.regionTypePriority |
| Key-Value Pair | ALLOC_REGION |
-- | us-west |
| Key-Value Pair | ALLOC_URL |
-- | https://STUDIO_IDENTIFIER.gamefabric.dev/allocator/prod/us/servers |
| Key-Value Pair | ALLOC_PAYLOAD_ANNOTATION |
-- | payload- |
| Key-Value Pair | ALLOC_PAYLOAD_FILE |
-- | /app/shared/payload.json |
| Secret | ALLOC_TOKEN |
allocator-prod-us |
registry_token |
What each variable does:
ALLOC_PRIORITY -- The pod field used
to determine allocation priority.
metadata.regionTypePriority allows GameFabric to prefer
servers in the requested region.ALLOC_REGION -- The region this fleet
is deployed to (e.g. us-west). This must match one of the
keys in gameServerZonesByProviderRegion in the Pragma
config.ALLOC_URL -- The URL the allocator
sidecar uses to register with the GameFabric allocator service so it can
receive allocation requests.ALLOC_PAYLOAD_ANNOTATION -- Prefix for
Agones annotations that contain payload data. The allocation payload
(GameInstanceId, tokens, pragmaBackendAddress, ServerArgs) is written as
annotations prefixed with this value.ALLOC_PAYLOAD_FILE -- Path where the
allocator sidecar writes the payload JSON file. The game server reads
this file on startup and watches for changes to this file in order to
get Pragma connection details.ALLOC_TOKEN -- Secret reference for
authenticating the allocator sidecar with the GameFabric allocator
service. allocator-prod-us is the secret name,
registry_token is the key within that secret.See the [Automatically registering game servers](https://docs.gamefabric. com/multiplayer-servers/multiplayer-services/server-allocation/automatically-registering-game-servers) section for more details on these environment variables.
prag).sample-game-armada-set).ALLOC_REGION value must differ per fleet
(e.g. us-west, eu-central-1).allocator-prod-us) containing the
registry_token that matches the allocatorToken
in your Pragma config./app/shared/payload.json
for changes in order to get details Pragma assigns the specific game
instance the game server will be associated with.The gameServerZonesByProviderRegion config maps
GameFabric region names to Pragma GameServerZone values.
Each region in GameFabric that you want to allocate to must have an
entry here:
gameServerZonesByProviderRegion:
us-west: "US_WEST"
eu-central-1: "EU_CENTRAL"The keys (e.g. us-west) must match the
ALLOC_REGION values set on GameFabric fleets, and the
values (e.g. US_WEST) are the Pragma-side identifiers used
in matchmaking and game instances.
The unreal/SampleGame directory contains a working
Unreal Engine 5 project that demonstrates a dedicated game server
integrating with both Pragma and GameFabric. It includes a server-side
game mode, a client-side player controller, a Dockerfile for
containerizing the server, and a script to build and push the image to
GameFabric's container registry.
| Path | Purpose |
|---|---|
Source/SampleGame/SampleGameGameModeBase.cpp/.h |
Dedicated server game mode - connects to Pragma, handles allocation, links the game instance, manages player connections |
Source/SampleGame/MyPlayerController.cpp/.h |
Client-side player controller - login, party, matchmaking, game instance UI |
Source/SampleGameServer.Target.cs |
Server build target (TargetType.Server) |
Source/SampleGame/SampleGame.Build.cs |
Module dependencies including PragmaSDK,
Agones, OnlineSubsystemSteam |
Dockerfile |
Containerizes the cooked Linux server build with the GameFabric game server wrapper |
push-image.sh |
Helper script to build the Docker image and push it to the GameFabric container registry |
SampleGameGameModeBase supports two operating modes,
selected automatically at startup based on whether command-line
parameters are present:
Local development mode - When
-PragmaGameInstanceId= is passed on the command line (along
with partner tokens and backend address), the server connects to Pragma
immediately. This is useful for iterating locally without GameFabric
infrastructure (LocalProcessGameServerProviderPlugin would need to be
configured on your locally running pragma-engine).
GameFabric mode - When no
PragmaGameInstanceId is on the command line, the server
assumes it is running inside a GameFabric-managed container. It polls
every 2 seconds for the allocation payload file at
/app/shared/payload.json, which the allocation sidecar
writes when the server receives an allocation. The payload contains:
| Field | Description |
|---|---|
GameInstanceId |
The Pragma game instance this server is allocated to |
PartnerGameToken |
Auth token for the Game Partner Backend |
PartnerSocialToken |
Auth token for the Social Partner Backend |
pragmaBackendAddress |
URL of the Pragma backend the server should connect to |
Once the payload is read, the server connects to Pragma, calls
Link() with the game instance ID, and then calls
ConnectMorePlayers() to make the server available to
clients. When the game ends (triggered by a client sending
"IWON"), it calls EndGame() and shuts down via
Agones.
The Dockerfile packages the cooked Unreal dedicated server for deployment on GameFabric:
FROM ubuntu:22.04
# Runtime dependencies for the Unreal dedicated server
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates libssl3 libcurl4 libfontconfig1 \
libfreetype6 libglu1-mesa libsm6 libxrandr2 \
libxinerama1 libxcursor1 \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*
# GameFabric game server wrapper (gswrapper)
ARG GSW_VERSION=v2.6.0
ADD https://github.com/GameFabric/gswrapper/releases/download/${GSW_VERSION}/gsw_linux_x86_64 \
/app/gsw
RUN chmod +x /app/gsw
# Copy the cooked LinuxServer build
COPY --chown=gameserver:gameserver Build/LinuxServer/ /app/gameserver/
# gswrapper is the entrypoint -- it manages Agones lifecycle
# and tails game logs for observability
ENTRYPOINT ["/app/gsw", \
"--shutdown.ready=1h", \
"--shutdown.allocated=24h", \
"--tail-log.paths=/app/gameserver/SampleGame/Saved/Logs/SampleGame.log", \
"--"]
# Template variables {{ .GameServerIP }} and {{ .GameServerPort }}
# are injected by gswrapper at runtime
CMD ["/app/gameserver/SampleGameServer.sh", \
"-server", "-log", \
"-Hostname={{ .GameServerIP }}", \
"-ExternalPort={{ .GameServerPort }}"]Key aspects:
{{ .GameServerIP }} and {{ .GameServerPort }}
into the CMD arguments. See the gswrapper
documentation for details.--shutdown.ready=1h -- if the server
sits in the Ready state for more than 1 hour without
receiving an allocation, gswrapper shuts it down.--shutdown.allocated=24h -- maximum
lifetime of an allocated server session.Build/LinuxServer/ directory must contain the
output of cooking the SampleGameServer target.push-image.sh builds the Docker image and pushes it to
GameFabric's container registry. Run it from the
unreal/SampleGame directory (where the Dockerfile
lives):
./push-image.sh -p <registry-password> -t <tag>| Flag | Description |
|---|---|
-p |
Service-account password for the GameFabric container registry |
-t |
Tag for the image (e.g. v1.0.0,
build-1234) |
The script uses three environment variables with sensible defaults that you should override for your project:
| Variable | Default | Description |
|---|---|---|
GF_REGISTRY_URL |
registry.gamefabric.io/your-org |
Your GameFabric container registry URL |
GF_BRANCH |
development |
The registry branch/namespace for the image |
GF_USERNAME |
your-service-account |
Service-account username for registry authentication |
Example with overrides (or replace the overrides in the script itself):
GF_REGISTRY_URL="registry.gamefabric.io/my-studio" \
GF_BRANCH="production" \
GF_USERNAME="deploy-bot" \
./push-image.sh -p "$REGISTRY_PASSWORD" -t v1.0.0The script will:
linux/amd64<GF_REGISTRY_URL>/<GF_BRANCH>/samplegame-server:<tag>After pushing, configure your GameFabric ArmadaSet to use this image for fleet deployments.
Follow the article here to learn how to expose your locally running pragma-engine to the outside world using ngrok.