/// <summary>
        /// Bind this proxy entity to an existing remote entity.
        /// <para>
        /// This function assumes the user will fully bind proxy entities for the remote entity parent,
        /// if a parent exists.
        ///
        /// Trying to bind an already bound remote entity will throw an exception.
        /// </para>
        /// </summary>
        /// <param name="remoteEntity">The entity to bind.</param>
        /// <param name="syncRemoteToLocal">
        /// Whether or not to the sync the proxy entity to the remote entity properties.
        /// </param>
        public void Bind(ARREntity remoteEntity, bool syncRemoteToLocal)
        {
            if (this.IsRemoteEntityValid &&
                !this.RemoteEntity.Equals(remoteEntity))
            {
                throw new InvalidOperationException($"Trying to bind an already bound {nameof(ARREntitySync)}");
            }
            else if (!this.IsAttached)
            {
                throw new InvalidOperationException($"{nameof(ARREntitySync)} is not attached.");
            }
            else
            {
                if (!this.IsRemoteEntityValid)
                {
                    BindToLocalEntity(remoteEntity, this.Owner);
                    this.RemoteEntity = remoteEntity;
                }

                if (syncRemoteToLocal)
                {
                    this.SyncToLocal();
                }
            }
        }
    /// <summary>
    /// Find all matching entities by a regex pattern. This entity's and all children's names will be tested against
    /// the given regest pattern.
    /// </summary>
    public static Remote.Entity[] FindAllByPattern(this Remote.Entity entity, string pattern)
    {
        List <Remote.Entity> entities = new List <Entity>();

        Regex regex = null;

        try
        {
            regex = new Regex(pattern);
        }
        catch (Exception)
        {
            Debug.LogFormat(LogType.Warning, LogOption.NoStacktrace, null, "{0}", $"Invalid regex pattern '{pattern}' given to FindAllByPattern.");
        }

        if (regex != null)
        {
            entity.VisitEntity((Remote.Entity child) =>
            {
                if (regex.IsMatch(child.Name))
                {
                    entities.Add(child);
                }

                return(Entity.VisitorResult.ContinueVisit);
            });
        }

        return(entities.ToArray());
    }
 /// <summary>
 /// Tries to find an existing <see cref="ARREntitySync"/> proxy component associated
 /// with remote <see cref="ARREntity"/>.
 /// </summary>
 /// <param name="remoteEntity">The remote <see cref="ARREntity"/>.</param>
 /// <param name="syncComponent">The associated <see cref="ARREntitySync"/> proxy component.</param>
 /// <returns>
 /// <c>true</c> if an associated <see cref="ARREntitySync"/> proxy component is found;
 /// otherwise, <c>false</c>.
 /// </returns>
 public static bool TryGetSyncComponent(ARREntity remoteEntity, out ARREntitySync syncComponent)
 {
     if (proxiesByRemoteId.TryGetValue(remoteEntity.InteropId, out var weak) &&
         weak.TryGetTarget(out var localEntity) &&
         localEntity != null)
     {
         // Proxy local entity is alive and well.
         syncComponent = localEntity.FindComponent <ARREntitySync>();
     }
Пример #4
0
        /// <summary>
        /// Get an existing proxy <see cref="EvergineEntity"/> for an remote <see cref="ARREntity"/>.
        /// If no proxy entity has been mapped to this remote entity then null.
        /// </summary>
        /// <param name="remoteEntity">The remote <see cref="ARREntity"/>.</param>
        /// <returns>An proxy <see cref="EvergineEntity"/> if exists; otherwise, <c>null</c>.</returns>
        public static EvergineEntity GetExistingProxyEntity(this ARREntity remoteEntity)
        {
            if (ARREntitySync.TryGetSyncComponent(remoteEntity, out var syncComponent))
            {
                return(syncComponent.Owner);
            }

            return(null);
        }
    /// <summary>
    /// Create an Azure Remote Rendering component of a given type on the given entity.
    /// </summary>
    public static T CreateComponentOfType <T>(this Remote.Entity entity) where T : ComponentBase
    {
        if (entity == null || !RemoteManagerUnity.IsInitialized)
        {
            return(default(T));
        }

        T result = RemoteManagerUnity.CurrentSession?.Actions.CreateComponent(GetObjectType <T>(), entity) as T ?? null;

        return(result);
    }
Пример #6
0
    /// <summary>
    /// Get the collider enable override. True if entity's colliders are enabled, false otherwise.
    /// </summary>
    public static bool GetColliderEnabledOverride(this Remote.Entity entity)
    {
        if (entity == null || !entity.Valid)
        {
            return(false);
        }

        var component = entity.EnsureComponentOfType <HierarchicalStateOverrideComponent>();

        return(component.DisableCollisionState == HierarchicalEnableState.InheritFromParent);
    }
    /// <summary>
    /// Get the visibility override
    /// </summary>
    public static bool GetVisibilityOverride(this Remote.Entity entity)
    {
        if (entity == null || !entity.Valid)
        {
            return(false);
        }

        var  component = entity.EnsureComponentOfType <HierarchicalStateOverrideComponent>();
        bool hidden    = (component.Flags & HierarchicalStates.Hidden) == HierarchicalStates.Hidden;

        return(!hidden);
    }
Пример #8
0
    /// <summary>
    /// Set the visibility override
    /// </summary>
    public static void SetVisibilityOverride(this Remote.Entity entity, bool value)
    {
        if (entity == null || !entity.Valid)
        {
            return;
        }

        var component = entity.EnsureComponentOfType <HierarchicalStateOverrideComponent>();

        component.HiddenState           = value ? HierarchicalEnableState.InheritFromParent : HierarchicalEnableState.ForceOn;
        component.DisableCollisionState = value ? HierarchicalEnableState.InheritFromParent : HierarchicalEnableState.ForceOn;
    }
    /// <summary>
    /// Get the collider enablement override. True if entity's colliders are enabled, false otherwise.
    /// </summary>
    public static bool GetColliderEnabledOverride(this Remote.Entity entity)
    {
        if (entity == null || !entity.Valid)
        {
            return(false);
        }

        var  component = entity.EnsureComponentOfType <HierarchicalStateOverrideComponent>();
        bool disabled  = (component.Flags & HierarchicalStates.DisableCollision) == HierarchicalStates.DisableCollision;

        return(!disabled);
    }
    /// <summary>
    /// Replace all mesh materials with the given material.
    /// </summary>
    public static void ReplaceMaterials(this Remote.Entity entity, Remote.Material material)
    {
        IEnumerable <Remote.MeshComponent> meshComponents =
            entity?.FindComponentsOfType <MeshComponent>();

        foreach (var mesh in meshComponents)
        {
            int materialCount = mesh.UsedMaterials.Count;
            for (int i = 0; i < materialCount; i++)
            {
                mesh.SetMaterial(i, material);
            }
        }
    }
    /// <summary>
    /// Create an Azure Remote Rendering component of a given type on the given entity, if one doesn't already exist.
    /// </summary>
    public static T EnsureComponentOfType <T>(this Remote.Entity entity) where T : ComponentBase
    {
        if (entity == null)
        {
            return(default(T));
        }

        T component = entity.FindComponentOfType <T>();

        if (component == null)
        {
            component = entity.CreateComponentOfType <T>();
        }

        return(component);
    }
Пример #12
0
        /// <summary>
        /// Removes the proxy entity bound to this remote entity without destroying the remote entity.
        /// </summary>
        /// <param name="entityManager">The entity manager where the proxy entity is included.</param>
        /// <param name="remoteEntity">The remote entity.</param>
        /// <param name="removeFlags">Flags to indicate how to proceed with parent entities of the proxy entity.</param>
        public static void RemoveProxyEntity(this EntityManager entityManager, ARREntity remoteEntity, ARRRemoveProxyEntityFlags removeFlags)
        {
            var proxyEntity = remoteEntity.GetExistingProxyEntity();

            if (proxyEntity == null)
            {
                return;
            }

            ARREntitySync  sync;
            EvergineEntity previous = null;

            if (removeFlags.HasFlag(ARRRemoveProxyEntityFlags.DestroyEmptyParents))
            {
                sync = proxyEntity.FindComponent <ARREntitySync>();
                while (proxyEntity.Parent?.NumChildren == 1)
                {
                    previous    = proxyEntity;
                    proxyEntity = proxyEntity.Parent;

                    // Unbind on our way up the hierarchy for performance, keep the last sync bound in case keepRemoteRoot is true.
                    var syncNext = proxyEntity.FindComponent <ARREntitySync>();
                    if (syncNext == null)
                    {
                        break;
                    }

                    // Unbind first entity recursively since it doesn't need to be leaf
                    sync.Unbind(sync.RemoteEntity == remoteEntity);
                    sync = syncNext;
                }
            }

            if (removeFlags.HasFlag(ARRRemoveProxyEntityFlags.KeepRemoteRoot))
            {
                proxyEntity = previous;
            }
            else
            {
                proxyEntity?.FindComponent <ARREntitySync>().Unbind(true);
            }

            if (proxyEntity != null)
            {
                entityManager.Remove(proxyEntity);
            }
        }
    /// <summary>
    /// This is the implementation of FindFirstParentEntity. Call FindFirstParentEntity(Remote.Entity)
    /// to correctly start the recursion.
    /// </summary>
    private static Entity.VisitorResult VisitParentEntityImpl(this Remote.Entity entity, Entity.VisitEntityDelegate visitor)
    {
        if (entity == null || visitor(entity) == Entity.VisitorResult.ExitVisit)
        {
            return(Entity.VisitorResult.ExitVisit);
        }

        if (entity.Parent != null)
        {
            if (entity.Parent.VisitParentEntityImpl(visitor) == Entity.VisitorResult.ExitVisit)
            {
                return(Entity.VisitorResult.ExitVisit);
            }
        }

        return(Entity.VisitorResult.ContinueVisit);
    }
    /// <summary>
    /// This is a "no exception" version of QueryLocalBoundsAsync(). This will catch exceptions and return a default result.
    /// </summary>
    public static async Task <Bounds> SafeQueryLocalBoundsAsync(this Remote.Entity entity)
    {
        Bounds result = new Bounds(Vector3.positiveInfinity, Vector3.negativeInfinity);

        try
        {
            var arrBounds = await entity.QueryLocalBoundsAsync().AsTask();

            result = arrBounds.toUnity();
        }
        catch (Exception ex)
        {
            UnityEngine.Debug.LogFormat(LogType.Warning, LogOption.NoStacktrace, null, "{0}", $"Failed to get bounds of remote object. Reason: {ex.Message}");
        }

        return(result);
    }
    /// <summary>
    /// Find first entity in this entity's parents (inclusive of itself) that fulfills pred.
    /// </summary>
    public static Entity FindFirstParentEntity(this Remote.Entity entity, Entity.EntitySearchDelegate pred)
    {
        if (pred(entity))
        {
            return(entity);
        }

        if (entity.Parent != null)
        {
            Entity res = entity.Parent.FindFirstParentEntity(pred);
            if (res != null)
            {
                return(res);
            }
        }

        return(null);
    }
Пример #16
0
    /// <summary>
    /// Set the collider enable override
    /// </summary>
    public static void SetColliderEnabledOverride(this Remote.Entity entity, bool enable)
    {
        if (entity == null || !entity.Valid)
        {
            return;
        }

        var component = entity.EnsureComponentOfType <HierarchicalStateOverrideComponent>();

        if (enable)
        {
            component.DisableCollisionState = HierarchicalEnableState.InheritFromParent;
        }
        else
        {
            component.DisableCollisionState = HierarchicalEnableState.ForceOn;
        }
    }
        /// <summary>
        /// Synchronize local proxy <see cref="EvergineEntity"/> transform and name
        /// with the remote <see cref="ARREntity"/>.
        /// </summary>
        public void SyncToRemote()
        {
            if (this.IsRemoteEntityValid)
            {
                ARREntity currentRemoteParent = null;
                bool      useGlobalTransform  = false;
                var       parent = this.Owner.Parent;
                if (parent != null)
                {
                    var parentSync = parent.FindComponent <ARREntitySync>();
                    if (parentSync != null && parentSync.IsRemoteEntityValid)
                    {
                        currentRemoteParent = parentSync.RemoteEntity;
                    }
                    else
                    {
                        // Parent exists but is not a remote entity, compute global transform.
                        useGlobalTransform = true;
                    }
                }

                if (!object.Equals(this.RemoteEntity.Parent, currentRemoteParent))
                {
                    // Apply re-parent of entity.
                    this.RemoteEntity.Parent = currentRemoteParent;
                }

                if (useGlobalTransform)
                {
                    this.RemoteEntity.Position = this.transform.Position.ToRemoteDouble();
                    this.RemoteEntity.Rotation = this.transform.Orientation.ToRemote();
                    this.RemoteEntity.Scale    = this.transform.Scale.ToRemoteFloat();
                }
                else
                {
                    this.RemoteEntity.Position = this.transform.LocalPosition.ToRemoteDouble();
                    this.RemoteEntity.Rotation = this.transform.LocalOrientation.ToRemote();
                    this.RemoteEntity.Scale    = this.transform.LocalScale.ToRemoteFloat();
                }

                this.RemoteEntity.Name = this.Owner.Name;
            }
        }
    /// <summary>
    /// Find the Azure Remote Rendering components of a given type on the given entity.
    /// </summary>
    public static IEnumerable <T> FindComponentsOfType <T>(this Remote.Entity entity)
        where T : ComponentBase
    {
        if (entity == null)
        {
            yield break;
        }

        IReadOnlyList <ComponentBase> components = entity.Components;
        int count = components.Count;

        for (int i = 0; i < count; i++)
        {
            ComponentBase component = components[i];
            if (component is T)
            {
                yield return((T)component);
            }
        }
    }
    /// <summary>
    /// Set the visibility override
    /// </summary>
    public static void SetVisibilityOverride(this Remote.Entity entity, bool value)
    {
        if (entity == null || !entity.Valid)
        {
            return;
        }

        // Clear the hidden flag, or add it to the overrides
        var component = entity.EnsureComponentOfType <HierarchicalStateOverrideComponent>();
        var newFlags  = component.Flags & ~HierarchicalStates.Hidden & ~HierarchicalStates.DisableCollision;

        if (!value)
        {
            newFlags |= (HierarchicalStates.Hidden | HierarchicalStates.DisableCollision);
        }

        // Ensure remote is up-to-date
        if (component.Flags != newFlags)
        {
            component.Flags = newFlags;
        }
    }
Пример #20
0
        /// <summary>
        /// Create a proxy <see cref="EvergineEntity"/> for a remote <see cref="ARREntity"/>.
        /// <para>
        ///
        /// When created, the path from the remote <see cref="ARREntity"/> to the remote scene root will have
        /// proxy entities created for it.
        /// These proxy entities must be created in order to appropriately set the
        /// <see cref="EvergineEntity.Parent"/> for the proxy entity.
        ///
        /// As a side effect, this means that, given a Remote hierarchy:
        ///
        /// ARR.Parent
        ///     ARR.Child
        ///
        /// Calling <see cref="CreateProxyEntity"/> on ARR.Child will also create a proxy entity for ARR.Parent.
        /// </para>
        /// </summary>
        /// <param name="entityManager">The entity manager where the proxy entity is included.</param>
        /// <param name="remoteEntity">The remote entity.</param>
        /// <param name="mode">Whether the proxy components will be created.</param>
        /// <param name="recursive">Whether to create proxy entities for children of the remote entity.</param>
        /// <returns>A proxy <see cref="EvergineEntity"/> for a remote <see cref="ARREntity"/>.</returns>
        public static EvergineEntity CreateProxyEntity(this EntityManager entityManager, ARREntity remoteEntity, ARRCreationMode mode, bool recursive = false)
        {
            if (!remoteEntity.Valid)
            {
                return(null);
            }

            if (ARREntitySync.TryGetSyncComponent(remoteEntity, out _))
            {
                throw new Exception("A proxy entity for this remote entity already exists!");
            }

            var proxyEntity = new EvergineEntity();

            proxyEntity.AddComponent(new Transform3D());

            var remoteParentEntity = remoteEntity.Parent;

            if (remoteParentEntity != null)
            {
                var proxyParentEntity = GetExistingProxyEntity(remoteParentEntity);
                if (proxyParentEntity == null)
                {
                    proxyParentEntity = entityManager.CreateProxyEntity(remoteParentEntity, ARRCreationMode.DoNotCreateProxyComponents, false);
                }

                proxyParentEntity.AddChild(proxyEntity);
            }
            else
            {
                entityManager.Add(proxyEntity);
            }

            var sync = proxyEntity.FindComponent <ARREntitySync>();

            if (sync == null)
            {
                sync = new ARREntitySync();
                proxyEntity.AddComponent(sync);
            }

            sync.Bind(remoteEntity, true);

            if (mode == ARRCreationMode.CreateProxyComponents)
            {
                proxyEntity.CreateARRComponentsFromRemoteEntity(remoteEntity);
            }

            if (recursive)
            {
                foreach (var remoteChild in remoteEntity.Children)
                {
                    entityManager.CreateProxyEntity(remoteChild, mode, true);
                }
            }

            return(proxyEntity);
        }
Пример #21
0
        /// <summary>
        /// Finds a proxy <see cref="EvergineEntity"/> for a remote <see cref="ARREntity"/>.
        /// If no proxy entity already exists, a new one will be created.
        /// </summary>
        /// <param name="entityManager">The entity manager where the proxy entity is included.</param>
        /// <param name="remoteEntity">The remote entity.</param>
        /// <param name="mode">Whether the proxy components will be created.</param>
        /// <param name="recursive">Whether to create proxy entities for children of the remote entity.</param>
        /// <returns>A proxy <see cref="EvergineEntity"/> for a remote <see cref="ARREntity"/>.</returns>
        public static EvergineEntity FindOrCreateProxyEntity(this EntityManager entityManager, ARREntity remoteEntity, ARRCreationMode mode, bool recursive = false)
        {
            var proxyEntity = remoteEntity.GetExistingProxyEntity();

            if (proxyEntity == null)
            {
                proxyEntity = entityManager.CreateProxyEntity(remoteEntity, mode, false);
            }
            else if (mode == ARRCreationMode.CreateProxyComponents)
            {
                proxyEntity.CreateARRComponentsFromRemoteEntity(remoteEntity);
            }

            if (recursive)
            {
                foreach (var remoteChild in remoteEntity.Children)
                {
                    entityManager.FindOrCreateProxyEntity(remoteChild, mode, true);
                }
            }

            return(proxyEntity);
        }
Пример #22
0
        /// <summary>
        /// Create proxy components for the proxy entity for all ARR remote Components on the remote entity.
        /// </summary>
        /// <param name="proxyEntity">The local proxy <see cref="EvergineEntity"/>.</param>
        /// <param name="remoteEntity">The remote <see cref="ARREntity"/>.</param>
        public static void CreateARRComponentsFromRemoteEntity(this EvergineEntity proxyEntity, ARREntity remoteEntity)
        {
            foreach (var comp in remoteEntity.Components)
            {
                switch (comp.Type)
                {
                case ObjectType.MeshComponent:
                    proxyEntity.BindARRComponent <ARRMeshComponent>(comp);
                    break;

                case ObjectType.CutPlaneComponent:
                    proxyEntity.BindARRComponent <ARRCutPlaneComponent>(comp);
                    break;

                case ObjectType.HierarchicalStateOverrideComponent:
                    proxyEntity.BindARRComponent <ARRHierarchicalStateOverrideComponent>(comp);
                    break;

                case ObjectType.PointLightComponent:
                    proxyEntity.BindARRComponent <ARRPointLightComponent>(comp);
                    break;

                case ObjectType.SpotLightComponent:
                    proxyEntity.BindARRComponent <ARRSpotLightComponent>(comp);
                    break;

                case ObjectType.DirectionalLightComponent:
                    proxyEntity.BindARRComponent <ARRDirectionalLightComponent>(comp);
                    break;

                default:
                    throw new InvalidOperationException("Unrecognized component type in ARR to Evergine translation.");
                }
            }
        }