Decompiled source of EnemyHealthBarMod v0.1.0
EnemyHealthBarMod.dll
Decompiled 17 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using Assets.Scripts.Actors.Enemies; using Assets.Scripts.Managers; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using HarmonyLib; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Microsoft.CodeAnalysis; using ModSettingsTabMod; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("EnemyHealthBarMod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+5f9babd392f363ec169e9d5b09860072e6cd82aa")] [assembly: AssemblyProduct("Enemy Health Bar Mod")] [assembly: AssemblyTitle("EnemyHealthBarMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } internal static class MyPluginInfo { public const string PLUGIN_GUID = "com.megabonk.enemyhealthbarmod"; public const string PLUGIN_NAME = "EnemyHealthBarMod"; public const string PLUGIN_VERSION = "1.0.0"; } namespace EnemyHealthBarMod { public static class MyPluginInfo { public const string PLUGIN_GUID = "EnemyHealthBarMod"; public const string PLUGIN_NAME = "Enemy Health Bar Mod"; public const string PLUGIN_VERSION = "0.1.0"; } } namespace EnemyHealthBarModBepinex { public static class HealthBarManager { private static readonly Dictionary<uint, HealthBarUI> healthBarsByEnemyId = new Dictionary<uint, HealthBarUI>(); private static readonly List<HealthBarUI> activeBarList = new List<HealthBarUI>(); private static readonly List<uint> removalList = new List<uint>(); private static readonly Dictionary<uint, Enemy> trackedEnemies = new Dictionary<uint, Enemy>(); public static readonly Dictionary<string, string> BoneNameCache = new Dictionary<string, string>(); private static readonly HashSet<string> loggedEnemyNames = new HashSet<string>(); private static readonly Queue<(Enemy enemy, uint id)> creationQueue = new Queue<(Enemy, uint)>(); private static readonly HashSet<uint> queuedIds = new HashSet<uint>(); private static Camera cachedCamera; private static Vector3 lastCameraPosition; private static int frameCounter = 0; private static float sqrSkipUpdateDistance = 0f; private static float sqrFadeEndDistance = 0f; private static bool distanceSettingsDirty = true; private static int culledBarCount = 0; private const int HIGH_BAR_COUNT_THRESHOLD = 75; private const float TARGET_FRAME_TIME = 1f / 60f; private static float lastUpdateTime = 0f; private static bool isThrottling = false; private static bool isSkipFrame = false; private const int PRIORITY_POOL_SIZE = 75; private const float PRIORITY_POOL_UPDATE_INTERVAL = 0.2f; private static readonly HashSet<uint> priorityPoolIds = new HashSet<uint>(); private static readonly List<(uint id, float sqrDist)> distanceSortList = new List<(uint, float)>(); private static float lastPriorityPoolUpdateTime = 0f; private static readonly HashSet<uint> damagedBarIds = new HashSet<uint>(); private static readonly float[] frustumNormalsX = new float[6]; private static readonly float[] frustumNormalsY = new float[6]; private static readonly float[] frustumNormalsZ = new float[6]; private static readonly float[] frustumDistances = new float[6]; private static bool frustumPlanesValid = false; private static Vector3 lastFrustumCameraPos; private static Quaternion lastFrustumCameraRot; private static Quaternion cachedBillboardRotation; private static bool billboardRotationValid = false; private static readonly Stack<HealthBarUI> healthBarPool = new Stack<HealthBarUI>(); private static bool poolPreallocated = false; private const int SIMD_BATCH_THRESHOLD = 32; private static float[] positionXArray = new float[128]; private static float[] positionYArray = new float[128]; private static float[] positionZArray = new float[128]; private static float[] sqrDistanceArray = new float[128]; private static Type cachedUiManagerType; private static PropertyInfo cachedUiManagerInstanceProperty; private static PropertyInfo cachedPauseProperty; private static PropertyInfo cachedPauseCurrentProperty; public static GameObject cachedEncounterWindowsObject; public static GameObject cachedLevelupChild; public static GameObject cachedEncounterChild; public static GameObject cachedChestChild; private static Type cachedGameManagerType; private static PropertyInfo cachedGameManagerInstanceProperty; private static FieldInfo cachedCutsceneField; private static PropertyInfo cachedIsGameOverProperty; private static MethodInfo cachedIsTimeFreezeMethod; private static Type cachedLevelupScreenType; private static FieldInfo cachedIsLevelingUpField; private static Func<object> getGameManagerInstance; private static Func<object, bool> getCutsceneValue; private static Func<object, bool> getIsGameOverValue; private static Func<object, bool> invokeIsTimeFreeze; private static Func<object> getUiManagerInstance; private static Func<object, object> getPauseValue; private static Func<object, object> getPauseCurrentValue; private static bool delegatesCompiled = false; public static bool IsPaused { get; private set; } public static Camera CachedCamera => cachedCamera; public static Quaternion BillboardRotation => cachedBillboardRotation; public static bool HasValidBillboard => billboardRotationValid; public static float GetEnemyYOffsetOverride(string enemyTypeName) { return 0f; } public static bool UsesMeshHeightPositioning(string enemyTypeName) { return string.Equals(enemyTypeName, "Bee", StringComparison.OrdinalIgnoreCase); } public static float GetEnemyMeshHeight(Enemy enemy) { if ((Object)(object)enemy == (Object)null) { return -1f; } try { Type type = ((object)enemy).GetType(); PropertyInfo property = type.GetProperty("meshHeight", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead && property.GetValue(enemy) is float result) { return result; } FieldInfo field = type.GetField("_meshHeight_k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null && field.GetValue(enemy) is float result2) { return result2; } field = type.GetField("meshHeight", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(enemy); if (value is float) { return (float)value; } } } catch { } return -1f; } public static void CreateHealthBar(Enemy enemy, uint id) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown if ((Object)(object)enemy == (Object)null) { return; } trackedEnemies[id] = enemy; if (Plugin.EnableDebugLogs.Value) { string enemyTypeName = GetEnemyTypeName(enemy); if (loggedEnemyNames.Add(enemyTypeName)) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(52, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[EnemyDiscovery] New enemy type: \""); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(enemyTypeName); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\" (GameObject: \""); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)enemy).name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\")"); } log.LogInfo(val); } } if (!healthBarsByEnemyId.ContainsKey(id) && !queuedIds.Contains(id)) { creationQueue.Enqueue((enemy, id)); queuedIds.Add(id); } } private static void ProcessCreationQueue() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) int num = 0; int value = Plugin.MaxBarsPerFrame.Value; bool flag = default(bool); while (creationQueue.Count > 0 && num < value) { var (val, num2) = creationQueue.Dequeue(); queuedIds.Remove(num2); if ((Object)(object)val == (Object)null || val.hp <= 0f) { num++; continue; } try { HealthBarUI pooledHealthBarUI = GetPooledHealthBarUI(val, num2); if (billboardRotationValid) { pooledHealthBarUI.ApplyBillboardRotation(cachedBillboardRotation); } healthBarsByEnemyId[num2] = pooledHealthBarUI; activeBarList.Add(pooledHealthBarUI); } catch (Exception ex) { ManualLogSource log = Plugin.Log; BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(40, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to create health bar for enemy "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<uint>(num2); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message); } log.LogWarning(val2); } num++; } } public static void UpdateHealthBar(Enemy enemy, uint id) { if (!Plugin.ShowHealthBars.Value || (Object)(object)enemy == (Object)null || enemy.hp <= 0f) { return; } trackedEnemies[id] = enemy; damagedBarIds.Add(id); if (!healthBarsByEnemyId.TryGetValue(id, out var value)) { if (!queuedIds.Contains(id)) { CreateHealthBar(enemy, id); } } else { value?.Update(enemy); } } public static void UpdateAllHealthBars() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) frameCounter++; int count = activeBarList.Count; isThrottling = count > 75; isSkipFrame = false; if (isThrottling) { float unscaledTime = Time.unscaledTime; if (unscaledTime - lastUpdateTime < 1f / 60f) { isSkipFrame = true; } else { lastUpdateTime = unscaledTime; } } UpdateCameraCache(); UpdatePauseState(); if ((Object)(object)cachedCamera != (Object)null) { cachedBillboardRotation = Quaternion.LookRotation(((Component)cachedCamera).transform.forward); billboardRotationValid = true; } else { billboardRotationValid = false; } ProcessCreationQueue(); removalList.Clear(); culledBarCount = 0; int updateFrequencyFar = (isThrottling ? Math.Max(Plugin.UpdateFrequencyFar.Value, 5) : Plugin.UpdateFrequencyFar.Value); if (distanceSettingsDirty) { float num = Plugin.SkipUpdateDistance.Value; sqrSkipUpdateDistance = num * num; float num2 = Plugin.FadeEndDistance.Value; sqrFadeEndDistance = num2 * num2; distanceSettingsDirty = false; } Vector3 camPos = (((Object)(object)cachedCamera != (Object)null) ? ((Component)cachedCamera).transform.position : Vector3.zero); bool flag = (Object)(object)cachedCamera != (Object)null; if (isThrottling && flag) { UpdatePriorityPool(camPos); } if (flag && count >= 32) { UpdateAllHealthBarsSimd(count, camPos, updateFrequencyFar); } else { UpdateAllHealthBarsScalar(count, camPos, flag, updateFrequencyFar); } for (int i = 0; i < removalList.Count; i++) { RemoveHealthBar(removalList[i]); } } private static void UpdatePriorityPool(Vector3 camPos) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown float unscaledTime = Time.unscaledTime; if (unscaledTime - lastPriorityPoolUpdateTime < 0.2f) { return; } lastPriorityPoolUpdateTime = unscaledTime; distanceSortList.Clear(); for (int i = 0; i < activeBarList.Count; i++) { HealthBarUI healthBarUI = activeBarList[i]; if (healthBarUI != null && healthBarUI.IsValid()) { Vector3 currentPosition = healthBarUI.CurrentPosition; if (!(currentPosition == Vector3.zero)) { float num = currentPosition.x - camPos.x; float num2 = currentPosition.y - camPos.y; float num3 = currentPosition.z - camPos.z; float item = num * num + num2 * num2 + num3 * num3; distanceSortList.Add((healthBarUI.EnemyId, item)); } } } distanceSortList.Sort(((uint id, float sqrDist) a, (uint id, float sqrDist) b) => a.sqrDist.CompareTo(b.sqrDist)); priorityPoolIds.Clear(); int num4 = Math.Min(75, distanceSortList.Count); for (int j = 0; j < num4; j++) { priorityPoolIds.Add(distanceSortList[j].id); } if (Plugin.EnableDebugLogs.Value) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(51, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Priority pool updated: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num4); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" bars in pool, "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(distanceSortList.Count - num4); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" low priority"); } log.LogInfo(val); } } private static void UpdateAllHealthBarsScalar(int count, Vector3 camPos, bool hasCamera, int updateFrequencyFar) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) bool flag = hasCamera && frustumPlanesValid && Plugin.EnableFrustumCulling.Value; bool flag2 = frameCounter % 30 == 0; for (int i = 0; i < count; i++) { HealthBarUI healthBarUI = activeBarList[i]; uint enemyId = healthBarUI.EnemyId; if (healthBarUI == null || !healthBarUI.IsValid()) { removalList.Add(enemyId); continue; } trackedEnemies.TryGetValue(enemyId, out var value); Vector3 currentPosition = healthBarUI.CurrentPosition; bool flag3 = damagedBarIds.Contains(enemyId); bool flag4 = flag3 || flag2 || (Object)(object)value == (Object)null || value.hp <= 0f; if (flag && currentPosition != Vector3.zero && !IsInFrustum(currentPosition)) { healthBarUI.SetCulled(culled: true); culledBarCount++; if (billboardRotationValid) { healthBarUI.ApplyBillboardRotation(cachedBillboardRotation); } if (flag4) { healthBarUI.Update(value); damagedBarIds.Remove(enemyId); } continue; } healthBarUI.SetCulled(culled: false); float num = -1f; if (hasCamera && currentPosition != Vector3.zero) { float num2 = currentPosition.x - camPos.x; float num3 = currentPosition.y - camPos.y; float num4 = currentPosition.z - camPos.z; num = num2 * num2 + num3 * num3 + num4 * num4; } healthBarUI.UpdateVisibility(num); if (isSkipFrame) { if ((Object)(object)value == (Object)null || value.hp <= 0f) { healthBarUI.Update(value, num); damagedBarIds.Remove(enemyId); } continue; } if (billboardRotationValid) { healthBarUI.ApplyBillboardRotation(cachedBillboardRotation); } if (hasCamera && num >= 0f) { if ((num > sqrSkipUpdateDistance && !flag4) || (num > sqrFadeEndDistance && !flag3 && frameCounter % updateFrequencyFar != 0)) { continue; } if (isThrottling && !priorityPoolIds.Contains(enemyId) && !flag3) { if ((Object)(object)value == (Object)null || value.hp <= 0f) { healthBarUI.Update(value, num); } continue; } } healthBarUI.Update(value, num); healthBarUI.LateTick(); damagedBarIds.Remove(enemyId); } } private static void UpdateAllHealthBarsSimd(int count, Vector3 camPos, int updateFrequencyFar) { //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) EnsureArrayCapacity(count); bool flag = frustumPlanesValid && Plugin.EnableFrustumCulling.Value; bool flag2 = frameCounter % 30 == 0; int num = 0; for (int i = 0; i < count; i++) { HealthBarUI healthBarUI = activeBarList[i]; if (healthBarUI == null || !healthBarUI.IsValid()) { removalList.Add(healthBarUI?.EnemyId ?? 0); positionXArray[i] = float.MaxValue; continue; } Vector3 currentPosition = healthBarUI.CurrentPosition; uint enemyId = healthBarUI.EnemyId; if (flag && currentPosition != Vector3.zero && !IsInFrustum(currentPosition)) { healthBarUI.SetCulled(culled: true); culledBarCount++; if (billboardRotationValid) { healthBarUI.ApplyBillboardRotation(cachedBillboardRotation); } trackedEnemies.TryGetValue(enemyId, out var value); if (damagedBarIds.Contains(enemyId) || flag2 || (Object)(object)value == (Object)null || value.hp <= 0f) { healthBarUI.Update(value); damagedBarIds.Remove(enemyId); } positionXArray[i] = float.MaxValue; } else { positionXArray[i] = currentPosition.x; positionYArray[i] = currentPosition.y; positionZArray[i] = currentPosition.z; num++; } } BatchCalculateDistances(count, camPos.x, camPos.y, camPos.z); for (int j = 0; j < count; j++) { if (positionXArray[j] == float.MaxValue) { continue; } HealthBarUI healthBarUI2 = activeBarList[j]; uint enemyId2 = healthBarUI2.EnemyId; trackedEnemies.TryGetValue(enemyId2, out var value2); float num2 = sqrDistanceArray[j]; healthBarUI2.SetCulled(culled: false); bool flag3 = damagedBarIds.Contains(enemyId2); bool flag4 = flag3 || flag2 || (Object)(object)value2 == (Object)null || value2.hp <= 0f; healthBarUI2.UpdateVisibility(num2); if (isSkipFrame) { if ((Object)(object)value2 == (Object)null || value2.hp <= 0f) { healthBarUI2.Update(value2, num2); damagedBarIds.Remove(enemyId2); } continue; } if (billboardRotationValid) { healthBarUI2.ApplyBillboardRotation(cachedBillboardRotation); } if ((num2 > sqrSkipUpdateDistance && !flag4) || (num2 > sqrFadeEndDistance && !flag3 && frameCounter % updateFrequencyFar != 0)) { continue; } if (isThrottling && !priorityPoolIds.Contains(enemyId2) && !flag3) { if ((Object)(object)value2 == (Object)null || value2.hp <= 0f) { healthBarUI2.Update(value2, num2); } } else { healthBarUI2.Update(value2, num2); healthBarUI2.LateTick(); damagedBarIds.Remove(enemyId2); } } } private static void UpdateCameraCache() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cachedCamera == (Object)null || frameCounter % 30 == 0) { cachedCamera = Camera.main; } if ((Object)(object)cachedCamera != (Object)null) { Vector3 position = ((Component)cachedCamera).transform.position; if (Vector3.SqrMagnitude(position - lastCameraPosition) > 1f) { lastCameraPosition = position; } UpdateFrustumPlanes(); } else { frustumPlanesValid = false; } } private static void UpdateFrustumPlanes() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cachedCamera == (Object)null) { frustumPlanesValid = false; return; } Transform transform = ((Component)cachedCamera).transform; Vector3 position = transform.position; Quaternion rotation = transform.rotation; bool flag = Vector3.SqrMagnitude(position - lastFrustumCameraPos) > 0.25f; bool flag2 = Quaternion.Angle(rotation, lastFrustumCameraRot) > 1f; if (!(!frustumPlanesValid || flag || flag2)) { return; } try { ExtractFrustumPlanes(cachedCamera.projectionMatrix * cachedCamera.worldToCameraMatrix); lastFrustumCameraPos = position; lastFrustumCameraRot = rotation; frustumPlanesValid = true; } catch { frustumPlanesValid = false; } } private static void ExtractFrustumPlanes(Matrix4x4 vp) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) float[] array = new float[6]; float[] array2 = new float[6]; float[] array3 = new float[6]; float[] array4 = new float[6]; array[0] = vp.m30 + vp.m00; array2[0] = vp.m31 + vp.m01; array3[0] = vp.m32 + vp.m02; array4[0] = vp.m33 + vp.m03; array[1] = vp.m30 - vp.m00; array2[1] = vp.m31 - vp.m01; array3[1] = vp.m32 - vp.m02; array4[1] = vp.m33 - vp.m03; array[2] = vp.m30 + vp.m10; array2[2] = vp.m31 + vp.m11; array3[2] = vp.m32 + vp.m12; array4[2] = vp.m33 + vp.m13; array[3] = vp.m30 - vp.m10; array2[3] = vp.m31 - vp.m11; array3[3] = vp.m32 - vp.m12; array4[3] = vp.m33 - vp.m13; array[4] = vp.m30 + vp.m20; array2[4] = vp.m31 + vp.m21; array3[4] = vp.m32 + vp.m22; array4[4] = vp.m33 + vp.m23; array[5] = vp.m30 - vp.m20; array2[5] = vp.m31 - vp.m21; array3[5] = vp.m32 - vp.m22; array4[5] = vp.m33 - vp.m23; for (int i = 0; i < 6; i++) { float num = Mathf.Sqrt(array[i] * array[i] + array2[i] * array2[i] + array3[i] * array3[i]); if (num > 0.0001f) { float num2 = 1f / num; frustumNormalsX[i] = array[i] * num2; frustumNormalsY[i] = array2[i] * num2; frustumNormalsZ[i] = array3[i] * num2; frustumDistances[i] = array4[i] * num2; } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsInFrustum(Vector3 position) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!frustumPlanesValid) { return true; } float x = position.x; float y = position.y; float z = position.z; for (int i = 0; i < 6; i++) { float num = frustumNormalsX[i]; float num2 = frustumNormalsY[i]; float num3 = frustumNormalsZ[i]; if (num * ((num >= 0f) ? (x + 1f) : (x - 1f)) + num2 * ((num2 >= 0f) ? (y + 3f) : (y - 3f)) + num3 * ((num3 >= 0f) ? (z + 1f) : (z - 1f)) + frustumDistances[i] < 0f) { return false; } } return true; } [MethodImpl(MethodImplOptions.AggressiveOptimization)] private static void BatchCalculateDistances(int count, float camX, float camY, float camZ) { int count2 = Vector<float>.Count; Vector<float> vector = new Vector<float>(camX); Vector<float> vector2 = new Vector<float>(camY); Vector<float> vector3 = new Vector<float>(camZ); int i = 0; for (int num = count - count2 + 1; i < num; i += count2) { Vector<float> vector4 = new Vector<float>(positionXArray, i); Vector<float> vector5 = new Vector<float>(positionYArray, i); Vector<float> vector6 = new Vector<float>(positionZArray, i); Vector<float> vector7 = vector4 - vector; Vector<float> vector8 = vector5 - vector2; Vector<float> vector9 = vector6 - vector3; (vector7 * vector7 + vector8 * vector8 + vector9 * vector9).CopyTo(sqrDistanceArray, i); } for (; i < count; i++) { float num2 = positionXArray[i] - camX; float num3 = positionYArray[i] - camY; float num4 = positionZArray[i] - camZ; sqrDistanceArray[i] = num2 * num2 + num3 * num3 + num4 * num4; } } private static void EnsureArrayCapacity(int required) { if (positionXArray.Length < required) { int num = Math.Max(required, positionXArray.Length * 2); positionXArray = new float[num]; positionYArray = new float[num]; positionZArray = new float[num]; sqrDistanceArray = new float[num]; } } public static void RemoveHealthBar(uint id) { if (healthBarsByEnemyId.TryGetValue(id, out var value)) { if (value != null) { SwapRemoveFromActiveList(value); ReturnHealthBarToPool(value); } healthBarsByEnemyId.Remove(id); } trackedEnemies.Remove(id); queuedIds.Remove(id); } private static void SwapRemoveFromActiveList(HealthBarUI item) { int count = activeBarList.Count; for (int i = 0; i < count; i++) { if (activeBarList[i] == item) { int num = count - 1; if (i != num) { activeBarList[i] = activeBarList[num]; } activeBarList.RemoveAt(num); break; } } } public static void SetGlobalVisibility(bool visible) { foreach (HealthBarUI activeBar in activeBarList) { activeBar?.SetVisible(visible); } } public static void RebuildAllHealthBars() { MarkDistanceSettingsDirty(); float num = Plugin.SkipUpdateDistance.Value; sqrSkipUpdateDistance = num * num; float num2 = Plugin.FadeEndDistance.Value; sqrFadeEndDistance = num2 * num2; distanceSettingsDirty = false; foreach (HealthBarUI activeBar in activeBarList) { if (activeBar != null) { ReturnHealthBarToPool(activeBar); } } activeBarList.Clear(); healthBarsByEnemyId.Clear(); creationQueue.Clear(); queuedIds.Clear(); foreach (KeyValuePair<uint, Enemy> trackedEnemy in trackedEnemies) { if ((Object)(object)trackedEnemy.Value != (Object)null && trackedEnemy.Value.hp > 0f) { CreateHealthBar(trackedEnemy.Value, trackedEnemy.Key); } } } public static int GetActiveBarCount() { return activeBarList.Count; } public static int GetTrackedEnemyCount() { return trackedEnemies.Count; } public static int GetCulledBarCount() { return culledBarCount; } public static IEnumerable<HealthBarUI> GetAllActiveBars() { return activeBarList; } public static void OnSceneChanged() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) MarkDistanceSettingsDirty(); ResetReflectionDelegates(); foreach (HealthBarUI activeBar in activeBarList) { activeBar?.Destroy(); } activeBarList.Clear(); healthBarsByEnemyId.Clear(); trackedEnemies.Clear(); creationQueue.Clear(); queuedIds.Clear(); while (healthBarPool.Count > 0) { healthBarPool.Pop()?.Destroy(); } poolPreallocated = false; cachedCamera = null; lastCameraPosition = Vector3.zero; frustumPlanesValid = false; priorityPoolIds.Clear(); distanceSortList.Clear(); lastPriorityPoolUpdateTime = 0f; damagedBarIds.Clear(); loggedEnemyNames.Clear(); Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name == "GeneratedMap") { WarmUpPauseDetection(); PreallocatePool(); } } public static void WarmUpPauseDetection() { cachedLevelupChild = null; cachedEncounterChild = null; cachedChestChild = null; cachedEncounterWindowsObject = null; EnsureGameManagerReflection(); EnsureUiManagerReflection(); EnsureLevelupScreenReflection(); BoneNameCache["Enemy1"] = "Render"; BoneNameCache["Enemy2"] = "Render"; BoneNameCache["Enemy3"] = "Render"; BoneNameCache["Enemy4"] = "Render"; BoneNameCache["Enemy5"] = "Render"; BoneNameCache["Enemy6"] = "Render"; GameObject val = GameObject.Find("EncounterWindows"); if ((Object)(object)val != (Object)null) { cachedEncounterWindowsObject = val; Transform transform = val.transform; Transform val2 = transform.Find("LevelupScreen/New"); if (Object.op_Implicit((Object)(object)val2)) { cachedLevelupChild = ((Component)val2).gameObject; } Transform val3 = transform.Find("EncounterWindow/EncounterWindowNew"); if (Object.op_Implicit((Object)(object)val3)) { cachedEncounterChild = ((Component)val3).gameObject; } Transform val4 = transform.Find("ChestOpeningWindow/W_Offers"); if (Object.op_Implicit((Object)(object)val4)) { cachedChestChild = ((Component)val4).gameObject; } } } public static void UpdatePauseState() { if (frameCounter % 10 == 0) { IsPaused = CheckIfGamePaused(); } } private static bool CheckIfGamePaused() { //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Expected O, but got Unknown try { if ((Object)(object)cachedLevelupChild != (Object)null && cachedLevelupChild.activeInHierarchy) { return true; } if ((Object)(object)cachedEncounterChild != (Object)null && cachedEncounterChild.activeInHierarchy) { return true; } if ((Object)(object)cachedChestChild != (Object)null && cachedChestChild.activeInHierarchy) { return true; } if (!delegatesCompiled) { CompileReflectionDelegates(); } object obj = null; if (getGameManagerInstance != null) { obj = getGameManagerInstance(); } else if (EnsureGameManagerReflection() && cachedGameManagerInstanceProperty != null) { obj = cachedGameManagerInstanceProperty.GetValue(null); } if (obj != null) { if (getCutsceneValue != null) { if (getCutsceneValue(obj)) { return true; } } else if (cachedCutsceneField != null && (bool)cachedCutsceneField.GetValue(obj)) { return true; } if (getIsGameOverValue != null) { if (getIsGameOverValue(obj)) { return true; } } else if (cachedIsGameOverProperty != null && (bool)cachedIsGameOverProperty.GetValue(obj)) { return true; } if (invokeIsTimeFreeze != null) { if (invokeIsTimeFreeze(obj)) { return true; } } else if (cachedIsTimeFreezeMethod != null && (bool)cachedIsTimeFreezeMethod.Invoke(obj, null)) { return true; } } object obj2 = null; if (getUiManagerInstance != null) { obj2 = getUiManagerInstance(); } else if (EnsureUiManagerReflection() && cachedUiManagerInstanceProperty != null) { obj2 = cachedUiManagerInstanceProperty.GetValue(null); } if (obj2 != null) { object obj3 = null; if (getPauseValue != null) { obj3 = getPauseValue(obj2); } else if (cachedPauseProperty != null) { obj3 = cachedPauseProperty.GetValue(obj2); } if (obj3 != null) { object obj4 = null; if (getPauseCurrentValue != null) { obj4 = getPauseCurrentValue(obj3); } else if (cachedPauseCurrentProperty != null) { obj4 = cachedPauseCurrentProperty.GetValue(obj3); } if (obj4 != null) { GameObject val = (GameObject)((obj4 is GameObject) ? obj4 : null); if (val != null) { return val.activeInHierarchy; } return true; } } } } catch (Exception ex) { if (Plugin.EnableDebugLogs.Value) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(25, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("CheckIfGamePaused error: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message); } log.LogError(val2); } } return false; } public static bool IsGamePaused() { return IsPaused; } private static bool EnsureGameManagerReflection() { if (cachedGameManagerType != null) { return true; } cachedGameManagerType = Type.GetType("GameManager, Assembly-CSharp"); if (cachedGameManagerType == null) { return false; } cachedGameManagerInstanceProperty = cachedGameManagerType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); cachedCutsceneField = cachedGameManagerType.GetField("cutscene", BindingFlags.Instance | BindingFlags.Public); cachedIsGameOverProperty = cachedGameManagerType.GetProperty("isGameOver", BindingFlags.Instance | BindingFlags.Public); cachedIsTimeFreezeMethod = cachedGameManagerType.GetMethod("IsTimeFreeze", BindingFlags.Instance | BindingFlags.Public); return true; } private static bool EnsureUiManagerReflection() { if (cachedUiManagerType != null) { return true; } cachedUiManagerType = Type.GetType("UiManager, Assembly-CSharp"); if (cachedUiManagerType == null) { return false; } cachedUiManagerInstanceProperty = cachedUiManagerType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); cachedPauseProperty = cachedUiManagerType.GetProperty("pause", BindingFlags.Instance | BindingFlags.Public); if (cachedPauseProperty != null) { cachedPauseCurrentProperty = cachedPauseProperty.PropertyType.GetProperty("current", BindingFlags.Instance | BindingFlags.Public); } return true; } private static bool EnsureLevelupScreenReflection() { if (cachedLevelupScreenType != null) { return true; } cachedLevelupScreenType = Type.GetType("LevelupScreen, Assembly-CSharp"); if (cachedLevelupScreenType != null) { cachedIsLevelingUpField = cachedLevelupScreenType.GetField("isLevelingUp", BindingFlags.Static | BindingFlags.Public); } return cachedLevelupScreenType != null; } private static void CompileReflectionDelegates() { //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Expected O, but got Unknown if (delegatesCompiled) { return; } bool flag = default(bool); try { EnsureGameManagerReflection(); EnsureUiManagerReflection(); if (cachedGameManagerInstanceProperty != null) { PropertyInfo prop5 = cachedGameManagerInstanceProperty; getGameManagerInstance = () => prop5.GetValue(null); } if (cachedCutsceneField != null) { FieldInfo field = cachedCutsceneField; getCutsceneValue = (object obj) => (bool)field.GetValue(obj); } if (cachedIsGameOverProperty != null) { PropertyInfo prop4 = cachedIsGameOverProperty; getIsGameOverValue = (object obj) => (bool)prop4.GetValue(obj); } if (cachedIsTimeFreezeMethod != null) { MethodInfo method = cachedIsTimeFreezeMethod; invokeIsTimeFreeze = (object obj) => (bool)method.Invoke(obj, null); } if (cachedUiManagerInstanceProperty != null) { PropertyInfo prop3 = cachedUiManagerInstanceProperty; getUiManagerInstance = () => prop3.GetValue(null); } if (cachedPauseProperty != null) { PropertyInfo prop2 = cachedPauseProperty; getPauseValue = (object obj) => prop2.GetValue(obj); } if (cachedPauseCurrentProperty != null) { PropertyInfo prop = cachedPauseCurrentProperty; getPauseCurrentValue = (object obj) => prop.GetValue(obj); } delegatesCompiled = true; if (Plugin.EnableDebugLogs.Value) { ManualLogSource log = Plugin.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Reflection delegates compiled: GM="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(getGameManagerInstance != null); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", UI="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(getUiManagerInstance != null); } log.LogInfo(val); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(40, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to compile reflection delegates: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message); } log2.LogWarning(val2); delegatesCompiled = true; } } private static void ResetReflectionDelegates() { delegatesCompiled = false; getGameManagerInstance = null; getCutsceneValue = null; getIsGameOverValue = null; invokeIsTimeFreeze = null; getUiManagerInstance = null; getPauseValue = null; getPauseCurrentValue = null; cachedGameManagerType = null; cachedUiManagerType = null; cachedLevelupScreenType = null; } public static void Cleanup() { MarkDistanceSettingsDirty(); foreach (HealthBarUI activeBar in activeBarList) { if (activeBar != null) { ReturnHealthBarToPool(activeBar); } } activeBarList.Clear(); healthBarsByEnemyId.Clear(); trackedEnemies.Clear(); creationQueue.Clear(); queuedIds.Clear(); while (healthBarPool.Count > 0) { healthBarPool.Pop()?.Destroy(); } poolPreallocated = false; } private static HealthBarUI GetPooledHealthBarUI(Enemy enemy, uint id) { while (healthBarPool.Count > 0) { HealthBarUI healthBarUI = healthBarPool.Pop(); if (healthBarUI != null && healthBarUI.IsValid()) { try { healthBarUI.Reinitialize(enemy, id); return healthBarUI; } catch { } } } return new HealthBarUI(enemy, id); } private static void ReturnHealthBarToPool(HealthBarUI healthBarUI) { if (healthBarUI != null && healthBarUI.IsValid()) { healthBarUI.ResetForPooling(); if (healthBarPool.Count < Plugin.PoolPreallocationCount.Value) { healthBarPool.Push(healthBarUI); } else { healthBarUI.Destroy(); } } } public static void PreallocatePool() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown if (poolPreallocated) { return; } int num = Plugin.PoolPreallocationCount.Value - healthBarPool.Count; if (num <= 0) { poolPreallocated = true; return; } ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(30, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Pre-allocating "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" health bars..."); } log.LogInfo(val); for (int i = 0; i < num; i++) { HealthBarUI item = HealthBarUI.CreateForPool(); healthBarPool.Push(item); } poolPreallocated = true; ManualLogSource log2 = Plugin.Log; val = new BepInExInfoLogInterpolatedStringHandler(41, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Pool pre-allocation complete. Pool size: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(healthBarPool.Count); } log2.LogInfo(val); } internal static void MarkDistanceSettingsDirty() { distanceSettingsDirty = true; sqrSkipUpdateDistance = 0f; sqrFadeEndDistance = 0f; HealthBarUI.InvalidateFadeCache(); } public static string GetEnemyTypeName(Enemy enemy) { if ((Object)(object)enemy == (Object)null) { return "null"; } try { Type type = ((object)enemy).GetType(); PropertyInfo property = type.GetProperty("enemyData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { string text = TryGetObjectName(property.GetValue(enemy)); if (text != null) { return text; } } FieldInfo fieldInfo = type.GetField("_enemyData_k__BackingField", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("<enemyData>k__BackingField", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { string text2 = TryGetObjectName(fieldInfo.GetValue(enemy)); if (text2 != null) { return text2; } } string[] array = new string[6] { "data", "enemyType", "type", "enemyInfo", "info", "config" }; foreach (string name in array) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { string text3 = TryGetObjectName(field.GetValue(enemy)); if (text3 != null) { return text3; } } PropertyInfo property2 = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(property2 != null) || !property2.CanRead) { continue; } try { string text4 = TryGetObjectName(property2.GetValue(enemy)); if (text4 != null) { return text4; } } catch { } } } catch { } GameObject gameObject = ((Component)enemy).gameObject; return ((gameObject == null) ? null : ((Object)gameObject).name?.Replace("(Clone)", "").Trim()) ?? "Unknown"; } private static string TryGetObjectName(object value) { if (value == null) { return null; } Object val = (Object)((value is Object) ? value : null); if (val != null) { string name = val.name; if (!string.IsNullOrEmpty(name)) { return name; } } try { Type type = value.GetType(); if (type.IsEnum) { return value.ToString(); } PropertyInfo property = type.GetProperty("name", BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanRead) { object value2 = property.GetValue(value); if (value2 != null) { string text = value2.ToString(); if (!string.IsNullOrEmpty(text)) { return text; } } } } catch { } return null; } } public class HealthBarUI { private static readonly char[] TextBuffer = new char[32]; private readonly GameObject rootObject; private readonly Canvas canvas; private readonly CanvasGroup canvasGroup; private readonly RectTransform canvasRect; private readonly RawImage backgroundBar; private readonly RawImage foregroundBar; private readonly Transform foregroundTransform; private readonly RawImage damageBar; private readonly Transform damageTransform; private TextMeshProUGUI healthText; private Vector3 scaleBuffer = Vector3.one; private uint enemyId; private bool useManualBillboard; private float cachedMaxHp = -1f; private bool isPlayingDeathAnimation; private bool isDestroyed; private Transform trackedBone; private Renderer trackedRenderer; private float deathAnimationTime; private const float DEATH_ANIMATION_DURATION = 0.1f; private Vector3 lastKnownPosition; private float currentHealth = 1f; private float lastHealthPercent = 1f; private bool isDamageFlashing; private bool isLingering; private float damageFlashTime; private float damageBarTargetScale = 1f; private const float DAMAGE_FLASH_DURATION = 0.5f; private float lastHpValue = -1f; private float lastMaxHpValue = -1f; private static float sqrFadeStart = -1f; private static float sqrFadeEnd = -1f; private static float cachedFadeStart = -1f; private static float cachedFadeEnd = -1f; private static readonly Color[] ColorLUT = (Color[])(object)new Color[256]; private static bool colorLutDirty = true; public uint EnemyId => enemyId; public Vector3 LastKnownPosition => lastKnownPosition; public Vector3 CurrentPosition { get { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rootObject != (Object)null)) { return lastKnownPosition; } return rootObject.transform.position; } } internal static void InvalidateColorLUT() { colorLutDirty = true; } private static void RebuildColorLUT() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) Color cachedLowHealthColor = Plugin.CachedLowHealthColor; Color cachedMidHealthColor = Plugin.CachedMidHealthColor; Color cachedFullHealthColor = Plugin.CachedFullHealthColor; for (int i = 0; i < 256; i++) { float num = (float)i / 255f; if (num < 0.5f) { ColorLUT[i] = Color.Lerp(cachedLowHealthColor, cachedMidHealthColor, num * 2f); } else { ColorLUT[i] = Color.Lerp(cachedMidHealthColor, cachedFullHealthColor, (num - 0.5f) * 2f); } } colorLutDirty = false; } internal static void InvalidateFadeCache() { cachedFadeStart = -1f; cachedFadeEnd = -1f; sqrFadeStart = -1f; sqrFadeEnd = -1f; } public void ApplyBillboardRotation(Quaternion rotation) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rootObject != (Object)null) { rootObject.transform.rotation = rotation; } } public static HealthBarUI CreateForPool() { return new HealthBarUI(); } private HealthBarUI() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Expected O, but got Unknown //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Expected O, but got Unknown //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) enemyId = 0u; currentHealth = 1f; lastHealthPercent = 1f; isDamageFlashing = false; isLingering = false; damageFlashTime = 0f; damageBarTargetScale = 1f; trackedBone = null; trackedRenderer = null; rootObject = new GameObject("HealthBar_Pooled"); rootObject.transform.position = Vector3.zero; lastKnownPosition = Vector3.zero; canvas = rootObject.AddComponent<Canvas>(); canvas.renderMode = (RenderMode)2; canvas.sortingOrder = 100; canvasGroup = rootObject.AddComponent<CanvasGroup>(); canvasGroup.alpha = 1f; canvasRect = ((Component)canvas).GetComponent<RectTransform>(); float num = Plugin.BarWidth.Value; float num2 = Plugin.BarHeight.Value; canvasRect.sizeDelta = new Vector2(num, num2 + 30f); ((Transform)canvasRect).localScale = Vector3.one * 0.01f; useManualBillboard = true; GameObject val = new GameObject("Background"); val.transform.SetParent(rootObject.transform, false); RectTransform obj = val.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(0.5f, 0.5f); obj.anchorMax = new Vector2(0.5f, 0.5f); obj.pivot = new Vector2(0.5f, 0.5f); obj.sizeDelta = new Vector2(num, num2); obj.anchoredPosition = Vector2.zero; val.AddComponent<CanvasRenderer>(); backgroundBar = val.AddComponent<RawImage>(); ((Graphic)backgroundBar).color = Plugin.CachedBackgroundColor; ((Graphic)backgroundBar).raycastTarget = false; GameObject val2 = new GameObject("DamageFlash"); val2.transform.SetParent(val.transform, false); RectTransform obj2 = val2.AddComponent<RectTransform>(); obj2.anchoredPosition = new Vector2((0f - num) / 2f, 0f); obj2.sizeDelta = new Vector2(num, num2); obj2.pivot = new Vector2(0f, 0.5f); ((Transform)obj2).localScale = new Vector3(1f, 1f, 1f); val2.AddComponent<CanvasRenderer>(); damageBar = val2.AddComponent<RawImage>(); ((Graphic)damageBar).color = Color.white; ((Graphic)damageBar).raycastTarget = false; damageTransform = val2.transform; GameObject val3 = new GameObject("Current"); val3.transform.SetParent(val.transform, false); RectTransform obj3 = val3.AddComponent<RectTransform>(); obj3.anchoredPosition = new Vector2((0f - num) / 2f, 0f); obj3.sizeDelta = new Vector2(num, num2); obj3.pivot = new Vector2(0f, 0.5f); ((Transform)obj3).localScale = new Vector3(1f, 1f, 1f); val3.AddComponent<CanvasRenderer>(); foregroundBar = val3.AddComponent<RawImage>(); ((Graphic)foregroundBar).color = Plugin.CachedFullHealthColor; ((Graphic)foregroundBar).raycastTarget = false; foregroundTransform = val3.transform; if (Plugin.ShowHealthText.Value) { CreateHealthText(num, num2); } rootObject.SetActive(false); isDestroyed = false; } public HealthBarUI(Enemy enemy, uint id) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_04d6: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_04db: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Unknown result type (might be due to invalid IL or missing references) //IL_04f4: Unknown result type (might be due to invalid IL or missing references) //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_051c: Unknown result type (might be due to invalid IL or missing references) //IL_0526: Unknown result type (might be due to invalid IL or missing references) //IL_052d: Unknown result type (might be due to invalid IL or missing references) //IL_0543: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Expected O, but got Unknown //IL_0574: Unknown result type (might be due to invalid IL or missing references) //IL_0589: Unknown result type (might be due to invalid IL or missing references) //IL_059e: Unknown result type (might be due to invalid IL or missing references) //IL_05ad: Unknown result type (might be due to invalid IL or missing references) //IL_05b7: Unknown result type (might be due to invalid IL or missing references) //IL_05dc: Unknown result type (might be due to invalid IL or missing references) //IL_05f7: Unknown result type (might be due to invalid IL or missing references) //IL_05fe: Expected O, but got Unknown //IL_0628: Unknown result type (might be due to invalid IL or missing references) //IL_0637: Unknown result type (might be due to invalid IL or missing references) //IL_064c: Unknown result type (might be due to invalid IL or missing references) //IL_0665: Unknown result type (might be due to invalid IL or missing references) //IL_068a: Unknown result type (might be due to invalid IL or missing references) //IL_06b2: Unknown result type (might be due to invalid IL or missing references) //IL_06b9: Expected O, but got Unknown //IL_06e3: Unknown result type (might be due to invalid IL or missing references) //IL_06f2: Unknown result type (might be due to invalid IL or missing references) //IL_0707: Unknown result type (might be due to invalid IL or missing references) //IL_0720: Unknown result type (might be due to invalid IL or missing references) //IL_0745: Unknown result type (might be due to invalid IL or missing references) enemyId = id; currentHealth = 1f; lastHealthPercent = 1f; isDamageFlashing = false; isLingering = false; damageFlashTime = 0f; damageBarTargetScale = 1f; trackedBone = FindHeadBone(enemy); if ((Object)(object)trackedBone != (Object)null) { trackedRenderer = ((Component)trackedBone).GetComponent<Renderer>(); if ((Object)(object)trackedRenderer == (Object)null) { trackedRenderer = ((Component)trackedBone).GetComponentInChildren<Renderer>(); } } else if (Plugin.EnableDebugLogs.Value) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(60, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HealthBarInit] ID:"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(id); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" No bone found, using default positioning"); } log.LogInfo(val); } rootObject = new GameObject($"HealthBar_{id}"); Transform val2 = (((Object)(object)trackedBone != (Object)null) ? trackedBone : ((Component)enemy).transform); rootObject.transform.SetParent(val2, false); Vector3 zero = Vector3.zero; bool flag2 = HealthBarManager.UsesMeshHeightPositioning(HealthBarManager.GetEnemyTypeName(enemy)); if (!flag2) { flag2 = HealthBarManager.UsesMeshHeightPositioning(((Object)enemy).name.Replace("(Clone)", "").Trim()); } float enemyMeshHeight = HealthBarManager.GetEnemyMeshHeight(enemy); Bounds bounds; if (flag2 && enemyMeshHeight > 0f && (Object)(object)trackedBone != (Object)null && (Object)(object)trackedRenderer != (Object)null) { float num = enemyMeshHeight + Plugin.BarYOffset.Value; Vector3 lossyScale = trackedBone.lossyScale; float num2 = 1f / Mathf.Max(new float[4] { lossyScale.x, lossyScale.y, lossyScale.z, 0.01f }); num *= num2; float x = trackedBone.position.x; bounds = trackedRenderer.bounds; Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(x, ((Bounds)(ref bounds)).max.y, trackedBone.position.z); Vector3 val4 = trackedBone.InverseTransformPoint(val3); if (Mathf.Abs(val4.z) > Mathf.Abs(val4.y)) { ((Vector3)(ref zero))..ctor(0f, 0f, num); } else { ((Vector3)(ref zero))..ctor(0f, num, 0f); } } else if ((Object)(object)trackedBone != (Object)null && (Object)(object)trackedRenderer != (Object)null) { float x2 = trackedBone.position.x; bounds = trackedRenderer.bounds; Vector3 val5 = default(Vector3); ((Vector3)(ref val5))..ctor(x2, ((Bounds)(ref bounds)).max.y, trackedBone.position.z); Vector3 val6 = trackedBone.InverseTransformPoint(val5); float num3 = Mathf.Max(Mathf.Abs(val6.y), Mathf.Abs(val6.z)); if (Mathf.Abs(val6.z) > Mathf.Abs(val6.y)) { ((Vector3)(ref zero))..ctor(0f, 0f, num3 + Plugin.BarYOffset.Value); } else { ((Vector3)(ref zero))..ctor(0f, num3 + Plugin.BarYOffset.Value, 0f); } } else { ((Vector3)(ref zero))..ctor(0f, Plugin.BarYOffset.Value, 0f); } rootObject.transform.localPosition = zero; lastKnownPosition = rootObject.transform.position; canvas = rootObject.AddComponent<Canvas>(); canvas.renderMode = (RenderMode)2; canvas.sortingOrder = 100; canvasGroup = rootObject.AddComponent<CanvasGroup>(); canvasGroup.alpha = 1f; canvasRect = ((Component)canvas).GetComponent<RectTransform>(); float num4 = Plugin.BarWidth.Value; float num5 = Plugin.BarHeight.Value; canvasRect.sizeDelta = new Vector2(num4, num5 + 30f); Vector3 val7 = (((Object)(object)rootObject.transform.parent != (Object)null) ? rootObject.transform.parent.lossyScale : Vector3.one); float num6 = 1f / Mathf.Max(new float[4] { val7.x, val7.y, val7.z, 0.01f }); ((Transform)canvasRect).localScale = Vector3.one * 0.01f * num6; useManualBillboard = true; GameObject val8 = new GameObject("Background"); val8.transform.SetParent(rootObject.transform, false); RectTransform obj = val8.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(0.5f, 0.5f); obj.anchorMax = new Vector2(0.5f, 0.5f); obj.pivot = new Vector2(0.5f, 0.5f); obj.sizeDelta = new Vector2(num4, num5); obj.anchoredPosition = Vector2.zero; val8.AddComponent<CanvasRenderer>(); backgroundBar = val8.AddComponent<RawImage>(); ((Graphic)backgroundBar).color = Plugin.CachedBackgroundColor; ((Graphic)backgroundBar).raycastTarget = false; GameObject val9 = new GameObject("DamageFlash"); val9.transform.SetParent(val8.transform, false); RectTransform obj2 = val9.AddComponent<RectTransform>(); obj2.anchoredPosition = new Vector2((0f - num4) / 2f, 0f); obj2.sizeDelta = new Vector2(num4, num5); obj2.pivot = new Vector2(0f, 0.5f); ((Transform)obj2).localScale = new Vector3(1f, 1f, 1f); val9.AddComponent<CanvasRenderer>(); damageBar = val9.AddComponent<RawImage>(); ((Graphic)damageBar).color = Color.white; ((Graphic)damageBar).raycastTarget = false; damageTransform = val9.transform; GameObject val10 = new GameObject("Current"); val10.transform.SetParent(val8.transform, false); RectTransform obj3 = val10.AddComponent<RectTransform>(); obj3.anchoredPosition = new Vector2((0f - num4) / 2f, 0f); obj3.sizeDelta = new Vector2(num4, num5); obj3.pivot = new Vector2(0f, 0.5f); ((Transform)obj3).localScale = new Vector3(1f, 1f, 1f); val10.AddComponent<CanvasRenderer>(); foregroundBar = val10.AddComponent<RawImage>(); ((Graphic)foregroundBar).color = Plugin.CachedFullHealthColor; ((Graphic)foregroundBar).raycastTarget = false; foregroundTransform = val10.transform; if (Plugin.ShowHealthText.Value) { CreateHealthText(num4, num5); } rootObject.SetActive(Plugin.ShowHealthBars.Value); Update(enemy); } private void CreateHealthText(float barWidth, float barHeight) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HealthText"); val.transform.SetParent(rootObject.transform, false); RectTransform obj = val.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(0.5f, 0.5f); obj.anchorMax = new Vector2(0.5f, 0.5f); obj.pivot = new Vector2(0.5f, 0.5f); obj.sizeDelta = new Vector2(barWidth, 30f); obj.anchoredPosition = new Vector2(0f, barHeight / 2f + 15f); healthText = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)healthText).alignment = (TextAlignmentOptions)514; ((TMP_Text)healthText).fontSize = Plugin.TextSize.Value; ((Graphic)healthText).color = Color.white; ((TMP_Text)healthText).text = ""; ((TMP_Text)healthText).enableWordWrapping = false; ((TMP_Text)healthText).overflowMode = (TextOverflowModes)0; ((TMP_Text)healthText).richText = false; ((TMP_Text)healthText).enableKerning = false; ((TMP_Text)healthText).extraPadding = false; ((Graphic)healthText).raycastTarget = false; ((TMP_Text)healthText).enableAutoSizing = false; ((TMP_Text)healthText).geometrySortingOrder = (VertexSortingOrder)0; } public void Update(Enemy enemy, float sqrDistanceToCamera = -1f) { //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) try { if (isPlayingDeathAnimation) { UpdateDeathAnimation(); return; } if ((Object)(object)enemy == (Object)null || enemy.hp <= 0f) { if (Plugin.EnableDeathAnimation.Value) { StartDeathAnimation(); } else { Destroy(); } return; } lastKnownPosition = rootObject.transform.position; if (sqrDistanceToCamera < 0f) { Camera val = HealthBarManager.CachedCamera ?? Camera.main; if ((Object)(object)val != (Object)null) { Vector3 val2 = lastKnownPosition - ((Component)val).transform.position; sqrDistanceToCamera = ((Vector3)(ref val2)).sqrMagnitude; } } UpdateDistanceFadeSqr(sqrDistanceToCamera); if (canvasGroup.alpha <= 0.01f) { return; } float hp = enemy.hp; float healthPercent = GetHealthPercent(enemy, hp); if (healthPercent < lastHealthPercent && !isDamageFlashing && Plugin.ShowDamageFlash.Value) { StartDamageFlash(enemy, lastHealthPercent, healthPercent); } if (isDamageFlashing) { UpdateDamageFlash(); } else { scaleBuffer.x = healthPercent; damageTransform.localScale = scaleBuffer; } currentHealth = healthPercent; scaleBuffer.x = healthPercent; foregroundTransform.localScale = scaleBuffer; if (Plugin.UseColorGradient.Value) { ((Graphic)foregroundBar).color = GetHealthColor(healthPercent); } lastHealthPercent = healthPercent; if ((Object)(object)healthText != (Object)null) { float maxHp = GetMaxHp(enemy, hp, healthPercent); int num = ((hp > 0f && hp < 1f) ? 1 : Mathf.RoundToInt(hp)); int num2 = Mathf.RoundToInt(maxHp); if ((float)num != lastHpValue || (float)num2 != lastMaxHpValue) { int num3 = FormatHealthText(num, num2); ((TMP_Text)healthText).SetCharArray(Il2CppStructArray<char>.op_Implicit(TextBuffer), 0, num3); lastHpValue = num; lastMaxHpValue = num2; } } } catch (Exception ex) { if (Plugin.EnableDebugLogs.Value && enemyId < 3) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(26, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[BarUpdate] Enemy "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<uint>(enemyId); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" error: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message); } log.LogError(val3); } } } private void StartDeathAnimation() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown if (isPlayingDeathAnimation) { return; } isPlayingDeathAnimation = true; deathAnimationTime = 0f; isDamageFlashing = false; isLingering = false; damageFlashTime = 0f; Transform transform = rootObject.transform; transform.SetParent((Transform)null, true); transform.position = lastKnownPosition; ((Graphic)foregroundBar).color = Plugin.CachedLowHealthColor; scaleBuffer.x = 1f; foregroundTransform.localScale = scaleBuffer; scaleBuffer.x = 0f; damageTransform.localScale = scaleBuffer; scaleBuffer.x = 1f; if ((Object)(object)healthText != (Object)null) { ((Component)healthText).gameObject.SetActive(false); } if (Plugin.EnableDebugLogs.Value) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(30, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[DeathAnim] Started for enemy "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(enemyId); } log.LogInfo(val); } } private void UpdateDeathAnimation() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (HealthBarManager.IsGamePaused()) { return; } deathAnimationTime += Time.deltaTime; float num = deathAnimationTime / 0.1f; if (num >= 1f) { Destroy(); return; } if (lastKnownPosition != Vector3.zero) { rootObject.transform.position = lastKnownPosition; } float num2 = 1f + num * 1.5f; ((Transform)canvasRect).localScale = Vector3.one * 0.01f * num2; float alpha = 1f - num; canvasGroup.alpha = alpha; } private void StartDamageFlash(Enemy enemy, float previousHealthPercent, float newHealthPercent) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (!isDamageFlashing) { isDamageFlashing = true; isLingering = true; damageFlashTime = 0f; scaleBuffer.x = previousHealthPercent; damageTransform.localScale = scaleBuffer; damageBarTargetScale = newHealthPercent; } } private void UpdateDamageFlash() { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) if (HealthBarManager.IsGamePaused()) { return; } damageFlashTime += Time.deltaTime; if (isLingering) { float num = (float)Plugin.DamageFlashLingerMs.Value / 1000f; if (damageFlashTime >= num) { isLingering = false; damageFlashTime = 0f; } return; } float num2 = damageFlashTime / 0.5f; if (num2 >= 1f) { isDamageFlashing = false; isLingering = false; damageFlashTime = 0f; scaleBuffer.x = damageBarTargetScale; damageTransform.localScale = scaleBuffer; } else { float x = Mathf.Lerp(damageTransform.localScale.x, damageBarTargetScale, num2 * 2f); scaleBuffer.x = x; damageTransform.localScale = scaleBuffer; } } private void UpdateDistanceFadeSqr(float sqrDistance) { if (sqrDistance < 0f) { canvasGroup.alpha = 1f; return; } float num = Plugin.FadeStartDistance.Value; if (Math.Abs(num - cachedFadeStart) > 0.1f) { cachedFadeStart = num; sqrFadeStart = num * num; float num2 = (cachedFadeEnd = Plugin.FadeEndDistance.Value); sqrFadeEnd = num2 * num2; } if (sqrDistance < sqrFadeStart) { canvasGroup.alpha = 1f; return; } if (sqrDistance > sqrFadeEnd) { canvasGroup.alpha = 0f; return; } float num3 = (Mathf.Sqrt(sqrDistance) - cachedFadeStart) / (cachedFadeEnd - cachedFadeStart); canvasGroup.alpha = 1f - num3; } public void UpdateVisibility(float sqrDistanceToCamera) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (!isPlayingDeathAnimation) { if ((Object)(object)rootObject != (Object)null) { lastKnownPosition = rootObject.transform.position; } UpdateDistanceFadeSqr(sqrDistanceToCamera); } } public void LateTick() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (useManualBillboard && (isPlayingDeathAnimation || rootObject.activeInHierarchy) && (!((((Object)(object)canvasGroup != (Object)null) ? canvasGroup.alpha : 1f) <= 0.01f) || isPlayingDeathAnimation) && HealthBarManager.HasValidBillboard) { rootObject.transform.rotation = HealthBarManager.BillboardRotation; } } private float GetMaxHp(Enemy enemy, float currentHp, float healthPercent) { if (cachedMaxHp > 0f && healthPercent > 0.99f) { return cachedMaxHp; } try { if (healthPercent > 0.01f && currentHp > 0f) { float result = currentHp / healthPercent; if (healthPercent > 0.99f) { cachedMaxHp = result; } return result; } } catch { } if (cachedMaxHp > 0f) { return cachedMaxHp; } if (!(currentHp > 0f)) { return 100f; } return currentHp; } private float GetHealthPercent(Enemy enemy, float currentHp) { try { float hpRatio = enemy.GetHpRatio(); if (!float.IsNaN(hpRatio) && !float.IsInfinity(hpRatio) && hpRatio >= 0f && hpRatio <= 1.1f) { return Mathf.Clamp01(hpRatio); } } catch { } if (cachedMaxHp > 0f && currentHp > 0f) { return Mathf.Clamp01(currentHp / cachedMaxHp); } return 1f; } private static Color GetHealthColor(float healthPercent) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (colorLutDirty) { RebuildColorLUT(); } int num = (int)(healthPercent * 255f); if (num < 0) { num = 0; } else if (num > 255) { num = 255; } return ColorLUT[num]; } public void SetVisible(bool visible) { if ((Object)(object)rootObject != (Object)null) { rootObject.SetActive(visible); } } public void SetCulled(bool culled) { if ((Object)(object)rootObject != (Object)null && !isPlayingDeathAnimation) { rootObject.SetActive(!culled); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsValid() { if (!isDestroyed) { return (Object)(object)rootObject != (Object)null; } return false; } public bool IsPlayingDeathAnimation() { return isPlayingDeathAnimation; } public bool IsDamageFlashing() { return isDamageFlashing; } public void Destroy() { isDestroyed = true; if ((Object)(object)rootObject != (Object)null) { Object.Destroy((Object)(object)rootObject); } } public void Reinitialize(Enemy enemy, uint id) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_0449: Unknown result type (might be due to invalid IL or missing references) //IL_0467: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_0499: Unknown result type (might be due to invalid IL or missing references) //IL_04cd: Unknown result type (might be due to invalid IL or missing references) //IL_04e6: Unknown result type (might be due to invalid IL or missing references) //IL_0500: Unknown result type (might be due to invalid IL or missing references) //IL_0518: Unknown result type (might be due to invalid IL or missing references) //IL_0532: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_055a: Unknown result type (might be due to invalid IL or missing references) //IL_056a: Unknown result type (might be due to invalid IL or missing references) //IL_05c1: Unknown result type (might be due to invalid IL or missing references) //IL_05de: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rootObject == (Object)null) { throw new InvalidOperationException("Cannot reinitialize destroyed health bar"); } enemyId = id; isDestroyed = false; cachedMaxHp = -1f; lastHpValue = -1f; lastMaxHpValue = -1f; isPlayingDeathAnimation = false; deathAnimationTime = 0f; currentHealth = 1f; lastHealthPercent = 1f; isDamageFlashing = false; isLingering = false; damageFlashTime = 0f; damageBarTargetScale = 1f; scaleBuffer.x = 1f; damageTransform.localScale = scaleBuffer; trackedBone = FindHeadBone(enemy); Transform transform = rootObject.transform; Transform val = (((Object)(object)trackedBone != (Object)null) ? trackedBone : ((Component)enemy).transform); transform.SetParent(val, false); bool flag = HealthBarManager.UsesMeshHeightPositioning(HealthBarManager.GetEnemyTypeName(enemy)); if (!flag) { flag = HealthBarManager.UsesMeshHeightPositioning(((Object)enemy).name.Replace("(Clone)", "").Trim()); } if ((Object)(object)trackedBone != (Object)null) { trackedRenderer = ((Component)trackedBone).GetComponent<Renderer>(); if ((Object)(object)trackedRenderer == (Object)null) { trackedRenderer = ((Component)trackedBone).GetComponentInChildren<Renderer>(); } } float enemyMeshHeight = HealthBarManager.GetEnemyMeshHeight(enemy); Bounds bounds; if (flag && enemyMeshHeight > 0f && (Object)(object)trackedBone != (Object)null && (Object)(object)trackedRenderer != (Object)null) { float num = enemyMeshHeight + Plugin.BarYOffset.Value; Vector3 lossyScale = trackedBone.lossyScale; float num2 = 1f / Mathf.Max(new float[4] { lossyScale.x, lossyScale.y, lossyScale.z, 0.01f }); num *= num2; float x = trackedBone.position.x; bounds = trackedRenderer.bounds; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(x, ((Bounds)(ref bounds)).max.y, trackedBone.position.z); Vector3 val3 = trackedBone.InverseTransformPoint(val2); if (Mathf.Abs(val3.z) > Mathf.Abs(val3.y)) { transform.localPosition = new Vector3(0f, 0f, num); } else { transform.localPosition = new Vector3(0f, num, 0f); } } else if ((Object)(object)trackedBone != (Object)null && (Object)(object)trackedRenderer != (Object)null) { float x2 = trackedBone.position.x; bounds = trackedRenderer.bounds; Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(x2, ((Bounds)(ref bounds)).max.y, trackedBone.position.z); Vector3 val5 = trackedBone.InverseTransformPoint(val4); float num3 = Mathf.Max(Mathf.Abs(val5.y), Mathf.Abs(val5.z)); Vector3 localPosition = default(Vector3); if (Mathf.Abs(val5.z) > Mathf.Abs(val5.y)) { ((Vector3)(ref localPosition))..ctor(0f, 0f, num3 + Plugin.BarYOffset.Value); } else { ((Vector3)(ref localPosition))..ctor(0f, num3 + Plugin.BarYOffset.Value, 0f); } transform.localPosition = localPosition; } else if ((Object)(object)trackedBone != (Object)null) { transform.localPosition = new Vector3(0f, Plugin.BarYOffset.Value, 0f); } else { transform.localPosition = new Vector3(0f, Plugin.BarYOffset.Value, 0f); } lastKnownPosition = transform.position; canvasGroup.alpha = 1f; Vector3 val6 = (((Object)(object)rootObject.transform.parent != (Object)null) ? rootObject.transform.parent.lossyScale : Vector3.one); float num4 = 1f / Mathf.Max(new float[4] { val6.x, val6.y, val6.z, 0.01f }); ((Transform)canvasRect).localScale = Vector3.one * 0.01f * num4; scaleBuffer.x = 1f; foregroundTransform.localScale = scaleBuffer; float num5 = Plugin.BarWidth.Value; float num6 = Plugin.BarHeight.Value; canvasRect.sizeDelta = new Vector2(num5, num6 + 30f); ((Component)backgroundBar).GetComponent<RectTransform>().sizeDelta = new Vector2(num5, num6); RectTransform component = ((Component)damageBar).GetComponent<RectTransform>(); component.sizeDelta = new Vector2(num5, num6); component.anchoredPosition = new Vector2((0f - num5) / 2f, 0f); RectTransform component2 = ((Component)foregroundBar).GetComponent<RectTransform>(); component2.sizeDelta = new Vector2(num5, num6); component2.anchoredPosition = new Vector2((0f - num5) / 2f, 0f); ((Graphic)backgroundBar).color = Plugin.CachedBackgroundColor; ((Graphic)foregroundBar).color = Plugin.CachedFullHealthColor; if (Plugin.ShowHealthText.Value) { if ((Object)(object)healthText == (Object)null) { CreateHealthText(num5, num6); } else { ((Component)healthText).gameObject.SetActive(true); RectTransform component3 = ((Component)healthText).GetComponent<RectTransform>(); component3.sizeDelta = new Vector2(num5, 30f); component3.anchoredPosition = new Vector2(0f, num6 / 2f + 15f); } ((TMP_Text)healthText).text = ""; ((TMP_Text)healthText).fontSize = Plugin.TextSize.Value; } else if ((Object)(object)healthText != (Object)null) { ((Component)healthText).gameObject.SetActive(false); } rootObject.SetActive(Plugin.ShowHealthBars.Value); Update(enemy); } public void ResetForPooling() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rootObject != (Object)null) { rootObject.transform.SetParent((Transform)null, true); cachedMaxHp = -1f; lastHpValue = -1f; lastMaxHpValue = -1f; isPlayingDeathAnimation = false; deathAnimationTime = 0f; trackedBone = null; trackedRenderer = null; lastKnownPosition = Vector3.zero; currentHealth = 1f; lastHealthPercent = 1f; isDamageFlashing = false; isLingering = false; damageFlashTime = 0f; damageBarTargetScale = 1f; rootObject.SetActive(false); if ((Object)(object)healthText != (Object)null) { ((TMP_Text)healthText).text = ""; } } } private Transform FindHeadBone(Enemy enemy) { if ((Object)(object)enemy == (Object)null) { return null; } string key = ((Object)enemy).name.Replace("(Clone)", "").Trim(); if (HealthBarManager.BoneNameCache.TryGetValue(key, out var value)) { Transform val = FindChildRecursive(((Component)enemy).transform, value); if ((Object)(object)val != (Object)null) { return val; } } try { Animator componentInChildren = ((Component)enemy).GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren != (Object)null && componentInChildren.isHuman) { Transform boneTransform = componentInChildren.GetBoneTransform((HumanBodyBones)10); if ((Object)(object)boneTransform != (Object)null) { return boneTransform; } } } catch { } string[] array = new string[4] { "head", "Render", "Body", "Mesh" }; foreach (string text in array) { Transform val2 = FindChildRecursive(((Component)enemy).transform, text); if ((Object)(object)val2 != (Object)null) { HealthBarManager.BoneNameCache[key] = text; return val2; } } return null; } private Transform FindChildRecursive(Transform parent, string namePart) { for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); if (((Object)child).name.IndexOf(namePart, StringComparison.OrdinalIgnoreCase) >= 0) { return child; } Transform val = FindChildRecursive(child, namePart); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static int FormatHealthText(int currentHp, int maxHp) { int pos = 0; pos = WriteInt(currentHp, pos); TextBuffer[pos++] = ' '; TextBuffer[pos++] = '/'; TextBuffer[pos++] = ' '; return WriteInt(maxHp, pos); } private static int WriteInt(int value, int pos) { if (value == 0) { TextBuffer[pos++] = '0'; return pos; } if (value < 0) { TextBuffer[pos++] = '-'; value = -value; } int num = pos; while (value > 0) { TextBuffer[pos++] = (char)(48 + value % 10); value /= 10; } int num2 = pos - 1; while (num < num2) { ref char reference = ref TextBuffer[num]; ref char reference2 = ref TextBuffer[num2]; char c = TextBuffer[num2]; char c2 = TextBuffer[num]; reference = c; reference2 = c2; num++; num2--; } return pos; } } [HarmonyPatch(typeof(Enemy), "InitEnemy")] internal static class EnemyInitPatch { private static void Postfix(Enemy __instance, uint id) { if ((Object)(object)__instance != (Object)null && Plugin.ShowHealthBars.Value) { HealthBarManager.CreateHealthBar(__instance, id); } } } [HarmonyPatch(typeof(Enemy), "Damage")] internal static class EnemyDamagePatch { private static void Postfix(Enemy __instance) { if ((Object)(object)__instance != (Object)null && Plugin.ShowHealthBars.Value) { HealthBarManager.UpdateHealthBar(__instance, __instance.id); } } } [HarmonyPatch(typeof(Enemy), "OnDestroy")] internal static class EnemyDestroyPatch { private static void Prefix(Enemy __instance) { if ((Object)(object)__instance != (Object)null) { HealthBarManager.RemoveHealthBar(__instance.id); } } } [HarmonyPatch(typeof(EnemyManager), "RemoveEnemy")] internal static class EnemyManagerRemovePatch { private static void Postfix(EnemyManager __instance, Enemy enemy) { if ((Object)(object)enemy != (Object)null) { HealthBarManager.RemoveHealthBar(enemy.