What's New In 1.2.3
Deterministic Commands API
This is a game changer. You are not required to encode low frequency player or game inputs into the input struct anymore. Create explicit commands now.
C#
public class EquipInventoryItem : DeterministicCommand {
public Int32 ItemId;
public override void Serialize(BitStream stream) {
stream.Serialize(ref ItemId);
}
}
C#
var equipCommand = new DeterministicCommand { ItemId = 10 };
QuantumRunner.Default.Game.SendCommand(equipCommand);
Read more about Commands.
NavMesh Agent Callbacks
While using a navmesh and its path-finding can be very game agnostic agent steering and agent avoidance is sometime very specific to the game you are creating. We try to help developers that want to inject their own steering and/or avoidance logic during the Quantum NavMeshAgent updating and still benefit from our path-finding and our physics broad-phase to detect close agents by introducing two new callbacks:
OnNavMeshUpdateSteering
and OnNavMeshUpdateAvoidance
Implement these callbacks in one of your systems to overwrite the internal steering and avoidance.
C#
public void OnNavMeshUpdateSteering(Frame f, NavMeshAgent* agent, Entity* entity, NavMeshAgentSteeringData* data) {
data->IgnoreInternalSteering = true;
transform->Rotation += 90 * FP.Deg2Rad * f.DeltaTime;
}
C#
public void OnNavMeshUpdateAvoidance(Frame f, NavMeshAgent* agentA, Entity* entityA, NavMeshAgent* agentB, Entity* entityB, NavMeshAgentAvoidanceData* data) {
data->IgnoreInternalAvoidance = true;
// ..
}
Find more information here: Navigation System - NavMesh Callbacks
What's coming next to Navmesh?
We want to add a system that is similar to Unity NavMesh dynamic obstacles that let's you activate or deactivate NavMesh triangles during run-time. This is already confirmed for 1.2.4.
We also noticed that the path quality as well as the agent movement and avoidance quality has room for improvement.
DSL: Primitive Array Support
Primitive arrays can be defined in the DSL:
C#
component Foo {
array<Int32>[26] Parameters;
}
We finally added proper support for them so they are not saved like this anymore:
C#
public unsafe partial struct Foo {
private Int32 Parameters0;
private Int32 Parameters1;
private Int32 Parameters2;
private Int32 Parameters3;
private Int32 Parameters4;
private Int32 Parameters5;
//...
public Int32 ParametersSize {
get {
return 26;
}
}
But appear and are usable like regular arrays like they should:
C#
public unsafe partial struct Foo {
public fixed Int32 Parameters[26];
public Int32 ParametersSize {
get {
return 26;
}
}
Read here on how to migrate your code: Migration Notes - DSL: Changed Primitive Type Array Generation (Breaking Change)
ECS: New Entity Life Cycle
We introduced a reasonable amount of states to the Quantum entity that makes working with them easier or at least more explicit. The Entity.IsActive
property should not be used anymore instead its Entity.Flags
is checked for:
C#
[Flags]
public enum EntityFlags : int {
Active = 1 << 0,
DestroyPending = 1 << 1,
Culled = 1 << 2,
NotCullable = 1 << 3
}
When an entity is scheduled for destruction at the end of a frame via a call to DestroyEntity()
or DestroyEntityType()
the DestroyPending
flag will be set.
GetAllEntityType()
and GetAllComponentType()
methods will by default not return entities scheduled for destruction anymore. If your code depends on the old behavior of returning all entities you can set #pragma legacy_entity_active_semantics 1
in the DSL.
Prediction culling
You might wonder what EntityFlags.Culled
means. This is a pure performance optimization for the client which you are definitely interested in if only a part of your game scene is visible to the player. A 2D game for example similar to this:

Where each player only has a limited view around his avatar.

If you enable prediction culling for rampageR
then all entities outside his view range will not go into prediction and only update themselves during a verified frame. There are a few caveats but in general it's very easy to set up and secure to use.
Read this article for more information: Prediction Culling
Photon Unity Networking 1.93
Why did we upgrade?
- To support the increased size limits for
RuntimePlayer
and the newDeterministic Commands API
Can I use PUN Classic from the Asset Store?
- Yes. You can update the PUN in the Quantum package with the newest version from the AssetStore.
- Delete the surplus
Newtonsoft.Json.dll
. - Manually add the "hk" region to
CloudRegionCode
andCloudRegionFlag
. - Note: Different PUN version will not find each other online unless you manually change the
PhotonNetwork.versionPUN
. - You actually need a newer
Photon3Unity3D.dll
(4.1.2.9) if you want to run your game on the Switch.
- Delete the surplus
Why not upgrade to PUN2?
- Our plan is to remove PUN completely from Quantum and build upon the Photon Realtime API directly. This change will come in 1.3. If you currently have PUN integrated into your matchmaking for example that will of course still be supported.
Improved Input Bandwidth
Bandwidth is costly for us and the end user. Quantum for real-time apps relies on sending the input of each player around at a very high frequency. Although the input struct is already small and developers do their best to keep it even smaller the accumulated bandwidth is not something looked over. Any improvement here is helpful.
What did we do?
Improved the serialization used for sending inputs from server to client by removing header information and switched to the same bit packing serialization that the game state serializer uses.
Added the option to enable a fixed input size. This stops quantum from writing the size of the input data to the byte stream when sending input from server to client: DeterministicInput.FixedSizeInput
.
QuantumRunner.ShutdownAll
The new shutdown method makes stopping Quantum from any point of execution easier.
C#
QuantumRunner.ShutdownAll(bool immediate = false)
If immediate
is true all runners will be destroyed which subsequently destroys the Quantum game and session right away. Calling this from "inside" the simulation, for example during a Quantum event or callback, will cause errors and exceptions. Calling this from anywhere on the Unity main tread and Update loop is safe.
If immediate
is false a flag is set on every runner and the shutdown is executed after the next Session update (see QuantumRunner.Update()
). This can be called at any time from anywhere.
When the runner shuts down this happens:
[QuantumRunner] The runner GameObject is destroyed
[QuantumRunner] This will trigger QuantumRunner.OnDisable()
[QuantumRunner] The session is destroyed
[DeterministicSession] If threaded: the thread is joined and destroyed
[DeterministicSession] QuantumGame.OnDestroy() is called
[QuantumGame] OnGameDestroyed callback is called
[EntityPrefabViewUpdater] destroys entity GameObjects
[QuantumGame] Callbacks are disposed
[DeterministicSession] The simulator is destroyed
[DeterministicSession] DeterministicNetwork.Destroy() is called
[DeterministicNetwork] QuantumNetworkCommunicator.OnDestroy() is called
[DeterministicSession] The FrameContext is destroyed
[DeterministicSession] QuantumRunner.Dispose() is called
Hook into the OnGameDestroyed
callback if you want to react to the destruction of the Quantum game for example unloading the level.