142 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			142 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using Fusion; | ||
|  | 
 | ||
|  | namespace TPSBR | ||
|  | { | ||
|  | 	using UnityEngine; | ||
|  | 
 | ||
|  | 	public class Explosion : ContextBehaviour | ||
|  | 	{ | ||
|  | 		// PRIVATE MEMBERS | ||
|  | 
 | ||
|  | 		[SerializeField] | ||
|  | 		private LayerMask  _hitMask; | ||
|  | 		[SerializeField] | ||
|  | 		private EHitType   _hitType; | ||
|  | 
 | ||
|  | 		[SerializeField] | ||
|  | 		private float      _innerRadius; | ||
|  | 		[SerializeField] | ||
|  | 		private float      _outerRadius; | ||
|  | 
 | ||
|  | 		[SerializeField] | ||
|  | 		private float      _innerHitValue; | ||
|  | 		[SerializeField] | ||
|  | 		private float      _outerHitValue; | ||
|  | 
 | ||
|  | 		[SerializeField] | ||
|  | 		private bool       _useBodyPartMultipliers; | ||
|  | 
 | ||
|  | 		[SerializeField] | ||
|  | 		private float      _despawnDelay; | ||
|  | 
 | ||
|  | 		[SerializeField] | ||
|  | 		private Transform  _effectRoot; | ||
|  | 
 | ||
|  | 
 | ||
|  | 		private TickTimer  _despawnTimer; | ||
|  | 
 | ||
|  | 		// NetworkBehaviour INTERFACE | ||
|  | 
 | ||
|  | 		public override void Spawned() | ||
|  | 		{ | ||
|  | 			base.Spawned(); | ||
|  | 
 | ||
|  | 			ShowEffect(); | ||
|  | 			Explode(); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		public override void FixedUpdateNetwork() | ||
|  | 		{ | ||
|  | 			if (HasStateAuthority == false) | ||
|  | 				return; | ||
|  | 			if (_despawnTimer.Expired(Runner) == false) | ||
|  | 				return; | ||
|  | 
 | ||
|  | 			Runner.Despawn(Object); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// PRIVATE METHODS | ||
|  | 
 | ||
|  | 		private void Explode() | ||
|  | 		{ | ||
|  | 			if (HasStateAuthority == false) | ||
|  | 				return; | ||
|  | 
 | ||
|  | 			var hits = ListPool.Get<LagCompensatedHit>(16); | ||
|  | 			var hitRoots = ListPool.Get<int>(16); | ||
|  | 
 | ||
|  | 			var position = transform.position + Vector3.up * 0.5f; // Check explosion slightly above | ||
|  | 
 | ||
|  | 			int count = Runner.LagCompensation.OverlapSphere(position, _outerRadius, Object.InputAuthority, hits, _hitMask); | ||
|  | 			bool damageFalloff = _innerRadius < _outerRadius && _innerHitValue != _outerHitValue; | ||
|  | 
 | ||
|  | 			var player = Context.NetworkGame.GetPlayer(Object.InputAuthority); | ||
|  | 			var owner = player != null ? player.ActiveAgent : null; | ||
|  | 
 | ||
|  | 			for (int i = 0; i < count; i++) | ||
|  | 			{ | ||
|  | 				var hit = hits[i]; | ||
|  | 
 | ||
|  | 				if (hit.Hitbox == null) | ||
|  | 					continue; | ||
|  | 
 | ||
|  | 				var hitTarget = hit.Hitbox.Root.GetComponent<IHitTarget>(); | ||
|  | 
 | ||
|  | 				if (hitTarget == null) | ||
|  | 					continue; | ||
|  | 
 | ||
|  | 				int hitRootID = hit.Hitbox.Root.GetInstanceID(); | ||
|  | 				if (hitRoots.Contains(hitRootID) == true) | ||
|  | 					continue; // Same object was hit multiple times | ||
|  | 
 | ||
|  | 				// TODO: Replace this when detailed hit info will be fixed | ||
|  | 				var direction = hit.GameObject.transform.position - position; | ||
|  | 				float distance = direction.magnitude; | ||
|  | 				direction /= distance; // Normalize | ||
|  | 
 | ||
|  | 				if (Runner.GetPhysicsScene().Raycast(position, direction, distance, ObjectLayerMask.Default) == true) | ||
|  | 					continue; | ||
|  | 
 | ||
|  | 				hitRoots.Add(hitRootID); | ||
|  | 
 | ||
|  | 				float damage = _innerHitValue; | ||
|  | 
 | ||
|  | 				if (damageFalloff == true && distance > _innerRadius) | ||
|  | 				{ | ||
|  | 					damage = MathUtility.Map(_innerRadius, _outerRadius, _innerHitValue, _outerHitValue, distance); | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// TODO: Remove this when detailed hit info will be fixed | ||
|  | 				hit.Point = hit.GameObject.transform.position; | ||
|  | 				hit.Normal = -direction; | ||
|  | 
 | ||
|  | 				if (owner != null) | ||
|  | 				{ | ||
|  | 					HitUtility.ProcessHit(owner.Object, direction, hit, damage, _hitType, out HitData hitData); | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{ | ||
|  | 					HitUtility.ProcessHit(Object.InputAuthority, direction, hit, damage, _hitType, out HitData hitData); | ||
|  | 				} | ||
|  | 			} | ||
|  | 
 | ||
|  | 			ListPool.Return(hitRoots); | ||
|  | 			ListPool.Return(hits); | ||
|  | 
 | ||
|  | 			_despawnTimer = TickTimer.CreateFromSeconds(Runner, _despawnDelay); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		private void ShowEffect() | ||
|  | 		{ | ||
|  | 			if (Runner.Mode == SimulationModes.Server) | ||
|  | 				return; | ||
|  | 
 | ||
|  | 			if (_effectRoot != null) | ||
|  | 			{ | ||
|  | 				_effectRoot.SetActive(true); | ||
|  | 				_effectRoot.localScale = Vector3.one * _outerRadius * 2f; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | } |