Decompiled source of Simple EnemyScaler v4.0.0

Simple_EnemyScaler.dll

Decompiled a week ago
using System;
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("REPOJP")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("zabuMod")]
[assembly: AssemblyTitle("zabuMod")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace REPOJP.Simple_EnemyScaler
{
	[BepInPlugin("REPOJP.Simple_EnemyScaler", "Simple_EnemyScaler", "4.0.0")]
	public sealed class Simple_EnemyScalerPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "REPOJP.Simple_EnemyScaler";

		public const string PluginName = "Simple_EnemyScaler";

		public const string PluginVersion = "4.0.0";

		internal static Simple_EnemyScalerPlugin Instance;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> EnableMod;

		internal static ConfigEntry<float> EnemyCountMultiplier;

		internal static ConfigEntry<bool> EnableLog;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			try
			{
				Instance = this;
				Log = ((BaseUnityPlugin)this).Logger;
				((Component)this).transform.parent = null;
				((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
				EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "Enable this mod. このMODの有効無効");
				EnemyCountMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "EnemyCountMultiplier", 1.5f, new ConfigDescription("Default enemy count multiplier applied by host only. ホストのみで適用する敵数倍率", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
				EnableLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableLog", true, "Enable log output. ログ出力有効無効");
				_harmony = new Harmony("REPOJP.Simple_EnemyScaler");
				_harmony.PatchAll(typeof(Simple_EnemyScalerPlugin).Assembly);
				WriteInfo("Loaded v4.0.0 EnemyCountMultiplier=" + EnemyCountMultiplier.Value.ToString("0.###"));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failure: Awake\n" + ex));
				throw;
			}
		}

		private void OnDestroy()
		{
			try
			{
				if (_harmony != null)
				{
					_harmony.UnpatchSelf();
					_harmony = null;
				}
			}
			catch
			{
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		internal static bool IsEnabled()
		{
			return EnableMod != null && EnableMod.Value;
		}

		internal static bool IsHostOrSingle()
		{
			try
			{
				return SemiFunc.IsMasterClientOrSingleplayer();
			}
			catch
			{
				return true;
			}
		}

		internal static void WriteInfo(string message)
		{
			if (Log != null && (EnableLog == null || EnableLog.Value))
			{
				Log.LogInfo((object)message);
			}
		}

		internal static void WriteWarning(string message)
		{
			if (Log != null && (EnableLog == null || EnableLog.Value))
			{
				Log.LogWarning((object)message);
			}
		}

		internal static void WriteError(string message)
		{
			if (Log != null && (EnableLog == null || EnableLog.Value))
			{
				Log.LogError((object)message);
			}
		}
	}
	[HarmonyPatch(typeof(EnemyDirector), "AmountSetup")]
	internal static class Patch_EnemyDirector_AmountSetup
	{
		private static readonly FieldInfo FiAmountCurve1Value = AccessTools.Field(typeof(EnemyDirector), "amountCurve1Value");

		private static readonly FieldInfo FiAmountCurve2Value = AccessTools.Field(typeof(EnemyDirector), "amountCurve2Value");

		private static readonly FieldInfo FiAmountCurve3Value = AccessTools.Field(typeof(EnemyDirector), "amountCurve3Value");

		private static readonly FieldInfo FiTotalAmount = AccessTools.Field(typeof(EnemyDirector), "totalAmount");

		private static readonly FieldInfo FiEnemyList = AccessTools.Field(typeof(EnemyDirector), "enemyList");

		private static readonly FieldInfo FiEnemyListCurrent = AccessTools.Field(typeof(EnemyDirector), "enemyListCurrent");

		private static readonly FieldInfo FiEnemyListIndex = AccessTools.Field(typeof(EnemyDirector), "enemyListIndex");

		private static readonly MethodInfo MiPickEnemies = AccessTools.Method(typeof(EnemyDirector), "PickEnemies", (Type[])null, (Type[])null);

		private static void Postfix(EnemyDirector __instance)
		{
			try
			{
				ApplyScaledEnemyCount(__instance);
			}
			catch (Exception ex)
			{
				Simple_EnemyScalerPlugin.WriteError("Failure: Enemy count scale\n" + ex);
			}
		}

		private static void ApplyScaledEnemyCount(EnemyDirector director)
		{
			if (!Simple_EnemyScalerPlugin.IsEnabled() || !Simple_EnemyScalerPlugin.IsHostOrSingle() || (Object)(object)director == (Object)null)
			{
				return;
			}
			if (FiAmountCurve1Value == null || FiAmountCurve2Value == null || FiAmountCurve3Value == null || FiTotalAmount == null || FiEnemyList == null || FiEnemyListCurrent == null || FiEnemyListIndex == null || MiPickEnemies == null)
			{
				Simple_EnemyScalerPlugin.WriteWarning("Required EnemyDirector reflection target is missing.");
				return;
			}
			if (director.enemiesDifficulty1 == null || director.enemiesDifficulty2 == null || director.enemiesDifficulty3 == null)
			{
				Simple_EnemyScalerPlugin.WriteWarning("Enemy difficulty list is missing.");
				return;
			}
			float num = 1f;
			if (Simple_EnemyScalerPlugin.EnemyCountMultiplier != null)
			{
				num = Simple_EnemyScalerPlugin.EnemyCountMultiplier.Value;
			}
			num = Mathf.Clamp(num, 0f, 10f);
			if (Mathf.Abs(num - 1f) < 0.0001f)
			{
				return;
			}
			int num2 = Mathf.Max(0, GetInt(director, FiAmountCurve1Value));
			int num3 = Mathf.Max(0, GetInt(director, FiAmountCurve2Value));
			int num4 = Mathf.Max(0, GetInt(director, FiAmountCurve3Value));
			int num5 = Mathf.Max(0, GetInt(director, FiTotalAmount));
			if (num5 != num2 + num3 + num4)
			{
				num5 = num2 + num3 + num4;
			}
			CalcScaledCounts(num2, num3, num4, num5, num, out var target, out var target2, out var target3, out var targetTotal);
			List<EnemySetup> enemyList = GetEnemyList(director, FiEnemyList);
			List<EnemySetup> enemyList2 = GetEnemyList(director, FiEnemyListCurrent);
			if (enemyList == null || enemyList2 == null)
			{
				Simple_EnemyScalerPlugin.WriteWarning("EnemyDirector enemy list is missing.");
				return;
			}
			enemyList.Clear();
			enemyList2.Clear();
			SetInt(director, FiEnemyListIndex, 0);
			if (targetTotal <= 0)
			{
				SetInt(director, FiAmountCurve1Value, 0);
				SetInt(director, FiAmountCurve2Value, 0);
				SetInt(director, FiAmountCurve3Value, 0);
				SetInt(director, FiTotalAmount, 0);
				Simple_EnemyScalerPlugin.WriteInfo("EnemyCountMultiplier applied " + num5 + " -> 0 x" + num.ToString("0.###"));
				return;
			}
			int num6 = PickEnemiesSafe(director, director.enemiesDifficulty3, target3, enemyList, enemyList2);
			int num7 = PickEnemiesSafe(director, director.enemiesDifficulty2, target2, enemyList, enemyList2);
			int num8 = PickEnemiesSafe(director, director.enemiesDifficulty1, target, enemyList, enemyList2);
			int value = num8 + num7 + num6;
			SetInt(director, FiAmountCurve1Value, num8);
			SetInt(director, FiAmountCurve2Value, num7);
			SetInt(director, FiAmountCurve3Value, num6);
			SetInt(director, FiTotalAmount, value);
			SetInt(director, FiEnemyListIndex, 0);
			Simple_EnemyScalerPlugin.WriteInfo("EnemyCountMultiplier applied " + num5 + " -> " + value + " x" + num.ToString("0.###") + " / D1 " + num2 + "->" + num8 + " / D2 " + num3 + "->" + num7 + " / D3 " + num4 + "->" + num6);
		}

		private static int PickEnemiesSafe(EnemyDirector director, List<EnemySetup> source, int count, List<EnemySetup> enemyList, List<EnemySetup> enemyListCurrent)
		{
			if ((Object)(object)director == (Object)null || source == null || count <= 0 || enemyList == null || enemyListCurrent == null)
			{
				return 0;
			}
			int num = 0;
			object[] parameters = new object[1] { source };
			for (int i = 0; i < count; i++)
			{
				int count2 = enemyList.Count;
				int count3 = enemyListCurrent.Count;
				try
				{
					MiPickEnemies.Invoke(director, parameters);
				}
				catch (Exception ex)
				{
					Simple_EnemyScalerPlugin.WriteWarning("PickEnemies failed.\n" + ex);
					RemoveAddedRange(enemyList, count2);
					RemoveAddedRange(enemyListCurrent, count3);
					continue;
				}
				EnemySetup val = null;
				if (enemyList.Count > count2)
				{
					val = enemyList[enemyList.Count - 1];
				}
				if ((Object)(object)val == (Object)null)
				{
					RemoveAddedRange(enemyList, count2);
					RemoveAddedRange(enemyListCurrent, count3);
				}
				else
				{
					num++;
				}
			}
			return num;
		}

		private static void RemoveAddedRange(List<EnemySetup> list, int originalCount)
		{
			if (list != null)
			{
				while (list.Count > originalCount)
				{
					list.RemoveAt(list.Count - 1);
				}
			}
		}

		private static int GetInt(object instance, FieldInfo field)
		{
			if (instance == null || field == null)
			{
				return 0;
			}
			try
			{
				object value = field.GetValue(instance);
				if (value is int)
				{
					return (int)value;
				}
			}
			catch
			{
			}
			return 0;
		}

		private static void SetInt(object instance, FieldInfo field, int value)
		{
			if (instance == null || field == null)
			{
				return;
			}
			try
			{
				field.SetValue(instance, value);
			}
			catch
			{
			}
		}

		private static List<EnemySetup> GetEnemyList(object instance, FieldInfo field)
		{
			if (instance == null || field == null)
			{
				return null;
			}
			try
			{
				return field.GetValue(instance) as List<EnemySetup>;
			}
			catch
			{
				return null;
			}
		}

		private static void CalcScaledCounts(int base1, int base2, int base3, int baseTotal, float multiplier, out int target1, out int target2, out int target3, out int targetTotal)
		{
			target1 = 0;
			target2 = 0;
			target3 = 0;
			targetTotal = 0;
			if (baseTotal <= 0 || (base1 <= 0 && base2 <= 0 && base3 <= 0))
			{
				return;
			}
			targetTotal = Mathf.RoundToInt((float)baseTotal * multiplier);
			targetTotal = Mathf.Clamp(targetTotal, 0, Mathf.RoundToInt((float)baseTotal * 10f));
			float num = (float)base1 * multiplier;
			float num2 = (float)base2 * multiplier;
			float num3 = (float)base3 * multiplier;
			int num4 = Mathf.Max(0, Mathf.FloorToInt(num));
			int num5 = Mathf.Max(0, Mathf.FloorToInt(num2));
			int num6 = Mathf.Max(0, Mathf.FloorToInt(num3));
			float num7 = Mathf.Max(0f, num - (float)num4);
			float num8 = Mathf.Max(0f, num2 - (float)num5);
			float num9 = Mathf.Max(0f, num3 - (float)num6);
			target1 = num4;
			target2 = num5;
			target3 = num6;
			int num10 = targetTotal - (target1 + target2 + target3);
			if (num10 > 0)
			{
				int[] array = new int[3] { 1, 2, 3 };
				float[] fractions2 = new float[3] { num7, num8, num9 };
				Array.Sort(array, (int a, int b) => fractions2[b - 1].CompareTo(fractions2[a - 1]));
				int num11 = 0;
				while (num10 > 0)
				{
					switch (array[num11 % 3])
					{
					case 1:
						target1++;
						break;
					case 2:
						target2++;
						break;
					default:
						target3++;
						break;
					}
					num10--;
					num11++;
				}
			}
			else if (num10 < 0)
			{
				int[] array2 = new int[3] { 1, 2, 3 };
				float[] fractions = new float[3] { num7, num8, num9 };
				Array.Sort(array2, (int a, int b) => fractions[a - 1].CompareTo(fractions[b - 1]));
				int num12 = 0;
				int num13 = 0;
				while (num10 < 0 && target1 + target2 + target3 > 0 && num13 < 100000)
				{
					int num14 = array2[num12 % 3];
					if (num14 == 1 && target1 > 0)
					{
						target1--;
						num10++;
					}
					else if (num14 == 2 && target2 > 0)
					{
						target2--;
						num10++;
					}
					else if (num14 == 3 && target3 > 0)
					{
						target3--;
						num10++;
					}
					num12++;
					num13++;
				}
			}
			target1 = Mathf.Max(0, target1);
			target2 = Mathf.Max(0, target2);
			target3 = Mathf.Max(0, target3);
			targetTotal = Mathf.Max(0, target1 + target2 + target3);
		}
	}
}