Beispiel #1
0
        internal void SendSpawnMessage(NetworkIdentity identity, INetworkConnection conn)
        {
            if (identity.serverOnly)
            {
                return;
            }

            // for easier debugging
            if (logger.LogEnabled())
            {
                logger.Log("Server SendSpawnMessage: name=" + identity.name + " sceneId=" + identity.sceneId.ToString("X") + " netid=" + identity.NetId);
            }

            // one writer for owner, one for observers
            using (PooledNetworkWriter ownerWriter = NetworkWriterPool.GetWriter(), observersWriter = NetworkWriterPool.GetWriter())
            {
                bool isOwner = identity.ConnectionToClient == conn;

                ArraySegment <byte> payload = CreateSpawnMessagePayload(isOwner, identity, ownerWriter, observersWriter);

                var msg = new SpawnMessage
                {
                    netId         = identity.NetId,
                    isLocalPlayer = conn.Identity == identity,
                    isOwner       = isOwner,
                    sceneId       = identity.sceneId,
                    assetId       = identity.AssetId,
                    // use local values for VR support
                    position = identity.transform.localPosition,
                    rotation = identity.transform.localRotation,
                    scale    = identity.transform.localScale,

                    payload = payload,
                };


                conn.Send(msg);
            }
        }
Beispiel #2
0
        // batch as many messages as possible into writer
        // returns true if any batch was made.
        public bool MakeNextBatch(NetworkWriter writer, double timeStamp)
        {
            // if we have no messages then there's nothing to do
            if (messages.Count == 0)
            {
                return(false);
            }

            // make sure the writer is fresh to avoid uncertain situations
            if (writer.Position != 0)
            {
                throw new ArgumentException($"MakeNextBatch needs a fresh writer!");
            }

            // write timestamp first
            // -> double precision for accuracy over long periods of time
            writer.WriteDouble(timeStamp);

            // do start no matter what
            do
            {
                // add next message no matter what. even if > threshold.
                // (we do allow > threshold sized messages as single batch)
                NetworkWriterPooled message = messages.Dequeue();
                ArraySegment <byte> segment = message.ToArraySegment();
                writer.WriteBytes(segment.Array, segment.Offset, segment.Count);

                // return the writer to pool
                NetworkWriterPool.Return(message);
            }
            // keep going as long as we have more messages,
            // AND the next one would fit into threshold.
            while (messages.Count > 0 &&
                   writer.Position + messages.Peek().Position <= threshold);

            // we had messages, so a batch was made
            return(true);
        }
        protected void SendTargetRPCInternal(NetworkConnection conn, Type invokeClass, string rpcName, NetworkWriter writer, int channelId)
        {
            // this was in Weaver before
            if (!NetworkServer.active)
            {
                Debug.LogError("TargetRPC Function " + rpcName + " called on client.");
                return;
            }
            // connection parameter is optional. assign if null.
            if (conn == null)
            {
                conn = connectionToClient;
            }
            // this was in Weaver before
            if (conn is ULocalConnectionToServer)
            {
                Debug.LogError("TargetRPC Function " + rpcName + " called on connection to server");
                return;
            }
            // This cannot use NetworkServer.active, as that is not specific to this object.
            if (!isServer)
            {
                Debug.LogWarning("TargetRpc " + rpcName + " called on un-spawned object: " + name);
                return;
            }

            // construct the message
            RpcMessage message = new RpcMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                functionHash   = GetMethodHash(invokeClass, rpcName), // type+func so Inventory.RpcUse != Equipment.RpcUse
                payload        = writer.ToArraySegment()              // segment to avoid reader allocations
            };

            conn.Send(message, channelId);
            NetworkWriterPool.Recycle(writer);
        }
        void FixedUpdate()
        {
            if (!SendMessagesAllowed)
            {
                return;
            }

            CheckSendRate();

            for (int i = 0; i < Animator.layerCount; i++)
            {
                if (!CheckAnimStateChanged(out int stateHash, out float normalizedTime, i))
                {
                    continue;
                }

                using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
                {
                    WriteParameters(writer);
                    SendAnimationMessage(stateHash, normalizedTime, i, writer.ToArray());
                }
            }
        }
Beispiel #5
0
 internal static void Update()
 {
     // local or remote connection?
     if (isLocalClient)
     {
         // process internal messages so they are applied at the correct time
         while (localClientPacketQueue.Count > 0)
         {
             NetworkWriter writer = localClientPacketQueue.Dequeue();
             // TODO avoid serializing and deserializng the message
             // just pass it as is
             OnDataReceived(writer.ToArraySegment(), Channels.DefaultReliable);
             NetworkWriterPool.Recycle(writer);
         }
     }
     else
     {
         // only update things while connected
         if (active && connectState == ConnectState.Connected)
         {
             NetworkTime.UpdateClient();
         }
     }
 }
        void Update()
        {
            // if server then always sync to others.
            if (isServer)
            {
                // just use OnSerialize via SetDirtyBit only sync when position
                // changed. set dirty bits 0 or 1
                SetDirtyBit(HasEitherMovedRotatedScaled() ? 1UL : 0UL);
            }

            // no 'else if' since host mode would be both
            if (isClient)
            {
                // send to server if we have local authority (and aren't the server)
                // -> only if connectionToServer has been initialized yet too
                if (!isServer && isClientWithAuthority)
                {
                    // check only each 'syncInterval'
                    if (Time.time - lastClientSendTime >= syncInterval)
                    {
                        if (HasEitherMovedRotatedScaled())
                        {
                            // serialize
                            // local position/rotation for VR support
                            NetworkWriter writer = NetworkWriterPool.GetWriter();
                            SerializeIntoWriter(writer, targetComponent.transform.localPosition, targetComponent.transform.localRotation, compressRotation, targetComponent.transform.localScale);

                            // send to server
                            CmdClientToServerSync(writer.ToArray());
                            NetworkWriterPool.Recycle(writer);
                        }
                        lastClientSendTime = Time.time;
                    }
                }

                // apply interpolation on client for all players
                // unless this client has authority over the object. could be
                // himself or another object that he was assigned authority over
                if (!isClientWithAuthority)
                {
                    // received one yet? (initialized?)
                    if (goal != null)
                    {
                        // teleport or interpolate
                        if (NeedsTeleport())
                        {
                            // local position/rotation for VR support
                            ApplyPositionRotationScale(goal.localPosition, goal.localRotation, goal.localScale);

                            // reset data points so we don't keep interpolating
                            start = null;
                            goal  = null;
                        }
                        else
                        {
                            // local position/rotation for VR support
                            ApplyPositionRotationScale(InterpolatePosition(start, goal, targetComponent.transform.localPosition),
                                                       InterpolateRotation(start, goal, targetComponent.transform.localRotation),
                                                       InterpolateScale(start, goal, targetComponent.transform.localScale));
                        }
                    }
                }
            }
        }
Beispiel #7
0
        // get next message, unpacked from batch (if any)
        // timestamp is the REMOTE time when the batch was created remotely.
        public bool GetNextMessage(out NetworkReader message, out double remoteTimeStamp)
        {
            // getting messages would be easy via
            //   <<size, message, size, message, ...>>
            // but to save A LOT of bandwidth, we use
            //   <<message, message, ...>
            // in other words, we don't know where the current message ends
            //
            // BUT: it doesn't matter!
            // -> we simply return the reader
            //    * if we have one yet
            //    * and if there's more to read
            // -> the caller can then read one message from it
            // -> when the end is reached, we retire the batch!
            //
            // for example:
            //   while (GetNextMessage(out message))
            //       ProcessMessage(message);
            //
            message = null;

            // do nothing if we don't have any batches.
            // otherwise the below queue.Dequeue() would throw an
            // InvalidOperationException if operating on empty queue.
            if (batches.Count == 0)
            {
                remoteTimeStamp = 0;
                return(false);
            }

            // was our reader pointed to anything yet?
            if (reader.Length == 0)
            {
                remoteTimeStamp = 0;
                return(false);
            }

            // no more data to read?
            if (reader.Remaining == 0)
            {
                // retire the batch
                NetworkWriterPooled writer = batches.Dequeue();
                NetworkWriterPool.Return(writer);

                // do we have another batch?
                if (batches.Count > 0)
                {
                    // point reader to the next batch.
                    // we'll return the reader below.
                    NetworkWriterPooled next = batches.Peek();
                    StartReadingBatch(next);
                }
                // otherwise there's nothing more to read
                else
                {
                    remoteTimeStamp = 0;
                    return(false);
                }
            }

            // use the current batch's remote timestamp
            // AFTER potentially moving to the next batch ABOVE!
            remoteTimeStamp = readerRemoteTimeStamp;

            // if we got here, then we have more data to read.
            message = reader;
            return(true);
        }
 public void Dispose()
 {
     NetworkWriterPool.Recycle(this);
 }
Beispiel #9
0
        internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnection conn)
        {
            if (identity.serverOnly)
            {
                return;
            }

            if (LogFilter.Debug)
            {
                Debug.Log("Server SendSpawnMessage: name=" + identity.name + " sceneId=" + identity.sceneId.ToString("X") + " netid=" + identity.netId);                  // for easier debugging
            }
            // serialize all components with initialState = true
            // (can be null if has none)
            // convert to ArraySegment to avoid reader allocations
            // (need to handle null case too)
            ArraySegment <byte> segment = identity.OnSerializeAllSafely(true, out NetworkWriter serialized) ? serialized.ToArraySegment() : default;

            // 'identity' is a prefab that should be spawned
            if (identity.sceneId == 0)
            {
                SpawnPrefabMessage msg = new SpawnPrefabMessage
                {
                    netId   = identity.netId,
                    owner   = conn?.playerController == identity,
                    assetId = identity.assetId,
                    // use local values for VR support
                    position = identity.transform.localPosition,
                    rotation = identity.transform.localRotation,
                    scale    = identity.transform.localScale,
                    payload  = segment
                };

                // conn is != null when spawning it for a client
                if (conn != null)
                {
                    conn.Send(msg);
                }
                // conn is == null when spawning it for the local player
                else
                {
                    SendToReady(identity, msg);
                }
            }
            // 'identity' is a scene object that should be spawned again
            else
            {
                SpawnSceneObjectMessage msg = new SpawnSceneObjectMessage
                {
                    netId   = identity.netId,
                    owner   = conn?.playerController == identity,
                    sceneId = identity.sceneId,
                    // use local values for VR support
                    position = identity.transform.localPosition,
                    rotation = identity.transform.localRotation,
                    scale    = identity.transform.localScale,
                    payload  = segment
                };

                // conn is != null when spawning it for a client
                if (conn != null)
                {
                    conn.Send(msg);
                }
                // conn is == null when spawning it for the local player
                else
                {
                    SendToReady(identity, msg);
                }
            }

            if (serialized != null)
            {
                NetworkWriterPool.Recycle(serialized);
            }
        }
Beispiel #10
0
 public void Dispose() => NetworkWriterPool.Return(this);
Beispiel #11
0
        internal void SendSpawnMessage(NetworkIdentity identity, NetworkConnection conn)
        {
            if (identity.serverOnly)
            {
                return;
            }

            // for easier debugging
            if (LogFilter.Debug)
            {
                Debug.Log("Server SendSpawnMessage: name=" + identity.name + " sceneId=" + identity.sceneId.ToString("X") + " netid=" + identity.NetId);
            }

            // one writer for owner, one for observers
            using (PooledNetworkWriter ownerWriter = NetworkWriterPool.GetWriter(), observersWriter = NetworkWriterPool.GetWriter())
            {
                // serialize all components with initialState = true
                // (can be null if has none)
                (int ownerWritten, int observersWritten) = identity.OnSerializeAllSafely(true, ownerWriter, observersWriter);

                // convert to ArraySegment to avoid reader allocations
                // (need to handle null case too)
                ArraySegment <byte> ownerSegment     = ownerWritten > 0 ? ownerWriter.ToArraySegment() : default;
                ArraySegment <byte> observersSegment = observersWritten > 0 ? observersWriter.ToArraySegment() : default;

                var msg = new SpawnMessage
                {
                    netId         = identity.NetId,
                    isLocalPlayer = conn.Identity == identity,
                    isOwner       = identity.ConnectionToClient == conn,
                    sceneId       = identity.sceneId,
                    assetId       = identity.AssetId,
                    // use local values for VR support
                    position = identity.transform.localPosition,
                    rotation = identity.transform.localRotation,
                    scale    = identity.transform.localScale
                };

                // use owner segment if 'conn' owns this identity, otherwise
                // use observers segment
                msg.payload = msg.isOwner ? ownerSegment : observersSegment;

                conn.Send(msg);
            }
        }