using 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()
{
}
}
}