/// <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); } } } }
/// <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(); } }
/// <summary> /// Check existence of fragment with indicated id, /// and create it if it doesn't already exist. /// </summary> /// <param name="id">The fragment id</param> private Fragment EnsureFragment(FragmentId id) { if (!id.IsKnown()) { return(null); } if (!fragments.ContainsKey(id)) { fragments[id] = new Fragment(id); } return(fragments[id]); }
/// <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); }