Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Enemy Editor v1.0.0
EnemyHealthEditor.dll
Decompiled 9 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("Omniscye")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EnemyHealthEditor")] [assembly: AssemblyTitle("EnemyHealthEditor")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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; } } } namespace RepoMods.EnemyHealthEditor { [BepInPlugin("com.repo.mods.enemy-health-editor", "Enemy Health + Respawn Editor", "1.4.0")] public class EnemyHealthEditorPlugin : BaseUnityPlugin { public const string PluginGuid = "com.repo.mods.enemy-health-editor"; public const string PluginName = "Enemy Health + Respawn Editor"; public const string PluginVersion = "1.4.0"; internal static Harmony Harmony; internal static EnemyHealthEditorPlugin Instance; internal static ConfigEntry<int> DefaultEnemyHealth; internal static ConfigEntry<bool> ClampExistingHealthOnChange; internal static ConfigEntry<float> DefaultRespawnMin; internal static ConfigEntry<float> DefaultRespawnMax; internal static ConfigEntry<bool> ApplyRespawnToExistingWhenChanged; internal static readonly Dictionary<string, ConfigEntry<int>> PerEnemyHP = new Dictionary<string, ConfigEntry<int>>(); internal static readonly Dictionary<string, ConfigEntry<float>> PerEnemyRespawnMin = new Dictionary<string, ConfigEntry<float>>(); internal static readonly Dictionary<string, ConfigEntry<float>> PerEnemyRespawnMax = new Dictionary<string, ConfigEntry<float>>(); private Rect _windowRect = new Rect(60f, 60f, 760f, 680f); private bool _showUI; private string _pendingHP = ""; private string _pendingRMin = ""; private string _pendingRMax = ""; private Vector2 _scroll; private string _search = string.Empty; private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown Instance = this; DefaultEnemyHealth = ((BaseUnityPlugin)this).Config.Bind<int>("General", "DefaultEnemyHealth", 100, new ConfigDescription("The base health value applied to enemies on Awake/Spawn.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100000), Array.Empty<object>())); ClampExistingHealthOnChange = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ApplyToExistingEnemiesWhenChanged", true, "When the HP value changes, immediately set all existing enemies to the new default."); DefaultRespawnMin = ((BaseUnityPlugin)this).Config.Bind<float>("Respawn", "DefaultRespawnMinSeconds", 5f, new ConfigDescription("Default minimum seconds between despawn and respawn (EnemyParent.DespawnedTimeMin).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 86400f), Array.Empty<object>())); DefaultRespawnMax = ((BaseUnityPlugin)this).Config.Bind<float>("Respawn", "DefaultRespawnMaxSeconds", 12f, new ConfigDescription("Default maximum seconds between despawn and respawn (EnemyParent.DespawnedTimeMax).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 86400f), Array.Empty<object>())); ApplyRespawnToExistingWhenChanged = ((BaseUnityPlugin)this).Config.Bind<bool>("Respawn", "ApplyRespawnToExistingWhenChanged", true, "When the respawn window changes, push to all existing EnemyParent instances."); _pendingHP = DefaultEnemyHealth.Value.ToString(); _pendingRMin = DefaultRespawnMin.Value.ToString("0.##"); _pendingRMax = DefaultRespawnMax.Value.ToString("0.##"); Harmony = new Harmony("com.repo.mods.enemy-health-editor"); Harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. Default HP={2}, Respawn={3}-{4}s", "Enemy Health + Respawn Editor", "1.4.0", DefaultEnemyHealth.Value, DefaultRespawnMin.Value, DefaultRespawnMax.Value)); } private void OnDestroy() { try { Harmony harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } private void Update() { if (Input.GetKeyDown((KeyCode)277)) { _showUI = !_showUI; } } private void OnGUI() { //IL_0017: 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_0037: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (_showUI) { _windowRect = GUILayout.Window(14753536, _windowRect, new WindowFunction(DrawWindow), "Enemy Health + Respawn Editor", Array.Empty<GUILayoutOption>()); } } private void DrawWindow(int id) { //IL_056d: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Unknown result type (might be due to invalid IL or missing references) //IL_058a: Unknown result type (might be due to invalid IL or missing references) //IL_08af: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.Label("Default Enemy Health", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(20f) }); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); int num = Mathf.Clamp(DefaultEnemyHealth.Value, 1, 100000); int num2 = (int)GUILayout.HorizontalSlider((float)num, 1f, 100000f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(320f) }); if (num2 != DefaultEnemyHealth.Value) { SetDefaultHPFromUI(num2); } GUILayout.Space(12f); _pendingHP = GUILayout.TextField(_pendingHP, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }); if (GUILayout.Button("Set HP", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) })) { if (int.TryParse(_pendingHP, out var result)) { SetDefaultHPFromUI(Mathf.Clamp(result, 1, 100000)); } else { _pendingHP = DefaultEnemyHealth.Value.ToString(); } } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Apply DEFAULT HP to ALL existing", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(360f) })) { EnemyUtilities.ApplyDefaultHPToAllExisting(DefaultEnemyHealth.Value); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Applied default {DefaultEnemyHealth.Value} HP to all existing enemies."); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(10f); GUILayout.Label("Respawn Window (DespawnedTimeMin/Max in EnemyParent)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(20f) }); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Min s:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(48f) }); _pendingRMin = GUILayout.TextField(_pendingRMin, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Space(12f); GUILayout.Label("Max s:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(56f) }); _pendingRMax = GUILayout.TextField(_pendingRMax, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Space(12f); if (GUILayout.Button("Set Respawn", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) })) { if (float.TryParse(_pendingRMin, out var result2) && float.TryParse(_pendingRMax, out var result3)) { SetDefaultRespawnFromUI(result2, result3); } else { _pendingRMin = DefaultRespawnMin.Value.ToString("0.##"); _pendingRMax = DefaultRespawnMax.Value.ToString("0.##"); } } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Apply DEFAULT RESPAWN to ALL existing", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(360f) })) { EnemyUtilities.ApplyDefaultRespawnToAllExisting(DefaultRespawnMin.Value, DefaultRespawnMax.Value); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Applied default respawn {DefaultRespawnMin.Value}-{DefaultRespawnMax.Value}s to all existing EnemyParents."); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(12f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Discover enemies in scene", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(220f) })) { EnemyUtilities.DiscoverAndRegisterOverrides(); } GUILayout.Space(10f); if (GUILayout.Button("Discover from EnemyDirector", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(240f) })) { EnemyUtilities.RegisterFromEnemyDirector(); } GUILayout.Space(10f); GUILayout.Label("Search:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }); _search = GUILayout.TextField(_search ?? string.Empty, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(180f) }); GUILayout.FlexibleSpace(); if (GUILayout.Button("Apply ALL overrides to existing", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(280f) })) { EnemyUtilities.ApplyAllOverridesToExisting(); } GUILayout.EndHorizontal(); GUILayout.Space(6f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Enemy (Prefab|Type)", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.MinWidth(320f), GUILayout.Height(18f) }); GUILayout.Label("HP", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUILayout.Label("Min s", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUILayout.Label("Max s", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUILayout.Space(70f); GUILayout.Space(70f); GUILayout.EndHorizontal(); GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); _scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(340f) }); List<string> list = new List<string>(PerEnemyHP.Keys); list.Sort(StringComparer.OrdinalIgnoreCase); foreach (string item in list) { if (string.IsNullOrEmpty(_search) || item.IndexOf(_search, StringComparison.OrdinalIgnoreCase) >= 0) { ConfigEntry<int> val = PerEnemyHP[item]; ConfigEntry<float> orCreateRespawnMinEntry = EnemyUtilities.GetOrCreateRespawnMinEntry(item, DefaultRespawnMin.Value); ConfigEntry<float> orCreateRespawnMaxEntry = EnemyUtilities.GetOrCreateRespawnMaxEntry(item, DefaultRespawnMax.Value); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(item, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(320f) }); string text = val.Value.ToString(); string text2 = GUILayout.TextField(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); if (text2 != text && int.TryParse(text2, out var result4)) { result4 = (val.Value = Mathf.Clamp(result4, 1, 100000)); ((BaseUnityPlugin)this).Config.Save(); } string text3 = orCreateRespawnMinEntry.Value.ToString("0.##"); string text4 = GUILayout.TextField(text3, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); if (text4 != text3 && float.TryParse(text4, out var result5)) { orCreateRespawnMinEntry.Value = Mathf.Clamp(result5, 0f, 86400f); ((BaseUnityPlugin)this).Config.Save(); } string text5 = orCreateRespawnMaxEntry.Value.ToString("0.##"); string text6 = GUILayout.TextField(text5, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); if (text6 != text5 && float.TryParse(text6, out var result6)) { orCreateRespawnMaxEntry.Value = Mathf.Clamp(result6, 0f, 86400f); ((BaseUnityPlugin)this).Config.Save(); } if (GUILayout.Button("Apply", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { EnemyUtilities.ApplyOverrideToExisting(item, val.Value, orCreateRespawnMinEntry.Value, orCreateRespawnMaxEntry.Value); } if (GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { val.Value = DefaultEnemyHealth.Value; orCreateRespawnMinEntry.Value = DefaultRespawnMin.Value; orCreateRespawnMaxEntry.Value = DefaultRespawnMax.Value; ((BaseUnityPlugin)this).Config.Save(); } GUILayout.EndHorizontal(); } } GUILayout.EndScrollView(); GUILayout.Space(6f); GUILayout.Label("Toggle UI with the Insert key.", Array.Empty<GUILayoutOption>()); GUILayout.EndVertical(); GUI.DragWindow(new Rect(0f, 0f, 10000f, 24f)); } private void SetDefaultHPFromUI(int value) { if (DefaultEnemyHealth.Value != value) { DefaultEnemyHealth.Value = value; _pendingHP = value.ToString(); ((BaseUnityPlugin)this).Config.Save(); if (ClampExistingHealthOnChange.Value) { EnemyUtilities.ApplyDefaultHPToAllExisting(value); } } } private void SetDefaultRespawnFromUI(float min, float max) { min = Mathf.Clamp(min, 0f, 86400f); max = Mathf.Clamp(max, 0f, 86400f); if (max < min) { float num = min; min = max; max = num; } if (!(Math.Abs(DefaultRespawnMin.Value - min) < 0.0001f) || !(Math.Abs(DefaultRespawnMax.Value - max) < 0.0001f)) { DefaultRespawnMin.Value = min; DefaultRespawnMax.Value = max; _pendingRMin = min.ToString("0.##"); _pendingRMax = max.ToString("0.##"); ((BaseUnityPlugin)this).Config.Save(); if (ApplyRespawnToExistingWhenChanged.Value) { EnemyUtilities.ApplyDefaultRespawnToAllExisting(min, max); } } } } internal static class EnemyUtilities { private static Type EnemyHealthType => AccessTools.TypeByName("EnemyHealth"); private static Type EnemyParentType => AccessTools.TypeByName("EnemyParent"); public static string BuildKey(object enemyHealthInstance) { if (enemyHealthInstance == null) { return "<null>|<null>"; } Component val = (Component)((enemyHealthInstance is Component) ? enemyHealthInstance : null); string text = (((Object)(object)val != (Object)null) ? ((Object)val.gameObject).name : enemyHealthInstance.GetType().Name); if (!string.IsNullOrEmpty(text)) { text = text.Replace("(Clone)", string.Empty).Trim(); } string name = enemyHealthInstance.GetType().Name; return text + "|" + name; } public static void DiscoverAndRegisterOverrides() { if (EnemyHealthType == null) { Debug.LogWarning((object)"EnemyHealth type not found."); return; } Object[] array = Resources.FindObjectsOfTypeAll(EnemyHealthType); Object[] array2 = array; foreach (Object enemyHealthInstance in array2) { string key = BuildKey(enemyHealthInstance); GetOrCreateHPEntry(key, EnemyHealthEditorPlugin.DefaultEnemyHealth.Value); GetOrCreateRespawnMinEntry(key, EnemyHealthEditorPlugin.DefaultRespawnMin.Value); GetOrCreateRespawnMaxEntry(key, EnemyHealthEditorPlugin.DefaultRespawnMax.Value); } } public static void RegisterFromEnemyDirector() { try { Type type = AccessTools.TypeByName("EnemyDirector"); if (type == null) { Debug.LogWarning((object)"EnemyDirector type not found."); return; } object? obj = AccessTools.Field(type, "instance")?.GetValue(null); Object val = (Object)(((obj is Object) ? obj : null) ?? Object.FindObjectOfType(type)); if (val == (Object)null) { Debug.LogWarning((object)"EnemyDirector instance not found."); return; } string[] array = new string[3] { "enemiesDifficulty1", "enemiesDifficulty2", "enemiesDifficulty3" }; string[] array2 = array; foreach (string text in array2) { if (!(AccessTools.Field(type, text)?.GetValue(val) is IEnumerable enumerable)) { continue; } foreach (object item in enumerable) { if (item == null) { continue; } Type type2 = item.GetType(); if (!(AccessTools.Field(type2, "spawnObjects")?.GetValue(item) is IEnumerable enumerable2)) { continue; } foreach (object item2 in enumerable2) { GameObject val2 = (GameObject)((item2 is GameObject) ? item2 : null); if ((Object)(object)val2 == (Object)null) { continue; } string text2 = ((Object)val2).name?.Replace("(Clone)", string.Empty).Trim(); string text3 = "EnemyHealth"; try { MonoBehaviour[] componentsInChildren = val2.GetComponentsInChildren<MonoBehaviour>(true); MonoBehaviour[] array3 = componentsInChildren; foreach (MonoBehaviour val3 in array3) { if ((Object)(object)val3 != (Object)null && ((object)val3).GetType().Name == "EnemyHealth") { text3 = ((object)val3).GetType().Name; break; } } } catch { } string key = text2 + "|" + text3; GetOrCreateHPEntry(key, EnemyHealthEditorPlugin.DefaultEnemyHealth.Value); GetOrCreateRespawnMinEntry(key, EnemyHealthEditorPlugin.DefaultRespawnMin.Value); GetOrCreateRespawnMaxEntry(key, EnemyHealthEditorPlugin.DefaultRespawnMax.Value); } } } } catch (Exception arg) { Debug.LogError((object)$"EnemyHealthEditor: RegisterFromEnemyDirector failed: {arg}"); } } public static ConfigEntry<int> GetOrCreateHPEntry(string key, int fallback) { if (EnemyHealthEditorPlugin.PerEnemyHP.TryGetValue(key, out ConfigEntry<int> value)) { return value; } value = ((BaseUnityPlugin)EnemyHealthEditorPlugin.Instance).Config.Bind<int>("PerEnemyHealth", key, fallback, "Override health for this enemy (Prefab|Type)"); EnemyHealthEditorPlugin.PerEnemyHP[key] = value; return value; } public static ConfigEntry<float> GetOrCreateRespawnMinEntry(string key, float fallback) { if (EnemyHealthEditorPlugin.PerEnemyRespawnMin.TryGetValue(key, out ConfigEntry<float> value)) { return value; } value = ((BaseUnityPlugin)EnemyHealthEditorPlugin.Instance).Config.Bind<float>("PerEnemyRespawnMin", key, fallback, "Override DESPAWN→RESPAWN minimum seconds (EnemyParent.DespawnedTimeMin)"); EnemyHealthEditorPlugin.PerEnemyRespawnMin[key] = value; return value; } public static ConfigEntry<float> GetOrCreateRespawnMaxEntry(string key, float fallback) { if (EnemyHealthEditorPlugin.PerEnemyRespawnMax.TryGetValue(key, out ConfigEntry<float> value)) { return value; } value = ((BaseUnityPlugin)EnemyHealthEditorPlugin.Instance).Config.Bind<float>("PerEnemyRespawnMax", key, fallback, "Override DESPAWN→RESPAWN maximum seconds (EnemyParent.DespawnedTimeMax)"); EnemyHealthEditorPlugin.PerEnemyRespawnMax[key] = value; return value; } public static int GetHealthFor(object enemyHealthInstance) { int fallback = EnemyHealthEditorPlugin.DefaultEnemyHealth?.Value ?? 100; string key = BuildKey(enemyHealthInstance); if (EnemyHealthEditorPlugin.PerEnemyHP.TryGetValue(key, out ConfigEntry<int> value)) { return value.Value; } return GetOrCreateHPEntry(key, fallback).Value; } public static (float min, float max) GetRespawnFor(object enemyHealthInstance) { float fallback = EnemyHealthEditorPlugin.DefaultRespawnMin?.Value ?? 0f; float fallback2 = EnemyHealthEditorPlugin.DefaultRespawnMax?.Value ?? 0f; string key = BuildKey(enemyHealthInstance); float value = GetOrCreateRespawnMinEntry(key, fallback).Value; float num = GetOrCreateRespawnMaxEntry(key, fallback2).Value; if (num < value) { num = value; } return (value, num); } public static void ApplyDefaultHPToAllExisting(int hp) { if (!(EnemyHealthType == null)) { Object[] array = Resources.FindObjectsOfTypeAll(EnemyHealthType); Object[] array2 = array; foreach (Object enemyHealthInstance in array2) { SetEnemyHealth(enemyHealthInstance, hp); } } } public static void ApplyDefaultRespawnToAllExisting(float min, float max) { if (EnemyParentType == null || EnemyHealthType == null) { return; } Object[] array = Resources.FindObjectsOfTypeAll(EnemyHealthType); Object[] array2 = array; foreach (Object val in array2) { Component enemyParentFromHealth = GetEnemyParentFromHealth((Component)(object)((val is Component) ? val : null)); if ((Object)(object)enemyParentFromHealth != (Object)null) { SetRespawnWindowOnParent(enemyParentFromHealth, min, max, adjustCurrentTimer: true); } } } public static void ApplyAllOverridesToExisting() { if (EnemyHealthType == null) { return; } Object[] array = Resources.FindObjectsOfTypeAll(EnemyHealthType); Object[] array2 = array; foreach (Object val in array2) { int healthFor = GetHealthFor(val); SetEnemyHealth(val, healthFor); (float min, float max) respawnFor = GetRespawnFor(val); float item = respawnFor.min; float item2 = respawnFor.max; Component enemyParentFromHealth = GetEnemyParentFromHealth((Component)(object)((val is Component) ? val : null)); if ((Object)(object)enemyParentFromHealth != (Object)null) { SetRespawnWindowOnParent(enemyParentFromHealth, item, item2, adjustCurrentTimer: true); } } } public static void ApplyOverrideToExisting(string key, int hp, float rmin, float rmax) { if (EnemyHealthType == null) { return; } Object[] array = Resources.FindObjectsOfTypeAll(EnemyHealthType); Object[] array2 = array; foreach (Object val in array2) { if (BuildKey(val) == key) { SetEnemyHealth(val, hp); Component enemyParentFromHealth = GetEnemyParentFromHealth((Component)(object)((val is Component) ? val : null)); if ((Object)(object)enemyParentFromHealth != (Object)null) { SetRespawnWindowOnParent(enemyParentFromHealth, rmin, rmax, adjustCurrentTimer: true); } } } } public static void SetEnemyHealth(object enemyHealthInstance, int hp) { if (enemyHealthInstance != null) { Type type = enemyHealthInstance.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "health"); FieldInfo fieldInfo2 = AccessTools.Field(type, "healthCurrent"); fieldInfo?.SetValue(enemyHealthInstance, hp); fieldInfo2?.SetValue(enemyHealthInstance, hp); } } public static Component GetEnemyParentFromHealth(Component enemyHealthComp) { if ((Object)(object)enemyHealthComp == (Object)null || EnemyParentType == null) { return null; } return enemyHealthComp.GetComponentInParent(EnemyParentType); } public static void SetRespawnWindowOnParent(Component enemyParent, float min, float max, bool adjustCurrentTimer) { if ((Object)(object)enemyParent == (Object)null) { return; } min = Mathf.Clamp(min, 0f, 86400f); max = Mathf.Clamp(max, 0f, 86400f); if (max < min) { float num = min; min = max; max = num; } Type type = ((object)enemyParent).GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "DespawnedTimeMin"); FieldInfo fieldInfo2 = AccessTools.Field(type, "DespawnedTimeMax"); FieldInfo fieldInfo3 = AccessTools.Field(type, "DespawnedTimer"); FieldInfo fieldInfo4 = AccessTools.Field(type, "Spawned"); try { fieldInfo?.SetValue(enemyParent, min); } catch { } try { fieldInfo2?.SetValue(enemyParent, max); } catch { } if (!adjustCurrentTimer || !(fieldInfo3 != null)) { return; } bool flag = true; try { if (fieldInfo4 != null) { flag = (bool)fieldInfo4.GetValue(enemyParent); } } catch { } if (flag) { return; } float num2 = (min + max) * 0.5f; try { fieldInfo3.SetValue(enemyParent, num2); } catch { } } } [HarmonyPatch] internal static class EnemyHealthPatches { [CompilerGenerated] private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; private Type <t>5__1; private string[] <names>5__2; private string[] <>s__3; private int <>s__4; private string <n>5__5; private MethodInfo <m>5__6; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <t>5__1 = null; <names>5__2 = null; <>s__3 = null; <n>5__5 = null; <m>5__6 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_00e0; } <>1__state = -1; <t>5__1 = AccessTools.TypeByName("EnemyHealth"); if (<t>5__1 == null) { return false; } <names>5__2 = new string[4] { "Awake", "OnSpawn", "Start", "OnEnable" }; <>s__3 = <names>5__2; <>s__4 = 0; goto IL_00fd; IL_00e0: <m>5__6 = null; <n>5__5 = null; <>s__4++; goto IL_00fd; IL_00fd: if (<>s__4 < <>s__3.Length) { <n>5__5 = <>s__3[<>s__4]; <m>5__6 = AccessTools.Method(<t>5__1, <n>5__5, (Type[])null, (Type[])null); if (<m>5__6 != null) { <>2__current = <m>5__6; <>1__state = 1; return true; } goto IL_00e0; } <>s__3 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__0(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } [IteratorStateMachine(typeof(<TargetMethods>d__0))] private static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__0(-2); } private static void Postfix(object __instance) { try { int healthFor = EnemyUtilities.GetHealthFor(__instance); EnemyUtilities.SetEnemyHealth(__instance, healthFor); (float min, float max) respawnFor = EnemyUtilities.GetRespawnFor(__instance); float item = respawnFor.min; float item2 = respawnFor.max; Component enemyParentFromHealth = EnemyUtilities.GetEnemyParentFromHealth((Component)((__instance is Component) ? __instance : null)); if ((Object)(object)enemyParentFromHealth != (Object)null) { EnemyUtilities.SetRespawnWindowOnParent(enemyParentFromHealth, item, item2, adjustCurrentTimer: false); } } catch (Exception arg) { Debug.LogError((object)$"EnemyHealthEditor: failed to apply HP/Respawn: {arg}"); } } } } namespace EnemyHealthEditor { [BepInPlugin("Omniscye.EnemyHealthEditor", "EnemyHealthEditor", "1.0")] public class EnemyHealthEditor : BaseUnityPlugin { internal static EnemyHealthEditor Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } private void Awake() { Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Patch(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!"); } internal void Patch() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0026: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(); } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { } } }