Multiplayer

Guide how to run, configure and join multiplayer servers.

Multiplayer comes in two flavors, both of them optional at build time:

  • Local splitscreen (WITH_MULTIPLAYER) — two to four players on a single machine, no networking involved. Every game mode can be played this way.
  • Online multiplayer (WITH_ONLINE_MULTIPLAYER, and WITH_WEBSOCKET for the additional WebSocket transport) — players connect over a network to a server, which can be the game itself or a headless dedicated server.

Every online session is server-authoritative: one side simulates the level, decides about damage, collectibles, scores and round transitions, and everyone else sends input and receives state. Because of that, a server is not a passive relay — it runs the whole game and the level has to be present on it. The role a machine plays is decided when the session starts, so the same executable is both the game and the server unless it was built with DEDICATED_SERVER. Multiplayer also requires threads (NCINE_WITH_THREADS), so it's compiled out on the few platforms that have none, see Game-specific parameters.

Running a server

Hosting from the game

Choose Play Multiplayer in the main menu and then one of:

  • Create Public Server — the server announces itself, see Public and private servers
  • Create Private Server — the server stays hidden and can only be joined by address
  • Create Local Splitscreen Game — no networking at all, the additional players use gamepads or a shared keyboard on the same machine

The next screens select the level (or the configured playlist) and the game mode. The host plays as an ordinary player, but its process is the authority for everyone else, which also means it has to be reachable — see Public and private servers for the port to forward. Everything else comes from the very same configuration file the dedicated server reads ("Jazz2.Server.config", see Configuring a server), only the game mode, the level and the public/private choice are taken from the menu instead of from the file.

Running a dedicated server

A dedicated server is the same executable started with the /server argument, optionally followed by the path to its configuration file:

./jazz2 /server Jazz2.Server.config

In this mode the application opens no window and initializes neither graphics nor audio, runs the simulation at a fixed rate of 60 frames per second, and reads console commands from standard input, so it can be run over SSH, from a service manager or in a container. The argument is available on Linux, macOS and — in a debug build only — on Windows; a release server for Windows is the DEDICATED_SERVER build, where the executable is always a server and takes the configuration path as its first argument without /server. See Game-specific parameters for both build parameters.

A dedicated server needs the same game files as a normal installation — the original Jazz Jackrabbit 2 data in the "Source" directory, which it converts into "Cache" on the first start — and it needs a playlist: the level it starts with is taken from the current playlist entry, so a configuration without one is refused with "Server cannot be started because of invalid configuration". The configuration path is relative to the directory of the preferences file (the same directory "Jazz2.config" lives in, which /config can move elsewhere); an absolute path is used as it is, and if the argument is omitted, "Jazz2.Server.config" is loaded from there.

Everything typed on standard input is sent to the server: a line starting with / is a command (see Server commands), anything else is broadcast as a chat message from the server. /exit or /quit stops the server, and so do Ctrl+C and a termination signal (SIGINT and SIGTERM; on Windows the console close events) — all of them shut it down cleanly, disconnecting the peers and delisting the server from the online list before the process exits. A second signal during an already running shutdown terminates the process the usual way.

Running a dedicated server as a container

The dedicated server is also published as a multi-architecture container image, which needs nothing to be built and comes with the DEDICATED_SERVER configuration already applied. See Running the dedicated server as a container for the image, the volumes it expects and the docker-compose.yml that describes the whole setup, including running several instances on a single host.

Configuring a server

Configuration file

The server is configured by a single JSON file, by default "Jazz2.Server.config" next to the preferences file. Comments are allowed in it, both the block and the single-line form, and the "$include" directive merges another file into it (recursively, but each file only once, so an include loop is harmless) — which is how several instances can share their common settings and only differ in a few properties. A minimal configuration of a server that rotates two levels looks like this:

{
    "ServerName": "{PlayerName}'s Server",
    "ServerPort": 7438,
    "MaxPlayerCount": 16,
    "MinPlayerCount": 2,

    "Playlist": [
        { "LevelName": "battle1", "GameMode": "battle", "TotalKills": 15 },
        { "LevelName": "arace1", "GameMode": "race", "TotalLaps": 3 }
    ],
    "PlaylistIndex": 0
}

See Jazz2::Multiplayer::ServerConfiguration for the description of every supported property, their default values and a fully annotated example configuration. The properties fall into a few groups:

  • Identity and reachability — "ServerName", "ServerPort", "ServerAddressOverride", "IsPrivate" and the WebSocket transport ("WsPort", "WsCertPath", "WsKeyPath")
  • Access control — "ServerPassword", "MaxPlayerCount", "AllowedPlayerTypes", "RequiresDiscordAuth" and the player ID lists, see Admins, whitelist and bans
  • Rules of a round — "GameMode", "InitialPlayerHealth", "TotalKills", "TotalLaps", "TotalTreasureCollected", "MaxGameTimeSecs", "Elimination", the team properties and the gameplay switches such as "ReforgedGameplay", "AllowLedgeClimb" or "PlayerStacking"
  • Session flow — "MinPlayerCount" and "PreGameSecs" decide when a round starts, "TotalPlayerPoints" how long a championship of several rounds lasts, "AllowJoinDuringRound", "JoinCooldownSecs", "ReconnectWindowSecs" and "IdleKickTimeSecs" how players enter and leave it
  • Operations — "AllowAssetStreaming" lets clients download levels they don't have from the server, and "WebhookUrl" with "WebhookEvents" post selected server events to a Discord channel

"{PlayerName}" and "{ServerName}" can be used in "ServerName" and "WelcomeMessage", and both properties also support text formatting.

Playlist

"Playlist" is an array of rounds, each of them at least a level name and usually a game mode. Every property a playlist entry doesn't specify is inherited from the root of the configuration, so the root can carry the common rules and an entry only override what makes its round different — see Jazz2::Multiplayer::PlaylistEntry for the properties an entry may contain. The entry that is played first is "PlaylistIndex", and once a round ends, the server advances to the next entry, wrapping around at the end. With "RandomizePlaylist" the list is shuffled when the server starts and again on every wrap.

A Cooperation entry with a story level is played to the end of its episode: when the level has a next level set, reaching the exit continues with it automatically, still with the same entry's settings, and the next entry is applied only once the whole episode is at the end.

The playlist is also the only way for a dedicated server to know which level to load at all (see Running a dedicated server). A server hosted from the menu uses it only when the level selection is left at the playlist, otherwise "PlaylistIndex" is -1 and the chosen level is played until an admin changes it.

Admins, whitelist and bans

Players are identified by a Unique Player ID, which every installation generates for itself. A player finds their own in Options → User Profile (the item copies it to the clipboard), and an admin can look up a connected one with the /ip command. Four properties of the configuration take these IDs:

PropertyEffect
"AdminUniquePlayerIDs"Players in this map may use the admin commands. The value is reserved for a list of privileges, "*" meaning all of them
"WhitelistedUniquePlayerIDs"If the map is not empty, only the players in it can join. The value is a user-defined comment
"BannedUniquePlayerIDs"Players in this map are rejected. The value is a user-defined comment, e.g. the reason
"BannedIPAddresses"The same for addresses, for a player whose ID is not known

"ServerPassword" is the simpler alternative to a whitelist — the server is visible to everybody, but only a player who knows the password can enter it. "RequiresDiscordAuth" additionally requires a running Discord client, which limits the server to players on Linux, macOS and Windows. "AllowCheats" is off by default; when it's on, admins may use cheats in any game mode and other players only in Cooperation, and always only on themselves.

Applying changes

The configuration file is read when the server starts. An admin can reload it at runtime with the /refresh command, which re-reads the file and re-applies the welcome message, the game mode and the current playlist entry, so most changes don't require a restart. Individual properties can also be changed temporarily with /set (see Server commands) — those changes live only until the next /refresh or restart, they are never written back to the file.

Public and private servers

Whether a server announces itself is decided by the "IsPrivate" property (or by the menu item the host started it with):

BehaviorPublic serverPrivate server
Announced on the local networkYes, answers discovery requests on UDP port 7439No
Published to the online server listYes, to https://de4th.dev/jazz2/serversNo
Shown in Join ServerYes, in both listsNo, has to be entered by address
Requires a reachable addressYes, otherwise nobody can connectYes, for everyone who is given the address
Password, whitelist and bansApply the same wayApply the same way

A private server runs no discovery at all, which is what makes it private: it appears in neither list, and the only way in is its address. It is not an access restriction on its own — anyone who learns the address can connect — so a server that should stay among friends is usually a private server and a password-protected one.

A public server re-publishes itself to the online list every 5 minutes and delists itself when it shuts down cleanly. The address it publishes is the one it detects for itself, which is of no use when the server is behind NAT or in a container — "ServerAddressOverride" then specifies the address (and, if it differs, the port) players on the internet should use. It takes either a single address or an array of them, for a server reachable at several addresses at once (e.g. IPv4 and IPv6, or a domain name next to a bare address); clients then try them in the listed order. A domain name does not need a list of its own to cover both protocols — a client resolves every endpoint it is given, a domain name among them, to all of the addresses behind it (up to four) and tries each one in the order the resolver returned them, so a server whose name carries both an A and an AAAA record is reachable over either. The port itself has to be reachable in any case: "ServerPort" over UDP for the default transport, and "WsPort" over TCP if the WebSocket transport is enabled. The /endpoints command lists the endpoints the server knows about, including the overrides.

Joining a server

Choose Play Multiplayer → Join Server in the main menu. The list is filled from two sources at once — servers discovered on the local network and the public online list — and shows the name, the player count, the version and the address of each of them, marked with "ws" for a server offering the WebSocket transport, "R" for reforged gameplay and "^" for one found on the local network. Servers the client can join are listed first and a version it cannot join is highlighted. A server can also be entered by address, which is the only way to reach a private server.

An endpoint is an IPv4 address, an IPv6 address in brackets or a domain name, optionally followed by a port (7438 is used when none is given), or a ws:// / wss:// URL to connect over the WebSocket transport:

192.168.1.10          # Local network, default port
example.com:7438      # Domain name and an explicit port
[2001:db8::1]:7438    # IPv6 address
wss://example.com:443 # WebSocket transport (browsers always use this one)

The game can also connect right after it starts, without going through the menu, which is what a server browser or a shortcut would use:

./jazz2 /connect example.com:7438 secret123

The second argument is the endpoint and the optional third one is the server password. On joining, the server first checks that the protocol version of the client is within the range it accepts (by default only its own version, patch included, see NCINE_PROTOCOL_VERSION_MIN and NCINE_PROTOCOL_VERSION_MAX) and announces that range back, so the client can also leave a server too old to announce one, then the player is authenticated against the whitelist, the ban lists and the password, and finally the client is asked for the assets of the level. A connection that doesn't authenticate within 20 seconds is dropped. Anything it is missing — levels, tilesets, music — is downloaded from the server if the server allows it with "AllowAssetStreaming"; otherwise the player has to install the missing files manually. Once in, an in-game lobby offers the character selection and the welcome message of the server.

If the connection drops, reconnecting within "ReconnectWindowSecs" restores the progression of the player — weapons, lives, score, gems and championship points — instead of starting over. A player removed by the server — kicked by an admin, banned, or kicked for inactivity or cheating — always starts over.

Server commands

Commands are typed into the in-game console (the backquote or T key by default) or, on a dedicated server, directly into its standard input. Anything that isn't a command is a chat message. These are available to every player:

CommandDescription
/infoName of the server, current level and game mode, player count, load and uptime
/playersList of connected players with their ping, points, kills, deaths and idle time
/team <team>Requests a change to the blue, red, green or yellow team, or back to auto, if the server allows it in the current mode
/killKills your own player
/vote <type>Starts a poll to restart the playlist, skip the current level or reset points. It stays open for 60 seconds
/yesVotes in the active poll

The remaining commands require admin rights, i.e. an entry in "AdminUniquePlayerIDs" (the console of a dedicated server is always an admin):

CommandDescription
/set mode <mode>Changes the game mode, which restarts the round. Accepts the same values as the "GameMode" property
/set level <level>Loads another level and leaves the playlist
/set name <name>Renames the server. An empty name stops publishing it to the online list
/set welcome <message>Changes the welcome message of the in-game lobby, \n starts a new line
/set kills, /set laps, /set treasure <n>Changes the win target of the current round
/set teamcount <2-4>Changes the number of teams, which re-splits them and restarts the round
/set autobalance, /set teamselect, /set friendlyfire <on/off>Team rules of the current round
/set cheats <on/off>Allows or forbids cheats
/set spawning <on/off>Stops or resumes spawning of players
/nextEnds the current round and continues with the next one
/playlist [<index>]Jumps to a playlist entry, or advances to the next one
/skipSkips the remaining pre-game countdown
/balanceRebalances the teams immediately
/setteam <player#> <team>Moves a player to a team
/reset pointsResets the championship points of all players
/alert <message>Shows a message over the HUD of every player
/kick <player>Disconnects a player, by name or by # and their index
/kill <player>Kills a player without counting it as a death
/ip <player>Address and Unique Player ID of a player
/endpointsEndpoints the server is reachable at, including "ServerAddressOverride"
/refreshReloads the configuration file, see Applying changes
/vote cancelCancels the active poll
/exit, /quitShuts the dedicated server down (its own console only)

Command-line arguments

ArgumentDescription
/server [<config>]Runs the application as a dedicated server, see Running a dedicated server. --server is accepted as well
/connect <endpoint> [<password>]Connects to a server right after the start instead of showing the main menu. --connect and -c are accepted as well
/config <path>Path to the preferences file, which is also the directory a relative server configuration path is resolved against
/logAttaches a console to the process (Windows only, where a non-server build has none)
/log:file[:<name>]Writes the trace log into a file in the preferences directory, "Jazz2.log" if no name is given

Opening the log file discards what the previous session wrote into it, so that content is first appended to "Jazz2.log.gz" next to it — a plain gzip file holding one member per session, oldest first, which any gzip tool reads back as one file with the sessions in order. It is trimmed from the front once it outgrows 4 MB or 32 sessions, so the most recent sessions are always the ones kept. A log file named explicitly with "/log:file:<name>" is left as the single file it was asked for and gets no archive.

/server is available on Linux and macOS, and on Windows only in a debug build — a release server for Windows is the DEDICATED_SERVER build, where no argument is needed to become one and the first argument is the path to the configuration file. In a DEDICATED_SERVER build the arguments of a client are naturally not available either.