You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1820 lines
74 KiB
C#

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Events;
using MalbersAnimations.Events;
using MalbersAnimations.Scriptables;
using MalbersAnimations.Controller;
using System.Collections;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif
/// <summary> Horse Animset Pro RIDING SYSTEM </summary>
/// <summary> Version 4.3 </summary>
namespace MalbersAnimations.HAP
{
public enum DismountType { Random, Input, Last }
[AddComponentMenu("Malbers/Riding/Rider")]
[HelpURL("https://malbersanimations.gitbook.io/animal-controller/riding/mrider")]
public class MRider : MonoBehaviour, IAnimatorListener, IRider
{
#region Public Variables
/// <summary>Parent to mount Point </summary>
public BoolReference Parent = new BoolReference(true);
/// <summary>This animal is the one that you can call or StartMount </summary>
public GameObjectReference m_MountStored = new GameObjectReference();
public Mount MountStored// => m_MountStored.Value != null ? m_MountStored.Value.FindComponent<Mount>() : null;
{
get => p_MountStored;
protected set
{
p_MountStored = value;
//Debug.Log("mountTrigger " + mountTrigger);
}
}
private Mount p_MountStored;
/// <summary>True iff we want to start mounted an animal </summary>
public BoolReference StartMounted;
[Tooltip("Resync Animations with the Mount")]
public bool ReSync = true;
public Vector3Reference Gravity = new Vector3Reference(Vector3.down);
[SerializeField] private BoolReference m_CanMount = new BoolReference(false);
[SerializeField] private BoolReference m_CanDismount = new BoolReference(false);
[SerializeField] private BoolReference m_CanCallAnimal = new BoolReference(false);
/// <summary>Changes the Dismount animation on the Rider</summary>
public DismountType DismountType = DismountType.Random;
/// <summary>Mounted Layer Path</summary>
public string LayerPath = "Layers/Mount v2";
/// <summary>Mounted Layer Name</summary>
public string MountLayer = "Mounted";
[Tooltip("Reference for the Right Hand gameobject")]
[ContextMenuItem("Find Right Hand","FindRHand")]
public Transform RightHand;
[ContextMenuItem("Find Left Hand", "FindLHand")]
[Tooltip("Reference for the Left Hand gameobject")]
public Transform LeftHand;
[Tooltip("Left Offset to place the Reins in the Left Hand")]
public Vector3Reference LeftReinOffset = new Vector3Reference();
[Tooltip("Right Offset to place the Reins in the Right Hand")]
public Vector3Reference RightReinOffset = new Vector3Reference();
private bool freeRightHand = true;
private bool freeLeftHand = true;
public readonly static int IKLeftFootHash = Animator.StringToHash("IKLeftFoot");
public readonly static int IKRightFootHash = Animator.StringToHash("IKRightFoot");
public readonly static int MountHash = Animator.StringToHash("Mount");
public readonly static int MountSideHash = Animator.StringToHash("MountSide");
public static readonly int EmptyHash = Animator.StringToHash("Empty");
/// <summary>Type to Update to set Everyframe the position and rotation of the rider to the Animal Mount Point</summary>
[Utilities.Flag("Update Type")]
public UpdateMode LinkUpdate = UpdateMode.Update | UpdateMode.FixedUpdate;
/// <summary>Time to Align to the Mount Trigger Position while is playing the Mount Animation</summary>
public FloatReference AlingMountTrigger = new FloatReference(0.2f);
private Hashtable animatorParams;
public bool debug;
#region Call Animal
public AudioClip CallAnimalA;
public AudioClip StopAnimalA;
public AudioSource RiderAudio;
/// <summary>Call for the animal, True: Calls The Animal, False: if the animal was calling then stop its movement</summary>
public bool ToggleCall { get; set; }
#endregion
#region ExtraCollider
public CapsuleCollider MainCollider;
private OverrideCapsuleCollider Def_CollPropeties;
[CreateScriptableAsset] public CapsuleColliderPreset MountCollider;
#endregion
#region UnityEvents
public GameObjectEvent OnFindMount = new GameObjectEvent();
public BoolEvent OnCanMount = new BoolEvent();
public BoolEvent OnCanDismount = new BoolEvent();
public BoolEvent CanCallMount = new BoolEvent();
public UnityEvent OnStartMounting = new UnityEvent();
public UnityEvent OnEndMounting = new UnityEvent();
public UnityEvent OnStartDismounting = new UnityEvent();
public UnityEvent OnEndDismounting = new UnityEvent();
public UnityEvent OnAlreadyMounted = new UnityEvent();
#endregion
public BoolReference DisableComponents;
public Behaviour[] DisableList;
#endregion
#region Auto Properties
/// <summary>Montura stored when the Riders enters a MountTrigger</summary>
public Mount Montura { get; set; }
public virtual IInputSource MountInput { get; set; }
/// <summary> If Null means that we are NOT Near to an Animal</summary>
public MountTriggers MountTrigger { get; set; }
//{
// get => mountTrigger;
// protected set
// {
// mountTrigger = value;
// Debug.Log("mountTrigger "+ mountTrigger);
// }
//}
//MountTriggers mountTrigger;
public bool CanMount { get => m_CanMount.Value; protected set => m_CanMount.Value = value; }
public bool CanDismount { get => m_CanDismount.Value; protected set => m_CanDismount.Value = value; }
/// <summary>Check if we can call the Animal</summary>
public bool CanCallAnimal { get => m_CanCallAnimal.Value; protected set => m_CanCallAnimal.Value = value; }
/// <summary> Speed Multiplier for the Speeds Changes while using other Animals</summary>
public float SpeedMultiplier { get; set; }
public float TargetSpeedMultiplier { get; set; }
public bool ForceLateUpdateLink { get; set; }
/// <summary> Store all the MonoBehaviours on this GameObject</summary>
protected MonoBehaviour[] AllComponents { get; set; }
#endregion
#region IK VARIABLES
protected float L_IKFootWeight = 0f; //IK Weight for Left Foot
protected float R_IKFootWeight = 0f; //IK Weight for Right Foot
#endregion
/// <summary>Target Rotation the Rider does while Mounting / Dismouting</summary>
public Quaternion MountRotation { get; set; }
/// <summary>Target Posttion the Rider does while Mounting / Dismouting</summary>
public Vector3 MountPosition { get; set; }
internal int MountLayerIndex = -1; //Mount Layer Index
protected AnimatorUpdateMode Default_Anim_UpdateMode;
#region Properties
protected bool mounted;
public bool Mounted
{
get => mounted;
set
{
mounted = value;
// Debug.Log("mounted = " + mounted);
SetAnimParameter(MountHash, Mounted); //Update Mount Parameter on the Animator
}
}
public bool IsOnHorse { get; protected set; }
public bool IsRiding => IsOnHorse && Mounted;
/// <summary>Returns true if the Rider is from the Start of the Mount to the End of the Dismount</summary>
public bool IsMountingDismounting => IsOnHorse || Mounted;
public bool IsMounting => !IsOnHorse && Mounted;
/// <summary>Returns true if the Rider is between the Start and the End of the Dismount Animations</summary>
public bool IsDismounting => IsOnHorse && !Mounted;
#region private vars
/// <summary>Straight Spine Weight for the Bones</summary>
protected float SP_Weight;
// protected float SAim_Weight;
protected RigidbodyConstraints DefaultConstraints;
protected CollisionDetectionMode DefaultCollision;
#region Re-Sync with Horse
//Used this for Sync Animators
private float RiderNormalizedTime;
private float HorseNormalizedTime;
[Tooltip("If the Mount and the Rider has a difference on the Animator greater than this value, it will force a resync")]
public float ResyncThreshold = 0.1f;
// private float LastSyncTime;
#endregion
#endregion
#region References
[SerializeField] private Animator animator;
[SerializeField] private Rigidbody m_rigidBody;
/// <summary>Reference for the Animator </summary>
public Animator Anim { get => animator; protected set => animator = value; } //Reference for the Animator
/// <summary>Reference for the rigidbody</summary>
public Rigidbody RB { get => m_rigidBody; protected set => m_rigidBody = value; } //Reference for the Animator
/// <summary>Root Gameobject for the Rider Character</summary>
public Transform RiderRoot { get => m_root; protected set => m_root = value; }
[SerializeField] private Transform m_root;
#region Bones
/// <summary>Spine Bone Transform</summary>
public Transform Spine { get; private set; }
// public Transform Hips { get; private set; }
public Transform Chest { get; private set; }
/// <summary>Ground Character Controller</summary>
public ISleepController GroundController { get; protected set; }
#endregion
/// <summary>Reference for all the colliders on this gameObject</summary>
protected List<Collider> colliders;
#endregion
#endregion
/// <summary> Store All colliders that are enabled and not Triggers </summary>
private void GetExtraColliders()
{
colliders = GetComponentsInChildren<Collider>().ToList();
var CleanCol = new List<Collider>();
foreach (var col in colliders)
{
if (col.enabled && !col.isTrigger)
CleanCol.Add(col);
}
colliders = new List<Collider>(CleanCol);
if (MainCollider)
{
Def_CollPropeties = new OverrideCapsuleCollider(MainCollider) { modify = (CapsuleModifier)(-1) };
colliders.Remove(MainCollider); //Remove the Main Collider from the Extra Colliders
}
}
public void Start()
{
if (RiderRoot == null) RiderRoot = transform.root;
if (Anim == null) Anim = this.FindComponent<Animator>();
if (RB == null) RB = this.FindComponent<Rigidbody>();
GroundController = GetComponent<ISleepController>(); //Find if there's a ground controller (ANIMAL CONTROLLER)
animatorParams = new Hashtable();
if (Anim)
{
//Store all the Animator parameters
foreach (AnimatorControllerParameter parameter in Anim.parameters)
animatorParams.Add(parameter.nameHash, parameter.name);
MountLayerIndex = Anim.GetLayerIndex(MountLayer);
if (MountLayerIndex != -1)
{
Anim.SetLayerWeight(MountLayerIndex, 1); //Just in case
Anim.Play("Empty", MountLayerIndex, 0);
}
Spine = Anim.GetBoneTransform(HumanBodyBones.Spine); //Get the Rider Spine transform
//Hips = Anim.GetBoneTransform(HumanBodyBones.Hips); //Get the Rider Hips transform
Chest = Anim.GetBoneTransform(HumanBodyBones.Chest); //Get the Rider Chest transform
Default_Anim_UpdateMode = Anim.updateMode; //Gets the Update Mode of the Animator to restore later when dismounted.
}
GetExtraColliders();
IsOnHorse = Mounted = false;
ForceLateUpdateLink = false;
SpeedMultiplier = 1f;
TargetSpeedMultiplier = 1f;
if ((int)LinkUpdate == 0 || !Parent)
LinkUpdate = UpdateMode.FixedUpdate | UpdateMode.LateUpdate;
FindStoredMount();
if (StartMounted.Value) Start_Mounted();
UpdateCanMountDismount();
}
void Update()
{
if ((LinkUpdate & UpdateMode.Update) == UpdateMode.Update) UpdateRiderTransform();
}
private void LateUpdate()
{
if ((LinkUpdate & UpdateMode.LateUpdate) == UpdateMode.LateUpdate || ForceLateUpdateLink) UpdateRiderTransform();
}
private void FixedUpdate()
{
if ((LinkUpdate & UpdateMode.FixedUpdate) == UpdateMode.FixedUpdate) UpdateRiderTransform();
}
/// <summary>Updates the Rider Position to the Mount Point</summary>
public virtual void UpdateRiderTransform()
{
if (IsRiding)
{
transform.position = Montura.MountPoint.position;
transform.rotation = Montura.MountPoint.rotation;
//Update the Mount Position/Rotation Also
MountRotation = transform.rotation;
MountPosition = transform.position;
}
}
/// <summary>Add the Mount Rotation and Position Modifications while Mounting Dismounting called y the animator</summary>
public virtual void Mount_TargetTransform()
{
transform.position = MountPosition;
transform.rotation = MountRotation;
}
void Debbuging(string value, string color = "white")
{
#if UNITY_EDITOR
if (debug) Debug.Log($"<b>{name}:<color={color}> [{value}] </color> </b>",this); //Debug
#endif
}
/// <summary>Set the Mount Index Value</summary>
internal void SetMountSide(int side) => SetAnimParameter(MountSideHash, side);
public virtual void MountAnimal()
{
if (!CanMount) return;
Debbuging("Mount Animal", "cyan");
if (!Montura.InstantMount) //If is instant Mount play it
{
Mounted = true; //Update MountSide Parameter In the Animator
SetMountSide(MountTrigger.MountID); //Update MountSide Parameter In the Animator
// Anim?.Play(MountTrigger.MountAnimation, MountLayerIndex); //Play the Mounting Animations
}
else
{
Anim?.Play(Montura.MountIdle, MountLayerIndex); //Ingore the Mounting Animations
Anim?.Update(0); //Update the Animator ????
Start_Mounting();
End_Mounting();
}
}
public virtual void DismountAnimal()
{
if (!CanDismount) return;
Debbuging("Dismount Animal", "cyan");
Montura.Mounted = Mounted = false; //Unmount the Animal
MountTrigger = GetDismountTrigger();
SetMountSide(MountTrigger.DismountID); //Update MountSide Parameter In the Animator
if (Montura.InstantDismount) //Use for Instant Dismount
{
Anim.Play(Hash.Empty, MountLayerIndex);
SetMountSide(0); //Update MountSide Parameter In the Animator
Start_Dismounting();
var MT = MountTrigger;
End_Dismounting();
RiderRoot.position = MT.transform.position + (MT.transform.forward * -0.2f); //Move the rider directly to the mounttrigger
RiderRoot.rotation = MT.transform.rotation;
}
}
/// <summary>Return the Correct Mount Trigger using the DismountType</summary>
protected MountTriggers GetDismountTrigger()
{
switch (DismountType)
{
case DismountType.Last:
if (MountTrigger == null) MountTrigger = Montura.MountTriggers[UnityEngine.Random.Range(0, Montura.MountTriggers.Count)];
return MountTrigger;
case DismountType.Input:
var MoveInput = Montura.Animal.MovementAxis;
MountTriggers close = MountTrigger;
float Diference = Vector3.Angle(MountTrigger.Direction, MoveInput);
foreach (var mt in Montura.MountTriggers)
{
var newDiff = Vector3.Angle(mt.Direction, MoveInput);
if (newDiff < Diference)
{
Diference = newDiff;
close = mt;
}
}
return close;
case DismountType.Random:
int Randomindex = UnityEngine.Random.Range(0, Montura.MountTriggers.Count);
return Montura.MountTriggers[Randomindex];
default:
return MountTrigger;
}
}
private void FindStoredMount()
{
MountStored = m_MountStored.Value != null ? m_MountStored.Value.FindComponent<Mount>() : null;
}
public virtual void Set_StoredMount(GameObject newMount)
{
m_MountStored.Value = newMount;
FindStoredMount();
}
public virtual void ClearStoredMount()
{
m_MountStored.Value = null;
MountStored = null;
}
/// <summary>Set all the correct atributes and variables to Start Mounted on the next frame</summary>
public void Start_Mounted()
{
if (MountStored != null && m_MountStored.Value.activeSelf)
{
if (m_MountStored.Value.IsPrefab()) //If the Stored Mount is a Prefab Instantiate it at the back of the Rider
m_MountStored.Value = Instantiate(m_MountStored.Value, transform.position - transform.forward, Quaternion.identity);
Montura = MountStored; //Set on the Rider which mount is using
Debbuging("Start Mounted", "green");
StopMountAI();
Montura.Rider = this; //Set on the Mount which Rider is using it
if (MountTrigger == null)
MountTrigger = Montura.transform.GetComponentInChildren<MountTriggers>(); //Save the first Mount trigger you found
Start_Mounting();
End_Mounting();
Anim?.Play(Montura.MountIdle, MountLayerIndex); //Play Mount Idle Animation Directly
Montura.Mounted = Mounted = true; //Send to the animalMount that mounted is active
OnAlreadyMounted.Invoke();
UpdateRiderTransform();
}
else
{
Debug.Log("There's no stored Mount or the Stored Mount GameObject has no Mount component");
}
}
/// <summary>Force the Rider to Dismount</summary>
public virtual void ForceDismount()
{
Debbuging("Force Dismount", "green");
DisconnectWithMount();
Anim?.Play(EmptyHash, MountLayerIndex);
SetMountSide(0); //Update MountSide Parameter In the Animator
Start_Dismounting();
End_Dismounting();
}
/// <summary>CallBack at the Start of the Mount Animations</summary>
internal virtual void Start_Mounting()
{
Montura.StartMounting(this); //Sync Mounted Values in Animal and Rider
IsOnHorse = false;
Mounted = true; //Sync Mounted Values in Animal and Rider
MountInput = Montura.MountInput; //Get the Input of the Mount
if (GroundController != null) GroundController.Sleep = true; //IF there's an Animal Controller send it to Sleep.
StopMountAI();
if (RB) //Deactivate stuffs for the Rider's Rigid Body
{
RB.useGravity = false;
DefaultConstraints = RB.constraints; //Store the Contraints before mounting
DefaultCollision = RB.collisionDetectionMode; //Store the Contraints before mounting
RB.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
RB.constraints = RigidbodyConstraints.FreezeAll;
RB.isKinematic = true;
}
ToogleColliders(false); //Deactivate All Colliders on the Rider IMPORTANT ... or the Rider will try to push the animal
ToggleCall = false; //Set the Call to Stop Animal
CallAnimal(false); //If is there an animal following us stop him
m_MountStored.Value = Montura.Animal.gameObject; //Store the last animal you mounted
MountStored = Montura;
if (Parent) RiderRoot.parent = Montura.MountPoint;
if (!MountTrigger)
MountTrigger = Montura.GetComponentInChildren<MountTriggers>(); //If null add the first mount trigger founded
if (DisableComponents)
ToggleComponents(false); //Disable all Monobehaviours breaking the Riding System
OnStartMounting.Invoke(); //Invoke UnityEvent for Start Mounting
UpdateCanMountDismount();
Debbuging("Start Mounting", "green");
}
/// <summary>CallBack at the End of the Mount Animations </summary>
public virtual void End_Mounting()
{
IsOnHorse = true; //Sync Mounted Values in Animal and Rider again Double Check
Montura.End_Mounting();
if (Parent)
{
RiderRoot.localPosition = Vector3.zero; //Reset Position when PARENTED
RiderRoot.localRotation = Quaternion.identity; //Reset Rotation when PARENTED
}
if (Anim)
{
Anim.updateMode = Montura.Anim.updateMode; //Use the Same UpdateMode from the Animal
SetAnimParameter(Montura.Animal.hash_Grounded, Montura.Animal.Grounded);
SetAnimParameter(Montura.Animal.hash_State, Montura.Animal.ActiveStateID.ID);
SetAnimParameter(Montura.Animal.hash_Mode, Montura.Animal.ModeAbility);
SetAnimParameter(Montura.Animal.hash_ModeStatus, Montura.Animal.ModeStatus);
SetAnimParameter(Montura.Animal.hash_Stance, Montura.ID);
Anim.speed = Montura.Anim.speed; //In case the Mount is not using Speed Modifiers
ConnectWithMount();
}
OnEndMounting.Invoke();
UpdateCanMountDismount();
SendMessage("SetIgnoreTransform", Montura.Animal.transform, SendMessageOptions.DontRequireReceiver);
Debbuging("End Mounting", "green");
}
/// <summary> CallBack at the Start of the Dismount Animations</summary>
public virtual void Start_Dismounting()
{
RiderRoot.parent = null; //Unparent! Important!
Montura.Start_Dismounting();
Mounted = false;
if (Anim)
{
Anim.updateMode = Default_Anim_UpdateMode; //Restore Update mode to its original
SetAnimParameter(Montura.Animal.hash_Stance, 0); //Reset the Stance.
SetAnimParameter(Montura.Animal.hash_Mode, 0);
SetAnimParameter(Montura.Animal.hash_ModeStatus, 0);
DisconnectWithMount();
Anim.speed = 1f;
}
OnStartDismounting.Invoke();
UpdateCanMountDismount();
SendMessage("ClearIgnoreTransform", SendMessageOptions.DontRequireReceiver); //Clear the Ingore Transform on the Weapon Manager
Debbuging("Start Dismounting", "green");
}
/// <summary>CallBack at the End of the Dismount Animations</summary>
public virtual void End_Dismounting()
{
IsOnHorse = false; //Is no longer on the Animal
if (Montura) Montura.EndDismounting(); //Disable Montura Logic
Montura = null; //Reset the Montura
MountTrigger = null; //Reset the Active Mount Trigger
ToggleCall = false; //Reset the Call Animal
if (RB) //Reactivate stuffs for the Rider's Rigid Body
{
RB.isKinematic = false;
RB.useGravity = true;
RB.constraints = DefaultConstraints;
RB.collisionDetectionMode = DefaultCollision;
}
if (Anim)
{
Anim.speed = 1; //Reset AnimatorSpeed
MTools.ResetFloatParameters(Anim);
}
//Reset the Up Vector; ****IMPORTANT
RiderRoot.rotation = Quaternion.FromToRotation(RiderRoot.up, -Gravity.Value) * RiderRoot.rotation;
ToogleColliders(true); //Enabled Rider Colliders
if (DisableComponents) ToggleComponents(true); //Enable all Monobehaviours breaking the Mount System
OnEndDismounting.Invoke(); //Invoke UnityEvent when is off Animal
UpdateCanMountDismount();
if (GroundController != null)
{
GroundController.Sleep = false;
SendMessage("ResetInputAxis", SendMessageOptions.DontRequireReceiver); //Little Hack for the new Enchance Inputs
}
Debbuging("End Dismounting", "green");
}
/// <summary>Connect the Animal Events from the Riders Methods (Grounded, State, Mode)</summary>
protected virtual void ConnectWithMount()
{
Montura.Animal.SetBoolParameter += SetAnimParameter;
Montura.Animal.SetIntParameter += SetAnimParameter;
Montura.Animal.SetFloatParameter += SetAnimParameter;
Montura.Animal.SetTriggerParameter += SetAnimParameter;
if (ReSync) Montura.Animal.StateCycle += Animators_Locomotion_ReSync;
}
/// <summary>Disconnect the Animal Events from the Riders Methods (Grounded, State, Mode)</summary>
protected void DisconnectWithMount()
{
Montura.Animal.SetBoolParameter -= SetAnimParameter;
Montura.Animal.SetIntParameter -= SetAnimParameter;
Montura.Animal.SetFloatParameter -= SetAnimParameter;
if (ReSync) Montura.Animal.StateCycle -= Animators_Locomotion_ReSync;
}
internal virtual void MountTriggerEnter(Mount mount, MountTriggers mountTrigger)
{
Montura = mount; //Set to Mount on this Rider
MountTrigger = mountTrigger; //Send the side transform to mount
OnFindMount.Invoke(mount.Animal.gameObject); //Invoke Found Mount
if (!mountTrigger.AutoMount)
Montura.OnCanBeMounted.Invoke(Montura.CanBeMountedByState); //Invoke Can Be mounted to true ???
Montura.NearbyRider = this;
UpdateCanMountDismount();
}
internal virtual void MountTriggerExit()
{
if (Montura)
Montura.ExitMountTrigger();
MountTrigger = null;
Montura = null;
MountInput = null;
OnFindMount.Invoke(null); ////Invoke Null Mount
UpdateCanMountDismount();
}
/// <summary> Update the values Can Mount Can Dismount </summary>
internal virtual void UpdateCanMountDismount()
{
CanMount = Montura && !Mounted && !IsOnHorse && Montura.CanBeMountedByState;
OnCanMount.Invoke(CanMount);
bool canDismount = IsRiding && Montura.CanBeDismountedByState;
CanDismount = canDismount;
OnCanDismount.Invoke(CanDismount);
bool canCallAnimal = !Montura && !Mounted && !IsOnHorse && m_MountStored.Value != null;
CanCallAnimal = canCallAnimal;
CanCallMount.Invoke(CanCallAnimal);
}
/// <summary> Syncronize the Animal/Rider animations if Rider loose sync with the animal on the locomotion state </summary>
protected virtual void Animators_Locomotion_ReSync(int CurrentState)
{
if (!Anim || MountLayerIndex == -1) return;
if (Montura.Animal.Stance != 0) return; //Skip if the we are not on the default stance
if (Montura.ID != 0) return; // if is not the Horse (Wagon do not sync )
if (Anim.IsInTransition(MountLayerIndex) || Montura.Anim.IsInTransition(0)) return; //Do not Resync when is
//Search for syncron the locomotion state on the animal. resync on Locomotion, Fly, Swim
if (MTools.CompareOR(CurrentState, StateEnum.Locomotion, StateEnum.Fly, StateEnum.Swim))
{
var HorseStateInfo = Montura.Animal.Anim.GetCurrentAnimatorStateInfo(0);
var RiderStateInfo = Anim.GetCurrentAnimatorStateInfo(MountLayerIndex);
HorseNormalizedTime = HorseStateInfo.normalizedTime; //Get the normalized time from the Rider
RiderNormalizedTime = RiderStateInfo.normalizedTime; //Get the normalized time from the Horse
var Diff = Mathf.Abs(HorseNormalizedTime - RiderNormalizedTime); //Calculate the difference on the syncronization
if (Diff >= ResyncThreshold) //Checking if the animal and the rider are unsync by the threshold
{
Anim.CrossFade(RiderStateInfo.fullPathHash, 0.2f, MountLayerIndex, HorseNormalizedTime); //Normalized with blend
if (debug) Debug.Log($"Re-sync [Mount:{HorseNormalizedTime:F3}] [Rider:{RiderNormalizedTime:F3}]. [Diff: {Diff:F3}]");
}
}
else
{
RiderNormalizedTime = HorseNormalizedTime = 0;
}
}
/// <summary> If the Animal has a IMountAI component it can be called</summary>
public virtual void CallAnimal(bool call)
{
if (CanCallAnimal)
{
ToggleCall = call;
if (m_MountStored.Value.IsPrefab()) //Insantiate a new Horse Behind the Rider...(Weird Option but it works for now)
{
//If there's an old Mount... Stop it
if (MountStored)
{
Debbuging($"Old Stored Mount Stop {MountStored.Animal.name}", "yellow");
MountStored.AI?.ClearTarget();
MountStored.AI?.Stop();
}
MountStored = m_MountStored.Value.FindComponent<Mount>();
if (MountStored)
{
Debbuging($"Mount Instantiated! [{MountStored.Animal.name}]", "yellow");
}
else
{
Debbuging($"Stored mount does not contain any Mount Component.","yellow");
return;
}
var InsMount = Instantiate(m_MountStored.Value, transform.position - (transform.forward * 4), Quaternion.identity);
InsMount.gameObject.name = InsMount.gameObject.name.Replace("(Clone)", "");
m_MountStored.UseConstant = true;
m_MountStored.Value = InsMount;
MountStored = InsMount.FindComponent<Mount>();
ToggleCall = true;
}
else
{
if (!MountStored)
{
MountStored = m_MountStored.Value.FindComponent<Mount>();
if (!MountStored)
{
Debbuging($"Stored mount does not contain any Mount Component."); //Debug
return;
}
}
}
Debbuging($"Calling Animal: ToggleCall = <{ToggleCall}>"); //Debug
if (MountStored.AI != null && MountStored.AI.Active)
{
if (ToggleCall)
{
MountStored.AI.SetActive(true);
MountStored.AI.SetTarget(RiderRoot,true); //Set the Rider as the Target to follow
MountStored.AI.Move(); //Move the Animal
if (CallAnimalA)
RiderAudio.PlayOneShot(CallAnimalA);
}
else
{
StopMountAI();
if (StopAnimalA)
RiderAudio.PlayOneShot(StopAnimalA);
}
}
}
}
public virtual void StopMountAI()
{
if (MountStored != null && MountStored.AI != null)
{
MountStored.AI.Stop();
MountStored.AI.ClearTarget();
}
}
public virtual void CallAnimalToggle()
{
if (CanCallAnimal)
{
ToggleCall ^= true;
CallAnimal(ToggleCall);
}
}
/// <summary>Enable/Disable The Colliders in this gameobject </summary>
protected virtual void ToogleColliders(bool active)
{
MountingCollider(!active); //Reestore Collider
foreach (var col in colliders) col.enabled = active;
}
/// <summary> Create a collider from hip to chest to check hits when is on the horse </summary>
private void MountingCollider(bool Mounting)
{
if (MainCollider && MountCollider)
{
if (Mounting)
MountCollider.Modify(MainCollider); //Modify
else
Def_CollPropeties.Modify(MainCollider); //Restore
}
}
/// <summary>Toogle the MonoBehaviour Components Attached to this game Objects but the Riders Scripts </summary>
protected virtual void ToggleComponents(bool enabled)
{
if (DisableList.Length == 0)
{
foreach (var component in AllComponents)
{
if (component is MRider) continue; //Do not Disable or enable Rider
component.enabled = enabled;
}
}
else
{
foreach (var component in DisableList)
{
if (component != null) component.enabled = enabled;
}
}
}
#region Set Animator Parameters
/// <summary>Set a Int on the Animator</summary>
public void SetAnimParameter(int hash, int value) { if (Anim && HasParam(hash)) Anim.SetInteger(hash, value); }
/// <summary>Set a float on the Animator</summary>
public void SetAnimParameter(int hash, float value) { if (Anim && HasParam(hash)) Anim.SetFloat(hash, value); }
/// <summary>Set a Bool on the Animator</summary>
public void SetAnimParameter(int hash, bool value) { if (Anim && HasParam(hash)) Anim.SetBool(hash, value); }
/// <summary>Set a Trigger on the Animator</summary>
public void SetAnimParameter(int hash) { if (Anim && HasParam(hash)) Anim.SetTrigger(hash); }
#endregion
private bool HasParam(int hash) => animatorParams.ContainsKey(hash);
#region Link Animator
protected virtual void SyncAnimator()
{
MAnimal animal = Montura.Animal;
SetAnimParameter(animal.hash_Vertical, animal.VerticalSmooth);
SetAnimParameter(animal.hash_Horizontal, animal.HorizontalSmooth);
SetAnimParameter(animal.hash_Slope, animal.SlopeNormalized);
SetAnimParameter(animal.hash_Grounded, animal.Grounded);
SetAnimParameter(animal.hash_ModeStatus, animal.ModeStatus);
SetAnimParameter(animal.hash_StateFloat, animal.State_Float);
if (!Montura.UseSpeedModifiers) SpeedMultiplier = animal.SpeedMultiplier; //In case the Mount is not using Speed Modifiers
if (Anim) Anim.speed = Montura.Anim.speed; //In case the Mount is not using Speed Modifiers
SpeedMultiplier = Mathf.MoveTowards(SpeedMultiplier, TargetSpeedMultiplier, Time.deltaTime * 5f);
SetAnimParameter(animal.hash_SpeedMultiplier, SpeedMultiplier);
}
#endregion
/// <summary> Checks and Execute without Input if the Rider can Mount, Dismount or Call an Animal </summary>
public virtual void CheckMountDismount()
{
UpdateCanMountDismount();
if (CanMount) MountAnimal(); //if are near an animal and we are not already on an animal//Run mounting Animations
else if (CanDismount) DismountAnimal(); //if we are already mounted and the animal is not moving (Mounted && IsOnHorse && Montura.CanDismount)//Run Dismounting Animations
else if (CanCallAnimal) CallAnimalToggle(); //if there is no horse near, call the animal stored
}
/// <summary>IK Feet Adjustment while mounting</summary>
void OnAnimatorIK()
{
if (Anim == null) return; //If there's no animator skip
IKFeet();
IK_Reins();
SolveStraightMount();
}
private void IK_Reins()
{
if (IsRiding)
{
if (Montura && LeftHand && RightHand)
{
var New_L_ReinPos = Montura.Rider.LeftHand.TransformPoint(LeftReinOffset);
var New_R_ReinPos = Montura.Rider.RightHand.TransformPoint(RightReinOffset);
if (!freeLeftHand && !freeRightHand) //When Both hands are free
{
Montura.ResetLeftRein();
Montura.ResetRightRein();
return;
}
if (Montura.LeftRein)
{
if (freeLeftHand)
{
Montura.LeftRein.position = New_L_ReinPos; //Put it in the middle o the left hand
}
else
{
if (freeRightHand)
{
Montura.LeftRein.position = New_R_ReinPos; //if the right hand is holding a weapon put the right rein to the Right hand
}
}
}
if (Montura.RightRein)
{
if (freeRightHand)
{
Montura.RightRein.position = New_R_ReinPos; //Put it in the middle o the RIGHT hand
}
else
{
if (freeLeftHand)
{
Montura.RightRein.position = New_L_ReinPos; //if the right hand is holding a weapon put the right rein to the Left hand
}
}
}
}
}
}
/// <summary>Is the Rider Aiming</summary>
public bool IsAiming { get; set; }
private void SolveStraightMount()
{
if (IsRiding && !IsAiming) //AIM IS IMPORTANT!!! CANNOT HAVE STRAIGHT SPINE WHILE AIMING
{
if (Montura.StraightSpine)
{
SP_Weight = Mathf.MoveTowards(SP_Weight, Montura.StraightSpine ? 1 : 0, Montura.Animal.DeltaTime * Montura.smoothSM / 2);
}
else
{
SP_Weight = Mathf.MoveTowards(SP_Weight, 0, Montura.Animal.DeltaTime * Montura.smoothSM / 2);
}
if (SP_Weight != 0)
{
//if (Montura.MountBase)
//{
// var targetRot = Quaternion.FromToRotation(Montura.MountBase.up, Montura.Animal.UpVector) * Montura.MountBase.rotation;
// Montura.MountBase.rotation = Quaternion.Lerp(Montura.MountBase.rotation, targetRot, SP_Weight);
//}
Anim.SetLookAtPosition(Montura.MonturaSpineOffset);
Anim.SetLookAtWeight(SP_Weight, 0.6f, 1);
}
}
}
private void IKFeet()
{
if (Montura && Montura.HasIKFeet)
{
//linking the weights to the animator
if (IsMountingDismounting)
{
L_IKFootWeight = 1f;
R_IKFootWeight = 1f;
if (IsMounting || IsDismounting)
{
L_IKFootWeight = Anim.GetFloat(IKLeftFootHash);
R_IKFootWeight = Anim.GetFloat(IKRightFootHash);
}
//setting the weight
Anim.SetIKPositionWeight(AvatarIKGoal.LeftFoot, L_IKFootWeight);
Anim.SetIKPositionWeight(AvatarIKGoal.RightFoot, R_IKFootWeight);
Anim.SetIKHintPositionWeight(AvatarIKHint.LeftKnee, L_IKFootWeight);
Anim.SetIKHintPositionWeight(AvatarIKHint.RightKnee, R_IKFootWeight);
//Knees
Anim.SetIKRotationWeight(AvatarIKGoal.LeftFoot, L_IKFootWeight);
Anim.SetIKRotationWeight(AvatarIKGoal.RightFoot, R_IKFootWeight);
//Set the IK Positions
Anim.SetIKPosition(AvatarIKGoal.LeftFoot, Montura.FootLeftIK.position);
Anim.SetIKPosition(AvatarIKGoal.RightFoot, Montura.FootRightIK.position);
//Knees
Anim.SetIKHintPosition(AvatarIKHint.LeftKnee, Montura.KneeLeftIK.position); //Position
Anim.SetIKHintPosition(AvatarIKHint.RightKnee, Montura.KneeRightIK.position); //Position
Anim.SetIKHintPositionWeight(AvatarIKHint.LeftKnee, L_IKFootWeight); //Weight
Anim.SetIKHintPositionWeight(AvatarIKHint.RightKnee, R_IKFootWeight); //Weight
//setting the IK Rotations of the Feet
Anim.SetIKRotation(AvatarIKGoal.LeftFoot, Montura.FootLeftIK.rotation);
Anim.SetIKRotation(AvatarIKGoal.RightFoot, Montura.FootRightIK.rotation);
}
else
{
Anim.SetIKPositionWeight(AvatarIKGoal.LeftFoot, 0f);
Anim.SetIKPositionWeight(AvatarIKGoal.RightFoot, 0f);
Anim.SetIKRotationWeight(AvatarIKGoal.LeftFoot, 0f);
Anim.SetIKRotationWeight(AvatarIKGoal.RightFoot, 0f);
}
}
}
/// <summary>Used for listening Message behaviour from the Animator</summary>
public virtual bool OnAnimatorBehaviourMessage(string message, object value) => this.InvokeWithParams(message, value);
/// <summary> Enable Disable the Input for the Mount</summary>
public virtual void EnableMountInput(bool value) => Montura?.EnableInput(value);
/// <summary> Enable Disable an Input for the Mount</summary>
public void DisableMountInput(string input) => MountInput?.DisableInput(input);
/// <summary> Enable Disable an Input for the Mount</summary>
public void EnableMountInput(string input) => MountInput?.EnableInput(input);
#region IKREINS
/// <summary>Free the Right Hand (True :The reins will not be on the Hand)</summary>
public void FreeRightHand(bool value)
{
if (Montura != null)
{
freeRightHand = !value;
if (freeRightHand) Montura.ResetRightRein();
}
}
/// <summary>Free the Left Hand (True :The reins will not be on the Hand)</summary>
public void FreeLeftHand(bool value)
{
if (Montura != null)
{
freeLeftHand = !value;
if (freeLeftHand) Montura.ResetLeftRein();
}
}
/// <summary>No Weapons is on the Hands so put the Reins on the Hands</summary>
public void FreeBothHands()
{
FreeRightHand(false);
FreeLeftHand(false);
}
public void WeaponInHands()
{
FreeRightHand(true);
FreeLeftHand(true);
}
#endregion
#if UNITY_EDITOR
private void OnValidate()
{
if (MountCollider == null)
MountCollider = Resources.Load<CapsuleColliderPreset>("Mount_Capsule");
}
private void Reset()
{
animator = this.FindComponent<Animator>();
RB = this.FindComponent<Rigidbody>();
RiderRoot = transform; //IMPORTANT
MainCollider = GetComponent<CapsuleCollider>();
MountCollider = Resources.Load<CapsuleColliderPreset>("Mount_Capsule");
if (MainCollider)
Def_CollPropeties = new OverrideCapsuleCollider(MainCollider) { modify = (CapsuleModifier)(-1) };
BoolVar CanMountV = MTools.GetInstance<BoolVar>("Can Mount");
BoolVar CanDismountV = MTools.GetInstance<BoolVar>("Can Dismount");
BoolVar CanCallMountV = MTools.GetInstance<BoolVar>("Can Call Mount");
MEvent CanMountE = MTools.GetInstance<MEvent>("Rider Can Mount");
MEvent CanDismountE = MTools.GetInstance<MEvent>("Rider Can Dismount");
MEvent RiderMountUI = MTools.GetInstance<MEvent>("Rider Mount UI");
MEvent CanCallMountE = MTools.GetInstance<MEvent>("Rider Can Call Mount");
MEvent RiderisRiding = MTools.GetInstance<MEvent>("Rider is Riding");
MEvent SetCameraSettings = MTools.GetInstance<MEvent>("Set Camera Settings");
BoolVar RCWeaponInput = MTools.GetInstance<BoolVar>("RC Weapon Input");
m_CanCallAnimal.Variable = CanCallMountV;
m_CanCallAnimal.UseConstant = false;
m_CanMount.Variable = CanMountV;
m_CanMount.UseConstant = false;
m_CanDismount.Variable = CanDismountV;
m_CanDismount.UseConstant = false;
OnCanMount = new BoolEvent();
OnCanDismount = new BoolEvent();
CanCallMount = new BoolEvent();
OnStartMounting = new UnityEvent();
OnEndMounting = new UnityEvent();
OnStartMounting = new UnityEvent();
OnStartDismounting = new UnityEvent();
// if (CanMountV != null) UnityEditor.Events.UnityEventTools.AddPersistentListener(OnCanMount, CanMountV.SetValue);
if (CanMountE != null) UnityEditor.Events.UnityEventTools.AddPersistentListener(OnCanMount, CanMountE.Invoke);
// if (CanDismountV != null) UnityEditor.Events.UnityEventTools.AddPersistentListener(OnCanDismount, CanDismountV.SetValue);
if (CanDismountE != null) UnityEditor.Events.UnityEventTools.AddPersistentListener(OnCanDismount, CanDismountE.Invoke);
// if (CanCallMountV != null) UnityEditor.Events.UnityEventTools.AddPersistentListener(CanCallMount, CanCallMountV.SetValue);
if (CanCallMountE != null) UnityEditor.Events.UnityEventTools.AddPersistentListener(CanCallMount, CanCallMountE.Invoke);
if (RiderMountUI != null) UnityEditor.Events.UnityEventTools.AddBoolPersistentListener(OnStartMounting, RiderMountUI.Invoke, false);
if (RiderisRiding != null)
{
UnityEditor.Events.UnityEventTools.AddBoolPersistentListener(OnEndMounting, RiderisRiding.Invoke, true);
UnityEditor.Events.UnityEventTools.AddBoolPersistentListener(OnStartDismounting, RiderisRiding.Invoke, false);
}
if (SetCameraSettings != null) UnityEditor.Events.UnityEventTools.AddObjectPersistentListener<Transform>(OnStartDismounting, SetCameraSettings.Invoke, transform);
if (RCWeaponInput != null)
{
UnityEditor.Events.UnityEventTools.AddBoolPersistentListener(OnStartDismounting, RCWeaponInput.SetValue, false);
UnityEditor.Events.UnityEventTools.AddBoolPersistentListener(OnEndMounting, RCWeaponInput.SetValue, true);
}
var malbersinput = GetComponent<MalbersInput>();
if (malbersinput)
{
UnityEditor.Events.UnityEventTools.AddBoolPersistentListener(OnStartMounting, malbersinput.SetMoveCharacter, false);
UnityEditor.Events.UnityEventTools.AddBoolPersistentListener(OnEndDismounting, malbersinput.SetMoveCharacter, true);
}
}
///Editor Variables
[HideInInspector] public int Editor_Tabs1;
[ContextMenu("Create Mount Inputs")]
void ConnectToInput()
{
MInput input = GetComponent<MInput>();
if (input == null) { input = gameObject.AddComponent<MInput>(); }
#region Mount Input
var mountInput = input.FindInput("Mount");
if (mountInput == null)
{
mountInput = new InputRow("Mount", "Mount", KeyCode.F, InputButton.Down, InputType.Key);
input.inputs.Add(mountInput);
//mountInput.active.Variable = MTools.GetInstance<BoolVar>("Can Mount");
//mountInput.active.UseConstant = false;
//Connect the Dismount Input
UnityEditor.Events.UnityEventTools.AddStringPersistentListener(OnStartMounting, input.DisableInput, mountInput.Name);
UnityEditor.Events.UnityEventTools.AddStringPersistentListener(OnEndDismounting, input.EnableInput, mountInput.Name);
UnityEditor.Events.UnityEventTools.AddPersistentListener(mountInput.OnInputDown, MountAnimal);
Debug.Log("<B>Mount</B> Input created and connected to Rider.MountAnimal");
}
#endregion
#region Dismount Input
var DismountInput = input.FindInput("Dismount");
if (DismountInput == null)
{
DismountInput = new InputRow("Dismount", "Dismount", KeyCode.F, InputButton.LongPress, InputType.Key);
DismountInput.LongPressTime = 0.2f;
input.inputs.Add(DismountInput);
DismountInput.Active = false; //Disable
//Connect the Dismount Input
UnityEditor.Events.UnityEventTools.AddStringPersistentListener(OnEndMounting, input.EnableInput, DismountInput.Name);
UnityEditor.Events.UnityEventTools.AddStringPersistentListener(OnStartDismounting, input.DisableInput, DismountInput.Name);
UnityEditor.Events.UnityEventTools.AddPersistentListener(DismountInput.OnLongPress, DismountAnimal); //Connect the Logic to the Dismount
var RiderDismountUI = MTools.GetInstance<MEvent>("Rider Dismount UI");
UnityEditor.Events.UnityEventTools.AddPersistentListener(DismountInput.OnLongPress, DismountAnimal);
if (RiderDismountUI != null)
{
UnityEditor.Events.UnityEventTools.AddPersistentListener(DismountInput.OnLongPress, RiderDismountUI.Invoke);
UnityEditor.Events.UnityEventTools.AddPersistentListener(DismountInput.OnPressedNormalized, RiderDismountUI.Invoke);
UnityEditor.Events.UnityEventTools.AddPersistentListener(DismountInput.OnInputUp, RiderDismountUI.Invoke);
UnityEditor.Events.UnityEventTools.AddIntPersistentListener(DismountInput.OnInputDown, RiderDismountUI.Invoke, 0);
}
Debug.Log("<B>Dismount</B> Input created and connected to Rider.DismountAnimal");
}
#endregion
#region CanCallMount Input
var CanCallMount = input.FindInput("Call Mount");
if (CanCallMount == null)
{
CanCallMount = new InputRow("Call Mount", "Call Mount", KeyCode.F, InputButton.Down, InputType.Key);
input.inputs.Add(CanCallMount);
//CanCallMount.active.Variable = MTools.GetInstance<BoolVar>("Can Call Mount");
//CanCallMount.active.UseConstant = false;
UnityEditor.Events.UnityEventTools.AddPersistentListener(CanCallMount.OnInputDown, CallAnimalToggle);
Debug.Log("<B>Call Mount</B> Input created and connected to Rider.CallAnimalToggle");
}
#endregion
UnityEditor.EditorUtility.SetDirty(this);
UnityEditor.EditorUtility.SetDirty(input);
}
[ContextMenu("Create Event Listeners")]
void CreateEventListeners()
{
MEvent RiderSetMount = MTools.GetInstance<MEvent>("Rider Set Mount");
MEvent RiderSetDismount = MTools.GetInstance<MEvent>("Rider Set Dismount");
MEventListener listener = GetComponent<MEventListener>();
if (listener == null)
{
listener = gameObject.AddComponent<MEventListener>();
}
if (listener.Events == null) listener.Events = new List<MEventItemListener>();
if (listener.Events.Find(item => item.Event == RiderSetMount) == null)
{
var item = new MEventItemListener()
{
Event = RiderSetMount,
useVoid = true,
};
UnityEditor.Events.UnityEventTools.AddPersistentListener(item.Response, MountAnimal);
listener.Events.Add(item);
Debug.Log("<B>Rider Set Mount</B> Added to the Event Listeners");
}
if (listener.Events.Find(item => item.Event == RiderSetDismount) == null)
{
var item = new MEventItemListener()
{
Event = RiderSetDismount,
useVoid = true,
};
UnityEditor.Events.UnityEventTools.AddPersistentListener(item.Response, DismountAnimal);
listener.Events.Add(item);
Debug.Log("<B>Rider Set Dismount</B> Added to the Event Listeners");
}
}
private void FindRHand()
{
if (animator != null && animator.avatar.isHuman)
{
RightHand = animator.GetBoneTransform(HumanBodyBones.RightHand);
SetDirty();
}
}
private void FindLHand()
{
if (animator != null && animator.avatar.isHuman)
{
LeftHand = animator.GetBoneTransform(HumanBodyBones.LeftHand);
SetDirty();
}
}
void SetDirty()
{
#if UNITY_EDITOR
EditorUtility.SetDirty(this);
#endif
}
void OnDrawGizmos()
{
if (Anim && Mounted && Montura.debug && Montura.Animal.ActiveStateID == StateEnum.Locomotion)
{
Transform head = Anim.GetBoneTransform(HumanBodyBones.Head);
Gizmos.color = (int)RiderNormalizedTime % 2 == 0 ? Color.red : Color.white;
Gizmos.DrawSphere((head.position - transform.root.right * 0.2f), 0.05f);
Gizmos.color = (int)HorseNormalizedTime % 2 == 0 ? new Color(0.11f, 1f, 0.25f) : Color.white;
Gizmos.DrawSphere((head.position + transform.root.right * 0.2f), 0.05f);
UnityEditor.Handles.color = Color.white;
UnityEditor.Handles.Label(head.position + transform.up * 0.5f, "Sync Status");
}
}
#endif
}
#region INSPECTOR
#if UNITY_EDITOR
[CustomEditor(typeof(MRider), true)]
public class MRiderEd : Editor
{
public readonly string version = "Riding System - HAP [v4.3.3]";
protected MRider M;
protected SerializedProperty
MountStored, StartMounted, Parent, animator, m_rigidBody, m_root, gravity, ReSync, ResyncThreshold,
MountLayer, LayerPath, OnCanMount, OnCanDismount, OnStartMounting, OnEndMounting, m_CanMount, m_CanDismount, m_CanCallAnimal,
OnStartDismounting, OnEndDismounting, OnFindMount, CanCallMount, OnAlreadyMounted, DisableList, MainCollider,
CallAnimalA, StopAnimalA, RiderAudio, MountCollider,
LinkUpdate, debug, AlingMountTrigger, DismountType, DisableComponents, Editor_Tabs1,
LeftHand, RightHand, RightReinOffset, LeftReinOffset
;
protected virtual void OnEnable()
{
M = (MRider)target;
MountStored = serializedObject.FindProperty("m_MountStored");
MainCollider = serializedObject.FindProperty("MainCollider");
MountCollider = serializedObject.FindProperty("MountCollider");
RightReinOffset = serializedObject.FindProperty("RightReinOffset");
LeftReinOffset = serializedObject.FindProperty("LeftReinOffset");
ReSync = serializedObject.FindProperty("ReSync");
ResyncThreshold = serializedObject.FindProperty("ResyncThreshold");
m_CanMount = serializedObject.FindProperty("m_CanMount");
m_CanDismount = serializedObject.FindProperty("m_CanDismount");
m_CanCallAnimal = serializedObject.FindProperty("m_CanCallAnimal");
gravity = serializedObject.FindProperty("Gravity");
animator = serializedObject.FindProperty("animator");
m_rigidBody = serializedObject.FindProperty("m_rigidBody");
m_root = serializedObject.FindProperty("m_root");
StartMounted = serializedObject.FindProperty("StartMounted");
Parent = serializedObject.FindProperty("Parent");
MountLayer = serializedObject.FindProperty("MountLayer");
LayerPath = serializedObject.FindProperty("LayerPath");
Editor_Tabs1 = serializedObject.FindProperty("Editor_Tabs1");
OnCanMount = serializedObject.FindProperty("OnCanMount");
OnCanDismount = serializedObject.FindProperty("OnCanDismount");
OnStartMounting = serializedObject.FindProperty("OnStartMounting");
OnEndMounting = serializedObject.FindProperty("OnEndMounting");
OnStartDismounting = serializedObject.FindProperty("OnStartDismounting");
OnEndDismounting = serializedObject.FindProperty("OnEndDismounting");
OnFindMount = serializedObject.FindProperty("OnFindMount");
CanCallMount = serializedObject.FindProperty("CanCallMount");
OnAlreadyMounted = serializedObject.FindProperty("OnAlreadyMounted");
CallAnimalA = serializedObject.FindProperty("CallAnimalA");
StopAnimalA = serializedObject.FindProperty("StopAnimalA");
RiderAudio = serializedObject.FindProperty("RiderAudio");
RightHand = serializedObject.FindProperty("RightHand");
LeftHand = serializedObject.FindProperty("LeftHand");
LinkUpdate = serializedObject.FindProperty("LinkUpdate");
debug = serializedObject.FindProperty("debug");
AlingMountTrigger = serializedObject.FindProperty("AlingMountTrigger");
DismountType = serializedObject.FindProperty("DismountType");
DisableComponents = serializedObject.FindProperty("DisableComponents");
DisableList = serializedObject.FindProperty("DisableList");
}
#region GUICONTENT
private readonly GUIContent G_DisableComponents = new GUIContent("Disable Components", "If some of the components are breaking the Rider Logic, disable them");
private readonly GUIContent G_DisableList = new GUIContent("Disable List", "Monobehaviours that will be disabled while mounted");
// private readonly GUIContent G_CreateColliderMounted = new GUIContent("Create capsule collider while Mounted", "This collider is for hit the Rider while mounted");
private readonly GUIContent G_Parent = new GUIContent("Parent to Mount", "Parent the Rider to the Mount Point on the Mountable Animal");
private readonly GUIContent G_DismountType = new GUIContent("Dismount Type", "Changes the Dismount animation on the Rider.\nRandom: Randomly select a Dismount Animation.\nInput: Select the Dismount Animation by the Horizontal and Vertical Input Axis.\n Last: Uses the Last Mount Animation as a reference for the Dismount Animation.");
// private readonly GUIContent G_DismountMountOnDeath = new GUIContent("Dismount if mount dies", "The Rider will automatically dismount if the Animal Dies");
#endregion
public override void OnInspectorGUI()
{
MalbersEditor.DrawDescription(version);
serializedObject.Update();
if (!Application.isPlaying) AddMountLayer();
EditorGUILayout.BeginVertical(MalbersEditor.StyleGray);
Editor_Tabs1.intValue = GUILayout.Toolbar(Editor_Tabs1.intValue, new string[] { "General", "Events", "Advanced", "Debug" });
int Selection = Editor_Tabs1.intValue;
if (Selection == 0) DrawGeneral();
else if (Selection == 1) DrawEvents();
else if (Selection == 2) DrawAdvanced();
else if (Selection == 3) DrawDebug();
serializedObject.ApplyModifiedProperties();
EditorGUILayout.EndVertical();
}
private void AddMountLayer()
{
Animator anim = M.Anim;
if (anim)
{
var controller = (UnityEditor.Animations.AnimatorController)anim.runtimeAnimatorController;
if (controller)
{
var layers = controller.layers.ToList();
if (layers.Find(layer => layer.name == M.MountLayer) == null)
{
var defaultColor = GUI.color;
GUI.color = Color.green;
var ST = new GUIStyle(EditorStyles.miniButtonMid) { fontStyle = FontStyle.Bold };
if (GUILayout.Button(new GUIContent("Add Mounted Layer",
"There's no [Mounted] layer on the Current Animator. This will add all the Animator Parameters and States needed for the Riding System"), ST))
{
AddLayerMounted(controller);
}
GUI.color = defaultColor;
}
}
}
}
private void DrawDebug()
{
if (Application.isPlaying)
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ToggleLeft("Can Mount", M.CanMount);
EditorGUILayout.ToggleLeft("Can Dismount", M.CanDismount);
EditorGUILayout.ToggleLeft("Can Call Animal", M.CanCallAnimal);
EditorGUILayout.Space();
EditorGUILayout.ToggleLeft("Mounted", M.Mounted);
EditorGUILayout.ToggleLeft("Is on Horse", M.IsOnHorse);
EditorGUILayout.ToggleLeft("Is Mounting", M.IsMounting);
EditorGUILayout.ToggleLeft("Is Riding", M.IsRiding);
EditorGUILayout.ToggleLeft("Is Dismounting", M.IsDismounting);
//EditorGUILayout.FloatField("Straight Spine", M.SP_Weight);
EditorGUILayout.Space();
EditorGUILayout.ObjectField("Current Mount", M.Montura, typeof(Mount), false);
EditorGUILayout.ObjectField("Stored Mount", M.MountStored, typeof(Mount), false);
EditorGUILayout.ObjectField("Mount Trigger", M.MountTrigger, typeof(MountTriggers), false);
EditorGUI.EndDisabledGroup();
EditorGUILayout.EndVertical();
Repaint();
}
}
private void DrawAdvanced()
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.LabelField("References", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(animator);
EditorGUILayout.PropertyField(m_rigidBody);
EditorGUILayout.PropertyField(m_root, new GUIContent("Rider's Root", "Root Gameobject for the Rider Character"));
}
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.PropertyField(ReSync);
EditorGUILayout.PropertyField(ResyncThreshold);
EditorGUILayout.PropertyField(AlingMountTrigger, new GUIContent("Align MTrigger Time", "Time to Align to the Mount Trigger Position while is playing the Mount Animation"));
EditorGUILayout.PropertyField(LayerPath);
EditorGUILayout.PropertyField(MountLayer);
}
EditorGUILayout.EndVertical();
}
private void DrawEvents()
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.PropertyField(OnCanMount);
EditorGUILayout.PropertyField(OnCanDismount);
EditorGUILayout.PropertyField(OnStartMounting);
EditorGUILayout.PropertyField(OnEndMounting);
EditorGUILayout.PropertyField(OnStartDismounting);
EditorGUILayout.PropertyField(OnEndDismounting);
EditorGUILayout.PropertyField(OnFindMount);
EditorGUILayout.PropertyField(CanCallMount);
if (M.StartMounted.Value)
{
EditorGUILayout.PropertyField(OnAlreadyMounted);
}
}
EditorGUILayout.EndVertical();
}
private void DrawGeneral()
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
var MStoredGUI = "Stored Mount";
var MStoredTooltip = "If Start Mounted is Active this will be the Animal to mount.";
if (M.m_MountStored.Value != null && M.m_MountStored.Value.IsPrefab())
{
MStoredGUI += "[Prefab]";
MStoredTooltip += "\nThe Stored Mount is a Prefab. It will be instantiated";
}
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(StartMounted, new GUIContent("Start Mounted", "Set an animal to start mounted on it"));
MalbersEditor.DrawDebugIcon(debug);
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(MountStored, new GUIContent(MStoredGUI, MStoredTooltip));
//if (M.StartMounted.Value && M.MountStored == null)
//{
// EditorGUILayout.HelpBox("Select an Animal with 'IMount' interface from the scene if you want to start mounted on it", MessageType.Warning);
//}
}
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.PropertyField(Parent, G_Parent);
EditorGUILayout.PropertyField(LinkUpdate, new GUIContent("Link Update", "Updates Everyframe the position and rotation of the rider to the Animal Mount Point"));
EditorGUILayout.PropertyField(DismountType, G_DismountType);
EditorGUILayout.PropertyField(gravity, new GUIContent("Gravity Dir"));
}
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
// CreateColliderMounted.boolValue = EditorGUILayout.ToggleLeft(G_CreateColliderMounted, CreateColliderMounted.boolValue);
EditorGUILayout.LabelField("Rider Collider", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(MainCollider, new GUIContent("Main Collider", "Main Character collider for the Rider"));
EditorGUILayout.PropertyField(MountCollider, new GUIContent("Collider Modifier", "When mounting the Collider will change its properties to this preset"));
// EditorGUILayout.PropertyField(ModifyMainCollider, new GUIContent("Collider Modifier", "When mounting the Collider will change its properties to this preset"));
}
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.PropertyField(RightHand);
EditorGUILayout.PropertyField(LeftHand);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(LeftReinOffset);
EditorGUILayout.PropertyField(RightReinOffset);
}
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.PropertyField(DisableComponents, G_DisableComponents);
if (M.DisableComponents)
{
MalbersEditor.Arrays(DisableList, G_DisableList);
if (M.DisableList != null && M.DisableList.Length == 0)
{
EditorGUILayout.HelpBox("If 'Disable List' is empty , it will disable all Monovehaviours while riding", MessageType.Info);
}
}
}
EditorGUILayout.EndVertical();
EditorGUI.BeginDisabledGroup(Application.isPlaying);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.LabelField("Exposed Values", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_CanMount, new GUIContent("Can Mount", "It will be enabled when the Rider is near a mount Trigger,\nIt's used on the Active parameter of the Mount Input"));
EditorGUILayout.PropertyField(m_CanDismount, new GUIContent("Can Dismount", "It will be enabled when the Rider riding a mount,\nIt's used on the Active parameter of the Dismount Input"));
EditorGUILayout.PropertyField(m_CanCallAnimal, new GUIContent("Can Call Mount", "It will be enabled when the Rider has a Mount Stored and is not near or mounted is near the mount,\nIt's used on the Active parameter of the Can call Mount Input"));
}
EditorGUILayout.EndVertical();
EditorGUI.EndDisabledGroup();
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.PropertyField(CallAnimalA, new GUIContent("Call Animal", "Sound to call the Stored Animal"));
EditorGUILayout.PropertyField(StopAnimalA, new GUIContent("Stop Animal", "Sound to stop calling the Stored Animal"));
EditorGUILayout.PropertyField(RiderAudio, new GUIContent("Audio Source", "The reference for the audio source"));
}
EditorGUILayout.EndVertical();
}
void AddLayerMounted(UnityEditor.Animations.AnimatorController AnimController)
{
var MountAnimator = Resources.Load<UnityEditor.Animations.AnimatorController>(M.LayerPath);
AddParametersOnAnimator(AnimController, MountAnimator);
foreach (var item in MountAnimator.layers)
{
AnimController.AddLayer(item);
}
Debug.Log("Mount Layer added to: " + AnimController.name);
}
public static void AddParametersOnAnimator(UnityEditor.Animations.AnimatorController AnimController, UnityEditor.Animations.AnimatorController Mounted)
{
AnimatorControllerParameter[] parameters = AnimController.parameters;
AnimatorControllerParameter[] Mountedparameters = Mounted.parameters;
foreach (var param in Mountedparameters)
{
if (!SearchParameter(parameters, param.name))
{
AnimController.AddParameter(param);
}
}
}
public static bool SearchParameter(AnimatorControllerParameter[] parameters, string name)
{
foreach (AnimatorControllerParameter item in parameters)
{
if (item.name == name) return true;
}
return false;
}
}
#endif
#endregion
}