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.
		
		
		
		
		
			
		
			
	
	
		
			288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
		
		
			
		
	
	
			288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
| 
								 
											1 year ago
										 
									 | 
							
								using System.Collections;
							 | 
						||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						||
| 
								 | 
							
								using UnityEngine;
							 | 
						||
| 
								 | 
							
								using UnityEngine.Events;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace Autohand {
							 | 
						||
| 
								 | 
							
								    public delegate void StabEvent(Stabber stabber, Stabbable stab);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [HelpURL("https://app.gitbook.com/s/5zKO0EvOjzUDeT2aiFk3/auto-hand/extras/stabbing")]
							 | 
						||
| 
								 | 
							
								    public class Stabber : MonoBehaviour {
							 | 
						||
| 
								 | 
							
								        [Tooltip("Can be left empty/null")]
							 | 
						||
| 
								 | 
							
								        public Grabbable grabbable;
							 | 
						||
| 
								 | 
							
								        [Header("Stab Settings")]
							 | 
						||
| 
								 | 
							
								        public CapsuleCollider stabCapsule;
							 | 
						||
| 
								 | 
							
								        [Tooltip("If left empty, will default to grabbable layers")]
							 | 
						||
| 
								 | 
							
								        public LayerMask stabbableLayers;
							 | 
						||
| 
								 | 
							
								        [Tooltip("The index that must match the stabbables index to allow stabbing")]
							 | 
						||
| 
								 | 
							
								        public int stabIndex;
							 | 
						||
| 
								 | 
							
								        public int maxStabs = 3;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [Header("Joint Settings")]
							 | 
						||
| 
								 | 
							
								        public Vector3 axis;
							 | 
						||
| 
								 | 
							
								        public float limit = float.MaxValue;
							 | 
						||
| 
								 | 
							
								        public ConfigurableJointMotion xMotion;
							 | 
						||
| 
								 | 
							
								        public ConfigurableJointMotion yMotion;
							 | 
						||
| 
								 | 
							
								        public ConfigurableJointMotion zMotion;
							 | 
						||
| 
								 | 
							
								        public ConfigurableJointMotion angularXMotion;
							 | 
						||
| 
								 | 
							
								        public ConfigurableJointMotion angularYMotion;
							 | 
						||
| 
								 | 
							
								        public ConfigurableJointMotion angularZMotion;
							 | 
						||
| 
								 | 
							
								        [Space]
							 | 
						||
| 
								 | 
							
								        public float positionDampeningMultiplyer = 1;
							 | 
						||
| 
								 | 
							
								        public float rotationDampeningMultiplyer = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [Header("Events")]
							 | 
						||
| 
								 | 
							
								        public UnityEvent StartStab;
							 | 
						||
| 
								 | 
							
								        public UnityEvent EndStab;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //Progammer Events <3
							 | 
						||
| 
								 | 
							
								        public StabEvent StartStabEvent;
							 | 
						||
| 
								 | 
							
								        public StabEvent EndStabEvent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public List<Stabbable> stabbed { get; private set; }
							 | 
						||
| 
								 | 
							
								        public List<ConfigurableJoint> stabbedJoints { get; private set; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>Helps prevent stabbable from being triggered accidently from the wrong angle</summary>
							 | 
						||
| 
								 | 
							
								        Dictionary<Stabbable, int> stabbedFrames;
							 | 
						||
| 
								 | 
							
								        const int STABFRAMES = 2;
							 | 
						||
| 
								 | 
							
								        int frames;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Vector3 startPos;
							 | 
						||
| 
								 | 
							
								        Quaternion startRot;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Vector3 lastPos;
							 | 
						||
| 
								 | 
							
								        Quaternion lastRot;
							 | 
						||
| 
								 | 
							
								        Collider[] resultsNonAlloc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Transform prereleaseParent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        void Start() {
							 | 
						||
| 
								 | 
							
								            stabbedFrames = new Dictionary<Stabbable, int>();
							 | 
						||
| 
								 | 
							
								            stabbed = new List<Stabbable>();
							 | 
						||
| 
								 | 
							
								            stabbedJoints = new List<ConfigurableJoint>();
							 | 
						||
| 
								 | 
							
								            resultsNonAlloc = new Collider[25];
							 | 
						||
| 
								 | 
							
								            if(stabbableLayers == 0)
							 | 
						||
| 
								 | 
							
								                stabbableLayers = LayerMask.GetMask(Hand.grabbableLayers);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(grabbable == null)
							 | 
						||
| 
								 | 
							
								                gameObject.HasGrabbable(out grabbable);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            startPos = transform.position;
							 | 
						||
| 
								 | 
							
								            startRot = transform.rotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            StartCoroutine(StartWait());
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //This will keep the stabbables in place for the start stab
							 | 
						||
| 
								 | 
							
								        IEnumerator StartWait() {
							 | 
						||
| 
								 | 
							
								            for(int i = 0; i < STABFRAMES; i++) {
							 | 
						||
| 
								 | 
							
								                transform.position = startPos;
							 | 
						||
| 
								 | 
							
								                transform.rotation = startRot;
							 | 
						||
| 
								 | 
							
								                yield return new WaitForFixedUpdate();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void FixedUpdate() {
							 | 
						||
| 
								 | 
							
								            if(transform.position != lastPos || lastRot != transform.rotation) {
							 | 
						||
| 
								 | 
							
								                frames = 0;
							 | 
						||
| 
								 | 
							
								                lastPos = transform.position;
							 | 
						||
| 
								 | 
							
								                lastRot = transform.rotation;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if(frames < STABFRAMES) {
							 | 
						||
| 
								 | 
							
								                CheckStabArea();
							 | 
						||
| 
								 | 
							
								                frames++;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected virtual void CheckStabArea() {
							 | 
						||
| 
								 | 
							
								            Vector3 point1;
							 | 
						||
| 
								 | 
							
								            Vector3 point2;
							 | 
						||
| 
								 | 
							
								            Vector3 capsuleAxis;
							 | 
						||
| 
								 | 
							
								            var height = stabCapsule.height;
							 | 
						||
| 
								 | 
							
								            var radius = stabCapsule.radius;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(stabCapsule.direction == 0) {
							 | 
						||
| 
								 | 
							
								                capsuleAxis = Vector3.right;
							 | 
						||
| 
								 | 
							
								                height *= stabCapsule.transform.lossyScale.x;
							 | 
						||
| 
								 | 
							
								                radius *= stabCapsule.transform.lossyScale.y > stabCapsule.transform.lossyScale.z ? stabCapsule.transform.lossyScale.y : stabCapsule.transform.lossyScale.z;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if(stabCapsule.direction == 1) {
							 | 
						||
| 
								 | 
							
								                capsuleAxis = Vector3.up;
							 | 
						||
| 
								 | 
							
								                height *= stabCapsule.transform.lossyScale.y;
							 | 
						||
| 
								 | 
							
								                radius *= stabCapsule.transform.lossyScale.z > stabCapsule.transform.lossyScale.x ? stabCapsule.transform.lossyScale.z : stabCapsule.transform.lossyScale.x;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                capsuleAxis = Vector3.forward;
							 | 
						||
| 
								 | 
							
								                height *= stabCapsule.transform.lossyScale.z;
							 | 
						||
| 
								 | 
							
								                radius *= stabCapsule.transform.lossyScale.y > stabCapsule.transform.lossyScale.x ? stabCapsule.transform.lossyScale.y : stabCapsule.transform.lossyScale.x;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(height / 2 <= radius) {
							 | 
						||
| 
								 | 
							
								                height = 0;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                height /= 2;
							 | 
						||
| 
								 | 
							
								                height -= radius;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            point1 = stabCapsule.bounds.center + stabCapsule.transform.rotation * capsuleAxis * (height);
							 | 
						||
| 
								 | 
							
								            point2 = stabCapsule.bounds.center - stabCapsule.transform.rotation * capsuleAxis * (height);
							 | 
						||
| 
								 | 
							
								            Physics.OverlapCapsuleNonAlloc(point1, point2, radius, resultsNonAlloc, stabbableLayers, QueryTriggerInteraction.Ignore);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            List<Stabbable> newStabbed = new List<Stabbable>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for(int i = 0; i < resultsNonAlloc.Length; i++) {
							 | 
						||
| 
								 | 
							
								                Stabbable tempStab;
							 | 
						||
| 
								 | 
							
								                if(resultsNonAlloc[i] != null) {
							 | 
						||
| 
								 | 
							
								                    if(resultsNonAlloc[i].CanGetComponent(out tempStab))
							 | 
						||
| 
								 | 
							
								                        if(tempStab.gameObject != gameObject)
							 | 
						||
| 
								 | 
							
								                            newStabbed.Add(tempStab);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for(int i = stabbed.Count - 1; i >= 0; i--)
							 | 
						||
| 
								 | 
							
								                if(!newStabbed.Contains(stabbed[i]))
							 | 
						||
| 
								 | 
							
								                    OnStabbableExit(stabbed[i]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(stabbed.Count < maxStabs)
							 | 
						||
| 
								 | 
							
								                for(int i = 0; i < newStabbed.Count; i++)
							 | 
						||
| 
								 | 
							
								                    if(!stabbed.Contains(newStabbed[i]) && newStabbed[i].CanStab(this))
							 | 
						||
| 
								 | 
							
								                        OnStabbableEnter(newStabbed[i]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for(int i = 0; i < resultsNonAlloc.Length; i++)
							 | 
						||
| 
								 | 
							
								                resultsNonAlloc[i] = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(stabbedFrames.Count > 0) {
							 | 
						||
| 
								 | 
							
								                var stabFrameKeys = new Stabbable[stabbedFrames.Count];
							 | 
						||
| 
								 | 
							
								                stabbedFrames.Keys.CopyTo(stabFrameKeys, 0);
							 | 
						||
| 
								 | 
							
								                foreach(var stabFrame in stabFrameKeys)
							 | 
						||
| 
								 | 
							
								                    if(!stabbed.Contains(stabFrame) && !newStabbed.Contains(stabFrame))
							 | 
						||
| 
								 | 
							
								                        stabbedFrames.Remove(stabFrame);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            newStabbed.Clear();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected virtual void OnStabbableEnter(Stabbable stab) {
							 | 
						||
| 
								 | 
							
								            if(stabbedFrames.ContainsKey(stab))
							 | 
						||
| 
								 | 
							
								                stabbedFrames[stab]++;
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                stabbedFrames.Add(stab, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(stabbedFrames[stab] < STABFRAMES)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            stabbed.Add(stab);
							 | 
						||
| 
								 | 
							
								            var joint = gameObject.AddComponent<ConfigurableJoint>();
							 | 
						||
| 
								 | 
							
								            joint.secondaryAxis = axis;
							 | 
						||
| 
								 | 
							
								            joint.connectedBody = stab.body;
							 | 
						||
| 
								 | 
							
								            joint.xMotion = xMotion;
							 | 
						||
| 
								 | 
							
								            joint.yMotion = yMotion;
							 | 
						||
| 
								 | 
							
								            joint.zMotion = zMotion;
							 | 
						||
| 
								 | 
							
								            joint.angularXMotion = angularXMotion;
							 | 
						||
| 
								 | 
							
								            joint.angularYMotion = angularYMotion;
							 | 
						||
| 
								 | 
							
								            joint.angularZMotion = angularZMotion;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            joint.linearLimit = new SoftJointLimit() { limit = this.limit };
							 | 
						||
| 
								 | 
							
								            joint.linearLimitSpring = new SoftJointLimitSpring() { damper = stab.positionDamper * positionDampeningMultiplyer };
							 | 
						||
| 
								 | 
							
								            joint.xDrive = new JointDrive() { positionDamper = stab.positionDamper * positionDampeningMultiplyer, maximumForce = float.MaxValue };
							 | 
						||
| 
								 | 
							
								            joint.yDrive = new JointDrive() { positionDamper = stab.positionDamper * positionDampeningMultiplyer, maximumForce = float.MaxValue };
							 | 
						||
| 
								 | 
							
								            joint.zDrive = new JointDrive() { positionDamper = stab.positionDamper * positionDampeningMultiplyer, maximumForce = float.MaxValue };
							 | 
						||
| 
								 | 
							
								            joint.slerpDrive = new JointDrive() { positionDamper = stab.positionDamper * positionDampeningMultiplyer };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            joint.angularXLimitSpring = new SoftJointLimitSpring() { damper = stab.rotationDamper * rotationDampeningMultiplyer };
							 | 
						||
| 
								 | 
							
								            joint.angularYZLimitSpring = new SoftJointLimitSpring() { damper = stab.rotationDamper * rotationDampeningMultiplyer };
							 | 
						||
| 
								 | 
							
								            joint.angularXDrive = new JointDrive() { positionDamper = stab.rotationDamper * rotationDampeningMultiplyer, maximumForce = float.MaxValue };
							 | 
						||
| 
								 | 
							
								            joint.angularYZDrive = new JointDrive() { positionDamper = stab.rotationDamper * rotationDampeningMultiplyer, maximumForce = float.MaxValue };
							 | 
						||
| 
								 | 
							
								            joint.projectionDistance /= 4f;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            joint.enablePreprocessing = true;
							 | 
						||
| 
								 | 
							
								            joint.enableCollision = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            Rigidbody jointBody;
							 | 
						||
| 
								 | 
							
								            joint.CanGetComponent(out jointBody);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            //resets the joint / wakes the body
							 | 
						||
| 
								 | 
							
								            jointBody.detectCollisions = false;
							 | 
						||
| 
								 | 
							
								            jointBody.detectCollisions = true;
							 | 
						||
| 
								 | 
							
								            stab.body.WakeUp();
							 | 
						||
| 
								 | 
							
								            jointBody.WakeUp();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(stab.parentOnStab && grabbable) {
							 | 
						||
| 
								 | 
							
								                grabbable.AddJointedBody(stab.body);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            stabbedJoints.Add(joint);
							 | 
						||
| 
								 | 
							
								            stab.OnStab(this);
							 | 
						||
| 
								 | 
							
								            StartStabEvent?.Invoke(this, stab);
							 | 
						||
| 
								 | 
							
								            StartStab?.Invoke();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected virtual void OnStabbableExit(Stabbable stab) {
							 | 
						||
| 
								 | 
							
								            var removeIndex = stabbed.IndexOf(stab);
							 | 
						||
| 
								 | 
							
								            stabbed.Remove(stab);
							 | 
						||
| 
								 | 
							
								            var joint = stabbedJoints[removeIndex];
							 | 
						||
| 
								 | 
							
								            stabbedJoints.RemoveAt(removeIndex);
							 | 
						||
| 
								 | 
							
								            Destroy(joint);
							 | 
						||
| 
								 | 
							
								            if(stab.parentOnStab && grabbable) {
							 | 
						||
| 
								 | 
							
								                grabbable.RemoveJointedBody(stab.body);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            stab.OnEndStab(this);
							 | 
						||
| 
								 | 
							
								            stabbedFrames.Remove(stab);
							 | 
						||
| 
								 | 
							
								            EndStabEvent?.Invoke(this, stab);
							 | 
						||
| 
								 | 
							
								            EndStab?.Invoke();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public List<Stabbable> GetStabbed() {
							 | 
						||
| 
								 | 
							
								            return stabbed;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public int GetStabbedCount() {
							 | 
						||
| 
								 | 
							
								            return stabbed.Count;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        void OnDrawGizmosSelected() {
							 | 
						||
| 
								 | 
							
								            Vector3 point1;
							 | 
						||
| 
								 | 
							
								            Vector3 point2;
							 | 
						||
| 
								 | 
							
								            Vector3 capsuleAxis;
							 | 
						||
| 
								 | 
							
								            var height = stabCapsule.height;
							 | 
						||
| 
								 | 
							
								            var radius = stabCapsule.radius;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(stabCapsule.direction == 0) {
							 | 
						||
| 
								 | 
							
								                capsuleAxis = Vector3.right;
							 | 
						||
| 
								 | 
							
								                height *= stabCapsule.transform.lossyScale.x;
							 | 
						||
| 
								 | 
							
								                radius *= stabCapsule.transform.lossyScale.y > stabCapsule.transform.lossyScale.z ? stabCapsule.transform.lossyScale.y : stabCapsule.transform.lossyScale.z;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if(stabCapsule.direction == 1) {
							 | 
						||
| 
								 | 
							
								                capsuleAxis = Vector3.up;
							 | 
						||
| 
								 | 
							
								                height *= stabCapsule.transform.lossyScale.y;
							 | 
						||
| 
								 | 
							
								                radius *= stabCapsule.transform.lossyScale.z > stabCapsule.transform.lossyScale.x ? stabCapsule.transform.lossyScale.z : stabCapsule.transform.lossyScale.x;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                capsuleAxis = Vector3.forward;
							 | 
						||
| 
								 | 
							
								                height *= stabCapsule.transform.lossyScale.z;
							 | 
						||
| 
								 | 
							
								                radius *= stabCapsule.transform.lossyScale.y > stabCapsule.transform.lossyScale.x ? stabCapsule.transform.lossyScale.y : stabCapsule.transform.lossyScale.x;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(height / 2 <= radius) {
							 | 
						||
| 
								 | 
							
								                height = 0;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                height /= 2;
							 | 
						||
| 
								 | 
							
								                height -= radius;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            point1 = stabCapsule.bounds.center + stabCapsule.transform.rotation * capsuleAxis * (height);
							 | 
						||
| 
								 | 
							
								            point2 = stabCapsule.bounds.center - stabCapsule.transform.rotation * capsuleAxis * (height);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            Gizmos.color = Color.blue;
							 | 
						||
| 
								 | 
							
								            Gizmos.DrawSphere(point1, radius);
							 | 
						||
| 
								 | 
							
								            Gizmos.DrawSphere(point2, radius);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |