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.

177 lines
4.5 KiB
C#

using System.Collections.Generic;
using Fusion;
using UnityEngine;
namespace Projectiles
{
public enum EHitAction : byte
{
None,
Damage,
Heal,
}
public struct HitData
{
public EHitAction Action;
public float Amount;
public bool IsFatal;
public Vector3 Position;
public Vector3 Direction;
public Vector3 Normal;
public Vector3 RootPosition;
public PlayerRef InstigatorRef;
public IHitInstigator Instigator;
public IHitTarget Target;
public EHitType HitType;
}
public enum EHitType
{
None,
Projectile,
Explosion,
Suicide,
}
public interface IHitTarget
{
bool IsActive { get; }
Transform HeadPivot { get; }
Transform BodyPivot { get; }
Transform GroundPivot { get; }
Hitbox BodyHitbox { get; }
void ProcessHit(ref HitData hit);
}
public interface IHitInstigator
{
void HitPerformed(HitData hit);
}
/// <summary>
/// A utility that encapsulates common approach of handling hits.
/// </summary>
public static class HitUtility
{
// PUBLIC METHODS
public static void GetAllTargets(NetworkRunner runner, List<IHitTarget> targets, bool onlyActive = true)
{
targets.Clear();
var healths = ListPool.Get<Health>(targets.Count);
// TODO: Best would be to get IHitTargets directly, but that is not possible for now
runner.GetAllBehaviours(healths);
if (onlyActive == true)
{
for (int i = 0; i < healths.Count; i++)
{
var target = healths[i] as IHitTarget;
if (target.IsActive == true)
targets.Add(target);
}
}
else
{
targets.AddRange(healths);
}
ListPool.Return(healths);
}
public static HitData ProcessHit(PlayerRef instigatorRef, Vector3 direction, LagCompensatedHit hit, float baseDamage, EHitType hitType)
{
var target = GetHitTarget(hit.Hitbox, hit.Collider);
if (target == null)
return default;
HitData hitData = default;
hitData.Action = EHitAction.Damage;
hitData.Amount = baseDamage;
hitData.Position = hit.Point;
hitData.Normal = hit.Normal;
hitData.Direction = direction;
hitData.Target = target;
hitData.InstigatorRef = instigatorRef;
hitData.HitType = hitType;
return ProcessHit(ref hitData);
}
public static HitData ProcessHit(NetworkBehaviour instigator, Vector3 direction, LagCompensatedHit hit, float baseDamage, EHitType hitType)
{
var target = GetHitTarget(hit.Hitbox, hit.Collider);
if (target == null)
return default;
HitData hitData = default;
hitData.Action = EHitAction.Damage;
hitData.Amount = baseDamage;
hitData.Position = hit.Point;
hitData.Normal = hit.Normal;
hitData.Direction = direction;
hitData.Target = target;
hitData.InstigatorRef = instigator != null ? instigator.Object.InputAuthority : default;
hitData.Instigator = instigator != null ? instigator.GetComponent<IHitInstigator>() : null;
hitData.HitType = hitType;
return ProcessHit(ref hitData);
}
public static HitData ProcessHit(NetworkBehaviour instigator, Collider collider, float damage, EHitType hitType)
{
var target = GetHitTarget(null, collider);
if (target == null)
return default;
HitData hitData = default;
hitData.Action = EHitAction.Damage;
hitData.Amount = damage;
hitData.InstigatorRef = instigator.Object.InputAuthority;
hitData.Instigator = instigator.GetComponent<IHitInstigator>();
hitData.Position = collider.transform.position;
hitData.Normal = (instigator.transform.position - collider.transform.position).normalized;
hitData.Direction = -hitData.Normal;
hitData.Target = target;
hitData.HitType = hitType;
return ProcessHit(ref hitData);
}
public static HitData ProcessHit(ref HitData hitData)
{
hitData.Target.ProcessHit(ref hitData);
// For local debug targets we show hit feedback immediately
// if (hitData.Instigator != null && hitData.Target is Health == false)
// {
// hitData.Instigator.HitPerformed(hitData);
// }
return hitData;
}
public static IHitTarget GetHitTarget(Hitbox hitbox, Collider collider)
{
if (hitbox != null)
return hitbox.Root.GetComponent<IHitTarget>();
if (collider == null)
return null;
if (ObjectLayerMask.HitTargets.value.IsBitSet(collider.gameObject.layer) == false)
return null;
return collider.GetComponentInParent<IHitTarget>();
}
}
}