using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using TMPro;
using ULTRAKILL.Cheats;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("UltrakillModTest1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UltrakillModTest1")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("2c7d4b1e-04d7-49d9-8ec3-4571b1b7fff2")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BetterHud;
public static class PlayerDamageEvents
{
public static event Action<int> OnHeavyDamageTaken;
internal static void TriggerHeavyDamage(int damage)
{
Action<int> onHeavyDamageTaken = PlayerDamageEvents.OnHeavyDamageTaken;
int num = ((onHeavyDamageTaken != null) ? onHeavyDamageTaken.GetInvocationList().Length : 0);
Debug.LogError((object)$"[BetterHud][DamageEvent] TriggerHeavyDamage({damage}), listeners={num}");
if (num == 0)
{
Debug.LogError((object)"[BetterHud][DamageEvent] WARNING: OnHeavyDamageTaken has no listeners!");
return;
}
try
{
PlayerDamageEvents.OnHeavyDamageTaken(damage);
}
catch (Exception arg)
{
Debug.LogError((object)$"[BetterHud][DamageEvent] Exception while invoking event:\n{arg}");
}
}
}
[HarmonyPatch(typeof(NewMovement), "GetHurt")]
public static class GetHurtPatch
{
[HarmonyPrefix]
public static void Prefix(NewMovement __instance, ref int damage, bool invincible, bool ignoreInvincibility)
{
if ((Object)(object)__instance == (Object)null)
{
Debug.LogError((object)"[BetterHud][GetHurt] __instance is null!");
return;
}
if (__instance.dead || __instance.levelOver || !(!invincible || ((Component)__instance).gameObject.layer != 15 || ignoreInvincibility) || damage <= 0)
{
Debug.LogError((object)"[BetterHud][GetHurt] Ignored by original damage conditions.");
return;
}
int num = damage;
AssistController instance = MonoSingleton<AssistController>.Instance;
if ((Object)(object)instance != (Object)null)
{
if (instance.majorEnabled)
{
num = Mathf.RoundToInt((float)damage * instance.damageTaken);
Debug.LogError((object)("[BetterHud][GetHurt] Major Assist changed damage: " + $"{damage} -> {num}"));
}
}
else
{
Debug.LogError((object)"[BetterHud][GetHurt] AssistController.Instance is null! Using original damage.");
}
if (Invincibility.Enabled)
{
Debug.LogError((object)"[BetterHud][GetHurt] Invincibility.Enabled = true, finalDamage forced to 0.");
num = 0;
}
if (__instance.hp - num > 0 && num >= 50)
{
Debug.LogError((object)$"[BetterHud][GetHurt] >>> HEAVY DAMAGE DETECTED: {num} <<<");
PlayerDamageEvents.TriggerHeavyDamage(num);
}
}
}
public class HeavyDamageVisualEffect : MonoBehaviour
{
private Coroutine _effectCoroutine;
private const float Duration = 1f;
private void OnEnable()
{
PlayerDamageEvents.OnHeavyDamageTaken += HandleHeavyDamage;
Debug.LogError((object)"[BetterHud][HeavyEffect] COMPONENT ENABLED - event subscribed.");
}
private void OnDisable()
{
PlayerDamageEvents.OnHeavyDamageTaken -= HandleHeavyDamage;
Debug.LogError((object)"[BetterHud][HeavyEffect] COMPONENT DISABLED - event unsubscribed.");
if (_effectCoroutine != null)
{
((MonoBehaviour)this).StopCoroutine(_effectCoroutine);
_effectCoroutine = null;
}
ResetShaderValues();
NewMovement instance = MonoSingleton<NewMovement>.Instance;
if ((Object)(object)instance == (Object)null || !instance.dead)
{
SetDeathEffect(enabled: false);
}
else
{
Debug.LogError((object)"[BetterHud][HeavyEffect] Player is dead, leaving DeathEffect control to original DeathSequence.");
}
}
private void HandleHeavyDamage(int damage)
{
Debug.LogError((object)$"[BetterHud][HeavyEffect] HANDLE HEAVY DAMAGE: {damage}");
if (_effectCoroutine != null)
{
Debug.LogError((object)"[BetterHud][HeavyEffect] Previous effect coroutine found. Restarting.");
((MonoBehaviour)this).StopCoroutine(_effectCoroutine);
_effectCoroutine = null;
}
_effectCoroutine = ((MonoBehaviour)this).StartCoroutine(DamageEffectRoutine(damage));
}
private IEnumerator DamageEffectRoutine(int damage)
{
Debug.LogError((object)$"[BetterHud][HeavyEffect] EFFECT START | damage={damage}");
float elapsed = 0f;
SetDeathEffect(enabled: true);
Shader.SetGlobalFloat("_Sharpness", 1f);
Shader.SetGlobalFloat("_Deathness", 1f);
Debug.LogError((object)"[BetterHud][HeavyEffect] Shader values initialized: _Sharpness=1, _Deathness=1");
float nextLogTime = 0.5f;
while (elapsed < 1f)
{
NewMovement player = MonoSingleton<NewMovement>.Instance;
if ((Object)(object)player != (Object)null && player.dead)
{
Debug.LogError((object)"[BetterHud][HeavyEffect] PLAYER DIED DURING EFFECT. Stopping custom effect without disabling original DeathEffect.");
ResetShaderValues();
_effectCoroutine = null;
yield break;
}
elapsed += Time.unscaledDeltaTime;
float progress = Mathf.Clamp01(elapsed / 1f);
float intensity = Mathf.Lerp(1f, 0f, progress);
Shader.SetGlobalFloat("_Sharpness", intensity);
Shader.SetGlobalFloat("_Deathness", intensity);
if (elapsed >= nextLogTime)
{
Debug.LogError((object)($"[BetterHud][HeavyEffect] t={elapsed:F2}/{1f:F2}, " + $"progress={progress:F2}, " + $"intensity={intensity:F2}"));
nextLogTime += 0.5f;
}
yield return null;
}
ResetShaderValues();
SetDeathEffect(enabled: false);
_effectCoroutine = null;
Debug.LogError((object)"[BetterHud][HeavyEffect] EFFECT FINISHED.");
}
private void SetDeathEffect(bool enabled)
{
PostProcessV2_Handler instance = MonoSingleton<PostProcessV2_Handler>.Instance;
if ((Object)(object)instance == (Object)null)
{
Debug.LogError((object)($"[BetterHud][HeavyEffect] Cannot set DeathEffect({enabled}): " + "PostProcessV2_Handler.Instance is null!"));
return;
}
instance.DeathEffect(enabled);
Debug.LogError((object)$"[BetterHud][HeavyEffect] DeathEffect({enabled}) called.");
}
private void ResetShaderValues()
{
Shader.SetGlobalFloat("_Sharpness", 0f);
Shader.SetGlobalFloat("_Deathness", 0f);
Debug.LogError((object)"[BetterHud][HeavyEffect] Shader values reset to 0.");
}
}
public class Trackpanel : MonoBehaviour
{
private const string BUNDLE_NAME = "trackertabel";
private readonly HashSet<int> debuggedEnemies = new HashSet<int>();
private const string PREFAB_NAME = "MainTrackerPanel";
private const string TARGET_CANVAS_NAME = "Canvas";
private static AssetBundle loadedBundle;
private static GameObject trackerPrefab;
private readonly Dictionary<EnemyIdentifier, GameObject> activeTrackers = new Dictionary<EnemyIdentifier, GameObject>();
private readonly List<EnemyIdentifier> cleanupBuffer = new List<EnemyIdentifier>();
private Canvas targetCanvas;
private readonly HashSet<string> lastEnemyNames = new HashSet<string>();
private string GetHierarchyPath(Transform target)
{
if ((Object)(object)target == (Object)null)
{
return "<null>";
}
string text = ((Object)target).name;
while ((Object)(object)target.parent != (Object)null)
{
target = target.parent;
text = ((Object)target).name + "/" + text;
}
return text;
}
private void DebugEnemy(EnemyIdentifier enemy)
{
if ((Object)(object)enemy == (Object)null)
{
return;
}
int instanceID = ((Object)((Component)enemy).gameObject).GetInstanceID();
if (debuggedEnemies.Contains(instanceID))
{
return;
}
debuggedEnemies.Add(instanceID);
Debug.Log((object)"[TrackerPanel] ===============================");
Debug.Log((object)("[TrackerPanel] EnemyIdentifier: " + ((Object)enemy).name));
Debug.Log((object)("[TrackerPanel] GameObject: " + ((Object)((Component)enemy).gameObject).name));
Debug.Log((object)$"[TrackerPanel] InstanceID: {instanceID}");
Debug.Log((object)$"[TrackerPanel] Health: {enemy.health}");
Debug.Log((object)$"[TrackerPanel] Dead: {enemy.dead}");
Debug.Log((object)$"[TrackerPanel] Active: {((Component)enemy).gameObject.activeInHierarchy}");
Debug.Log((object)("[TrackerPanel] Hierarchy: " + GetHierarchyPath(((Component)enemy).transform)));
Component[] components = ((Component)enemy).gameObject.GetComponents<Component>();
foreach (Component val in components)
{
if ((Object)(object)val != (Object)null)
{
Debug.Log((object)("[TrackerPanel] Component: " + ((object)val).GetType().Name));
}
}
Component[] componentsInChildren = ((Component)enemy).GetComponentsInChildren<Component>(true);
foreach (Component val2 in componentsInChildren)
{
if ((Object)(object)val2 != (Object)null && (Object)(object)val2.gameObject != (Object)(object)((Component)enemy).gameObject)
{
Debug.Log((object)("[TrackerPanel] CHILD: " + GetHierarchyPath(val2.transform) + " -> " + ((object)val2).GetType().Name));
}
}
Debug.Log((object)"[TrackerPanel] ===============================");
}
private void Awake()
{
Debug.Log((object)"[TrackerPanel] Awake");
LoadAssetBundle();
SceneManager.sceneLoaded += OnSceneLoaded;
FindAndSetupCanvas();
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
ClearAllTrackers();
}
private void Update()
{
if ((Object)(object)targetCanvas == (Object)null)
{
FindAndSetupCanvas();
if ((Object)(object)targetCanvas == (Object)null)
{
return;
}
}
EnemyTracker instance = MonoSingleton<EnemyTracker>.Instance;
if ((Object)(object)instance == (Object)null)
{
return;
}
List<EnemyIdentifier> currentEnemies = instance.GetCurrentEnemies();
if (currentEnemies != null)
{
int count = currentEnemies.Count;
for (int i = 0; i < count; i++)
{
EnemyIdentifier val = currentEnemies[i];
DebugEnemy(val);
if (IsValidEnemy(val) && !activeTrackers.ContainsKey(val))
{
CreateTracker(val);
}
}
}
cleanupBuffer.Clear();
foreach (KeyValuePair<EnemyIdentifier, GameObject> activeTracker in activeTrackers)
{
EnemyIdentifier key = activeTracker.Key;
GameObject value = activeTracker.Value;
if (!IsValidEnemy(key) || (Object)(object)value == (Object)null)
{
cleanupBuffer.Add(key);
}
}
int count2 = cleanupBuffer.Count;
for (int j = 0; j < count2; j++)
{
EnemyIdentifier key2 = cleanupBuffer[j];
if (activeTrackers.TryGetValue(key2, out var value2))
{
if ((Object)(object)value2 != (Object)null)
{
Object.Destroy((Object)(object)value2);
}
activeTrackers.Remove(key2);
}
}
}
private void LoadAssetBundle()
{
if ((Object)(object)trackerPrefab != (Object)null)
{
return;
}
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string directoryName = Path.GetDirectoryName(executingAssembly.Location);
string text = Path.Combine(directoryName, "trackertabel");
if (File.Exists(text))
{
loadedBundle = AssetBundle.LoadFromFile(text);
if ((Object)(object)loadedBundle != (Object)null)
{
Debug.Log((object)"[TrackerPanel] Bundle loaded: trackertabel");
}
}
if ((Object)(object)loadedBundle == (Object)null)
{
Debug.LogError((object)"[TrackerPanel] Failed to load AssetBundle: trackertabel");
return;
}
trackerPrefab = loadedBundle.LoadAsset<GameObject>("MainTrackerPanel");
if ((Object)(object)trackerPrefab == (Object)null)
{
Debug.LogError((object)"[TrackerPanel] Prefab not found: MainTrackerPanel");
}
else
{
Debug.Log((object)("[TrackerPanel] Prefab loaded: " + ((Object)trackerPrefab).name));
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
ClearAllTrackers();
FindAndSetupCanvas();
}
private void FindAndSetupCanvas()
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
string currentScene = SceneHelper.CurrentScene;
if (currentScene == "Main Menu" || currentScene == "Bootstrap")
{
targetCanvas = null;
return;
}
Scene activeScene = SceneManager.GetActiveScene();
GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
foreach (GameObject val in rootGameObjects)
{
if (!(((Object)val).name != "Canvas"))
{
Canvas component = val.GetComponent<Canvas>();
if (!((Object)(object)component == (Object)null))
{
targetCanvas = component;
Debug.Log((object)("[TrackerPanel] Target Canvas found in active scene: " + ((Scene)(ref activeScene)).name));
break;
}
}
}
}
private void CreateTracker(EnemyIdentifier enemy)
{
if ((Object)(object)enemy == (Object)null)
{
return;
}
if ((Object)(object)trackerPrefab == (Object)null)
{
Debug.LogError((object)"[TrackerPanel] trackerPrefab is null");
}
else
{
if ((Object)(object)targetCanvas == (Object)null)
{
return;
}
Enemy component = ((Component)enemy).GetComponent<Enemy>();
if ((Object)(object)component == (Object)null)
{
Debug.LogWarning((object)("[TrackerPanel] SKIPPING '" + ((Object)enemy).name + "' - Enemy component not found. Hierarchy: " + GetHierarchyPath(((Component)enemy).transform)));
return;
}
GameObject val = Object.Instantiate<GameObject>(trackerPrefab, ((Component)targetCanvas).transform);
val.transform.SetAsFirstSibling();
EnemyTrackerUI enemyTrackerUI = val.GetComponent<EnemyTrackerUI>();
if ((Object)(object)enemyTrackerUI == (Object)null)
{
enemyTrackerUI = val.AddComponent<EnemyTrackerUI>();
}
enemyTrackerUI.Initialize(enemy);
activeTrackers.Add(enemy, val);
}
}
private bool IsValidEnemy(EnemyIdentifier enemy)
{
return (Object)(object)enemy != (Object)null && !enemy.dead && enemy.health > 0f && ((Component)enemy).gameObject.activeInHierarchy;
}
private void ClearAllTrackers()
{
foreach (KeyValuePair<EnemyIdentifier, GameObject> activeTracker in activeTrackers)
{
if ((Object)(object)activeTracker.Value != (Object)null)
{
Object.Destroy((Object)(object)activeTracker.Value);
}
}
activeTrackers.Clear();
}
}
public class EnemyTrackerUI : MonoBehaviour
{
private const float MIN_ASPECT_RATIO = 0.05f;
private const float MAX_ASPECT_RATIO = 20f;
private const float MIN_SCREEN_SIZE = 0.01f;
private EnemyIdentifier enemy;
private Enemy enemyComponent;
private Collider enemyCollider;
private RectTransform rectTransform;
private Camera mainCamera;
private RectTransform leftFiller;
private RectTransform rightFiller;
private Image leftFillerImage;
private Image rightFillerImage;
private float enemyHeightOffset;
private float enemyAspectRatio = 1f;
private bool aspectRatioInitialized = false;
private static readonly Color NORMAL_FILLER_COLOR = new Color(0f, 1f, 0f, 1f);
private static readonly Color INVINCIBLE_FILLER_COLOR = new Color(0f, 1f, 1f, 1f);
private void UpdateInvincibilityColor()
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: 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_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)enemyComponent == (Object)null)
{
return;
}
Color color = (enemy.blessed ? INVINCIBLE_FILLER_COLOR : NORMAL_FILLER_COLOR);
if ((Object)(object)leftFiller != (Object)null)
{
Image component = ((Component)leftFiller).GetComponent<Image>();
if ((Object)(object)component != (Object)null)
{
((Graphic)component).color = color;
}
}
if ((Object)(object)rightFiller != (Object)null)
{
Image component2 = ((Component)rightFiller).GetComponent<Image>();
if ((Object)(object)component2 != (Object)null)
{
((Graphic)component2).color = color;
}
}
}
public void Initialize(EnemyIdentifier targetEnemy)
{
//IL_0218: Unknown result type (might be due to invalid IL or missing references)
//IL_021d: Unknown result type (might be due to invalid IL or missing references)
//IL_0221: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_0255: 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_025f: 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_0274: Unknown result type (might be due to invalid IL or missing references)
//IL_0280: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
enemy = targetEnemy;
rectTransform = ((Component)this).GetComponent<RectTransform>();
if ((Object)(object)enemy == (Object)null)
{
Debug.LogError((object)"[TrackerPanel] Initialize received null enemy");
return;
}
enemyComponent = ((Component)targetEnemy).GetComponent<Enemy>();
if ((Object)(object)enemyComponent == (Object)null)
{
Debug.LogError((object)("[TrackerPanel] Enemy component NOT FOUND on " + ((Object)((Component)targetEnemy).gameObject).name));
}
if (((Object)targetEnemy).name.IndexOf("Mass", StringComparison.OrdinalIgnoreCase) >= 0)
{
Transform val = ((Component)targetEnemy).transform.Find("scorpionboss3 (1)/Armature/spine2");
if ((Object)(object)val != (Object)null)
{
enemyCollider = (Collider)(object)((Component)val).GetComponent<SphereCollider>();
}
if ((Object)(object)enemyCollider == (Object)null)
{
enemyCollider = (Collider)(object)((Component)targetEnemy).GetComponentInChildren<SphereCollider>();
}
}
Bounds bounds;
if ((Object)(object)enemyCollider == (Object)null)
{
enemyCollider = ((Component)enemy).GetComponent<Collider>();
if ((Object)(object)enemyCollider != (Object)null)
{
bounds = enemyCollider.bounds;
if (((Bounds)(ref bounds)).size == Vector3.zero)
{
Collider[] componentsInChildren = ((Component)enemy).GetComponentsInChildren<Collider>();
for (int i = 0; i < componentsInChildren.Length; i++)
{
bounds = componentsInChildren[i].bounds;
if (((Bounds)(ref bounds)).size != Vector3.zero)
{
enemyCollider = componentsInChildren[i];
break;
}
}
}
}
}
if ((Object)(object)enemyCollider == (Object)null)
{
Debug.LogWarning((object)("[TrackerPanel] No collider found for " + ((Object)enemy).name + ". Skipping tracker initialization."));
return;
}
string[] obj = new string[6]
{
"[TrackerPanel] ",
((Object)enemy).name,
" Collider = ",
((object)enemyCollider).GetType().Name,
", ",
null
};
bounds = enemyCollider.bounds;
obj[5] = $"Bounds = {((Bounds)(ref bounds)).size}";
Debug.Log((object)string.Concat(obj));
if ((Object)(object)enemyCollider != (Object)null)
{
Bounds bounds2 = enemyCollider.bounds;
enemyHeightOffset = (((Bounds)(ref bounds2)).center - ((Component)enemy).transform.position).y + ((Bounds)(ref bounds2)).extents.y;
}
Transform val2 = ((Component)this).transform.Find("LeftBorder");
Transform val3 = ((Component)this).transform.Find("RightBorder");
if ((Object)(object)val2 != (Object)null)
{
ref RectTransform reference = ref leftFiller;
Transform obj2 = val2.Find("LeftFiller");
reference = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null);
}
else
{
Debug.LogError((object)("[TrackerPanel] LeftBorder NOT FOUND on tracker prefab. Tracker: " + ((Object)((Component)this).gameObject).name));
}
if ((Object)(object)val3 != (Object)null)
{
ref RectTransform reference2 = ref rightFiller;
Transform obj3 = val3.Find("RightFiller");
reference2 = (RectTransform)(object)((obj3 is RectTransform) ? obj3 : null);
}
else
{
Debug.LogError((object)("[TrackerPanel] RightBorder NOT FOUND on tracker prefab. Tracker: " + ((Object)((Component)this).gameObject).name));
}
}
private void UpdateHealthFillers()
{
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)enemyComponent == (Object)null)
{
return;
}
if (enemyComponent.originalHealth <= 0f)
{
Debug.LogError((object)$"[TrackerPanel] Invalid originalHealth for {((Object)enemy).name}: {enemyComponent.originalHealth}");
return;
}
float y = Mathf.Clamp01(enemyComponent.health / enemyComponent.originalHealth);
if ((Object)(object)leftFiller != (Object)null)
{
Vector2 anchorMax = leftFiller.anchorMax;
anchorMax.y = y;
leftFiller.anchorMax = anchorMax;
}
if ((Object)(object)rightFiller != (Object)null)
{
Vector2 anchorMax2 = rightFiller.anchorMax;
anchorMax2.y = y;
rightFiller.anchorMax = anchorMax2;
}
}
private void LateUpdate()
{
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: 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_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: 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_0156: 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)
if ((Object)(object)enemy == (Object)null || enemy.dead || enemy.health <= 0f || (Object)(object)((Component)enemy).transform == (Object)null)
{
Object.Destroy((Object)(object)((Component)this).gameObject);
return;
}
UpdateInvincibilityColor();
UpdateHealthFillers();
if ((Object)(object)rectTransform == (Object)null)
{
return;
}
if ((Object)(object)mainCamera == (Object)null)
{
if ((Object)(object)MonoSingleton<CameraController>.Instance != (Object)null)
{
mainCamera = MonoSingleton<CameraController>.Instance.cam;
}
else
{
mainCamera = Camera.main;
}
if ((Object)(object)mainCamera == (Object)null)
{
return;
}
}
Vector3 val = ((Component)enemy).transform.position + Vector3.up * (enemyHeightOffset * 0.5f);
Vector3 screenPoint = mainCamera.WorldToScreenPoint(val);
ApplyPostProcessCorrection(ref screenPoint);
if (screenPoint.z < 0f)
{
((Transform)rectTransform).position = new Vector3(-9999f, -9999f, 0f);
return;
}
((Transform)rectTransform).position = screenPoint;
UpdateTrackerSize();
}
private void UpdateTrackerSize()
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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_0043: 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_004f: 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_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: 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_0079: 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_0085: 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_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: 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)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: 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_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
//IL_011b: 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_0126: 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_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01d5: 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_01e6: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)enemyCollider == (Object)null)
{
return;
}
Bounds bounds = enemyCollider.bounds;
Vector3[] array = (Vector3[])(object)new Vector3[8];
Vector3 min = ((Bounds)(ref bounds)).min;
Vector3 max = ((Bounds)(ref bounds)).max;
array[0] = new Vector3(min.x, min.y, min.z);
array[1] = new Vector3(min.x, min.y, max.z);
array[2] = new Vector3(min.x, max.y, min.z);
array[3] = new Vector3(min.x, max.y, max.z);
array[4] = new Vector3(max.x, min.y, min.z);
array[5] = new Vector3(max.x, min.y, max.z);
array[6] = new Vector3(max.x, max.y, min.z);
array[7] = new Vector3(max.x, max.y, max.z);
float num = float.MaxValue;
float num2 = float.MinValue;
float num3 = float.MaxValue;
float num4 = float.MinValue;
bool flag = false;
for (int i = 0; i < array.Length; i++)
{
Vector3 screenPoint = mainCamera.WorldToScreenPoint(array[i]);
if (!(screenPoint.z < 0f))
{
ApplyPostProcessCorrection(ref screenPoint);
if (screenPoint.x < num)
{
num = screenPoint.x;
}
if (screenPoint.x > num2)
{
num2 = screenPoint.x;
}
if (screenPoint.y < num3)
{
num3 = screenPoint.y;
}
if (screenPoint.y > num4)
{
num4 = screenPoint.y;
}
flag = true;
}
}
if (!flag)
{
return;
}
float num5 = num2 - num;
float num6 = num4 - num3;
if (num5 <= 0.01f || num6 <= 0.01f)
{
return;
}
if (!aspectRatioInitialized)
{
float num7 = num5 / num6;
if (num7 >= 0.05f && num7 <= 20f)
{
enemyAspectRatio = num7;
aspectRatioInitialized = true;
Debug.Log((object)$"[TrackerPanel] Aspect ratio initialized for {((Object)enemy).name}: {enemyAspectRatio:F3}");
}
else
{
enemyAspectRatio = 1f;
aspectRatioInitialized = true;
Debug.LogWarning((object)$"[TrackerPanel] Invalid aspect ratio for {((Object)enemy).name}: {num7:F3}. Using 1:1.");
}
}
float num8 = Mathf.Min(num6, 700f);
float num9 = Mathf.Min(num5, 700f * enemyAspectRatio);
if (!(num9 <= 0f) && !(num8 <= 0f))
{
rectTransform.SetSizeWithCurrentAnchors((Axis)0, num9);
rectTransform.SetSizeWithCurrentAnchors((Axis)1, num8);
}
}
private void ApplyPostProcessCorrection(ref Vector3 screenPoint)
{
if ((Object)(object)MonoSingleton<PostProcessV2_Handler>.Instance != (Object)null)
{
int privateField = GetPrivateField<int>(MonoSingleton<PostProcessV2_Handler>.Instance, "width");
int privateField2 = GetPrivateField<int>(MonoSingleton<PostProcessV2_Handler>.Instance, "height");
if (privateField > 0 && privateField2 > 0)
{
screenPoint.x *= (float)Screen.width / (float)privateField;
screenPoint.y *= (float)Screen.height / (float)privateField2;
}
}
}
private T GetPrivateField<T>(object instance, string fieldName)
{
if (instance == null)
{
return default(T);
}
FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field == null)
{
return default(T);
}
return (T)field.GetValue(instance);
}
}
[BepInPlugin("betterhud", "BetterHud", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
[Serializable]
private class StarterPanelConfig
{
public string[] texts;
}
private const string BundleName = "myui2";
private const string PrefabName = "MyHUD";
private const string UIDllName = "UltrakillUnityPrefab.dll";
private Harmony _harmony;
private const bool StarterPanelRandom = true;
private const int StarterPanelTextIndex = 0;
private AssetBundle _bundle;
private GameObject _hudInstance;
private Image _fillerImage;
private TMP_Text _starterPanelText;
private static string ModFolder => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
private void Awake()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Expected O, but got Unknown
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] StartePanel is awake!");
try
{
_harmony = new Harmony("betterhudmod");
_harmony.PatchAll(Assembly.GetExecutingAssembly());
((BaseUnityPlugin)this).Logger.LogInfo((object)"[BetterHud][Harmony] PatchAll SUCCESS!");
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"[BetterHud][Harmony] PatchAll FAILED:\n{arg}");
}
LoadUIDll();
PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Combine(PrefsManager.onPrefChanged, new Action<string, object>(OnPreferenceChanged));
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] Subscribed to PrefsManager.onPrefChanged");
((Component)this).gameObject.AddComponent<HeavyDamageVisualEffect>();
((BaseUnityPlugin)this).Logger.LogInfo((object)"[BetterHud][HeavyEffect] HeavyDamageVisualEffect component added!");
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Remove(PrefsManager.onPrefChanged, new Action<string, object>(OnPreferenceChanged));
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] Unsubscribed from PrefsManager.onPrefChanged");
try
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
((BaseUnityPlugin)this).Logger.LogInfo((object)"[BetterHud][Harmony] Harmony patches removed.");
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"[BetterHud][Harmony] Failed to unpatch:\n{arg}");
}
CleanupHUDReferences();
UnloadAssetBundle();
}
private void LoadUIDll()
{
string text = Path.Combine(ModFolder, "UltrakillUnityPrefab.dll");
((BaseUnityPlugin)this).Logger.LogInfo((object)("[StartPanel] Looking for UI DLL: " + text));
if (!File.Exists(text))
{
((BaseUnityPlugin)this).Logger.LogError((object)("[StartPanel] UI DLL not found: " + text));
return;
}
try
{
Assembly.LoadFrom(text);
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] UltrakillUnityPrefab.dll successfully loaded!");
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"[StartPanel] Failed to load UI DLL: {arg}");
}
}
private void CleanupHUDReferences()
{
if ((Object)(object)_hudInstance != (Object)null)
{
Object.Destroy((Object)(object)_hudInstance);
_hudInstance = null;
}
_fillerImage = null;
_starterPanelText = null;
}
private void UnloadAssetBundle()
{
if ((Object)(object)_bundle != (Object)null)
{
_bundle.Unload(false);
_bundle = null;
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
string currentScene = SceneHelper.CurrentScene;
((BaseUnityPlugin)this).Logger.LogInfo((object)currentScene);
if (!IsIgnoredScene(currentScene))
{
SpawnTrackerPanel();
if (!((Object)(object)_hudInstance != (Object)null) && TryFindGunCanvas(out var gunCanvas))
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] GunCanvas found!");
((MonoBehaviour)this).StartCoroutine(LoadHUDCoroutine(gunCanvas));
}
}
}
private bool IsIgnoredScene(string sceneName)
{
return sceneName == "Main Menu" || sceneName == "Intro" || sceneName == "Bootstrap";
}
private void SpawnTrackerPanel()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
GameObject val = new GameObject("TrackerPanelScript");
val.AddComponent<Trackpanel>();
((BaseUnityPlugin)this).Logger.LogInfo((object)"[TrackerPanel] Tracker Panel script loaded!");
}
private bool TryFindGunCanvas(out GameObject gunCanvas)
{
gunCanvas = null;
GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
GameObject[] array2 = array;
foreach (GameObject val in array2)
{
if ((Object)(object)val != (Object)null && ((Object)val).name == "GunCanvas")
{
gunCanvas = val;
return true;
}
}
return false;
}
private void OnPreferenceChanged(string key, object value)
{
if (!(key != "hudBackgroundOpacity"))
{
((BaseUnityPlugin)this).Logger.LogInfo((object)$"[StartPanel] hudBackgroundOpacity changed: {value}");
if (value is float opacity)
{
UpdateFillerOpacity(opacity);
}
else
{
((BaseUnityPlugin)this).Logger.LogWarning((object)$"[StartPanel] hudBackgroundOpacity has unexpected type: {value?.GetType()}");
}
}
}
private IEnumerator LoadHUDCoroutine(GameObject gunCanvas)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] Waiting 1 second before loading MyHUD...");
yield return (object)new WaitForSeconds(1f);
if ((Object)(object)gunCanvas == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] GunCanvas became null during the delay!");
}
else
{
if (!TryEnsureBundleLoaded())
{
yield break;
}
GameObject prefab = _bundle.LoadAsset<GameObject>("MyHUD");
if ((Object)(object)prefab == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] Prefab 'MyHUD' not found in AssetBundle!");
yield break;
}
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] MyHUD prefab found!");
if (TryInstantiateHUD(prefab, gunCanvas))
{
BindUIComponents();
_hudInstance.SetActive(true);
UpdateFillerOpacityFromPrefs();
LoadStarterPanelText();
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] MyHUD successfully added to GunCanvas!");
}
}
}
private bool TryEnsureBundleLoaded()
{
if ((Object)(object)_bundle != (Object)null)
{
return true;
}
string text = Path.Combine(ModFolder, "myui2");
((BaseUnityPlugin)this).Logger.LogInfo((object)("[StartPanel] Looking for AssetBundle: " + text));
if (!File.Exists(text))
{
((BaseUnityPlugin)this).Logger.LogError((object)("[StartPanel] AssetBundle not found: " + text));
return false;
}
_bundle = AssetBundle.LoadFromFile(text);
if ((Object)(object)_bundle == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] Failed to load AssetBundle!");
return false;
}
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] AssetBundle successfully loaded!");
return true;
}
private bool TryInstantiateHUD(GameObject prefab, GameObject parentCanvas)
{
try
{
_hudInstance = Object.Instantiate<GameObject>(prefab);
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"[StartPanel] Failed to instantiate MyHUD: {arg}");
return false;
}
if ((Object)(object)_hudInstance == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] MyHUD instance is null!");
return false;
}
RectTransform component = _hudInstance.GetComponent<RectTransform>();
if ((Object)(object)component == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] MyHUD does not have a RectTransform!");
Object.Destroy((Object)(object)_hudInstance);
_hudInstance = null;
return false;
}
((Transform)component).SetParent(parentCanvas.transform, false);
return true;
}
private void BindUIComponents()
{
Transform val = _hudInstance.transform.Find("Filler");
if ((Object)(object)val == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] Filler not found inside MyHUD!");
return;
}
_fillerImage = ((Component)val).GetComponent<Image>();
if ((Object)(object)_fillerImage == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] Filler does not have an Image component!");
}
else
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] Filler Image found!");
}
Transform val2 = val.Find("Viewport/Content/Text");
if ((Object)(object)val2 == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] Text not found at Filler/Viewport/Content/Text!");
return;
}
_starterPanelText = ((Component)val2).GetComponent<TMP_Text>();
if ((Object)(object)_starterPanelText == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] Text does not have a TMP_Text component!");
}
else
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"[StartPanel] TextMeshPro component found!");
}
}
private void UpdateFillerOpacity(float opacity)
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: 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)
if ((Object)(object)_fillerImage == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"[StartPanel] FillerImage is null, cannot update opacity!");
return;
}
if (opacity > 10f)
{
opacity -= 10f;
}
float num = opacity / 100f;
Color color = ((Graphic)_fillerImage).color;
color.a = num;
((Graphic)_fillerImage).color = color;
((BaseUnityPlugin)this).Logger.LogInfo((object)$"[StartPanel] FillerImage alpha updated: {num}");
}
private void UpdateFillerOpacityFromPrefs()
{
if (!((Object)(object)_fillerImage == (Object)null))
{
float opacity = MonoSingleton<PrefsManager>.Instance.GetFloat("hudBackgroundOpacity", 50f);
UpdateFillerOpacity(opacity);
}
}
private void LoadStarterPanelText()
{
StarterPanelConfig config;
string text;
if ((Object)(object)_starterPanelText == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] StarterPanel TMP_Text is null!");
}
else if (TryLoadStarterConfig(out config) && TrySelectText(config, out text))
{
_starterPanelText.text = text;
((BaseUnityPlugin)this).Logger.LogInfo((object)("[StartPanel] StarterPanel text set: \"" + text + "\""));
}
}
private bool TryLoadStarterConfig(out StarterPanelConfig config)
{
config = null;
string text = Path.Combine(ModFolder, "Config", "StarterPanel.json");
((BaseUnityPlugin)this).Logger.LogInfo((object)("[StartPanel] Looking for StarterPanel.json: " + text));
if (!File.Exists(text))
{
((BaseUnityPlugin)this).Logger.LogError((object)("[StartPanel] StarterPanel.json not found: " + text));
return false;
}
try
{
string text2 = File.ReadAllText(text);
config = JsonUtility.FromJson<StarterPanelConfig>(text2);
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"[StartPanel] Failed to read/parse StarterPanel.json: {arg}");
return false;
}
if (config == null || config.texts == null || config.texts.Length == 0)
{
((BaseUnityPlugin)this).Logger.LogError((object)"[StartPanel] StarterPanel.json is invalid or contains no texts!");
return false;
}
return true;
}
private bool TrySelectText(StarterPanelConfig config, out string text)
{
text = null;
bool flag = true;
int num = Random.Range(0, config.texts.Length);
((BaseUnityPlugin)this).Logger.LogInfo((object)$"[StartPanel] StarterPanelRandom = true, selected index: {num}");
text = config.texts[num];
return true;
}
}