using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using Facepunch.Steamworks; using JetBrains.Annotations; using Rewired; using RoR2.Networking; using RoR2.Projectile; using UnityEngine; using UnityEngine.Networking; namespace RoR2; public static class Util { private struct EasyTargetCandidate { public Transform transform; public float score; public float distance; } public const string attackSpeedRtpcName = "attackSpeed"; private static readonly string strBackslash = "\\"; private static readonly string strBackslashBackslash = strBackslash + strBackslash; private static readonly string strQuote = "\""; private static readonly string strBackslashQuote = strBackslash + strQuote; private static readonly Regex backlashSearch = new Regex(strBackslashBackslash); private static readonly Regex quoteSearch = new Regex(strQuote); public static readonly DateTime dateZero = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); public static bool useCachedNetWriter = false; public static bool breakInVerify = true; public static bool logVerify = true; public static bool cacheBulletHitHurtBox = true; private static readonly StringBuilder sharedStringBuilder = new StringBuilder(); private static readonly Stack sharedStringStack = new Stack(); private static readonly string cloneString = "(Clone)"; public static void CleanseBody(CharacterBody characterBody, bool removeDebuffs, bool removeBuffs, bool removeCooldownBuffs, bool removeDots, bool removeStun, bool removeNearbyProjectiles) { if (removeDebuffs || removeBuffs || removeCooldownBuffs) { BuffIndex buffIndex = (BuffIndex)0; for (BuffIndex buffCount = (BuffIndex)BuffCatalog.buffCount; buffIndex < buffCount; buffIndex++) { BuffDef buffDef = BuffCatalog.GetBuffDef(buffIndex); if ((buffDef.isDebuff && removeDebuffs) || (buffDef.isCooldown && removeCooldownBuffs) || (!buffDef.isDebuff && !buffDef.isCooldown && removeBuffs)) { characterBody.ClearTimedBuffs(buffIndex); } } } if (removeDots) { DotController.RemoveAllDots(characterBody.gameObject); } if (removeStun) { SetStateOnHurt component = characterBody.GetComponent(); if ((bool)component) { component.Cleanse(); } } if (!removeNearbyProjectiles) { return; } float num = 6f * 6f; TeamIndex teamIndex = characterBody.teamComponent.teamIndex; List instancesList = InstanceTracker.GetInstancesList(); List list = new List(); int i = 0; for (int count = instancesList.Count; i < count; i++) { ProjectileController projectileController = instancesList[i]; if (!projectileController.cannotBeDeleted && projectileController.teamFilter.teamIndex != teamIndex && (projectileController.transform.position - characterBody.corePosition).sqrMagnitude < num) { list.Add(projectileController); } } int j = 0; for (int count2 = list.Count; j < count2; j++) { ProjectileController projectileController2 = list[j]; if ((bool)projectileController2) { UnityEngine.Object.Destroy(projectileController2.gameObject); } } } public static WeightedSelection CreateReasonableDirectorCardSpawnList(float availableCredit, int maximumNumberToSpawnBeforeSkipping, int minimumToSpawn) { WeightedSelection monsterSelection = ClassicStageInfo.instance.monsterSelection; WeightedSelection weightedSelection = new WeightedSelection(); for (int i = 0; i < monsterSelection.Count; i++) { DirectorCard value = monsterSelection.choices[i].value; float combatDirectorHighestEliteCostMultiplier = CombatDirector.CalcHighestEliteCostMultiplier(value.spawnCard.eliteRules); if (DirectorCardIsReasonableChoice(availableCredit, maximumNumberToSpawnBeforeSkipping, minimumToSpawn, value, combatDirectorHighestEliteCostMultiplier)) { weightedSelection.AddChoice(value, monsterSelection.choices[i].weight); } } return weightedSelection; } public static bool DirectorCardIsReasonableChoice(float availableCredit, int maximumNumberToSpawnBeforeSkipping, int minimumToSpawn, DirectorCard card, float combatDirectorHighestEliteCostMultiplier) { float num = (float)(card.cost * maximumNumberToSpawnBeforeSkipping) * ((card.spawnCard as CharacterSpawnCard).noElites ? 1f : combatDirectorHighestEliteCostMultiplier); if (card.IsAvailable() && (float)card.cost * (float)minimumToSpawn <= availableCredit) { return num / 2f > availableCredit; } return false; } public static CharacterBody HurtBoxColliderToBody(Collider collider) { HurtBox component = collider.GetComponent(); if ((bool)component && (bool)component.healthComponent) { return component.healthComponent.body; } return null; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ConvertAmplificationPercentageIntoReductionPercentage(float amplificationPercentage) { return (1f - 100f / (100f + amplificationPercentage)) * 100f; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ConvertAmplificationPercentageIntoReductionNormalized(float amplificationNormal) { return (1f - 1f / (1f + amplificationNormal)) * 1f; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NonlinearLerp(float min, float max, float amplifactionNormalixed) { return Mathf.Lerp(min, max, ConvertAmplificationPercentageIntoReductionNormalized(amplifactionNormalixed)); } public static Vector3 ClosestPointOnLine(Vector3 vA, Vector3 vB, Vector3 vPoint) { Vector3 rhs = vPoint - vA; Vector3 normalized = (vB - vA).normalized; float num = Vector3.Distance(vA, vB); float num2 = Vector3.Dot(normalized, rhs); if (num2 <= 0f) { return vA; } if (num2 >= num) { return vB; } Vector3 vector = normalized * num2; return vA + vector; } public static CharacterBody TryToCreateGhost(CharacterBody targetBody, CharacterBody ownerBody, int duration) { if (!NetworkServer.active) { UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterBody RoR2.Util::TryToCreateGhost(RoR2.CharacterBody, RoR2.CharacterBody, int)' called on client"); return null; } if (!targetBody) { return null; } GameObject bodyPrefab = BodyCatalog.FindBodyPrefab(targetBody); if (!bodyPrefab) { return null; } CharacterMaster characterMaster = MasterCatalog.allAiMasters.FirstOrDefault((CharacterMaster master) => master.bodyPrefab == bodyPrefab); if (!characterMaster) { return null; } MasterSummon obj = new MasterSummon { masterPrefab = characterMaster.gameObject, ignoreTeamMemberLimit = false, position = targetBody.footPosition }; CharacterDirection component = targetBody.GetComponent(); obj.rotation = (component ? Quaternion.Euler(0f, component.yaw, 0f) : targetBody.transform.rotation); obj.summonerBodyObject = (ownerBody ? ownerBody.gameObject : null); obj.inventoryToCopy = targetBody.inventory; obj.useAmbientLevel = null; obj.preSpawnSetupCallback = (Action)Delegate.Combine(obj.preSpawnSetupCallback, new Action(PreSpawnSetup)); CharacterMaster characterMaster2 = obj.Perform(); if (!characterMaster2) { return null; } CharacterBody body = characterMaster2.GetBody(); if ((bool)body) { EntityStateMachine[] components = body.GetComponents(); foreach (EntityStateMachine obj2 in components) { obj2.initialStateType = obj2.mainStateType; } } return body; void PreSpawnSetup(CharacterMaster newMaster) { newMaster.inventory.GiveItem(RoR2Content.Items.Ghost); newMaster.inventory.GiveItem(RoR2Content.Items.HealthDecay, duration); newMaster.inventory.GiveItem(RoR2Content.Items.BoostDamage, 150); } } public static float OnHitProcDamage(float damageThatProccedIt, float damageStat, float damageCoefficient) { float b = damageThatProccedIt * damageCoefficient; return Mathf.Max(1f, b); } public static float OnKillProcDamage(float baseDamage, float damageCoefficient) { return baseDamage * damageCoefficient; } public static Quaternion QuaternionSafeLookRotation(Vector3 forward) { Quaternion result = Quaternion.identity; if (forward.sqrMagnitude > Mathf.Epsilon && forward != Vector3.zero) { result = Quaternion.LookRotation(forward); } return result; } public static Quaternion QuaternionSafeLookRotation(Vector3 forward, Vector3 upwards) { Quaternion result = Quaternion.identity; if (forward.sqrMagnitude > Mathf.Epsilon) { result = Quaternion.LookRotation(forward, upwards); } return result; } public static bool HasParameterOfType(Animator animator, string name, AnimatorControllerParameterType type) { AnimatorControllerParameter[] parameters = animator.parameters; foreach (AnimatorControllerParameter animatorControllerParameter in parameters) { if (animatorControllerParameter.type == type && animatorControllerParameter.name == name) { return true; } } return false; } public static uint PlaySound(string soundString, GameObject gameObject) { if (string.IsNullOrEmpty(soundString)) { return 0u; } if (gameObject == null) { return AkSoundEngine.PostEvent(soundString, ulong.MaxValue); } return AkSoundEngine.PostEvent(soundString, gameObject); } public static uint PlaySound(string soundString, GameObject gameObject, string RTPCstring, float RTPCvalue) { uint num = PlaySound(soundString, gameObject); if (num != 0) { AkSoundEngine.SetRTPCValueByPlayingID(RTPCstring, RTPCvalue, num); } return num; } public static uint PlayAttackSpeedSound(string soundString, GameObject gameObject, float attackSpeedStat) { uint num = PlaySound(soundString, gameObject); if (num != 0) { float in_value = CalculateAttackSpeedRtpcValue(attackSpeedStat); AkSoundEngine.SetRTPCValueByPlayingID("attackSpeed", in_value, num); } return num; } public static float CalculateAttackSpeedRtpcValue(float attackSpeedStat) { float num = Mathf.Log(attackSpeedStat, 2f); return 1200f * num / 96f + 50f; } public static void RotateAwayFromWalls(float raycastLength, int raycastCount, Vector3 raycastOrigin, Transform referenceTransform) { float num = 360f / (float)raycastCount; float angle = 0f; float num2 = 0f; for (int i = 0; i < raycastCount; i++) { Vector3 direction = Quaternion.Euler(0f, num * (float)i, 0f) * Vector3.forward; float num3 = raycastLength; if (Physics.Raycast(raycastOrigin, direction, out var hitInfo, raycastLength, LayerIndex.world.mask)) { num3 = hitInfo.distance; } if (hitInfo.distance > num2) { angle = num * (float)i; num2 = num3; } } referenceTransform.Rotate(Vector3.up, angle, Space.Self); } public static string GetActionDisplayString(ActionElementMap actionElementMap) { if (actionElementMap == null) { return ""; } return actionElementMap.elementIdentifierName switch { "Left Mouse Button" => "M1", "Right Mouse Button" => "M2", "Left Shift" => "Shift", _ => actionElementMap.elementIdentifierName, }; } public static float AngleSigned(Vector3 v1, Vector3 v2, Vector3 n) { return Mathf.Atan2(Vector3.Dot(n, Vector3.Cross(v1, v2)), Vector3.Dot(v1, v2)) * 57.29578f; } public static float Remap(float value, float inMin, float inMax, float outMin, float outMax) { return outMin + (value - inMin) / (inMax - inMin) * (outMax - outMin); } public static bool HasAnimationParameter(string paramName, Animator animator) { AnimatorControllerParameter[] parameters = animator.parameters; for (int i = 0; i < parameters.Length; i++) { if (parameters[i].name == paramName) { return true; } } return false; } public static bool HasAnimationParameter(int paramHash, AnimatorControllerParameter[] parameters) { int i = 0; for (int num = parameters.Length; i < num; i++) { if (parameters[i].nameHash == paramHash) { return true; } } return false; } public static bool HasAnimationParameter(int paramHash, Animator animator) { return HasAnimationParameter(paramHash, animator.parameters); } public static bool CheckRoll(float percentChance, float luck = 0f, CharacterMaster effectOriginMaster = null) { if (percentChance <= 0f) { return false; } int num = Mathf.CeilToInt(Mathf.Abs(luck)); float num2 = UnityEngine.Random.Range(0f, 100f); float num3 = num2; for (int i = 0; i < num; i++) { float b = UnityEngine.Random.Range(0f, 100f); num2 = ((luck > 0f) ? Mathf.Min(num2, b) : Mathf.Max(num2, b)); } if (num2 <= percentChance) { if (num3 > percentChance && (bool)effectOriginMaster) { GameObject bodyObject = effectOriginMaster.GetBodyObject(); if ((bool)bodyObject) { CharacterBody component = bodyObject.GetComponent(); if ((bool)component) { component.wasLucky = true; } } } return true; } return false; } public static bool CheckRoll(float percentChance, CharacterMaster master) { return CheckRoll(percentChance, master ? master.luck : 0f, master); } public static float EstimateSurfaceDistance(Collider a, Collider b) { Vector3 center = a.bounds.center; Vector3 center2 = b.bounds.center; RaycastHit hitInfo; Vector3 a2 = ((!b.Raycast(new Ray(center, center2 - center), out hitInfo, float.PositiveInfinity)) ? b.ClosestPointOnBounds(center) : hitInfo.point); Vector3 b2 = ((!a.Raycast(new Ray(center2, center - center2), out hitInfo, float.PositiveInfinity)) ? a.ClosestPointOnBounds(center2) : hitInfo.point); return Vector3.Distance(a2, b2); } public static bool HasEffectiveAuthority(GameObject gameObject) { if ((bool)gameObject) { return HasEffectiveAuthority(gameObject.GetComponent()); } return false; } public static bool HasEffectiveAuthority(NetworkIdentity networkIdentity) { if ((bool)networkIdentity) { if (!networkIdentity.hasAuthority) { if (NetworkServer.active) { return networkIdentity.clientAuthorityOwner == null; } return false; } return true; } return false; } public static float CalculateSphereVolume(float radius) { return 4.1887903f * radius * radius * radius; } public static float CalculateCylinderVolume(float radius, float height) { return MathF.PI * radius * radius * height; } public static float CalculateColliderVolume(Collider collider) { Vector3 lossyScale = collider.transform.lossyScale; float num = lossyScale.x * lossyScale.y * lossyScale.z; float num2 = 0f; if (collider is BoxCollider) { Vector3 size = ((BoxCollider)collider).size; num2 = size.x * size.y * size.z; } else if (collider is SphereCollider) { num2 = CalculateSphereVolume(((SphereCollider)collider).radius); } else if (collider is CapsuleCollider) { CapsuleCollider obj = (CapsuleCollider)collider; float radius = obj.radius; float num3 = CalculateSphereVolume(radius); float num4 = Mathf.Max(obj.height - num3, 0f); float num5 = MathF.PI * radius * radius * num4; num2 = num3 + num5; } else if (collider is CharacterController) { CharacterController obj2 = (CharacterController)collider; float radius2 = obj2.radius; float num6 = CalculateSphereVolume(radius2); float num7 = Mathf.Max(obj2.height - num6, 0f); float num8 = MathF.PI * radius2 * radius2 * num7; num2 = num6 + num8; } return num2 * num; } public static Vector3 RandomColliderVolumePoint(Collider collider) { Transform transform = collider.transform; Vector3 position = Vector3.zero; if (collider is BoxCollider) { BoxCollider obj = (BoxCollider)collider; Vector3 size = obj.size; Vector3 center = obj.center; position = new Vector3(center.x + UnityEngine.Random.Range(size.x * -0.5f, size.x * 0.5f), center.y + UnityEngine.Random.Range(size.y * -0.5f, size.y * 0.5f), center.z + UnityEngine.Random.Range(size.z * -0.5f, size.z * 0.5f)); } else if (collider is SphereCollider) { SphereCollider sphereCollider = (SphereCollider)collider; position = sphereCollider.center + UnityEngine.Random.insideUnitSphere * sphereCollider.radius; } else if (collider is CapsuleCollider) { CapsuleCollider capsuleCollider = (CapsuleCollider)collider; float radius = capsuleCollider.radius; float num = Mathf.Max(capsuleCollider.height - radius, 0f); float num2 = CalculateSphereVolume(radius); float num3 = CalculateCylinderVolume(radius, num); float maxInclusive = num2 + num3; if (UnityEngine.Random.Range(0f, maxInclusive) <= num2) { position = UnityEngine.Random.insideUnitSphere * radius; float num4 = ((float)UnityEngine.Random.Range(0, 2) * 2f - 1f) * num * 0.5f; switch (capsuleCollider.direction) { case 0: position.x += num4; break; case 1: position.y += num4; break; case 2: position.z += num4; break; } } else { Vector2 vector = UnityEngine.Random.insideUnitCircle * radius; float num5 = UnityEngine.Random.Range(num * -0.5f, num * 0.5f); switch (capsuleCollider.direction) { case 0: position = new Vector3(num5, vector.x, vector.y); break; case 1: position = new Vector3(vector.x, num5, vector.y); break; case 2: position = new Vector3(vector.x, vector.y, num5); break; } } position += capsuleCollider.center; } else if (collider is CharacterController) { CharacterController characterController = (CharacterController)collider; float radius2 = characterController.radius; float num6 = Mathf.Max(characterController.height - radius2, 0f); float num7 = CalculateSphereVolume(radius2); float num8 = CalculateCylinderVolume(radius2, num6); float maxInclusive2 = num7 + num8; if (UnityEngine.Random.Range(0f, maxInclusive2) <= num7) { position = UnityEngine.Random.insideUnitSphere * radius2; float num9 = ((float)UnityEngine.Random.Range(0, 2) * 2f - 1f) * num6 * 0.5f; position.y += num9; } else { Vector2 vector2 = UnityEngine.Random.insideUnitCircle * radius2; float y = UnityEngine.Random.Range(num6 * -0.5f, num6 * 0.5f); position = new Vector3(vector2.x, y, vector2.y); } position += characterController.center; } return transform.TransformPoint(position); } public static CharacterBody GetFriendlyEasyTarget(CharacterBody casterBody, Ray aimRay, float maxDistance, float maxDeviation = 20f) { TeamIndex teamIndex = TeamIndex.Neutral; TeamComponent component = casterBody.GetComponent(); if ((bool)component) { teamIndex = component.teamIndex; } ReadOnlyCollection teamMembers = TeamComponent.GetTeamMembers(teamIndex); Vector3 origin = aimRay.origin; Vector3 direction = aimRay.direction; List candidatesList = new List(teamMembers.Count); List list = new List(teamMembers.Count); float num = Mathf.Cos(maxDeviation * (MathF.PI / 180f)); for (int i = 0; i < teamMembers.Count; i++) { Transform transform = teamMembers[i].transform; Vector3 vector = transform.position - origin; float magnitude = vector.magnitude; float num2 = Vector3.Dot(vector * (1f / magnitude), direction); CharacterBody component2 = transform.GetComponent(); if (num2 >= num && component2 != casterBody) { float num3 = 1f / magnitude; float score = num2 + num3; candidatesList.Add(new EasyTargetCandidate { transform = transform, score = score, distance = magnitude }); list.Add(list.Count); } } list.Sort(delegate(int a, int b) { float score2 = candidatesList[a].score; float score3 = candidatesList[b].score; return (score2 != score3) ? ((!(score2 > score3)) ? 1 : (-1)) : 0; }); for (int j = 0; j < list.Count; j++) { int index = list[j]; CharacterBody component3 = candidatesList[index].transform.GetComponent(); if ((bool)component3 && component3 != casterBody) { return component3; } } return null; } public static CharacterBody GetEnemyEasyTarget(CharacterBody casterBody, Ray aimRay, float maxDistance, float maxDeviation = 20f) { TeamIndex teamIndex = TeamIndex.Neutral; TeamComponent component = casterBody.GetComponent(); if ((bool)component) { teamIndex = component.teamIndex; } List list = new List(); for (TeamIndex teamIndex2 = TeamIndex.Neutral; teamIndex2 < TeamIndex.Count; teamIndex2++) { if (teamIndex2 != teamIndex) { list.AddRange(TeamComponent.GetTeamMembers(teamIndex2)); } } Vector3 origin = aimRay.origin; Vector3 direction = aimRay.direction; List candidatesList = new List(list.Count); List list2 = new List(list.Count); float num = Mathf.Cos(maxDeviation * (MathF.PI / 180f)); for (int i = 0; i < list.Count; i++) { Transform transform = list[i].transform; Vector3 vector = transform.position - origin; float magnitude = vector.magnitude; float num2 = Vector3.Dot(vector * (1f / magnitude), direction); CharacterBody component2 = transform.GetComponent(); if (num2 >= num && component2 != casterBody && magnitude < maxDistance) { float num3 = 1f / magnitude; float score = num2 + num3; candidatesList.Add(new EasyTargetCandidate { transform = transform, score = score, distance = magnitude }); list2.Add(list2.Count); } } list2.Sort(delegate(int a, int b) { float score2 = candidatesList[a].score; float score3 = candidatesList[b].score; return (score2 != score3) ? ((!(score2 > score3)) ? 1 : (-1)) : 0; }); for (int j = 0; j < list2.Count; j++) { int index = list2[j]; CharacterBody component3 = candidatesList[index].transform.GetComponent(); if ((bool)component3 && component3 != casterBody) { return component3; } } return null; } public static float GetBodyPrefabFootOffset(GameObject prefab) { CapsuleCollider component = prefab.GetComponent(); if ((bool)component) { return component.height * 0.5f - component.center.y; } return 0f; } public static void ShuffleList(List list) { for (int num = list.Count - 1; num > 0; num--) { int index = UnityEngine.Random.Range(0, num + 1); T value = list[num]; list[num] = list[index]; list[index] = value; } } public static void ShuffleList(List list, Xoroshiro128Plus rng) { for (int num = list.Count - 1; num > 0; num--) { int index = rng.RangeInt(0, num + 1); T value = list[num]; list[num] = list[index]; list[index] = value; } } public static void ShuffleArray(T[] array) { for (int num = array.Length - 1; num > 0; num--) { int num2 = UnityEngine.Random.Range(0, num + 1); T val = array[num]; array[num] = array[num2]; array[num2] = val; } } public static void ShuffleArray(T[] array, Xoroshiro128Plus rng) { for (int num = array.Length - 1; num > 0; num--) { int num2 = rng.RangeInt(0, num + 1); T val = array[num]; array[num] = array[num2]; array[num2] = val; } } public static Transform FindNearest(Vector3 position, List transformsList, float range = float.PositiveInfinity) { Transform result = null; float num = range * range; for (int i = 0; i < transformsList.Count; i++) { float sqrMagnitude = (transformsList[i].position - position).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = transformsList[i]; } } return result; } public static Vector3 ApplySpread(Vector3 aimDirection, float minSpread, float maxSpread, float spreadYawScale, float spreadPitchScale, float bonusYaw = 0f, float bonusPitch = 0f) { Vector3 up = Vector3.up; Vector3 axis = Vector3.Cross(up, aimDirection); 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 + bonusYaw) * spreadYawScale; float angle2 = (Mathf.Atan2(y, vector.magnitude) * 57.29578f + bonusPitch) * spreadPitchScale; return Quaternion.AngleAxis(angle, up) * (Quaternion.AngleAxis(angle2, axis) * aimDirection); } public static string GenerateColoredString(string str, Color32 color) { return string.Format(CultureInfo.InvariantCulture, "{3}", color.r, color.g, color.b, str); } public static bool GuessRenderBounds(GameObject gameObject, out Bounds bounds) { Renderer[] componentsInChildren = gameObject.GetComponentsInChildren(); if (componentsInChildren.Length != 0) { bounds = componentsInChildren[0].bounds; for (int i = 1; i < componentsInChildren.Length; i++) { bounds.Encapsulate(componentsInChildren[i].bounds); } return true; } bounds = new Bounds(gameObject.transform.position, Vector3.zero); return false; } public static bool GuessRenderBoundsMeshOnly(GameObject gameObject, out Bounds bounds) { Renderer[] array = (from renderer in gameObject.GetComponentsInChildren() where renderer is MeshRenderer || renderer is SkinnedMeshRenderer select renderer).ToArray(); if (array.Length != 0) { bounds = array[0].bounds; for (int i = 1; i < array.Length; i++) { bounds.Encapsulate(array[i].bounds); } return true; } bounds = new Bounds(gameObject.transform.position, Vector3.zero); return false; } public static GameObject FindNetworkObject(NetworkInstanceId networkInstanceId) { if (NetworkServer.active) { return NetworkServer.FindLocalObject(networkInstanceId); } return ClientScene.FindLocalObject(networkInstanceId); } public static string GetGameObjectHierarchyName(GameObject gameObject) { int num = 0; Transform transform = gameObject.transform; while ((bool)transform) { num++; transform = transform.parent; } string[] array = new string[num]; Transform transform2 = gameObject.transform; while ((bool)transform2) { array[--num] = transform2.gameObject.name; transform2 = transform2.parent; } return string.Join("/", array); } public static string GetBestBodyName(GameObject bodyObject) { CharacterBody characterBody = null; string text = "???"; if ((bool)bodyObject) { characterBody = bodyObject.GetComponent(); if ((bool)characterBody) { text = characterBody.GetUserName(); } else { IDisplayNameProvider component = bodyObject.GetComponent(); if (component != null) { text = component.GetDisplayName(); } } } string text2 = text; if ((bool)characterBody) { if (characterBody.isElite) { BuffIndex[] eliteBuffIndices = BuffCatalog.eliteBuffIndices; foreach (BuffIndex buffIndex in eliteBuffIndices) { if (characterBody.HasBuff(buffIndex)) { text2 = Language.GetStringFormatted(BuffCatalog.GetBuffDef(buffIndex).eliteDef.modifierToken, text2); } } } if ((bool)characterBody.inventory) { if (characterBody.inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0) { text2 = Language.GetStringFormatted("BODY_MODIFIER_DOPPELGANGER", text2); } if (characterBody.inventory.GetItemCount(DLC1Content.Items.GummyCloneIdentifier) > 0) { text2 = Language.GetStringFormatted("BODY_MODIFIER_GUMMYCLONE", text2); } } } return text2; } public static string GetBestBodyNameColored(GameObject bodyObject) { if ((bool)bodyObject) { CharacterBody component = bodyObject.GetComponent(); if ((bool)component) { CharacterMaster master = component.master; if ((bool)master) { PlayerCharacterMasterController component2 = master.GetComponent(); if ((bool)component2) { GameObject networkUserObject = component2.networkUserObject; if ((bool)networkUserObject) { NetworkUser component3 = networkUserObject.GetComponent(); if ((bool)component3) { return GenerateColoredString(component3.userName, component3.userColor); } } } } } IDisplayNameProvider component4 = bodyObject.GetComponent(); if (component4 != null) { return component4.GetDisplayName(); } } return "???"; } public static string GetBestMasterName(CharacterMaster characterMaster) { if ((bool)characterMaster) { string text = characterMaster.playerCharacterMasterController?.networkUser?.userName; if (text == null) { string text2 = characterMaster.bodyPrefab?.GetComponent().baseNameToken; if (text2 != null) { text = Language.GetString(text2); } } return text; } return "Null Master"; } public static NetworkUser LookUpBodyNetworkUser(GameObject bodyObject) { if ((bool)bodyObject) { return LookUpBodyNetworkUser(bodyObject.GetComponent()); } return null; } public static NetworkUser LookUpBodyNetworkUser(CharacterBody characterBody) { if ((bool)characterBody) { CharacterMaster master = characterBody.master; if ((bool)master) { PlayerCharacterMasterController component = master.GetComponent(); if ((bool)component) { GameObject networkUserObject = component.networkUserObject; if ((bool)networkUserObject) { NetworkUser component2 = networkUserObject.GetComponent(); if ((bool)component2) { return component2; } } } } } return null; } private static bool HandleCharacterPhysicsCastResults(GameObject bodyObject, Ray ray, int numHits, RaycastHit[] hits, out RaycastHit hitInfo) { int num = -1; float num2 = float.PositiveInfinity; for (int i = 0; i < numHits; i++) { if (bodyObject == hits[i].collider.gameObject) { continue; } float distance = hits[i].distance; if (!(distance < num2)) { continue; } HurtBox component = hits[i].collider.GetComponent(); if ((bool)component) { HealthComponent healthComponent = component.healthComponent; if ((bool)healthComponent && healthComponent.gameObject == bodyObject) { continue; } } if (distance == 0f) { hitInfo = hits[i]; hitInfo.point = ray.origin; return true; } num = i; num2 = distance; } if (num == -1) { hitInfo = default(RaycastHit); return false; } hitInfo = hits[num]; return true; } public static bool CharacterRaycast(GameObject bodyObject, Ray ray, out RaycastHit hitInfo, float maxDistance, LayerMask layerMask, QueryTriggerInteraction queryTriggerInteraction) { int num = 0; num = HGPhysics.RaycastAll(out var hits, ray.origin, ray.direction, maxDistance, layerMask, queryTriggerInteraction); bool result = HandleCharacterPhysicsCastResults(bodyObject, ray, num, hits, out hitInfo); HGPhysics.ReturnResults(hits); return result; } public static bool CharacterSpherecast(GameObject bodyObject, Ray ray, float radius, out RaycastHit hitInfo, float maxDistance, LayerMask layerMask, QueryTriggerInteraction queryTriggerInteraction) { RaycastHit[] hits; int numHits = HGPhysics.SphereCastAll(out hits, ray.origin, radius, ray.direction, maxDistance, layerMask, queryTriggerInteraction); bool result = HandleCharacterPhysicsCastResults(bodyObject, ray, numHits, hits, out hitInfo); HGPhysics.ReturnResults(hits); return result; } public static bool ConnectionIsLocal([NotNull] NetworkConnection conn) { if (conn is SteamNetworkConnection) { return false; } if (conn is EOSNetworkConnection) { return false; } return conn.GetType() != typeof(NetworkConnection); } public static string EscapeRichTextForTextMeshPro(string rtString) { string text = rtString; text = text.Replace("<", "<"); return "" + text + ""; } public static string EscapeQuotes(string str) { str = backlashSearch.Replace(str, strBackslashBackslash); str = quoteSearch.Replace(str, strBackslashQuote); return str; } public static string RGBToHex(Color32 rgb) { return string.Format(CultureInfo.InvariantCulture, "{0:X2}{1:X2}{2:X2}", rgb.r, rgb.g, rgb.b); } public static Vector2 Vector3XZToVector2XY(Vector3 vector3) { return new Vector2(vector3.x, vector3.z); } public static Vector2 Vector3XZToVector2XY(ref Vector3 vector3) { return new Vector2(vector3.x, vector3.z); } public static void Vector3XZToVector2XY(Vector3 vector3, out Vector2 vector2) { vector2.x = vector3.x; vector2.y = vector3.z; } public static void Vector3XZToVector2XY(ref Vector3 vector3, out Vector2 vector2) { vector2.x = vector3.x; vector2.y = vector3.z; } public static Vector2 RotateVector2(Vector2 vector2, float degrees) { float num = Mathf.Sin(degrees * (MathF.PI / 180f)); float num2 = Mathf.Cos(degrees * (MathF.PI / 180f)); return new Vector2(num2 * vector2.x - num * vector2.y, num * vector2.x + num2 * vector2.y); } public static Quaternion SmoothDampQuaternion(Quaternion current, Quaternion target, ref float currentVelocity, float smoothTime, float maxSpeed, float deltaTime) { float target2 = Quaternion.Angle(current, target); target2 = Mathf.SmoothDamp(0f, target2, ref currentVelocity, smoothTime, maxSpeed, deltaTime); return Quaternion.RotateTowards(current, target, target2); } public static Quaternion SmoothDampQuaternion(Quaternion current, Quaternion target, ref float currentVelocity, float smoothTime) { float target2 = Quaternion.Angle(current, target); target2 = Mathf.SmoothDamp(0f, target2, ref currentVelocity, smoothTime); return Quaternion.RotateTowards(current, target, target2); } public static HurtBox FindBodyMainHurtBox(CharacterBody characterBody) { return characterBody.mainHurtBox; } public static HurtBox FindBodyMainHurtBox(GameObject bodyObject) { CharacterBody component = bodyObject.GetComponent(); if ((bool)component) { return FindBodyMainHurtBox(component); } return null; } public static Vector3 GetCorePosition(CharacterBody characterBody) { return characterBody.corePosition; } public static Vector3 GetCorePosition(GameObject bodyObject) { CharacterBody component = bodyObject.GetComponent(); if ((bool)component) { return GetCorePosition(component); } return bodyObject.transform.position; } public static Transform GetCoreTransform(GameObject bodyObject) { CharacterBody component = bodyObject.GetComponent(); if ((bool)component) { return component.coreTransform; } return bodyObject.transform; } public static float SphereRadiusToVolume(float radius) { return 4.1887903f * (radius * radius * radius); } public static float SphereVolumeToRadius(float volume) { return Mathf.Pow(3f * volume / (MathF.PI * 4f), 1f / 3f); } public static void CopyList(List src, List dest) { dest.Clear(); foreach (T item in src) { dest.Add(item); } } public static float ScanCharacterAnimationClipForMomentOfRootMotionStop(GameObject characterPrefab, string clipName, string rootBoneNameInChildLocator) { GameObject gameObject = UnityEngine.Object.Instantiate(characterPrefab); Transform modelTransform = gameObject.GetComponent().modelTransform; Transform transform = modelTransform.GetComponent().FindChild(rootBoneNameInChildLocator); AnimationClip animationClip = modelTransform.GetComponent().runtimeAnimatorController.animationClips.FirstOrDefault((AnimationClip c) => c.name == clipName); float result = 1f; animationClip.SampleAnimation(gameObject, 0f); Vector3 vector = transform.position; for (float num = 0.1f; num < 1f; num += 0.1f) { animationClip.SampleAnimation(gameObject, num); Vector3 position = transform.position; if ((position - vector).magnitude == 0f) { result = num; break; } vector = position; } UnityEngine.Object.Destroy(gameObject); return result; } public static void DebugCross(Vector3 position, float radius, UnityEngine.Color color, float duration) { UnityEngine.Debug.DrawLine(position - Vector3.right * radius, position + Vector3.right * radius, color, duration); UnityEngine.Debug.DrawLine(position - Vector3.up * radius, position + Vector3.up * radius, color, duration); UnityEngine.Debug.DrawLine(position - Vector3.forward * radius, position + Vector3.forward * radius, color, duration); } public static void DebugBounds(Bounds bounds, UnityEngine.Color color, float duration) { Vector3 min = bounds.min; Vector3 max = bounds.max; Vector3 start = new Vector3(min.x, min.y, min.z); Vector3 vector = new Vector3(min.x, min.y, max.z); Vector3 vector2 = new Vector3(min.x, max.y, min.z); Vector3 end = new Vector3(min.x, max.y, max.z); Vector3 vector3 = new Vector3(max.x, min.y, min.z); Vector3 vector4 = new Vector3(max.x, min.y, max.z); Vector3 end2 = new Vector3(max.x, max.y, min.z); Vector3 start2 = new Vector3(max.x, max.y, max.z); UnityEngine.Debug.DrawLine(start, vector, color, duration); UnityEngine.Debug.DrawLine(start, vector3, color, duration); UnityEngine.Debug.DrawLine(start, vector2, color, duration); UnityEngine.Debug.DrawLine(vector2, end, color, duration); UnityEngine.Debug.DrawLine(vector2, end2, color, duration); UnityEngine.Debug.DrawLine(start2, end, color, duration); UnityEngine.Debug.DrawLine(start2, end2, color, duration); UnityEngine.Debug.DrawLine(start2, vector4, color, duration); UnityEngine.Debug.DrawLine(vector4, vector3, color, duration); UnityEngine.Debug.DrawLine(vector4, vector, color, duration); UnityEngine.Debug.DrawLine(vector, end, color, duration); UnityEngine.Debug.DrawLine(vector3, end2, color, duration); } public static bool PositionIsValid(Vector3 value) { float f = value.x + value.y + value.z; if (!float.IsInfinity(f)) { return !float.IsNaN(f); } return false; } public static void Swap(ref T a, ref T b) { T val = a; a = b; b = val; } public static DateTime UnixTimeStampToDateTimeUtc(uint unixTimeStamp) { DateTime dateTime = dateZero; return dateTime.AddSeconds(unixTimeStamp).ToUniversalTime(); } public static double GetCurrentUnixEpochTimeInSeconds() { return Client.Instance.Utils.GetServerRealTime(); } public static bool IsValid(UnityEngine.Object o) { return o; } [Conditional("VERIFY_COMPONENTS")] public static void VerifyComponent(T a, T b) where T : Component { if (a != b) { if (logVerify) { UnityEngine.Debug.LogErrorFormat("Components are not the same! {0} != {1}", (a != null) ? a.ToString() : "null", (b != null) ? b.ToString() : "null"); } if (breakInVerify) { UnityEngine.Debug.DebugBreak(); } } } [Conditional("VERIFY_COMPONENTS")] public static void VerifyNullComponent(Component a) { if (a != null) { if (logVerify) { UnityEngine.Debug.LogErrorFormat("Components is not null! {0} != null", a.ToString()); } if (breakInVerify) { UnityEngine.Debug.DebugBreak(); } } } [Conditional("VERIFY_COMPONENTS")] public static void VerifyNonNullComponent(T a, string desc) where T : Component { if (a == null) { if (logVerify) { UnityEngine.Debug.LogErrorFormat("Component is null! {0}: {1}", typeof(T).ToString(), string.IsNullOrEmpty(desc) ? "" : desc); } if (breakInVerify) { UnityEngine.Debug.DebugBreak(); } } } [Conditional("VERIFY_COMPONENTS")] public static void VerifyComponent(T a, GameObject b) where T : Component { _ = b != null; } [Conditional("VERIFY_COMPONENTS")] public static void VerifyComponent(T a, X b) where T : Component where X : Component { _ = b != null; } [Conditional("VERIFY_COMPONENTS")] public static void VerifyObject(GameObject a, GameObject b) { if (a != b) { if (logVerify) { UnityEngine.Debug.LogErrorFormat("Objects are not the same! {0} != {1}", a.ToString(), b.ToString()); } if (breakInVerify) { UnityEngine.Debug.DebugBreak(); } } } [Conditional("VERIFY_COMPONENTS")] public static void VerifyTeam(TeamIndex a, Component b) { if (a != TeamComponent.GetObjectTeam(b.gameObject)) { if (logVerify) { UnityEngine.Debug.LogErrorFormat("Objects are not the same! {0} != {1}", a.ToString(), b.ToString()); } if (breakInVerify) { UnityEngine.Debug.DebugBreak(); } } } public static string BuildPrefabTransformPath(Transform root, Transform transform, bool appendCloneSuffix = false, bool includeRoot = false) { if (!root) { throw new ArgumentException("Value provided as 'root' is an invalid object.", "root"); } if (!transform) { throw new ArgumentException("Value provided as 'transform' is an invalid object.", "transform"); } try { Transform transform2 = transform; while ((object)transform2 != root) { if (!transform2) { string arg = TakeResult(); throw new ArgumentException($"\"{arg}\" is not a child of \"{root}\"."); } if (sharedStringStack.Count > 0) { sharedStringStack.Push("/"); } sharedStringStack.Push(transform2.gameObject.name); transform2 = transform2.parent; } if (includeRoot) { if (sharedStringStack.Count > 0) { sharedStringStack.Push("/"); } sharedStringStack.Push(root.gameObject.name); } return TakeResult(); } finally { sharedStringBuilder.Clear(); sharedStringStack.Clear(); } string TakeResult() { while (sharedStringStack.Count > 0) { sharedStringBuilder.Append(sharedStringStack.Pop()); } if (appendCloneSuffix) { sharedStringBuilder.Append(cloneString); } return sharedStringBuilder.Take(); } } public static int GetItemCountForTeam(TeamIndex teamIndex, ItemIndex itemIndex, bool requiresAlive, bool requiresConnected = true) { int num = 0; ReadOnlyCollection readOnlyInstancesList = CharacterMaster.readOnlyInstancesList; int i = 0; for (int count = readOnlyInstancesList.Count; i < count; i++) { CharacterMaster characterMaster = readOnlyInstancesList[i]; if (characterMaster.teamIndex == teamIndex && (!requiresAlive || characterMaster.hasBody) && (!requiresConnected || !characterMaster.playerCharacterMasterController || characterMaster.playerCharacterMasterController.isConnected)) { num += characterMaster.inventory.GetItemCount(itemIndex); } } return num; } public static int GetItemCountGlobal(ItemIndex itemIndex, bool requiresAlive, bool requiresConnected = true) { int num = 0; ReadOnlyCollection readOnlyInstancesList = CharacterMaster.readOnlyInstancesList; int i = 0; for (int count = readOnlyInstancesList.Count; i < count; i++) { CharacterMaster characterMaster = readOnlyInstancesList[i]; if ((!requiresAlive || characterMaster.hasBody) && (!requiresConnected || !characterMaster.playerCharacterMasterController || characterMaster.playerCharacterMasterController.isConnected)) { num += characterMaster.inventory.GetItemCount(itemIndex); } } return num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NullifyIfInvalid(ref T objRef) where T : UnityEngine.Object { if ((object)objRef != null && !objRef) { objRef = null; } } public static bool IsPrefab(GameObject gameObject) { if ((bool)gameObject) { return !gameObject.scene.IsValid(); } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint IntToUintPlusOne(int value) { return (uint)(value + 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int UintToIntMinusOne(uint value) { return (int)(value - 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong LongToUlongPlusOne(long value) { return (ulong)(value + 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long UlongToLongMinusOne(ulong value) { return (long)(value - 1); } public static float GetExpAdjustedDropChancePercent(float baseChancePercent, GameObject characterBodyObject) { int num = 0; DeathRewards component = characterBodyObject.GetComponent(); if ((bool)component) { num = component.spawnValue; } return baseChancePercent * Mathf.Log((float)num + 1f, 2f); } public static bool IsDontDestroyOnLoad(GameObject go) { return go.scene.name == "DontDestroyOnLoad"; } }