Replays
Introduction
This documentation explores ways of saving and playing back deterministic Quantum simulation replays. Every part of the system comes in source code form. The implementation can be inspected, use it as-is or tweak it to serve project requirements in a better way.
Replays are an unaltered compiled application that re-runs the game simulation with the exact same user input and game assets, from a recorded session. Also, it can be used to run a second runner besides the default runner to perform, for instance, a killcam replay. The compiled application does not need to be the same one or even run on the same platform, e.g. Android, Unity Editor, Windows exe or a custom game server, but it has to be built with the same quantum dlls.
Running a Quantum replay requires four parts:
- An application build with the same version of Quantum libraries
- PhotonDeterministic.dll and quantum.core.dll
- The custom quantum.code.dll
- The game assets
- The Quantum asset database (DB)
- The LUT files (FP look-up tables for math, usually never changes)
- The game session specific configuration files
- SimulationConfig
- RuntimeConfig
- The game session specific input history
Replay Files
Asset DB
To play-back a replay Quantum requires the exact same versions of all game assets that the replay was recorded with. It has to be started with a versioned Quantum asset db. The db can be exported from Unity into a Json file (db.json).
C#
var serializer = new QuantumUnityJsonSerializer();
var data = serializer.SerializeAssets(UnityDB.DefaultResourceManager.LoadAllAssets(true));
File.WriteAllBytes(“db.json”, data);
Configuration Files And Input History
For convenience the default replay format used by the API and scripts consists of one class which is serialized and saved as a file using Json (replay.json). This format contains (3) and (4) of the required parts and additionally can store an optional frame to start from (Frame
, InitialFrame
, InitialFrameData
).
If size and performance are a consideration, any binary serialization can be added. The required classes (e.g. DeterministicTickInputSet
) are fairly simple. We also provide snippets for this.
Related class: quantum.code/Replay/ReplayFile.cs
C#
var serializer = new QuantumUnityJsonSerializer();
var replay = QuantumRunner.Default.Game.GetRecordedReplay();
var data = serializer.serializer.SerializeReplay(replay);
File.WriteAllBytes(“db.json”, data);
Checksums
If frame checksums are enabled in the SessionConfig they can be captured and saved into a file. When playing back a replay, the newly generated checksums are then verified against the recorded ones to validate that the simulation is correct. Because checksums are expensive to calculate this is only regarded as a development feature.
Related class: quantum.code/Replay/ChecksumFile.cs
C#
var serializer = new QuantumUnityJsonSerializer();
var data = serializer.SerializeChecksum(QuantumRunner.Default.Game.RecordedChecksums);
File.WriteAllBytes(“db.json”, data);
Saving A Replay In Unity
Set RecordingFlags
When starting a Quantum game, set the desired RecordingFlags
in the start parameters QuantumRunner.StartParameters.RecordingFlags
.
The QuantumRunnerLocalDebug
script has a toggleable member for this. When starting from custom menu classes it has to be set explicitly in code.
C#
[Flags]
public enum RecordingFlags {
None = 0,
Input = 1 << 0,
Checksums = 1 << 1,
Default = Input | Checksums,
All = 0xFF
}
Exporting A Replay
Use the Unity Editor menu Quantum > Export > Replay (JSON) and select a destination folder for the files.
Search for the method ReplayMenu.ExportDialogReplayAndDB()
to look at the code required to export the db and replay file.
Replay API
Apart from the StartParameters
and serializer the QuantumGame
class holds the rest of the relevant replay methods.
C#
public class QuantumGame : IDeterministicGame {
public InputProvider RecordedInputs { get; }
public ChecksumFile RecordedChecksums { get; }
public ReplayFile GetRecordedReplay();
public void StartRecordingInput(Int32? startFrame = null);
public void StartRecordingChecksums();
public void StartRecordingInstantReplaySnapshots();
public void StartVerifyingChecksums(ChecksumFile checksums);
}
Another key part is the InputProvider
class. It is designed to work as an adapter between the Quantum input system and something read- and save-able.
It is used to record the input (QuantumGame.RecordedInputs
and InjectInput()
), save and load (ImportFromList()
and ExportToList()
) and to play back input for the simulation (StartParameters.ReplayProvider
).
Playback A Replay In Unity
Similar to the script to start a local game (QuantumRunnerLocalDebug
) the QuantumRunnerLocalReplay
script starts and plays the game from a replay file.
Drag and drop the replay.json file onto the replay runner script in a field named Replay File. The other files for db and optional checksums are then assigned automatically. If not, drag the two files into their respective fields. The DatabasePath
field is not used anymore.
Find the QuantumRunnerLocalReplay.cs
script to research all required actions to start a game with a replay file.
Deserialize The Replay Files
C#
var serializer = new QuantumUnityJsonSerializer();
var replayFile = serializer.DeserializeReplay(ReplayFile.bytes);
var assets = serializer.DeserializeAssets(DatabaseFile.bytes);
var checksums = serializer.DeserializeChecksum(ChecksumFile.bytes);
Configure The Start Parameters
- Set
SessionConfig
andRuntimeConfig
from the replay file. - Set the
ReplayProvider
by creating a new instance of theInputProvider
with the loaded and deserialized input history. - Set
GameMode
toReplay
. - Set
PlayerCount
andLocalPlayerCount
from setSessionConfig
. In this mode all players are considered local. - Optionally set InitialFrame and FrameData.
- Set
ResourceManageOverride
to a new instance using the deserialized asset db.
C#
var param = new QuantumRunner.StartParameters {
RuntimeConfig = replayFile.RuntimeConfig,
DeterministicConfig = replayFile.DeterministicConfig,
ReplayProvider = new InputProvider(replayFile.InputHistory),
GameMode = Photon.Deterministic.DeterministicGameMode.Replay,
RunnerId = "Replay",
PlayerCount = replayFile.DeterministicConfig.PlayerCount,
LocalPlayerCount = replayFile.DeterministicConfig.PlayerCount,
InstantReplayConfig = InstantReplayConfig,
InitialFrame = replayFile.InitialFrame,
FrameData = replayFile.InitialFrameData,
ResourceManagerOverride = new ResourceManagerStatic(assets, new QuantumUnityNativeAllocator())
};
Start the Quantum game.
C#
var runner = QuantumRunner.StartGame("Replay", param);
Optionally start verifying the checksums while playing back the replay.
C#
runner.Game.StartVerifyingChecksums(checksums);
Console Runner
The console runner is distributed with the SDK and is a simple Dotnet console application that can run a Quantum simulation from a replay outside of Unity.
The quantum.console.runner
project can be added to the quantum_code solution. By default it references the Quantum dlls in the assemblies folder and the code solution.
Either select the project as the start-up project and run debugging with F5 where the following StartArguments are set for debugging the project. It expects the replay files to be located under quantum_unity/Assets/Resources/replay
.
<StartArguments>../../../../quantum_unity/Assets/Photon/Quantum/Resources/LUT ../../../../quantum_unity/Assets/Resources/replay/db.json ../../../../quantum_unity/Assets/Resources/replay/replay.json ../../../../quantum_unity/Assets/Resources/replay/checksum.json</StartArguments>
Or compile the console app and run with the following parameters.
C#
console.runner.exe [folder path to LUT files] [file path to database] [file path to replay] ([file path to checksums])
Caveat: The replay runner requires the exact set of libraries, db, configs and input that was discussed in the introduction to work properly.
Caveat: When still encountering verification errors it may be because of platform compatibility. The recorded checksums in Unity are not compatible with the ones generated in the Dotnet runner. Activate ChecksumCrossPlatformDeterminism
in the SessionConfig and record the replay again to fix the errors.
Instant Replays
We provide a script which demonstrates how to do instant replays, like killcam replays which happen during the game, in an auxiliary QuantumRunner, and then gets back to the default runner once the instant replay is over.
To use it, you just need to add the component called QuantumInstantReplayDemo
, do the setup (set playback speed, replay length, etc) and then, during gameplay, you can just hit the Start and Stop buttons.