Decompiled source of Mutators v0.6.1
Mutators.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Mutators.Enums; using Mutators.Extensions; using Mutators.Managers; using Mutators.Mutators; using Mutators.Mutators.Behaviours; using Mutators.Mutators.Behaviours.Custom; using Mutators.Mutators.Behaviours.UI; using Mutators.Mutators.Patches; using Mutators.Network; using Mutators.Network.Meta; using Mutators.Patches; using Mutators.Settings; using Mutators.Settings.Specific; using Mutators.Utility; using Photon.Pun; using Photon.Realtime; using REPOLib; using REPOLib.Modules; using Sirenix.Utilities; 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: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("Xepos")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.6.1.0")] [assembly: AssemblyInformationalVersion("0.6.1+6c8941ea3b27653e90876ca3aa09119ce58cedf2")] [assembly: AssemblyProduct("Mutators")] [assembly: AssemblyTitle("Mutators")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.6.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Mutators { internal class AssetStore { internal static ExplosionPreset Preset { get; set; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Xepos.REPO-Mutators"; public const string NAME = "Mutators"; public const string PLUGIN_VERSION = "0.6.1"; } [BepInDependency("REPOLib", "2.1.0")] [BepInPlugin("Xepos.REPO-Mutators", "Mutators", "0.6.1")] public class RepoMutators : BaseUnityPlugin { internal const string MainScenePath = "Assets/Scenes/Main/Main.unity"; internal const string NETWORKMANAGER_NAME = "MutatorsNetworkManager"; internal static RepoMutators Instance { get; private set; } internal static ModSettings Settings { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } private void Awake() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "mutators"); BundleLoader.LoadBundle(text, (Action<AssetBundle>)delegate(AssetBundle assetbundle) { AssetStore.Preset = assetbundle.LoadAsset<ExplosionPreset>("explosion default"); GameObject val2 = assetbundle.LoadAsset<GameObject>("FiringMyLaser"); val2.SetActive(false); val2.AddComponent<PhotonView>(); val2.AddComponent<LaserFiringBehaviour>(); NetworkPrefabs.RegisterNetworkPrefab("Xepos.REPO-Mutators/FiringMyLaser", val2); _logger.LogInfo((object)"Loaded Mutators asset bundle"); }, false); Settings = new ModSettings(((BaseUnityPlugin)this).Config); MutatorSettings.Initialize(((BaseUnityPlugin)this).Config); 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); SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode loadSceneMode) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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((object)"Reviving network manager"); NetworkPrefabs.SpawnNetworkPrefab(myPrefabId, Vector3.zero, Quaternion.identity, (byte)0, (object[])null); MutatorManager instance2 = MutatorManager.Instance; IMutator weightedMutator = instance2.GetWeightedMutator(); Logger.LogDebug((object)("Picked weighted mutator: " + weightedMutator.Name)); instance2.CurrentMutator = weightedMutator; MutatorsNetworkManager.Instance.SendActiveMutator(weightedMutator.Name, weightedMutator.Settings.AsMetadata()); Logger.LogDebug((object)("Mutator set: " + weightedMutator.Name)); } } }; MutatorManager instance = MutatorManager.Instance; instance.GameStateChanged = (Action<MutatorsGameState>)Delegate.Combine(instance.GameStateChanged, (Action<MutatorsGameState>)delegate(MutatorsGameState gameState) { Logger.LogDebug((object)$"Changed Mutators gamestate to {gameState}"); }); Patch(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!"); Logger.LogDebug((object)"Initializing default mutators."); MutatorManager.Instance.InitializeDefaultMutators(); } internal 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)); 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(); } } } } namespace Mutators.Utility { internal static class DescriptionUtils { internal enum DescriptionReplacementType { REPLACE, PREPEND, APPEND } [CompilerGenerated] private sealed class <LateUpdateDescription>d__1 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public DescriptionReplacementType replacementType; public string description; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LateUpdateDescription>d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (!Object.op_Implicit((Object)(object)MutatorDescriptionAnnouncingBehaviour.Instance)) { <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; } TextMeshProUGUI text = MutatorDescriptionAnnouncingBehaviour.Instance.Text; switch (replacementType) { case DescriptionReplacementType.REPLACE: ((TMP_Text)text).text = description; break; case DescriptionReplacementType.PREPEND: ((TMP_Text)text).text = description + "\n" + ((TMP_Text)text).text; break; case DescriptionReplacementType.APPEND: ((TMP_Text)text).text = ((TMP_Text)text).text + "\n" + description; break; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [IteratorStateMachine(typeof(<LateUpdateDescription>d__1))] internal static IEnumerator LateUpdateDescription(string description, DescriptionReplacementType replacementType = DescriptionReplacementType.REPLACE) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LateUpdateDescription>d__1(0) { description = description, replacementType = replacementType }; } } public static class TemporaryItemUtils { public static void RemoveMarkedItems(string marker) { string marker2 = marker; StatsManager instance = StatsManager.instance; foreach (string item in (from item in instance.item where item.Key.Contains("(" + marker2 + ")") select item into x select x.Key).ToList()) { instance.item.Remove(item); instance.itemStatBattery.Remove(item); } } public static void DropMarkedItems(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.Settings { public abstract class AbstractMutatorSettings { protected const string WeightConfigKey = "Weight"; protected const string MinimumLevelConfigKey = "Minimum level"; protected const string MaximumLevelConfigKey = "Maximum level"; public abstract string MutatorName { get; } public abstract string MutatorDescription { get; } public abstract uint Weight { get; } public abstract uint MinimumLevel { get; } public abstract uint MaximumLevel { get; } public virtual bool IsEligibleForSelection() { int levelsCompleted = RunManager.instance.levelsCompleted; if (MaximumLevel != 0 && MinimumLevel > MaximumLevel) { RepoMutators.Logger.LogWarning((object)(MutatorName + " was configured with a minimum level larger than the maximum level!")); RepoMutators.Logger.LogWarning((object)"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 virtual IDictionary<string, object>? AsMetadata() { return null; } } public class EnemyDisablingMutatorSettings : GenericMutatorSettings { private readonly ConfigEntry<string> _excludedEnemies; public IList<string> ExcludedEnemies { get; private set; } = new List<string>(); public EnemyDisablingMutatorSettings(string name, string description, ConfigFile config, params string[] defaultDisabledEnemies) : base(name, description, 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)"); CacheEnemies(); } internal void CacheEnemies() { ExcludedEnemies = (from value in _excludedEnemies.Value.Split(",") select value.Trim()).ToList(); } } public class GenericMutatorSettings : AbstractMutatorSettings { private readonly ConfigEntry<uint> _weight; private readonly ConfigEntry<uint> _minimumLevel; private readonly ConfigEntry<uint> _maximumLevel; public override string MutatorName { get; } public override string MutatorDescription { get; } public override uint Weight => _weight.Value; public override uint MinimumLevel => _minimumLevel.Value; public override uint MaximumLevel => _maximumLevel.Value; public GenericMutatorSettings(string name, string description, ConfigFile config) { MutatorName = name; MutatorDescription = description; _weight = config.Bind<uint>(GetSection(name), "Weight", 100u, "Weighted chance for the " + name + " Mutator to be active."); _minimumLevel = config.Bind<uint>(GetSection(name), "Minimum level", 0u, "The minimum level on which the " + name + " Mutator can show up"); _maximumLevel = config.Bind<uint>(GetSection(name), "Maximum level", 1000u, "The maximum level on which the " + name + " mutator can show up (0 = no upper bound)"); } 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 } 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; 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; } internal ModSettings(ConfigFile config) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown _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"); CacheKeys(); } internal void CacheKeys() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got I4 //IL_0028->IL0028: Incompatible stack types: O vs I4 //IL_0022->IL0028: Incompatible stack types: I4 vs O //IL_0022->IL0028: Incompatible stack types: O vs I4 //IL_0091->IL0091: Incompatible stack types: O vs I4 //IL_008b->IL0091: Incompatible stack types: I4 vs O //IL_008b->IL0091: Incompatible stack types: O vs I4 object obj = this; int num; if (Enum.TryParse(typeof(KeyCode), _mutatorDisplayToggleKey.Value, out object result)) { obj = (object)(KeyCode)result; num = (int)obj; } else { num = 0; obj = num; num = (int)obj; } ((ModSettings)num).MutatorDisplayToggleKey = (KeyCode)obj; MutatorDisplayToggleType = (Enum.TryParse(typeof(MutatorNameToggleType), _mutatorDisplayToggleType.Value.Replace(" ", ""), out object result2) ? ((MutatorNameToggleType)result2) : MutatorNameToggleType.Keybind); object obj2 = this; int num2; if (Enum.TryParse(typeof(KeyCode), _specialActionKey.Value, out object result3)) { obj2 = (object)(KeyCode)result3; num2 = (int)obj2; } else { num2 = 0; obj2 = num2; num2 = (int)obj2; } ((ModSettings)num2).SpecialActionKey = (KeyCode)obj2; } } 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 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("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("Hunting Season", "No valuables spawn, weapons spawn instead\nEnemy respawn time reduced to 10 seconds\nOrb drop cap is removed", config, "Voodoo", "Weeping Angel"); ThereCanOnlyBeOne = new ThereCanOnlyBeOneMutatorSettings("There Can Only Be One", "All monster spawns are of the same type", config); VolatileCargo = new GenericMutatorSettings("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); } } } namespace Mutators.Settings.Specific { public class AmalgamMutatorSettings : GenericMutatorSettings, ILevelRemovingMutatorSettings { private readonly ConfigEntry<string> _excludedLevels; public bool AllowCustomLevels => true; public IList<string> ExcludedLevels { get; private set; } internal AmalgamMutatorSettings(string name, string description, ConfigFile config) : base(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"); ExcludedLevels = ExcludedLevelsAsList(); _excludedLevels.SettingChanged += SettingChanged; } private void SettingChanged(object sender, EventArgs e) { ExcludedLevels = ExcludedLevelsAsList(); } private IList<string> ExcludedLevelsAsList() { IList<string> list = (from value in _excludedLevels.Value.Split(",") select value.Trim()).ToList(); if (!list.Contains("Backrooms")) { list.Add("Backrooms"); } return list; } } public class ApolloElevenMutatorSettings : GenericMutatorSettings { private readonly ConfigEntry<bool> _applyToEnemies; private readonly ConfigEntry<bool> _applyInCart; private readonly ConfigEntry<string> _downwardsKey; public bool ApplyToEnemies => _applyToEnemies.Value; public bool ApplyInCart => _applyInCart.Value; public KeyCode DownwardsKey { get; private set; } internal ApolloElevenMutatorSettings(string name, string description, ConfigFile config) : base(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 { private readonly ConfigEntry<float> _duckAggroCooldown; public float AggroCooldown => _duckAggroCooldown.Value; internal DuckThisMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { _duckAggroCooldown = config.Bind<float>(GenericMutatorSettings.GetSection(name), "Duck aggro cooldown", 50f, "The cooldown between duck aggro while the Duck This Mutator is active."); } } public class FiringMyLaserMutatorSettings : GenericMutatorSettings { private readonly ConfigEntry<int> _laserActionCooldown; private readonly ConfigEntry<int> _laserActionEnemyDamage; private readonly ConfigEntry<bool> _laserActionEnabled; public int LaserActionCooldown => _laserActionCooldown.Value; public int LaserActionEnemyDamage => _laserActionEnemyDamage.Value; public bool LaserActionEnabled => _laserActionEnabled.Value; internal FiringMyLaserMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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"); _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>())); } public override IDictionary<string, object>? AsMetadata() { IDictionary<string, object> dictionary = new Dictionary<string, object> { { "laserActionEnabled", LaserActionEnabled } }; return dictionary.WithMutator(MutatorName); } } public class HandleWithCareMutatorSettings : GenericMutatorSettings { private readonly ConfigEntry<float> _valueMultiplier; private readonly ConfigEntry<bool> _instaDestroySurplus; private readonly ConfigEntry<bool> _multiplySurplus; public float ValueMultiplier => _valueMultiplier.Value; public bool InstantlyDestroySurplus => _instaDestroySurplus.Value; public bool MultiplySurplusValue => _multiplySurplus.Value; internal HandleWithCareMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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 { private readonly ConfigEntry<float> _strongDivisionFactor; private readonly ConfigEntry<float> _weakDivisionFactor; private readonly ConfigEntry<float> _valueGainMultiplier; public float StrongDivisionFactor => _strongDivisionFactor.Value; public float WeakDivisionFactor => _weakDivisionFactor.Value; public float ValueGainMultiplier => _valueGainMultiplier.Value; internal LessIsMoreMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: 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>())); } public override IDictionary<string, object>? AsMetadata() { IDictionary<string, object> dictionary = new Dictionary<string, object> { { "ValueGainMultiplier", ValueGainMultiplier } }; return dictionary.WithMutator(MutatorName); } } public class NopMutatorSettings : AbstractMutatorSettings { private readonly ConfigEntry<uint> _weight; private readonly ConfigEntry<uint> _minimumLevel; private readonly ConfigEntry<uint> _maximumLevel; public override string MutatorName => "None"; public override string MutatorDescription => "A normal run, no special effects"; public override uint Weight => _weight.Value; public override uint MinimumLevel => _minimumLevel.Value; public override uint MaximumLevel => _maximumLevel.Value; internal NopMutatorSettings(ConfigFile config) { _weight = config.Bind<uint>("No Mutator", "Weight", (uint)((ulong)(global::Mutators.Mutators.Mutators.All().Length - 1) * 100uL), "Weighted chance for no mutator to be active."); _minimumLevel = config.Bind<uint>("No Mutator", "Minimum level", 0u, "The minimum level on which no mutator can show up"); _maximumLevel = config.Bind<uint>("No Mutator", "Maximum level", 1000u, "The maximum level on which no mutator can show up (0 = no upper bound)"); } } public class OneShotOneKillMutatorSettings : EnemyDisablingMutatorSettings { private readonly ConfigEntry<bool> _instaReviveInTruckOrExtraction; private readonly ConfigEntry<uint> _instaReviveHealth; public bool InstaReviveInTruckOrExtraction => _instaReviveInTruckOrExtraction.Value; public int InstaReviveHealth { get; private set; } internal OneShotOneKillMutatorSettings(string name, string description, ConfigFile config) : base(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.Bind<uint>(GenericMutatorSettings.GetSection(name), "Instant revive health", 0u, "The amount of health the player should be revived with when Instant revive is enabled. (0 = Revive with max health)"); Cache(); } private void Cache() { InstaReviveHealth = (int)Math.Clamp(_instaReviveHealth.Value, 0u, 2147483647u); } } public class OutWithABangMutatorSettings : GenericMutatorSettings { public const string Tier1Radius = "OutWithABang-Radius1"; public const string Tier1Damage = "OutWithABang-Damage1"; public const string Tier2Radius = "OutWithABang-Radius2"; public const string Tier2Damage = "OutWithABang-Damage2"; public const string Tier3Radius = "OutWithABang-Radius3"; public const string Tier3Damage = "OutWithABang-Damage3"; 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(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.Bind<int>(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.Bind<int>(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.Bind<int>(GenericMutatorSettings.GetSection(name), "Tier 3 Enemy Explosion Damage", 200, "The on-death explosion damage of Tier 3 enemies during the " + name + " Mutator."); } public override IDictionary<string, object>? AsMetadata() { IDictionary<string, object> dictionary = new Dictionary<string, object> { { "OutWithABang-Radius1", Tier1ExplosionRadius }, { "OutWithABang-Damage1", Tier1ExplosionDamage }, { "OutWithABang-Radius2", Tier2ExplosionRadius }, { "OutWithABang-Damage2", Tier2ExplosionDamage }, { "OutWithABang-Radius3", Tier3ExplosionRadius }, { "OutWithABang-Damage3", Tier3ExplosionDamage } }; return dictionary.WithMutator(MutatorName); } } public class ProtectThePresidentMutatorSettings : GenericMutatorSettings { private readonly ConfigEntry<byte> _minimumPlayerCount; public byte MinimumPlayerCount => _minimumPlayerCount.Value; internal ProtectThePresidentMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { _minimumPlayerCount = config.Bind<byte>(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", (byte)3, "The minimum amount of players required for the " + name + " Mutator to be available for selection."); } 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<byte> _minimumPlayerCount; public byte MinimumPlayerCount => _minimumPlayerCount.Value; internal ProtectTheWeakMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { _minimumPlayerCount = config.Bind<byte>(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", (byte)3, "The minimum amount of players required for the " + name + " Mutator to be available for selection."); } 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 { private readonly ConfigEntry<int> _maximumMonsterSpawns; private readonly ConfigEntry<float> _monsterSpawnChance; public int MaximumMonsterSpawns => _maximumMonsterSpawns.Value; public float MonsterSpawnChance => _monsterSpawnChance.Value; internal SealedAwayMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config, "Voodoo", "Shadow Child") { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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", 10f, 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 TheFloorIsLavaMutatorSettings : GenericMutatorSettings, ILevelRemovingMutatorSettings { 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 { get; private set; } public bool UsePercentageDamage => _usePercentageDamage.Value; public bool AllowCustomLevels => _allowCustomLevels.Value; public bool DisableEnemies => _disableEnemies.Value; public float ReviveImmunityDuration => _reviveImmunityDuration.Value; public IList<string> ExcludedLevels => new List<string>(); internal TheFloorIsLavaMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { ConfigEntry<int> val = config.Bind<int>(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."); ConfigEntry<int> val2 = config.Bind<int>(GenericMutatorSettings.GetSection(name), "Immune player count", 0, "The amount of players that are immune to " + name + " damage."); _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."); _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); ImmunePlayerCount = Math.Clamp(val2.Value, 0, int.MaxValue); } public override IDictionary<string, object>? AsMetadata() { IDictionary<string, object> dictionary = new Dictionary<string, object> { { "damage", DamagePerTick }, { "usePercentageDamage", UsePercentageDamage }, { "reviveImmunityDuration", ReviveImmunityDuration } }; return dictionary.WithMutator(MutatorName); } } public class ThereCanOnlyBeOneMutatorSettings : EnemyDisablingMutatorSettings { private readonly ConfigEntry<uint> _groupSpawnsThreshold; public uint GroupSpawnsThreshold => _groupSpawnsThreshold.Value; internal ThereCanOnlyBeOneMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { _groupSpawnsThreshold = config.Bind<uint>(GenericMutatorSettings.GetSection(name), "Group spawn minimum level", 8u, "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 ConfigEntry<bool> _keepOnLight; private readonly ConfigEntry<byte> _minimumPlayerCount; public bool KeepOnLight => _keepOnLight.Value; public byte MinimumPlayerCount => _minimumPlayerCount.Value; internal UltraViolenceMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { _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<byte>(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", (byte)0, "The minimum amount of players required for the " + name + " Mutator to be available for selection."); } public override bool IsEligibleForSelection() { if (base.IsEligibleForSelection()) { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { return currentRoom.PlayerCount >= MinimumPlayerCount; } return false; } return false; } public override IDictionary<string, object>? AsMetadata() { IDictionary<string, object> dictionary = new Dictionary<string, object> { { "keepLightsOn", KeepOnLight } }; return dictionary.WithMutator(MutatorName); } } public class VoiceoverMutatorSettings : GenericMutatorSettings { private readonly ConfigEntry<byte> _minimumPlayerCount; public byte MinimumPlayerCount => _minimumPlayerCount.Value; internal VoiceoverMutatorSettings(string name, string description, ConfigFile config) : base(name, description, config) { _minimumPlayerCount = config.Bind<byte>(GenericMutatorSettings.GetSection(name), "Minimum player amount requirement", (byte)3, "The minimum amount of players required for the " + name + " Mutator to be available for selection."); } public override bool IsEligibleForSelection() { if (base.IsEligibleForSelection()) { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { return currentRoom.PlayerCount >= MinimumPlayerCount; } return false; } return false; } } } namespace Mutators.Patches { [HarmonyPatch(typeof(EnemyDirector))] internal class EnemyDirectorPatch { private static List<EnemySetup> _startingEnemyList = new List<EnemySetup>(); private static bool _isListSet; [HarmonyPrefix] [HarmonyPriority(600)] [HarmonyPatch("GetEnemy")] private static void EnemyDirectorGetEnemyPrefix(ref List<EnemySetup> ___enemyList, int ___enemyListIndex) { if (!SemiFunc.IsMultiplayer() || !SemiFunc.IsNotMasterClient()) { ___enemyList.RemoveAll((EnemySetup x) => (Object)(object)x == (Object)null); if (!_isListSet) { _startingEnemyList = new List<EnemySetup>(___enemyList); _isListSet = true; } if (___enemyList.Count == 0) { EnemySetup val = ScriptableObject.CreateInstance<EnemySetup>(); val.spawnObjects = new List<GameObject>(); ___enemyList.Add(val); } while (___enemyList.Count < ___enemyListIndex + 1) { int index = Random.Range(0, _startingEnemyList.Count); ___enemyList.Add(___enemyList[index]); } } } } [HarmonyPatch(typeof(LevelGenerator))] internal class LevelGeneratorPatch { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyPatch("GenerateDone")] private static void LevelGeneratorGenerateDonePrefix() { if (SemiFunc.RunIsLevel()) { MutatorManager.Instance.GameState = MutatorsGameState.LevelGenerated; } } } [HarmonyPatch(typeof(LoadingUI))] internal class LoadingUIPatch { [HarmonyPostfix] [HarmonyPriority(800)] [HarmonyPatch("StopLoading")] private static void LoadingUIStopLoadingPostfix() { if (SemiFunc.RunIsLevel()) { GameObject hud = GameObject.Find("Game Hud"); GameObject health = GameObject.Find("Health"); CreateMutatorText(hud, health); CreateMutatorDescriptionText(hud, health); CreateTargetPlayerText(hud, health); IMutator currentMutator = MutatorManager.Instance.CurrentMutator; if (currentMutator != null && currentMutator.HasSpecialAction) { GameObject energy = GameObject.Find("Energy"); CreateSpecialActionText(hud, health, energy); } } } private static void CreateMutatorText(GameObject hud, GameObject health) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Mutator"); val.transform.SetParent(hud.transform, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); TextMeshProUGUI component = health.GetComponent<TextMeshProUGUI>(); ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontMaterial = ((TMP_Text)component).fontMaterial; RectTransform component2 = val.GetComponent<RectTransform>(); component2.sizeDelta = new Vector2(200f, 50f); component2.anchorMin = new Vector2(1f, 1f); component2.anchorMax = new Vector2(1f, 1f); component2.pivot = new Vector2(1f, 1f); component2.anchoredPosition = new Vector2(0f, RepoMutators.Settings.MutatorDisplayY); ((TMP_Text)val2).alignment = (TextAlignmentOptions)516; val.AddComponent<MutatorAnnouncingBehaviour>(); ((TMP_Text)val2).text = MutatorManager.Instance.CurrentMutator.Name; ((TMP_Text)val2).fontSize = RepoMutators.Settings.MutatorDisplaySize; ((Behaviour)val2).enabled = true; } private static void CreateMutatorDescriptionText(GameObject hud, GameObject health) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Mutator Description"); val.transform.SetParent(hud.transform, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); TextMeshProUGUI component = health.GetComponent<TextMeshProUGUI>(); ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontMaterial = ((TMP_Text)component).fontMaterial; RectTransform component2 = val.GetComponent<RectTransform>(); component2.sizeDelta = new Vector2(300f, 100f); component2.anchorMin = new Vector2(1f, 1f); component2.anchorMax = new Vector2(1f, 1f); component2.pivot = new Vector2(1f, 1f); component2.anchoredPosition = new Vector2(0f, RepoMutators.Settings.MutatorDescriptionDisplayY); ((TMP_Text)val2).alignment = (TextAlignmentOptions)516; ((TMP_Text)val2).verticalAlignment = (VerticalAlignmentOptions)256; val.AddComponent<MutatorDescriptionAnnouncingBehaviour>(); ((TMP_Text)val2).text = string.Empty; ((TMP_Text)val2).lineSpacing = -50f; ((TMP_Text)val2).fontSize = RepoMutators.Settings.MutatorDescriptionDisplaySize; ((Behaviour)val2).enabled = true; } private static void CreateTargetPlayerText(GameObject hud, GameObject health) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ChosenPlayerTarget"); val.transform.SetParent(hud.transform, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); TextMeshProUGUI component = health.GetComponent<TextMeshProUGUI>(); ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontMaterial = ((TMP_Text)component).fontMaterial; ((Graphic)val2).color = ((Graphic)component).color; RectTransform component2 = val.GetComponent<RectTransform>(); component2.sizeDelta = new Vector2(300f, 50f); component2.anchorMin = new Vector2(0.5f, 1f); component2.anchorMax = new Vector2(0.5f, 1f); component2.pivot = new Vector2(0.5f, 1f); component2.anchoredPosition = new Vector2(0f, 10f); ((TMP_Text)val2).alignment = (TextAlignmentOptions)4098; val.AddComponent<TargetPlayerAnnouncingBehaviour>(); ((TMP_Text)val2).text = string.Empty; ((TMP_Text)val2).fontSize = RepoMutators.Settings.TargetDisplaySize; ((Behaviour)val2).enabled = true; } private static void CreateSpecialActionText(GameObject hud, GameObject health, GameObject energy) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SpecialAction"); val.transform.SetParent(hud.transform, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); Zap(val, energy); GameObject val3 = new GameObject("SpecialActionMax"); val3.transform.SetParent(val.transform, false); TextMeshProUGUI val4 = val3.AddComponent<TextMeshProUGUI>(); TextMeshProUGUI component = health.GetComponent<TextMeshProUGUI>(); ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontWeight = ((TMP_Text)component).fontWeight; ((TMP_Text)val2).fontMaterial = ((TMP_Text)component).fontMaterial; ((Graphic)val2).color = Color.red; RectTransform component2 = val.GetComponent<RectTransform>(); component2.sizeDelta = new Vector2(120f, 50f); component2.anchorMin = new Vector2(0f, 1f); component2.anchorMax = new Vector2(0f, 1f); component2.pivot = new Vector2(0f, 1f); component2.anchoredPosition = new Vector2(29f, RepoMutators.Settings.SpecialActionY); ((TMP_Text)val2).alignment = (TextAlignmentOptions)513; ((TMP_Text)val2).text = string.Empty; ((TMP_Text)val2).fontStyle = (FontStyles)1; ((TMP_Text)val2).fontSize = 40f; ((Behaviour)val2).enabled = true; ((TMP_Text)val4).font = ((TMP_Text)component).font; ((TMP_Text)val4).fontMaterial = ((TMP_Text)component).fontMaterial; ((Graphic)val4).color = Color.red; RectTransform component3 = val3.GetComponent<RectTransform>(); component3.sizeDelta = new Vector2(120f, 50f); component3.anchorMin = new Vector2(0f, 1f); component3.anchorMax = new Vector2(0f, 1f); component3.pivot = new Vector2(0f, 1f); component3.anchoredPosition = new Vector2(45f, 5f); ((TMP_Text)val4).alignment = (TextAlignmentOptions)513; val.AddComponent<SpecialActionAnnouncingBehaviour>(); ((TMP_Text)val4).text = string.Empty; ((TMP_Text)val4).fontSize = 20f; ((Behaviour)val4).enabled = true; } private static void Zap(GameObject specialActionObject, GameObject energy) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SpecialActionZap"); val.transform.SetParent(specialActionObject.transform, false); Image component = ((Component)energy.transform.Find("Zap")).GetComponent<Image>(); Image val2 = val.AddComponent<Image>(); val2.sprite = component.sprite; ((Graphic)val2).color = Color.red; RectTransform component2 = val.GetComponent<RectTransform>(); component2.sizeDelta = new Vector2(25f, 25f); component2.anchoredPosition = new Vector2(-75f, 0f); } } [HarmonyPatch(typeof(MapToolController))] internal class MapToolControllerPatch { [HarmonyPostfix] [HarmonyPatch("Update")] private static void Postfix(MapToolController __instance) { MutatorDescriptionAnnouncingBehaviour instance = MutatorDescriptionAnnouncingBehaviour.Instance; if (Object.op_Implicit((Object)(object)instance) && __instance.Active && RepoMutators.Settings.MutatorDescriptionInMapTool && (Object)(object)__instance.PlayerAvatar == (Object)(object)PlayerAvatar.instance) { ((SemiUI)instance).Show(); } if (RepoMutators.Settings.MutatorDisplayToggleType == ModSettings.MutatorNameToggleType.WithDescription) { MutatorAnnouncingBehaviour instance2 = MutatorAnnouncingBehaviour.instance; if (Object.op_Implicit((Object)(object)instance2) && __instance.Active && RepoMutators.Settings.MutatorDescriptionInMapTool && (Object)(object)__instance.PlayerAvatar == (Object)(object)PlayerAvatar.instance) { ((SemiUI)instance2).Show(); } } } } [HarmonyPatch(typeof(MenuPage))] internal class MenuPagePatch { [HarmonyPostfix] [HarmonyPatch("LockAndHide")] private static void MenuPageLockAndHidePostfix() { MutatorAnnouncingBehaviour instance = MutatorAnnouncingBehaviour.instance; MutatorDescriptionAnnouncingBehaviour instance2 = MutatorDescriptionAnnouncingBehaviour.Instance; TargetPlayerAnnouncingBehaviour instance3 = TargetPlayerAnnouncingBehaviour.instance; SpecialActionAnnouncingBehaviour instance4 = SpecialActionAnnouncingBehaviour.instance; if (Object.op_Implicit((Object)(object)instance)) { ((SemiUI)instance).Hide(); } if (Object.op_Implicit((Object)(object)instance2)) { ((SemiUI)instance2).Hide(); } if (Object.op_Implicit((Object)(object)instance3)) { ((SemiUI)instance3).Hide(); } if (Object.op_Implicit((Object)(object)instance4)) { ((SemiUI)instance4).Hide(); } } } [HarmonyPatch(typeof(RunManager))] internal class RunManagerPatch { private static readonly ISet<string> vanillaLevelNames = new HashSet<string> { "Level - Artic", "Level - Manor", "Level - Wizard", "Level - Museum" }; [HarmonyPostfix] [HarmonyPatch("ChangeLevel")] private static void RunManagerChangeLevelPostfix() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMultiplayer() && SemiFunc.IsNotMasterClient()) { return; } RepoMutators.Logger.LogDebug((object)"RunManagerPatch Host only"); if (!SemiFunc.IsMultiplayer() && !SemiFunc.RunIsLobbyMenu() && (Object)(object)MutatorsNetworkManager.Instance == (Object)null) { RepoMutators.Logger.LogDebug((object)"Spawning singleplayer NetworkManager"); string text = "Xepos.REPO-Mutators/MutatorsNetworkManager"; GameObject val = NetworkPrefabs.SpawnNetworkPrefab(text, Vector3.zero, Quaternion.identity, (byte)0, (object[])null); if (val != null) { val.SetActive(true); } GetAndSendMutator(); } ApplyPatch(); } [HarmonyPostfix] [HarmonyPatch("UpdateLevel")] private static void RunManagerUpdateLevelPostfix() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { RepoMutators.Logger.LogDebug((object)"RunManagerPatch Client only"); ApplyPatch(); } } [HarmonyPrefix] [HarmonyPatch("SetRunLevel")] private static void RunManagerChangeLevelPrefix(RunManager __instance, ref Level ___previousRunLevel) { if (!SemiFunc.IsMasterClientOrSingleplayer() || !(MutatorManager.Instance.CurrentMutator.Settings is ILevelRemovingMutatorSettings levelRemovingMutatorSettings)) { return; } if (!levelRemovingMutatorSettings.AllowCustomLevels) { __instance.levels.RemoveAll((Level l) => !vanillaLevelNames.Contains(((Object)l).name)); } if (levelRemovingMutatorSettings.ExcludedLevels.Count > 0) { ISet<string> excludedSet = new HashSet<string>(levelRemovingMutatorSettings.ExcludedLevels.Select((string level) => (!level.StartsWith("level - ", StringComparison.OrdinalIgnoreCase)) ? ("level - " + level).ToLowerInvariant() : level.ToLowerInvariant())); __instance.levels.RemoveAll((Level level) => excludedSet.Contains(((Object)level).name.ToLowerInvariant())); } if (__instance.levels.Count == 1) { ___previousRunLevel = null; } else if (__instance.levels.Count == 0) { ___previousRunLevel = null; RepoMutators.Logger.LogError((object)"Attempted to start a run with 0 available levels, please revisit your mod settings!"); RepoMutators.Logger.LogError((object)"There must be at least one level available to choose from!"); } } private static void ApplyPatch() { MutatorManager instance = MutatorManager.Instance; if (IsInShop()) { instance.GameState = MutatorsGameState.Shop; if (SemiFunc.IsMasterClientOrSingleplayer()) { MutatorsNetworkManager.Instance.ClearBufferedRPCs(); GetAndSendMutator(); } } else if (SemiFunc.RunIsLevel()) { RepoMutators.Logger.LogDebug((object)("Applying patch now for mutator: " + instance.CurrentMutator.Name)); instance.CurrentMutator.Patch(); } else { instance.GameState = MutatorsGameState.None; if (SemiFunc.RunIsArena()) { instance.SetActiveMutator("None"); } } } private static void GetAndSendMutator() { IMutator weightedMutator = MutatorManager.Instance.GetWeightedMutator(); MutatorsNetworkManager.Instance.SendActiveMutator(weightedMutator.Name, weightedMutator.Settings.AsMetadata()); } private static bool IsInShop() { RunManager instance = RunManager.instance; return ((Object)instance.levelCurrent).name == ((Object)instance.levelShop).name; } } [HarmonyPatch(typeof(SemiFunc))] internal class SemiFuncPatch { [HarmonyPostfix] [HarmonyPriority(800)] [HarmonyPatch("OnSceneSwitch")] private static void SemiFuncOnSceneSwitchPostfix(bool _gameOver, bool _leaveGame) { if (_leaveGame) { MutatorManager instance = MutatorManager.Instance; instance.GameState = MutatorsGameState.None; instance.SetActiveMutator("None"); } } } [HarmonyPatch(typeof(SpectateCamera))] internal class SpectateCameraPatch { [HarmonyPostfix] [HarmonyPatch("LateUpdate")] private static void SpectateCameraLateUpdatePostfix() { SpecialActionAnnouncingBehaviour instance = SpecialActionAnnouncingBehaviour.instance; if (Object.op_Implicit((Object)(object)instance)) { ((SemiUI)instance).Hide(); } } } } namespace Mutators.Network { internal class MutatorsNetworkManager : MonoBehaviourPunCallbacks { [CompilerGenerated] private sealed class <ComparedModVersionCoroutine>d__26 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public MutatorsNetworkManager <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ComparedModVersionCoroutine>d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown int num = <>1__state; MutatorsNetworkManager mutatorsNetworkManager = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((Object)(object)mutatorsNetworkManager._photonView == (Object)null) { <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; } mutatorsNetworkManager._photonView.RPC("CompareModVersion", (RpcTarget)2, new object[1] { "0.6.1" }); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <PrintViewId>d__7 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public MutatorsNetworkManager <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PrintViewId>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown int num = <>1__state; MutatorsNetworkManager mutatorsNetworkManager = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; RepoMutators.Logger.LogInfo((object)$"ViewID - {mutatorsNetworkManager._photonView.ViewID}"); } else { <>1__state = -1; } <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private PhotonView _photonView; private readonly bool _debug; internal static MutatorsNetworkManager Instance { get; private set; } private void Awake() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) Instance = this; ((Component)this).transform.parent = ((Component)StatsManager.instance).transform; ((Object)((Component)this).gameObject).name = "MutatorsNetworkManager"; GameObject gameObject = ((Component)this).gameObject; ((Object)gameObject).hideFlags = (HideFlags)(((Object)gameObject).hideFlags & -62); _photonView = ((Component)this).GetComponent<PhotonView>(); if (_debug) { Run(PrintViewId()); } } [IteratorStateMachine(typeof(<PrintViewId>d__7))] private IEnumerator PrintViewId() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PrintViewId>d__7(0) { <>4__this = this }; } internal void ClearBufferedRPCs() { if (_photonView.IsMine) { PhotonNetwork.RemoveBufferedRPCs(_photonView.ViewID, (string)null, (int[])null); } } public void SendMetadata(IDictionary<string, object> metadata) { Send<Hashtable>(metadata.ToPhotonHashtable(), SetMetadata, (RpcTarget)4); } public void SendActiveMutator(string name, IDictionary<string, object>? metadata = null) { if (SemiFunc.IsMasterClientOrSingleplayer()) { Hashtable value = metadata?.ToPhotonHashtable(); Send<string, Hashtable>(name, value, SetActiveMutator, (RpcTarget)4); } } public void SendComponentForViews(int[] views, Type componentType) { Send(views, componentType.FullName, AddComponentToViewGameObject, (RpcTarget)4); } internal void SendScaleChange(int photonViewId, float scale, bool buffered = true) { Send(photonViewId, scale, SetScale, (RpcTarget)((!buffered) ? 1 : 4)); } public void SendMetaToHost(string sender, IDictionary<string, object> meta) { Hashtable val = meta.ToPhotonHashtable(); if (SemiFunc.IsMultiplayer() && !SemiFunc.IsMasterClient()) { _photonView.RPC("SetClientMetadata", (RpcTarget)2, new object[2] { sender, val }); } } [PunRPC] public void AddComponentToViewGameObject(int[] views, string componentType) { Type type = Type.GetType(componentType); if (type == null) { RepoMutators.Logger.LogError((object)("Failed to resolve type: " + componentType)); return; } foreach (int num in views) { PhotonView val = PhotonView.Find(num); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)((Component)val).gameObject)) { ((Component)val).gameObject.AddComponent(type); } } } [PunRPC] public void SetActiveMutator(string name, Hashtable? hashtable) { MutatorManager instance = MutatorManager.Instance; bool flag = SemiFunc.RunIsLevel(); RepoMutators.Logger.LogDebug((object)("Set mutator to " + name + ", applying patch " + (flag ? "now" : "later"))); instance.SetActiveMutator(name, flag); IDictionary<string, object> dictionary; if (hashtable != null) { dictionary = hashtable.FromPhotonHashtable(); } else { IDictionary<string, object> dictionary2 = new Dictionary<string, object>(); dictionary = dictionary2; } IDictionary<string, object> dictionary3 = dictionary; if (dictionary3.TryGetValue(MutatorSettings.TheFloorIsLava.MutatorName, out var value) && value is IDictionary<string, object> source) { RepoMutators.Logger.LogDebug((object)("[RPC] Received metadata: " + string.Join(", ", source.Select((KeyValuePair<string, object> kvp) => $"{kvp.Key}: {kvp.Value}")))); } else { RepoMutators.Logger.LogDebug((object)("[RPC] Received metadata: " + string.Join(", ", dictionary3.Select((KeyValuePair<string, object> kvp) => $"{kvp.Key}: {kvp.Value}")))); } instance.CurrentMutator.ConsumeMetadata(dictionary3); } [PunRPC] public void SetMetadata(Hashtable hashtable) { MutatorManager instance = MutatorManager.Instance; IDictionary<string, object> dictionary = hashtable.FromPhotonHashtable(); if (dictionary.TryGetValue(MutatorSettings.TheFloorIsLava.MutatorName, out var value) && value is IDictionary<string, object> source) { RepoMutators.Logger.LogDebug((object)("[RPC] Received metadata: " + string.Join(", ", source.Select((KeyValuePair<string, object> kvp) => $"{kvp.Key}: {kvp.Value}")))); } else { RepoMutators.Logger.LogDebug((object)("[RPC] Received metadata: " + string.Join(", ", dictionary.Select((KeyValuePair<string, object> kvp) => $"{kvp.Key}: {kvp.Value}")))); } instance.CurrentMutator.ConsumeMetadata(dictionary); } [PunRPC] public void SetClientMetadata(string steamId, Hashtable hashtable) { MutatorManager instance = MutatorManager.Instance; IDictionary<string, object> value = hashtable.FromPhotonHashtable(); IDictionary<string, object> value2 = new Dictionary<string, object> { { steamId, value } }; IDictionary<string, object> metadata = new Dictionary<string, object> { { "clients", value2 } }; instance.CurrentMutator.ConsumeMetadata(metadata); } [PunRPC] public void SetScale(int viewId, float scale) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) PhotonView val = PhotonView.Find(viewId); if ((Object)(object)val != (Object)null) { ((Component)val).transform.localScale = new Vector3(scale, scale, scale); } } [PunRPC] public void SendModVersion() { ((MonoBehaviour)this).StartCoroutine(ComparedModVersionCoroutine()); } [PunRPC] public void CompareModVersion(string version, PhotonMessageInfo info) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (version == "0.6.1") { RepoMutators.Logger.LogInfo((object)(info.Sender.NickName + " is on the same version!")); } else { HandleVersionMismatch(version, info.Sender.NickName); } } public override void OnPlayerEnteredRoom(Player newPlayer) { if (_photonView.IsMine) { _photonView.RPC("SendModVersion", newPlayer, Array.Empty<object>()); } } private void HandleVersionMismatch(string version, string playerName) { string[] array = version.Split('.'); string[] array2 = "0.6.1".Split('.'); if (array[0] != array2[0] || array[1] != array2[1]) { RepoMutators.Logger.LogError((object)(playerName + " is on version " + version + ", which doesn't match the host version!")); } else if (array[2] != array2[2]) { RepoMutators.Logger.LogWarning((object)(playerName + " is on version " + version + ", which doesn't match the host version!")); } } private bool ValidateClientMeta(IDictionary<string, object> clientMeta, IDictionary<string, IAllowedClientMeta> allowedMeta) { foreach (KeyValuePair<string, object> clientMetum in clientMeta) { if (!allowedMeta.TryGetValue(clientMetum.Key, out IAllowedClientMeta value)) { return false; } if (value.HasNested()) { if (!(clientMetum.Value is IDictionary<string, object> clientMeta2)) { return false; } if (!ValidateClientMeta(clientMeta2, value.NestedMeta)) { return false; } } } return true; } private void Send<T>(T data, Action<T> rpcMethod, RpcTarget rpcTarget) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMultiplayer()) { if (SemiFunc.IsMasterClient()) { _photonView.RPC(rpcMethod.Method.Name, rpcTarget, new object[1] { data }); rpcMethod(data); } } else { rpcMethod(data); } } private void Send<T, D>(T data, D value, Action<T, D> rpcMethod, RpcTarget rpcTarget) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMultiplayer()) { if (SemiFunc.IsMasterClient()) { _photonView.RPC(rpcMethod.Method.Name, rpcTarget, new object[2] { data, value }); rpcMethod(data, value); } } else { rpcMethod(data, value); } } [IteratorStateMachine(typeof(<ComparedModVersionCoroutine>d__26))] private IEnumerator ComparedModVersionCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ComparedModVersionCoroutine>d__26(0) { <>4__this = this }; } internal void Run(IEnumerator coroutine) { ((MonoBehaviour)this).StartCoroutine(coroutine); } } } namespace Mutators.Network.Meta { public class AllowedClientMeta : IAllowedClientMeta { public bool PurgeAfterAccepting { get; private set; } public IDictionary<string, IAllowedClientMeta> NestedMeta { get; private set; } public AllowedClientMeta(IDictionary<string, IAllowedClientMeta> meta, bool purgeAfterAccepting = false) { PurgeAfterAccepting = purgeAfterAccepting; NestedMeta = meta; } public AllowedClientMeta(bool purgeAfterAccepting = false) { PurgeAfterAccepting = purgeAfterAccepting; NestedMeta = new Dictionary<string, IAllowedClientMeta>(); } } public interface IAllowedClientMeta { bool PurgeAfterAccepting { get; } IDictionary<string, IAllowedClientMeta> NestedMeta { get; } bool HasNested() { if (NestedMeta != null) { return NestedMeta.Count > 0; } return false; } } } namespace Mutators.Mutators { public interface IMutator { string Name { get; } string Description { get; } bool Active { get; } bool HasSpecialAction { get; } AbstractMutatorSettings Settings { get; } IReadOnlyList<Type> Patches { get; } IReadOnlyList<Func<bool>> Conditions { get; } void Patch(); void Unpatch(); void ConsumeMetadata(IDictionary<string, object> metadata); } public class Mutator : IMutator { private readonly Harmony _harmony; private readonly IList<Type> _patches; private readonly IList<Func<bool>> _conditions; private readonly IDictionary<string, object> _pendingDeferredMetadata = new Dictionary<string, object>(); private IDictionary<string, object> _metadata; private readonly IList<Action> _beforePatchAllHooks = new List<Action>(); private readonly IList<Action> _afterPatchAllHooks = new List<Action>(); private readonly IList<Action<IDictionary<string, object>>> _onMetadataChangedHooks = new List<Action<IDictionary<string, object>>>(); private readonly IList<Action> _beforeUnpatchAllHooks = new List<Action>(); private readonly IList<Action> _afterUnpatchAllHooks = new List<Action>(); public string Name => Settings.MutatorName; public string Description => Settings.MutatorDescription; public IReadOnlyDictionary<string, object> Metadata => new ReadOnlyDictionary<string, object>(_metadata); public bool Active { get; private set; } public bool HasSpecialAction { get; private set; } public AbstractMutatorSettings Settings { get; private set; } public IReadOnlyList<Func<bool>> Conditions => new ReadOnlyCollection<Func<bool>>(_conditions); public IReadOnlyList<Type> Patches => new ReadOnlyCollection<Type>(_patches); public Mutator(AbstractMutatorSettings settings, IList<Type> patches, IList<Func<bool>> conditions = null, bool specialActionOverlay = false) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown Settings = settings; _harmony = new Harmony("Xepos.REPO-Mutators-" + settings.MutatorName); _patches = patches ?? new List<Type>(); _conditions = conditions ?? new List<Func<bool>>(); _metadata = new Dictionary<string, object>(); HasSpecialAction = specialActionOverlay; foreach (Type patch in _patches) { TryAddHook(patch, "BeforePatchAll", _beforePatchAllHooks); TryAddHook(patch, "AfterPatchAll", _afterPatchAllHooks); TryAddHook(patch, "BeforeUnpatchAll", _beforeUnpatchAllHooks); TryAddHook(patch, "AfterUnpatchAll", _afterUnpatchAllHooks); TryAddMetadataHook(patch); } } public Mutator(AbstractMutatorSettings settings, Type patch, IList<Func<bool>> conditions = null, bool specialActionOverlay = false) : this(settings, new List<Type>(1) { patch }, conditions, specialActionOverlay) { } public void Patch() { RepoMutators.Logger.LogDebug((object)$"{Name} active: {Active}"); if (Active) { return; } RepoMutators.Logger.LogDebug((object)$"About to apply {_patches.Count} patches for {Name}"); Active = true; MutatorManager instance = MutatorManager.Instance; instance.GameStateChanged = (Action<MutatorsGameState>)Delegate.Combine(instance.GameStateChanged, new Action<MutatorsGameState>(TryApplyDeferredMetadata)); LinqExtensions.ForEach<Action>((IEnumerable<Action>)_beforePatchAllHooks, (Action<Action>)delegate(Action action) { action?.Invoke(); }); foreach (Type patch in _patches) { _harmony.PatchAll(patch); RepoMutators.Logger.LogDebug((object)("Applied patch: " + patch.Name)); } LinqExtensions.ForEach<Action>((IEnumerable<Action>)_afterPatchAllHooks, (Action<Action>)delegate(Action action) { action?.Invoke(); }); } public void Unpatch() { if (Active) { MutatorManager instance = MutatorManager.Instance; instance.GameStateChanged = (Action<MutatorsGameState>)Delegate.Remove(instance.GameStateChanged, new Action<MutatorsGameState>(TryApplyDeferredMetadata)); _metadata.Clear(); _pendingDeferredMetadata.Clear(); LinqExtensions.ForEach<Action>((IEnumerable<Action>)_beforeUnpatchAllHooks, (Action<Action>)delegate(Action action) { action?.Invoke(); }); _harmony.UnpatchSelf(); Active = false; LinqExtensions.ForEach<Action>((IEnumerable<Action>)_afterUnpatchAllHooks, (Action<Action>)delegate(Action action) { action?.Invoke(); }); RepoMutators.Logger.LogDebug((object)("Unpatched mutator: " + Name)); } } public void ConsumeMetadata(IDictionary<string, object> metadata) { if (metadata == null || metadata.Count == 0) { return; } IDictionary<string, object> dictionary = metadata; if (metadata.TryGetValue(Settings.MutatorName, out object value) && value is IDictionary<string, object> dictionary2) { dictionary = dictionary2; } Dictionary<string, object> dictionary3 = new Dictionary<string, object>(); IDictionary<string, object> dictionary4 = Settings.AsMetadata() ?? new Dictionary<string, object>(); if (dictionary4.TryGetValue(Settings.MutatorName, out var value2) && value2 is IDictionary<string, object> dictionary5) { dictionary4 = dictionary5; } foreach (var (text2, value3) in dictionary) { if (MutatorManager.Instance.GameState > MutatorsGameState.None || dictionary4.ContainsKey(text2)) { dictionary3[text2] = value3; RepoMutators.Logger.LogDebug((object)("Metadata key '" + text2 + "' immediate for mutator '" + Name + "'.")); } else { _pendingDeferredMetadata[text2] = value3; RepoMutators.Logger.LogDebug((object)("Metadata key '" + text2 + "' deferred for mutator '" + Name + "'.")); } } if (dictionary3.Count > 0) { ApplyMetadata(dictionary3); } } protected void TryApplyDeferredMetadata(MutatorsGameState gameState) { if (gameState == MutatorsGameState.LevelGenerated && _pendingDeferredMetadata.Count != 0) { RepoMutators.Logger.LogDebug((object)("Applying deferred metadata for mutator '" + Name + "'")); ApplyDeferredMetadata(_pendingDeferredMetadata); } } protected void ApplyDeferredMetadata(IDictionary<string, object> pendingDeferredMetadata) { Dictionary<string, object> metadataToApply = new Dictionary<string, object>(pendingDeferredMetadata); pendingDeferredMetadata.Clear(); ApplyMetadata(metadataToApply); } protected void ApplyMetadata(IDictionary<string, object> metadataToApply) { _metadata = _metadata.DeepMergedWith(metadataToApply); RepoMutators.Logger.LogInfo((object)"DeepMerged: "); foreach (KeyValuePair<string, object> metadatum in _metadata) { RepoMutators.Logger.LogInfo((object)$"{metadatum.Key}: {metadatum.Value}"); } LinqExtensions.ForEach<Action<IDictionary<string, object>>>((IEnumerable<Action<IDictionary<string, object>>>)_onMetadataChangedHooks, (Action<Action<IDictionary<string, object>>>)delegate(Action<IDictionary<string, object>> hook) { hook?.Invoke(_metadata); }); } protected static void TryAddHook(Type type, string methodName, IList<Action> hookList) { MethodInfo method = type.GetMethod(methodName, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return; } if (method.GetParameters().Length != 0) { RepoMutators.Logger.LogWarning((object)("Lifecycle hook '" + methodName + "' in type '" + type.FullName + "' must not have parameters.")); return; } if (method.ReturnType != typeof(void)) { RepoMutators.Logger.LogWarning((object)("Lifecycle hook '" + methodName + "' in type '" + type.FullName + "' must return void.")); return; } try { Action item = (Action)Delegate.CreateDelegate(typeof(Action), method); hookList.Add(item); RepoMutators.Logger.LogDebug((object)("Lifecycle hook '" + methodName + "' in type '" + type.FullName + "' was succesfully registered")); } catch (Exception ex) { RepoMutators.Logger.LogError((object)("Failed to bind lifecycle hook '" + methodName + "' in type '" + type.FullName + "': " + ex.Message)); } } protected void TryAddMetadataHook(Type type) { MethodInfo method = type.GetMethod("OnMetadataChanged", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return; } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 1) { RepoMutators.Logger.LogWarning((object)("Lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "' must have one parameter of type IDictionary<string, object>.")); return; } if (method.ReturnType != typeof(void)) { RepoMutators.Logger.LogWarning((object)("Lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "' must return void.")); return; } if (!typeof(IDictionary<string, object>).IsAssignableFrom(parameters[0].ParameterType)) { RepoMutators.Logger.LogWarning((object)("Lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "' must take a parameter of type IDictionary<string, object> or a compatible type.")); return; } try { Action<IDictionary<string, object>> item = (Action<IDictionary<string, object>>)Delegate.CreateDelegate(typeof(Action<IDictionary<string, object>>), method); _onMetadataChangedHooks.Add(item); RepoMutators.Logger.LogDebug((object)("Lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "' was succesfully registered")); } catch (Exception ex) { RepoMutators.Logger.LogError((object)("Failed to bind lifecycle hook 'OnMetadataChanged' in type '" + type.FullName + "': " + ex.Message)); } } } public static class Mutators { public const string NopMutatorName = "None"; public const string OutWithABangName = "Out With a Bang!"; public const string ApolloElevenName = "Apollo 11"; public const string UltraViolenceName = "Ultra-Violence"; public const string DuckThisName = "Duck This"; public const string ProtectThePresidentName = "Protect the President"; public const string OneShotOneKillName = "One Shot, One Kill"; public const string RustyServosName = "Rusty Servos"; public const string HandleWithCareName = "Handle With Care"; public const string HuntingSeasonName = "Hunting Season"; public const string ThereCanOnlyBeOneName = "There Can Only Be One"; public const string VolatileCargoName = "Volatile Cargo"; public const string SealedAwayName = "Sealed Away"; public const string ProtectTheWeakName = "Protect the Weak"; public const string FiringMyLaserName = "Firing My Laser"; public const string VoiceoverName = "Voiceover"; public const string TheFloorIsLavaName = "The Floor Is Lava"; public const string LessIsMoreName = "Less Is More"; public const string FragmentationProtocolName = "Fragmentation Protocol"; public const string AmalgamName = "Amalgam"; public const string NopMutatorDescription = "A normal run, no special effects"; public const string OutWithABangDescription = "Monsters explode on death"; public const string ApolloElevenDescription = "Level-wide Zero-Gravity"; public const string UltraViolenceDescription = "Immediately activates the final extraction phase"; public const string DuckThisDescription = "Ducks aggro on sight instead of on interaction\nAlways spawn at least 1 duck"; public const string ProtectThePresidentDescription = "A random player becomes the \"President\"\nIf they die, everyone else self-destructs"; public const string OneShotOneKillDescription = "Any damage taken by a player is lethal"; public const string RustyServosDescription = "Players cannot jump\n+3 Grab Range"; public const string HandleWithCareDescription = "Valuables are worth more but break on any impact"; public const string HuntingSeasonDescription = "No valuables spawn, weapons spawn instead\nEnemy respawn time reduced to 10 seconds\nOrb drop cap is removed"; public const string ThereCanOnlyBeOneDescription = "All monster spawns are of the same type"; public const string VolatileCargoDescription = "Valuables explode on destruction\nExplosion radius and strength based on value"; public const string SealedAwayDescription = "Breaking valuables has a chance to spawn monsters"; public const string ProtectTheWeakDescription = "Protect your weaker friends!"; public const string FiringMyLaserDescription = "Fire your laser by pressing {specialActionKey}\nUncontrollably fire your laser when taking damage"; public const string VoiceoverDescription = "Player voices are shuffled"; public const string TheFloorIsLavaDescription = "You take damage while standing on the floor"; public const string LessIsMoreDescription = "Valuables are worth less but gain value when hit\nNormal breaking mechanics apply"; public const string AmalgamDescription = "You’ve been here before — just not all at once"; internal static string[] All() { return new string[18] { "None", "Out With a Bang!", "Apollo 11", "Ultra-Violence", "Duck This", "Protect the President", "Rusty Servos", "Handle With Care", "Hunting Season", "There Can Only Be One", "Volatile Cargo", "Sealed Away", "Protect the Weak", "Firing My Laser", "Voiceover", "The Floor Is Lava", "Less Is More", "Amalgam" }; } } public sealed class NopMutator : IMutator { private static readonly IReadOnlyList<Type> _patches = Array.Empty<Type>(); private static readonly IReadOnlyList<Func<bool>> _conditions = Array.Empty<Func<bool>>(); public string Name => "None"; public string Description => "A normal run, no special effects"; public bool Active { get; private set; } public AbstractMutatorSettings Settings { get; private set; } public IReadOnlyList<Type> Patches => _patches; public IReadOnlyList<Func<bool>> Conditions => _conditions; public bool HasSpecialAction => false; internal NopMutator(AbstractMutatorSettings settings) { Settings = settings; } public void Patch() { Active = true; } public void Unpatch() { Active = false; } public void ConsumeMetadata(IDictionary<string, object> metadata) { } } } namespace Mutators.Mutators.Patches { internal class AmalgamPatch { private static bool initDone = false; private static Level actualLevel = null; private static readonly IDictionary<GameObject, Level> roomParentLevelMap = new Dictionary<GameObject, Level>(); [HarmonyPrefix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("SpawnModule")] private static void LevelGeneratorSpawnModulePrefix(LevelGenerator __instance) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown if (!SemiFunc.IsMasterClientOrSingleplayer() || initDone) { return; } actualLevel = __instance.Level; __instance.Level = new Level(); actualLevel.ModulesNormal1.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesNormal2.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesNormal3.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesPassage1.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesPassage2.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesPassage3.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesDeadEnd1.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesDeadEnd2.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesDeadEnd3.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesExtraction1.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesExtraction2.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); actualLevel.ModulesExtraction3.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = actualLevel; }); RepoMutators.Logger.LogInfo((object)"[Amalgam] Building level from the following available levels:"); foreach (Level allEligibleLevel in GetAllEligibleLevels()) { RepoMutators.Logger.LogInfo((object)("[Amalgam] " + ((Object)allEligibleLevel).name)); AddNormalModules(__instance, allEligibleLevel); AddPassageModules(__instance, allEligibleLevel); AddDeadEndModules(__instance, allEligibleLevel); AddExtractionModules(__instance, allEligibleLevel); } initDone = true; } [HarmonyPrefix] [HarmonyPatch(typeof(EnvironmentDirector))] [HarmonyPatch("Setup")] private static void EnvironmentDirectorSetupPrefix() { if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)actualLevel != (Object)null) { LevelGenerator.Instance.Level = actualLevel; roomParentLevelMap.Clear(); } } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator))] [HarmonyPatch("PickModule")] private static void LevelGeneratorPickModulePrefix(LevelGenerator __instance, ref GameObject __result) { if (SemiFunc.IsMasterClientOrSingleplayer()) { if (roomParentLevelMap.TryGetValue(__result, out Level value)) { __instance.Level.ResourcePath = value.ResourcePath; } else { RepoMutators.Logger.LogError((object)("Failed to determine to which level module " + ((Object)__result).name + " belongs!")); } } } private static void AddNormalModules(LevelGenerator levelGenerator, Level level) { Level level2 = level; levelGenerator.ModulesNormalShuffled_1.AddRange(level2.ModulesNormal1); levelGenerator.ModulesNormalShuffled_2.AddRange(level2.ModulesNormal2); levelGenerator.ModulesNormalShuffled_3.AddRange(level2.ModulesNormal3); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesNormalShuffled_1); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesNormalShuffled_2); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesNormalShuffled_3); level2.ModulesNormal1.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); level2.ModulesNormal2.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); level2.ModulesNormal3.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); } private static void AddPassageModules(LevelGenerator levelGenerator, Level level) { Level level2 = level; levelGenerator.ModulesPassageShuffled_1.AddRange(level2.ModulesPassage1); levelGenerator.ModulesPassageShuffled_2.AddRange(level2.ModulesPassage2); levelGenerator.ModulesPassageShuffled_3.AddRange(level2.ModulesPassage3); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesPassageShuffled_1); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesPassageShuffled_2); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesPassageShuffled_3); level2.ModulesPassage1.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); level2.ModulesPassage2.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); level2.ModulesPassage3.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); } private static void AddDeadEndModules(LevelGenerator levelGenerator, Level level) { Level level2 = level; levelGenerator.ModulesDeadEndShuffled_1.AddRange(level2.ModulesDeadEnd1); levelGenerator.ModulesDeadEndShuffled_2.AddRange(level2.ModulesDeadEnd2); levelGenerator.ModulesDeadEndShuffled_3.AddRange(level2.ModulesDeadEnd3); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesDeadEndShuffled_1); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesDeadEndShuffled_2); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesDeadEndShuffled_3); level2.ModulesDeadEnd1.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); level2.ModulesDeadEnd2.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); level2.ModulesDeadEnd3.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); } private static void AddExtractionModules(LevelGenerator levelGenerator, Level level) { Level level2 = level; levelGenerator.ModulesExtractionShuffled_1.AddRange(level2.ModulesExtraction1); levelGenerator.ModulesExtractionShuffled_2.AddRange(level2.ModulesExtraction2); levelGenerator.ModulesExtractionShuffled_3.AddRange(level2.ModulesExtraction3); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesExtractionShuffled_1); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesExtractionShuffled_2); ListExtension.Shuffle<GameObject>((IList<GameObject>)levelGenerator.ModulesExtractionShuffled_3); level2.ModulesExtraction1.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); level2.ModulesExtraction2.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); level2.ModulesExtraction3.ForEach(delegate(GameObject module) { roomParentLevelMap[module] = level2; }); } private static IList<Level> GetAllEligibleLevels() { ISet<string> excludedSet = new HashSet<string>(MutatorSettings.Amalgam.ExcludedLevels.Select((string level) => (!level.StartsWith("level - ", StringComparison.OrdinalIgnoreCase)) ? ("level - " + level).ToLowerInvariant() : level.ToLowerInvariant())); return (from level in Levels.AllLevels where !((Object)level).name.Equals(((Object)actualLevel).name, StringComparison.OrdinalIgnoreCase) where !excludedSet.Contains(((Object)level).name.ToLowerInvariant()) sel