示例#1
0
        /// <summary>
        /// Returns a base64 encoded version of the config
        /// </summary>
        /// <returns></returns>
        public string ToBase64()
        {
            NetworkConfig config = this;

            using (PooledBitStream stream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                {
                    writer.WriteUInt16Packed(config.ProtocolVersion);
                    writer.WriteBits((byte)config.Transport, 5);

                    writer.WriteUInt16Packed((ushort)config.Channels.Count);
                    for (int i = 0; i < config.Channels.Count; i++)
                    {
                        writer.WriteString(config.Channels[i].Name);
                        writer.WriteBits((byte)config.Channels[i].Type, 5);
                    }

                    writer.WriteUInt16Packed((ushort)config.RegisteredScenes.Count);
                    for (int i = 0; i < config.RegisteredScenes.Count; i++)
                    {
                        writer.WriteString(config.RegisteredScenes[i]);
                    }

                    writer.WriteUInt16Packed((ushort)config.NetworkedPrefabs.Count);
                    for (int i = 0; i < config.NetworkedPrefabs.Count; i++)
                    {
                        writer.WriteBool(config.NetworkedPrefabs[i].playerPrefab);
                        writer.WriteString(config.NetworkedPrefabs[i].name);
                    }

                    writer.WriteInt32Packed(config.MessageBufferSize);
                    writer.WriteInt32Packed(config.ReceiveTickrate);
                    writer.WriteInt32Packed(config.MaxReceiveEventsPerTickRate);
                    writer.WriteInt32Packed(config.SendTickrate);
                    writer.WriteInt32Packed(config.EventTickrate);
                    writer.WriteInt32Packed(config.MaxConnections);
                    writer.WriteInt32Packed(config.ConnectPort);
                    writer.WriteString(config.ConnectAddress);
                    writer.WriteInt32Packed(config.ClientConnectionBufferTimeout);
                    writer.WriteBool(config.ConnectionApproval);
                    writer.WriteInt32Packed(config.SecondsHistory);
                    writer.WriteBool(config.HandleObjectSpawning);
                    writer.WriteBool(config.EnableEncryption);
                    writer.WriteBool(config.SignKeyExchange);
                    writer.WriteBool(config.EnableSceneSwitching);
                    writer.WriteInt32Packed(config.LoadSceneTimeOut);
                    writer.WriteBool(config.EnableTimeResync);
                    writer.WriteBits((byte)config.RpcHashSize, 3);
                    stream.PadStream();

                    return(Convert.ToBase64String(stream.ToArray()));
                }
            }
        }
        /// <inheritdoc />
        public void WriteDelta(Stream stream)
        {
            using (PooledBitWriter writer = PooledBitWriter.Get(stream))
            {
                writer.WriteUInt16Packed((ushort)dirtyEvents.Count);
                for (int i = 0; i < dirtyEvents.Count; i++)
                {
                    writer.WriteBits((byte)dirtyEvents[i].eventType, 2);

                    switch (dirtyEvents[i].eventType)
                    {
                    case NetworkedSetEvent <T> .EventType.Add:
                    {
                        writer.WriteObjectPacked(dirtyEvents[i].value);         //BOX
                    }
                    break;

                    case NetworkedSetEvent <T> .EventType.Remove:
                    {
                        writer.WriteObjectPacked(dirtyEvents[i].value);         //BOX
                    }
                    break;

                    case NetworkedSetEvent <T> .EventType.Clear:
                    {
                        //Nothing has to be written
                    }
                    break;
                    }
                }
            }
        }
示例#3
0
        internal void SendClientRPCPerformance(ulong hash, uint clientId, Stream messageStream, string channel, SecuritySendFlags security)
        {
            if (!IsServer && IsRunning)
            {
                //We are NOT a server.
                if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                {
                    LogHelper.LogWarning("Only clients and host can invoke ClientRPC");
                }
                return;
            }

            using (PooledBitStream stream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                {
                    writer.WriteUInt32Packed(NetworkId);
                    writer.WriteUInt16Packed(NetworkedObject.GetOrderIndex(this));
                    writer.WriteUInt64Packed(hash);

                    stream.CopyFrom(messageStream);

                    if (IsHost && clientId == NetworkingManager.Singleton.LocalClientId)
                    {
                        messageStream.Position = 0;
                        InvokeClientRPCLocal(hash, NetworkingManager.Singleton.LocalClientId, messageStream);
                    }
                    else
                    {
                        InternalMessageHandler.Send(clientId, MLAPIConstants.MLAPI_CLIENT_RPC, string.IsNullOrEmpty(channel) ? "MLAPI_DEFAULT_MESSAGE" : channel, stream, security);
                    }
                }
            }
        }
示例#4
0
        /// <summary>
        /// Returns a base64 encoded version of the config
        /// </summary>
        /// <returns></returns>
        public string ToBase64()
        {
            NetworkConfig config = this;

            using (PooledBitStream stream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                {
                    writer.WriteUInt16Packed(config.ProtocolVersion);

                    writer.WriteUInt16Packed((ushort)config.RegisteredScenes.Count);

                    for (int i = 0; i < config.RegisteredScenes.Count; i++)
                    {
                        writer.WriteString(config.RegisteredScenes[i]);
                    }

                    writer.WriteInt32Packed(config.ServerTargetFramerate);
                    writer.WriteInt32Packed(config.NetworkedTransformTickrate);
                    writer.WriteInt32Packed(config.ClientCommandTickrate);
                    writer.WriteInt32Packed(config.MaxReceiveEventsPerTickRate);
                    writer.WriteInt32Packed(config.LagCompensationTickRate);
                    writer.WriteInt32Packed(config.EventTickrate);
                    writer.WriteInt32Packed(config.ClientConnectionBufferTimeout);
                    writer.WriteBool(config.ConnectionApproval);
                    writer.WriteInt32Packed(config.SecondsHistory);
                    writer.WriteBool(config.EnableEncryption);
                    writer.WriteBool(config.SignKeyExchange);
                    writer.WriteInt32Packed(config.LoadSceneTimeOut);
                    writer.WriteBool(config.EnableTimeResync);
                    writer.WriteBool(config.EnsureNetworkedVarLengthSafety);
                    writer.WriteBits((byte)config.RpcHashSize, 2);
                    writer.WriteBool(ForceSamePrefabs);
                    writer.WriteBool(UsePrefabSync);
                    writer.WriteBool(EnableSceneManagement);
                    writer.WriteBool(RecycleNetworkIds);
                    writer.WriteSinglePacked(NetworkIdRecycleDelay);
                    writer.WriteBool(EnableNetworkedVar);
                    writer.WriteBool(AllowRuntimeSceneChanges);
                    writer.WriteBool(EnableNetworkLogs);
                    stream.PadStream();

                    return(Convert.ToBase64String(stream.ToArray()));
                }
            }
        }
示例#5
0
        /// <summary>
        /// Gets a SHA256 hash of parts of the NetworkingConfiguration instance
        /// </summary>
        /// <param name="cache"></param>
        /// <returns></returns>
        public ulong GetConfig(bool cache = true)
        {
            if (ConfigHash != null && cache)
            {
                return(ConfigHash.Value);
            }

            Sort();

            using (PooledBitStream stream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                {
                    writer.WriteUInt16Packed(ProtocolVersion);
                    writer.WriteString(MLAPIConstants.MLAPI_PROTOCOL_VERSION);

                    for (int i = 0; i < Channels.Count; i++)
                    {
                        writer.WriteString(Channels[i].Name);
                        writer.WriteByte((byte)Channels[i].Type);
                    }

                    if (EnableSceneSwitching)
                    {
                        for (int i = 0; i < RegisteredScenes.Count; i++)
                        {
                            writer.WriteString(RegisteredScenes[i]);
                        }
                    }

                    if (HandleObjectSpawning && ForceSamePrefabs)
                    {
                        List <NetworkedPrefab> sortedPrefabList = NetworkedPrefabs.OrderBy(x => x.hash).ToList();
                        for (int i = 0; i < sortedPrefabList.Count; i++)
                        {
                            writer.WriteUInt64Packed(sortedPrefabList[i].hash);
                        }
                    }

                    writer.WriteBool(ForceSamePrefabs);
                    writer.WriteBool(HandleObjectSpawning);
                    writer.WriteBool(EnableEncryption);
                    writer.WriteBool(EnableSceneSwitching);
                    writer.WriteBool(SignKeyExchange);
                    writer.WriteBits((byte)RpcHashSize, 3);
                    writer.WriteBits((byte)PrefabHashSize, 3);
                    stream.PadStream();

                    if (cache)
                    {
                        ConfigHash = stream.ToArray().GetStableHash64();
                        return(ConfigHash.Value);
                    }

                    return(stream.ToArray().GetStableHash64());
                }
            }
        }
示例#6
0
 public void Write(Stream stream)
 {
     using (PooledBitWriter writer = PooledBitWriter.Get(stream))
     {
         writer.WriteByte((byte)ImposterCount);
         writer.WriteSinglePacked(MovementSpeed);
         writer.WriteSinglePacked(VoteDuration);
         writer.WriteUInt16Packed((ushort)TaskCount);
     }
 }
示例#7
0
        /// <summary>
        /// Gets a SHA256 hash of parts of the NetworkingConfiguration instance
        /// </summary>
        /// <param name="cache"></param>
        /// <returns></returns>
        public ulong GetConfig(bool cache = true)
        {
            if (ConfigHash != null && cache)
            {
                return(ConfigHash.Value);
            }

            Sort();

            using (PooledBitStream stream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                {
                    writer.WriteUInt16Packed(ProtocolVersion);
                    writer.WriteString(MLAPIConstants.MLAPI_PROTOCOL_VERSION);

                    for (int i = 0; i < Channels.Count; i++)
                    {
                        writer.WriteString(Channels[i].Name);
                        writer.WriteByte((byte)Channels[i].Type);
                    }

                    if (EnableSceneSwitching)
                    {
                        for (int i = 0; i < RegisteredScenes.Count; i++)
                        {
                            writer.WriteString(RegisteredScenes[i]);
                        }
                    }

                    if (HandleObjectSpawning && RequireNetworkedPrefabsAreSyncronized)
                    {
                        for (int i = 0; i < NetworkedPrefabs.Count; i++)
                        {
                            writer.WriteString(NetworkedPrefabs[i].name);
                        }
                    }

                    writer.WriteBool(HandleObjectSpawning);
                    writer.WriteBool(EnableEncryption);
                    writer.WriteBool(EnableSceneSwitching);
                    writer.WriteBool(SignKeyExchange);
                    writer.WriteBits((byte)AttributeMessageMode, 3);

                    // Returns a 160 bit / 20 byte / 5 int checksum of the config
                    if (cache)
                    {
                        ConfigHash = stream.ToArray().GetStableHash64();
                        return(ConfigHash.Value);
                    }
                    return(stream.ToArray().GetStableHash64());
                }
            }
        }
示例#8
0
 /// <inheritdoc />
 public void WriteField(Stream stream)
 {
     using (PooledBitWriter writer = PooledBitWriter.Get(stream))
     {
         writer.WriteUInt16Packed((ushort)list.Count);
         for (int i = 0; i < list.Count; i++)
         {
             writer.WriteObjectPacked(list[i]); //BOX
         }
     }
 }
示例#9
0
        /// <summary>
        /// Writes the current ProfilerTick to the stream
        /// </summary>
        /// <param name="stream">The stream containing</param>
        public void SerializeToStream(Stream stream)
        {
            using (PooledBitWriter writer = PooledBitWriter.Get(stream))
            {
                writer.WriteUInt16Packed((ushort)Events.Count);

                for (int i = 0; i < Events.Count; i++)
                {
                    Events[i].SerializeToStream(stream);
                }
            }
        }
        /// <inheritdoc />
        public void WriteField(Stream stream)
        {
            using (PooledBitWriter writer = PooledBitWriter.Get(stream))
            {
                writer.WriteUInt16Packed((ushort)set.Count);

                foreach (T value in set)
                {
                    writer.WriteObjectPacked(value); //BOX
                }
            }
        }
示例#11
0
 /// <inheritdoc />
 public void WriteField(Stream stream)
 {
     using (PooledBitWriter writer = PooledBitWriter.Get(stream))
     {
         writer.WriteUInt16Packed((ushort)dictionary.Count);
         foreach (KeyValuePair <TKey, TValue> pair in dictionary)
         {
             writer.WriteObjectPacked(pair.Key);
             writer.WriteObjectPacked(pair.Value);
         }
     }
 }
示例#12
0
        /// <inheritdoc />
        public void WriteDelta(Stream stream)
        {
            using (PooledBitWriter writer = PooledBitWriter.Get(stream))
            {
                writer.WriteUInt16Packed((ushort)dirtyEvents.Count);
                for (int i = 0; i < dirtyEvents.Count; i++)
                {
                    writer.WriteBits((byte)dirtyEvents[i].eventType, 3);
                    switch (dirtyEvents[i].eventType)
                    {
                    //F**k me these signatures are proper aids
                    case NetworkedListEvent <T> .EventType.Add:
                    {
                        writer.WriteObjectPacked(dirtyEvents[i].value);         //BOX
                    }
                    break;

                    case NetworkedListEvent <T> .EventType.Insert:
                    {
                        writer.WriteInt32Packed(dirtyEvents[i].index);
                        writer.WriteObjectPacked(dirtyEvents[i].value);         //BOX
                    }
                    break;

                    case NetworkedListEvent <T> .EventType.Remove:
                    {
                        writer.WriteObjectPacked(dirtyEvents[i].value);         //BOX
                    }
                    break;

                    case NetworkedListEvent <T> .EventType.RemoveAt:
                    {
                        writer.WriteInt32Packed(dirtyEvents[i].index);
                    }
                    break;

                    case NetworkedListEvent <T> .EventType.Value:
                    {
                        writer.WriteInt32Packed(dirtyEvents[i].index);
                        writer.WriteObjectPacked(dirtyEvents[i].value);         //BOX
                    }

                    break;

                    case NetworkedListEvent <T> .EventType.Clear:
                    {
                        //Nothing has to be written
                    }
                    break;
                    }
                }
            }
        }
示例#13
0
        /// <summary>
        /// Gets a SHA256 hash of parts of the NetworkingConfiguration instance
        /// </summary>
        /// <param name="cache"></param>
        /// <returns></returns>
        public ulong GetConfig(bool cache = true)
        {
            if (ConfigHash != null && cache)
            {
                return(ConfigHash.Value);
            }

            Sort();

            using (PooledBitStream stream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                {
                    writer.WriteUInt16Packed(ProtocolVersion);
                    writer.WriteString(MLAPIConstants.MLAPI_PROTOCOL_VERSION);

                    if (EnableSceneManagement && !AllowRuntimeSceneChanges)
                    {
                        for (int i = 0; i < RegisteredScenes.Count; i++)
                        {
                            writer.WriteString(RegisteredScenes[i]);
                        }
                    }

                    if (ForceSamePrefabs)
                    {
                        List <NetworkedPrefab> sortedPrefabList = NetworkedPrefabs.OrderBy(x => x.Hash).ToList();
                        for (int i = 0; i < sortedPrefabList.Count; i++)
                        {
                            writer.WriteUInt64Packed(sortedPrefabList[i].Hash);
                        }
                    }

                    writer.WriteBool(EnableNetworkedVar);
                    writer.WriteBool(ForceSamePrefabs);
                    writer.WriteBool(UsePrefabSync);
                    writer.WriteBool(EnableSceneManagement);
                    writer.WriteBool(EnsureNetworkedVarLengthSafety);
                    writer.WriteBool(EnableEncryption);
                    writer.WriteBool(SignKeyExchange);
                    writer.WriteBits((byte)RpcHashSize, 2);
                    stream.PadStream();

                    if (cache)
                    {
                        ConfigHash = stream.ToArray().GetStableHash64();
                        return(ConfigHash.Value);
                    }

                    return(stream.ToArray().GetStableHash64());
                }
            }
        }
示例#14
0
        /// <summary>
        /// Returns a base64 encoded version of the config
        /// </summary>
        /// <returns></returns>
        public string ToBase64()
        {
            NetworkConfig config = this;

            using (PooledBitStream stream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                {
                    writer.WriteUInt16Packed(config.ProtocolVersion);

                    writer.WriteUInt16Packed((ushort)config.RegisteredScenes.Count);

                    for (int i = 0; i < config.RegisteredScenes.Count; i++)
                    {
                        writer.WriteString(config.RegisteredScenes[i]);
                    }

                    writer.WriteInt32Packed(config.ReceiveTickrate);
                    writer.WriteInt32Packed(config.MaxReceiveEventsPerTickRate);
                    writer.WriteInt32Packed(config.SendTickrate);
                    writer.WriteInt32Packed(config.EventTickrate);
                    writer.WriteInt32Packed(config.ClientConnectionBufferTimeout);
                    writer.WriteBool(config.ConnectionApproval);
                    writer.WriteInt32Packed(config.SecondsHistory);
                    writer.WriteBool(config.EnableEncryption);
                    writer.WriteBool(config.SignKeyExchange);
                    writer.WriteInt32Packed(config.LoadSceneTimeOut);
                    writer.WriteBool(config.EnableTimeResync);
                    writer.WriteBits((byte)config.RpcHashSize, 3);
                    writer.WriteBool(ForceSamePrefabs);
                    writer.WriteBool(UsePrefabSync);
                    writer.WriteBool(EnableNetworkedVar);
                    stream.PadStream();

                    return(Convert.ToBase64String(stream.ToArray()));
                }
            }
        }
示例#15
0
        /// <inheritdoc />
        public void WriteDelta(Stream stream)
        {
            using (PooledBitWriter writer = PooledBitWriter.Get(stream))
            {
                writer.WriteUInt16Packed((ushort)dirtyEvents.Count);
                for (int i = 0; i < dirtyEvents.Count; i++)
                {
                    writer.WriteBits((byte)dirtyEvents[i].eventType, 3);
                    switch (dirtyEvents[i].eventType)
                    {
                    case NetworkedDictionaryEvent <TKey, TValue> .NetworkedListEventType.Add:
                    {
                        writer.WriteObjectPacked(dirtyEvents[i].key);
                        writer.WriteObjectPacked(dirtyEvents[i].value);
                    }
                    break;

                    case NetworkedDictionaryEvent <TKey, TValue> .NetworkedListEventType.Remove:
                    {
                        writer.WriteObjectPacked(dirtyEvents[i].key);
                    }
                    break;

                    case NetworkedDictionaryEvent <TKey, TValue> .NetworkedListEventType.RemovePair:
                    {
                        writer.WriteObjectPacked(dirtyEvents[i].key);
                        writer.WriteObjectPacked(dirtyEvents[i].value);
                    }
                    break;

                    case NetworkedDictionaryEvent <TKey, TValue> .NetworkedListEventType.Clear:
                    {
                        //write nothing
                    }
                    break;

                    case NetworkedDictionaryEvent <TKey, TValue> .NetworkedListEventType.Value:
                    {
                        writer.WriteObjectPacked(dirtyEvents[i].key);
                        writer.WriteObjectPacked(dirtyEvents[i].value);
                    }
                    break;

                    default:
                        break;
                    }
                }
            }
        }
示例#16
0
        /// <summary>
        /// Hides a list of objects from a client
        /// </summary>
        /// <param name="networkedObjects">The objects to hide</param>
        /// <param name="clientId">The client to hide the objects from</param>
        public static void NetworkHide(List <NetworkedObject> networkedObjects, ulong clientId)
        {
            if (!NetworkingManager.Singleton.IsServer)
            {
                throw new NotServerException("Only server can change visibility");
            }

            if (clientId == NetworkingManager.Singleton.ServerClientId)
            {
                throw new VisibilityChangeException("Cannot hide an object from the server");
            }

            // Do the safety loop first to prevent putting the MLAPI in an invalid state.
            for (int i = 0; i < networkedObjects.Count; i++)
            {
                if (!networkedObjects[i].IsSpawned)
                {
                    throw new SpawnStateException("Object is not spawned");
                }

                if (!networkedObjects[i].observers.Contains(clientId))
                {
                    throw new VisibilityChangeException("NetworkedObject with NetworkId: " + networkedObjects[i].NetworkId + " is already hidden");
                }
            }


            using (PooledBitStream stream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                {
                    writer.WriteUInt16Packed((ushort)networkedObjects.Count);

                    for (int i = 0; i < networkedObjects.Count; i++)
                    {
                        // Send destroy call
                        networkedObjects[i].observers.Remove(clientId);

                        writer.WriteUInt64Packed(networkedObjects[i].NetworkId);
                    }
                }

                InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_DESTROY_OBJECTS, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null);
            }
        }
示例#17
0
        /// <summary>
        /// Shows a list of previously hidden objects to a client
        /// </summary>
        /// <param name="networkedObjects">The objects to show</param>
        /// <param name="clientId">The client to show the objects to</param>
        /// <param name="payload">An optional payload to send as part of the spawns</param>
        public static void NetworkShow(List <NetworkedObject> networkedObjects, ulong clientId, Stream payload = null)
        {
            if (!NetworkingManager.Singleton.IsServer)
            {
                throw new NotServerException("Only server can change visibility");
            }

            // Do the safety loop first to prevent putting the MLAPI in an invalid state.
            for (int i = 0; i < networkedObjects.Count; i++)
            {
                if (!networkedObjects[i].IsSpawned)
                {
                    throw new SpawnStateException("Object is not spawned");
                }

                if (networkedObjects[i].observers.Contains(clientId))
                {
                    throw new VisibilityChangeException("NetworkedObject with NetworkId: " + networkedObjects[i].NetworkId + " is already visible");
                }
            }

            using (PooledBitStream stream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                {
                    writer.WriteUInt16Packed((ushort)networkedObjects.Count);
                }

                for (int i = 0; i < networkedObjects.Count; i++)
                {
                    // Send spawn call
                    networkedObjects[i].observers.Add(clientId);

                    SpawnManager.WriteSpawnCallForObject(stream, clientId, networkedObjects[i], payload);
                }

                InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_ADD_OBJECTS, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null);
            }
        }
示例#18
0
        internal void NetworkedVarUpdate()
        {
            if (!networkedVarInit)
            {
                NetworkedVarInit();
            }

            //TODO: Do this efficiently.

            if (!CouldHaveDirtyVars())
            {
                return;
            }

            networkedVarIndexesToReset.Clear();
            networkedVarIndexesToResetSet.Clear();

            for (int i = 0; i < NetworkingManager.Singleton.ConnectedClientsList.Count; i++)
            {
                //This iterates over every "channel group".
                for (int j = 0; j < channelMappedVarIndexes.Count; j++)
                {
                    using (PooledBitStream stream = PooledBitStream.Get())
                    {
                        using (PooledBitWriter writer = PooledBitWriter.Get(stream))
                        {
                            writer.WriteUInt32Packed(NetworkId);
                            writer.WriteUInt16Packed(NetworkedObject.GetOrderIndex(this));

                            uint clientId   = NetworkingManager.Singleton.ConnectedClientsList[i].ClientId;
                            bool writtenAny = false;
                            for (int k = 0; k < networkedVarFields.Count; k++)
                            {
                                if (!channelMappedVarIndexes[j].Contains(k))
                                {
                                    //This var does not belong to the currently iterating channel group.
                                    writer.WriteBool(false);
                                    continue;
                                }

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

                                if (isDirty && (!IsServer || networkedVarFields[k].CanClientRead(clientId)))
                                {
                                    writtenAny = true;
                                    networkedVarFields[k].WriteDelta(stream);
                                    if (!networkedVarIndexesToResetSet.Contains(k))
                                    {
                                        networkedVarIndexesToResetSet.Add(k);
                                        networkedVarIndexesToReset.Add(k);
                                    }
                                }
                            }

                            if (writtenAny)
                            {
                                if (IsServer)
                                {
                                    InternalMessageHandler.Send(clientId, MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA, channelsForVarGroups[j], stream, SecuritySendFlags.None);
                                }
                                else
                                {
                                    InternalMessageHandler.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA, channelsForVarGroups[j], stream, SecuritySendFlags.None);
                                }
                            }
                        }
                    }
                }
            }

            for (int i = 0; i < networkedVarIndexesToReset.Count; i++)
            {
                networkedVarFields[networkedVarIndexesToReset[i]].ResetDirty();
            }
        }