Custom serialization and SetDirtyBit

Hi,

I’ve been trying to find some information about dirty bit in regards to custom serialization. As far as I can tell SetDirtyBit works only if you use SyncVars.

Am I missing something or should I implement this myself?

Thank you

http://docs.unity3d.com/Manual/UNetStateSync.html

I have read that page from the manual, I was looking for some clarification on it’s implementation when not using SyncVars.

From what I understand, every NetworkBehaviour has syncVarDirtyBits, but only if you use SyncVars it is written to automatically.

Am I able to use it as my custom dirty bit mask or will it’s value be overwritten automatically?

SyncVar accessor properties write to the dirty mask, and it is set to zero after an update is sent. Those are the only built-in interactions.

1 Like

For anyone with this problem here go’s a solution. It’s kinda bad but it works (NOTE : Haven’t tested the code but it should work. If you have any problems just comment and i’ll fix it) :

public class Player : NetworkBehaviour
{
    public delegate void PlayerEventHandler(Player sender);

    public event PlayerEventHandler  OnCanBeDamagedChanged,
                                                          OnCanBeHealedChanged,
                                                          OnCanBeRevivedChanged;

    public bool canBeDamaged = true;
    public bool canBeHealed = true;
    public bool canBeRevived = true;

    public const uint BIT_CANBEDAMAGED = 1u,
                               BIT_CANBEHEALED = 2u,
                               BIT_CANBEREVIVED = 4u; //It has to power o 2 (i.e : 8, 16, 32, 64, 128 etc...)

    protected virtual void Start()
    {
        OnCanBeDamagedChanged += OnCanBeDamagedHasChanged;
        OnCanBeHealedChanged += OnCanBeHealedHasChanged;
        OnCanBeRevivedChanged += OnCanBeRevivedHasChanged;
    }

    protected virtual void OnDestroy()
    {
        OnCanBeDamagedChanged -= OnCanBeDamagedHasChanged;
        OnCanBeHealedChanged -= OnCanBeHealedHasChanged;
        OnCanBeRevivedChanged -= OnCanBeRevivedHasChanged;
    }

    //Press A to change canBeDamaged value
    [ServerCallback]
    protected virtual void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
            CanBeDamaged = !canBeDamaged;
    }

   public override bool OnSerialize(NetworkWriter writer, bool initialState)
    {
        bool e = base.OnSerialize(writer, initialState);
        if (initialState)
        {
            writer.Write(canBeDamaged);
            writer.Write(canBeHealed);
            writer.Write(canBeRevived);

            return true;
        }

        writer.Write(syncVarDirtyBits);

        bool wroteSyncVar = false;  

        if ((syncVarDirtyBits & BIT_CANBEDAMAGED) != 0u)
        {
            wroteSyncVar = true;
            writer.Write(canBeDamaged);
        }

        if ((syncVarDirtyBits & BIT_CANBEHEALED) != 0u)
        {
            wroteSyncVar = true;
            writer.Write(canBeHealed);
        }

        if ((syncVarDirtyBits & BIT_CANBEREVIVED) != 0u)
        {
            wroteSyncVar = true;
            writer.Write(canBeRevived);
        }

        return e || wroteSyncVar;
    }

    public override void OnDeserialize(NetworkReader reader, bool initialState)
    {
        base.OnDeserialize(reader, initialState);

        if (initialState)
        {
             canBeDamaged = reader.ReadBoolean();
             canBeHealed     = reader.ReadBoolean();
             canBeRevived   = reader.ReadBoolean();

             return;
        }

         uint _syncVarDirtyBits = reader.ReadUint32();

         if ((_syncVarDirtyBits & BIT_CANBEDAMAGED) != 0u)
         {
             canBeDamaged = reader.ReadBoolean();
             if (OnCanBeDamagedChanged != null)
                 OnCanBeDamagedChanged(this);
         }

         if ((_syncVarDirtyBits & BIT_CANBEHEALED) != 0u)
         {
             canBeHealed = reader.ReadBoolean();
             if (OnCanBeHealedChanged != null)
                 OnCanBeHealedChanged(this);
         }

         if ((_syncVarDirtyBits & BIT_CANBEREVIVED) != 0u)
         {
             canBeRevived = reader.ReadBoolean();
             if (OnCanBeRevivedChanged != null)
                 OnCanBeRevivedChanged(this);
         }
    }
 
    protected virtual void OnCanBeDamagedHasChanged()
    {
        //Code for logic when can be damaged
        //changes
        Debug.Log("Player : " + gameObject.name + ", can be damaged has been changed to " + canBeDamaged.ToString());
    }

    protected virtual void OnCanBeHealedHasChanged()
    {
        //Code for logic when can be healed
        //changes
        Debug.Log("Player : " + gameObject.name + ", can be healedhas been changed to " + canBeHealed.ToString());
    }

    protected virtual void OnCanBeRevivedHasChanged()
    {
        //Code for logic when can be revived
        //changes
        Debug.Log("Player : " + gameObject.name + ", can be revived has been changed to " + canBeRevived.ToString());
    }

    //Use this implementation to make this NetworkBehaviour
    //send a new update if canbeDamaged changes
    //(NOTE : The "set" implementation should run on the Server)
    public bool CanBeDamaged
    {
        get { return canBeDamaged; }

        set
        {
            if (canBeDamaged == value)
                return;

            canBeDamaged = value;

            if (isServer)
                SetDirtyBit(BIT_CANBEDAMAGED);

            if (OnCanBeDamagedChanged != null)
                OnCanBeDamagedChanged(this);
        }
    }
    public bool CanBeHealed
    {
        get { return canBeHealed; }

        set
        {
            if (canBeHealed == value)
                return;

            canBeHealed = value;

            if (isServer)
                SetDirtyBit(BIT_CANBEHEALED);

            if (OnCanBeHealedChanged != null)
                OnCanBeHealedChanged(this);
        }
    }
    public bool CanBeRevived
    {
        get { return canBeRevived; }

        set
        {
            if (canBeRevived == value)
                return;

            canBeRevived = value;

            if (isServer)
                SetDirtyBit(BIT_CANBEREVIVED);

            if (OnCanBeRevivedChanged != null)
                OnCanBeRevivedChanged(this);
        }
    }
}

When you set “CanBeDamaged”, to a different value, then it will make the NetworkBehaviour send a new update, forcing it to serialize.

if you want to listen player canBeDamaged from outside the Player class then use the event :

something like :

public class Test : MonoBehaviour
{
    private Player player;

    private void Start()
    {
        player = GameObject.FindObjectOfType<Player>();

        if (player != null)
        {
            //Assigning Player OnCanBeDamagedChanged event
            player.OnCanBeDamagedChanged += OnPlayerCanBeDamagedChanged;
        }
    }
 
    private void OnDestroy()
    {
        if (player != null)
        {
            player.OnCanBeDamagedChanged -= OnPlayerCanBeDamagedChanged;
            player = null;
        }
    }

    private void OnPlayerCanBeDamagedChanged(Player sender)
    {
        //Code when player can be damaged changes.
        Debug.Log("Player Can Be Damaged = " + sender.canBeDamaged.ToString());
    }
}

(NOTE : For OnSerialize to work properly you can’t have any SyncVar fields. The Documentation explains it further :
“…If a class has SyncVars, then an implementation of this function and OnDeserialize() are added automatically to the class. So a class that has SyncVars cannot also have custom serialization functions…” From : https://docs.unity3d.com/ScriptReference/Networking.NetworkBehaviour.OnSerialize.html )

Hope this helps.