336 lines
8.9 KiB
C#
336 lines
8.9 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Networking;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace RoR2;
|
|
|
|
public class DamageTrail : MonoBehaviour
|
|
{
|
|
private struct TrailPoint
|
|
{
|
|
public Vector3 position;
|
|
|
|
public float localStartTime;
|
|
|
|
public float localEndTime;
|
|
|
|
public Transform segmentTransform;
|
|
}
|
|
|
|
[FormerlySerializedAs("updateInterval")]
|
|
[Tooltip("How often to drop a new point onto the trail.")]
|
|
public float pointUpdateInterval = 0.2f;
|
|
|
|
[Tooltip("How often the damage trail should deal damage.")]
|
|
public float damageUpdateInterval = 0.2f;
|
|
|
|
[Tooltip("How large the radius, or width, of the damage detection should be.")]
|
|
public float radius = 0.5f;
|
|
|
|
[Tooltip("How large the height of the damage detection should be.")]
|
|
public float height = 0.5f;
|
|
|
|
[Tooltip("How long a point on the trail should last.")]
|
|
public float pointLifetime = 3f;
|
|
|
|
[Tooltip("The line renderer to use for display.")]
|
|
public LineRenderer lineRenderer;
|
|
|
|
public bool active = true;
|
|
|
|
[Tooltip("Prefab to use per segment.")]
|
|
public GameObject segmentPrefab;
|
|
|
|
public bool destroyTrailSegments;
|
|
|
|
public float damagePerSecond;
|
|
|
|
public GameObject owner;
|
|
|
|
private HashSet<GameObject> ignoredObjects = new HashSet<GameObject>();
|
|
|
|
private TeamIndex teamIndex;
|
|
|
|
private new Transform transform;
|
|
|
|
private List<TrailPoint> pointsList;
|
|
|
|
private float localTime;
|
|
|
|
private float nextTrailPointUpdate;
|
|
|
|
private float nextTrailDamageUpdate;
|
|
|
|
private static float optimizedDamageUpdateinterval;
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
|
private static void Init()
|
|
{
|
|
RoR2Application.onUpdate += UpdateOptimizedDamageUpdateInterval;
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
pointsList = new List<TrailPoint>();
|
|
transform = base.transform;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
localTime = 0f;
|
|
AddPoint();
|
|
AddPoint();
|
|
}
|
|
|
|
private static void UpdateOptimizedDamageUpdateInterval()
|
|
{
|
|
float b = 0.4f;
|
|
float a = 0.2f;
|
|
float num = 60f;
|
|
float num2 = 1f / Time.deltaTime;
|
|
if (num2 > num)
|
|
{
|
|
optimizedDamageUpdateinterval = a;
|
|
return;
|
|
}
|
|
float a2 = (num - num2) / 30f;
|
|
a2 = Mathf.Min(a2, 1f);
|
|
optimizedDamageUpdateinterval = Mathf.Lerp(a, b, a2);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (!EffectManager.UsePools)
|
|
{
|
|
return;
|
|
}
|
|
for (int num = pointsList.Count - 1; num >= 0; num--)
|
|
{
|
|
if ((bool)pointsList[num].segmentTransform)
|
|
{
|
|
GameObject gameObject = pointsList[num].segmentTransform.gameObject;
|
|
EffectManagerHelper component = gameObject.GetComponent<EffectManagerHelper>();
|
|
if (component != null && component.OwningPool != null)
|
|
{
|
|
component.OwningPool.ReturnObject(component);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogFormat("DamageTrail.OnDestroy: No EFH on {0} ({1})", gameObject.name, gameObject.GetInstanceID());
|
|
}
|
|
}
|
|
pointsList.RemoveAt(num);
|
|
}
|
|
}
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
MyFixedUpdate(Time.fixedDeltaTime);
|
|
}
|
|
|
|
private void MyFixedUpdate(float deltaTime)
|
|
{
|
|
localTime += deltaTime;
|
|
if (localTime >= nextTrailPointUpdate)
|
|
{
|
|
nextTrailPointUpdate += pointUpdateInterval;
|
|
UpdateTrail(active);
|
|
}
|
|
if (localTime >= nextTrailDamageUpdate)
|
|
{
|
|
nextTrailDamageUpdate += optimizedDamageUpdateinterval;
|
|
DoDamage(optimizedDamageUpdateinterval);
|
|
}
|
|
if (pointsList.Count > 0)
|
|
{
|
|
TrailPoint value = pointsList[pointsList.Count - 1];
|
|
value.position = transform.position;
|
|
value.localEndTime = localTime + pointLifetime;
|
|
pointsList[pointsList.Count - 1] = value;
|
|
if ((bool)value.segmentTransform)
|
|
{
|
|
value.segmentTransform.position = transform.position;
|
|
}
|
|
if ((bool)lineRenderer)
|
|
{
|
|
lineRenderer.SetPosition(pointsList.Count - 1, value.position);
|
|
}
|
|
}
|
|
if (!segmentPrefab)
|
|
{
|
|
return;
|
|
}
|
|
Vector3 position = transform.position;
|
|
for (int num = pointsList.Count - 1; num >= 0; num--)
|
|
{
|
|
Transform segmentTransform = pointsList[num].segmentTransform;
|
|
if ((bool)segmentTransform)
|
|
{
|
|
segmentTransform.LookAt(position, Vector3.up);
|
|
Vector3 vector = pointsList[num].position - position;
|
|
segmentTransform.position = position + vector * 0.5f;
|
|
float num2 = Mathf.Clamp01(Mathf.InverseLerp(pointsList[num].localStartTime, pointsList[num].localEndTime, localTime));
|
|
Vector3 localScale = new Vector3(radius * (1f - num2), radius * (1f - num2), vector.magnitude);
|
|
segmentTransform.localScale = localScale;
|
|
position = pointsList[num].position;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateTrail(bool addPoint)
|
|
{
|
|
while (pointsList.Count > 0 && pointsList[0].localEndTime <= localTime)
|
|
{
|
|
RemovePoint(0);
|
|
}
|
|
if (addPoint)
|
|
{
|
|
AddPoint();
|
|
}
|
|
if ((bool)lineRenderer)
|
|
{
|
|
UpdateLineRenderer(lineRenderer);
|
|
}
|
|
}
|
|
|
|
private void DoDamage(float damageInterval)
|
|
{
|
|
if (!NetworkServer.active || pointsList.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
Vector3 vector = pointsList[pointsList.Count - 1].position;
|
|
ignoredObjects.Clear();
|
|
TeamIndex attackerTeamIndex = TeamIndex.Neutral;
|
|
float damage = damagePerSecond * damageInterval;
|
|
if ((bool)owner)
|
|
{
|
|
ignoredObjects.Add(owner);
|
|
attackerTeamIndex = TeamComponent.GetObjectTeam(owner);
|
|
}
|
|
DamageInfo damageInfo = new DamageInfo();
|
|
damageInfo.attacker = owner;
|
|
damageInfo.inflictor = base.gameObject;
|
|
damageInfo.crit = false;
|
|
damageInfo.damage = damage;
|
|
damageInfo.damageColorIndex = DamageColorIndex.Item;
|
|
damageInfo.damageType = DamageType.Generic;
|
|
damageInfo.force = Vector3.zero;
|
|
damageInfo.procCoefficient = 0f;
|
|
for (int num = pointsList.Count - 2; num >= 0; num--)
|
|
{
|
|
Vector3 position = pointsList[num].position;
|
|
Vector3 forward = position - vector;
|
|
Vector3 halfExtents = new Vector3(radius, height, forward.magnitude);
|
|
Vector3 center = Vector3.Lerp(position, vector, 0.5f);
|
|
Quaternion orientation = Util.QuaternionSafeLookRotation(forward);
|
|
Collider[] colliders;
|
|
int num2 = HGPhysics.OverlapBox(out colliders, center, halfExtents, orientation, LayerIndex.entityPrecise.mask);
|
|
for (int i = 0; i < num2; i++)
|
|
{
|
|
HurtBox component = colliders[i].GetComponent<HurtBox>();
|
|
if (!component)
|
|
{
|
|
continue;
|
|
}
|
|
HealthComponent healthComponent = component.healthComponent;
|
|
if ((bool)healthComponent)
|
|
{
|
|
GameObject item = healthComponent.gameObject;
|
|
if (!ignoredObjects.Contains(item) && FriendlyFireManager.ShouldSplashHitProceed(healthComponent, attackerTeamIndex))
|
|
{
|
|
ignoredObjects.Add(item);
|
|
damageInfo.position = colliders[i].transform.position;
|
|
healthComponent.TakeDamage(damageInfo);
|
|
}
|
|
}
|
|
}
|
|
HGPhysics.ReturnResults(colliders);
|
|
vector = position;
|
|
}
|
|
}
|
|
|
|
private void UpdateLineRenderer(LineRenderer lineRenderer)
|
|
{
|
|
lineRenderer.positionCount = pointsList.Count;
|
|
for (int i = 0; i < pointsList.Count; i++)
|
|
{
|
|
lineRenderer.SetPosition(i, pointsList[i].position);
|
|
}
|
|
}
|
|
|
|
private void AddPoint()
|
|
{
|
|
TrailPoint trailPoint = default(TrailPoint);
|
|
trailPoint.position = transform.position;
|
|
trailPoint.localStartTime = localTime;
|
|
trailPoint.localEndTime = localTime + pointLifetime;
|
|
TrailPoint item = trailPoint;
|
|
if ((bool)segmentPrefab)
|
|
{
|
|
if (!EffectManager.ShouldUsePooledEffect(segmentPrefab))
|
|
{
|
|
item.segmentTransform = Object.Instantiate(segmentPrefab, transform).transform;
|
|
}
|
|
else
|
|
{
|
|
EffectManagerHelper andActivatePooledEffect = EffectManager.GetAndActivatePooledEffect(segmentPrefab, transform, inResetLocal: true);
|
|
item.segmentTransform = andActivatePooledEffect.gameObject.transform;
|
|
}
|
|
}
|
|
pointsList.Add(item);
|
|
}
|
|
|
|
private void RemovePoint(int pointIndex)
|
|
{
|
|
if (destroyTrailSegments)
|
|
{
|
|
if ((bool)pointsList[pointIndex].segmentTransform)
|
|
{
|
|
if (!EffectManager.UsePools)
|
|
{
|
|
Object.Destroy(pointsList[pointIndex].segmentTransform.gameObject);
|
|
}
|
|
else
|
|
{
|
|
GameObject gameObject = pointsList[pointIndex].segmentTransform.gameObject;
|
|
EffectManagerHelper component = gameObject.GetComponent<EffectManagerHelper>();
|
|
if (component != null && component.OwningPool != null)
|
|
{
|
|
component.OwningPool.ReturnObject(component);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogFormat("DamageTrail.RemovePoint: No EFH on {0} ({1})", gameObject.name, gameObject.GetInstanceID());
|
|
Object.Destroy(gameObject);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (EffectManager.UsePools && (bool)pointsList[pointIndex].segmentTransform)
|
|
{
|
|
pointsList[pointIndex].segmentTransform.gameObject.transform.SetParent(null);
|
|
}
|
|
pointsList.RemoveAt(pointIndex);
|
|
}
|
|
|
|
private void OnDrawGizmos()
|
|
{
|
|
Vector3 vector = pointsList[pointsList.Count - 1].position;
|
|
for (int num = pointsList.Count - 2; num >= 0; num--)
|
|
{
|
|
Vector3 position = pointsList[num].position;
|
|
Vector3 forward = position - vector;
|
|
Vector3 s = new Vector3(radius, 0.5f, forward.magnitude);
|
|
Vector3 pos = Vector3.Lerp(position, vector, 0.5f);
|
|
Quaternion q = Util.QuaternionSafeLookRotation(forward);
|
|
Gizmos.matrix = Matrix4x4.TRS(pos, q, s);
|
|
Gizmos.color = Color.blue;
|
|
Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
|
|
Gizmos.matrix = Matrix4x4.identity;
|
|
vector = position;
|
|
}
|
|
}
|
|
}
|