PUN Classic (v1), PUN 2 and Bolt are in maintenance mode. PUN 2 will support Unity 2019 to 2022, but no new features will be added. Of course all your PUN & Bolt projects will continue to work and run with the known performance in the future. For any upcoming or new projects: please switch to Photon Fusion or Quantum.

PackObjects (SyncVars)

[PackObject] Attribute allows you to tag a class or struct to be included in automatic field synchronization. PackObjectAttribute can be set to serialize all public fields, or to find all [SyncVar] Attributes in the class/struct. These are essentially the same as SyncVars in other platforms, with the primary differences being that fields:

  1. Capture/Serialize/Deserialize/Apply on the same simulation-based tick timings as all of Simple. This ensures that changes made to these objects (ideally change them in the OnPreSimulate timing segment) happen deterministically in execution order on the owner and all clients and use the same deferred timing mechanisms as SyncObjects.
  2. Can be defined with SyncVarBaseAttribute derived classes to serialize and deserialize with custom compression methods, allowing for bitpacking and other compression, frameId based keyframes/delta frames, auto-interpolation/extraction, etc.

Example Usage:

    defaultKeyRate = DefaultKeyRate.Every,
    defaultInclusion = DefaultPackInclusion.Explicit,
    postApplyCallback = "",
    postSnapCallback = "",
    syncAs = SyncAs.State

public class TestPackObj : NetComponent

        applyCallback = "SyncAngleHook",
        setValueTiming = SetValueTiming.BeforeCallback,
        interpolate = true,
        keyRate = KeyRate.Every
    public float syncedAngle = 45;

    // Hooks are methods associated with a syncvar. They are called
    // whenever the networked value changes.
    public void SyncAngleHook(float newVal, float oldVal)
        // Do something here with the newVal value
        // This gets called on all clients when the networked
        // value changes.

    // This is the default SyncVarAttribute, which uses simple
    // compression for the types it supports.
    public Vector3 syncedV3;

    // SyncRangedInt bitpacks ints by dropping unused upper bits.
    // Supply the min and max allowed values and it will come up
    // with the best compression values automatically.
    [SyncRangedInt(-1, 2)]
    public int syncedInt;

Pack Objects (SyncVars)


[PackObject] tells the Code Generation system that a class/struct needs to have serialization extensions created for it. The Code Generation engine will find all **[SyncVar]** Attributes on fields in the Class/Struct and create automated synchronization extensions that tie into the NetMaster and NetObject automatically.

  • DefaultKeyRate defaultKeyRate
    This is the rate at which complete updates will be sent, regardless of whether values have changed. Setting this to 0 indicates no keyframes, and that values should be sent as reliable on change.

  • DefaultPackInclusion defaultPackInclusion
    Indicates if all fields should be serialized, or only fields explicitly with SyncVarBaseAttribute.

  • string postApplyCallback
    Callback method inside of this class/struct. Called after all fields have been applied this update.

  • string postSnapCallback
    Callback method inside of this class/struct. Called after all values have been consumed and applied for a new tick.

  • SyncAs syncAs Indicates of this class/struct should treat all values as triggers.

    • SyncAs.State: Normal behavior. Values are individual synced when changed and on keyframes.
    • SyncAs.Trigger: If any value changes, this triggers a send for this tick, and all values will reset to default afterwards.


The SyncVarBaseAttribute (and derived attributes) tell the Code Generation which fields of a PackObject should be included in serialization/synchronization.

  • int keyRate
    How often a keyframe is sent. Keyframes send a complete update regardless of whether a value has changed or not. In between these updates, data will only send if a value has changed.

  • string snapshotCallback
    Name of a method inside of the PackObject you want called AFTER a new frame is acquired from the frame buffer, and the previous snapshot value is applied as the current state (the field value). The snap (Snapshot) and targ (Target) values are the new interpolation start/end values. This callback fires right before the Snapshot value is applied and before the applyCallback is called. Each tick, the snap value is applied, and is replaced with the previous targ value, and a new targ value is acquired from the Frame buffer.

  • string applyCallback
    Name of the function inside of PackObject that will be called when values have been remotely changed and the update with the change is being locally applied. The setValueTiming indicates if the snapshot value is applied to the syncvar before or after this callback or if it is set automatically at all.

  • SyncAs syncAs
    Indicates how the SyncVar should be treated.

    • SyncAs.State maintains the value on the owner until changed.
    • SyncAs.Trigger indicates that when the value is captured/sent by the owner, it should be reset to default with a new() operation.
  • SetValueTiming setValueTiming
    Indicates when the snapshot value should be applied to the SyncVar in relation to the applyCallback.

  • bool interpolate
    Indicates if the SyncVar value should be lerped every update automatically when the value changes.

  • int bitCount
    If the compression method supports setting a bitcount, it can be set here. This will bitpack the value using this many bits, discarding all bits left of this count.

Supported Types

  • byte, sbyte, short, ushort, int, uint, long, ulong, float, double, char
  • string, StringBuilder
  • Vector2, Vector3, Vector2Int, Vector3Int
  • List<> of any of the above types (still very experimental)

To Document Top