Esempio n. 1
0
        /// <summary>
        /// If conditions have changed to allow finalizing creation of any pending attachment points,
        /// do it now.
        /// </summary>
        private void ProcessPendingAttachmentPoints()
        {
            if (CurrentFragmentId.IsKnown() && pendingAttachments.Count > 0)
            {
                // We have a valid destination fragment. Note that since this queue is in order of submission,
                // if an attachment point depends on a second attachment point for context,
                // that second will be either earlier in the list (because there was no valid current fragment when it was
                // created) or it will have a valid fragment. So by the time we get to the one with a dependency (pending.context != null),
                // its dependency will have a valid fragment id.
                int pendingCount = pendingAttachments.Count;
                for (int i = 0; i < pendingCount; ++i)
                {
                    AttachmentPoint  target         = pendingAttachments[i].target;
                    Vector3          frozenPosition = pendingAttachments[i].target.ObjectPosition;
                    IAttachmentPoint context        = pendingAttachments[i].context;

                    SetupAttachmentPoint(plugin, target, context);

                    FragmentId fragmentId = CurrentFragmentId;
                    if (context != null)
                    {
                        fragmentId = context.FragmentId;
                    }
                    Debug.Assert(fragmentId.IsKnown(), $"FragmentId {fragmentId.FormatStr()} invalid from {(context != null ? "context" : "head")} in processing pending");
                    Fragment fragment = EnsureFragment(fragmentId);
                    Debug.Assert(fragment != null, "Valid fragmentId but no fragment found");
                    fragment.AddAttachmentPoint(target);
                }
                // All pending must now be in a good home fragment, clear the to-do list.
                pendingAttachments.Clear();
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Teleport (as opposed to Move) means that the object is meant to have disappeared at its old position
        /// and instantaneously reappeared at its new position in frozen space without traversing the space in between.
        /// </summary>
        /// <remarks>
        /// This is equivalent to releasing the existing attachment point and creating a new one,
        /// except in that the attachment point reference remains valid.
        /// See <see cref="WorldLockingManager.TeleportAttachmentPoint"/>.
        /// </remarks>
        /// <param name="attachPointIface">The attachment point to teleport</param>
        /// <param name="newFrozenPosition">The position to teleport to.</param>
        /// <param name="context">The optional context.</param>
        public void TeleportAttachmentPoint(IAttachmentPoint attachPointIface, Vector3 newFrozenPosition, IAttachmentPoint context)
        {
            AttachmentPoint attachPoint = attachPointIface as AttachmentPoint;

            if (attachPoint != null)
            {
                attachPoint.ObjectPosition = newFrozenPosition;

                // Save the fragment it's currently in, in case it changes here.
                FragmentId oldFragmentId = attachPoint.FragmentId;

                // If it's not in a valid fragment, it is still pending and will get processed when the system is ready.
                if (oldFragmentId.IsKnown())
                {
                    FragmentId newFragmentId = GetTargetFragmentId(context);
                    // If there is a valid current fragment,
                    if (newFragmentId.IsKnown())
                    {
                        // Fill it in with a new one.
                        SetupAttachmentPoint(plugin, attachPoint, context);

                        if (attachPoint.FragmentId != oldFragmentId)
                        {
                            ChangeAttachmentPointFragment(oldFragmentId, attachPoint);
                        }
                    }
                    else
                    {
                        AddPendingAttachmentPoint(attachPoint, context);
                    }
                }
            }
        }
Esempio n. 3
0
 /// <summary>
 /// Add a new attachment point to the pending list to be processed when the system is ready.
 /// </summary>
 /// <param name="attachPoint">Attachment point to process later.</param>
 /// <param name="context">Optional spawning attachment point, may be null.</param>
 private void AddPendingAttachmentPoint(AttachmentPoint attachPoint, IAttachmentPoint context)
 {
     // Flag as being in an invalid state
     attachPoint.HandleStateChange(AttachmentPointStateType.Pending);
     pendingAttachments.Add(
         new PendingAttachmentPoint
     {
         target  = attachPoint,
         context = context
     }
         );
 }
Esempio n. 4
0
 /// <summary>
 /// Add an existing attachment point to this fragment.
 /// </summary>
 /// <remarks>
 /// The attachment point might currently belong to another fragment, if
 /// it is being moved from the other to this.
 /// Since this is only used internally, it operates directly on an AttachmentPoint
 /// rather than an interface to avoid an unnecessary downcast.
 /// </remarks>
 /// <param name="attachPoint"></param>
 public void AddAttachmentPoint(AttachmentPoint attachPoint)
 {
     if (attachPoint != null)
     {
         if (attachPoint.StateHandler != null)
         {
             updateStateAllAttachments += attachPoint.StateHandler;
         }
         attachPoint.HandleStateChange(State);
         attachmentList.Add(attachPoint);
     }
 }
Esempio n. 5
0
        /// <summary>
        /// Helper to move an attachment point from one fragment to another.
        /// </summary>
        /// <remarks>
        /// Assumes that the attachment point's FragmentId property has already been set to the new fragment.
        /// </remarks>
        /// <param name="oldFragmentId">Source fragment</param>
        /// <param name="attachPoint">The attachment point</param>
        private void ChangeAttachmentPointFragment(FragmentId oldFragmentId, AttachmentPoint attachPoint)
        {
            Debug.Assert(oldFragmentId != attachPoint.FragmentId, "Moving attachment point from and to same fragment");

            Fragment oldFragment = EnsureFragment(oldFragmentId);
            Fragment newFragment = EnsureFragment(attachPoint.FragmentId);

            Debug.Assert(oldFragment != null, "Valid fragmentId's but null source fragment");
            Debug.Assert(newFragment != null, "Valid fragmentId's but null destination fragment");

            // Add to the new fragment
            newFragment.AddAttachmentPoint(attachPoint);

            // Remove from the old fragment
            oldFragment.ReleaseAttachmentPoint(attachPoint);
        }
Esempio n. 6
0
        /// <summary>
        /// Absorb the contents of another fragment, emptying it.
        /// </summary>
        /// <param name="other">The fragment to lose all its contents to this.</param>
        public void AbsorbOtherFragment(Fragment other)
        {
            Debug.Assert(other != this, $"Trying to merge to and from the same fragment {FragmentId}");
            int otherCount = other.attachmentList.Count;

            for (int i = 0; i < otherCount; ++i)
            {
                AttachmentPoint att = other.attachmentList[i];
                att.Set(FragmentId, att.CachedPosition, att.AnchorId, att.LocationFromAnchor);
                if (att.StateHandler != null)
                {
                    updateStateAllAttachments += att.StateHandler;
                }
                att.HandleStateChange(State);
                attachmentList.Add(att);
            }
            other.ReleaseAll();
        }
Esempio n. 7
0
        /// <summary>
        /// Notify system attachment point is no longer needed. See <see cref="IAttachmentPointManager.ReleaseAttachmentPoint"/>
        /// </summary>
        /// <param name="attachmentPoint"></param>
        public void ReleaseAttachmentPoint(IAttachmentPoint attachmentPoint)
        {
            AttachmentPoint attachPoint = attachmentPoint as AttachmentPoint;

            if (attachPoint != null)
            {
                if (attachPoint.StateHandler != null)
                {
                    updateStateAllAttachments -= attachPoint.StateHandler;
                }
                attachPoint.HandleStateChange(AttachmentPointStateType.Released);
                attachmentList.Remove(attachPoint);
            }
            else
            {
                Debug.LogError("On release, IAttachmentPoint isn't AttachmentPoint");
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Create and register a new attachment point.
        /// </summary>
        /// <remarks>
        /// The attachment point itself is a fairly opaque handle. Its effects are propagated to the client via the
        /// two handlers associated with it.
        /// The optional context attachment point provides an optional contextual hint to where in the anchor
        /// graph to bind the new attachment point.
        /// See <see cref="IAttachmentPointManager.CreateAttachmentPoint"/>.
        /// </remarks>
        /// <param name="frozenPosition">The position in the frozen space at which to start the attachment point</param>
        /// <param name="context">The optional context into which to create the attachment point (may be null)</param>
        /// <param name="locationHandler">Delegate to handle WorldLocking system adjustments to position</param>
        /// <param name="stateHandler">Delegate to handle WorldLocking connectivity changes</param>
        /// <returns>The new attachment point interface.</returns>
        public IAttachmentPoint CreateAttachmentPoint(Vector3 frozenPosition, IAttachmentPoint context,
                                                      AdjustLocationDelegate locationHandler, AdjustStateDelegate stateHandler)
        {
            FragmentId      fragmentId  = GetTargetFragmentId(context);
            AttachmentPoint attachPoint = new AttachmentPoint(locationHandler, stateHandler);

            attachPoint.ObjectPosition = frozenPosition;
            if (fragmentId.IsKnown())
            {
                SetupAttachmentPoint(plugin, attachPoint, context);

                Fragment fragment = EnsureFragment(fragmentId);
                Debug.Assert(fragment != null, "Valid fragmentId but no fragment found");
                fragment.AddAttachmentPoint(attachPoint);
            }
            else
            {
                AddPendingAttachmentPoint(attachPoint, context);
            }
            return(attachPoint);
        }
Esempio n. 9
0
        /// <summary>
        /// Release an attachment point for disposal. The attachment point is no longer valid after this call.
        /// </summary>
        /// <remarks>
        /// In the unlikely circumstance that another attachment point has been spawned from this one
        /// but has not yet been processed (is still in the pending queue),
        /// that relationship is broken on release of this one, and when the other attachment point is
        /// finally processed, it will be as if it was created with a null context.
        /// </remarks>
        /// <param name="attachPointIface">The attachment point to release.</param>
        public void ReleaseAttachmentPoint(IAttachmentPoint attachPointIface)
        {
            AttachmentPoint attachPoint = attachPointIface as AttachmentPoint;

            if (attachPoint != null)
            {
                Fragment fragment = EnsureFragment(attachPoint.FragmentId);
                if (fragment != null)
                {
                    // Fragment handles notification.
                    fragment.ReleaseAttachmentPoint(attachPoint);
                }
                else
                {
                    // Notify of the state change to released.
                    attachPoint.HandleStateChange(AttachmentPointStateType.Released);
                    // The list of pending attachments is expected to be small, and release of an attachment
                    // point while there are pending attachments is expected to be rare. So brute force it here.
                    // If the attachment point being released is a target in the pending list, remove it.
                    // If it is the context of another pending target, set that context to null.
                    // Proceed through the list in reverse order, because context fixes will only be found
                    // later in the list than the original, and once the original is found we are done.
                    int pendingCount = pendingAttachments.Count;
                    for (int i = pendingCount - 1; i >= 0; --i)
                    {
                        if (pendingAttachments[i].context == attachPoint)
                        {
                            var p = pendingAttachments[i];
                            p.context             = null;
                            pendingAttachments[i] = p;
                        }
                        else if (pendingAttachments[i].target == attachPoint)
                        {
                            pendingAttachments.RemoveAt(i);
                            break;
                        }
                    }
                }
            }
        }
Esempio n. 10
0
 /// <summary>
 /// Helper function for setting up the internals of an AttachmentPoint
 /// </summary>
 /// <param name="plugin">The global plugin</param>
 /// <param name="target">The attachment point to setup</param>
 /// <param name="context">The optional context <see cref="CreateAttachmentPoint"/></param>
 public static void SetupAttachmentPoint(IPlugin plugin, AttachmentPoint target, IAttachmentPoint context)
 {
     if (context != null)
     {
         AnchorId anchorId;
         Vector3  locationFromAnchor;
         plugin.CreateAttachmentPointFromSpawner(context.AnchorId, context.LocationFromAnchor, target.ObjectPosition,
                                                 out anchorId, out locationFromAnchor);
         FragmentId fragmentId = context.FragmentId;
         target.Set(fragmentId, target.ObjectPosition, anchorId, locationFromAnchor);
     }
     else
     {
         FragmentId currentFragmentId = plugin.GetMostSignificantFragmentId();
         AnchorId   anchorId;
         Vector3    locationFromAnchor;
         plugin.CreateAttachmentPointFromHead(target.ObjectPosition,
                                              out anchorId, out locationFromAnchor);
         FragmentId fragmentId = currentFragmentId;
         target.Set(fragmentId, target.ObjectPosition, anchorId, locationFromAnchor);
     }
 }
Esempio n. 11
0
        /// <summary>
        /// Move (as opposed to Teleport) means that the object is meant to have traversed
        /// flozen space from its old position to the given new position on some continuous path.
        /// </summary>
        /// <remarks>
        /// Not to be used for automatic (i.e. FrozenWorld Engine instigated) moves.
        /// See <see cref="WorldLockingManager.MoveAttachmentPoint"/>
        /// </remarks>
        /// <param name="attachPoint">Attachment point to move</param>
        /// <param name="newFrozenPosition">The new position in frozen space</param>
        public void MoveAttachmentPoint(IAttachmentPoint attachPointIface, Vector3 newFrozenPosition)
        {
            AttachmentPoint attachPoint = attachPointIface as AttachmentPoint;

            if (attachPoint != null)
            {
                attachPoint.ObjectPosition = newFrozenPosition;

                // If it's not in a valid fragment, it is still pending and will get processed when the system is ready.
                if (attachPoint.FragmentId.IsKnown())
                {
                    float minDistToUpdateSq = 0.5f * 0.5f;

                    float moveDistanceSq = (newFrozenPosition - attachPoint.CachedPosition).sqrMagnitude;
                    if (moveDistanceSq > minDistToUpdateSq)
                    {
                        attachPoint.LocationFromAnchor = plugin.MoveAttachmentPoint(newFrozenPosition, attachPoint.AnchorId, attachPoint.LocationFromAnchor);
                        attachPoint.CachedPosition     = newFrozenPosition;
                    }
                    // Else we haven't moved enough to bother doing anything.
                }
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Run through all attachment points, get their adjustments from the plugin and apply them.
        /// </summary>
        /// <remarks>
        /// This must be called between plugin.Refreeze() and plugin.RefreezeFinish().
        /// </remarks>
        public void AdjustAll(IPlugin plugin)
        {
            int count = attachmentList.Count;

            for (int i = 0; i < count; ++i)
            {
                AttachmentPoint attach = attachmentList[i];

                AnchorId newAnchorId;
                Vector3  newLocationFromAnchor;
                Pose     adjustment;
                if (plugin.ComputeAttachmentPointAdjustment(attach.AnchorId, attach.LocationFromAnchor,
                                                            out newAnchorId, out newLocationFromAnchor, out adjustment))
                {
                    attach.Set(FragmentId, attach.CachedPosition, newAnchorId, newLocationFromAnchor);

                    attach.HandlePoseAdjustment(adjustment);
                }
                else
                {
                    Debug.Log($"No adjustment during refreeze for {attach.AnchorId.ToString()}");
                }
            }
        }