Shooter Game Sample

A sample showcasing SnapNet features and demonstrating best practices for networking first-person shooters

This sample repurposes the assets from Epic’s Shooter Game sample but is rewritten from the ground up to demonstrate how to build a first-person shooter in Unreal Engine using SnapNet. The project files can be downloaded from the GitHub repository.

Installation and Setup

The project is compatible with the binary version of Unreal Engine installed via Epic’s launcher. With Unreal Engine installed, you should be able to clone the repository and generate project files for SnapNetShooterGame.uproject.

Before running for the first time, copy the license.dat file that was provided with your license into <Game>/Content/SnapNet where <Game> is the folder that contains the SnapNetShooterGame.uproject file.

SnapNet licensees can replace the SnapNet plugin included in the sample with the files from the licensee repo(s) in order to build on all licensed platforms.

Configuring Sample for Dedicated Servers

By default, the project is configured to use the Steam Online Subsystem and SnapNet’s Steam transport plugin. This provides an easy way to host listen servers and join via a session browser without configuring port forwarding or deploying servers.

To configure the sample for use with dedicated servers, open up DefaultEngine.ini and change:

DefaultTransportClass=/Script/SnapNetSteam.SnapNetSteamTransport

to

DefaultTransportClass=/Script/SnapNet.SnapNetDTLSTransport

and remove the lines:

[OnlineSubsystem]
DefaultPlatformService=Steam

After these changes are made, the main menu in the game will automatically change so you can join a session directly by IP address in place of the Steam session browser.

Demonstrated SnapNet Features

Fixed tick rate with automatic interpolation

All gameplay is executed at a fixed tick rate (60 Hz by default) and can be modified at any time via the SnapNet project settings in the editor without changing any code. The rendering is completely decoupled from the simulation tick rate and will render frames that are automatically interpolated between fixed ticks.

Client-side prediction

All gameplay is server authoritative to prevent most types of cheating. Local players are predicted on the client so input is responded to instantly. Remote players are interpolated between updates received from the server so that they move smoothly and without artifacts.

Predicted projectiles

The rocket launcher weapon in the sample fires projectiles that are predicted by all players. This allows players to accurately dodge the projectile as seen on their screen. Without this feature, players might be hit by projectiles they appeared to dodge. Server corrections such as these can be incredibly frustrating and potentially game-breaking for end-users.

Backwards reconciliation

When bullet/hitscan weapons are fired, the server rewinds the state of the world so that everything is as the client originally saw it when they fired on their machine. This mechanism is critical to ensuring that a player’s shot always registers as expected. Critically, it does this while remaining 100% server authoritative—preventing many classes of cheats.

Developers can configure the maximum amount of time the server is allowed to rewind when performing backwards reconciliation. The longer the allowed duration, the higher a player’s latency can be before they need to start leading their target. The downside to this is that it lengthens the time between when a player can duck behind cover and when they may later find out they were killed from a high latency player. The default value is 200ms which is comparable to the values used for other competitive shooters.

Rollback-aware effects

Using SnapNet’s event system, developers can easily choose how cosmetic effects handle mispredictions. In this sample, a SnapNet event is spawned when one player shoots another. This event is then configured to trigger a predicted impact effect right away for instant feedback—decals or cosmetic blood splatters. Other effects, such as the the crosshair tick marks, only play when the hit is confirmed by the server. Mispredicted impact effects are killed early if the shot was mispredicted e.g., due to high latency in excess of the limit on backwards reconciliation.

Instant replays

When a player is killed and waiting to respawn, they see an instant replay of how they were killed from the attacker’s perspective. This is a built-in feature of SnapNet and is triggered using a single line of code.

Full match replays

SnapNet supports full match replays out of the box and can be controlled in this sample using the built-in console commands. For example, play for a while and then in the console run:

SaveSnapNetReplay myreplay
PlaySnapNetReplay myreplay
SpectateSnapNetReplay 0

The commands above save the replay file, load and start playing the replay file, and then spectate from the first player’s perspective, respectively.

Lag compensated replays

Both the instant and full match replays above are automatically lag compensated. When you spectate from any given player’s perspective, you see the state of the world as they saw it rather than simply the state of the server at that time. Without this feature, a number of artifacts would be present that would misrepresent how the game actually played out. For example, when spectating players who had higher latency during the match, they would always appear to be aiming behind their targets.