示例#1
0
        public void SendRPC(NetAsset netAsset, string methodName, object[] args)
        {
            if (State == ServerState.Debug)
            {
                return;
            }
            if (State != ServerState.Started)
            {
                throw new InvalidOperationException($"Cannot send rpc {methodName}: Server not running");
            }

            var streamWriter = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);

            streamWriter.WriteInt(Commands.NetAssetRPC);
            streamWriter.WriteFloat(Time);
            streamWriter.WriteInt(netAsset.NetID);
            netAsset.SerializeRPC(ref streamWriter, methodName, args);

            for (var i = 0; i < _connections.Length; i++)
            {
                DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, _connections[i]);
                writer.WriteBytes(streamWriter.AsNativeArray());
                _serverDriver.EndSend(writer);
            }
        }
示例#2
0
        private static void SerializeNetAsset(NetAsset netAsset, ref DataStreamWriter streamWriter, bool fullLoad)
        {
            streamWriter.WriteInt(netAsset.NetID);
            DataStreamWriter sizeWriter = streamWriter;

            streamWriter.WriteInt(0);
            int length = streamWriter.Length;

            netAsset.Serialize(ref streamWriter, fullLoad);
            sizeWriter.WriteInt(streamWriter.Length - length);
        }
示例#3
0
        public void SendRPC(NetAsset netAsset, string methodName, object[] args)
        {
            if (State == ClientState.Debug)
            {
                return;
            }
            if (State != ClientState.Connected)
            {
                throw new InvalidOperationException($"Cannot send rpc {methodName}: not connected");
            }

            DataStreamWriter streamWriter = _clientDriver.BeginSend(_reliablePipeline, _clientToServerConnection);

            streamWriter.WriteInt(Commands.NetAssetRPC);
            streamWriter.WriteFloat(Server.Time);
            streamWriter.WriteInt(netAsset.NetID);
            netAsset.SerializeRPC(ref streamWriter, methodName, args);
            _clientDriver.EndSend(streamWriter);
            DataSent?.Invoke(streamWriter.Length);
        }
示例#4
0
        private void SendNetAssetUpdate(bool fullLoad, NativeList <NetworkConnection> connections)
        {
            if (State == ServerState.Debug)
            {
                return;
            }
            if (State != ServerState.Started)
            {
                throw new InvalidOperationException("Cannot send NetAsset update: Server not running");
            }
            Profiler.BeginSample("NetAsset Update");

            NetAsset[] netAssets         = NetAssetManager.Instance.GetAll();
            const int  headerSizeInBytes = 8;
            var        streamWriter      = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            var        assetWriter       = new DataStreamWriter(MaxBytesPerMessage - headerSizeInBytes, Allocator.Temp);
            var        assetIndex        = 0;

            // compose new message if assets left to send or serialize
            while (assetIndex < netAssets.Length || assetWriter.Length > 0)
            {
                streamWriter.Clear();

                // write header
                streamWriter.WriteInt(Commands.UpdateNetAssets);
                DataStreamWriter netAssetCountWriter = streamWriter;
                streamWriter.WriteInt(0);

                // add assets as long as they fit
                var assetsInMessage = 0;
                while (streamWriter.Length + assetWriter.Length <= MaxBytesPerMessage)
                {
                    if (assetWriter.Length > 0)
                    {
                        streamWriter.WriteBytes(assetWriter.AsNativeArray());
                        assetWriter.Clear();
                        assetsInMessage++;
                    }

                    // next asset. Serialize if dirty
                    if (assetIndex < netAssets.Length)
                    {
                        NetAsset netAsset = netAssets[assetIndex++];
                        if (fullLoad || netAsset.IsDirty())
                        {
                            SerializeNetAsset(netAsset, ref assetWriter, fullLoad);
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                netAssetCountWriter.WriteInt(assetsInMessage);

                // message complete. Send if payload exists
                if (assetsInMessage == 0)
                {
                    break;
                }
                for (var connectionIndex = 0; connectionIndex < connections.Length; connectionIndex++)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, connections[connectionIndex]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }

            Profiler.EndSample();
        }
示例#5
0
        private void ReadDataEvent(NetworkConnection connection, DataStreamReader streamReader)
        {
            try
            {
                int senderActorNumber = connection.InternalId;
                int command           = streamReader.ReadInt();
                switch (command)
                {
                case Commands.AcknowledgeActorNumber:
                {
                    if (_acceptAllPlayers)
                    {
                        AcceptPlayer(senderActorNumber);
                    }
                    break;
                }

                case Commands.PlayerData:
                {
                    string playerData = streamReader.ReadManagedString();
                    PlayerDataReceived?.Invoke(senderActorNumber, playerData);
                    break;
                }

                case Commands.Ping:
                    _lastPingTimes[connection] = Time;
                    float            sendLocalTime = streamReader.ReadFloat();
                    DataStreamWriter writer        = _serverDriver.BeginSend(_unreliablePipeline, connection);
                    writer.WriteInt(Commands.Ping);
                    writer.WriteFloat(sendLocalTime);
                    writer.WriteFloat(Time);
                    writer.WriteFloat(UnityEngine.Time.deltaTime);
                    _serverDriver.EndSend(writer);
                    break;

                case Commands.RequestSpawnMessage:
                {
                    var connections = new NativeList <NetworkConnection>(1, Allocator.Temp)
                    {
                        connection
                    };
                    SendSpawnMessage(NetObjectManager.Instance.NetObjects, connections);
                    connections.Dispose();
                    break;
                }

                case Commands.UpdateNetObjects:
                {
                    int objectsInMessage = streamReader.ReadInt();
                    for (var obj = 0; obj < objectsInMessage; obj++)
                    {
                        int       netObjID  = streamReader.ReadInt();
                        int       size      = streamReader.ReadInt();
                        NetObject netObject = NetObjectManager.Instance.Exists(netObjID)
                                ? NetObjectManager.Instance.Get(netObjID)
                                : null;

                        // ignore illegal updates and those from local host client
                        if (netObject == null ||
                            netObject.OwnerActorNumber != senderActorNumber ||     // cheater?
                            Client.IsHost && Client.Instance.ActorNumber == senderActorNumber)
                        {
                            streamReader.DiscardBytes(size);
                        }
                        else
                        {
                            int bytesRead = streamReader.GetBytesRead();
                            try
                            {
                                netObject.Deserialize(ref streamReader, b => b.ClientAuthoritative);
                            }
                            catch (Exception e)
                            {
                                Debug.LogException(e);
                                int remainingBytes = size + bytesRead - streamReader.GetBytesRead();
                                streamReader.DiscardBytes(remainingBytes);
                            }
                        }
                    }

                    break;
                }

                case Commands.GameAction:
                {
                    int   gameActionID = streamReader.ReadInt();
                    int   actorNumber  = streamReader.ReadInt();
                    float triggerTime  = streamReader.ReadFloat();
                    try
                    {
                        GameAction             gameAction = GameActionManager.Instance.Get(gameActionID);
                        GameAction.IParameters parameters =
                            gameAction.DeserializeParameters(ref streamReader);
                        gameAction.ReceiveOnServer(parameters, actorNumber, senderActorNumber,
                                                   triggerTime);
                        break;
                    }
                    catch (Exception e)
                    {
                        Debug.LogException(e);
                        break;
                    }
                }

                case Commands.NetAssetRPC:
                {
                    float        sentServerTime = streamReader.ReadFloat();
                    int          netAssetID     = streamReader.ReadInt();
                    NetAsset     netAsset       = NetAssetManager.Instance.Get(netAssetID);
                    NetAsset.RPC rpc            = netAsset.DeserializeRPC(ref streamReader);
                    var          messageInfo    = new MessageInfo
                    {
                        SentServerTime = sentServerTime, SenderActorNumber = senderActorNumber
                    };
                    rpc.Invoke(messageInfo);
                    break;
                }

                case Commands.NetObjectRPC:
                {
                    float sentServerTime = streamReader.ReadFloat();
                    int   netObjectID    = streamReader.ReadInt();
                    if (!NetObjectManager.Instance.Exists(netObjectID))
                    {
                        Debug.LogWarning("Ignoring received RPC, because NetObject was not found.");
                        break;
                    }

                    NetObject            netObject      = NetObjectManager.Instance.Get(netObjectID);
                    ushort               netBehaviourID = streamReader.ReadUShort();
                    NetBehaviour         netBehaviour   = netObject.Get(netBehaviourID);
                    NetObjectManager.RPC rpc            =
                        NetObjectManager.Instance.DeserializeRPC(ref streamReader, netBehaviour);
                    var messageInfo = new MessageInfo
                    {
                        SentServerTime = sentServerTime, SenderActorNumber = senderActorNumber
                    };
                    rpc.Invoke(messageInfo);
                    break;
                }

                default:
                    Debug.LogException(new NetException($"Unknown command {command}"));
                    break;
                }
            }
            catch (Exception e)
            {
                Debug.LogException(new NetException("Failed to handle data event", e));
            }
        }
示例#6
0
        public void Tick()
        {
            if (!_clientDriver.IsCreated)
            {
                return;
            }
            _clientDriver.ScheduleUpdate().Complete();

            if (_timeout > 0 && IsConnected && Time.time - LastPongTime > _timeout)
            {
                Debug.LogWarning("Disconnected due to timeout");
                Disconnect();
                return;
            }

            // listen for events
            NetworkEvent.Type eventType;
            while ((eventType = _clientToServerConnection.PopEvent(_clientDriver, out DataStreamReader streamReader))
                   != NetworkEvent.Type.Empty)
            {
                if (eventType == NetworkEvent.Type.Connect)
                {
                    Debug.Log("Connected!");
                    State = ClientState.Connected;
                    Connected?.Invoke();
                }
                else if (eventType == NetworkEvent.Type.Data)
                {
                    DataReceived?.Invoke(streamReader.Length);
                    int command = streamReader.ReadInt();
                    switch (command)
                    {
                    case Commands.AssignActorNumber:
                    {
                        ActorNumber = streamReader.ReadInt();
                        Debug.Log($"Got assigned actor number {ActorNumber}");
                        DataStreamWriter writer =
                            _clientDriver.BeginSend(_reliablePipeline, _clientToServerConnection);
                        writer.WriteInt(Commands.AcknowledgeActorNumber);
                        _clientDriver.EndSend(writer);
                        DataSent?.Invoke(writer.Length);
                        break;
                    }

                    case Commands.AcceptPlayer:
                    {
                        DataStreamWriter writer =
                            _clientDriver.BeginSend(_reliablePipeline, _clientToServerConnection);
                        writer.WriteInt(Commands.RequestSpawnMessage);
                        writer.WriteInt(SceneManager.sceneCount);
                        for (var i = 0; i < SceneManager.sceneCount; i++)
                        {
                            writer.WriteInt(SceneManager.GetSceneAt(i).buildIndex);
                        }
                        SceneManager.sceneLoaded += OnSceneLoaded;
                        _clientDriver.EndSend(writer);
                        break;
                    }

                    case Commands.Ping:
                    {
                        LastPongTime = Time.time;
                        float sendLocalTime   = streamReader.ReadFloat();
                        float serverTime      = streamReader.ReadFloat();
                        float serverDeltaTime = streamReader.ReadFloat();
                        RoundTripTime = Time.time - sendLocalTime;
                        Latency       = IsHost
                                ? 0
                                : Mathf.Max(0, (RoundTripTime - serverDeltaTime / 2 - Time.deltaTime / 2) / 2);
                        // estimated server time NOW is received serverTime + latency for one trip + average frame wait on client side
                        float serverTimeOffset = serverTime - Time.time + Latency + Time.deltaTime / 2;
                        _averageServerTimeOffset = Mathf.Abs(_averageServerTimeOffset - serverTime) > 0.5f
                                ? serverTimeOffset
                                : 0.9f * _averageServerTimeOffset + 0.1f * serverTimeOffset;
                        PingReceived?.Invoke(RoundTripTime, Latency);
                        break;
                    }

                    case Commands.SpawnNetObjects:
                    {
                        if (IsHost)
                        {
                            break;
                        }
                        int count = streamReader.ReadInt();

                        for (var i = 0; i < count; i++)
                        {
                            int        netObjID         = streamReader.ReadInt();
                            ushort     prefabIndex      = streamReader.ReadUShort();
                            int        ownerActorNumber = streamReader.ReadInt();
                            Vector3    position         = streamReader.ReadVector3();
                            Quaternion rotation         = streamReader.ReadQuaternion();
                            int        sceneBuildIndex  = streamReader.ReadInt();
                            int        size             = streamReader.ReadInt();
                            int        bytesRead        = streamReader.GetBytesRead();
                            Scene      scene            = SceneManager.GetSceneByBuildIndex(sceneBuildIndex);
                            var        deserialized     = false;
                            if (scene != null && scene.isLoaded)
                            {
                                NetObject netObject = NetObjectManager.Instance.SpawnOnClient(netObjID, prefabIndex,
                                                                                              ownerActorNumber, position, rotation, scene);
                                if (netObject != null)
                                {
                                    netObject.Deserialize(ref streamReader, behaviour => true);
                                    deserialized = true;
                                }
                            }

                            if (!deserialized)
                            {
                                streamReader.DiscardBytes(size);
                            }
                            if (streamReader.GetBytesRead() - bytesRead != size)
                            {
                                Debug.LogWarning("Did not deserialize properly!");
                            }
                        }

                        break;
                    }

                    case Commands.UpdateNetAssets:
                    {
                        if (IsHost)
                        {
                            break;
                        }
                        int assetsInMessage = streamReader.ReadInt();
                        for (var i = 0; i < assetsInMessage; i++)
                        {
                            int assetNetID = streamReader.ReadInt();
                            int size       = streamReader.ReadInt();
                            int bytesRead  = streamReader.GetBytesRead();
                            try
                            {
                                NetAsset netAsset = NetAssetManager.Instance.Get(assetNetID);
                                netAsset.Deserialize(ref streamReader);
                            }
                            catch (Exception e)
                            {
                                Debug.LogException(new NetException($"Failed to update net asset {assetNetID}", e));
                                streamReader.DiscardBytes(size + bytesRead - streamReader.GetBytesRead());
                            }
                        }

                        break;
                    }

                    case Commands.UpdateNetObjects:
                    {
                        if (IsHost)
                        {
                            break;
                        }
                        int objectsInMessage = streamReader.ReadInt();
                        for (var i = 0; i < objectsInMessage; i++)
                        {
                            int netObjID = streamReader.ReadInt();
                            int size     = streamReader.ReadInt();
                            if (NetObjectManager.Instance.Exists(netObjID))
                            {
                                NetObject netObject = NetObjectManager.Instance.Get(netObjID);
                                int       bytesRead = streamReader.GetBytesRead();
                                try
                                {
                                    netObject.Deserialize(ref streamReader, behaviour => !behaviour.HasAuthority);
                                }
                                catch (Exception e)
                                {
                                    Debug.LogException(
                                        new NetException($"Failed to update net object {netObjID}", e));
                                    streamReader.DiscardBytes(size + bytesRead - streamReader.GetBytesRead());
                                }
                            }
                            else
                            {
                                streamReader.DiscardBytes(size);
                            }
                        }

                        break;
                    }

                    case Commands.UnspawnNetObjects:
                    {
                        if (IsHost)
                        {
                            break;
                        }
                        int count = streamReader.ReadInt();
                        for (var i = 0; i < count; i++)
                        {
                            int netObjID = streamReader.ReadInt();
                            NetObjectManager.Instance.Unspawn(netObjID);
                        }

                        break;
                    }

                    case Commands.GameAction:
                    {
                        if (IsHost)
                        {
                            break;
                        }
                        int   gameActionID = streamReader.ReadInt();
                        int   actorNumber  = streamReader.ReadInt();
                        float triggerTime  = streamReader.ReadFloat();
                        bool  valid        = streamReader.ReadBool();
                        try
                        {
                            GameAction             gameAction = GameActionManager.Instance.Get(gameActionID);
                            GameAction.IParameters parameters = gameAction.DeserializeParameters(ref streamReader);
                            gameAction.ReceiveOnClient(parameters, valid, actorNumber, triggerTime);
                            break;
                        }
                        catch (Exception e)
                        {
                            Debug.LogException(e);
                            break;
                        }
                    }

                    case Commands.NetAssetRPC:
                    {
                        if (IsHost)
                        {
                            break;
                        }
                        float        sentServerTime = streamReader.ReadFloat();
                        int          netAssetID     = streamReader.ReadInt();
                        NetAsset     netAsset       = NetAssetManager.Instance.Get(netAssetID);
                        NetAsset.RPC rpc            = netAsset.DeserializeRPC(ref streamReader);
                        var          messageInfo    = new MessageInfo
                        {
                            SentServerTime = sentServerTime, SenderActorNumber = Server.ServerActorNumber
                        };
                        rpc.Invoke(messageInfo);
                        break;
                    }

                    case Commands.NetObjectRPC:
                    {
                        if (IsHost)
                        {
                            break;
                        }
                        float sentServerTime = streamReader.ReadFloat();
                        int   netObjectID    = streamReader.ReadInt();
                        if (!NetObjectManager.Instance.Exists(netObjectID))
                        {
                            Debug.LogWarning("Ignoring received RPC, because NetObject was not found.");
                            break;
                        }

                        NetObject            netObject      = NetObjectManager.Instance.Get(netObjectID);
                        ushort               netBehaviourID = streamReader.ReadUShort();
                        NetBehaviour         netBehaviour   = netObject.Get(netBehaviourID);
                        NetObjectManager.RPC rpc            =
                            NetObjectManager.Instance.DeserializeRPC(ref streamReader, netBehaviour);
                        var messageInfo = new MessageInfo
                        {
                            SentServerTime = sentServerTime, SenderActorNumber = Server.ServerActorNumber
                        };
                        rpc.Invoke(messageInfo);
                        break;
                    }

                    default:
                        Debug.LogError($"Unknown event type {eventType}");
                        break;
                    }
                }
                else if (eventType == NetworkEvent.Type.Disconnect)
                {
                    Debug.Log("Disconnected!");
                    SceneManager.sceneLoaded -= OnSceneLoaded;
                    Disconnected?.Invoke();
                    State = ClientState.Disconnected;
                    _clientToServerConnection = default;
                }
            }
        }