private void NetworkVariableUpdate(ulong clientId)
        {
            if (!CouldHaveDirtyNetworkVariables())
            {
                return;
            }

            for (int j = 0; j < m_ChannelMappedNetworkVariableIndexes.Count; j++)
            {
                using (var buffer = PooledNetworkBuffer.Get())
                {
                    using (var writer = PooledNetworkWriter.Get(buffer))
                    {
                        writer.WriteUInt64Packed(NetworkObjectId);
                        writer.WriteUInt16Packed(NetworkObject.GetNetworkBehaviourOrderIndex(this));

                        // Write the current tick frame
                        // todo: this is currently done per channel, per tick. The snapshot system might improve on this
                        writer.WriteUInt16Packed(CurrentTick);

                        bool writtenAny = false;
                        for (int k = 0; k < NetworkVariableFields.Count; k++)
                        {
                            if (!m_ChannelMappedNetworkVariableIndexes[j].Contains(k))
                            {
                                // This var does not belong to the currently iterating channel group.
                                if (NetworkManager.Singleton.NetworkConfig.EnsureNetworkVariableLengthSafety)
                                {
                                    writer.WriteUInt16Packed(0);
                                }
                                else
                                {
                                    writer.WriteBool(false);
                                }

                                continue;
                            }

                            bool isDirty = NetworkVariableFields[k].IsDirty(); // cache this here. You never know what operations users will do in the dirty methods

                            //   if I'm dirty AND a client, write (server always has all permissions)
                            //   if I'm dirty AND the server AND the client can read me, send.
                            bool shouldWrite = isDirty && (!IsServer || NetworkVariableFields[k].CanClientRead(clientId));

                            if (NetworkManager.Singleton.NetworkConfig.EnsureNetworkVariableLengthSafety)
                            {
                                if (!shouldWrite)
                                {
                                    writer.WriteUInt16Packed(0);
                                }
                            }
                            else
                            {
                                writer.WriteBool(shouldWrite);
                            }

                            if (shouldWrite)
                            {
                                writtenAny = true;

                                // write the network tick at which this NetworkVariable was modified remotely
                                // this will allow lag-compensation
                                writer.WriteUInt16Packed(NetworkVariableFields[k].RemoteTick);

                                if (NetworkManager.Singleton.NetworkConfig.EnsureNetworkVariableLengthSafety)
                                {
                                    using (var varBuffer = PooledNetworkBuffer.Get())
                                    {
                                        NetworkVariableFields[k].WriteDelta(varBuffer);
                                        varBuffer.PadBuffer();

                                        writer.WriteUInt16Packed((ushort)varBuffer.Length);
                                        buffer.CopyFrom(varBuffer);
                                    }
                                }
                                else
                                {
                                    NetworkVariableFields[k].WriteDelta(buffer);
                                }

                                if (!m_NetworkVariableIndexesToResetSet.Contains(k))
                                {
                                    m_NetworkVariableIndexesToResetSet.Add(k);
                                    m_NetworkVariableIndexesToReset.Add(k);
                                }
                            }
                        }

                        if (writtenAny)
                        {
                            InternalMessageSender.Send(clientId, NetworkConstants.NETWORK_VARIABLE_DELTA, m_ChannelsForNetworkVariableGroups[j], buffer);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Used to serialize a NetworkObjects during scene synchronization that occurs
        /// upon a client being approved or a scene transition.
        /// </summary>
        /// <param name="writer">writer into the outbound stream</param>
        /// <param name="targetClientId">clientid we are targeting</param>
        internal void SerializeSceneObject(NetworkWriter writer, ulong targetClientId)
        {
            writer.WriteBool(IsPlayerObject);
            writer.WriteUInt64Packed(NetworkObjectId);
            writer.WriteUInt64Packed(OwnerClientId);

            NetworkObject parentNetworkObject = null;

            if (!AlwaysReplicateAsRoot && transform.parent != null)
            {
                parentNetworkObject = transform.parent.GetComponent <NetworkObject>();
            }

            if (parentNetworkObject == null)
            {
                // We don't have a parent
                writer.WriteBool(false);
            }
            else
            {
                // We do have a parent
                writer.WriteBool(true);
                // Write the parent's NetworkObjectId to be used for linking back to the child
                writer.WriteUInt64Packed(parentNetworkObject.NetworkObjectId);
            }

            // Write if we are a scene object or not
            writer.WriteBool(IsSceneObject ?? true);

            // Write the hash for this NetworkObject
            writer.WriteUInt32Packed(GlobalObjectIdHash);

            if (IncludeTransformWhenSpawning == null || IncludeTransformWhenSpawning(OwnerClientId))
            {
                // Set the position and rotation data marker to true (i.e. flag to know, when reading from the stream, that position and rotation data follows).
                writer.WriteBool(true);

                // Write position
                writer.WriteSinglePacked(transform.position.x);
                writer.WriteSinglePacked(transform.position.y);
                writer.WriteSinglePacked(transform.position.z);

                // Write rotation
                writer.WriteSinglePacked(transform.rotation.eulerAngles.x);
                writer.WriteSinglePacked(transform.rotation.eulerAngles.y);
                writer.WriteSinglePacked(transform.rotation.eulerAngles.z);
            }
            else
            {
                // Set the position and rotation data marker to false (i.e. flag to know, when reading from the stream, that position and rotation data *was not included*)
                writer.WriteBool(false);
            }

            // Write whether we are including network variable data
            writer.WriteBool(NetworkManager.NetworkConfig.EnableNetworkVariable);

            //If we are including NetworkVariable data
            if (NetworkManager.NetworkConfig.EnableNetworkVariable)
            {
                var buffer = writer.GetStream() as NetworkBuffer;

                // Write placeholder size, NOT as a packed value, initially as zero (i.e. we do not know how much NetworkVariable data will be written yet)
                writer.WriteUInt32(0);

                // Mark our current position before we potentially write any NetworkVariable data
                var positionBeforeNetworkVariableData = buffer.Position;

                // Write network variable data
                WriteNetworkVariableData(buffer, targetClientId);

                // If our current buffer position is greater than our positionBeforeNetworkVariableData then we wrote NetworkVariable data
                // Part 1: This will include the total NetworkVariable data size, if there was NetworkVariable data written, to the stream
                // in order to be able to skip past this entry on the deserialization side in the event this NetworkObject fails to be
                // constructed (See Part 2 below in the DeserializeSceneObject method)
                if (buffer.Position > positionBeforeNetworkVariableData)
                {
                    // Store our current stream buffer position
                    var endOfNetworkVariableData = buffer.Position;

                    // Calculate the total NetworkVariable data size written
                    var networkVariableDataSize = endOfNetworkVariableData - positionBeforeNetworkVariableData;

                    // Move the stream position back to just before we wrote our size (we include the unpacked UInt32 data size placeholder)
                    buffer.Position = positionBeforeNetworkVariableData - sizeof(uint);

                    // Now write the actual data size written into our unpacked UInt32 placeholder position
                    writer.WriteUInt32((uint)(networkVariableDataSize));

                    // Finally, revert the buffer position back to the end of the network variable data written
                    buffer.Position = endOfNetworkVariableData;
                }
            }
        }
 /// <summary>
 /// Returns a the NetworkBehaviour with a given BehaviourId for the current NetworkObject
 /// </summary>
 /// <param name="behaviourId">The behaviourId to return</param>
 /// <returns>Returns NetworkBehaviour with given behaviourId</returns>
 protected NetworkBehaviour GetNetworkBehaviour(ushort behaviourId)
 {
     return(NetworkObject.GetNetworkBehaviourAtOrderIndex(behaviourId));
 }