public sealed override MountResult Mount(Accessory accessory, MountPointType locationType,
                                                 bool ignoreRestrictions, IAccessoryMounter priorityMounter, BodyCoverage additionalCoverage)
        {
            // Error checks are optimized with the assumption that the mount will succeed. Remounts to the same
            // location are allowed.  (Mounter may have changed or may have special remount behavior.)

            var location = GetMountPoint(locationType);

            if (!location)
            {
                Release(accessory);
                return(MountResult.NoMountPoint);
            }
            else if (location.IsBlocked)
            {
                Release(accessory);
                return(MountResult.LocationBlocked);
            }

            if (!ignoreRestrictions)
            {
                if (AccessoriesLimited && !accessory.IgnoreLimited)
                {
                    Release(accessory);
                    return(MountResult.OutfitIsLimited);
                }

                var currentCoverage = CurrentCoverage;
                if (m_Accessories.Contains(accessory))
                {
                    currentCoverage &= ~accessory.CurrentCoverage;
                }

                if (((accessory.GetCoverageFor(location) | additionalCoverage) & currentCoverage) != 0)
                {
                    Release(accessory);
                    return(MountResult.CoverageBlocked);
                }
            }

            if (priorityMounter != null && LizUtil.IsUnityDestroyed(priorityMounter))
            {
                Debug.LogError("The priority mounter is a reference to a destroyed object.", this);
                Release(accessory);
                return(MountResult.FailedOnError);
            }

            if (!accessory.Mount(location, gameObject, priorityMounter, additionalCoverage))
            {
                Release(accessory);
                return(MountResult.RejectedByAccessory);
            }

            LinkAccessory(accessory);

            Observers.SendAccessoryMount(this, accessory);

            return(MountResult.Success);
        }
        protected sealed override IAccessoryMounter GetInitializedMounter(MountPoint location, GameObject owner)
        {
            if (!LizUtil.IsUnityDestroyed(m_PriorityMounter) && PriorityMounter.InitializeMount(this, location))
            {
                return(PriorityMounter);
            }

            return(m_Mounters.GetInitializedMounter(this, location));
        }
        /// <summary>
        /// Determines if the mounter can mount the accessory to the specified location based on the accessory's
        /// current state and without violating the coverage restrictions.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method implements the standard method for this check, including all appropriate null checks.
        /// (E.g. If there is no accessory, it will return false.)
        /// </para>
        /// <para>
        /// The coverage restrictions are violated if a successful mount will result in a coverage that overlaps
        /// <paramref name="restrictions"/>.
        /// </para>
        /// </remarks>
        /// <param name="accessory">The accessory. (Optional)</param>
        /// <param name="mounter">The mounter. (Optional)</param>
        /// <param name="location">The mount location. (Optional)</param>
        /// <param name="restrictions">The body coverage restrictions.</param>
        /// <returns>
        /// True if accessory, mounter, and location are all non-null and the mounter can mount the accessory to the
        /// specified location with the coverage restrictions.
        /// </returns>
        public static bool CanMount(
            Accessory accessory, IAccessoryMounter mounter, MountPoint location, BodyCoverage restrictions)
        {
            if (accessory && location && !LizUtil.IsUnityDestroyed(mounter) &&
                (mounter.GetCoverageFor(location) & restrictions) == 0)
            {
                return(mounter.CanMount(accessory, location));
            }

            return(false);
        }
        /// <summary>
        /// Kicks off a coroutine to run the mounter through to completion.
        /// </summary>
        private System.Collections.IEnumerator DoDurationMount(
            IAccessoryMounter mounter, GameObject owner, MountPoint location)
        {
            m_CurrentMounter = mounter;
            var id = m_MounterId;

            SetState(AccessoryStatus.Mounting, owner, location);

            yield return(null);

            while (m_MounterId == id && !LizUtil.IsUnityDestroyed(mounter) && mounter.UpdateMount(this, location))
            {
                yield return(null);
            }

            if (m_MounterId == id)
            {
                SetState(AccessoryStatus.Mounted, owner, location);
                m_CurrentMounter = null;
            }
        }
        /// <summary>
        /// Mount the accessory to the specified location.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method will always succeed if <see cref="CanMount(MountPoint, BodyCoverage)"/> returns true.
        /// </para>
        /// <para>
        /// Supports lazy calling.  E.g. As an optimitation it is valid to simply call this method on a list of
        /// available accessories to let the accessory decide whether or not it can mount.
        /// </para>
        /// <para>
        /// <paramref name="additionalCoverage"/> is useful in situations where an accessory uses a generic mounter
        /// that doesn't provide coverage information.  On a successful mount the additional coverage will be
        /// added to the coverage supplied by the mounter and/or built into the accessory.
        /// </para>
        /// <para>
        /// Mounter priority is as follows:
        /// </para>
        /// <para>
        /// <ol>
        /// <li>The priority mounter supplied by the mount method.</li>
        /// <li>The mounter provided by <see cref="GetInitializedMounter"/></li>
        /// <li><see cref="MountInternal"/> if <see cref="CanMountInteral"/> is true</li>
        /// </ol>
        /// </para>
        /// <para>
        /// <see cref="MountInternal"/> only supports immediate completion.
        /// </para>
        /// </remarks>
        /// <param name="location">The mount location. (Required)</param>
        /// <param name="owner">The object that will own the accessory after a successful mount. (Required)</param>
        /// <param name="priorityMounter">
        /// The mounter to attempt before any others are tried. (Optional)
        /// </param>
        /// <param name="additionalCoverage">
        /// Additional coverage to apply on a successful mount, above and beyond the coverage supplied by the
        /// mounter and/or built into the accessory. (Optional)
        /// </param>
        /// <returns>True if the mount succeeded, otherwise false.</returns>
        public sealed override bool Mount(MountPoint location, GameObject owner, IAccessoryMounter priorityMounter,
                                          BodyCoverage additionalCoverage)
        {
            // While not expected to be common, it is technically ok to re-attach to the same
            // mount location, so there is no optimization check for that.

            if (!(location && owner))
            {
                Debug.LogError("Null mount location and/or owner.", this);
                return(false);
            }
            ;

            if (!LizUtil.IsUnityDestroyed(priorityMounter) && priorityMounter.InitializeMount(this, location))
            {
                RunMounter(priorityMounter, owner, location, additionalCoverage);
                return(true);
            }

            var mounter = GetInitializedMounter(location, owner);

            if (!LizUtil.IsUnityDestroyed(mounter))
            {
                RunMounter(mounter, owner, location, additionalCoverage);
                return(true);
            }

            if (CanMountInternal(location, owner))
            {
                CleanupCurrentState();

                m_CurrentCoverage = MountInternal(location, owner) | additionalCoverage;
                SetState(AccessoryStatus.Mounted, owner, location);

                return(true);
            }

            return(false);
        }