Decompiled source of MonsterScaler v1.0.0

plugins/MonsterScaler.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using REPOLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("MonsterScaler")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MonsterScaler")]
[assembly: AssemblyTitle("MonsterScaler")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 MonsterScaler
{
	[BepInPlugin("com.PxntxrezStudio.monsterscaler", "MonsterScaler", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class MonsterScalerPlugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "com.PxntxrezStudio.monsterscaler";

		public const string PLUGIN_NAME = "MonsterScaler";

		public const string PLUGIN_VERSION = "1.0.0";

		internal static MonsterScalerPlugin Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		internal static Harmony Harmony { get; set; }

		internal static ConfigManager ConfigManager { get; private set; }

		private void Awake()
		{
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			ConfigManager = new ConfigManager(((BaseUnityPlugin)this).Config);
			Patch();
			Logger.LogInfo((object)"MonsterScaler v1.0.0 loaded!");
		}

		internal static void Patch()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony = new Harmony("com.PxntxrezStudio.monsterscaler");
			}
			Logger.LogDebug((object)"Patching...");
			Harmony.PatchAll();
			Logger.LogDebug((object)"Patching complete!");
		}

		internal static void Unpatch()
		{
			Harmony harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public class ConfigManager
	{
		private ConfigFile _configFile;

		public ConfigEntry<bool> EnableSpawning { get; private set; }

		public ConfigEntry<int> MonsterMultiplier { get; private set; }

		public ConfigEntry<bool> EnableTier1 { get; private set; }

		public ConfigEntry<bool> EnableTier2 { get; private set; }

		public ConfigEntry<bool> EnableTier3 { get; private set; }

		public Dictionary<string, ConfigEntry<bool>> MonsterToggles { get; private set; }

		public ConfigManager(ConfigFile configFile)
		{
			_configFile = configFile;
			MonsterToggles = new Dictionary<string, ConfigEntry<bool>>();
			SetupConfig();
		}

		private void SetupConfig()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			EnableSpawning = _configFile.Bind<bool>("General", "EnableSpawning", true, "Enable or disable all monster spawning");
			MonsterMultiplier = _configFile.Bind<int>("General", "MonsterMultiplier", 1, new ConfigDescription("Multiplier for total monster count (1-1000)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>()));
			EnableTier1 = _configFile.Bind<bool>("Categories", "EnableTier1", true, "Enable/disable Tier 1 (easy) monsters");
			EnableTier2 = _configFile.Bind<bool>("Categories", "EnableTier2", true, "Enable/disable Tier 2 (medium) monsters");
			EnableTier3 = _configFile.Bind<bool>("Categories", "EnableTier3", true, "Enable/disable Tier 3 (hard) monsters");
		}

		public void RegisterMonster(string monsterName, int tier)
		{
			if (!MonsterToggles.ContainsKey(monsterName))
			{
				ConfigEntry<bool> value = _configFile.Bind<bool>("Monsters", monsterName, true, $"Enable/disable {monsterName} (Tier {tier})");
				MonsterToggles[monsterName] = value;
			}
		}

		public bool IsMonsterEnabled(string monsterName, int tier)
		{
			if (!EnableSpawning.Value)
			{
				return false;
			}
			if (tier switch
			{
				1 => EnableTier1.Value ? 1 : 0, 
				2 => EnableTier2.Value ? 1 : 0, 
				3 => EnableTier3.Value ? 1 : 0, 
				_ => 0, 
			} == 0)
			{
				return false;
			}
			if (MonsterToggles.TryGetValue(monsterName, out var value))
			{
				return value.Value;
			}
			return true;
		}
	}
	public class MonsterData
	{
		public string Name { get; set; }

		public int Tier { get; set; }

		public EnemySetup OriginalSetup { get; set; }

		public bool IsEnabled { get; set; }

		public MonsterData(string name, int tier, EnemySetup setup)
		{
			Name = name;
			Tier = tier;
			OriginalSetup = setup;
			IsEnabled = true;
		}
	}
	public static class MonsterManager
	{
		private static bool _initialized = false;

		public static Dictionary<string, MonsterData> AllMonsters { get; private set; } = new Dictionary<string, MonsterData>();


		public static void Initialize(EnemyDirector director)
		{
			if (_initialized)
			{
				return;
			}
			AllMonsters.Clear();
			RegisterMonstersFromList(director.enemiesDifficulty1, 1);
			RegisterMonstersFromList(director.enemiesDifficulty2, 2);
			RegisterMonstersFromList(director.enemiesDifficulty3, 3);
			_initialized = true;
			MonsterScalerPlugin.Logger.LogInfo((object)$"Registered {AllMonsters.Count} monsters");
			foreach (MonsterData value in AllMonsters.Values)
			{
				MonsterScalerPlugin.Logger.LogInfo((object)$"  - {value.Name} (Tier {value.Tier})");
			}
		}

		private static void RegisterMonstersFromList(List<EnemySetup> enemies, int tier)
		{
			foreach (EnemySetup enemy in enemies)
			{
				string name = ((Object)enemy).name;
				if (!AllMonsters.ContainsKey(name))
				{
					MonsterData value = new MonsterData(name, tier, enemy);
					AllMonsters[name] = value;
					MonsterScalerPlugin.ConfigManager.RegisterMonster(name, tier);
				}
			}
		}

		public static List<MonsterData> GetEnabledMonsters()
		{
			List<MonsterData> list = new List<MonsterData>();
			foreach (MonsterData value in AllMonsters.Values)
			{
				if (MonsterScalerPlugin.ConfigManager.IsMonsterEnabled(value.Name, value.Tier))
				{
					list.Add(value);
				}
			}
			return list;
		}

		public static void UpdateEnabledStatus()
		{
			foreach (MonsterData value in AllMonsters.Values)
			{
				value.IsEnabled = MonsterScalerPlugin.ConfigManager.IsMonsterEnabled(value.Name, value.Tier);
			}
		}
	}
	public static class SpawnCalculator
	{
		public static Dictionary<int, int> CalculateSpawnCounts()
		{
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			if (!MonsterScalerPlugin.ConfigManager.EnableSpawning.Value)
			{
				dictionary[1] = 0;
				dictionary[2] = 0;
				dictionary[3] = 0;
				return dictionary;
			}
			List<MonsterData> enabledMonsters = MonsterManager.GetEnabledMonsters();
			if (enabledMonsters.Count == 0)
			{
				MonsterScalerPlugin.Logger.LogWarning((object)"No monsters enabled! Using default spawning.");
				dictionary[1] = 1;
				dictionary[2] = 1;
				dictionary[3] = 1;
				return dictionary;
			}
			int value = MonsterScalerPlugin.ConfigManager.MonsterMultiplier.Value;
			Dictionary<int, int> dictionary2 = new Dictionary<int, int>
			{
				{
					1,
					enabledMonsters.Count((MonsterData m) => m.Tier == 1)
				},
				{
					2,
					enabledMonsters.Count((MonsterData m) => m.Tier == 2)
				},
				{
					3,
					enabledMonsters.Count((MonsterData m) => m.Tier == 3)
				}
			};
			int[] array = new int[3] { 1, 2, 3 };
			foreach (int key in array)
			{
				if (dictionary2[key] > 0)
				{
					dictionary[key] = value;
				}
				else
				{
					dictionary[key] = 0;
				}
			}
			MonsterScalerPlugin.Logger.LogInfo((object)$"Spawn calculation: Multiplier={value}");
			MonsterScalerPlugin.Logger.LogInfo((object)$"  Tier 1: {dictionary[1]} total spawns for {dictionary2[1]} monsters");
			MonsterScalerPlugin.Logger.LogInfo((object)$"  Tier 2: {dictionary[2]} total spawns for {dictionary2[2]} monsters");
			MonsterScalerPlugin.Logger.LogInfo((object)$"  Tier 3: {dictionary[3]} total spawns for {dictionary2[3]} monsters");
			return dictionary;
		}
	}
	public static class ReflectionHelper
	{
		private static FieldInfo _enemyListField;

		private static FieldInfo _enemyListCurrentField;

		private static FieldInfo _totalAmountField;

		static ReflectionHelper()
		{
			Type typeFromHandle = typeof(EnemyDirector);
			_enemyListField = typeFromHandle.GetField("enemyList", BindingFlags.Instance | BindingFlags.NonPublic);
			_enemyListCurrentField = typeFromHandle.GetField("enemyListCurrent", BindingFlags.Instance | BindingFlags.NonPublic);
			_totalAmountField = typeFromHandle.GetField("totalAmount", BindingFlags.Instance | BindingFlags.NonPublic);
			if (_enemyListField == null || _enemyListCurrentField == null || _totalAmountField == null)
			{
				MonsterScalerPlugin.Logger.LogError((object)"Failed to find internal fields via reflection!");
			}
		}

		public static List<EnemySetup> GetEnemyList(EnemyDirector director)
		{
			return (List<EnemySetup>)(_enemyListField?.GetValue(director));
		}

		public static List<EnemySetup> GetEnemyListCurrent(EnemyDirector director)
		{
			return (List<EnemySetup>)(_enemyListCurrentField?.GetValue(director));
		}

		public static void SetTotalAmount(EnemyDirector director, int value)
		{
			_totalAmountField?.SetValue(director, value);
		}

		public static int GetTotalAmount(EnemyDirector director)
		{
			return (int)(_totalAmountField?.GetValue(director) ?? ((object)0));
		}
	}
	[HarmonyPatch(typeof(EnemyDirector))]
	public class EnemyDirectorPatches
	{
		private static bool _setupComplete;

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		public static void Start_Postfix(EnemyDirector __instance)
		{
			BundleLoader.OnAllBundlesLoaded += delegate
			{
				MonsterScalerPlugin.Logger.LogInfo((object)"All bundles loaded, initializing MonsterScaler...");
				MonsterManager.Initialize(__instance);
				_setupComplete = true;
			};
		}

		[HarmonyPatch("AmountSetup")]
		[HarmonyPrefix]
		public static bool AmountSetup_Prefix(EnemyDirector __instance)
		{
			if (!_setupComplete)
			{
				MonsterScalerPlugin.Logger.LogWarning((object)"Setup not complete yet, using default spawning");
				return true;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return false;
			}
			try
			{
				CustomAmountSetup(__instance);
				return false;
			}
			catch (Exception arg)
			{
				MonsterScalerPlugin.Logger.LogError((object)$"Error in CustomAmountSetup: {arg}");
				return true;
			}
		}

		private static void CustomAmountSetup(EnemyDirector director)
		{
			List<EnemySetup> enemyListCurrent = ReflectionHelper.GetEnemyListCurrent(director);
			List<EnemySetup> enemyList = ReflectionHelper.GetEnemyList(director);
			enemyListCurrent.Clear();
			enemyList.Clear();
			MonsterManager.UpdateEnabledStatus();
			Dictionary<int, int> dictionary = SpawnCalculator.CalculateSpawnCounts();
			MonsterScalerPlugin.Logger.LogInfo((object)"=== Custom Spawn Setup ===");
			director.enemiesDifficulty1.Clear();
			director.enemiesDifficulty2.Clear();
			director.enemiesDifficulty3.Clear();
			foreach (MonsterData enabledMonster in MonsterManager.GetEnabledMonsters())
			{
				EnemySetup originalSetup = enabledMonster.OriginalSetup;
				switch (enabledMonster.Tier)
				{
				case 1:
					director.enemiesDifficulty1.Add(originalSetup);
					break;
				case 2:
					director.enemiesDifficulty2.Add(originalSetup);
					break;
				case 3:
					director.enemiesDifficulty3.Add(originalSetup);
					break;
				}
			}
			SpawnMonstersForTier(director, director.enemiesDifficulty3, dictionary[3], 3);
			SpawnMonstersForTier(director, director.enemiesDifficulty2, dictionary[2], 2);
			SpawnMonstersForTier(director, director.enemiesDifficulty1, dictionary[1], 1);
			ReflectionHelper.SetTotalAmount(director, enemyList.Count);
			MonsterScalerPlugin.Logger.LogInfo((object)$"Total spawns: {ReflectionHelper.GetTotalAmount(director)}");
			MonsterScalerPlugin.Logger.LogInfo((object)"==========================");
		}

		private static void SpawnMonstersForTier(EnemyDirector director, List<EnemySetup> enemyList, int totalCount, int tier)
		{
			if (enemyList.Count == 0 || totalCount == 0)
			{
				return;
			}
			List<EnemySetup> enemyList2 = ReflectionHelper.GetEnemyList(director);
			int num = totalCount / enemyList.Count;
			int num2 = totalCount % enemyList.Count;
			MonsterScalerPlugin.Logger.LogInfo((object)$"Tier {tier}: Spawning {totalCount} total ({num} each, +{num2} remainder)");
			for (int i = 0; i < enemyList.Count; i++)
			{
				EnemySetup val = enemyList[i];
				int num3 = num;
				if (i < num2)
				{
					num3++;
				}
				for (int j = 0; j < num3; j++)
				{
					enemyList2.Add(val);
				}
				MonsterScalerPlugin.Logger.LogInfo((object)$"  - {((Object)val).name}: x{num3}");
			}
		}
	}
	[HarmonyPatch(typeof(LevelGenerator))]
	public class LevelGeneratorPatches
	{
		[HarmonyPatch("EnemySpawn")]
		[HarmonyPrefix]
		public static bool EnemySpawn_Prefix(EnemySetup enemySetup)
		{
			if (!MonsterScalerPlugin.ConfigManager.EnableSpawning.Value)
			{
				MonsterScalerPlugin.Logger.LogInfo((object)"Spawn blocked: spawning disabled");
				return false;
			}
			return true;
		}
	}
}