r2mods/ilspy_dump/ror2_csproj/RoR2/OverlapAttack.cs

411 lines
12 KiB
C#

using System.Collections.Generic;
using RoR2.Audio;
using RoR2.Networking;
using UnityEngine;
using UnityEngine.Networking;
namespace RoR2;
public class OverlapAttack
{
private struct OverlapInfo
{
public HurtBox hurtBox;
public Vector3 hitPosition;
public Vector3 pushDirection;
}
public struct AttackInfo
{
public GameObject attacker;
public GameObject inflictor;
public float damage;
public bool isCrit;
public float procCoefficient;
public DamageColorIndex damageColorIndex;
public DamageTypeCombo damageType;
public Vector3 forceVector;
}
private class OverlapAttackMessage : MessageBase
{
public GameObject attacker;
public GameObject inflictor;
public float damage;
public bool isCrit;
public ProcChainMask procChainMask;
public float procCoefficient;
public DamageColorIndex damageColorIndex;
public DamageTypeCombo damageType;
public Vector3 forceVector;
public float pushAwayForce;
public readonly List<OverlapInfo> overlapInfoList = new List<OverlapInfo>();
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(attacker);
writer.Write(inflictor);
writer.Write(damage);
writer.Write(isCrit);
writer.Write(procChainMask);
writer.Write(procCoefficient);
writer.Write(damageColorIndex);
writer.WriteDamageType(damageType);
writer.Write(forceVector);
writer.Write(pushAwayForce);
writer.WritePackedUInt32((uint)overlapInfoList.Count);
foreach (OverlapInfo overlapInfo in overlapInfoList)
{
writer.Write(HurtBoxReference.FromHurtBox(overlapInfo.hurtBox));
writer.Write(overlapInfo.hitPosition);
writer.Write(overlapInfo.pushDirection);
}
}
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
attacker = reader.ReadGameObject();
inflictor = reader.ReadGameObject();
damage = reader.ReadSingle();
isCrit = reader.ReadBoolean();
procChainMask = reader.ReadProcChainMask();
procCoefficient = reader.ReadSingle();
damageColorIndex = reader.ReadDamageColorIndex();
damageType = reader.ReadDamageType();
forceVector = reader.ReadVector3();
pushAwayForce = reader.ReadSingle();
overlapInfoList.Clear();
int i = 0;
for (int num = (int)reader.ReadPackedUInt32(); i < num; i++)
{
OverlapInfo item = default(OverlapInfo);
item.hurtBox = reader.ReadHurtBoxReference().ResolveGameObject()?.GetComponent<HurtBox>();
item.hitPosition = reader.ReadVector3();
item.pushDirection = reader.ReadVector3();
overlapInfoList.Add(item);
}
}
}
public GameObject attacker;
public GameObject inflictor;
public TeamIndex teamIndex;
public AttackerFiltering attackerFiltering = AttackerFiltering.NeverHitSelf;
public Vector3 forceVector = Vector3.zero;
public float pushAwayForce;
public float damage = 1f;
public bool isCrit;
public ProcChainMask procChainMask;
public float procCoefficient = 1f;
public HitBoxGroup hitBoxGroup;
public GameObject hitEffectPrefab;
public NetworkSoundEventIndex impactSound = NetworkSoundEventIndex.Invalid;
public DamageColorIndex damageColorIndex;
public DamageTypeCombo damageType;
public int maximumOverlapTargets = 100;
private readonly List<HealthComponent> ignoredHealthComponentList = new List<HealthComponent>();
public float retriggerTimeout = float.PositiveInfinity;
private Queue<(HealthComponent, float)> ignoredRemovalList = new Queue<(HealthComponent, float)>();
private readonly List<OverlapInfo> overlapList = new List<OverlapInfo>();
private static readonly OverlapAttackMessage incomingMessage = new OverlapAttackMessage();
private static readonly OverlapAttackMessage outgoingMessage = new OverlapAttackMessage();
public Vector3 lastFireAverageHitPosition { get; private set; }
private bool HurtBoxPassesFilter(HurtBox hurtBox)
{
if (!hurtBox.healthComponent)
{
return true;
}
if (hurtBox.healthComponent.gameObject == attacker && attackerFiltering == AttackerFiltering.NeverHitSelf)
{
return false;
}
if (attacker == null && hurtBox.healthComponent.gameObject.GetComponent<MaulingRock>() != null)
{
return false;
}
if (ignoredHealthComponentList.Contains(hurtBox.healthComponent))
{
return false;
}
if (!FriendlyFireManager.ShouldDirectHitProceed(hurtBox.healthComponent, teamIndex))
{
return false;
}
return true;
}
public bool Fire(List<HurtBox> hitResults = null)
{
if (!hitBoxGroup)
{
return false;
}
HitBox[] hitBoxes = hitBoxGroup.hitBoxes;
foreach (HitBox hitBox in hitBoxes)
{
if (!hitBox || !hitBox.enabled || !hitBox.gameObject || !hitBox.gameObject.activeInHierarchy || !hitBox.transform)
{
continue;
}
Transform transform = hitBox.transform;
Vector3 position = transform.position;
Vector3 halfExtents = transform.lossyScale * 0.5f;
Quaternion rotation = transform.rotation;
if (float.IsInfinity(halfExtents.x) || float.IsInfinity(halfExtents.y) || float.IsInfinity(halfExtents.z))
{
Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxHalfExtents are infinite.");
continue;
}
if (float.IsNaN(halfExtents.x) || float.IsNaN(halfExtents.y) || float.IsNaN(halfExtents.z))
{
Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxHalfExtents are NaN.");
continue;
}
if (float.IsInfinity(position.x) || float.IsInfinity(position.y) || float.IsInfinity(position.z))
{
Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxCenter is infinite.");
continue;
}
if (float.IsNaN(position.x) || float.IsNaN(position.y) || float.IsNaN(position.z))
{
Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxCenter is NaN.");
continue;
}
if (float.IsInfinity(rotation.x) || float.IsInfinity(rotation.y) || float.IsInfinity(rotation.z) || float.IsInfinity(rotation.w))
{
Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxRotation is infinite.");
continue;
}
if (float.IsNaN(rotation.x) || float.IsNaN(rotation.y) || float.IsNaN(rotation.z) || float.IsNaN(rotation.w))
{
Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxRotation is NaN.");
continue;
}
Collider[] colliders;
int num = HGPhysics.OverlapBox(out colliders, position, halfExtents, rotation, LayerIndex.entityPrecise.mask);
cleanupRetriggerList();
int num2 = 0;
for (int j = 0; j < num; j++)
{
if ((bool)colliders[j])
{
HurtBox component = colliders[j].GetComponent<HurtBox>();
if ((bool)component && HurtBoxPassesFilter(component) && (bool)component.transform)
{
Vector3 position2 = component.transform.position;
overlapList.Add(new OverlapInfo
{
hurtBox = component,
hitPosition = position2,
pushDirection = (position2 - position).normalized
});
addIgnoredHitList(component.healthComponent);
hitResults?.Add(component);
num2++;
}
if (num2 >= maximumOverlapTargets)
{
break;
}
}
}
HGPhysics.ReturnResults(colliders);
}
ProcessHits(overlapList);
bool result = overlapList.Count > 0;
overlapList.Clear();
return result;
}
public void addIgnoredHitList(HealthComponent component)
{
if (retriggerTimeout != float.PositiveInfinity)
{
ignoredRemovalList.Enqueue((component, Time.realtimeSinceStartup + retriggerTimeout));
}
ignoredHealthComponentList.Add(component);
}
public void cleanupRetriggerList()
{
while (ignoredRemovalList.Count > 0 && Time.realtimeSinceStartup > ignoredRemovalList.Peek().Item2)
{
(HealthComponent, float) tuple = ignoredRemovalList.Dequeue();
ignoredHealthComponentList.Remove(tuple.Item1);
}
}
[NetworkMessageHandler(msgType = 71, client = false, server = true)]
public static void HandleOverlapAttackHits(NetworkMessage netMsg)
{
netMsg.ReadMessage(incomingMessage);
PerformDamage(incomingMessage.attacker, incomingMessage.inflictor, incomingMessage.damage, incomingMessage.isCrit, incomingMessage.procChainMask, incomingMessage.procCoefficient, incomingMessage.damageColorIndex, incomingMessage.damageType, incomingMessage.forceVector, incomingMessage.pushAwayForce, incomingMessage.overlapInfoList);
}
private void ProcessHits(List<OverlapInfo> hitList)
{
if (hitList.Count == 0)
{
return;
}
Vector3 zero = Vector3.zero;
float num = 1f / (float)hitList.Count;
for (int i = 0; i < hitList.Count; i++)
{
OverlapInfo overlapInfo = hitList[i];
if ((bool)hitEffectPrefab)
{
Vector3 forward = -hitList[i].pushDirection;
EffectManager.SpawnEffect(hitEffectPrefab, new EffectData
{
origin = overlapInfo.hitPosition,
rotation = Util.QuaternionSafeLookRotation(forward),
networkSoundEventIndex = impactSound
}, transmit: true);
}
zero += overlapInfo.hitPosition * num;
SurfaceDefProvider surfaceDefProvider = (overlapInfo.hurtBox ? overlapInfo.hurtBox.GetComponent<SurfaceDefProvider>() : null);
if (!surfaceDefProvider || !surfaceDefProvider.surfaceDef)
{
continue;
}
SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitList[i].hurtBox.collider, hitList[i].hitPosition);
if ((bool)objectSurfaceDef)
{
if ((bool)objectSurfaceDef.impactEffectPrefab)
{
EffectManager.SpawnEffect(objectSurfaceDef.impactEffectPrefab, new EffectData
{
origin = overlapInfo.hitPosition,
rotation = ((overlapInfo.pushDirection == Vector3.zero) ? Quaternion.identity : Util.QuaternionSafeLookRotation(overlapInfo.pushDirection)),
color = objectSurfaceDef.approximateColor,
scale = 2f
}, transmit: true);
}
if (objectSurfaceDef.impactSoundString != null && objectSurfaceDef.impactSoundString.Length != 0)
{
Util.PlaySound(objectSurfaceDef.impactSoundString, hitList[i].hurtBox.gameObject);
}
}
}
lastFireAverageHitPosition = zero;
if (NetworkServer.active)
{
PerformDamage(attacker, inflictor, damage, isCrit, procChainMask, procCoefficient, damageColorIndex, damageType, forceVector, pushAwayForce, hitList);
return;
}
outgoingMessage.attacker = attacker;
outgoingMessage.inflictor = inflictor;
outgoingMessage.damage = damage;
outgoingMessage.isCrit = isCrit;
outgoingMessage.procChainMask = procChainMask;
outgoingMessage.procCoefficient = procCoefficient;
outgoingMessage.damageColorIndex = damageColorIndex;
outgoingMessage.damageType = damageType;
outgoingMessage.forceVector = forceVector;
outgoingMessage.pushAwayForce = pushAwayForce;
Util.CopyList(hitList, outgoingMessage.overlapInfoList);
PlatformSystems.networkManager.client.connection.SendByChannel(71, outgoingMessage, QosChannelIndex.defaultReliable.intVal);
}
private static void PerformDamage(GameObject attacker, GameObject inflictor, float damage, bool isCrit, ProcChainMask procChainMask, float procCoefficient, DamageColorIndex damageColorIndex, DamageTypeCombo damageType, Vector3 forceVector, float pushAwayForce, List<OverlapInfo> hitList)
{
for (int i = 0; i < hitList.Count; i++)
{
OverlapInfo overlapInfo = hitList[i];
if ((bool)overlapInfo.hurtBox)
{
HealthComponent healthComponent = overlapInfo.hurtBox.healthComponent;
if ((bool)healthComponent)
{
DamageInfo damageInfo = new DamageInfo();
damageInfo.attacker = attacker;
damageInfo.inflictor = inflictor;
damageInfo.force = forceVector + pushAwayForce * overlapInfo.pushDirection;
damageInfo.damage = damage;
damageInfo.crit = isCrit;
damageInfo.position = overlapInfo.hitPosition;
damageInfo.procChainMask = procChainMask;
damageInfo.procCoefficient = procCoefficient;
damageInfo.damageColorIndex = damageColorIndex;
damageInfo.damageType = damageType;
damageInfo.ModifyDamageInfo(overlapInfo.hurtBox.damageModifier);
healthComponent.TakeDamage(damageInfo);
GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
}
}
}
}
public void ResetIgnoredHealthComponents()
{
ignoredHealthComponentList.Clear();
ignoredRemovalList.Clear();
}
public void Reset()
{
attacker = null;
inflictor = null;
teamIndex = TeamIndex.Neutral;
forceVector = Vector3.zero;
pushAwayForce = 0f;
damage = 1f;
isCrit = false;
procChainMask.mask = 0u;
procCoefficient = 1f;
hitBoxGroup = null;
hitEffectPrefab = null;
damageColorIndex = DamageColorIndex.Default;
damageType = DamageType.Generic;
ignoredHealthComponentList.Clear();
ignoredRemovalList.Clear();
}
}