using System; using System.Collections.Generic; using Grumpy; using RoR2.Networking; using UnityEngine; using UnityEngine.Networking; namespace RoR2; public class BulletAttack { public enum FalloffModel { None, DefaultBullet, Buckshot } public delegate bool HitCallback(BulletAttack bulletAttack, ref BulletHit hitInfo); public delegate void ModifyOutgoingDamageCallback(BulletAttack bulletAttack, ref BulletHit hitInfo, DamageInfo damageInfo); public delegate bool FilterCallback(BulletAttack bulletAttack, ref BulletHit hitInfo); public class BulletHit { public Vector3 direction; public Vector3 point; public Vector3 surfaceNormal; public float distance; public Collider collider; public HurtBox hitHurtBox; public GameObject entityObject; public HurtBox.DamageModifier damageModifier; public bool isSniperHit; public HurtBox hurtBox; public void Reset() { direction = Vector3.zero; point = Vector3.zero; surfaceNormal = Vector3.zero; distance = 0f; collider = null; entityObject = null; damageModifier = HurtBox.DamageModifier.Normal; isSniperHit = false; hurtBox = null; } } public class BulletHitPool : GenericPool { protected override BulletHit CreateNewObject(bool inPoolEntry = true) { return new BulletHit(); } public void ReturnAllInUse() { if (_InUse != null) { for (int num = _InUse.Count - 1; num >= 0; num--) { ReturnObject(_InUse[num]); } } } } private static GameObject sniperTargetHitEffect; public GameObject owner; public GameObject weapon; public float damage = 1f; public bool isCrit; public float force = 1f; public ProcChainMask procChainMask; public float procCoefficient = 1f; public DamageTypeCombo damageType = DamageType.Generic; public DamageColorIndex damageColorIndex; public bool sniper; public FalloffModel falloffModel = FalloffModel.DefaultBullet; public GameObject tracerEffectPrefab; public GameObject hitEffectPrefab; public string muzzleName = ""; public bool HitEffectNormal = true; public Vector3 origin; private Vector3 _aimVector; private float _maxDistance = 200f; public float radius; public uint bulletCount = 1u; public float minSpread; public float maxSpread; public float spreadPitchScale = 1f; public float spreadYawScale = 1f; public QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.Ignore; private static readonly LayerMask defaultHitMask = (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask; public LayerMask hitMask = defaultHitMask; private static readonly LayerMask defaultStopperMask = defaultHitMask; public LayerMask stopperMask = defaultStopperMask; public bool smartCollision; public bool cheapMultiBullet; public float multiBulletOdds = 0.4f; public bool allowTrajectoryAimAssist = true; public float trajectoryAimAssistMultiplier = 1f; public HitCallback hitCallback; protected DamageInfo _dmgInfo; public static readonly HitCallback defaultHitCallback = DefaultHitCallbackImplementation; public ModifyOutgoingDamageCallback modifyOutgoingDamageCallback; private static NetworkWriter messageWriter = new NetworkWriter(); public FilterCallback filterCallback; public static readonly FilterCallback defaultFilterCallback = DefaultFilterCallbackImplementation; protected static BulletHitPool __BulletHitPool = null; protected static List _BulletHits = new List(); protected static List _IgnoreList = new List(); protected static HashSet _EncounteredEntityObjects = new HashSet(); protected static bool _UsePools = true; protected static EffectData _effectData = null; public Vector3 aimVector { get { return _aimVector; } set { _aimVector = value; _aimVector.Normalize(); } } public float maxDistance { get { return _maxDistance; } set { if (!float.IsInfinity(value) && !float.IsNaN(value)) { _maxDistance = value; return; } Debug.LogFormat("BulletAttack.maxDistance was assigned a value other than a finite number. value={0}", value); } } [Obsolete("Use .defaultHitCallback instead.", false)] public static HitCallback DefaultHitCallback => defaultHitCallback; [Obsolete("Use .defaultFilterCallback instead.", false)] public static FilterCallback DefaultFilterCallback => defaultFilterCallback; protected static BulletHitPool _BulletHitPool { get { if (__BulletHitPool == null) { __BulletHitPool = new BulletHitPool(); __BulletHitPool.AlwaysGrowable = true; __BulletHitPool.Initialize(20, 10); } return __BulletHitPool; } } public static bool UsePools => _UsePools; public BulletAttack() { filterCallback = defaultFilterCallback; hitCallback = defaultHitCallback; } [InitDuringStartup] private static void Init() { LegacyResourcesAPI.LoadAsyncCallback("Prefabs/Effects/ImpactEffects/SniperTargetHitEffect", delegate(GameObject operationResult) { sniperTargetHitEffect = operationResult; }); } public void Reset() { owner = null; weapon = null; damage = 1f; isCrit = false; force = 1f; procChainMask.mask = 0u; procCoefficient = 1f; damageType = DamageType.Generic; damageColorIndex = DamageColorIndex.Default; sniper = false; falloffModel = FalloffModel.DefaultBullet; tracerEffectPrefab = null; hitEffectPrefab = null; muzzleName = ""; HitEffectNormal = true; origin = Vector3.zero; _aimVector = Vector3.zero; _maxDistance = 200f; radius = 0f; bulletCount = 1u; minSpread = 0f; maxSpread = 0f; spreadPitchScale = 1f; spreadYawScale = 1f; queryTriggerInteraction = QueryTriggerInteraction.Ignore; hitMask = defaultHitMask; stopperMask = defaultStopperMask; smartCollision = false; cheapMultiBullet = false; filterCallback = defaultFilterCallback; hitCallback = defaultHitCallback; } private static void PlayHitEffect(BulletAttack bulletAttack, ref BulletHit hitInfo) { if ((bool)bulletAttack.hitEffectPrefab) { EffectManager.SimpleImpactEffect(bulletAttack.hitEffectPrefab, hitInfo.point, bulletAttack.HitEffectNormal ? hitInfo.surfaceNormal : (-hitInfo.direction), transmit: true); } if (hitInfo.isSniperHit && (object)sniperTargetHitEffect != null) { EffectData effectData = new EffectData { origin = hitInfo.point, rotation = Quaternion.LookRotation(-hitInfo.direction) }; effectData.SetHurtBoxReference(hitInfo.hitHurtBox); EffectManager.SpawnEffect(sniperTargetHitEffect, effectData, transmit: true); } if ((bool)hitInfo.collider) { SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitInfo.collider, hitInfo.point); if ((bool)objectSurfaceDef && (bool)objectSurfaceDef.impactEffectPrefab) { EffectData effectData2 = new EffectData { origin = hitInfo.point, rotation = Quaternion.LookRotation(hitInfo.surfaceNormal), color = objectSurfaceDef.approximateColor, surfaceDefIndex = objectSurfaceDef.surfaceDefIndex }; EffectManager.SpawnEffect(objectSurfaceDef.impactEffectPrefab, effectData2, transmit: true); } } } private static bool DefaultHitCallbackImplementation(BulletAttack bulletAttack, ref BulletHit hitInfo) { bool result = false; if ((bool)hitInfo.collider) { result = ((1 << hitInfo.collider.gameObject.layer) & (int)bulletAttack.stopperMask) == 0; } PlayHitEffect(bulletAttack, ref hitInfo); GameObject entityObject = hitInfo.entityObject; if ((bool)entityObject) { float num = CalcFalloffFactor(bulletAttack.falloffModel, hitInfo.distance); DamageInfo damageInfo = new DamageInfo(); damageInfo.damage = bulletAttack.damage * num; damageInfo.crit = bulletAttack.isCrit; damageInfo.attacker = bulletAttack.owner; damageInfo.inflictor = bulletAttack.weapon; damageInfo.position = hitInfo.point; damageInfo.force = hitInfo.direction * (bulletAttack.force * num); damageInfo.procChainMask = bulletAttack.procChainMask; damageInfo.procCoefficient = bulletAttack.procCoefficient; damageInfo.damageType = bulletAttack.damageType; damageInfo.damageColorIndex = bulletAttack.damageColorIndex; damageInfo.ModifyDamageInfo(hitInfo.damageModifier); if (hitInfo.isSniperHit) { damageInfo.crit = true; damageInfo.damageColorIndex = DamageColorIndex.Sniper; } bulletAttack.modifyOutgoingDamageCallback?.Invoke(bulletAttack, ref hitInfo, damageInfo); TeamIndex attackerTeamIndex = TeamIndex.None; if ((bool)bulletAttack.owner) { TeamComponent component = bulletAttack.owner.GetComponent(); if ((bool)component) { attackerTeamIndex = component.teamIndex; } } HealthComponent healthComponent = null; if ((bool)hitInfo.hitHurtBox) { healthComponent = hitInfo.hitHurtBox.healthComponent; } bool flag = (bool)healthComponent && FriendlyFireManager.ShouldDirectHitProceed(healthComponent, attackerTeamIndex); if (NetworkServer.active) { if (flag) { healthComponent.TakeDamage(damageInfo); GlobalEventManager.instance.OnHitEnemy(damageInfo, hitInfo.entityObject); } GlobalEventManager.instance.OnHitAll(damageInfo, hitInfo.entityObject); } else if (ClientScene.ready) { messageWriter.StartMessage(53); int currentLogLevel = LogFilter.currentLogLevel; LogFilter.currentLogLevel = 4; messageWriter.Write(entityObject); LogFilter.currentLogLevel = currentLogLevel; messageWriter.Write(damageInfo); messageWriter.Write(flag); messageWriter.FinishMessage(); ClientScene.readyConnection.SendWriter(messageWriter, QosChannelIndex.defaultReliable.intVal); } } return result; } private static float CalcFalloffFactor(FalloffModel falloffModel, float distance) { return falloffModel switch { FalloffModel.DefaultBullet => 0.5f + Mathf.Clamp01(Mathf.InverseLerp(60f, 25f, distance)) * 0.5f, FalloffModel.Buckshot => 0.25f + Mathf.Clamp01(Mathf.InverseLerp(25f, 7f, distance)) * 0.75f, _ => 1f, }; } private static bool DefaultFilterCallbackImplementation(BulletAttack bulletAttack, ref BulletHit hitInfo) { HurtBox component = hitInfo.collider.GetComponent(); if ((bool)component && (bool)component.healthComponent && component.healthComponent.gameObject == bulletAttack.weapon) { return false; } return hitInfo.entityObject != bulletAttack.weapon; } private void InitBulletHitFromOriginHit(ref BulletHit bulletHit, Vector3 direction, Collider hitCollider) { bulletHit.direction = direction; bulletHit.point = origin; bulletHit.surfaceNormal = -direction; bulletHit.distance = 0f; bulletHit.collider = hitCollider; HurtBox component = bulletHit.collider.GetComponent(); bulletHit.hitHurtBox = component; bulletHit.entityObject = (((bool)component && (bool)component.healthComponent) ? component.healthComponent.gameObject : bulletHit.collider.gameObject); bulletHit.damageModifier = (component ? component.damageModifier : HurtBox.DamageModifier.Normal); } private void InitBulletHitFromRaycastHit(ref BulletHit bulletHit, Vector3 origin, Vector3 direction, ref RaycastHit raycastHit) { bulletHit.direction = direction; bulletHit.surfaceNormal = raycastHit.normal; bulletHit.distance = raycastHit.distance; bulletHit.collider = raycastHit.collider; bulletHit.point = ((bulletHit.distance == 0f) ? origin : raycastHit.point); HurtBox component = bulletHit.collider.GetComponent(); bulletHit.hitHurtBox = component; bulletHit.entityObject = (((bool)component && (bool)component.healthComponent) ? component.healthComponent.gameObject : bulletHit.collider.gameObject); bulletHit.damageModifier = (component ? component.damageModifier : HurtBox.DamageModifier.Normal); } private bool ProcessHit(ref BulletHit hitInfo) { if (!filterCallback(this, ref hitInfo)) { return true; } if (sniper) { hitInfo.isSniperHit = IsSniperTargetHit(in hitInfo); } return hitCallback(this, ref hitInfo); } private static bool IsSniperTargetHit(in BulletHit hitInfo) { if ((bool)hitInfo.hitHurtBox && (bool)hitInfo.hitHurtBox.hurtBoxGroup) { HurtBox[] hurtBoxes = hitInfo.hitHurtBox.hurtBoxGroup.hurtBoxes; foreach (HurtBox hurtBox in hurtBoxes) { if ((bool)hurtBox && hurtBox.isSniperTarget && Vector3.ProjectOnPlane(hitInfo.point - hurtBox.transform.position, hitInfo.direction).sqrMagnitude <= HurtBox.sniperTargetRadiusSqr) { return true; } } } return false; } private GameObject ProcessHitList(List hits, ref Vector3 endPosition, List ignoreList) { int count = hits.Count; int[] array = new int[count]; for (int i = 0; i < count; i++) { array[i] = i; } for (int j = 0; j < count; j++) { float distance = maxDistance; int num = j; for (int k = j; k < count; k++) { int index = array[k]; if (hits[index].distance < distance) { distance = hits[index].distance; num = k; } } GameObject entityObject = hits[array[num]].entityObject; if (!ignoreList.Contains(entityObject)) { ignoreList.Add(entityObject); BulletHit hitInfo = hits[array[num]]; if (!ProcessHit(ref hitInfo)) { endPosition = hits[array[num]].point; return entityObject; } } array[num] = array[j]; } return null; } private static GameObject LookUpColliderEntityObject(Collider collider) { HurtBox component = collider.GetComponent(); if (!component || !component.healthComponent) { return collider.gameObject; } return component.healthComponent.gameObject; } private static Collider[] PhysicsOverlapPoint(Vector3 point, int layerMask = -1, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.Ignore) { return Physics.OverlapBox(point, Vector3.zero, Quaternion.identity, layerMask, queryTriggerInteraction); } public void Fire() { if (allowTrajectoryAimAssist) { aimVector = TrajectoryAimAssist.ApplyTrajectoryAimAssist(aimVector, origin, maxDistance, owner, weapon, trajectoryAimAssistMultiplier); } Vector3[] array = new Vector3[bulletCount]; Vector3 up = Vector3.up; Vector3 axis = Vector3.Cross(up, aimVector); for (int i = 0; i < bulletCount; i++) { float x = UnityEngine.Random.Range(minSpread, maxSpread); float z = UnityEngine.Random.Range(0f, 360f); Vector3 vector = Quaternion.Euler(0f, 0f, z) * (Quaternion.Euler(x, 0f, 0f) * Vector3.forward); float y = vector.y; vector.y = 0f; float angle = (Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f) * spreadYawScale; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f * spreadPitchScale; array[i] = Quaternion.AngleAxis(angle, up) * (Quaternion.AngleAxis(angle2, axis) * aimVector); } int muzzleIndex = -1; if (!weapon) { weapon = owner; } if ((bool)weapon) { ModelLocator component = weapon.GetComponent(); if ((bool)component && (bool)component.modelTransform) { ChildLocator component2 = component.modelTransform.GetComponent(); if ((bool)component2) { muzzleIndex = component2.FindChildIndex(muzzleName); } } } Vector3 axis2 = Vector3.Cross(Vector3.up, aimVector); Vector3 forward = Vector3.forward; if (cheapMultiBullet) { float x2 = UnityEngine.Random.Range(minSpread, maxSpread); float z2 = UnityEngine.Random.Range(0f, 360f); Vector3 vector2 = Quaternion.Euler(0f, 0f, z2) * (Quaternion.Euler(x2, 0f, 0f) * Vector3.forward); float y2 = vector2.y; vector2.y = 0f; float angle3 = (Mathf.Atan2(vector2.z, vector2.x) * 57.29578f - 90f) * spreadYawScale; float angle4 = Mathf.Atan2(y2, vector2.magnitude) * 57.29578f * spreadPitchScale; forward = Quaternion.AngleAxis(angle3, Vector3.up) * (Quaternion.AngleAxis(angle4, axis2) * aimVector); FireMulti(forward, muzzleIndex); return; } for (int j = 0; j < bulletCount; j++) { float x3 = UnityEngine.Random.Range(minSpread, maxSpread); float z3 = UnityEngine.Random.Range(0f, 360f); Vector3 vector3 = Quaternion.Euler(0f, 0f, z3) * (Quaternion.Euler(x3, 0f, 0f) * Vector3.forward); float y3 = vector3.y; vector3.y = 0f; float angle5 = (Mathf.Atan2(vector3.z, vector3.x) * 57.29578f - 90f) * spreadYawScale; float angle6 = Mathf.Atan2(y3, vector3.magnitude) * 57.29578f * spreadPitchScale; forward = Quaternion.AngleAxis(angle5, Vector3.up) * (Quaternion.AngleAxis(angle6, axis2) * aimVector); FireSingle(forward, muzzleIndex); } } public Vector3 Fire_ReturnHit() { int muzzleIndex = -1; _ = origin; if (!weapon) { weapon = owner; } if ((bool)weapon) { ModelLocator component = weapon.GetComponent(); if ((bool)component && (bool)component.modelTransform) { ChildLocator component2 = component.modelTransform.GetComponent(); if ((bool)component2) { muzzleIndex = component2.FindChildIndex(muzzleName); } } } Vector3 axis = Vector3.Cross(Vector3.up, aimVector); Vector3 forward = Vector3.forward; Vector3 result = Vector3.zero; for (int i = 0; i < bulletCount; i++) { float x = UnityEngine.Random.Range(minSpread, maxSpread); float z = UnityEngine.Random.Range(0f, 360f); Vector3 vector = Quaternion.Euler(0f, 0f, z) * (Quaternion.Euler(x, 0f, 0f) * Vector3.forward); float y = vector.y; vector.y = 0f; float angle = (Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f) * spreadYawScale; float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f * spreadPitchScale; forward = Quaternion.AngleAxis(angle, Vector3.up) * (Quaternion.AngleAxis(angle2, axis) * aimVector); result = FireSingle_ReturnHit(forward, muzzleIndex); } return result; } public static void TogglePooling() { _UsePools = !_UsePools; Debug.LogFormat("BulletAttack pooling {0}", _UsePools ? "ENABLED" : "DISABLED"); } public static void DumpPools() { Debug.LogFormat("BulletAttack Pool: Pooled {0}, InUse {1}", _BulletHitPool.PoolCount(), _BulletHitPool.InUseCount()); } protected static BulletHit GetBulletHit() { BulletHit @object = _BulletHitPool.GetObject(); @object.Reset(); return @object; } private void FireSingle(Vector3 normal, int muzzleIndex) { if (_UsePools) { float distance = maxDistance; Vector3 endPosition = origin + normal * maxDistance; _BulletHits.Clear(); bool num = radius == 0f || smartCollision; bool flag = radius != 0f; if (smartCollision) { _EncounteredEntityObjects.Clear(); } if (num) { int num2 = 0; num2 = HGPhysics.RaycastAll(out var hits, origin, normal, distance, hitMask, queryTriggerInteraction); for (int i = 0; i < num2; i++) { BulletHit bulletHit = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit, origin, normal, ref hits[i]); _BulletHits.Add(bulletHit); if (smartCollision) { _EncounteredEntityObjects.Add(bulletHit.entityObject); } if (bulletHit.distance < distance) { distance = bulletHit.distance; } } HGPhysics.ReturnResults(hits); } if (flag) { LayerMask layerMask = hitMask; if (smartCollision) { layerMask = (int)layerMask & ~(int)LayerIndex.world.mask; } int num3 = 0; num3 = HGPhysics.SphereCastAll(out var hits2, origin, radius, normal, distance, layerMask, queryTriggerInteraction); for (int j = 0; j < num3; j++) { BulletHit bulletHit2 = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit2, origin, normal, ref hits2[j]); if (!smartCollision || !_EncounteredEntityObjects.Contains(bulletHit2.entityObject)) { _BulletHits.Add(bulletHit2); } } HGPhysics.ReturnResults(hits2); } _IgnoreList.Clear(); ProcessHitList(_BulletHits, ref endPosition, _IgnoreList); if ((bool)tracerEffectPrefab) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.Reset(); _effectData.origin = endPosition; _effectData.start = origin; _effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, _effectData, transmit: true); } _BulletHitPool.ReturnAllInUse(); _EncounteredEntityObjects.Clear(); return; } float distance2 = maxDistance; Vector3 endPosition2 = origin + normal * maxDistance; List list = new List(); bool num4 = radius == 0f || smartCollision; bool flag2 = radius != 0f; HashSet hashSet = null; if (smartCollision) { hashSet = new HashSet(); } if (num4) { int num5 = 0; num5 = HGPhysics.RaycastAll(out var hits3, origin, normal, distance2, hitMask, queryTriggerInteraction); for (int k = 0; k < num5; k++) { BulletHit bulletHit3 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit3, origin, normal, ref hits3[k]); list.Add(bulletHit3); if (smartCollision) { hashSet.Add(bulletHit3.entityObject); } if (bulletHit3.distance < distance2) { distance2 = bulletHit3.distance; } } HGPhysics.ReturnResults(hits3); } if (flag2) { LayerMask layerMask2 = hitMask; if (smartCollision) { layerMask2 = (int)layerMask2 & ~(int)LayerIndex.world.mask; } int num6 = 0; num6 = HGPhysics.SphereCastAll(out var hits4, origin, radius, normal, distance2, layerMask2, queryTriggerInteraction); for (int l = 0; l < num6; l++) { BulletHit bulletHit4 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit4, origin, normal, ref hits4[l]); if (!smartCollision || !hashSet.Contains(bulletHit4.entityObject)) { list.Add(bulletHit4); } } HGPhysics.ReturnResults(hits4); } ProcessHitList(list, ref endPosition2, new List()); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = endPosition2, start = origin }; effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } } private void FireMulti(Vector3 normal, int muzzleIndex) { if (_UsePools) { float distance = maxDistance; Vector3 endPosition = origin + normal * maxDistance; _BulletHits.Clear(); bool num = radius == 0f || smartCollision; bool flag = radius != 0f; if (smartCollision) { _EncounteredEntityObjects.Clear(); } if (num) { int num2 = 0; num2 = HGPhysics.RaycastAll(out var hits, origin, normal, distance, hitMask, queryTriggerInteraction); for (int i = 0; i < num2; i++) { BulletHit bulletHit = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit, origin, normal, ref hits[i]); _BulletHits.Add(bulletHit); if (smartCollision) { _EncounteredEntityObjects.Add(bulletHit.entityObject); } if (bulletHit.distance < distance) { distance = bulletHit.distance; } } HGPhysics.ReturnResults(hits); } if (flag) { LayerMask layerMask = hitMask; if (smartCollision) { layerMask = (int)layerMask & ~(int)LayerIndex.world.mask; } int num3 = 0; num3 = HGPhysics.SphereCastAll(out var hits2, origin, radius, normal, distance, layerMask, queryTriggerInteraction); for (int j = 0; j < num3; j++) { BulletHit bulletHit2 = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit2, origin, normal, ref hits2[j]); if (!smartCollision || !_EncounteredEntityObjects.Contains(bulletHit2.entityObject)) { _BulletHits.Add(bulletHit2); } } HGPhysics.ReturnResults(hits2); } _IgnoreList.Clear(); ProcessHitList(_BulletHits, ref endPosition, _IgnoreList); if ((bool)tracerEffectPrefab) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.Reset(); _effectData.origin = endPosition; _effectData.start = origin; _effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, _effectData, transmit: true); } _BulletHitPool.ReturnAllInUse(); _EncounteredEntityObjects.Clear(); return; } float distance2 = maxDistance; Vector3 endPosition2 = origin + normal * maxDistance; List list = new List(); bool num4 = radius == 0f || smartCollision; bool flag2 = radius != 0f; HashSet hashSet = null; if (smartCollision) { hashSet = new HashSet(); } if (num4) { int num5 = 0; num5 = HGPhysics.RaycastAll(out var hits3, origin, normal, distance2, hitMask, queryTriggerInteraction); for (int k = 0; k < num5; k++) { BulletHit bulletHit3 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit3, origin, normal, ref hits3[k]); list.Add(bulletHit3); if (smartCollision) { hashSet.Add(bulletHit3.entityObject); } if (bulletHit3.distance < distance2) { distance2 = bulletHit3.distance; } } HGPhysics.ReturnResults(hits3); } if (flag2) { LayerMask layerMask2 = hitMask; if (smartCollision) { layerMask2 = (int)layerMask2 & ~(int)LayerIndex.world.mask; } int num6 = 0; num6 = HGPhysics.SphereCastAll(out var hits4, origin, radius, normal, distance2, layerMask2, queryTriggerInteraction); for (int l = 0; l < num6; l++) { BulletHit bulletHit4 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit4, origin, normal, ref hits4[l]); if (!smartCollision || !hashSet.Contains(bulletHit4.entityObject)) { list.Add(bulletHit4); } } HGPhysics.ReturnResults(hits4); } ProcessHitList(list, ref endPosition2, new List()); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = endPosition2, start = origin }; effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } } private Vector3 FireSingle_ReturnHit(Vector3 normal, int muzzleIndex) { Vector3 endPosition; if (_UsePools) { float distance = maxDistance; endPosition = origin + normal * maxDistance; _BulletHits.Clear(); bool num = radius == 0f || smartCollision; bool flag = radius != 0f; if (smartCollision) { _EncounteredEntityObjects.Clear(); } if (num) { int num2 = 0; num2 = HGPhysics.RaycastAll(out var hits, origin, normal, distance, hitMask, queryTriggerInteraction); for (int i = 0; i < num2; i++) { BulletHit bulletHit = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit, origin, normal, ref hits[i]); _BulletHits.Add(bulletHit); if (smartCollision) { _EncounteredEntityObjects.Add(bulletHit.entityObject); } if (bulletHit.distance < distance) { distance = bulletHit.distance; } } HGPhysics.ReturnResults(hits); } if (flag) { LayerMask layerMask = hitMask; if (smartCollision) { layerMask = (int)layerMask & ~(int)LayerIndex.world.mask; } int num3 = 0; num3 = HGPhysics.SphereCastAll(out var hits2, origin, radius, normal, distance, layerMask, queryTriggerInteraction); for (int j = 0; j < num3; j++) { BulletHit bulletHit2 = GetBulletHit(); InitBulletHitFromRaycastHit(ref bulletHit2, origin, normal, ref hits2[j]); if (!smartCollision || !_EncounteredEntityObjects.Contains(bulletHit2.entityObject)) { _BulletHits.Add(bulletHit2); } } HGPhysics.ReturnResults(hits2); } _IgnoreList.Clear(); ProcessHitList(_BulletHits, ref endPosition, _IgnoreList); if ((bool)tracerEffectPrefab) { if (_effectData == null) { _effectData = new EffectData(); } _effectData.Reset(); _effectData.origin = endPosition; _effectData.start = origin; _effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, _effectData, transmit: true); } _BulletHitPool.ReturnAllInUse(); _EncounteredEntityObjects.Clear(); } else { float distance2 = maxDistance; endPosition = origin + normal * maxDistance; List list = new List(); bool num4 = radius == 0f || smartCollision; bool flag2 = radius != 0f; HashSet hashSet = null; if (smartCollision) { hashSet = new HashSet(); } if (num4) { int num5 = 0; num5 = HGPhysics.RaycastAll(out var hits3, origin, normal, distance2, hitMask, queryTriggerInteraction); for (int k = 0; k < num5; k++) { BulletHit bulletHit3 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit3, origin, normal, ref hits3[k]); list.Add(bulletHit3); if (smartCollision) { hashSet.Add(bulletHit3.entityObject); } if (bulletHit3.distance < distance2) { distance2 = bulletHit3.distance; } } HGPhysics.ReturnResults(hits3); } if (flag2) { LayerMask layerMask2 = hitMask; if (smartCollision) { layerMask2 = (int)layerMask2 & ~(int)LayerIndex.world.mask; } int num6 = 0; num6 = HGPhysics.SphereCastAll(out var hits4, origin, radius, normal, distance2, layerMask2, queryTriggerInteraction); for (int l = 0; l < num6; l++) { BulletHit bulletHit4 = new BulletHit(); InitBulletHitFromRaycastHit(ref bulletHit4, origin, normal, ref hits4[l]); if (!smartCollision || !hashSet.Contains(bulletHit4.entityObject)) { list.Add(bulletHit4); } } HGPhysics.ReturnResults(hits4); } ProcessHitList(list, ref endPosition, new List()); if ((bool)tracerEffectPrefab) { EffectData effectData = new EffectData { origin = endPosition, start = origin }; effectData.SetChildLocatorTransformReference(weapon, muzzleIndex); EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true); } } return endPosition; } [NetworkMessageHandler(msgType = 53, server = true)] private static void HandleBulletDamage(NetworkMessage netMsg) { NetworkReader reader = netMsg.reader; GameObject gameObject = reader.ReadGameObject(); DamageInfo damageInfo = reader.ReadDamageInfo(); if (reader.ReadBoolean() && (bool)gameObject) { HealthComponent component = gameObject.GetComponent(); if ((bool)component) { component.TakeDamage(damageInfo); } GlobalEventManager.instance.OnHitEnemy(damageInfo, gameObject); } GlobalEventManager.instance.OnHitAll(damageInfo, gameObject); } }