コード例 #1
0
        private void PrepareAndTransmitSynchronisation(ComponentizedEntity entity, int tick, bool isFromClient, ClientAuthoritiveMode clientAuthoritiveMode)
        {
            if (!_uniqueIdentifierForEntity.HasValue)
            {
                throw new InvalidOperationException("PrepareAndTransmit should not be called without an entity ID!");
            }

            // If the entity is a synchronised entity, collect properties of the synchronised object
            // directly.
            var synchronisedEntity = entity as ISynchronisedObject;

            if (synchronisedEntity != null)
            {
                _synchronisationContext = synchronisedEntity;
                _synchronisationContext.DeclareSynchronisedProperties(this);
            }

            // Iterate through all the components on the entity and get their synchronisation data as well.
            foreach (var synchronisedComponent in entity.Components.OfType <ISynchronisedObject>())
            {
                _synchronisationContext = synchronisedComponent;
                _synchronisationContext.DeclareSynchronisedProperties(this);
            }

            // Sync properties to each client.
            foreach (var dispatcher in _networkEngine.CurrentDispatchers)
            {
                foreach (var group in dispatcher.ValidClientGroups)
                {
                    if (ClientAuthoritiveMode != ClientAuthoritiveMode.None &&
                        ClientOwnership != null &&
                        OnlySendToAuthoritiveClient)
                    {
                        if (ClientOwnership != group)
                        {
                            // This client doesn't own the entity, and this entity is only
                            // synchronised with clients that own it.
                            continue;
                        }
                    }

                    if (isFromClient || _clientsEntityIsKnownOn.Contains(group))
                    {
                        if (_synchronisedData.Count > 0)
                        {
                            // Now calculate the delta to transmit over the network.
                            var currentTick = tick; // TODO: Use TimeTick
                            _synchronisedDataToTransmit.Clear();
                            foreach (var data in _synchronisedData.Values)
                            {
                                var needsSync = false;

                                // Check the target for this data to see whether or not we send it to
                                // this particular client.
                                if (data.SynchronisationTargets == SynchroniseTargets.OwningClient &&
                                    (ClientOwnership == null ||
                                     !(ClientOwnership == group)))
                                {
                                    // This data should only be synchronised to the owning client, and
                                    // we are not the owning client.
                                    continue;
                                }
                                else if (data.SynchronisationTargets == SynchroniseTargets.NonOwningClients &&
                                         (ClientOwnership == null ||
                                          ClientOwnership == group))
                                {
                                    // This data should only be synchronised to non-owning clients, and
                                    // we either are the owning client, or no client ownership has been set.
                                    continue;
                                }

                                // If we're on the client and we haven't had an initial piece of data from the server,
                                // we never synchronise because we don't know what the initial value is.
                                if (isFromClient && !data.HasReceivedInitialSync.GetOrDefault(group, false))
                                {
                                    continue;
                                }

                                // If we haven't performed the initial synchronisation, we always transmit the data.
                                if (!data.HasPerformedInitialSync.GetOrDefault(group, false))
                                {
                                    _networkEngine.LogSynchronisationEvent(
                                        "Must send property '" + data.Name + "' on entity ID " + _uniqueIdentifierForEntity +
                                        " because the endpoint " + group + " has not received it's initial sync.");
                                    needsSync = true;
                                }

                                // If we are on the client (i.e. the client assumes it's authoritive), or if the
                                // server knows that the client does not have authority, then allow this next section.
                                // Or to put it another way, if we're not on the client and we know the client has
                                // authority, only transmit data for the first time because the client will make
                                // decisions from that point onwards.
                                if (isFromClient || clientAuthoritiveMode != ClientAuthoritiveMode.TrustClient ||
                                    (clientAuthoritiveMode == ClientAuthoritiveMode.TrustClient &&
                                     group != ClientOwnership))
                                {
                                    var lastValue    = data.LastValue;
                                    var currentValue = data.CurrentValue;

                                    if (lastValue is ITransform)
                                    {
                                        throw new InvalidOperationException(
                                                  "Last value property got stored as ITransform, but should have been stored as NetworkTransform!");
                                    }

                                    if (currentValue is ITransform)
                                    {
                                        currentValue = ((ITransform)currentValue).SerializeToNetwork();
                                    }

                                    if (!Equals(lastValue, currentValue))
                                    {
                                        if (data.LastFrameSynced.GetOrDefault(group, 0) + data.FrameInterval < currentTick)
                                        {
                                            _networkEngine.LogSynchronisationEvent(
                                                "Sending property '" + data.Name + "' on entity ID " + _uniqueIdentifierForEntity +
                                                " because the value has changed (old value: " + lastValue + ", new value: " + currentValue + ")," +
                                                " and the next frame synced target for group " + group + "" +
                                                " is " + (data.LastFrameSynced.GetOrDefault(group, 0) + data.FrameInterval) + "" +
                                                " and the current tick is " + currentTick + ".");
                                            needsSync = true;
                                        }
                                    }
                                }

                                if (needsSync)
                                {
                                    _synchronisedDataToTransmit.Add(data);
                                }
                            }

                            if (_synchronisedDataToTransmit.Count > 0)
                            {
                                // Build up the synchronisation message.
                                var message = new EntityPropertiesMessage();
                                message.EntityID        = _uniqueIdentifierForEntity.Value;
                                message.FrameTick       = currentTick;
                                message.PropertyNames   = new string[_synchronisedDataToTransmit.Count];
                                message.PropertyTypes   = new int[_synchronisedDataToTransmit.Count];
                                message.IsClientMessage = isFromClient;
                                message.MessageOrder    = _messageOrder++;

                                bool reliable;
                                AssignSyncDataToMessage(_synchronisedDataToTransmit, message, currentTick, group, out reliable);

                                // Send an entity properties message to the client.
                                _networkEngine.Send(
                                    dispatcher,
                                    group,
                                    message,
                                    reliable);
                            }
                        }
                    }
                }
            }
        }