internal static void OnUpdateVarsMessage(UpdateVarsMessage msg)
        {
            if (LogFilter.Debug)
            {
                Debug.Log("ClientScene.OnUpdateVarsMessage " + msg.netId);
            }

            if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null)
            {
                using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload))
                    localObject.OnDeserializeAllSafely(networkReader, false);
            }
            else
            {
                Debug.LogWarning("Did not find target for sync message for " + msg.netId + " . Note: this can be completely normal because UDP messages may arrive out of order, so this message might have arrived after a Destroy message.");
            }
        }
예제 #2
0
        internal void OnSyncEventMessage(SyncEventMessage msg)
        {
            if (logger.LogEnabled())
            {
                logger.Log("ClientScene.OnSyncEventMessage " + msg.netId);
            }

            if (Spawned.TryGetValue(msg.netId, out NetworkIdentity identity))
            {
                using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload))
                    identity.HandleSyncEvent(msg.componentIndex, msg.functionHash, networkReader);
            }
            else
            {
                logger.LogWarning("Did not find target for SyncEvent message for " + msg.netId);
            }
        }
        static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage msg)
        {
            identity.Reset();

            if (msg.assetId != Guid.Empty)
            {
                identity.assetId = msg.assetId;
            }

            if (!identity.gameObject.activeSelf)
            {
                identity.gameObject.SetActive(true);
            }

            // apply local values for VR support
            identity.transform.localPosition = msg.position;
            identity.transform.localRotation = msg.rotation;
            identity.transform.localScale    = msg.scale;
            identity.hasAuthority            = msg.isOwner;
            identity.netId = msg.netId;

            if (msg.isLocalPlayer)
            {
                InternalAddPlayer(identity);
            }

            // deserialize components if any payload
            // (Count is 0 if there were no components)
            if (msg.payload.Count > 0)
            {
                using (PooledNetworkReader payloadReader = NetworkReaderPool.GetReader(msg.payload))
                {
                    identity.OnDeserializeAllSafely(payloadReader, true);
                }
            }

            NetworkIdentity.spawned[msg.netId] = identity;

            // objects spawned as part of initial state are started on a second pass
            if (isSpawnFinished)
            {
                identity.NotifyAuthority();
                identity.OnStartClient();
                CheckForLocalPlayer(identity);
            }
        }
예제 #4
0
        /// <summary>
        /// This function invokes the registered handler function for a message.
        /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para>
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message object to process.</param>
        /// <returns>Returns true if the handler was successfully invoked</returns>
        public bool InvokeHandler <T>(T msg, int channelId)
            where T : struct, NetworkMessage
        {
            using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
            {
                // if it is a value type,  just use typeof(T) to avoid boxing
                // this works because value types cannot be derived
                // if it is a reference type (for example NetworkMessage),
                // ask the message for the real type
                int msgType = MessagePacker.GetId <T>();

                MessagePacker.Pack(msg, writer);
                ArraySegment <byte> segment = writer.ToArraySegment();
                using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(segment))
                    return(InvokeHandler(msgType, networkReader, channelId));
            }
        }
예제 #5
0
        void CmdOnAnimationServerMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters)
        {
            // Ignore messages from client if not in client authority mode
            if (!clientAuthority)
            {
                return;
            }

            // Debug.Log("OnAnimationMessage for netId=" + netId);

            // handle and broadcast
            using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters))
            {
                HandleAnimMsg(stateHash, normalizedTime, layerId, weight, networkReader);
                RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, weight, parameters);
            }
        }
        // unpack a message we received
        public static T Unpack <T>(byte[] data) where T : IMessageBase, new()
        {
            using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(data))
            {
                int msgType = GetId <T>();

                int id = networkReader.ReadUInt16();
                if (id != msgType)
                {
                    throw new FormatException("Invalid message,  could not unpack " + typeof(T).FullName);
                }

                T message = new T();
                message.Deserialize(networkReader);

                return(message);
            }
        }
예제 #7
0
        internal static void OnSyncEventMessage(SyncEventMessage msg)
        {
            if (LogFilter.Debug)
            {
                Debug.Log("ClientScene.OnSyncEventMessage " + msg.netId);
            }

            if (NetworkIdentity.spawned.TryGetValue(msg.netId, out var identity))
            {
                var networkReader = NetworkReaderPool.GetReader(msg.payload);
                identity.HandleSyncEvent(msg.componentIndex, msg.functionHash, networkReader);
                NetworkReaderPool.Recycle(networkReader);
            }
            else
            {
                Debug.LogWarning("Did not find target for SyncEvent message for " + msg.netId);
            }
        }
        void CmdClientToServerSync(byte[] payload)
        {
            // deserialize payload
            NetworkReader networkReader = NetworkReaderPool.GetReader(payload);

            DeserializeFromReader(networkReader);
            NetworkReaderPool.Recycle(networkReader);

            // server-only mode does no interpolation to save computations,
            // but let's set the position directly
            if (isServer && !isClient)
            {
                ApplyPositionRotationScale(goal.localPosition, goal.localRotation, goal.localScale);
            }

            // set dirty so that OnSerialize broadcasts it
            SetDirtyBit(1UL);
        }
예제 #9
0
        /// <summary>
        /// This function invokes the registered handler function for a message.
        /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para>
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message object to process.</param>
        /// <returns></returns>
        public bool InvokeHandler <T>(T msg, int channelId) where T : IMessageBase
        {
            // get writer from pool
            using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
            {
                // if it is a value type,  just use typeof(T) to avoid boxing
                // this works because value types cannot be derived
                // if it is a reference type (for example IMessageBase),
                // ask the message for the real type
                int msgType = MessagePacker.GetId(typeof(T).IsValueType ? typeof(T) : msg.GetType());

                Debug.Log("[NetworkConnection].InvokeHandler -- msg: " + msg.ToString());

                MessagePacker.Pack(msg, writer);
                ArraySegment <byte> segment = writer.ToArraySegment();
                using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(segment))
                    return(InvokeHandler(msgType, networkReader, channelId));
            }
        }
예제 #10
0
        internal void OnRpcMessage(RpcMessage msg)
        {
            if (logger.LogEnabled())
            {
                logger.Log("ClientScene.OnRPCMessage hash:" + msg.functionHash + " netId:" + msg.netId);
            }

            Skeleton skeleton = RemoteCallHelper.GetSkeleton(msg.functionHash);

            if (skeleton.invokeType != MirrorInvokeType.ClientRpc)
            {
                throw new MethodInvocationException($"Invalid RPC call with id {msg.functionHash}");
            }
            if (client.Spawned.TryGetValue(msg.netId, out NetworkIdentity identity) && identity != null)
            {
                using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload))
                    identity.HandleRemoteCall(skeleton, msg.componentIndex, networkReader);
            }
        }
예제 #11
0
        // note: original HLAPI HandleBytes function handled >1 message in a while loop, but this wasn't necessary
        //       anymore because NetworkServer/NetworkClient Update both use while loops to handle >1 data events per
        //       frame already.
        //       -> in other words, we always receive 1 message per Receive call, never two.
        //       -> can be tested easily with a 1000ms send delay and then logging amount received in while loops here
        //          and in NetworkServer/Client Update. HandleBytes already takes exactly one.
        /// <summary>
        /// This function allows custom network connection classes to process data from the network before it is passed to the application.
        /// </summary>
        /// <param name="buffer">The data received.</param>
        internal void TransportReceive(ArraySegment <byte> buffer, int channelId)
        {
            // unpack message
            using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(buffer))
            {
                try
                {
                    int msgType = MessagePacker.UnpackId(networkReader);

                    // try to invoke the handler for that message
                    InvokeHandler(msgType, networkReader, channelId);
                }
                catch (Exception ex)
                {
                    Debug.LogError("Closed connection: " + this + ". Invalid message " + ex);
                    Disconnect();
                }
            }
        }
예제 #12
0
        /// <summary>
        /// This function invokes the registered handler function for a message.
        /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para>
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message object to process.</param>
        /// <returns></returns>
        public bool InvokeHandler <T>(T msg, int channelId) where T : IMessageBase
        {
            // get writer from pool
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            // pack and invoke
            int msgType = MessagePacker.GetId(typeof(T).IsValueType ? typeof(T) : msg.GetType());

            MessagePacker.Pack(msg, writer);
            ArraySegment <byte> segment = writer.ToArraySegment();
            NetworkReader       reader  = NetworkReaderPool.GetReader(segment);
            bool result = InvokeHandler(msgType, reader, channelId);

            NetworkReaderPool.Recycle(reader);

            // recycle writer and return
            NetworkWriterPool.Recycle(writer);
            return(result);
        }
예제 #13
0
        // unpack a message we received
        public static T Unpack <T>(byte[] data) where T : IMessageBase, new()
        {
            NetworkReader reader = NetworkReaderPool.GetReader(data);

            int msgType = GetId <T>();

            int id = reader.ReadUInt16();

            if (id != msgType)
            {
                throw new FormatException("Invalid message,  could not unpack " + typeof(T).FullName);
            }

            T message = typeof(T).IsValueType ? default : new T();

                        message.Deserialize(reader);
                        NetworkReaderPool.Recycle(reader);
                        return(message);
        }
        void CmdOnMotionServerMessage(int stateHash, byte[] parameters)
        {
            // Ignore messages from client if not in client authority mode
            if (!clientAuthority)
            {
                return;
            }

            if (logger.LogEnabled())
            {
                logger.Log("OnAnimationMessage for netId=" + netId);
            }

            // handle and broadcast
            using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters))
            {
                HandleMotionMsg(stateHash, networkReader);
                RpcOnMotionClientMessage(stateHash, parameters);
            }
        }
예제 #15
0
        public void ReadBytesCountTooBigTest()
        {
            // calling ReadBytes with a count bigger than what is in Reader
            // should throw an exception
            byte[] bytes = { 0x00, 0x01 };

            using (PooledNetworkReader reader = NetworkReaderPool.GetReader(bytes))
            {
                try
                {
                    reader.ReadBytes(bytes, bytes.Length + 1);
                    // BAD: IF WE GOT HERE, THEN NO EXCEPTION WAS THROWN
                    Assert.Fail();
                }
                catch (EndOfStreamException)
                {
                    // GOOD
                }
            }
        }
예제 #16
0
        public void ShrinkCapacity()
        {
            NetworkReaderPool.Capacity = 2;

            // get Reader and recycle so we have 2 in there, hence 'next' is at limit
            PooledNetworkReader a = NetworkReaderPool.GetReader(default(ArraySegment <byte>));
            PooledNetworkReader b = NetworkReaderPool.GetReader(default(ArraySegment <byte>));

            NetworkReaderPool.Recycle(a);
            NetworkReaderPool.Recycle(b);

            // shrink
            NetworkReaderPool.Capacity = 1;

            // get one. should return the only one which is still in there.
            PooledNetworkReader c = NetworkReaderPool.GetReader(default(ArraySegment <byte>));

            Assert.That(c, !Is.Null);
            Assert.That(c == a || c == b);
        }
예제 #17
0
        void CmdClientToServerSync(byte[] payload)
        {
            // Ignore messages from client if not in client authority mode
            if (!clientAuthority)
            {
                return;
            }

            // deserialize payload
            using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(payload)) DeserializeFromReader(networkReader);

            // server-only mode does no interpolation to save computations,
            // but let's set the position directly
            if (isServer && !isClient)
            {
                ApplyPositionRotationScale(goal.thePosition, goal.theRotation, goal.theScale);
            }

            // set dirty so that OnSerialize broadcasts it
            SetDirtyBit(1UL);
        }
예제 #18
0
        /// <summary>
        /// This function invokes the registered handler function for a message.
        /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para>
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message object to process.</param>
        /// <returns></returns>
        public bool InvokeHandler <T>(T msg, int channelId) where T : IMessageBase
        {
            // get writer from pool
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            // if it is a value type,  just use typeof(T) to avoid boxing
            // this works because value types cannot be derived
            // if it is a reference type (for example IMessageBase),
            // ask the message for the real type
            int msgType = MessagePacker.GetId(typeof(T).IsValueType ? typeof(T) : msg.GetType());

            MessagePacker.Pack(msg, writer);
            ArraySegment <byte> segment       = writer.ToArraySegment();
            NetworkReader       networkReader = NetworkReaderPool.GetReader(segment);
            bool result = InvokeHandler(msgType, networkReader, channelId);

            NetworkReaderPool.Recycle(networkReader);

            // recycle writer and return
            NetworkWriterPool.Recycle(writer);
            return(result);
        }
예제 #19
0
        /// <summary>
        /// This function allows custom network connection classes to process data from the network before it is passed to the application.
        /// </summary>
        /// <param name="buffer">The data received.</param>
        /// <param name="channelId"></param>
        internal void TransportReceive(ArraySegment <byte> buffer, int channelId)
        {
            if (buffer.Count < MessagePacker.HeaderSize)
            {
                logger.LogError($"ConnectionRecv {this} Message was too short (messages should start with message id)");
                Disconnect();
                return;
            }

            // unpack message
            using (PooledNetworkReader reader = NetworkReaderPool.GetReader(buffer))
            {
                // the other end might batch multiple messages into one packet.
                // we need to try to unpack multiple times.
                while (reader.Position < reader.Length)
                {
                    if (!UnpackAndInvoke(reader, channelId))
                    {
                        break;
                    }
                }
            }
        }
예제 #20
0
        public void PoolReUsesReadersUpToSizeLimit()
        {
            NetworkReaderPool.Capacity = 1;

            // get 2 Readers
            PooledNetworkReader a = NetworkReaderPool.GetReader(default(ArraySegment <byte>));
            PooledNetworkReader b = NetworkReaderPool.GetReader(default(ArraySegment <byte>));

            // recycle all
            NetworkReaderPool.Recycle(a);
            NetworkReaderPool.Recycle(b);

            // get 2 new ones
            PooledNetworkReader c = NetworkReaderPool.GetReader(default(ArraySegment <byte>));
            PooledNetworkReader d = NetworkReaderPool.GetReader(default(ArraySegment <byte>));

            // exactly one should be reused, one should be new
            bool cReused = c == a || c == b;
            bool dReused = d == a || d == b;

            Assert.That((cReused && !dReused) ||
                        (!cReused && dReused));
        }
예제 #21
0
        /// <summary>
        /// Handle ServerRpc from specific player, this could be one of multiple players on a single client
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="msg"></param>
        void OnServerRpcMessage(INetworkConnection conn, ServerRpcMessage msg)
        {
            if (!server.Spawned.TryGetValue(msg.netId, out NetworkIdentity identity) || identity is null)
            {
                if (logger.WarnEnabled())
                {
                    logger.LogWarning("Spawned object not found when handling ServerRpc message [netId=" + msg.netId + "]");
                }
                return;
            }
            Skeleton skeleton = RemoteCallHelper.GetSkeleton(msg.functionHash);

            if (skeleton.invokeType != MirrorInvokeType.ServerRpc)
            {
                throw new MethodInvocationException($"Invalid ServerRpc for id {msg.functionHash}");
            }

            // ServerRpcs can be for player objects, OR other objects with client-authority
            // -> so if this connection's controller has a different netId then
            //    only allow the ServerRpc if clientAuthorityOwner
            if (skeleton.cmdRequireAuthority && identity.ConnectionToClient != conn)
            {
                if (logger.WarnEnabled())
                {
                    logger.LogWarning("ServerRpc for object without authority [netId=" + msg.netId + "]");
                }
                return;
            }

            if (logger.LogEnabled())
            {
                logger.Log("OnServerRpcMessage for netId=" + msg.netId + " conn=" + conn);
            }

            using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload))
                identity.HandleRemoteCall(skeleton, msg.componentIndex, networkReader, conn, msg.replyId);
        }
예제 #22
0
 void RpcOnAnimationParametersClientMessage(byte[] parameters)
 {
     using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters))
         HandleAnimParamsMsg(networkReader);
 }
예제 #23
0
 void RpcOnAnimationClientMessage(int stateHash, float normalizedTime, int layerId, byte[] parameters)
 {
     using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(parameters))
         HandleAnimMsg(stateHash, normalizedTime, layerId, networkReader);
 }
 public void Dispose()
 {
     NetworkReaderPool.Recycle(this);
 }
예제 #25
0
 public void Dispose() => NetworkReaderPool.Return(this);