Search Unity

  1. Check out the Unite LA keynote for updates on the Visual Effect Editor, the FPS Sample, ECS, Unity for Film and more! Watch it now!
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  4. Want more efficiency in your development work? Sign up to receive weekly tech and creative know-how from Unity experts.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Unity Multiplayer Custom serialization and SetDirtyBit

Discussion in 'Connected Games' started by glitchers, Jul 23, 2015.

  1. glitchers

    glitchers

    Joined:
    Apr 29, 2014
    Posts:
    48
    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
     
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
  3. glitchers

    glitchers

    Joined:
    Apr 29, 2014
    Posts:
    48
    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?
     
  4. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    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.
     
    glitchers likes this.
  5. Mr-Slat

    Mr-Slat

    Joined:
    Jan 25, 2013
    Posts:
    2
    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) :

    Code (CSharp):
    1.  
    2. public class Player : NetworkBehaviour
    3. {
    4.     public delegate void PlayerEventHandler(Player sender);
    5.  
    6.     public event PlayerEventHandler  OnCanBeDamagedChanged,
    7.                                                           OnCanBeHealedChanged,
    8.                                                           OnCanBeRevivedChanged;
    9.  
    10.     public bool canBeDamaged = true;
    11.     public bool canBeHealed = true;
    12.     public bool canBeRevived = true;
    13.  
    14.     public const uint BIT_CANBEDAMAGED = 1u,
    15.                                BIT_CANBEHEALED = 2u,
    16.                                BIT_CANBEREVIVED = 4u; //It has to power o 2 (i.e : 8, 16, 32, 64, 128 etc...)
    17.  
    18.     protected virtual void Start()
    19.     {
    20.         OnCanBeDamagedChanged += OnCanBeDamagedHasChanged;
    21.         OnCanBeHealedChanged += OnCanBeHealedHasChanged;
    22.         OnCanBeRevivedChanged += OnCanBeRevivedHasChanged;
    23.     }
    24.  
    25.     protected virtual void OnDestroy()
    26.     {
    27.         OnCanBeDamagedChanged -= OnCanBeDamagedHasChanged;
    28.         OnCanBeHealedChanged -= OnCanBeHealedHasChanged;
    29.         OnCanBeRevivedChanged -= OnCanBeRevivedHasChanged;
    30.     }
    31.  
    32.     //Press A to change canBeDamaged value
    33.     [ServerCallback]
    34.     protected virtual void Update()
    35.     {
    36.         if (Input.GetKeyDown(KeyCode.A))
    37.             CanBeDamaged = !canBeDamaged;
    38.     }
    39.  
    40.    public override bool OnSerialize(NetworkWriter writer, bool initialState)
    41.     {
    42.         bool e = base.OnSerialize(writer, initialState);
    43.         if (initialState)
    44.         {
    45.             writer.Write(canBeDamaged);
    46.             writer.Write(canBeHealed);
    47.             writer.Write(canBeRevived);
    48.  
    49.             return true;
    50.         }
    51.  
    52.         writer.Write(syncVarDirtyBits);
    53.  
    54.         bool wroteSyncVar = false;  
    55.  
    56.         if ((syncVarDirtyBits & BIT_CANBEDAMAGED) != 0u)
    57.         {
    58.             wroteSyncVar = true;
    59.             writer.Write(canBeDamaged);
    60.         }
    61.  
    62.         if ((syncVarDirtyBits & BIT_CANBEHEALED) != 0u)
    63.         {
    64.             wroteSyncVar = true;
    65.             writer.Write(canBeHealed);
    66.         }
    67.  
    68.         if ((syncVarDirtyBits & BIT_CANBEREVIVED) != 0u)
    69.         {
    70.             wroteSyncVar = true;
    71.             writer.Write(canBeRevived);
    72.         }
    73.  
    74.         return e || wroteSyncVar;
    75.     }
    76.  
    77.     public override void OnDeserialize(NetworkReader reader, bool initialState)
    78.     {
    79.         base.OnDeserialize(reader, initialState);
    80.  
    81.         if (initialState)
    82.         {
    83.              canBeDamaged = reader.ReadBoolean();
    84.              canBeHealed     = reader.ReadBoolean();
    85.              canBeRevived   = reader.ReadBoolean();
    86.  
    87.              return;
    88.         }
    89.  
    90.          uint _syncVarDirtyBits = reader.ReadUint32();
    91.  
    92.          if ((_syncVarDirtyBits & BIT_CANBEDAMAGED) != 0u)
    93.          {
    94.              canBeDamaged = reader.ReadBoolean();
    95.              if (OnCanBeDamagedChanged != null)
    96.                  OnCanBeDamagedChanged(this);
    97.          }
    98.  
    99.          if ((_syncVarDirtyBits & BIT_CANBEHEALED) != 0u)
    100.          {
    101.              canBeHealed = reader.ReadBoolean();
    102.              if (OnCanBeHealedChanged != null)
    103.                  OnCanBeHealedChanged(this);
    104.          }
    105.  
    106.          if ((_syncVarDirtyBits & BIT_CANBEREVIVED) != 0u)
    107.          {
    108.              canBeRevived = reader.ReadBoolean();
    109.              if (OnCanBeRevivedChanged != null)
    110.                  OnCanBeRevivedChanged(this);
    111.          }
    112.     }
    113.  
    114.     protected virtual void OnCanBeDamagedHasChanged()
    115.     {
    116.         //Code for logic when can be damaged
    117.         //changes
    118.         Debug.Log("Player : " + gameObject.name + ", can be damaged has been changed to " + canBeDamaged.ToString());
    119.     }
    120.  
    121.     protected virtual void OnCanBeHealedHasChanged()
    122.     {
    123.         //Code for logic when can be healed
    124.         //changes
    125.         Debug.Log("Player : " + gameObject.name + ", can be healedhas been changed to " + canBeHealed.ToString());
    126.     }
    127.  
    128.     protected virtual void OnCanBeRevivedHasChanged()
    129.     {
    130.         //Code for logic when can be revived
    131.         //changes
    132.         Debug.Log("Player : " + gameObject.name + ", can be revived has been changed to " + canBeRevived.ToString());
    133.     }
    134.  
    135.     //Use this implementation to make this NetworkBehaviour
    136.     //send a new update if canbeDamaged changes
    137.     //(NOTE : The "set" implementation should run on the Server)
    138.     public bool CanBeDamaged
    139.     {
    140.         get { return canBeDamaged; }
    141.  
    142.         set
    143.         {
    144.             if (canBeDamaged == value)
    145.                 return;
    146.  
    147.             canBeDamaged = value;
    148.  
    149.             if (isServer)
    150.                 SetDirtyBit(BIT_CANBEDAMAGED);
    151.  
    152.             if (OnCanBeDamagedChanged != null)
    153.                 OnCanBeDamagedChanged(this);
    154.         }
    155.     }
    156.     public bool CanBeHealed
    157.     {
    158.         get { return canBeHealed; }
    159.  
    160.         set
    161.         {
    162.             if (canBeHealed == value)
    163.                 return;
    164.  
    165.             canBeHealed = value;
    166.  
    167.             if (isServer)
    168.                 SetDirtyBit(BIT_CANBEHEALED);
    169.  
    170.             if (OnCanBeHealedChanged != null)
    171.                 OnCanBeHealedChanged(this);
    172.         }
    173.     }
    174.     public bool CanBeRevived
    175.     {
    176.         get { return canBeRevived; }
    177.  
    178.         set
    179.         {
    180.             if (canBeRevived == value)
    181.                 return;
    182.  
    183.             canBeRevived = value;
    184.  
    185.             if (isServer)
    186.                 SetDirtyBit(BIT_CANBEREVIVED);
    187.  
    188.             if (OnCanBeRevivedChanged != null)
    189.                 OnCanBeRevivedChanged(this);
    190.         }
    191.     }
    192. }
    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 :

    Code (CSharp):
    1.  
    2. public class Test : MonoBehaviour
    3. {
    4.     private Player player;
    5.  
    6.     private void Start()
    7.     {
    8.         player = GameObject.FindObjectOfType<Player>();
    9.  
    10.         if (player != null)
    11.         {
    12.             //Assigning Player OnCanBeDamagedChanged event
    13.             player.OnCanBeDamagedChanged += OnPlayerCanBeDamagedChanged;
    14.         }
    15.     }
    16.  
    17.     private void OnDestroy()
    18.     {
    19.         if (player != null)
    20.         {
    21.             player.OnCanBeDamagedChanged -= OnPlayerCanBeDamagedChanged;
    22.             player = null;
    23.         }
    24.     }
    25.  
    26.     private void OnPlayerCanBeDamagedChanged(Player sender)
    27.     {
    28.         //Code when player can be damaged changes.
    29.         Debug.Log("Player Can Be Damaged = " + sender.canBeDamaged.ToString());
    30.     }
    31. }
    32.  
    (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.
     
    Last edited: Nov 19, 2018 at 8:28 AM