Decompiled source of Mutators Addon v0.1.0

BepInEx/plugins/GastrodonGroup-Mutators_Addon/MutatorsAddon.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GastrodonGroup.MutatorsAddon.Behaviours;
using GastrodonGroup.MutatorsAddon.MutatorDefinitions.BadDog;
using GastrodonGroup.MutatorsAddon.Patches;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mutators.Enums;
using Mutators.Managers;
using Mutators.Mutators;
using Mutators.Settings;
using REPOLib.Modules;
using UnityEngine;

[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("GastrodonGroup")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+17998fb6623b18b883f128654cfbd0327516ed81")]
[assembly: AssemblyProduct("MutatorsAddon")]
[assembly: AssemblyTitle("MutatorsAddon")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GastrodonGroup.MutatorsAddon
{
	[BepInDependency("Xepos.REPO-Mutators", "1.0.2")]
	[BepInPlugin("GastrodonGroup.MutatorsAddon", "Mutators Addon", "0.1.0")]
	public class MutatorsAddonPlugin : BaseUnityPlugin
	{
		internal static MutatorsAddonPlugin Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			RegisterBadDog();
			RegisterWrongWayMap();
			RegisterSilentStalkers();
			Logger.LogInfo((object)string.Format("{0} v{1} has loaded! Build: {2}", ((BaseUnityPlugin)this).Info.Metadata.GUID, ((BaseUnityPlugin)this).Info.Metadata.Version, "2026-07-04 08:20"));
		}

		private static void RegisterWrongWayMap()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			IMutator val = (IMutator)new Mutator((AbstractMutatorSettings)new GenericMutatorSettings("GastrodonGroup.MutatorsAddon", "MAP-side Down", "The minimap screen is rotated 180 degrees", ((BaseUnityPlugin)Instance).Config), typeof(WrongWayMapPatch), (MutatorDifficulty)3, (IList<Func<bool>>)null, false);
			MutatorManager.Instance.RegisterMutator(val);
			Logger.LogInfo((object)"Registered mutator: MAP-side Down");
		}

		private static void RegisterSilentStalkers()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			IMutator val = (IMutator)new Mutator((AbstractMutatorSettings)new GenericMutatorSettings("GastrodonGroup.MutatorsAddon", "Silent Stalkers", "You cannot hear the enemy sounds", ((BaseUnityPlugin)Instance).Config), typeof(SilentStalkersPatch), (MutatorDifficulty)2, (IList<Func<bool>>)null, false);
			MutatorManager.Instance.RegisterMutator(val);
			Logger.LogInfo((object)"Registered mutator: Silent Stalkers");
		}

		private static void RegisterBadDog()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			BadDogMutator.BindConfig(((BaseUnityPlugin)Instance).Config);
			IMutator val = (IMutator)new Mutator((AbstractMutatorSettings)new GenericMutatorSettings("GastrodonGroup.MutatorsAddon", "Watchdog Out!", "Elsa transforms on sight instead of waiting for pets", ((BaseUnityPlugin)Instance).Config), typeof(BadDogPatch), (MutatorDifficulty)3, (IList<Func<bool>>)null, false);
			MutatorManager.Instance.RegisterMutator(val);
			Logger.LogInfo((object)"Registered mutator: Watchdog Out!");
		}
	}
	internal static class PluginInfo
	{
		internal const string PLUGIN_GUID = "GastrodonGroup.MutatorsAddon";

		internal const string PLUGIN_NAME = "Mutators Addon";

		internal const string PLUGIN_VERSION = "0.1.0";

		internal const string THUNDERSTORE_PACKAGE_NAME = "Mutators_Addon";
	}
	internal static class BuildInfo
	{
		internal const string Timestamp = "2026-07-04 08:20";
	}
}
namespace GastrodonGroup.MutatorsAddon.Patches
{
	internal class BadDogPatch
	{
		private const string ElsaEnemyName = "Elsa";

		private const string ElsaSetupName = "Enemy - Elsa";

		[HarmonyPostfix]
		[HarmonyPriority(99)]
		[HarmonyPatch(typeof(EnemyDirector), "AmountSetup")]
		private static void EnemyDirectorAmountSetupPostfix(EnemyDirector __instance)
		{
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			IList<EnemySetup> enemyList = __instance.enemyList;
			if (enemyList.Any((EnemySetup setup) => setup.spawnObjects.Select((PrefabRef so) => ((PrefabRef<GameObject>)(object)so).Prefab.GetComponent<EnemyParent>()).Any((EnemyParent ep) => (Object)(object)ep != (Object)null && ep.enemyName == "Elsa")))
			{
				return;
			}
			EnemySetup val = ((IEnumerable<EnemySetup>)Enemies.AllEnemies).FirstOrDefault((Func<EnemySetup, bool>)((EnemySetup setup) => ((Object)setup).name == "Enemy - Elsa"));
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			IList<EnemySetup> list = enemyList.Where(delegate(EnemySetup setup)
			{
				IEnumerable<EnemyParent> source = from so in setup.spawnObjects
					select ((PrefabRef<GameObject>)(object)so).Prefab.GetComponent<EnemyParent>() into ep
					where (Object)(object)ep != (Object)null
					select ep;
				return source.All((EnemyParent ep) => (int)ep.difficulty == 0) && source.All((EnemyParent ep) => ep.enemyName != "Elsa");
			}).ToList();
			if (list.Count == 0)
			{
				MutatorsAddonPlugin.Logger.LogWarning((object)"No suitable enemies found to replace with Elsa");
				return;
			}
			EnemySetup item = list[Random.Range(0, list.Count)];
			if (enemyList.Remove(item))
			{
				enemyList.Add(val);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(EnemyElsa), "Update")]
		private static void EnemyElsaUpdatePrefix(EnemyElsa __instance)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Invalid comparison between Unknown and I4
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Invalid comparison between Unknown and I4
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			BadDogBehaviour badDogBehaviour = ((Component)__instance).GetComponent<BadDogBehaviour>() ?? ((Component)__instance).gameObject.AddComponent<BadDogBehaviour>();
			State currentState = __instance.currentState;
			if (currentState - 6 <= 2)
			{
				if (badDogBehaviour.CanNotice())
				{
					__instance.UpdateState((State)24);
				}
			}
			else if ((int)__instance.currentState == 25)
			{
				badDogBehaviour.PendingLeaveAfterShrink = true;
			}
			else if ((int)__instance.currentState == 1 && badDogBehaviour.PendingLeaveAfterShrink)
			{
				badDogBehaviour.PendingLeaveAfterShrink = false;
				__instance.playerTarget = null;
				__instance.UpdateState((State)16);
				badDogBehaviour.NoticeCooldown = BadDogMutator.TransformCooldown.Value;
			}
		}
	}
	internal class SilentStalkersPatch
	{
		private const string WesleysEnemiesPluginGuid = "WesleysEnemies";

		private static readonly HashSet<Sound> EnemySounds = new HashSet<Sound>();

		private static readonly Dictionary<int, HashSet<Sound>> SoundsByParentId = new Dictionary<int, HashSet<Sound>>();

		private static readonly Dictionary<Type, FieldInfo[]> SoundFieldsByType = new Dictionary<Type, FieldInfo[]>();

		private static readonly Dictionary<string, string[]> WesleyMutedAudioSourceFields = new Dictionary<string, string[]> { ["Shotgunner"] = new string[1] { "ambientAudio" } };

		[HarmonyPostfix]
		[HarmonyPatch(typeof(EnemyParent), "SpawnRPC")]
		private static void EnemyParentSpawnPostfix(EnemyParent __instance)
		{
			RegisterEnemySounds(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(EnemyParent), "DespawnRPC")]
		private static void EnemyParentDespawnPostfix(EnemyParent __instance)
		{
			UnregisterEnemySounds(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Sound), "Play", new Type[]
		{
			typeof(Vector3),
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(float)
		})]
		private static bool SoundPlayVector3Prefix(Sound __instance)
		{
			return !ShouldMuteSound(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Sound), "Play", new Type[]
		{
			typeof(Transform),
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(float)
		})]
		private static bool SoundPlayTransformPrefix(Sound __instance, Transform followTarget)
		{
			return !ShouldMuteSound(__instance, followTarget);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Sound), "Play", new Type[]
		{
			typeof(Transform),
			typeof(Vector3),
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(float)
		})]
		private static bool SoundPlayTransformContactPrefix(Sound __instance, Transform followTarget)
		{
			return !ShouldMuteSound(__instance, followTarget);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Sound), "PlayLoop")]
		private static bool SoundPlayLoopPrefix(Sound __instance, bool playing)
		{
			if (!playing)
			{
				return true;
			}
			return !ShouldMuteSound(__instance);
		}

		internal static void AfterPatchAll()
		{
			ClearRegistry();
			EnemyParent[] array = Object.FindObjectsByType<EnemyParent>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (EnemyParent parent in array)
			{
				RegisterEnemySounds(parent);
			}
		}

		internal static void AfterUnpatchAll()
		{
			ClearRegistry();
		}

		private static bool ShouldMuteSound(Sound sound, Transform? followTarget = null)
		{
			if (EnemySounds.Contains(sound))
			{
				return true;
			}
			if ((Object)(object)followTarget != (Object)null && IsUnderEnemyHierarchy(followTarget))
			{
				return true;
			}
			if ((Object)(object)sound.Source != (Object)null)
			{
				return IsUnderEnemyHierarchy(((Component)sound.Source).transform);
			}
			return false;
		}

		private static bool IsUnderEnemyHierarchy(Transform root)
		{
			if (!((Object)(object)((Component)root).GetComponentInParent<EnemyParent>(true) != (Object)null))
			{
				return (Object)(object)((Component)root).GetComponentInParent<Enemy>(true) != (Object)null;
			}
			return true;
		}

		private static void RegisterEnemySounds(EnemyParent parent)
		{
			int instanceID = ((Object)parent).GetInstanceID();
			if (SoundsByParentId.ContainsKey(instanceID))
			{
				return;
			}
			HashSet<Sound> hashSet = new HashSet<Sound>();
			MonoBehaviour[] componentsInChildren = ((Component)parent).GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				FieldInfo[] soundFields = GetSoundFields(((object)val).GetType());
				foreach (FieldInfo fieldInfo in soundFields)
				{
					object? value = fieldInfo.GetValue(val);
					Sound val2 = (Sound)((value is Sound) ? value : null);
					if (val2 != null)
					{
						hashSet.Add(val2);
					}
				}
			}
			SoundsByParentId[instanceID] = hashSet;
			foreach (Sound item in hashSet)
			{
				EnemySounds.Add(item);
			}
			if (Chainloader.PluginInfos.ContainsKey("WesleysEnemies"))
			{
				MuteWesleyExtraAudio(parent);
			}
		}

		private static void MuteWesleyExtraAudio(EnemyParent parent)
		{
			bool flag = false;
			MonoBehaviour[] componentsInChildren = ((Component)parent).GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || ((object)val).GetType().Assembly.GetName().Name != "WesleysEnemies")
				{
					continue;
				}
				if (WesleyMutedAudioSourceFields.TryGetValue(((object)val).GetType().Name, out string[] value))
				{
					string[] array = value;
					foreach (string fieldName in array)
					{
						TryMuteAudioSourceField(val, fieldName);
					}
				}
				if (((object)val).GetType().Name == "Gusher")
				{
					flag = true;
				}
			}
			if (flag)
			{
				MuteGusherAmbienceAudioSources(parent);
			}
		}

		private static void MuteGusherAmbienceAudioSources(EnemyParent parent)
		{
			Transform[] componentsInChildren = ((Component)parent).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (!(((Object)val).name != "Ambience"))
				{
					AudioSource[] components = ((Component)val).GetComponents<AudioSource>();
					foreach (AudioSource val2 in components)
					{
						val2.mute = true;
					}
				}
			}
		}

		private static void TryMuteAudioSourceField(MonoBehaviour mb, string fieldName)
		{
			object? obj = ((object)mb).GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(mb);
			AudioSource val = (AudioSource)((obj is AudioSource) ? obj : null);
			if (val != null)
			{
				val.mute = true;
			}
		}

		private static void UnregisterEnemySounds(EnemyParent parent)
		{
			int instanceID = ((Object)parent).GetInstanceID();
			if (!SoundsByParentId.Remove(instanceID, out HashSet<Sound> value))
			{
				return;
			}
			foreach (Sound item in value)
			{
				EnemySounds.Remove(item);
			}
		}

		private static void ClearRegistry()
		{
			EnemySounds.Clear();
			SoundsByParentId.Clear();
		}

		private static FieldInfo[] GetSoundFields(Type type)
		{
			if (SoundFieldsByType.TryGetValue(type, out FieldInfo[] value))
			{
				return value;
			}
			List<FieldInfo> list = new List<FieldInfo>();
			Type type2 = type;
			while (type2 != null && type2 != typeof(MonoBehaviour))
			{
				FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (fieldInfo.FieldType == typeof(Sound))
					{
						list.Add(fieldInfo);
					}
				}
				type2 = type2.BaseType;
			}
			FieldInfo[] array = list.ToArray();
			SoundFieldsByType[type] = array;
			return array;
		}
	}
	internal class WrongWayMapPatch
	{
		private static readonly int MainTexStId = Shader.PropertyToID("_MainTex_ST");

		private static readonly Vector4 FlippedMainTexSt = new Vector4(-1f, -1f, 1f, 1f);

		private static readonly MaterialPropertyBlock FlipPropertyBlock = new MaterialPropertyBlock();

		private static int _flippedDisplayMeshId;

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(MapToolController), "Update")]
		private static void MapToolControllerUpdatePostfix(MapToolController __instance)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance.PlayerAvatar != (Object)(object)PlayerAvatar.instance)
			{
				return;
			}
			MeshRenderer displayMesh = __instance.DisplayMesh;
			if (!((Object)(object)displayMesh == (Object)null))
			{
				int instanceID = ((Object)displayMesh).GetInstanceID();
				if (ShouldFlipDisplay(__instance))
				{
					((Renderer)displayMesh).GetPropertyBlock(FlipPropertyBlock);
					FlipPropertyBlock.SetVector(MainTexStId, FlippedMainTexSt);
					((Renderer)displayMesh).SetPropertyBlock(FlipPropertyBlock);
					_flippedDisplayMeshId = instanceID;
				}
				else if (_flippedDisplayMeshId == instanceID)
				{
					((Renderer)displayMesh).SetPropertyBlock((MaterialPropertyBlock)null);
					_flippedDisplayMeshId = 0;
				}
			}
		}

		private static bool ShouldFlipDisplay(MapToolController controller)
		{
			if (((Component)controller.VisualTransform).gameObject.activeSelf)
			{
				return controller.HideLerp < 1f;
			}
			return false;
		}

		internal static void AfterUnpatchAll()
		{
			_flippedDisplayMeshId = 0;
			MapToolController[] array = Object.FindObjectsByType<MapToolController>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (MapToolController val in array)
			{
				if ((Object)(object)val.DisplayMesh != (Object)null)
				{
					((Renderer)val.DisplayMesh).SetPropertyBlock((MaterialPropertyBlock)null);
				}
			}
		}
	}
}
namespace GastrodonGroup.MutatorsAddon.MutatorDefinitions.WrongWayMap
{
	internal static class WrongWayMapMutator
	{
		internal const string Name = "MAP-side Down";

		internal const string Description = "The minimap screen is rotated 180 degrees";
	}
}
namespace GastrodonGroup.MutatorsAddon.MutatorDefinitions.SilentStalkers
{
	internal static class SilentStalkersMutator
	{
		internal const string Name = "Silent Stalkers";

		internal const string Description = "You cannot hear the enemy sounds";
	}
}
namespace GastrodonGroup.MutatorsAddon.MutatorDefinitions.BadDog
{
	internal static class BadDogMutator
	{
		internal const string Name = "Watchdog Out!";

		internal const string Description = "Elsa transforms on sight instead of waiting for pets";

		internal static ConfigEntry<float> TransformCooldown { get; private set; }

		internal static void BindConfig(ConfigFile config)
		{
			TransformCooldown = config.Bind<float>("Watchdog Out!", "Transform cooldown", 50f, "Seconds before Elsa can instantly transform again after leaving.");
		}
	}
}
namespace GastrodonGroup.MutatorsAddon.Behaviours
{
	internal class BadDogBehaviour : MonoBehaviour
	{
		public float NoticeCooldown { get; internal set; }

		internal bool PendingLeaveAfterShrink { get; set; }

		private void Update()
		{
			if (!(NoticeCooldown <= 0f) && SemiFunc.IsMasterClientOrSingleplayer())
			{
				NoticeCooldown -= Time.deltaTime;
			}
		}

		internal bool CanNotice()
		{
			return NoticeCooldown <= 0f;
		}
	}
}