Ejemplo n.º 1
0
        public override void Send(ulong clientId, ArraySegment <byte> data, string channelName)
        {
            if (!channelNameToId.ContainsKey(channelName))
            {
                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                {
                    NetworkLog.LogError("SteamP2PTransport - Can't Send to client, channel with channelName: " + channelName + " is not present");
                }
                return;
            }

            int     channelId = channelNameToId[channelName];
            P2PSend sendType  = channelSendTypes[channelId];

            if (clientId == ServerClientId)
            {
                SteamNetworking.SendP2PPacket(serverUser.SteamId, data.Array, data.Count, channelId, sendType);
            }
            else
            {
                if (connectedUsers.ContainsKey(clientId))
                {
                    SteamNetworking.SendP2PPacket(connectedUsers[clientId].SteamId, data.Array, data.Count, channelId, sendType);
                }
                else
                {
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                    {
                        NetworkLog.LogError("SteamP2PTransport - Can't Send to client, client not connected, clientId: " + clientId);
                    }
                }
            }
        }
        /// <summary>
        /// Cleans up our instance count and warns if there instantiation issues
        /// </summary>
        public void Dispose()
        {
            Shutdown();

#if UNITY_EDITOR || DEVELOPMENT_BUILD
            if (s_RpcQueueContainerInstances > 0)
            {
                if (NetworkLog.CurrentLogLevel == LogLevel.Developer)
                {
                    NetworkLog.LogInfo($"[Instance : {s_RpcQueueContainerInstances}] {nameof(RpcQueueContainer)} disposed.");
                }

                s_RpcQueueContainerInstances--;
            }
            else //This should never happen...if so something else has gone very wrong.
            {
                if (NetworkLog.CurrentLogLevel >= LogLevel.Normal)
                {
                    NetworkLog.LogError($"[*** Warning ***] {nameof(RpcQueueContainer)} is being disposed twice?");
                }

                throw new Exception("[*** Warning ***] System state is not stable!  Check all references to the Dispose method!");
            }
#endif
        }
Ejemplo n.º 3
0
 public override ulong GetCurrentRtt(ulong clientId)
 {
     if (isServer)
     {
         if (clientId == ServerClientId)
         {
             return(0);
         }
         if (connectedUsers.ContainsKey(clientId))
         {
             return(connectedUsers[clientId].Ping.Get());
         }
         else
         {
             if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
             {
                 NetworkLog.LogError("SteamP2PTransport - Can't GetCurrentRtt from client, client not connected, clientId: " + clientId);
             }
         }
     }
     else
     {
         return(serverUser.Ping.Get());
     }
     return(0ul);
 }
Ejemplo n.º 4
0
        public override void DisconnectRemoteClient(ulong clientId)
        {
            if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
            {
                NetworkLog.LogInfo("SteamP2PTransport - DisconnectRemoteClient clientId: " + clientId);
            }

            if (!connectedUsers.ContainsKey(clientId))
            {
                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                {
                    NetworkLog.LogError("SteamP2PTransport - Can't disconect client, client not connected, clientId: " + clientId);
                }
                return;
            }

            SteamNetworking.SendP2PPacket(connectedUsers[clientId].SteamId, new byte[] { 0 }, 1, (int)InternalChannelType.Disconnect, P2PSend.Reliable);
            SteamId steamId = connectedUsers[clientId].SteamId;

            NetworkingManager.Singleton.StartCoroutine(Delay(100, () =>
            { //Need to delay the closing of the p2p sessions to not block the disconect message before it is sent.
                SteamNetworking.CloseP2PSessionWithUser(steamId);
                if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
                {
                    NetworkLog.LogInfo("SteamP2PTransport - DisconnectRemoteClient - has Closed P2P Session With clientId: " + clientId);
                }
            }));

            connectedUsers.Remove(clientId);
        }
Ejemplo n.º 5
0
 internal NetworkedBehaviour GetBehaviourAtOrderIndex(ushort index)
 {
     if (index >= childNetworkedBehaviours.Count)
     {
         if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
         {
             NetworkLog.LogError("Behaviour index (" + index + ") was out of bounds (" + childNetworkedBehaviours.Count + "). Did you mess up the order of your NetworkedBehaviours?");
         }
         return(null);
     }
     return(childNetworkedBehaviours[index]);
 }
Ejemplo n.º 6
0
        internal NetworkBehaviour GetNetworkBehaviourAtOrderIndex(ushort index)
        {
            if (index >= ChildNetworkBehaviours.Count)
            {
                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                {
                    NetworkLog.LogError($"Behaviour index was out of bounds. Did you mess up the order of your {nameof(NetworkBehaviour)}s?");
                }

                return(null);
            }

            return(ChildNetworkBehaviours[index]);
        }
Ejemplo n.º 7
0
        // This method is responsible for unwrapping a message, that is extracting the messagebody.
        internal static NetworkBuffer UnwrapMessage(NetworkBuffer inputBuffer, out byte messageType)
        {
            using (var inputHeaderReader = PooledNetworkReader.Get(inputBuffer))
            {
                if (inputBuffer.Length < 1)
                {
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                    {
                        NetworkLog.LogError("The incoming message was too small");
                    }
                    messageType = NetworkConstants.INVALID;

                    return(null);
                }

                messageType = inputHeaderReader.ReadByteDirect();

                // The input stream is now ready to be read from. It's "safe" and has the correct position
                return(inputBuffer);
            }
        }
Ejemplo n.º 8
0
        public override void Init()
        {
            if (!SteamClient.IsValid)
            {
                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                {
                    NetworkLog.LogError("SteamClient.IsValid - false - SteamClient is not Initialized, SteamP2PTransport can not run without it, init with SteamClient.Init()");
                }
                return;
            }

            channelIdToName.Clear();
            channelNameToId.Clear();
            channelSendTypes.Clear();
            channelCounter     = 0;
            currentPollChannel = 0;

            // Add SteamP2PTransport internal channels
            for (int i = 0; i < (int)InternalChannelType.InternalChannelsCount; i++)
            {
                int channelId = AddChannel(ChannelType.Reliable);
            }

            // MLAPI Channels
            for (int i = 0; i < MLAPI_CHANNELS.Length; i++)
            {
                int channelId = AddChannel(MLAPI_CHANNELS[i].Type);
                channelIdToName.Add(channelId, MLAPI_CHANNELS[i].Name);
                channelNameToId.Add(MLAPI_CHANNELS[i].Name, channelId);
            }

            // User Channels
            for (int i = 0; i < UserChannels.Count; i++)
            {
                int channelId = AddChannel(UserChannels[i].Type);
                channelIdToName.Add(channelId, UserChannels[i].Name);
                channelNameToId.Add(UserChannels[i].Name, channelId);
            }
        }
        public override SocketTasks StartServer()
        {
            var topology = new HostTopology(GetConfig(), MaxConnections);

            if (SupportWebsocket)
            {
                if (!UseMLAPIRelay)
                {
                    int websocketHostId = UnityEngine.Networking.NetworkTransport.AddWebsocketHost(topology, ServerWebsocketListenPort);
                }
                else
                {
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                    {
                        NetworkLog.LogError("Cannot create websocket host when using MLAPI relay");
                    }
                }
            }

            int normalHostId = RelayTransport.AddHost(topology, ServerListenPort, true);

            return(SocketTask.Done.AsTasks());
        }
Ejemplo n.º 10
0
        private static ulong HashMethodNameAndValidate(string name)
        {
            ulong hash = NetworkedBehaviour.HashMethodName(name);

            if (hashResults.ContainsKey(hash))
            {
                string hashResult = hashResults[hash];

                if (hashResult != name)
                {
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                    {
                        NetworkLog.LogError("Hash collision detected for RPC method. The method \"" + name + "\" collides with the method \"" + hashResult + "\". This can be solved by increasing the amount of bytes to use for hashing in the NetworkConfig or changing the name of one of the conflicting methods.");
                    }
                }
            }
            else
            {
                hashResults.Add(hash, name);
            }

            return(hash);
        }
Ejemplo n.º 11
0
        // Only ran on Client
        internal static NetworkObject CreateLocalNetworkObject(bool softCreate, ulong instanceId, ulong prefabHash, ulong?parentNetworkId, Vector3?position, Quaternion?rotation)
        {
            NetworkObject parentNetworkObject = null;

            if (parentNetworkId != null && SpawnedObjects.ContainsKey(parentNetworkId.Value))
            {
                parentNetworkObject = SpawnedObjects[parentNetworkId.Value];
            }
            else if (parentNetworkId != null)
            {
                if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                {
                    NetworkLog.LogWarning("Cannot find parent. Parent objects always have to be spawned and replicated BEFORE the child");
                }
            }

            if (!NetworkManager.Singleton.NetworkConfig.EnableSceneManagement || NetworkManager.Singleton.NetworkConfig.UsePrefabSync || !softCreate)
            {
                // Create the object
                if (CustomSpawnHandlers.ContainsKey(prefabHash))
                {
                    var networkObject = CustomSpawnHandlers[prefabHash](position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity));

                    if (!ReferenceEquals(parentNetworkObject, null))
                    {
                        networkObject.transform.SetParent(parentNetworkObject.transform, true);
                    }

                    if (NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad)
                    {
                        GameObject.DontDestroyOnLoad(networkObject.gameObject);
                    }

                    return(networkObject);
                }
                else
                {
                    int prefabIndex = GetNetworkPrefabIndexOfHash(prefabHash);

                    if (prefabIndex < 0)
                    {
                        if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                        {
                            NetworkLog.LogError($"Failed to create object locally. [{nameof(prefabHash)}={prefabHash}]. Hash could not be found. Is the prefab registered?");
                        }

                        return(null);
                    }

                    var prefab        = NetworkManager.Singleton.NetworkConfig.NetworkPrefabs[prefabIndex].Prefab;
                    var networkObject = ((position == null && rotation == null) ? MonoBehaviour.Instantiate(prefab) : MonoBehaviour.Instantiate(prefab, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity))).GetComponent <NetworkObject>();

                    if (!ReferenceEquals(parentNetworkObject, null))
                    {
                        networkObject.transform.SetParent(parentNetworkObject.transform, true);
                    }

                    if (NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad)
                    {
                        GameObject.DontDestroyOnLoad(networkObject.gameObject);
                    }

                    return(networkObject);
                }
            }
            else
            {
                // SoftSync them by mapping
                if (!PendingSoftSyncObjects.ContainsKey(instanceId))
                {
                    // TODO: Fix this message
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                    {
                        NetworkLog.LogError("Cannot find pending soft sync object. Is the projects the same?");
                    }
                    return(null);
                }

                var networkObject = PendingSoftSyncObjects[instanceId];
                PendingSoftSyncObjects.Remove(instanceId);

                if (!ReferenceEquals(parentNetworkObject, null))
                {
                    networkObject.transform.SetParent(parentNetworkObject.transform, true);
                }

                return(networkObject);
            }
        }
Ejemplo n.º 12
0
        internal static BitStream WrapMessage(byte messageType, ulong clientId, BitStream messageBody, SecuritySendFlags flags)
        {
            try
            {
                bool encrypted     = ((flags & SecuritySendFlags.Encrypted) == SecuritySendFlags.Encrypted) && NetworkingManager.Singleton.NetworkConfig.EnableEncryption;
                bool authenticated = (flags & SecuritySendFlags.Authenticated) == SecuritySendFlags.Authenticated && NetworkingManager.Singleton.NetworkConfig.EnableEncryption;

                PooledBitStream outStream = PooledBitStream.Get();

                using (PooledBitWriter outWriter = PooledBitWriter.Get(outStream))
                {
                    outWriter.WriteBit(encrypted);
                    outWriter.WriteBit(authenticated);

#if !DISABLE_CRYPTOGRAPHY
                    if (authenticated || encrypted)
                    {
                        outWriter.WritePadBits();
                        long hmacWritePos = outStream.Position;

                        if (authenticated)
                        {
                            outStream.Write(HMAC_PLACEHOLDER, 0, HMAC_PLACEHOLDER.Length);
                        }

                        if (encrypted)
                        {
                            using (RijndaelManaged rijndael = new RijndaelManaged())
                            {
                                rijndael.GenerateIV();
                                rijndael.Padding = PaddingMode.PKCS7;

                                byte[] key = NetworkingManager.Singleton.IsServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey();

                                if (key == null)
                                {
                                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                                    {
                                        NetworkLog.LogError("Failed to grab key");
                                    }
                                    return(null);
                                }

                                rijndael.Key = key;

                                outStream.Write(rijndael.IV);

                                using (CryptoStream encryptionStream = new CryptoStream(outStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write))
                                {
                                    encryptionStream.WriteByte(messageType);
                                    encryptionStream.Write(messageBody.GetBuffer(), 0, (int)messageBody.Length);
                                }
                            }
                        }
                        else
                        {
                            outStream.WriteByte(messageType);
                            outStream.Write(messageBody.GetBuffer(), 0, (int)messageBody.Length);
                        }

                        if (authenticated)
                        {
                            byte[] key = NetworkingManager.Singleton.IsServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey();

                            if (key == null)
                            {
                                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                                {
                                    NetworkLog.LogError("Failed to grab key");
                                }
                                return(null);
                            }

                            using (HMACSHA256 hmac = new HMACSHA256(key))
                            {
                                byte[] computedHmac = hmac.ComputeHash(outStream.GetBuffer(), 0, (int)outStream.Length);

                                outStream.Position = hmacWritePos;
                                outStream.Write(computedHmac, 0, computedHmac.Length);
                            }
                        }
                    }
                    else
                    {
#endif
                    outWriter.WriteBits(messageType, 6);
                    outStream.Write(messageBody.GetBuffer(), 0, (int)messageBody.Length);
#if !DISABLE_CRYPTOGRAPHY
                }
#endif
                }

                return(outStream);
            }
            catch (Exception e)
            {
                if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                {
                    NetworkLog.LogError("Error while wrapping headers");
                }
                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                {
                    NetworkLog.LogError(e.ToString());
                }

                return(null);
            }
        }
Ejemplo n.º 13
0
        // This method is responsible for unwrapping a message, that is extracting the messagebody.
        // Could include decrypting and/or authentication.
        internal static BitStream UnwrapMessage(BitStream inputStream, ulong clientId, out byte messageType, out SecuritySendFlags security)
        {
            using (PooledBitReader inputHeaderReader = PooledBitReader.Get(inputStream))
            {
                try
                {
                    if (inputStream.Length < 1)
                    {
                        if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                        {
                            NetworkLog.LogError("The incoming message was too small");
                        }
                        messageType = MLAPIConstants.INVALID;
                        security    = SecuritySendFlags.None;
                        return(null);
                    }

                    bool isEncrypted     = inputHeaderReader.ReadBit();
                    bool isAuthenticated = inputHeaderReader.ReadBit();

                    if (isEncrypted && isAuthenticated)
                    {
                        security = SecuritySendFlags.Encrypted | SecuritySendFlags.Authenticated;
                    }
                    else if (isEncrypted)
                    {
                        security = SecuritySendFlags.Encrypted;
                    }
                    else if (isAuthenticated)
                    {
                        security = SecuritySendFlags.Authenticated;
                    }
                    else
                    {
                        security = SecuritySendFlags.None;
                    }


#if !DISABLE_CRYPTOGRAPHY
                    if (isEncrypted || isAuthenticated)
                    {
                        if (!NetworkingManager.Singleton.NetworkConfig.EnableEncryption)
                        {
                            if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                            {
                                NetworkLog.LogError("Got a encrypted and/or authenticated message but key exchange (\"encryption\") was not enabled");
                            }
                            messageType = MLAPIConstants.INVALID;
                            return(null);
                        }

                        // Skip last bits in first byte
                        inputHeaderReader.SkipPadBits();

                        if (isAuthenticated)
                        {
                            long hmacStartPos = inputStream.Position;

                            int readHmacLength = inputStream.Read(HMAC_BUFFER, 0, HMAC_BUFFER.Length);

                            if (readHmacLength != HMAC_BUFFER.Length)
                            {
                                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                                {
                                    NetworkLog.LogError("HMAC length was invalid");
                                }
                                messageType = MLAPIConstants.INVALID;
                                return(null);
                            }

                            // Now we have read the HMAC, we need to set the hmac in the input to 0s to perform the HMAC.
                            inputStream.Position = hmacStartPos;
                            inputStream.Write(HMAC_PLACEHOLDER, 0, HMAC_PLACEHOLDER.Length);

                            byte[] key = NetworkingManager.Singleton.IsServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey();

                            if (key == null)
                            {
                                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                                {
                                    NetworkLog.LogError("Failed to grab key");
                                }
                                messageType = MLAPIConstants.INVALID;
                                return(null);
                            }

                            using (HMACSHA256 hmac = new HMACSHA256(key))
                            {
                                byte[] computedHmac = hmac.ComputeHash(inputStream.GetBuffer(), 0, (int)inputStream.Length);


                                if (!CryptographyHelper.ConstTimeArrayEqual(computedHmac, HMAC_BUFFER))
                                {
                                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                                    {
                                        NetworkLog.LogError("Received HMAC did not match the computed HMAC");
                                    }
                                    messageType = MLAPIConstants.INVALID;
                                    return(null);
                                }
                            }
                        }

                        if (isEncrypted)
                        {
                            int ivRead = inputStream.Read(IV_BUFFER, 0, IV_BUFFER.Length);

                            if (ivRead != IV_BUFFER.Length)
                            {
                                if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                                {
                                    NetworkLog.LogError("Invalid IV size");
                                }
                                messageType = MLAPIConstants.INVALID;
                                return(null);
                            }

                            PooledBitStream outputStream = PooledBitStream.Get();

                            using (RijndaelManaged rijndael = new RijndaelManaged())
                            {
                                rijndael.IV      = IV_BUFFER;
                                rijndael.Padding = PaddingMode.PKCS7;

                                byte[] key = NetworkingManager.Singleton.IsServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey();

                                if (key == null)
                                {
                                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                                    {
                                        NetworkLog.LogError("Failed to grab key");
                                    }
                                    messageType = MLAPIConstants.INVALID;
                                    return(null);
                                }

                                rijndael.Key = key;

                                using (CryptoStream cryptoStream = new CryptoStream(outputStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write))
                                {
                                    cryptoStream.Write(inputStream.GetBuffer(), (int)inputStream.Position, (int)(inputStream.Length - inputStream.Position));
                                }

                                outputStream.Position = 0;

                                if (outputStream.Length == 0)
                                {
                                    if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                                    {
                                        NetworkLog.LogError("The incoming message was too small");
                                    }
                                    messageType = MLAPIConstants.INVALID;
                                    return(null);
                                }

                                int msgType = outputStream.ReadByte();
                                messageType = msgType == -1 ? MLAPIConstants.INVALID : (byte)msgType;
                            }

                            return(outputStream);
                        }
                        else
                        {
                            if (inputStream.Length - inputStream.Position <= 0)
                            {
                                if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                                {
                                    NetworkLog.LogError("The incoming message was too small");
                                }
                                messageType = MLAPIConstants.INVALID;
                                return(null);
                            }

                            int msgType = inputStream.ReadByte();
                            messageType = msgType == -1 ? MLAPIConstants.INVALID : (byte)msgType;
                            return(inputStream);
                        }
                    }
                    else
                    {
#endif
                    messageType = inputHeaderReader.ReadByteBits(6);
                    // The input stream is now ready to be read from. It's "safe" and has the correct position
                    return(inputStream);

#if !DISABLE_CRYPTOGRAPHY
                }
#endif
                }
                catch (Exception e)
                {
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                    {
                        NetworkLog.LogError("Error while unwrapping headers");
                    }
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                    {
                        NetworkLog.LogError(e.ToString());
                    }

                    security    = SecuritySendFlags.None;
                    messageType = MLAPIConstants.INVALID;
                    return(null);
                }
            }
        }
Ejemplo n.º 14
0
        internal static void HandleNetworkVariableUpdate(List <INetworkVariable> networkVariableList, Stream stream, ulong clientId, NetworkBehaviour logInstance, NetworkManager networkManager)
        {
            using (var reader = PooledNetworkReader.Get(stream))
            {
                for (int i = 0; i < networkVariableList.Count; i++)
                {
                    ushort varSize = 0;

                    if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
                    {
                        varSize = reader.ReadUInt16Packed();

                        if (varSize == 0)
                        {
                            continue;
                        }
                    }
                    else
                    {
                        if (!reader.ReadBool())
                        {
                            continue;
                        }
                    }

                    if (networkManager.IsServer && !networkVariableList[i].CanClientWrite(clientId))
                    {
                        if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
                        {
                            if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                            {
                                NetworkLog.LogWarning($"Client wrote to {nameof(NetworkVariable)} without permission. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}");
                            }

                            stream.Position += varSize;
                            continue;
                        }

                        //This client wrote somewhere they are not allowed. This is critical
                        //We can't just skip this field. Because we don't actually know how to dummy read
                        //That is, we don't know how many bytes to skip. Because the interface doesn't have a
                        //Read that gives us the value. Only a Read that applies the value straight away
                        //A dummy read COULD be added to the interface for this situation, but it's just being too nice.
                        //This is after all a developer fault. A critical error should be fine.
                        // - TwoTen
                        if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                        {
                            NetworkLog.LogError($"Client wrote to {nameof(NetworkVariable)} without permission. No more variables can be read. This is critical. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}");
                        }

                        return;
                    }

                    long readStartPos = stream.Position;

                    networkVariableList[i].ReadField(stream, NetworkTickSystem.NoTick, NetworkTickSystem.NoTick);
                    PerformanceDataManager.Increment(ProfilerConstants.NetworkVarUpdates);

                    ProfilerStatManager.NetworkVarsRcvd.Record();

                    if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
                    {
                        if (stream is NetworkBuffer networkBuffer)
                        {
                            networkBuffer.SkipPadBits();
                        }

                        if (stream.Position > (readStartPos + varSize))
                        {
                            if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                            {
                                NetworkLog.LogWarning($"Var update read too far. {stream.Position - (readStartPos + varSize)} bytes. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}");
                            }

                            stream.Position = readStartPos + varSize;
                        }
                        else if (stream.Position < (readStartPos + varSize))
                        {
                            if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                            {
                                NetworkLog.LogWarning($"Var update read too little. {(readStartPos + varSize) - stream.Position} bytes. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}");
                            }

                            stream.Position = readStartPos + varSize;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Should only run on the client
        /// </summary>
        internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash, ulong ownerClientId, ulong?parentNetworkId, Vector3?position, Quaternion?rotation)
        {
            NetworkObject parentNetworkObject = null;

            if (parentNetworkId != null)
            {
                if (SpawnedObjects.TryGetValue(parentNetworkId.Value, out NetworkObject networkObject))
                {
                    parentNetworkObject = networkObject;
                }
                else
                {
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
                    {
                        NetworkLog.LogWarning("Cannot find parent. Parent objects always have to be spawned and replicated BEFORE the child");
                    }
                }
            }

            if (!NetworkManager.NetworkConfig.EnableSceneManagement || !softCreate)
            {
                // If the prefab hash has a registered INetworkPrefabInstanceHandler derived class
                if (NetworkManager.PrefabHandler.ContainsHandler(prefabHash))
                {
                    // Let the handler spawn the NetworkObject
                    var networkObject = NetworkManager.PrefabHandler.HandleNetworkPrefabSpawn(prefabHash, ownerClientId, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity));

                    if (parentNetworkObject != null)
                    {
                        networkObject.transform.SetParent(parentNetworkObject.transform, true);
                    }

                    if (NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad)
                    {
                        UnityEngine.Object.DontDestroyOnLoad(networkObject.gameObject);
                    }

                    return(networkObject);
                }
                else
                {
                    // See if there is a valid registered NetworkPrefabOverrideLink associated with the provided prefabHash
                    GameObject networkPrefabReference = null;
                    if (NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(prefabHash))
                    {
                        switch (NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks[prefabHash].Override)
                        {
                        default:
                        case NetworkPrefabOverride.None:
                            networkPrefabReference = NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks[prefabHash].Prefab;
                            break;

                        case NetworkPrefabOverride.Hash:
                        case NetworkPrefabOverride.Prefab:
                            networkPrefabReference = NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks[prefabHash].OverridingTargetPrefab;
                            break;
                        }
                    }

                    // If not, then there is an issue (user possibly didn't register the prefab properly?)
                    if (networkPrefabReference == null)
                    {
                        if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                        {
                            NetworkLog.LogError($"Failed to create object locally. [{nameof(prefabHash)}={prefabHash}]. {nameof(NetworkPrefab)} could not be found. Is the prefab registered with {nameof(NetworkManager)}?");
                        }
                        return(null);
                    }

                    // Otherwise, instantiate an instance of the NetworkPrefab linked to the prefabHash
                    var networkObject = ((position == null && rotation == null) ? UnityEngine.Object.Instantiate(networkPrefabReference) : UnityEngine.Object.Instantiate(networkPrefabReference, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity))).GetComponent <NetworkObject>();

                    networkObject.NetworkManagerOwner = NetworkManager;

                    if (parentNetworkObject != null)
                    {
                        networkObject.transform.SetParent(parentNetworkObject.transform, true);
                    }

                    if (NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad)
                    {
                        UnityEngine.Object.DontDestroyOnLoad(networkObject.gameObject);
                    }

                    return(networkObject);
                }
            }
            else
            {
                // SoftSync them by mapping
                if (!PendingSoftSyncObjects.TryGetValue(prefabHash, out NetworkObject networkObject))
                {
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                    {
                        NetworkLog.LogError($"{nameof(NetworkPrefab)} hash was not found! In-Scene placed {nameof(NetworkObject)} soft synchronization failure for Hash: {prefabHash}!");
                    }
                    return(null);
                }

                PendingSoftSyncObjects.Remove(prefabHash);

                if (parentNetworkObject != null)
                {
                    networkObject.transform.SetParent(parentNetworkObject.transform, true);
                }

                return(networkObject);
            }
        }