/// <summary> /// Process the mount operation until it completes using the provided time increment. /// </summary> /// <remarks> /// <para> /// <see cref="InitializeMount"/> must be called and return true before calling this method, then either /// this method must be called through to completion or <see cref="CancelMount"/> used to cancel the operation. /// </para> /// <para> /// No matter the value of <see cref="deltaTime"/>, the normalized time is clamped to the zero to one range. /// </para> /// </remarks> /// <param name="accessory">The accessory to update. (Required)</param> /// <param name="location">The mount location. (Required)</param> /// <param name="deltaTime">The number of seconds to to apply to the update.</param> /// <returns>True while the mount operation is in-progress. False when the operation is complete.</returns> public bool UpdateMount(Accessory accessory, MountPoint location, float deltaTime) { var state = GetMountState(accessory); if (!state.accessory) { Debug.LogError( "Accessory not initialized. Update failed: " + (accessory ? accessory.name : "Null"), accessory); return(false); } state.easeTime += deltaTime; var ntime = Mathf.Max(0, state.easeTime / m_EaseDuration); if (ntime >= 1) { FinalizeMount(accessory, location.transform); RemoveMountState(accessory); return(false); } accessory.transform.localPosition = GetLocalPosition(state.localStartPosition, PositionOffset, ntime); accessory.transform.localEulerAngles = GetLocalEulerAngles(state.localStartEulers, RotationOffset, ntime); SetMountState(state); return(true); }
protected sealed override BodyCoverage MountInternal(MountPoint location, GameObject owner) { transform.parent = location.transform; transform.localPosition = PositionOffset; transform.localEulerAngles = RotationOffset; return(m_Coverage); }
protected override IAccessoryMounter GetInitializedMounter(MountPoint location, GameObject owner) { if (!LizittUtil.IsUnityDestroyed(m_PriorityMounter) && PriorityMounter.InitializeMount(this, location)) { return(PriorityMounter); } return(m_Mounters.GetInitializedMounter(this, location)); }
// Do not seal. Allow overrides to add functionality. public override bool InitializeMount(Accessory accessory, MountPoint location) { if (!location) { return(false); } return(CanMount(accessory, 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> /// Performs a <see cref="IAccessoryMounter.CanMount"/> check on the mounters and returns the index of the /// first one that returns true, or -1 if none was found. /// </summary> /// <param name="accessory">The accessory. (Required)</param> /// <param name="location">The location.</param> /// <param name="restrictions">The body converage restrictions.</param> /// <returns>The index of the mounter than can mount the accessory, or -1 if none was found.</returns> public int CanMount(Accessory accessory, MountPoint location, BodyCoverage restrictions) { for (int i = 0; i < Count; i++) { if (Accessory.CanMount(accessory, this[i], location, restrictions)) { return(i); } } return(-1); }
/// <summary> /// Return the first mounter found that can mount the accessory, initialized and ready to update. Or null if /// none is avaiable. /// </summary> /// <param name="accessory">The accessory. (Required)</param> /// <param name="location">The mount location. (Required)</param> /// <returns></returns> public IAccessoryMounter GetInitializedMounter(Accessory accessory, MountPoint location) { for (int i = 0; i < Count; i++) { var mounter = this[i]; if (mounter != null && mounter.InitializeMount(accessory, location)) { return(mounter); } } return(null); }
/// <summary> /// Synchronize the state to the specified mount point. /// </summary> /// <remarks> /// <para> /// The main purpose of this method is to synchronized the state of mount points on two different outfits. /// </para> /// <para> /// The 'is blocked' state and context are synchronized, depending on the parameter values. Other properties /// such as location type, transform values, etc., are ignored. /// </para> /// </remarks> /// <param name="to">The mount point to sync to. (Required)</param> /// <param name="from">The mount point to sync from. (Required)</param> /// <param name="includeBlocked">Synchronize the mount point 'is blocked' state.</param> /// <param name="includeContext">Synchronize the context unless it is <paramref name="ignoreContext"/>.</param> /// <param name="ignoreContext"> /// The context that should never be synchronized. (Usually the object <paramref name="from"/> is a member of, /// such at its outfit. (Required if <paramref name="includeContext"/> is true.) /// </param> public static void Synchronize(MountPoint to, MountPoint from, bool includeBlocked, bool includeContext, GameObject ignoreContext) { if (includeBlocked) { to.IsBlocked = from.IsBlocked; } if (includeContext && from.Context != ignoreContext) { to.Context = from.Context; } }
public sealed override bool CanMount(MountPoint location, BodyCoverage restrictions) { if (!location) { return(false); } if (Accessory.CanMount(this, PriorityMounter, location, restrictions)) { return(true); } return(m_Mounters.CanMount(this, location, restrictions) != -1); }
/// <summary> /// True if the item is in the group. /// </summary> /// <remarks> /// <para> /// a null or destroyed <paramref name="item"/> always returns false. /// </para> /// </remarks> /// <param name="item">The item to check. (Required)</param> /// <returns>True if the item is in the group.</returns> public bool Contains(MountPoint item) { if (item) { for (int i = 0; i < m_Items.Length; i++) { if (m_Items[i] == item) { return(true); } } } return(false); }
private void SetState(AccessoryStatus status, GameObject owner, MountPoint location) { if (m_Status == status && m_Owner == owner && m_CurrentLocation == location) { return; } m_Status = status; m_Owner = owner; m_CurrentLocation = location; OnStateChangeLocal(); m_Observers.SendStateChange(this); }
protected sealed override BodyCoverage MountInternal(MountPoint location, GameObject owner) { if (!m_UseDefaultMounter) { Debug.LogWarning("Unexpected configuation: No mounter found for default mount location." + " Used default mounter: " + location.LocationType, this); } transform.parent = location.transform; transform.localPosition = Vector3.zero; transform.localRotation = Quaternion.identity; // The default mounter never has coverage. return(0); }
/// <summary> /// True if the mount point is part of the outfit. /// </summary> /// <param name="location">The mount point. (Required)</param> /// <returns>True if the mount point is a part of the outfit.</returns> public bool Contains(MountPoint location) { if (location) { for (int i = 0; i < MountPointCount; i++) { var item = GetMountPoint(i); if (item && item == location) { return(true); } } } return(false); }
public sealed override BodyCoverage GetCoverageFor(MountPoint location) { if (Accessory.CanMount(this, PriorityMounter, location, 0)) { return(PriorityMounter.GetCoverageFor(location)); } for (int i = 0; i < m_Mounters.Count; i++) { if (Accessory.CanMount(this, m_Mounters[i], location, 0)) { return(m_Mounters[i].GetCoverageFor(location)); } } return(0); }
/// <summary> /// Synchronize the mount point state of all common mount points. /// </summary> /// <param name="to">The outfit being synchonized to. (Required)</param> /// <param name="from">The outfit being syncronzied from. (Required)</param> /// <param name="includeBlocked">Synchronize the mount point 'is blocked' state.</param> /// <param name="includeContext"> /// Synchronize the context unless it is the <paramref name="from"/> object's GameObject. /// </param> public static void SynchronizeMountPointState(Outfit to, Outfit from, bool includeBlocked, bool includeContext) { if (!(from && to)) { return; } for (int i = 0; i < from.MountPointCount; i++) { var prevPart = from.GetMountPoint(i); if (prevPart) { var part = to.GetMountPoint(prevPart.LocationType); if (part) { MountPoint.Synchronize(part, prevPart, includeBlocked, includeContext, from.gameObject); } } } }
/// <summary> /// Performs the first update on the mounter and takes the appropriate action if it completes or needs /// more updates. /// </summary> private void RunMounter(IAccessoryMounter mounter, GameObject owner, MountPoint location, BodyCoverage additionalCoverage) { CleanupCurrentState(); int id = m_MounterId + 1; m_MounterId = id; m_CurrentCoverage = mounter.GetCoverageFor(location.LocationType) | additionalCoverage; if (mounter.UpdateMount(this, location, !Application.isPlaying)) { StartCoroutine(DoDurationMount(mounter, owner, location)); } else { SetState(AccessoryStatus.Mounted, owner, location); } }
// TODO: EVAL: Convert mounting to a method that supports serialization. // This is not a high proiority, especially since the standard mounters support // immediate completion outside of play mode. But having all major features except // mounting provide support for serialization might be an issue. /// <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 && !LizittUtil.IsUnityDestroyed(mounter) && mounter.UpdateMount(this, location)) { yield return(null); } if (m_MounterId == id) { SetState(AccessoryStatus.Mounted, owner, location); m_CurrentMounter = null; } }
public override bool InitializeMount(Accessory accessory, MountPoint location) { if (location && CanMount(accessory, location.LocationType)) { var state = GetMountState(accessory); state.accessory = accessory; // Might be a new state. state.easeTime = state.easeTime == 0 ? 0 : state.easeTime; accessory.transform.parent = location.transform; state.localStartPosition = accessory.transform.localPosition; state.localStartEulers = accessory.transform.localEulerAngles; SetMountState(state); return(true); } return(false); }
/// <summary> /// Process the mount operation until it completes using the provided time increment. /// </summary> /// <remarks> /// <para> /// <see cref="InitializeMount"/> must be called and return true before calling this method, then either /// this method must be called through to completion or <see cref="CancelMount"/> used to cancel the operation. /// </para> /// <para> /// No matter the value of <see cref="deltaTime"/>, the normalized time is clamped to the zero to one range. /// </para> /// </remarks> /// <param name="accessory">The accessory to update. (Required)</param> /// <param name="location">The mount location. (Required)</param> /// <param name="deltaTime">The number of seconds to to apply to the update.</param> /// <returns>True while the mount operation is in-progress. False when the operation is complete.</returns> public sealed override bool UpdateMount(Accessory accessory, MountPoint location, float deltaTime) { var state = GetMountState(accessory); if (!state.accessory) { Debug.LogError( "Accessory not initialized. Update failed: " + (accessory ? accessory.name : "Null"), accessory); return(false); } state.easeTime += deltaTime; var ntime = Mathf.Max(0, state.easeTime / m_EaseDuration); if (ntime >= 1) { FinalizeMount(accessory, location.transform); RemoveMountState(accessory); return(false); } // Local offset -> Global space. var endPos = location.transform.TransformPoint(PositionOffset); var endRot = location.transform.rotation * Quaternion.Euler(RotationOffset); if (accessory.transform.parent) { // Global space -> Same space as accessory. endPos = accessory.transform.parent.InverseTransformPoint(endPos); endRot = (Quaternion.Inverse(accessory.transform.parent.rotation) * endRot); } accessory.transform.localPosition = GetPosition(state.startPosition, endPos, ntime); accessory.transform.localEulerAngles = GetEulerAngles(state.startEulers, endRot.eulerAngles, ntime); SetMountState(state); return(true); }
/// <summary> /// Mount the accessory to the specified mount point. /// </summary> /// <remarks> /// <para> /// This method is guarenteed to return true if <see cref="CanMount"/> returns true. /// But it is valid to use a call to this method without pre-checking mountability. E.g. As an optimitation, /// it is valid to simply call this method on a list of all available accessories to let the accessory /// decide whether or not it can attach /// </para> /// <para> /// <paramref name="additionalCoverage"/> is useful in when an accessory uses a generic mounter that doesn't /// provide coverage information. /// </para> /// <para> /// Mount priority is as follows: The priority mounter supplied by the mount method, /// the mounter provided by <see cref="GetInitializedMounter"/>, <see cref="MountInternal"/> if /// <see cref="CanMountInteral"/> is true. <see cref="MountInternal"/> only supports immediate completion /// mounting. /// </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. (I.e. A custom mounter.) /// </param> /// <param name="additionalCoverage"> /// Additional coverage to apply on a successful mount, above and beyond the coverage /// supplied by the mounter or built into the accessory. /// </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 (!LizittUtil.IsUnityDestroyed(priorityMounter) && priorityMounter.InitializeMount(this, location)) { RunMounter(priorityMounter, owner, location, additionalCoverage); return(true); } var mounter = GetInitializedMounter(location, owner); if (!LizittUtil.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); }
public sealed override bool UpdateMount(Accessory accessory, MountPoint location, bool immediateComplete) { float deltaTime = (Application.isPlaying && !immediateComplete) ? Time.deltaTime : m_EaseDuration + 0.1f; return(UpdateMount(accessory, location, deltaTime)); }
public sealed override bool InitializeMount(Accessory accessory, MountPoint location) { if (location && CanMount(accessory, location)) { var state = GetMountState(accessory); state.accessory = accessory; // Might be a new state. state.easeTime = state.easeTime == 0 ? 0 : state.easeTime; if (m_UseSharedSpace) { if (accessory.transform.IsChildOf(location.transform) || location.transform.IsChildOf(accessory.transform)) // Unexpected. But who knows. { accessory.transform.parent = null; } else { accessory.transform.parent = accessory.transform.GetSharedParent(location.transform); } } else { accessory.transform.parent = location.transform; } // See notes for EaseSpaceType. Restore or remove by v0.4. //switch (m_Space) //{ // case EaseSpaceType.FirstShared: // if (accessory.transform.IsChildOf(location.transform) // || location.transform.IsChildOf(accessory.transform)) // Unexpected. But who knows. // { // accessory.transform.parent = null; // } // else // accessory.transform.parent = accessory.transform.GetSharedParent(location.transform); // break; // case EaseSpaceType.MotionRoot: // var outfit = location.GetComponentInParent<Outfit>(); // if (!outfit && location.Context) // outfit = location.Context.GetComponent<Outfit>(); // if (outfit) // accessory.transform.parent = outfit.transform; // else // { // accessory.transform.parent = null; // Debug.LogWarning( // "Could not locate the mount point's Outfit. Falling back to world space. MountPoint: " // + location.name, location); // } // break; // case EaseSpaceType.MountPoint: // accessory.transform.parent = location.transform; // break; // case EaseSpaceType.MountParent: // accessory.transform.parent = location.transform.parent; // break; // case EaseSpaceType.MountContext: // accessory.transform.parent = location.Context ? location.Context.transform : null; // break; // case EaseSpaceType.AccessoryParent: // // Do nothing. // break; // default: // accessory.transform.parent = null; // break; //} state.startPosition = accessory.transform.localPosition; state.startEulers = accessory.transform.localEulerAngles; SetMountState(state); return(true); } return(false); }
protected sealed override IAccessoryMounter GetInitializedMounter(MountPoint location, GameObject owner) { return(null); }
protected sealed override bool CanMountInternal(MountPoint location, GameObject owner) { return(location.LocationType == m_Location); }
public sealed override bool CanMount(Accessory accessory, MountPoint location) { return(location && location.LocationType == m_To && accessory && accessory.CurrentLocation && accessory.CurrentLocation.LocationType == m_From); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract bool UpdateMount(Accessory accessory, MountPoint location, float deltaTime);
public sealed override void CancelMount(Accessory accessory, MountPoint location) { // Don't finalize the mount. Assume that another mounter is taking over and that it is designed to take // over easing as needed. (Since that is the best design.) RemoveMountState(accessory); }
public virtual void CancelMount(Accessory accessory, MountPoint location) { // Do nothing. // Most mounters are expected to be immediate-complete, so don't make them all implement this method. }
public sealed override BodyCoverage GetCoverageFor(MountPoint location) { return((location && location.LocationType == m_To) ? MountedCoverage : 0); }
// Don't seal this. Extensions may need to put in place additional checks. public override bool CanMount(MountPoint location, BodyCoverage restrictions) { return(location && location.LocationType == m_Location && (m_Coverage & restrictions) == 0); }