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;
}
}
}