This document is about: QUANTUM 1
SWITCH TO

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.

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:

2D Game
2D Game

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

2D Game Player View
2D Game Player View

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 new Deterministic 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 and CloudRegionFlag.
    • 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.

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.

Back to top