Esempio n. 1
0
        /// <summary>
        /// Relays the changes to attributes to other connected sync nodes and process them locally.
        /// </summary>
        /// <param name="guid">Guid of the entity containing affected attributes.</param>
        /// <param name="changedAttributes">A set of modified attributes with their remote sync info.</param>
        private void HandleRemoteChangedAttributes(Connection connection, Guid guid, EntitySyncInfo changedAttributes)
        {
            if (IsSyncRelay)
            {
                RelaySyncMessage(connection, "changeAttributes", guid, changedAttributes);
            }

            ProcessChangedAttributes(guid, changedAttributes);
        }
Esempio n. 2
0
        /// <summary>
        /// Creates a new sync for an entity.
        /// </summary>
        /// <param name="entity">Entity for which sync info is to be created.</param>
        /// <returns>Created sync info.</returns>
        private EntitySyncInfo CreateSyncInfoForNewEntity(Entity entity)
        {
            var entitySyncInfo = new EntitySyncInfo();

            foreach (Component component in entity.Components)
            {
                foreach (ReadOnlyAttributeDefinition attrDefinition in component.Definition.AttributeDefinitions)
                {
                    entitySyncInfo[component.Name][attrDefinition.Name] =
                        new AttributeSyncInfo(LocalSyncID, component[attrDefinition.Name]);
                }
            }
            return(entitySyncInfo);
        }
Esempio n. 3
0
        /// <summary>
        /// Handler for the event ChangedAttribute event in the Entity. Update local sync info for the attribute and
        /// invokes changedAttributes method on the connected sync nodes to notify them about the change.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void HandleLocalChangedAttribute(object sender, ChangedAttributeEventArgs e)
        {
            var componentName = e.Component.Name;
            var attributeName = e.AttributeName;

            // Ignore this change if it was caused by the scalability plugin itself.
            lock (remoteAttributeChanges)
            {
                foreach (RemoteAttributeChange change in remoteAttributeChanges)
                {
                    if (change.Entity == e.Entity && change.ComponentName == componentName &&
                        change.AttributeName == attributeName && change.Value == e.NewValue)
                    {
                        remoteAttributeChanges.Remove(change);
                        return;
                    }
                }
            }

            var newAttributeSyncInfo = new AttributeSyncInfo(LocalSyncID, e.NewValue);

            lock (localSyncInfo)
            {
                if (!localSyncInfo.ContainsKey(e.Entity.Guid))
                {
                    logger.Warn("Local attribute changed in an entity which has no sync info.");
                    return;
                }

                EntitySyncInfo entitySyncInfo = localSyncInfo[e.Entity.Guid];
                entitySyncInfo[componentName][attributeName] = newAttributeSyncInfo;
            }

            // TODO: Optimization: we can send batch updates to improve performance. Received code is written to
            // process batches already, but sending is trickier as we don't have network load feedback from KIARA yet.
            var changedAttributes = new EntitySyncInfo();

            changedAttributes[componentName][attributeName] = newAttributeSyncInfo;

            lock (remoteSyncNodes)
            {
                foreach (Connection connection in remoteSyncNodes)
                {
                    connection["changeAttributes"](e.Entity.Guid, changedAttributes);
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Processes changes to a set of attributes on the remote sync node and updates local values accordingly.
        /// </summary>
        /// <param name="guid">Guid of the entity containing affected attributes.</param>
        /// <param name="changedAttributes">A set of modified attributes with their remote sync info.</param>
        private void ProcessChangedAttributes(Guid guid, EntitySyncInfo changedAttributes)
        {
            lock (localSyncInfo)
            {
                if (!localSyncInfo.ContainsKey(guid))
                {
                    logger.Warn("Ignoring changes to attributes in an entity that does not exist. Guid: " + guid);
                    return;
                }

                Entity localEntity = World.Instance.FindEntity(guid);
                foreach (KeyValuePair <string, ComponentSyncInfo> componentPair in changedAttributes.Components)
                {
                    foreach (KeyValuePair <string, AttributeSyncInfo> attributePair in componentPair.Value.Attributes)
                    {
                        HandleRemoteChangedAttribute(localEntity, componentPair.Key, attributePair.Key,
                                                     attributePair.Value);
                    }
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Handles an entity addition update from the remote sync node and adds a new entity locally.
        /// </summary>
        /// <param name="guid">Guid of the new entity.</param>
        /// <param name="initialSyncInfo">Initial sync info for the entity.</param>
        private void HandleRemoteAddedEntity(Connection connection, Guid guid, EntitySyncInfo initialSyncInfo)
        {
            lock (localSyncInfo)
            {
                if (IsSyncRelay)
                {
                    RelaySyncMessage(connection, "addEntity", guid, initialSyncInfo);
                }

                if (!localSyncInfo.ContainsKey(guid))
                {
                    localSyncInfo.Add(guid, new EntitySyncInfo());
                    lock (remoteEntityAdditions)
                        remoteEntityAdditions.Add(guid);
                    World.Instance.Add(new Entity(guid));
                }
                else
                {
                    logger.Warn("Processing addition of already existing entity. Guid: " + guid);
                }

                ProcessChangedAttributes(guid, initialSyncInfo);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Handles an update to a single attribute.
        /// </summary>
        /// <param name="localEntity">Entity containing attribute.</param>
        /// <param name="componentName">Name of the component containing attribute.</param>
        /// <param name="attributeName">Name of the attribute.</param>
        /// <param name="remoteAttributeSyncInfo">Remote sync info on this attribute.</param>
        /// <returns>True if the update should be propagated to other sync nodes.</returns>
        private bool HandleRemoteChangedAttribute(Entity localEntity, string componentName, string attributeName,
                                                  AttributeSyncInfo remoteAttributeSyncInfo)
        {
            EntitySyncInfo localEntitySyncInfo = localSyncInfo[localEntity.Guid];

            bool shouldUpdateLocalAttribute = false;

            if (!localEntitySyncInfo.Components.ContainsKey(componentName) ||
                !localEntitySyncInfo[componentName].Attributes.ContainsKey(attributeName))
            {
                shouldUpdateLocalAttribute = true;
                localEntitySyncInfo[componentName][attributeName] = remoteAttributeSyncInfo;
            }
            else
            {
                AttributeSyncInfo localAttributeSyncInfo = localEntitySyncInfo[componentName][attributeName];
                shouldUpdateLocalAttribute =
                    (localAttributeSyncInfo.LastValue == null && remoteAttributeSyncInfo.LastValue != null) ||
                    (localAttributeSyncInfo.LastValue != null &&
                     !localAttributeSyncInfo.LastValue.Equals(remoteAttributeSyncInfo.LastValue));
                if (!localAttributeSyncInfo.Sync(remoteAttributeSyncInfo))
                {
                    return(false);  // ignore this update because sync discarded it
                }
            }

            if (shouldUpdateLocalAttribute)
            {
                try
                {
                    // This is necessary, because Json.NET serializes primitive types using basic JSON values, which do
                    // not retain original type (e.g. integer values always become int even if they were stored as
                    // float values before) and there is no way to change this.
                    var attributeType  = localEntity[componentName].Definition[attributeName].Type;
                    var attributeValue = Convert.ChangeType(remoteAttributeSyncInfo.LastValue, attributeType);

                    // Ignore event for this change.
                    lock (remoteAttributeChanges)
                    {
                        var remoteChange = new RemoteAttributeChange
                        {
                            Entity        = localEntity,
                            ComponentName = componentName,
                            AttributeName = attributeName,
                            Value         = attributeValue
                        };

                        remoteAttributeChanges.Add(remoteChange);
                    }

                    localEntity[componentName][attributeName] = attributeValue;
                    return(true);
                }
                catch (ComponentAccessException)
                {
                    // This is fine, because we may have some plugins not loaded on this node.
                }
            }

            // If we are here, it means that this update was not discarded by sync and thus should be propagated to
            // other nodes. This is still the case even if the value has been the same and local attribute has not been
            // update, because we still need to update sync info on other nodes.
            return(true);
        }