Decompiled source of Mutators v1.0.3

Mutators.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mutators.Announcements;
using Mutators.Assets;
using Mutators.Assets.Loaders;
using Mutators.Enums;
using Mutators.Extensions;
using Mutators.Logging.Loggers;
using Mutators.Managers;
using Mutators.Mutators;
using Mutators.Mutators.Behaviours;
using Mutators.Mutators.Behaviours.HurtColliders;
using Mutators.Mutators.Behaviours.Markers;
using Mutators.Mutators.Behaviours.UI;
using Mutators.Mutators.MultiMutators;
using Mutators.Mutators.Patches;
using Mutators.Network;
using Mutators.Patches;
using Mutators.Providers.Random;
using Mutators.Providers.Semiwork;
using Mutators.Rules.Loaders;
using Mutators.Rules.Loaders.Json;
using Mutators.Rules.Loaders.Strategies;
using Mutators.Rules.Registries;
using Mutators.Services.Selection;
using Mutators.Services.Selection.Strategies;
using Mutators.Settings;
using Mutators.Settings.Specific;
using Mutators.Utility;
using Mutators.Utility.Config;
using Newtonsoft.Json;
using Photon.Pun;
using Photon.Realtime;
using REPOLib.Modules;
using ScalerCore;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Xepos")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3+da0a5261df0daa082b4c5feafc5e4a019daf68b4")]
[assembly: AssemblyProduct("Mutators")]
[assembly: AssemblyTitle("Mutators")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Justin-dr/REPO-Mutators.git")]
[assembly: InternalsVisibleTo("Mutators.Tests")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[CompilerGenerated]
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	int ICollection.Count => _items.Length;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => _items.Length;

	T IReadOnlyList<T>.this[int index] => _items[index];

	int ICollection<T>.Count => _items.Length;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlyArray(T[] items)
	{
		_items = items;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return ((IEnumerable)_items).GetEnumerator();
	}

	void ICollection.CopyTo(Array array, int index)
	{
		((ICollection)_items).CopyTo(array, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return ((IList)_items).Contains(value);
	}

	int IList.IndexOf(object value)
	{
		return ((IList)_items).IndexOf(value);
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return ((IEnumerable<T>)_items).GetEnumerator();
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return ((ICollection<T>)_items).Contains(item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		((ICollection<T>)_items).CopyTo(array, arrayIndex);
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		return ((IList<T>)_items).IndexOf(item);
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}
[CompilerGenerated]
internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T>
	{
		object IEnumerator.Current => _item;

		T IEnumerator<T>.Current => _item;

		public Enumerator(T item)
		{
			_item = item;
		}

		bool IEnumerator.MoveNext()
		{
			if (!_moveNextCalled)
			{
				return _moveNextCalled = true;
			}
			return false;
		}

		void IEnumerator.Reset()
		{
			_moveNextCalled = false;
		}

		void IDisposable.Dispose()
		{
		}
	}

	int ICollection.Count => 1;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => 1;

	T IReadOnlyList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
	}

	int ICollection<T>.Count => 1;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlySingleElementList(T item)
	{
		_item = item;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection.CopyTo(Array array, int index)
	{
		array.SetValue(_item, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return EqualityComparer<T>.Default.Equals(_item, (T)value);
	}

	int IList.IndexOf(object value)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, (T)value))
		{
			return -1;
		}
		return 0;
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return EqualityComparer<T>.Default.Equals(_item, item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		array[arrayIndex] = _item;
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, item))
		{
			return -1;
		}
		return 0;
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 Mutators
{
	[BepInDependency("Vippy.ScalerCore", "1.0.2")]
	[BepInDependency("REPOLib", "4.2.0")]
	[BepInPlugin("Xepos.REPO-Mutators", "Mutators", "1.0.3")]
	public class RepoMutators : BaseUnityPlugin
	{
		internal const string MainScenePath = "Assets/Scenes/Main/Main.unity";

		internal const string NETWORKMANAGER_NAME = "MutatorsNetworkManager";

		internal const string MUTATOR_OVERRIDES = "mutatorOverrides";

		public static string ConfigPath => Path.Combine(Paths.ConfigPath, "Mutators");

		internal static RepoMutators Instance { get; private set; } = null;

		internal static ModSettings Settings { get; private set; } = null;

		internal static IMutatorsLogger Logger { get; private set; } = new NullMutatorsLogger();

		internal Harmony? Harmony { get; set; }

		public static event Action<IRuleLoader<Func<IReadOnlyCollection<string>, string, bool>>>? OnLoadMultiMutatorRules;

		public static event Action<IRuleLoader<Predicate<string>>>? OnLoadSingleMutatorRules;

		private RepoMutators()
		{
		}

		private void Awake()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			Instance = this;
			Logger = new MutatorsLogger(((BaseUnityPlugin)this).Logger);
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Settings = new ModSettings(((BaseUnityPlugin)this).Config);
			MutatorSettings.Initialize(((BaseUnityPlugin)this).Config);
			InitializeDependencyContainer(new NopMutator(MutatorSettings.NopMutator));
			GameObject val = new GameObject("RepoMutatorsPrefab")
			{
				hideFlags = (HideFlags)61
			};
			val.SetActive(false);
			val.AddComponent<PhotonView>();
			val.AddComponent<MutatorsNetworkManager>();
			string myPrefabId = "Xepos.REPO-Mutators/MutatorsNetworkManager";
			NetworkPrefabs.RegisterNetworkPrefab(myPrefabId, val);
			ScheduleAssetLoad();
			SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode _)
			{
				//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				if (!(((Scene)(ref scene)).path != "Assets/Scenes/Main/Main.unity") && SemiFunc.IsMasterClientOrSingleplayer())
				{
					if ((Object)(object)RunManager.instance.levelCurrent == (Object)(object)RunManager.instance.levelMainMenu)
					{
						if ((Object)(object)MutatorsNetworkManager.Instance != (Object)null && (Object)(object)((Component)MutatorsNetworkManager.Instance).gameObject != (Object)null)
						{
							Object.Destroy((Object)(object)((Component)MutatorsNetworkManager.Instance).gameObject);
						}
					}
					else if (!((Object)(object)MutatorsNetworkManager.Instance != (Object)null) && SemiFunc.RunIsLobbyMenu())
					{
						Logger.LogDebug("Reviving network manager");
						PrefabRef val2 = default(PrefabRef);
						if (!NetworkPrefabs.TryGetNetworkPrefabRef(myPrefabId, ref val2))
						{
							throw new Exception("Unable to establish Mutators NetworkManager: Could not find PrefabRef with id: " + myPrefabId);
						}
						NetworkPrefabs.SpawnNetworkPrefab(val2, Vector3.zero, Quaternion.identity, (byte)0, (object[])null);
						MutatorManager instance = MutatorManager.Instance;
						Logger.LogInfo(string.Join(", ", instance.RegisteredMutators.Select<KeyValuePair<string, IMutator>, string>((KeyValuePair<string, IMutator> x) => $"{x.Key}: {x.Value.Settings.Weight}")) ?? "");
						IMutator weightedMutator = instance.GetWeightedMutator();
						Logger.LogDebug("Picked weighted mutator: " + weightedMutator.Name);
						instance.CurrentMutator = weightedMutator;
						if (weightedMutator is IMultiMutator multiMutator)
						{
							(IList<string>, IDictionary<string, object>) tuple = multiMutator.Format();
							MutatorsNetworkManager.Instance.SendActiveMutators(multiMutator, tuple.Item2);
						}
						else
						{
							MutatorsNetworkManager.Instance.SendActiveMutator(weightedMutator.NamespacedName, weightedMutator.Settings.AsMetadata());
						}
						Logger.LogDebug("Mutator set: " + weightedMutator.Name);
					}
				}
			};
			MutatorManager.Instance.GameStateChanged += delegate(MutatorsGameState gameState)
			{
				Logger.LogDebug($"Changed Mutators gamestate to {gameState}");
			};
			Patch();
			Logger.LogInfo($"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
			Logger.LogDebug("Initializing default mutators.");
			MutatorManager.Instance.InitializeDefaultMutators();
			OnLoadSingleMutatorRules += delegate(IRuleLoader<Predicate<string>> ruleLoader)
			{
				ruleLoader.AddRuleStrategy(new ExclusionRuleLoadingStrategy());
				ruleLoader.AddDefaultRule(new JsonMutatorRule("exclude-null-signal", "Exclusion", new string[1] { MutatorSettings.NullSignal.NamespacedName }));
			};
			OnLoadMultiMutatorRules += delegate(IRuleLoader<Func<IReadOnlyCollection<string>, string, bool>> ruleLoader)
			{
				ruleLoader.AddRuleStrategy(new MultiExclusionRuleLoadingStrategy());
				ruleLoader.AddRuleStrategy(new MutualExclusionRuleLoadingStrategy());
				ruleLoader.AddRuleStrategy(new RequiresAmountOfOtherMutatorsRuleLoadingStrategy());
				IDictionary<string, object> arguments = new Dictionary<string, object> { { "other-mutators-required-amount", 2 } };
				ruleLoader.AddDefaultRules(new JsonMutatorRule("handle-with-care-less-is-more", "Mutual Exclusion", new string[2]
				{
					MutatorSettings.HandleWithCare.NamespacedName,
					MutatorSettings.LessIsMore.NamespacedName
				}), new JsonMutatorRule("protect-the-weak-protect-the-president", "Mutual Exclusion", new string[2]
				{
					MutatorSettings.ProtectTheWeak.NamespacedName,
					MutatorSettings.ProtectThePresident.NamespacedName
				}), new JsonMutatorRule("the-floor-is-lava-one-shot-one-kill", "Mutual Exclusion", new string[2]
				{
					MutatorSettings.TheFloorIsLava.NamespacedName,
					MutatorSettings.OneShotOneKill.NamespacedName
				}), new JsonMutatorRule("the-floor-is-lava-rusty-servos", "Mutual Exclusion", new string[2]
				{
					MutatorSettings.TheFloorIsLava.NamespacedName,
					MutatorSettings.RustyServos.NamespacedName
				}), new JsonMutatorRule("size-matters-rusty-servos", "Mutual Exclusion", new string[2]
				{
					MutatorSettings.SizeMatters.NamespacedName,
					MutatorSettings.RustyServos.NamespacedName
				}), new JsonMutatorRule("null-signal-required-amount-of-other-mutators", "Requires Amount Of Other Mutators", new string[1] { MutatorSettings.NullSignal.NamespacedName }, null, arguments));
			};
		}

		private void InitializeDependencyContainer(NopMutator nopMutator)
		{
			DI.Container.AddSingleton(Logger).AddSingleton<IRandomProvider, RandomProvider>().AddSingleton<ISemiFuncProvider, SemiFuncProvider>()
				.AddSingleton(new GeneratedMultiMutatorSelectionRulesRegistry())
				.AddSingleton<SingleMutatorSelectionRulesRegistry>()
				.AddSingleton<IRepeatSelectionTracker, RepeatSelectionTracker>()
				.AddSingleton(Settings.MoonMutatorSettings)
				.AddSingleton(Settings.RandomMutatorSettings)
				.AddSingleton(nopMutator)
				.AddSingleton<NoneScalingSelectionStrategy>()
				.AddSingleton<MoonScalingSelectionStrategy>()
				.AddSingleton<RandomScalingSelectionStrategy>()
				.AddSingleton<IMutatorSelectionService, MutatorSelectionService>()
				.AddSingleton<MutatorManager>();
		}

		private static void ScheduleAssetLoad()
		{
			UnityAction<Scene, LoadSceneMode> sceneLoaded = null;
			sceneLoaded = delegate(Scene scene, LoadSceneMode _)
			{
				if (!(((Scene)(ref scene)).path != "Assets/Scenes/Main/Main.unity"))
				{
					List<BaseGameAssetLoader> list = new List<BaseGameAssetLoader>(2)
					{
						new LaserAssetLoader(),
						new ExplosionAssetLoader()
					};
					list.ForEach(delegate(BaseGameAssetLoader loader)
					{
						loader.Load();
					});
					SceneManager.sceneLoaded -= sceneLoaded;
				}
			};
			SceneManager.sceneLoaded += sceneLoaded;
		}

		private void LoadRules()
		{
			SingleMutatorRuleLoader singleMutatorRuleLoader = new SingleMutatorRuleLoader();
			MultiMutatorRuleLoader multiMutatorRuleLoader = new MultiMutatorRuleLoader();
			RepoMutators.OnLoadSingleMutatorRules?.Invoke(singleMutatorRuleLoader);
			RepoMutators.OnLoadMultiMutatorRules?.Invoke(multiMutatorRuleLoader);
			IDictionary<string, Predicate<string>> source = singleMutatorRuleLoader.Load();
			IDictionary<string, Func<IReadOnlyCollection<string>, string, bool>> source2 = multiMutatorRuleLoader.Load();
			SingleMutatorSelectionRulesRegistry singleRegistry = DI.Container.Resolve<SingleMutatorSelectionRulesRegistry>();
			GeneratedMultiMutatorSelectionRulesRegistry multiRegistry = DI.Container.Resolve<GeneratedMultiMutatorSelectionRulesRegistry>();
			source.ForEach(delegate(KeyValuePair<string, Predicate<string>> rule)
			{
				singleRegistry.Register(rule.Key, rule.Value);
			});
			source2.ForEach(delegate(KeyValuePair<string, Func<IReadOnlyCollection<string>, string, bool>> rule)
			{
				multiRegistry.Register(rule.Key, rule.Value);
			});
			RepoMutators.OnLoadSingleMutatorRules = null;
			RepoMutators.OnLoadMultiMutatorRules = null;
		}

		private void Start()
		{
			MutatorManager.Instance.InitializeMultiMutators();
			LoadRules();
		}

		private void Patch()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0054: Expected O, but got Unknown
			bool flag = Chainloader.PluginInfos.Values.Any((PluginInfo x) => x.Metadata.GUID == "soundedsquash.spawnmanager");
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll(typeof(RunManagerPatch));
			Harmony.PatchAll(typeof(LoadingUIPatch));
			Harmony.PatchAll(typeof(MapToolControllerPatch));
			Harmony.PatchAll(typeof(SemiFuncPatch));
			Harmony.PatchAll(typeof(MenuPagePatch));
			Harmony.PatchAll(typeof(SpectateCameraPatch));
			Harmony.PatchAll(typeof(LevelGeneratorPatch));
			Harmony.PatchAll(typeof(MenuManagerPatch));
			Harmony.PatchAll(typeof(HealthUIPatch));
			Harmony.PatchAll(typeof(MapBacktrackPatch));
			if (!flag)
			{
				Harmony.PatchAll(typeof(EnemyDirectorPatch));
			}
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			foreach (IMutator value in MutatorManager.Instance.RegisteredMutators.Values)
			{
				value.Unpatch();
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Xepos.REPO-Mutators";

		public const string PLUGIN_NAME = "Mutators";

		public const string PLUGIN_VERSION = "1.0.3";
	}
	internal class DI
	{
		private IDictionary<Type, Type> _registry = new Dictionary<Type, Type>();

		private IDictionary<Type, object> _singletons = new Dictionary<Type, object>();

		public static DI Container { get; } = new DI();

		public IReadOnlyCollection<Type> RegisteredTypes => new ReadOnlyCollection<Type>(_registry.Keys.ToList());

		public DI AddSingleton<T, I>() where I : T
		{
			Type typeFromHandle = typeof(T);
			Type typeFromHandle2 = typeof(I);
			if (_registry.ContainsKey(typeFromHandle))
			{
				throw new InvalidOperationException($"A type of {typeFromHandle} has already been registered.");
			}
			if (IsStatic(typeFromHandle2))
			{
				throw new ArgumentException("Concrete type " + typeFromHandle2.FullName + " may not be static.");
			}
			if (typeFromHandle2.IsInterface || typeFromHandle2.IsAbstract)
			{
				throw new ArgumentException(typeFromHandle2.FullName + " must be a concrete type.");
			}
			GetConstructor(typeFromHandle2);
			_registry[typeFromHandle] = typeFromHandle2;
			return this;
		}

		public DI AddSingleton<T>() where T : class
		{
			return AddSingleton<T, T>();
		}

		public DI AddSingleton<T>(T instance) where T : class
		{
			if (instance == null)
			{
				throw new ArgumentNullException("instance");
			}
			Type typeFromHandle = typeof(T);
			if (_registry.ContainsKey(typeFromHandle))
			{
				throw new InvalidOperationException($"A type of {typeFromHandle} has already been registered.");
			}
			_registry[typeFromHandle] = instance.GetType();
			_singletons[typeFromHandle] = instance;
			return this;
		}

		public T Resolve<T>()
		{
			return (T)Resolve(typeof(T), new List<Type>());
		}

		private object Resolve(Type serviceType, IList<Type> resolutionPath)
		{
			if (_singletons.TryGetValue(serviceType, out var value))
			{
				return value;
			}
			int num = resolutionPath.IndexOf(serviceType);
			if (num >= 0)
			{
				string text = string.Join(" -> ", from type in resolutionPath.Skip(num).Append(serviceType)
					select type.Name);
				throw new InvalidOperationException("Circular dependency detected: " + text);
			}
			if (!_registry.TryGetValue(serviceType, out var value2))
			{
				throw new ArgumentException("Could not find registered implementation for " + serviceType.FullName + ".");
			}
			ConstructorInfo constructor = GetConstructor(value2);
			resolutionPath.Add(serviceType);
			try
			{
				object[] parameters = (from parameter in constructor.GetParameters()
					select Resolve(parameter.ParameterType, resolutionPath)).ToArray();
				object obj = constructor.Invoke(parameters);
				_singletons[serviceType] = obj;
				return obj;
			}
			finally
			{
				resolutionPath.RemoveAt(resolutionPath.Count - 1);
			}
		}

		private static ConstructorInfo GetConstructor(Type concreteType)
		{
			ConstructorInfo[] constructors = concreteType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			ConstructorInfo[] array = constructors.Where((ConstructorInfo c) => c.IsDefined(typeof(InjectAttribute))).ToArray();
			if (array.Length > 1)
			{
				throw new ArgumentException("Type " + concreteType.FullName + " has multiple constructors marked with [Inject].");
			}
			if (array.Length == 1)
			{
				return array[0];
			}
			return constructors.OrderByDescending((ConstructorInfo c) => c.GetParameters().Length).FirstOrDefault();
		}

		private static bool IsStatic(Type type)
		{
			if ((object)type != null && type.IsClass && type.IsSealed)
			{
				return type.IsAbstract;
			}
			return false;
		}
	}
	[AttributeUsage(AttributeTargets.Constructor)]
	internal class InjectAttribute : Attribute
	{
	}
}
namespace Mutators.Utility
{
	internal static class LevelRemovalUtils
	{
		internal static void RemoveLevels(bool lobbyMenu = false)
		{
			IMutator currentMutator = MutatorManager.Instance.CurrentMutator;
			if (currentMutator is IMultiMutator multiMutator)
			{
				{
					foreach (KeyValuePair<IMutator, IDictionary<string, object>> subMutator in multiMutator.SubMutators)
					{
						subMutator.Key.Settings.ClearRuntimeOverrides();
						subMutator.Key.Settings.ApplyRuntimeOverrides(subMutator.Value);
						if (subMutator.Key.Settings is ILevelRemovingMutatorSettings settings)
						{
							settings.RemoveLevels(lobbyMenu);
						}
					}
					return;
				}
			}
			if (currentMutator.Settings is ILevelRemovingMutatorSettings settings2)
			{
				settings2.RemoveLevels(lobbyMenu);
			}
		}
	}
	public static class TemporaryItemUtils
	{
		public static void RemoveMarkedItems(string marker)
		{
			StatsManager instance = StatsManager.instance;
			foreach (string item in (from x in instance.item
				where x.Key.Contains("(" + marker + ")")
				select x.Key).ToList())
			{
				instance.item.Remove(item);
				instance.itemStatBattery.Remove(item);
			}
		}

		public static void DropAndRemoveMarkedItems(string marker)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			Inventory instance = Inventory.instance;
			foreach (InventorySpot inventorySpot in instance.inventorySpots)
			{
				ItemEquippable currentItem = inventorySpot.CurrentItem;
				if (Object.op_Implicit((Object)(object)currentItem) && Object.op_Implicit((Object)(object)((Component)currentItem).gameObject.GetComponent<TemporaryLevelItemBehaviour>()))
				{
					((Component)currentItem).GetComponent<ItemEquippable>().ForceUnequip(instance.playerAvatar.PlayerVisionTarget.VisionTransform.position, SemiFunc.IsMultiplayer() ? instance.physGrabber.photonView.ViewID : (-1));
				}
			}
			RemoveMarkedItems(marker);
		}
	}
}
namespace Mutators.Utility.Config
{
	public class ConfigRange<T> where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
	{
		private readonly ConfigEntry<T> _min;

		private readonly ConfigEntry<T> _max;

		public T MinimumValue => _min.Value;

		public T MaximumValue => _max.Value;

		internal ConfigRange(ConfigEntry<T> min, ConfigEntry<T> max)
		{
			_min = min;
			_max = max;
		}
	}
	internal class PositiveIntValue : AcceptableValueBase
	{
		private const int MinValue = 0;

		public PositiveIntValue()
			: base(typeof(int))
		{
		}

		public override object Clamp(object value)
		{
			if (!(value is int num))
			{
				return 0;
			}
			return (num >= 0) ? num : 0;
		}

		public override bool IsValid(object value)
		{
			if (value is int)
			{
				return (int)value >= 0;
			}
			return false;
		}

		public override string ToDescriptionString()
		{
			return "# Acceptable values are integers of 0 or higher";
		}
	}
}
namespace Mutators.Settings
{
	public abstract class AbstractMutatorSettings
	{
		protected const string WeightConfigKey = "Weight";

		protected const string MinimumLevelConfigKey = "Minimum level";

		protected const string MaximumLevelConfigKey = "Maximum level";

		private readonly IDictionary<string, object> _runtimeOverrides = new Dictionary<string, object>();

		public string NamespacedName { get; }

		public string MutatorName { get; }

		public string MutatorDescription { get; }

		public abstract int Weight { get; }

		public abstract int MinimumLevel { get; }

		public abstract int MaximumLevel { get; }

		public AbstractMutatorSettings(string @namespace, string name, string description)
		{
			NamespacedName = name.ToSlug(@namespace);
			MutatorName = name;
			MutatorDescription = description;
		}

		public virtual void ApplyRuntimeOverrides(IDictionary<string, object>? overrides)
		{
			if (overrides == null || overrides.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<string, object> @override in overrides)
			{
				_runtimeOverrides[@override.Key] = @override.Value;
			}
		}

		public virtual void ClearRuntimeOverrides()
		{
			_runtimeOverrides.Clear();
		}

		protected T GetRuntimeOverride<T>(string key, T fallback)
		{
			if (!_runtimeOverrides.TryGetValue(key, out object value))
			{
				return fallback;
			}
			if (value.TryCoerce(typeof(T), out object coerced) && coerced is T)
			{
				return (T)coerced;
			}
			return fallback;
		}

		protected IList<T> GetRuntimeOverrideList<T>(string key, IList<T> fallback)
		{
			if (!_runtimeOverrides.TryGetValue(key, out object value))
			{
				return fallback;
			}
			if (value is IList<T> result)
			{
				return result;
			}
			if (value is IEnumerable<T> source)
			{
				return source.ToList();
			}
			if (value is string text && typeof(T) == typeof(string))
			{
				return (from text2 in text.Split(",")
					select text2.Trim() into text2
					where text2.Length > 0
					select text2).Cast<T>().ToList();
			}
			if (value is IEnumerable<object> enumerable)
			{
				IList<T> list = new List<T>();
				{
					foreach (object item3 in enumerable)
					{
						if (item3.TryCoerce(typeof(T), out object coerced) && coerced is T item)
						{
							list.Add(item);
							continue;
						}
						return fallback;
					}
					return list;
				}
			}
			if (!value.TryCoerce(typeof(T), out object coerced2) || !(coerced2 is T item2))
			{
				return fallback;
			}
			return new List<T>(1) { item2 };
		}

		public virtual bool IsEligibleForSelection()
		{
			int levelsCompleted = RunManager.instance.levelsCompleted;
			if (MaximumLevel > 0 && MinimumLevel > MaximumLevel)
			{
				RepoMutators.Logger.LogWarning(MutatorName + " was configured with a minimum level larger than the maximum level!");
				RepoMutators.Logger.LogWarning("This configuration is consider invalid, the level bounds will be ignored.");
				return true;
			}
			if (MaximumLevel == 0)
			{
				return levelsCompleted >= MinimumLevel;
			}
			if (levelsCompleted >= MinimumLevel)
			{
				return levelsCompleted <= MaximumLevel;
			}
			return false;
		}

		public IDictionary<string, object>? AsMetadata()
		{
			return CreateMetadata()?.WithMutator(NamespacedName);
		}

		protected virtual IDictionary<string, object>? CreateMetadata()
		{
			return null;
		}
	}
	public class EnemyDisablingMutatorSettings : GenericMutatorSettings
	{
		public const string ExcludedEnemiesKey = "excluded-enemies";

		private readonly ConfigEntry<string> _excludedEnemies;

		private IList<string> _excludedEnemiesList = new List<string>();

		public IList<string> ExcludedEnemies => GetRuntimeOverrideList("excluded-enemies", _excludedEnemiesList);

		public EnemyDisablingMutatorSettings(string @namespace, string name, string description, int weight, ConfigFile config, params string[] defaultDisabledEnemies)
			: base(@namespace, name, description, weight, config)
		{
			_excludedEnemies = config.Bind<string>(GenericMutatorSettings.GetSection(name), "Excluded enemies", string.Join(", ", defaultDisabledEnemies), "Enemies that cannot be spawned by the " + name + " Mutator. (Comma separated e.g. Apex Predator,Huntsman)");
			_excludedEnemies.SettingChanged += delegate
			{
				CacheEnemies();
			};
			CacheEnemies();
		}

		public EnemyDisablingMutatorSettings(string @namespace, string name, string description, ConfigFile config, params string[] defaultDisabledEnemies)
			: this(@namespace, name, description, 100, config, defaultDisabledEnemies)
		{
		}

		internal void CacheEnemies()
		{
			_excludedEnemiesList = (from value in _excludedEnemies.Value.Split(",")
				select value.Trim()).ToList();
		}
	}
	public class GenericMutatorSettings : AbstractMutatorSettings
	{
		private readonly ConfigEntry<int> _weight;

		private readonly ConfigEntry<int> _minimumLevel;

		private readonly ConfigEntry<int> _maximumLevel;

		public override int Weight => _weight.Value;

		public override int MinimumLevel => _minimumLevel.Value;

		public override int MaximumLevel => _maximumLevel.Value;

		public GenericMutatorSettings(string @namespace, string name, string description, int weight, ConfigFile config)
			: base(@namespace, name, description)
		{
			_weight = config.BindPositive(GetSection(name), "Weight", weight, "Weighted chance for the " + name + " Mutator to be active.");
			_minimumLevel = config.BindPositive(GetSection(name), "Minimum level", 0, "The minimum level on which the " + name + " Mutator can show up");
			_maximumLevel = config.BindPositive(GetSection(name), "Maximum level", 1000, "The maximum level on which the " + name + " mutator can show up (0 = no upper bound)");
		}

		public GenericMutatorSettings(string @namespace, string name, string description, ConfigFile config)
			: this(@namespace, name, description, 100, config)
		{
		}

		protected T GetClampedRuntimeOverride<T>(string key, ConfigEntry<T> entry)
		{
			T runtimeOverride = GetRuntimeOverride(key, entry.Value);
			if (((ConfigEntryBase)entry).Description.AcceptableValues == null)
			{
				return runtimeOverride;
			}
			return (T)((ConfigEntryBase)entry).Description.AcceptableValues.Clamp((object)runtimeOverride);
		}

		protected static string GetSection(string name)
		{
			return name + " Mutator";
		}
	}
	internal interface ILevelRemovingMutatorSettings
	{
		bool AllowCustomLevels { get; }

		IList<string> ExcludedLevels { get; }
	}
	internal class ModSettings
	{
		internal enum MutatorNameToggleType
		{
			Keybind,
			WithDescription
		}

		internal enum MultiMutatorScalingType
		{
			None,
			Random,
			Moon
		}

		internal sealed class MoonSetting(ConfigRange<int> multiMutatorMoonRange, ConfigEntry<int> generatedChance)
		{
			private ConfigRange<int> MultiMutatorMoonRange => multiMutatorMoonRange;

			internal int GeneratedChance => generatedChance.Value;

			internal int MaximumMutators => MultiMutatorMoonRange.MaximumValue;

			internal int MinimumMutators => MultiMutatorMoonRange.MinimumValue;
		}

		internal sealed class MoonSettings
		{
			private readonly IDictionary<int, MoonSetting> _multiMutatorMoonRanges = new Dictionary<int, MoonSetting>();

			private int _moonCount;

			internal void LateBindMoonConfig(ConfigFile config, int moonCount)
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Expected O, but got Unknown
				_moonCount = moonCount;
				for (int i = 0; i <= _moonCount; i++)
				{
					ConfigEntry<int> generatedChance = config.Bind<int>(GetMoonSection(i), "Generated Multi-Mutator Chance (%)", 50, new ConfigDescription($"The chance that a Generated Multi-Mutator will occur when the moon level is {i}", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
					ConfigRange<int> multiMutatorMoonRange = new ConfigRange<int>(CreateMoonRange(config, i, min: true), CreateMoonRange(config, i, min: false));
					_multiMutatorMoonRanges[i] = new MoonSetting(multiMutatorMoonRange, generatedChance);
				}
				RepoMutators.Logger.LogDebug($"Late-bound moon config with {moonCount} moons.");
			}

			internal MoonSetting GetMultiMutatorMoonRange(int moon)
			{
				int key = Math.Clamp(moon, 0, _moonCount);
				return _multiMutatorMoonRanges[key];
			}
		}

		internal sealed class RandomSettings
		{
			private const string ConfigSection = "Multi-Mutators - Random";

			private readonly ConfigEntry<int> _minimumAmount;

			private readonly ConfigEntry<int> _maximumAmount;

			private readonly IDictionary<byte, ConfigEntry<int>> _weight = new Dictionary<byte, ConfigEntry<int>>(MaximumGeneratedActiveSubMutators);

			private readonly IDictionary<byte, ConfigEntry<int>> _generatedChance = new Dictionary<byte, ConfigEntry<int>>(MaximumGeneratedActiveSubMutators);

			internal int MinimumAmount => _minimumAmount.Value;

			internal int MaximumAmount => _maximumAmount.Value;

			internal RandomSettings(ConfigFile config)
			{
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Expected O, but got Unknown
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: Expected O, but got Unknown
				//IL_00de: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e8: Expected O, but got Unknown
				//IL_012d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0137: Expected O, but got Unknown
				_minimumAmount = config.Bind<int>("Multi-Mutators - Random", "Minimum amount of Mutators", 1, new ConfigDescription("The minimum amount of Mutators that can be selected when using random scaling.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, (int)MaximumGeneratedActiveSubMutators), Array.Empty<object>()));
				_maximumAmount = config.Bind<int>("Multi-Mutators - Random", "Maximum amount of Mutators", 4, new ConfigDescription("The maximum amount of Mutators that can be selected when using random scaling.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, (int)MaximumGeneratedActiveSubMutators), Array.Empty<object>()));
				for (byte b = 1; b <= MaximumGeneratedActiveSubMutators; b++)
				{
					_weight[b] = config.Bind<int>("Multi-Mutators - Random", $"{b} Mutators - Weight", 50, new ConfigDescription(string.Format("The weighted chance for {0} {1} to be selected when using random scaling.", b, (b == 1) ? "Mutator" : "Mutators"), (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
					if (b > 1)
					{
						_generatedChance[b] = config.Bind<int>("Multi-Mutators - Random", $"{b} Mutators - Generated Multi-Mutator Chance (%)", 50, new ConfigDescription($"The chance that a Generated Multi-Mutator will occur when picking {b} Mutators.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
					}
				}
			}

			internal int GetWeight(int amountOfMutators)
			{
				if (amountOfMutators < 0 || amountOfMutators > MaximumGeneratedActiveSubMutators)
				{
					throw new ArgumentException($"Amount of Mutators should be between 0 and {MaximumGeneratedActiveSubMutators}", "amountOfMutators");
				}
				return _weight[(byte)amountOfMutators].Value;
			}

			internal int GetGeneratedChance(int amountOfMutators)
			{
				if (amountOfMutators < 2)
				{
					return 0;
				}
				if (amountOfMutators <= MaximumGeneratedActiveSubMutators)
				{
					return _generatedChance[(byte)amountOfMutators].Value;
				}
				throw new ArgumentException($"Amount of Mutators should not be greater than {MaximumGeneratedActiveSubMutators}", "amountOfMutators");
			}
		}

		internal static readonly byte MaximumGeneratedActiveSubMutators = 10;

		private readonly ConfigEntry<bool> _extendedLogging;

		private readonly ConfigEntry<float> _mutatorDisplayY;

		private readonly ConfigEntry<float> _mutatorDisplaySize;

		private readonly ConfigEntry<string> _mutatorDisplayToggleKey;

		private readonly ConfigEntry<string> _mutatorDisplayToggleType;

		private readonly ConfigEntry<float> _mutatorDescriptionDisplayY;

		private readonly ConfigEntry<float> _mutatorDescriptionDisplaySize;

		private readonly ConfigEntry<float> _mutatorDescriptionInitialDisplayTime;

		private readonly ConfigEntry<bool> _mutatorDescriptionPinned;

		private readonly ConfigEntry<bool> _mutatorDescriptionInMapTool;

		private readonly ConfigEntry<float> _targetDisplaySize;

		private readonly ConfigEntry<float> _specialActionY;

		private readonly ConfigEntry<string> _specialActionKey;

		private readonly ConfigEntry<string> _multiMutatorSelectionMode;

		public RandomSettings RandomMutatorSettings { get; }

		public MoonSettings MoonMutatorSettings { get; }

		public bool ExtendedLogging => _extendedLogging.Value;

		public float MutatorDisplayY => _mutatorDisplayY.Value;

		public float MutatorDisplaySize => _mutatorDisplaySize.Value;

		public KeyCode MutatorDisplayToggleKey { get; private set; }

		public MutatorNameToggleType MutatorDisplayToggleType { get; private set; }

		public float MutatorDescriptionDisplayY => _mutatorDescriptionDisplayY.Value;

		public float MutatorDescriptionDisplaySize => _mutatorDescriptionDisplaySize.Value;

		public float MutatorDescriptionInitialDisplayTime => _mutatorDescriptionInitialDisplayTime.Value;

		public bool MutatorDescriptionPinned => _mutatorDescriptionPinned.Value;

		public bool MutatorDescriptionInMapTool => _mutatorDescriptionInMapTool.Value;

		public float TargetDisplaySize => _targetDisplaySize.Value;

		public float SpecialActionY => _specialActionY.Value;

		public KeyCode SpecialActionKey { get; private set; }

		public MultiMutatorScalingType MutatorScalingType { get; private set; }

		internal ModSettings(ConfigFile config)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Expected O, but got Unknown
			_extendedLogging = config.Bind<bool>("Logging", "Extended Logging", false, "Enable extended logging.");
			_mutatorDisplayY = config.Bind<float>("Mutator Interface", "Y position", -75f, "The Y position of the active Mutator overlay");
			_mutatorDisplaySize = config.Bind<float>("Mutator Interface", "Size", 30f, "The size of the active Mutator overlay");
			_mutatorDisplayToggleType = config.Bind<string>("Mutator Interface", "Mutator display toggle type", "Keybind", new ConfigDescription("The method used to toggle the active Mutator overlay", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Keybind", "With Description" }), Array.Empty<object>()));
			_mutatorDisplayToggleKey = config.Bind<string>("Mutator Interface", "Mutator display toggle key", "H", "The key use to toggle the active Mutator overlay");
			_mutatorDescriptionDisplayY = config.Bind<float>("Mutator Interface", "Description Y position", -110f, "The Y position of the active Mutator's description overlay");
			_mutatorDescriptionDisplaySize = config.Bind<float>("Mutator Interface", "Description size", 20f, "The size of the active Mutator's description overlay");
			_mutatorDescriptionInitialDisplayTime = config.Bind<float>("Mutator Interface", "Description initial display time", 8f, "The time for which the mutator's description is on screen when starting the level");
			_mutatorDescriptionPinned = config.Bind<bool>("Mutator Interface", "Description always active", false, "If true, \"Description initial display time\" will be ignored and the description will always stay on screen");
			_mutatorDescriptionInMapTool = config.Bind<bool>("Mutator Interface", "Description active in map tool", true, "If true, the mutator's description will be displayed when opening the map tool");
			_targetDisplaySize = config.Bind<float>("Mutator Interface", "Target Size", 40f, "The size of the target (e.g. president health) overlay");
			_specialActionY = config.Bind<float>("Special Action", "Special Action Y position", -50f, "The Y position of the Special Action overlay");
			_specialActionKey = config.Bind<string>("Special Action", "Special Action Key", "R", "Keybind that activates the Special Action");
			_multiMutatorSelectionMode = config.Bind<string>("Multi-Mutators", "Scaling Mode", "Moon", new ConfigDescription("The method used to scale the amount of mutators. None = No scaling, Random = Random scaling, Moon = Scaling based on moon", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "None", "Random", "Moon" }), Array.Empty<object>()));
			RandomMutatorSettings = new RandomSettings(config);
			MoonMutatorSettings = new MoonSettings();
			CacheKeys();
			config.SettingChanged += delegate
			{
				CacheKeys();
			};
		}

		internal void LateBindMoonConfig(ConfigFile config, int moonCount)
		{
			MoonMutatorSettings.LateBindMoonConfig(config, moonCount);
		}

		internal void CacheKeys()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			MutatorDisplayToggleKey = (KeyCode)(Enum.TryParse(typeof(KeyCode), _mutatorDisplayToggleKey.Value, out object result) ? ((int)(KeyCode)result) : 0);
			MutatorDisplayToggleType = (Enum.TryParse(typeof(MutatorNameToggleType), _mutatorDisplayToggleType.Value.Replace(" ", ""), out object result2) ? ((MutatorNameToggleType)result2) : MutatorNameToggleType.Keybind);
			SpecialActionKey = (KeyCode)(Enum.TryParse(typeof(KeyCode), _specialActionKey.Value, out object result3) ? ((int)(KeyCode)result3) : 0);
			MutatorScalingType = (Enum.TryParse(typeof(MultiMutatorScalingType), _multiMutatorSelectionMode.Value, out object result4) ? ((MultiMutatorScalingType)result4) : MultiMutatorScalingType.None);
		}

		private static ConfigEntry<int> CreateMoonRange(ConfigFile config, int moon, bool min)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			return config.Bind<int>(GetMoonSection(moon), min ? "Minimum Mutators" : "Maximum Mutators", GetMoonDefaultValue(moon, min), new ConfigDescription(string.Format("The {0} amount of mutators that can be selected for moon {1}", min ? "minimum" : "maximum", moon), (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, (int)MaximumGeneratedActiveSubMutators), Array.Empty<object>()));
		}

		private static int GetMoonDefaultValue(int moon, bool min)
		{
			if (!min)
			{
				return Math.Min(4, moon + 1);
			}
			return Math.Max(moon, 1);
		}

		private static string GetMoonSection(int moon)
		{
			return "Multi-Mutators - " + ((moon == 0) ? "No Moon" : $"Moon {moon}");
		}
	}
	internal class MultiMutatorSettings : AbstractMutatorSettings
	{
		public override int Weight { get; }

		public override int MinimumLevel { get; }

		public override int MaximumLevel { get; }

		public MultiMutatorSettings(string @namespace, string name, string description, int weight = 0, int minimumLevel = 0, int maximumLevel = 1000)
			: base(@namespace, name, description)
		{
			Weight = weight;
			MinimumLevel = minimumLevel;
			MaximumLevel = maximumLevel;
		}
	}
	public static class MutatorSettings
	{
		public static NopMutatorSettings NopMutator { get; private set; }

		public static ApolloElevenMutatorSettings ApolloEleven { get; private set; }

		public static OutWithABangMutatorSettings OutWithABang { get; private set; }

		public static DuckThisMutatorSettings DuckThis { get; private set; }

		public static UltraViolenceMutatorSettings UltraViolence { get; private set; }

		public static ProtectThePresidentMutatorSettings ProtectThePresident { get; private set; }

		public static OneShotOneKillMutatorSettings OneShotOneKill { get; private set; }

		public static GenericMutatorSettings RustyServos { get; private set; }

		public static HandleWithCareMutatorSettings HandleWithCare { get; private set; }

		public static EnemyDisablingMutatorSettings HuntingSeason { get; private set; }

		public static ThereCanOnlyBeOneMutatorSettings ThereCanOnlyBeOne { get; private set; }

		public static GenericMutatorSettings VolatileCargo { get; private set; }

		public static SealedAwayMutatorSettings SealedAway { get; private set; }

		public static GenericMutatorSettings ProtectTheWeak { get; private set; }

		public static FiringMyLaserMutatorSettings FiringMyLaser { get; private set; }

		public static VoiceoverMutatorSettings Voiceover { get; private set; }

		public static TheFloorIsLavaMutatorSettings TheFloorIsLava { get; private set; }

		public static LessIsMoreMutatorSettings LessIsMore { get; private set; }

		public static AmalgamMutatorSettings Amalgam { get; private set; }

		public static GenericMutatorSettings NullSignal { get; private set; }

		public static SizeMattersMutatorSettings SizeMatters { get; private set; }

		internal static void Initialize(ConfigFile config)
		{
			NopMutator = new NopMutatorSettings(config);
			ApolloEleven = new ApolloElevenMutatorSettings("Apollo 11", "Level-wide Zero-Gravity", config);
			OutWithABang = new OutWithABangMutatorSettings("Out With a Bang!", "Monsters explode on death", config);
			DuckThis = new DuckThisMutatorSettings("Duck This", "Ducks aggro on sight instead of on interaction\nAlways spawn at least 1 duck", config);
			UltraViolence = new UltraViolenceMutatorSettings("Ultra-Violence", "Immediately activates the final extraction phase", config);
			ProtectThePresident = new ProtectThePresidentMutatorSettings("Protect the President", "A random player becomes the \"President\"\nIf they die, everyone else self-destructs", config);
			OneShotOneKill = new OneShotOneKillMutatorSettings("One Shot, One Kill", "Any damage taken by a player is lethal", config);
			RustyServos = new GenericMutatorSettings("Xepos.REPO-Mutators", "Rusty Servos", "Players cannot jump\n+3 Grab Range", config);
			HandleWithCare = new HandleWithCareMutatorSettings("Handle With Care", "Valuables are worth more but break on any impact", config);
			HuntingSeason = new EnemyDisablingMutatorSettings("Xepos.REPO-Mutators", "Hunting Season", "No valuables spawn, weapons spawn instead\nEnemy respawn time reduced to 10 seconds", config, "Voodoo", "Weeping Angel");
			ThereCanOnlyBeOne = new ThereCanOnlyBeOneMutatorSettings("There Can Only Be One", "All monster spawns are of the same type", config);
			VolatileCargo = new GenericMutatorSettings("Xepos.REPO-Mutators", "Volatile Cargo", "Valuables explode on destruction\nExplosion radius and strength based on value", config);
			SealedAway = new SealedAwayMutatorSettings("Sealed Away", "Breaking valuables has a chance to spawn monsters", config);
			ProtectTheWeak = new ProtectTheWeakMutatorSettings("Protect the Weak", "Protect your weaker friends!", config);
			FiringMyLaser = new FiringMyLaserMutatorSettings("Firing My Laser", "Fire your laser by pressing {specialActionKey}\nUncontrollably fire your laser when taking damage", config);
			Voiceover = new VoiceoverMutatorSettings("Voiceover", "Player voices are shuffled", config);
			TheFloorIsLava = new TheFloorIsLavaMutatorSettings("The Floor Is Lava", "You take damage while standing on the floor", config);
			LessIsMore = new LessIsMoreMutatorSettings("Less Is More", "Valuables are worth less but gain value when hit\nNormal breaking mechanics apply", config);
			Amalgam = new AmalgamMutatorSettings("Amalgam", "You’ve been here before — just not all at once", config);
			NullSignal = new GenericMutatorSettings("Xepos.REPO-Mutators", "Null Signal", "Active Mutator information is hidden", config);
			SizeMatters = new SizeMattersMutatorSettings("Size Matters", "All players are shrunk", config);
		}
	}
}
namespace Mutators.Settings.Specific
{
	public class AmalgamMutatorSettings : GenericMutatorSettings, ILevelRemovingMutatorSettings
	{
		public const string ExcludedLevelsKey = "excluded-levels";

		private readonly ConfigEntry<string> _excludedLevels;

		private IList<string> _excludedLevelsList;

		public bool AllowCustomLevels => true;

		public IList<string> ExcludedLevels => GetExcludedLevelsWithDefault(GetRuntimeOverrideList("excluded-levels", _excludedLevelsList));

		internal AmalgamMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			_excludedLevels = config.Bind<string>(GenericMutatorSettings.GetSection(name), "Excluded levels", "", "Levels that should be excluded from the " + name + " Mutator. These can neither be picked as a base, nor will their rooms be used in the level generation");
			_excludedLevelsList = ExcludedLevelsAsList();
			_excludedLevels.SettingChanged += SettingChanged;
		}

		private void SettingChanged(object sender, EventArgs e)
		{
			_excludedLevelsList = ExcludedLevelsAsList();
		}

		private IList<string> ExcludedLevelsAsList()
		{
			return (from value in _excludedLevels.Value.Split(",")
				select value.Trim()).ToList();
		}

		private static IList<string> GetExcludedLevelsWithDefault(IList<string> excluded)
		{
			IList<string> list = excluded.ToList();
			if (!list.Contains("Backrooms"))
			{
				list.Add("Backrooms");
			}
			if (!list.Contains("PeachCastle"))
			{
				list.Add("PeachCastle");
			}
			return list;
		}
	}
	public class ApolloElevenMutatorSettings : GenericMutatorSettings
	{
		public const string ApplyToEnemiesKey = "apply-to-enemies";

		public const string ApplyInCartKey = "apply-in-cart";

		private readonly ConfigEntry<bool> _applyToEnemies;

		private readonly ConfigEntry<bool> _applyInCart;

		private readonly ConfigEntry<string> _downwardsKey;

		public bool ApplyToEnemies => GetRuntimeOverride("apply-to-enemies", _applyToEnemies.Value);

		public bool ApplyInCart => GetRuntimeOverride("apply-in-cart", _applyInCart.Value);

		public KeyCode DownwardsKey { get; private set; }

		internal ApolloElevenMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			_applyToEnemies = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Apply to monsters", false, "If true, Zero-Gravity will also be applied to monsters while the " + name + " Mutator is active.");
			_applyInCart = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Apply in cart/extraction", true, "If true, Zero-Gravity will also apply to valuables in the cart and extraction points.");
			_downwardsKey = config.Bind<string>(GenericMutatorSettings.GetSection(name), "Downwards momentum keybind", "LeftControl", "(Client sided) If bound, this key can be used to control yourself downwards while the " + name + " Mutator is active");
			CacheKey();
		}

		internal void CacheKey()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (Enum.TryParse(typeof(KeyCode), _downwardsKey.Value, out object result))
			{
				DownwardsKey = (KeyCode)result;
			}
			else
			{
				DownwardsKey = (KeyCode)0;
			}
		}
	}
	public class DuckThisMutatorSettings : GenericMutatorSettings
	{
		public const string AggroCooldownKey = "aggro-cooldown";

		private readonly ConfigEntry<float> _duckAggroCooldown;

		public float AggroCooldown => GetClampedRuntimeOverride<float>("aggro-cooldown", _duckAggroCooldown);

		internal DuckThisMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			_duckAggroCooldown = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Duck aggro cooldown", 50f, new ConfigDescription("The cooldown between duck aggro while the Duck This Mutator is active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f), Array.Empty<object>()));
		}
	}
	public class FiringMyLaserMutatorSettings : GenericMutatorSettings
	{
		public const string LaserActionCooldownKey = "laser-action-cooldown";

		public const string LaserActionEnemyDamageKey = "laser-enemy-damage";

		public const string LaserActionEnabledKey = "laser-action-enabled";

		public const string LaserOnHurtEnabledKey = "laser-on-hurt-enabled";

		private readonly ConfigEntry<int> _laserActionCooldown;

		private readonly ConfigEntry<int> _laserActionEnemyDamage;

		private readonly ConfigEntry<bool> _laserActionEnabled;

		private readonly ConfigEntry<bool> _laserOnHurtEnabled;

		public int LaserActionCooldown => GetClampedRuntimeOverride<int>("laser-action-cooldown", _laserActionCooldown);

		public int LaserActionEnemyDamage => GetClampedRuntimeOverride<int>("laser-enemy-damage", _laserActionEnemyDamage);

		public bool LaserActionEnabled => GetRuntimeOverride("laser-action-enabled", _laserActionEnabled.Value);

		public bool LaserOnHurtEnabled => GetRuntimeOverride("laser-on-hurt-enabled", _laserOnHurtEnabled.Value);

		internal FiringMyLaserMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			_laserActionEnabled = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Allow manual laser action", true, "If true, players can manually use their laser action while the cooldown is over. Otherwise, only use the laser when getting hit");
			_laserOnHurtEnabled = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Fire laser on hurt", true, "If true, players will automatically fire their laser when getting hurt.");
			_laserActionCooldown = config.Bind<int>(GenericMutatorSettings.GetSection(name), "Laser action cooldown", 60, new ConfigDescription("The amount of seconds before the laser special action can be used again.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 10000), Array.Empty<object>()));
			_laserActionEnemyDamage = config.Bind<int>(GenericMutatorSettings.GetSection(name), "Laser action enemy damage", 30, new ConfigDescription("The amount of damage the laser special action deals to enemies per tick.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 200), Array.Empty<object>()));
		}

		protected override IDictionary<string, object> CreateMetadata()
		{
			return new Dictionary<string, object>
			{
				{ "laser-action-enabled", LaserActionEnabled },
				{ "laser-on-hurt-enabled", LaserOnHurtEnabled }
			};
		}
	}
	public class HandleWithCareMutatorSettings : GenericMutatorSettings
	{
		public const string ValueMultiplierKey = "value-multiplier";

		public const string InstantlyDestroySurplusKey = "instantly-destroy-surplus";

		public const string MultiplySurplusValueKey = "multiply-surplus-value";

		private readonly ConfigEntry<float> _valueMultiplier;

		private readonly ConfigEntry<bool> _instaDestroySurplus;

		private readonly ConfigEntry<bool> _multiplySurplus;

		public float ValueMultiplier => GetClampedRuntimeOverride<float>("value-multiplier", _valueMultiplier);

		public bool InstantlyDestroySurplus => GetClampedRuntimeOverride<bool>("instantly-destroy-surplus", _instaDestroySurplus);

		public bool MultiplySurplusValue => GetClampedRuntimeOverride<bool>("multiply-surplus-value", _multiplySurplus);

		internal HandleWithCareMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			_valueMultiplier = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Value Multiplier", 2f, new ConfigDescription("The amount by which the value of valuables should be multiplier when " + name + " is active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			_instaDestroySurplus = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Instantly Destroy Surplus on Damage", false, "If true, while the " + name + " Mutator is active, the surplus will instantly be destroyed when taking any damage, just like other valuables.");
			_multiplySurplus = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Multiply Surplus Value", false, "If true, while the " + name + " Mutator is active, the surplus value will be multiplied, just like other valuables.");
		}
	}
	public class LessIsMoreMutatorSettings : GenericMutatorSettings
	{
		public const string StrongDivisionFactorKey = "strong-division-factor";

		public const string WeakDivisionFactorKey = "weak-division-factor";

		private readonly ConfigEntry<float> _strongDivisionFactor;

		private readonly ConfigEntry<float> _weakDivisionFactor;

		private readonly ConfigEntry<float> _valueGainMultiplier;

		public float StrongDivisionFactor => GetClampedRuntimeOverride<float>("strong-division-factor", _strongDivisionFactor);

		public float WeakDivisionFactor => GetClampedRuntimeOverride<float>("weak-division-factor", _weakDivisionFactor);

		public float ValueGainMultiplier => _valueGainMultiplier.Value;

		internal LessIsMoreMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			_weakDivisionFactor = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Weak Durability Division Factor", 1f, new ConfigDescription("The amount by which the value of weak durability valuables should be divided when the " + name + " Mutator is active. Acts as an lower bound.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
			_strongDivisionFactor = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Strong Durability Division Factor", 2f, new ConfigDescription("The amount by which the value of strong durability valuables should be divided when the " + name + " Mutator is active. Acts as a upper bound.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
			_valueGainMultiplier = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Value Gain Multiplier", 2f, new ConfigDescription("The amount by which the normal value gain should be multiplied when the " + name + " Mutator is active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
		}

		protected override IDictionary<string, object>? CreateMetadata()
		{
			return new Dictionary<string, object> { { "value-gain-multiplier", ValueGainMultiplier } };
		}
	}
	public sealed class NopMutatorSettings : AbstractMutatorSettings
	{
		private readonly ConfigEntry<int> _weight;

		private readonly ConfigEntry<int> _minimumLevel;

		private readonly ConfigEntry<int> _maximumLevel;

		public override int Weight => _weight.Value;

		public override int MinimumLevel => _minimumLevel.Value;

		public override int MaximumLevel => _maximumLevel.Value;

		internal NopMutatorSettings(ConfigFile config)
			: base("Xepos.REPO-Mutators", "None", "A normal run, no special effects")
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			_weight = config.Bind<int>("No Mutator", "Chance (%)", 50, new ConfigDescription("Percentage chance for no mutator to be active. Unlike other mutators, this one is not weighted", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			_minimumLevel = config.BindPositive("No Mutator", "Minimum level", 0, "The minimum level on which no mutator can show up");
			_maximumLevel = config.BindPositive("No Mutator", "Maximum level", 1000, "The maximum level on which no mutator can show up (0 = no upper bound)");
		}
	}
	public class OneShotOneKillMutatorSettings : EnemyDisablingMutatorSettings
	{
		public const string InstaReviveInTruckOrExtractionKey = "revive-in-truck-or-extraction";

		public const string InstaReviveHealthKey = "revive-health";

		private readonly ConfigEntry<bool> _instaReviveInTruckOrExtraction;

		private readonly ConfigEntry<int> _instaReviveHealth;

		public bool InstaReviveInTruckOrExtraction => GetRuntimeOverride("revive-in-truck-or-extraction", _instaReviveInTruckOrExtraction.Value);

		public int InstaReviveHealth => GetClampedRuntimeOverride<int>("revive-health", _instaReviveHealth);

		internal OneShotOneKillMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config, "Peeper")
		{
			_instaReviveInTruckOrExtraction = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Instant revive in truck or extraction", false, "If true, while the " + name + " Mutator is active, players are instantly revived with full head if their head is brought to the truck or an active extraction point.");
			_instaReviveHealth = config.BindPositive(GenericMutatorSettings.GetSection(name), "Instant revive health", 0, "The amount of health the player should be revived with when Instant revive is enabled. (0 = Revive with max health)");
		}
	}
	public class OutWithABangMutatorSettings : GenericMutatorSettings
	{
		public const string Tier1Radius = "tier-1-enemy-explosion-radius";

		public const string Tier1Damage = "tier-1-enemy-explosion-damage";

		public const string Tier2Radius = "tier-2-enemy-explosion-radius";

		public const string Tier2Damage = "tier-2-enemy-explosion-damage";

		public const string Tier3Radius = "tier-3-enemy-explosion-radius";

		public const string Tier3Damage = "tier-3-enemy-explosion-damage";

		private readonly ConfigEntry<float> _tier1ExplosionRadius;

		private readonly ConfigEntry<int> _tier1ExplosionDamage;

		private readonly ConfigEntry<float> _tier2ExplosionRadius;

		private readonly ConfigEntry<int> _tier2ExplosionDamage;

		private readonly ConfigEntry<float> _tier3ExplosionRadius;

		private readonly ConfigEntry<int> _tier3ExplosionDamage;

		public float Tier1ExplosionRadius => _tier1ExplosionRadius.Value;

		public int Tier1ExplosionDamage => _tier1ExplosionDamage.Value;

		public float Tier2ExplosionRadius => _tier2ExplosionRadius.Value;

		public int Tier2ExplosionDamage => _tier2ExplosionDamage.Value;

		public float Tier3ExplosionRadius => _tier3ExplosionRadius.Value;

		public int Tier3ExplosionDamage => _tier3ExplosionDamage.Value;

		internal OutWithABangMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			_tier1ExplosionRadius = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Tier 1 Enemy Explosion Radius", 1f, "The on-death explosion radius of Tier 1 enemies during the " + name + " Mutator.");
			_tier1ExplosionDamage = config.BindPositive(GenericMutatorSettings.GetSection(name), "Tier 1 Enemy Explosion Damage", 50, "The on-death explosion damage of Tier 1 enemies during the " + name + " Mutator.");
			_tier2ExplosionRadius = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Tier 2 Enemy Explosion Radius", 2f, "The on-death explosion radius of Tier 2 enemies during the " + name + " Mutator.");
			_tier2ExplosionDamage = config.BindPositive(GenericMutatorSettings.GetSection(name), "Tier 2 Enemy Explosion Damage", 100, "The on-death explosion damage of Tier 2 enemies during the " + name + " Mutator.");
			_tier3ExplosionRadius = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Tier 3 Enemy Explosion Radius", 3f, "The on-death explosion radius of Tier 3 enemies during the " + name + " Mutator.");
			_tier3ExplosionDamage = config.BindPositive(GenericMutatorSettings.GetSection(name), "Tier 3 Enemy Explosion Damage", 200, "The on-death explosion damage of Tier 3 enemies during the " + name + " Mutator.");
		}

		protected override IDictionary<string, object>? CreateMetadata()
		{
			return new Dictionary<string, object>
			{
				{ "tier-1-enemy-explosion-radius", Tier1ExplosionRadius },
				{ "tier-1-enemy-explosion-damage", Tier1ExplosionDamage },
				{ "tier-2-enemy-explosion-radius", Tier2ExplosionRadius },
				{ "tier-2-enemy-explosion-damage", Tier2ExplosionDamage },
				{ "tier-3-enemy-explosion-radius", Tier3ExplosionRadius },
				{ "tier-3-enemy-explosion-damage", Tier3ExplosionDamage }
			};
		}
	}
	public class ProtectThePresidentMutatorSettings : GenericMutatorSettings
	{
		private readonly ConfigEntry<int> _minimumPlayerCount;

		public byte MinimumPlayerCount => (byte)_minimumPlayerCount.Value;

		internal ProtectThePresidentMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			_minimumPlayerCount = config.Bind<int>(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", 3, new ConfigDescription("The minimum amount of players required for the " + name + " Mutator to be available for selection.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
		}

		public override bool IsEligibleForSelection()
		{
			if (base.IsEligibleForSelection())
			{
				Room currentRoom = PhotonNetwork.CurrentRoom;
				if (currentRoom != null)
				{
					return currentRoom.PlayerCount >= MinimumPlayerCount;
				}
				return false;
			}
			return false;
		}
	}
	public class ProtectTheWeakMutatorSettings : GenericMutatorSettings
	{
		private readonly ConfigEntry<int> _minimumPlayerCount;

		public byte MinimumPlayerCount => (byte)_minimumPlayerCount.Value;

		internal ProtectTheWeakMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			_minimumPlayerCount = config.Bind<int>(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", 3, new ConfigDescription("The minimum amount of players required for the " + name + " Mutator to be available for selection.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
		}

		public override bool IsEligibleForSelection()
		{
			if (base.IsEligibleForSelection())
			{
				Room currentRoom = PhotonNetwork.CurrentRoom;
				if (currentRoom != null)
				{
					return currentRoom.PlayerCount >= MinimumPlayerCount;
				}
				return false;
			}
			return false;
		}
	}
	public class SealedAwayMutatorSettings : EnemyDisablingMutatorSettings
	{
		public const string MaximumMonsterSpawnsKey = "maximum-monster-spawns";

		public const string MonsterSpawnChanceKey = "monster-spawn-chance";

		private readonly ConfigEntry<int> _maximumMonsterSpawns;

		private readonly ConfigEntry<float> _monsterSpawnChance;

		public int MaximumMonsterSpawns => GetClampedRuntimeOverride<int>("maximum-monster-spawns", _maximumMonsterSpawns);

		public float MonsterSpawnChance => GetClampedRuntimeOverride<float>("monster-spawn-chance", _monsterSpawnChance);

		internal SealedAwayMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config, "Voodoo", "Shadow Child")
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			_maximumMonsterSpawns = config.Bind<int>(GenericMutatorSettings.GetSection(name), "Maximum monster spawns", 5, new ConfigDescription("Maximum amount of extra monsters that can be spawned by the " + name + " Mutator per level.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 15), Array.Empty<object>()));
			_monsterSpawnChance = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Monster spawn chance", 65f, new ConfigDescription("The chance that a monster is spawned when breaking a valuable when the " + name + " Mutator is active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
		}
	}
	public class SizeMattersMutatorSettings : GenericMutatorSettings
	{
		public const string ScaleValuablesKey = "scale-valuables";

		public const string ScaleEnemiesKey = "scale-enemies";

		public const string ScaleCartsKey = "scale-carts";

		private readonly ConfigEntry<bool> _scaleValuables;

		private readonly ConfigEntry<bool> _scaleEnemies;

		private readonly ConfigEntry<bool> _scaleCart;

		public bool ScaleValuables => GetRuntimeOverride("scale-valuables", _scaleValuables.Value);

		public bool ScaleEnemies => GetRuntimeOverride("scale-enemies", _scaleEnemies.Value);

		public bool ScaleCarts => GetRuntimeOverride("scale-carts", _scaleCart.Value);

		internal SizeMattersMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			_scaleValuables = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Scale valuables", false, "If true, valuables will also be scaled.");
			_scaleEnemies = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Scale enemies", false, "If true, enemies will also be scaled.");
			_scaleCart = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Scale carts", false, "If true, carts will also be scaled.");
		}

		protected override IDictionary<string, object> CreateMetadata()
		{
			return new Dictionary<string, object>
			{
				{ "scale-valuables", ScaleValuables },
				{ "scale-enemies", ScaleEnemies },
				{ "scale-carts", ScaleCarts }
			};
		}
	}
	public class TheFloorIsLavaMutatorSettings : GenericMutatorSettings, ILevelRemovingMutatorSettings
	{
		public const string ImmunePlayerCountKey = "immune-player-amount";

		public const string AllowCustomLevelsKey = "allow-custom-levels";

		public const string DisableEnemiesKey = "disable-enemies";

		private readonly ConfigEntry<int> _immunePlayerCount;

		private readonly ConfigEntry<bool> _usePercentageDamage;

		private readonly ConfigEntry<bool> _allowCustomLevels;

		private readonly ConfigEntry<bool> _disableEnemies;

		private readonly ConfigEntry<float> _reviveImmunityDuration;

		public int DamagePerTick { get; private set; }

		public int ImmunePlayerCount => GetClampedRuntimeOverride<int>("immune-player-amount", _immunePlayerCount);

		public bool UsePercentageDamage => _usePercentageDamage.Value;

		public bool AllowCustomLevels => GetRuntimeOverride("allow-custom-levels", _allowCustomLevels.Value);

		public bool DisableEnemies => GetRuntimeOverride("disable-enemies", _disableEnemies.Value);

		public float ReviveImmunityDuration => _reviveImmunityDuration.Value;

		public IList<string> ExcludedLevels => new List<string>();

		internal TheFloorIsLavaMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, 0, config)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			ConfigEntry<int> val = config.BindPositive(GenericMutatorSettings.GetSection(name), "Damage", 1, "The amount of damage that players receive per second when standing on floor tiles.");
			_usePercentageDamage = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Use percentage damage", false, "If true, players will receive percentage max health damage instead of a flat amount.");
			_immunePlayerCount = config.Bind<int>(GenericMutatorSettings.GetSection(name), "Immune player count", 0, new ConfigDescription("The amount of players that are immune to " + name + " damage.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
			_allowCustomLevels = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Allow custom levels", true, "If false, custom levels cannot be picked while the " + name + " Mutator is active.");
			_disableEnemies = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Disable enemies", false, "If true, no enemies will spawn while the " + name + " Mutator is active.");
			_reviveImmunityDuration = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Revive immunity duration", 20f, "The time in seconds for which players are immune to lava damage after reviving while the " + name + " Mutator is active.");
			DamagePerTick = Math.Clamp(val.Value, 1, int.MaxValue);
		}

		protected override IDictionary<string, object>? CreateMetadata()
		{
			return new Dictionary<string, object>
			{
				{ "damage", DamagePerTick },
				{ "is-percentage-damage", UsePercentageDamage },
				{ "revive-immunity-duration", ReviveImmunityDuration }
			};
		}
	}
	public class ThereCanOnlyBeOneMutatorSettings : EnemyDisablingMutatorSettings
	{
		public const string GroupSpawnsThresholdKey = "group-spawns-threshold";

		private readonly ConfigEntry<int> _groupSpawnsThreshold;

		public int GroupSpawnsThreshold => GetClampedRuntimeOverride<int>("group-spawns-threshold", _groupSpawnsThreshold);

		internal ThereCanOnlyBeOneMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			_groupSpawnsThreshold = config.BindPositive(GenericMutatorSettings.GetSection(name), "Group spawn minimum level", 8, "The minimum level from which enemy groups (e.g. 3 mentalists or 10 gnomes) can be spawned by the " + name + " Mutator.");
		}
	}
	public class UltraViolenceMutatorSettings : EnemyDisablingMutatorSettings
	{
		private readonly ConfigEntry<bool> _keepOnLight;

		private readonly ConfigEntry<int> _minimumPlayerCount;

		public bool KeepOnLight => _keepOnLight.Value;

		public byte MinimumPlayerCount => (byte)_minimumPlayerCount.Value;

		internal UltraViolenceMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, 0, config)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			_keepOnLight = config.Bind<bool>(GenericMutatorSettings.GetSection(name), "Keep on lights", false, "Keep on the level lighting while the " + name + " Mutator is active.");
			_minimumPlayerCount = config.Bind<int>(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", 0, new ConfigDescription("The minimum amount of players required for the " + name + " Mutator to be available for selection.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
		}

		public override bool IsEligibleForSelection()
		{
			if (base.IsEligibleForSelection())
			{
				Room currentRoom = PhotonNetwork.CurrentRoom;
				if (currentRoom != null)
				{
					return currentRoom.PlayerCount >= MinimumPlayerCount;
				}
				return false;
			}
			return false;
		}

		protected override IDictionary<string, object>? CreateMetadata()
		{
			return new Dictionary<string, object> { { "keep-lights-on", KeepOnLight } };
		}
	}
	public class VoiceoverMutatorSettings : GenericMutatorSettings
	{
		private readonly ConfigEntry<int> _minimumPlayerCount;

		public byte MinimumPlayerCount => (byte)_minimumPlayerCount.Value;

		internal VoiceoverMutatorSettings(string name, string description, ConfigFile config)
			: base("Xepos.REPO-Mutators", name, description, config)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			_minimumPlayerCount = config.Bind<int>(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", 3, new ConfigDescription("The minimum amount of players required for the " + name + " Mutator to be available for selection.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()));
		}

		public override bool IsEligibleForSelection()
		{
			if (base.IsEligibleForSelection())
			{
				Room currentRoom = PhotonNetwork.CurrentRoom;
				if (currentRoom != null)
				{
					return currentRoom.PlayerCount >= MinimumPlayerCount;
				}
				return false;
			}
			return false;
		}
	}
}
namespace Mutators.Services.Selection
{
	public interface IMutatorSelectionService
	{
		IMutator GetWeightedMutator(ICollection<IMutator> mutators);
	}
	internal interface IRepeatSelectionTracker
	{
		IMutator? PreviousMutator { get; }

		bool ShouldBlockRepeat(IMutator mutator, float probability);

		IMutator TrackSelectedMutator(IMutator mutator);
	}
	public class MutatorSelectionContext(uint amountToPick)
	{
		public uint AmountToPick { get; } = amountToPick;
	}
	public class MutatorSelectionService : IMutatorSelectionService
	{
		private readonly IDictionary<ModSettings.MultiMutatorScalingType, MutatorSelectionStrategy> _selectionStrategies;

		private readonly NopMutator _nopMutator;

		private readonly IRepeatSelectionTracker _repeatSelectionTracker;

		private readonly IRandomProvider _randomProvider;

		internal MutatorSelectionService(NoneScalingSelectionStrategy noneScalingSelectionStrategy, MoonScalingSelectionStrategy moonScalingSelectionStrategy, RandomScalingSelectionStrategy randomScalingSelectionStrategy, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator nopMutator)
		{
			_selectionStrategies = new Dictionary<ModSettings.MultiMutatorScalingType, MutatorSelectionStrategy>
			{
				{
					ModSettings.MultiMutatorScalingType.None,
					noneScalingSelectionStrategy
				},
				{
					ModSettings.MultiMutatorScalingType.Moon,
					moonScalingSelectionStrategy
				},
				{
					ModSettings.MultiMutatorScalingType.Random,
					randomScalingSelectionStrategy
				}
			};
			_repeatSelectionTracker = repeatSelectionTracker;
			_randomProvider = randomProvider;
			_nopMutator = nopMutator;
		}

		public IMutator GetWeightedMutator(ICollection<IMutator> mutators)
		{
			ModSettings.MultiMutatorScalingType mutatorScalingType = RepoMutators.Settings.MutatorScalingType;
			if (ShouldUseNopMutator(_nopMutator))
			{
				return _repeatSelectionTracker.TrackSelectedMutator(_nopMutator);
			}
			IList<IMutator> mutators2 = mutators.Where((IMutator mutator) => !(mutator is NopMutator) && mutator.Settings.Weight > 0).ToList();
			return _selectionStrategies[mutatorScalingType].Execute(mutators2);
		}

		private bool ShouldUseNopMutator(NopMutator nopMutator)
		{
			int weight = nopMutator.Settings.Weight;
			if (weight <= 0)
			{
				return false;
			}
			float probability = (float)weight / 100f;
			if (_repeatSelectionTracker.ShouldBlockRepeat(nopMutator, probability))
			{
				RepoMutators.Logger.LogDebug("Cannot pick " + nopMutator.Name + ", threshold reached");
				return false;
			}
			if (weight < 100)
			{
				return _randomProvider.Range(0f, 100f) <= (float)weight;
			}
			return true;
		}
	}
	internal class RepeatSelectionTracker : IRepeatSelectionTracker
	{
		private int _repeatCount;

		public IMutator? PreviousMutator { get; private set; }

		public bool ShouldBlockRepeat(IMutator mutator, float probability)
		{
			if (mutator == PreviousMutator)
			{
				return MathF.Pow(probability, _repeatCount + 1) < 0.1f;
			}
			return false;
		}

		public IMutator TrackSelectedMutator(IMutator mutator)
		{
			if (mutator == PreviousMutator)
			{
				_repeatCount++;
			}
			else
			{
				PreviousMutator = mutator;
				_repeatCount = 1;
			}
			return mutator;
		}
	}
}
namespace Mutators.Services.Selection.Strategies
{
	internal class MoonScalingSelectionStrategy : MutatorSelectionStrategy
	{
		private readonly ModSettings.MoonSettings _moonSettings;

		private readonly ISemiFuncProvider _semiFuncProvider;

		public MoonScalingSelectionStrategy(GeneratedMultiMutatorSelectionRulesRegistry multiRegistry, SingleMutatorSelectionRulesRegistry singleRegistry, ModSettings.MoonSettings moonSettings, ISemiFuncProvider semiFuncProvider, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator fallbackMutator)
			: base(multiRegistry, singleRegistry, repeatSelectionTracker, randomProvider, fallbackMutator)
		{
			_moonSettings = moonSettings;
			_semiFuncProvider = semiFuncProvider;
		}

		public sealed override IMutator Execute(IList<IMutator> mutators)
		{
			int moonMutatorsAmount = GetMoonMutatorsAmount();
			if (moonMutatorsAmount == 1)
			{
				return GetSingleMutator(mutators);
			}
			if (!ShouldGenerateMulti(GetMoonGeneratedChance()))
			{
				return TryPickUserDefinedMultiMutatorOrElseGenerate(mutators, moonMutatorsAmount);
			}
			return PickGeneratedMultiMutator(mutators, moonMutatorsAmount);
		}

		private int GetMoonMutatorsAmount()
		{
			ModSettings.MoonSetting multiMutatorMoonRange = _moonSettings.GetMultiMutatorMoonRange(_semiFuncProvider.MoonLevel());
			return randomProvider.RandomRangeInt(multiMutatorMoonRange.MinimumMutators, multiMutatorMoonRange.MaximumMutators + 1);
		}

		private int GetMoonGeneratedChance()
		{
			return _moonSettings.GetMultiMutatorMoonRange(_semiFuncProvider.MoonLevel()).GeneratedChance;
		}
	}
	internal abstract class MutatorSelectionStrategy
	{
		private readonly IMutator _fallbackMutator;

		private readonly GeneratedMultiMutatorSelectionRulesRegistry _multiRegistry;

		private readonly SingleMutatorSelectionRulesRegistry _singleRegistry;

		protected readonly IRandomProvider randomProvider;

		private readonly IRepeatSelectionTracker _repeatSelectionTracker;

		internal MutatorSelectionStrategy(GeneratedMultiMutatorSelectionRulesRegistry multiRegistry, SingleMutatorSelectionRulesRegistry singleRegistry, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator nopMutator)
		{
			_multiRegistry = multiRegistry;
			_singleRegistry = singleRegistry;
			_repeatSelectionTracker = repeatSelectionTracker;
			this.randomProvider = randomProvider;
			_fallbackMutator = nopMutator;
		}

		public abstract IMutator Execute(IList<IMutator> mutators);

		protected IMutator PickSingleMutator(IList<IMutator> mutators, MutatorSelectionContext context)
		{
			if (context.AmountToPick == 1)
			{
				mutators = mutators.Where((IMutator m) => _singleRegistry.RunRules(m)).ToList();
			}
			IMutator previousMutator = _repeatSelectionTracker.PreviousMutator;
			float num = mutators.Sum((IMutator item) => item.Settings.Weight);
			if (previousMutator != null && mutators.Contains(previousMutator) && num > 0f)
			{
				float num2 = previousMutator.Settings.Weight;
				if (num2 > 0f && _repeatSelectionTracker.ShouldBlockRepeat(previousMutator, num2 / num))
				{
					RepoMutators.Logger.LogDebug("Cannot pick " + (previousMutator?.Name ?? "None") + ", threshold reached");
					mutators = mutators.Where((IMutator m) => m != previousMutator).ToList();
					num = mutators.Sum((IMutator m) => m.Settings.Weight);
				}
			}
			if (num <= 0f)
			{
				RepoMutators.Logger.LogWarning($"Fell back to None mutator, invalid total weight: {num}");
				return _fallbackMutator;
			}
			float num3 = randomProvider.Range(0f, num);
			float num4 = 0f;
			foreach (IMutator mutator in mutators)
			{
				num4 += (float)mutator.Settings.Weight;
				if (num3 <= num4)
				{
					return _repeatSelectionTracker.TrackSelectedMutator(mutator);
				}
			}
			RepoMutators.Logger.LogWarning("Fell back to None mutator, mutator selection failed");
			return _fallbackMutator;
		}

		protected IMutator PickGeneratedMultiMutator(IList<IMutator> mutators, int amountToPick)
		{
			IList<IMutator> excludeList = new List<IMutator>(1) { _fallbackMutator };
			IList<IMutator> pickedMutators = new List<IMutator>();
			MutatorSelectionContext context = new MutatorSelectionContext((uint)amountToPick);
			IList<IMutator> selection = mutators.GetSelection((IMutator mutator2) => !(mutator2 is IMultiMutator) && !excludeList.Contains(mutator2));
			for (int num = 0; num < amountToPick; num++)
			{
				IList<IMutator> selection2 = selection.GetSelection((IMutator mutator2) => ApplyGenerationRules(pickedMutators, mutator2));
				IMutator mutator = PickSingleMutator(selection2, context);
				if (mutator != _fallbackMutator)
				{
					pickedMutators.Add(mutator);
				}
			}
			if (pickedMutators.Count == 0)
			{
				return _fallbackMutator;
			}
			if (pickedMutators.Count == 1)
			{
				return pickedMutators.First();
			}
			return new MultiMutator(new MultiMutatorSettings("Xepos.REPO-Mutators", string.Empty, string.Empty), ((IEnumerable<IMutator>)pickedMutators).ToDictionary((Func<IMutator, IMutator>)((IMutator m) => m), (Func<IMutator, IDictionary<string, object>>)((IMutator _) => new Dictionary<string, object>())));
		}

		private bool ApplyGenerationRules(IList<IMutator> pickedMutators, IMutator mutator)
		{
			if (pickedMutators.Contains(mutator))
			{
				return false;
			}
			return _multiRegistry.RunRules(new ReadOnlyCollection<IMutator>(pickedMutators), mutator);
		}

		protected bool ShouldGenerateMulti(int generatedChance)
		{
			if (generatedChance <= 0)
			{
				if (generatedChance < 0)
				{
					LogMisconfiguredMultiMutatorChance(generatedChance);
					RepoMutators.Logger.LogWarning("The minimum allowed value is 0.");
				}
				return false;
			}
			if (generatedChance > 100)
			{
				LogMisconfiguredMultiMutatorChance(generatedChance);
				RepoMutators.Logger.LogWarning("The maximum allowed value is 100.");
				return true;
			}
			if (generatedChance != 100)
			{
				return randomProvider.RandomRangeInt(1, 101) <= generatedChance;
			}
			return true;
		}

		protected IMutator GetSingleMutator(IList<IMutator> mutators)
		{
			return PickSingleMutator(mutators.GetSelection(delegate(IMutator mutator)
			{
				if (mutator is IMultiMutator multiMutator)
				{
					IReadOnlyDictionary<IMutator, IDictionary<string, object>> subMutators = multiMutator.SubMutators;
					if (subMutators != null)
					{
						int count = subMutators.Count;
						if (count == 1)
						{
							goto IL_001f;
						}
					}
					return false;
				}
				goto IL_001f;
				IL_001f:
				return true;
			}).ToList(), new MutatorSelectionContext(1u));
		}

		protected IMutator TryPickUserDefinedMultiMutatorOrElseGenerate(IList<IMutator> mutators, int amountOfSubMutators)
		{
			IList<IMutator> list = mutators.GetSelection((IMutator mutator) => mutator is IMultiMutator multiMutator && multiMutator.SubMutators.Count == amountOfSubMutators).ToList();
			if (list.Select((IMutator m) => m.Settings.Weight).Sum() > 0)
			{
				return PickSingleMutator(list, new MutatorSelectionContext(1u));
			}
			RepoMutators.Logger.LogDebug($"No user defined multi-mutator found for {amountOfSubMutators} sub-mutators.");
			return PickGeneratedMultiMutator(mutators, amountOfSubMutators);
		}

		private static void LogMisconfiguredMultiMutatorChance(int generatedChance)
		{
			RepoMutators.Logger.LogWarning($"Generated multi-mutator chance is misconfigured: {generatedChance}.");
		}
	}
	internal class NoneScalingSelectionStrategy : MutatorSelectionStrategy
	{
		public NoneScalingSelectionStrategy(GeneratedMultiMutatorSelectionRulesRegistry multiRegistry, SingleMutatorSelectionRulesRegistry singleRegistry, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator fallbackMutator)
			: base(multiRegistry, singleRegistry, repeatSelectionTracker, randomProvider, fallbackMutator)
		{
		}

		public sealed override IMutator Execute(IList<IMutator> mutators)
		{
			return PickSingleMutator(mutators.GetSelection(delegate(IMutator mutator)
			{
				if (mutator is IMultiMutator multiMutator)
				{
					IReadOnlyDictionary<IMutator, IDictionary<string, object>> subMutators = multiMutator.SubMutators;
					if (subMutators != null)
					{
						int count = subMutators.Count;
						if (count == 1)
						{
							goto IL_001f;
						}
					}
					return false;
				}
				goto IL_001f;
				IL_001f:
				return true;
			}), new MutatorSelectionContext(1u));
		}
	}
	internal class RandomScalingSelectionStrategy : MutatorSelectionStrategy
	{
		private readonly ModSettings.RandomSettings _randomSettings;

		public RandomScalingSelectionStrategy(GeneratedMultiMutatorSelectionRulesRegistry multiRegistry, SingleMutatorSelectionRulesRegistry singleRegistry, ModSettings.RandomSettings randomSettings, IRepeatSelectionTracker repeatSelectionTracker, IRandomProvider randomProvider, NopMutator fallbackMutator)
			: base(multiRegistry, singleRegistry, repeatSelectionTracker, randomProvider, fallbackMutator)
		{
			_randomSettings = randomSettings;
		}

		public sealed override IMutator Execute(IList<IMutator> mutators)
		{
			int randomAmountOfMutatorsBetweenByWeight = GetRandomAmountOfMutatorsBetweenByWeight();
			if (randomAmountOfMutatorsBetweenByWeight == 1)
			{
				return GetSingleMutator(mutators);
			}
			if (!ShouldGenerateMulti(GetRandomGeneratedChance(randomAmountOfMutatorsBetweenByWeight)))
			{
				return TryPickUserDefinedMultiMutatorOrElseGenerate(mutators, randomAmountOfMutatorsBetweenByWeight);
			}
			return PickGeneratedMultiMutator(mutators, randomAmountOfMutatorsBetweenByWeight);
		}

		private int GetRandomGeneratedChance(int amountOfMutators)
		{
			return _randomSettings.GetGeneratedChance(amountOfMutators);
		}

		private int GetRandomAmountOfMutatorsBetweenByWeight()
		{
			int minimumAmount = _randomSettings.MinimumAmount;
			int maximumAmount = _randomSettings.MaximumAmount;
			if (minimumAmount < 1 || minimumAmount > ModSettings.MaximumGeneratedActiveSubMutators)
			{
				throw new ArgumentException($"Minimum amount of Mutators should be between 1 and {ModSettings.MaximumGeneratedActiveSubMutators}", "minimumAmount");
			}
			if (maximumAmount < 1 || maximumAmount > ModSettings.MaximumGeneratedActiveSubMutators)
			{
				throw new ArgumentException($"Maximum amount of Mutators should be between 1 and {ModSettings.MaximumGeneratedActiveSubMutators}", "maximumAmount");
			}
			if (minimumAmount > maximumAmount)
			{
				throw new ArgumentException("Minimum amount of Mutators should not be greater than maximum amount of Mutators.", "minimumAmount");
			}
			int num = 0;
			for (int i = minimumAmount; i <= maximumAmount; i++)
			{
				num += _randomSettings.GetWeight(i);
			}
			if (num <= 0)
			{
				return randomProvider.RandomRangeInt(minimumAmount, maximumAmount + 1);
			}
			int num2 = randomProvider.RandomRangeInt(0, num);
			int num3 = 0;
			for (int j = minimumAmount; j <= maximumAmount; j++)
			{
				num3 += _randomSettings.GetWeight(j);
				if (num2 < num3)
				{
					return j;
				}
			}
			return maximumAmount;
		}
	}
}
namespace Mutators.Rules
{
	public static class MultiMutatorRules
	{
		public static Func<IReadOnlyCollection<string>, string, bool> RequiresAmountOfOtherMutatorsRule(string namespacedName, int amount)
		{
			return (IReadOnlyCollection<string> pickedList, string candidate) => namespacedName != candidate || pickedList.Count >= amount;
		}

		public static Func<IReadOnlyCollection<string>, string, bool> MutualExclusionRule(string firstNamespacedName, string secondNamespacedName)
		{
			return (IReadOnlyCollection<string> pickedList, string candidate) => (!pickedList.Contains(firstNamespacedName) || !string.Equals(candidate, secondNamespacedName, StringComparison.OrdinalIgnoreCase)) && (!pickedList.Contains(secondNamespacedName) || !string.Equals(candidate, firstNamespacedName, StringComparison.OrdinalIgnoreCase));
		}
	}
	public static class MultiMutatorRuleType
	{
		public const string Exclusion = "Exclusion";

		public const string MutualExclusion = "Mutual Exclusion";

		public const string RequiresAmountOfOtherMutators = "Requires Amount Of Other Mutators";
	}
	public static class SingleMutatorRules
	{
		public static Predicate<IMutator> ExclusionRule(string namespacedName)
		{
			return (IMutator mutator) => mutator.NamespacedName != namespacedName;
		}
	}
	public static class SingleMutatorRuleType
	{
		public const string Exclusion = "Exclusion";
	}
}
namespace Mutators.Rules.Registries
{
	public class GeneratedMultiMutatorSelectionRulesRegistry : MutatorSelectionRulesRegistry<Func<IReadOnlyCollection<string>, string, bool>, Func<IReadOnlyCollection<IMutator>, IMutator, bool>>
	{
		internal GeneratedMultiMutatorSelectionRulesRegistry()
		{
		}

		internal bool RunRules(ICollection<IMutator> pickedMutators, IMutator mutator)
		{
			ReadOnlyCollection<string> pickedMutatorNamesReadOnly = pickedMutators.Select((IMutator m) => m.NamespacedName).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList()
				.AsReadOnly();
			IReadOnlyCollection<IMutator> pickedMutatorsReadonly = new ReadOnlyCollection<IMutator>(pickedMutators.ToList());
			if (mutatorSelectionRulesExtended.Values.All((Func<IReadOnlyCollection<IMutator>, IMutator, bool> rule) => rule(pickedMutatorsReadonly, mutator)))
			{
				return mutatorSelectionRules.Values.All((Func<IReadOnlyCollection<string>, string, bool> rule) => rule(pickedMutatorNamesReadOnly, mutator.NamespacedName));
			}
			return false;
		}
	}
	public abstract class MutatorSelectionRulesRegistry<T, TE>
	{
		protected readonly IDictionary<string, T> mutatorSelectionRules = new Dictionary<string, T>();

		protected readonly IDictionary<string, TE> mutatorSelectionRulesExtended = new Dictionary<string, TE>();

		public void Register(string key, T rule)
		{
			ValidateAndThen(key, delegate
			{
				mutatorSelectionRules.Add(key, rule);
			});
		}

		public void Register(string key, TE rule)
		{
			ValidateAndThen(key, delegate
			{
				mutatorSelectionRulesExtended.Add(key, rule);
			});
		}

		public bool Unregister(string key)
		{
			if (!mutatorSelectionRules.Remove(key))
			{
				return mutatorSelectionRulesExtended.Remove(key);
			}
			return true;
		}

		public bool IsRuleRegistered(string key)
		{
			if (!mutatorSelectionRules.ContainsKey(key))
			{
				return mutatorSelectionRulesExtended.ContainsKey(key);
			}
			return true;
		}

		private void ValidateAndThen(string key, Action action)
		{
			if (IsRuleRegistered(key))
			{
				throw new InvalidOperationException("Rule with key " + key + " already exists");
			}
			action();
		}
	}
	public class SingleMutatorSelectionRulesRegistry : MutatorSelectionRulesRegistry<Predicate<string>, Predicate<IMutator>>
	{
		internal bool RunRules(IMutator mutator)
		{
			if (mutatorSelectionRulesExtended.Values.All((Predicate<IMutator> rule) => rule(mutator)))
			{
				return mutatorSelectionRules.Values.All((Predicate<string> rule) => rule(mutator.NamespacedName));
			}
			return false;
		}
	}
}
namespace Mutators.Rules.Loaders
{
	public interface IRuleLoader<T>
	{
		void AddDefaultRule(JsonMutatorRule jsonRule);

		void AddDefaultRules(params JsonMutatorRule[] jsonRules);

		void AddRuleStrategy(IRuleLoadingStrategy<T> strategy);
	}
	internal sealed class MultiMutatorRuleLoader : RuleLoader<Func<IReadOnlyCollection<string>, string, bool>>
	{
		private static readonly string MultiMutatorRulesPath = Path.Combine(RepoMutators.ConfigPath, "multi-mutator-rules.json");

		protected override JsonMutatorRule[] CreateDefaultRules()
		{
			return Array.Empty<JsonMutatorRule>();
		}

		protected override string GetRulesPath()
		{
			return MultiMutatorRulesPath;
		}
	}
	public abstract class RuleLoader<T> : IRuleLoader<T>
	{
		protected readonly IDictionary<string, JsonMutatorRule> defaultRules = new Dictionary<string, JsonMutatorRule>();

		protected readonly IDictionary<string, IRuleLoadingStrategy<T>> strategies = new Dictionary<string, IRuleLoadingStrategy<T>>();

		public IDictionary<string, T> Load()
		{
			IDictionary<string, T> executableRules = new Dictionary<string, T>();
			CreateDefaultFilesAndThen(RepoMutators.ConfigPath, delegate
			{
				JsonMutatorRule[] array = ReadRules(GetRulesPath());
				JsonMutatorRule[] array2 = array;
				foreach (JsonMutatorRule jsonMutatorRule in array2)
				{
					defaultRules[jsonMutatorRule.Key] = jsonMutatorRule;
					if (!strategies.TryGetValue(jsonMutatorRule.Type, out IRuleLoadingStrategy<T> value))
					{
						RepoMutators.Logger.LogError("Skipping invalid rule " + jsonMutatorRule.Key + ": unknown rule type " + jsonMutatorRule.Type);
					}
					else if (!jsonMutatorRule.Enabled)
					{
						RepoMutators.Logger.LogDebug("Skipping disabled rule " + jsonMutatorRule.Key);
					}
					else if (!value.Validate(jsonMutatorRule))
					{
						RepoMutators.Logger.LogWarning("Rule " + jsonMutatorRule.Key + " has an invalid configuration, skipping...");
					}
					else
					{
						executableRules.Add(jsonMutatorRule.Key, value.Load(jsonMutatorRule.Mutators, jsonMutatorRule.Arguments));
						RepoMutators.Logger.LogDebug("Successfully loaded rule " + jsonMutatorRule.Key + " with strategy " + value.Key + "!");
					}
				}
			});
			WriteRules(GetRulesPath(), GetSortedDefaultRules());
			return executableRules;
		}

		protected void CreateDefaultFilesAndThen(string configPath, Action then)
		{
			if (!Directory.Exists(configPath))
			{
				Directory.CreateDirectory(configPath);
			}
			if (!File.Exists(GetRulesPath()))
			{
				WriteRules(GetRulesPath(), GetSortedDefaultRules());
			}
			then();
		}

		private JsonMutatorRule[] GetSortedDefaultRules()
		{
			return (from kv in defaultRules
				select kv.Value into rule
				orderby rule.Enabled, rule.Key
				select rule).ToArray();
		}

		public void AddDefaultRule(JsonMutatorRule jsonRule)
		{
			defaultRules.Add(jsonRule.Key, jsonRule);
		}

		public void AddDefaultRules(params JsonMutatorRule[] jsonRules)
		{
			foreach (JsonMutatorRule jsonRule in jsonRules)
			{
				AddDefaultRule(jsonRule);
			}
		}

		public void AddRuleStrategy(IRuleLoadingStrategy<T> strategy)
		{
			strategies.Add(strategy.Key, strategy);
		}

		protected JsonMutatorRule[] ReadRules(string path)
		{
			string text = File.ReadAllText(path);
			return JsonConvert.DeserializeObject<JsonMutatorRule[]>(text) ?? CreateDefaultRules();
		}

		protected void WriteRules(string path, JsonMutatorRule[] rules)
		{
			RepoMutators.Logger.LogDebug("Writing rules to " + path);
			File.WriteAllText(path, JsonConvert.SerializeObject((object)rules, (Formatting)1));
		}

		protected abstract JsonMutatorRule[] CreateDefaultRules();

		protected abstract string GetRulesPath();
	}
	internal sealed class SingleMutatorRuleLoader : RuleLoader<Predicate<string>>
	{
		private static readonly string SingleMutatorRulesPath = Path.Combine(RepoMutators.ConfigPath, "single-mutator-rules.json");

		protected override JsonMutatorRule[] CreateDefaultRules()
		{
			return Array.Empty<JsonMutatorRule>();
		}

		protected override string GetRulesPath()
		{
			return SingleMutatorRulesPath;
		}

		private void ValidateAndRegisterExclusionRul