Decompiled source of Taborusic Modpack v0.3.6

plugins/TestPackCompatibilityFix/TestPackCompatibilityFix.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using TMPro;
using UnityEngine;

[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.1.0.0")]
namespace TestPackCompatibilityFix;

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("dieforlol1.testpack.compatibilityfix", "TestPack Compatibility Fix", "0.1.0")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "dieforlol1.testpack.compatibilityfix";

	public const string PluginName = "TestPack Compatibility Fix";

	public const string PluginVersion = "0.1.0";

	internal static ManualLogSource ModLogger;

	private void Awake()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		ModLogger = ((BaseUnityPlugin)this).Logger;
		new Harmony("dieforlol1.testpack.compatibilityfix").PatchAll(typeof(Plugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"TestPack Compatibility Fix 0.1.0 loaded");
	}
}
internal static class RagdollTagCompatibility
{
	internal const string IndexedTagFormat = "PlayerRagdoll{0}";

	internal const string GenericRagdollTag = "PlayerRagdoll";

	internal static string FormatRagdollTag(string format, object playerIdValue)
	{
		if (format == "PlayerRagdoll{0}" && TryConvertPlayerId(playerIdValue, out var playerId) && playerId >= 4)
		{
			return "PlayerRagdoll";
		}
		return string.Format(format, playerIdValue);
	}

	private static bool TryConvertPlayerId(object value, out int playerId)
	{
		try
		{
			playerId = Convert.ToInt32(value);
			return true;
		}
		catch
		{
			playerId = -1;
			return false;
		}
	}
}
[HarmonyPatch(typeof(DeadBodyInfo), "Start")]
internal static class DeadBodyInfoStartPatch
{
	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		MethodInfo objB = AccessTools.Method(typeof(string), "Format", new Type[2]
		{
			typeof(string),
			typeof(object)
		}, (Type[])null);
		MethodInfo operand = AccessTools.Method(typeof(RagdollTagCompatibility), "FormatRagdollTag", (Type[])null, (Type[])null);
		int num = 0;
		for (int i = 0; i < list.Count; i++)
		{
			CodeInstruction val = list[i];
			bool flag = false;
			for (int j = Math.Max(0, i - 5); j < i; j++)
			{
				if (list[j].opcode == OpCodes.Ldstr && string.Equals(list[j].operand as string, "PlayerRagdoll{0}", StringComparison.Ordinal))
				{
					flag = true;
					break;
				}
			}
			bool flag2 = (val.opcode == OpCodes.Call || val.opcode == OpCodes.Callvirt) && object.Equals(val.operand, objB);
			if (flag && flag2)
			{
				val.opcode = OpCodes.Call;
				val.operand = operand;
				num++;
			}
		}
		if (num != 1)
		{
			Plugin.ModLogger.LogError((object)("Ragdoll tag patch expected one replacement, got " + num + "."));
		}
		return list;
	}
}
[HarmonyPatch(typeof(PlayerPhysicsRegion), "OnTriggerStay")]
internal static class PlayerPhysicsRegionPatch
{
	private static bool Prefix(PlayerPhysicsRegion __instance, Collider other)
	{
		if ((Object)(object)other == (Object)null || ((Component)other).gameObject.layer != 20 || ((Object)((Component)other).gameObject).name != "spine.002")
		{
			return true;
		}
		DeadBodyInfo componentInParent = ((Component)other).GetComponentInParent<DeadBodyInfo>();
		if ((Object)(object)componentInParent == (Object)null || componentInParent.playerObjectId < 4)
		{
			return true;
		}
		if (!componentInParent.isParentedToPhysicsRegion)
		{
			componentInParent.SetPhysicsParent(__instance.physicsTransform, __instance.physicsCollider);
		}
		return false;
	}
}
internal static class RadarNameCompatibility
{
	internal static void Repair(ManualCameraRenderer renderer, bool updateVisibleLabel)
	{
		if ((Object)(object)renderer == (Object)null || renderer.radarTargets == null)
		{
			return;
		}
		int num = 0;
		for (int i = 0; i < renderer.radarTargets.Count; i++)
		{
			TransformAndName val = renderer.radarTargets[i];
			if (val != null && !((Object)(object)val.transform == (Object)null))
			{
				PlayerControllerB component = ((Component)val.transform).gameObject.GetComponent<PlayerControllerB>();
				if (!((Object)(object)component == (Object)null) && !string.IsNullOrEmpty(component.playerUsername) && !LabelBelongsToPlayer(val.name, component.playerUsername))
				{
					val.name = component.playerUsername;
					num++;
				}
			}
		}
		if (num > 0)
		{
			Plugin.ModLogger.LogDebug((object)("Repaired " + num + " mismatched radar player name(s)."));
		}
		if (updateVisibleLabel && renderer.targetTransformIndex >= 0 && renderer.targetTransformIndex < renderer.radarTargets.Count && !((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)StartOfRound.Instance.mapScreenPlayerName == (Object)null))
		{
			TransformAndName val2 = renderer.radarTargets[renderer.targetTransformIndex];
			if (val2 != null)
			{
				((TMP_Text)StartOfRound.Instance.mapScreenPlayerName).text = val2.name ?? string.Empty;
			}
		}
	}

	private static bool LabelBelongsToPlayer(string label, string username)
	{
		if (string.Equals(label, username, StringComparison.Ordinal))
		{
			return true;
		}
		if (string.IsNullOrEmpty(label) || !label.StartsWith(username, StringComparison.Ordinal) || label.Length == username.Length)
		{
			return false;
		}
		for (int i = username.Length; i < label.Length; i++)
		{
			if (!char.IsDigit(label[i]))
			{
				return false;
			}
		}
		return true;
	}
}
[HarmonyPatch(typeof(PlayerControllerB), "SendNewPlayerValuesClientRpc")]
internal static class NewPlayerValuesPatch
{
	private static void Postfix()
	{
		if ((Object)(object)StartOfRound.Instance != (Object)null)
		{
			RadarNameCompatibility.Repair(StartOfRound.Instance.mapScreen, updateVisibleLabel: true);
		}
	}
}
[HarmonyPatch(typeof(ManualCameraRenderer), "SyncOrderOfRadarBoostersInList")]
internal static class RadarOrderPatch
{
	private static void Postfix(ManualCameraRenderer __instance)
	{
		RadarNameCompatibility.Repair(__instance, updateVisibleLabel: true);
	}
}
[HarmonyPatch(typeof(ManualCameraRenderer), "updateMapTarget")]
internal static class UpdateMapTargetPatch
{
	private static void Prefix(ManualCameraRenderer __instance)
	{
		RadarNameCompatibility.Repair(__instance, updateVisibleLabel: false);
	}
}
[HarmonyPatch(typeof(ManualCameraRenderer), "UpdateRadarTargetName")]
internal static class UpdateRadarTargetNamePatch
{
	private static void Prefix(ManualCameraRenderer __instance)
	{
		RadarNameCompatibility.Repair(__instance, updateVisibleLabel: false);
	}
}
[HarmonyPatch]
internal static class FacilityMeltdownEnemyFilterPatch
{
	private static readonly HashSet<string> LoggedEnemyNames = new HashSet<string>(StringComparer.Ordinal);

	private static bool Prepare()
	{
		return AccessTools.TypeByName("FacilityMeltdown.MeltdownSequence.Behaviours.MeltdownHandler+<>c__DisplayClass20_0") != null;
	}

	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("FacilityMeltdown.MeltdownSequence.Behaviours.MeltdownHandler+<>c__DisplayClass20_0");
		if (!(type == null))
		{
			return AccessTools.Method(type, "<HandleEnemies>b__0", (Type[])null, (Type[])null);
		}
		return null;
	}

	private static bool Prefix(SpawnableEnemyWithRarity enemy, ref bool __result)
	{
		if (enemy == null || (Object)(object)enemy.enemyType == (Object)null)
		{
			__result = false;
			return false;
		}
		Type type = AccessTools.TypeByName("Dawn.EnemyTypeExtensions");
		MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "GetDawnInfo", new Type[1] { typeof(EnemyType) }, (Type[])null));
		if (methodInfo == null)
		{
			return true;
		}
		object obj;
		try
		{
			obj = methodInfo.Invoke(null, new object[1] { enemy.enemyType });
		}
		catch (Exception ex)
		{
			Plugin.ModLogger.LogWarning((object)("Could not check FacilityMeltdown enemy metadata: " + ex.GetBaseException().Message));
			__result = false;
			return false;
		}
		if (obj != null)
		{
			return true;
		}
		string text = (string.IsNullOrEmpty(enemy.enemyType.enemyName) ? ((Object)enemy.enemyType).name : enemy.enemyType.enemyName);
		if (LoggedEnemyNames.Add(text))
		{
			Plugin.ModLogger.LogDebug((object)("FacilityMeltdown skipped enemy without Dawn metadata: " + text));
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch]
internal static class FacilityMeltdownEmergencyLightsPatch
{
	private static bool Prepare()
	{
		return AccessTools.TypeByName("FacilityMeltdown.MeltdownSequence.MeltdownEffects+<EmergencyLights>d__8") != null;
	}

	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("FacilityMeltdown.MeltdownSequence.MeltdownEffects+<EmergencyLights>d__8");
		if (!(type == null))
		{
			return AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null);
		}
		return null;
	}

	private static bool Prefix(ref bool __result)
	{
		RoundManager instance = RoundManager.Instance;
		if ((Object)(object)instance == (Object)null || instance.allPoweredLightsAnimators == null)
		{
			__result = false;
			return false;
		}
		instance.allPoweredLightsAnimators.RemoveAll((Animator animator) => (Object)(object)animator == (Object)null);
		return true;
	}
}
[HarmonyPatch]
internal static class TheCabinetFollowingStatePatch
{
	private static FieldInfo ownerField;

	private static bool Prepare()
	{
		return AccessTools.TypeByName("TheCabinet.CabinetState_Following") != null;
	}

	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("TheCabinet.CabinetState_Following");
		if (type == null)
		{
			return null;
		}
		ownerField = AccessTools.Field(type.BaseType, "owner");
		return AccessTools.Method(type, "ExecuteSlow", (Type[])null, (Type[])null);
	}

	private static bool Prefix(object __instance)
	{
		if (ownerField == null)
		{
			return true;
		}
		object? value = ownerField.GetValue(__instance);
		EnemyAI val = (EnemyAI)((value is EnemyAI) ? value : null);
		if ((Object)(object)val != (Object)null)
		{
			return (Object)(object)val.targetPlayer != (Object)null;
		}
		return false;
	}
}
[HarmonyPatch]
internal static class CoronerGiantSapsuckerLogPatch
{
	private static MethodInfo validatePlayerDead;

	private static bool Prepare()
	{
		if (AccessTools.TypeByName("Coroner.Patch.GiantKiwiAIAnimationEventBPatch") != null)
		{
			return AccessTools.TypeByName("Coroner.Patch.CauseOfDeathPatchState") != null;
		}
		return false;
	}

	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("Coroner.Patch.GiantKiwiAIAnimationEventBPatch");
		Type type2 = AccessTools.TypeByName("Coroner.Patch.CauseOfDeathPatchState");
		validatePlayerDead = ((type2 == null) ? null : AccessTools.Method(type2, "ValidateIsPlayerDead", new Type[1] { typeof(bool) }, (Type[])null));
		if (!(type == null))
		{
			return AccessTools.Method(type, "Postfix", (Type[])null, (Type[])null);
		}
		return null;
	}

	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		int num = 0;
		for (int i = 1; i < list.Count; i++)
		{
			CodeInstruction val = list[i];
			if ((val.opcode == OpCodes.Call || val.opcode == OpCodes.Callvirt) && object.Equals(val.operand, validatePlayerDead) && list[i - 1].opcode == OpCodes.Ldc_I4_1)
			{
				list[i - 1].opcode = OpCodes.Ldc_I4_0;
				list[i - 1].operand = null;
				num++;
			}
		}
		if (num != 1)
		{
			Plugin.ModLogger.LogWarning((object)("Coroner Giant Sapsucker log patch expected one replacement, got " + num + "."));
		}
		return list;
	}
}
[HarmonyPatch(typeof(PlayerControllerB), "DestroyItemInSlot")]
internal static class DestroyItemInUtilitySlotPatch
{
	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Expected O, but got Unknown
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		MethodInfo objB = AccessTools.PropertyGetter(typeof(HUDManager), "Instance");
		FieldInfo objB2 = AccessTools.Field(typeof(HUDManager), "itemSlotIcons");
		MethodInfo objB3 = AccessTools.PropertySetter(typeof(Behaviour), "enabled");
		MethodInfo methodInfo = AccessTools.Method(typeof(DestroyItemInUtilitySlotPatch), "UpdateSlotIcon", (Type[])null, (Type[])null);
		int num = 0;
		for (int i = 0; i + 5 < list.Count; i++)
		{
			if ((list[i].opcode == OpCodes.Call || list[i].opcode == OpCodes.Callvirt) && object.Equals(list[i].operand, objB) && list[i + 1].opcode == OpCodes.Ldfld && object.Equals(list[i + 1].operand, objB2) && list[i + 2].opcode == OpCodes.Ldarg_1 && list[i + 3].opcode == OpCodes.Ldelem_Ref && list[i + 4].opcode == OpCodes.Ldc_I4_0 && (list[i + 5].opcode == OpCodes.Call || list[i + 5].opcode == OpCodes.Callvirt) && object.Equals(list[i + 5].operand, objB3))
			{
				CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_1, (object)null);
				val.labels.AddRange(list[i].labels);
				val.blocks.AddRange(list[i].blocks);
				CodeInstruction val2 = new CodeInstruction(OpCodes.Call, (object)methodInfo);
				val2.labels.AddRange(list[i + 5].labels);
				val2.blocks.AddRange(list[i + 5].blocks);
				list.RemoveRange(i, 6);
				list.Insert(i, val2);
				list.Insert(i, val);
				num++;
				i++;
			}
		}
		if (num != 1)
		{
			Plugin.ModLogger.LogWarning((object)("Utility-slot icon patch expected one replacement, got " + num + "."));
		}
		return list;
	}

	private static void UpdateSlotIcon(int itemSlot)
	{
		HUDManager instance = HUDManager.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		if (itemSlot == 50)
		{
			if ((Object)(object)instance.itemOnlySlotIcon != (Object)null)
			{
				((Behaviour)instance.itemOnlySlotIcon).enabled = false;
			}
		}
		else if (instance.itemSlotIcons != null && itemSlot >= 0 && itemSlot < instance.itemSlotIcons.Length && (Object)(object)instance.itemSlotIcons[itemSlot] != (Object)null)
		{
			((Behaviour)instance.itemSlotIcons[itemSlot]).enabled = false;
		}
	}
}

plugins/Taborusic/Taborusic.SonicThumperCompat.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace Taborusic.SonicThumperCompat;

[BepInPlugin("Dieforl0l.Taborusic.SonicThumperCompat", "Taborusic SonicThumper Compatibility", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BaseUnityPlugin
{
	private sealed class RemovedPostfix
	{
		internal MethodBase Target;

		internal string Owner;

		internal HarmonyMethod Method;
	}

	public const string PluginGuid = "Dieforl0l.Taborusic.SonicThumperCompat";

	public const string PluginName = "Taborusic SonicThumper Compatibility";

	public const string PluginVersion = "1.1.0";

	internal const float DefaultChaseVolume = 0.32f;

	private static Plugin instance;

	private readonly HashSet<ChaseAudioLifecycle> activeSources = new HashSet<ChaseAudioLifecycle>();

	private readonly List<RemovedPostfix> removedPostfixes = new List<RemovedPostfix>();

	private FieldInfo angeredAudioField;

	private FieldInfo rpcExecStageField;

	private ConfigEntry<float> chaseVolume;

	private Harmony harmony;

	private bool ready;

	internal float Volume => NormalizeVolume((chaseVolume == null) ? 0.32f : chaseVolume.Value);

	internal static float NormalizeVolume(float value)
	{
		if (float.IsNaN(value) || float.IsInfinity(value))
		{
			return 0.32f;
		}
		return Math.Max(0f, Math.Min(1f, value));
	}

	private void Awake()
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Expected O, but got Unknown
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Expected O, but got Unknown
		chaseVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ChaseVolume", 0.32f, new ConfigDescription("Local Sonic chase music volume; 0 mutes it. Applied to active sources on the next frame.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[0]));
		harmony = new Harmony("Dieforl0l.Taborusic.SonicThumperCompat");
		try
		{
			Type type = AccessTools.TypeByName("SonicThumper.Plugin");
			Type type2 = AccessTools.TypeByName("SonicThumper.Patches.SonicThumperPatch");
			MethodInfo methodInfo = AccessTools.Method(typeof(CrawlerAI), "BeginChasingPlayerClientRpc", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(CrawlerAI), "EatPlayerBodyClientRpc", (Type[])null, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(CrawlerAI), "Start", (Type[])null, (Type[])null);
			MethodInfo methodInfo4 = AccessTools.Method(typeof(CrawlerAI), "KillEnemy", (Type[])null, (Type[])null);
			angeredAudioField = ((type == null) ? null : AccessTools.Field(type, "AngeredAudio"));
			rpcExecStageField = AccessTools.Field(typeof(CrawlerAI), "__rpc_exec_stage");
			if (type2 == null || angeredAudioField == null || !angeredAudioField.IsStatic || angeredAudioField.FieldType != typeof(AudioClip) || methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null || methodInfo4.DeclaringType != typeof(CrawlerAI) || rpcExecStageField == null || !rpcExecStageField.FieldType.IsEnum || Convert.ToInt32(Enum.Parse(rpcExecStageField.FieldType, "Execute")) != 1)
			{
				throw new InvalidOperationException("Required SonicThumper/v81 CrawlerAI members were not found; no replacements applied.");
			}
			List<Patch> list = FindSonicPostfixes(methodInfo, type2, "StartSonicSound");
			List<Patch> list2 = FindSonicPostfixes(methodInfo2, type2, "StopSonicSound");
			if (list.Count == 0 || list2.Count == 0)
			{
				throw new InvalidOperationException("Expected SonicThumper sound postfixes were not found; refusing a partial replacement.");
			}
			RemoveSonicPostfixes(methodInfo, list);
			RemoveSonicPostfixes(methodInfo2, list2);
			harmony.Patch((MethodBase)methodInfo, PatchMethod("SoundRpcPrefix"), PatchMethod("BeginChasingPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, PatchMethod("SoundRpcPrefix"), PatchMethod("EatPlayerPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, PatchMethod("CrawlerKilledPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			HarmonyMethod val = PatchMethod("CrawlerStartPrefix");
			val.priority = 800;
			HarmonyMethod val2 = PatchMethod("CrawlerStartPostfix");
			val2.priority = 0;
			harmony.Patch((MethodBase)methodInfo3, val, val2, (HarmonyMethod)null, PatchMethod("CrawlerStartFinalizer"), (HarmonyMethod)null);
			instance = this;
			ready = true;
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("SonicThumper compatibility 1.1.0 ready: ChaseVolume=" + Volume + "; per-crawler lifecycle/anti-stacking; SoundAPI BitePlayer preserved; chase is local 3D only (no uncancellable radio one-shot)."));
		}
		catch (Exception ex)
		{
			Shutdown();
			((BaseUnityPlugin)this).Logger.LogError((object)("SonicThumper compatibility was not enabled: " + ex));
		}
	}

	private static HarmonyMethod PatchMethod(string name)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		return new HarmonyMethod(AccessTools.Method(typeof(Plugin), name, (Type[])null, (Type[])null));
	}

	private static List<Patch> FindSonicPostfixes(MethodBase target, Type type, string name)
	{
		Patches patchInfo = Harmony.GetPatchInfo(target);
		if (patchInfo != null)
		{
			return patchInfo.Postfixes.Where((Patch p) => p.PatchMethod != null && p.PatchMethod.DeclaringType == type && p.PatchMethod.Name == name).ToList();
		}
		return new List<Patch>();
	}

	private void RemoveSonicPostfixes(MethodBase target, List<Patch> patches)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		foreach (Patch patch in patches)
		{
			List<RemovedPostfix> list = removedPostfixes;
			RemovedPostfix removedPostfix = new RemovedPostfix
			{
				Target = target,
				Owner = patch.owner
			};
			HarmonyMethod val = new HarmonyMethod(patch.PatchMethod);
			val.priority = patch.priority;
			val.before = patch.before;
			val.after = patch.after;
			val.debug = patch.debug;
			val.wrapTryCatch = patch.wrapTryCatch;
			removedPostfix.Method = val;
			list.Add(removedPostfix);
			harmony.Unpatch(target, patch.PatchMethod);
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Replaced " + patches.Count + " SonicThumper postfix(es) on " + target.Name + "."));
	}

	private static void CrawlerStartPrefix(CrawlerAI __instance, out AudioClip __state)
	{
		__state = (((Object)(object)__instance == (Object)null) ? null : __instance.bitePlayerSFX);
	}

	private static void CrawlerStartPostfix(CrawlerAI __instance, AudioClip __state)
	{
		if ((Object)(object)__instance != (Object)null && (Object)(object)__state != (Object)null)
		{
			__instance.bitePlayerSFX = __state;
		}
	}

	private static Exception CrawlerStartFinalizer(CrawlerAI __instance, AudioClip __state, Exception __exception)
	{
		if (__exception != null)
		{
			CrawlerStartPostfix(__instance, __state);
		}
		return __exception;
	}

	private static void SoundRpcPrefix(CrawlerAI __instance, out bool __state)
	{
		Plugin plugin = instance;
		__state = (Object)(object)plugin != (Object)null && plugin.ready && (Object)(object)__instance != (Object)null && ((NetworkBehaviour)__instance).IsClient && ((NetworkBehaviour)__instance).IsSpawned && (Object)(object)((NetworkBehaviour)__instance).NetworkManager != (Object)null && ((NetworkBehaviour)__instance).NetworkManager.IsListening && Convert.ToInt32(plugin.rpcExecStageField.GetValue(__instance)) == 1;
	}

	private static void BeginChasingPostfix(CrawlerAI __instance, bool __state)
	{
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		Plugin plugin = instance;
		if (!__state || (Object)(object)plugin == (Object)null || !plugin.ready || (Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsClient || !((NetworkBehaviour)__instance).IsSpawned || ((EnemyAI)__instance).isEnemyDead || ((EnemyAI)__instance).currentBehaviourStateIndex != 1)
		{
			return;
		}
		object? value = plugin.angeredAudioField.GetValue(null);
		AudioClip val = (AudioClip)((value is AudioClip) ? value : null);
		if ((Object)(object)val == (Object)null || (Object)(object)plugin.FindSource(__instance) != (Object)null)
		{
			return;
		}
		GameObject val2 = new GameObject("TaborusicSonicChaseAudio");
		ChaseAudioLifecycle chaseAudioLifecycle = null;
		try
		{
			val2.transform.SetParent(((Component)__instance).transform, false);
			chaseAudioLifecycle = val2.AddComponent<ChaseAudioLifecycle>();
			chaseAudioLifecycle.Initialize(plugin, __instance, val);
		}
		catch (Exception ex)
		{
			if ((Object)(object)chaseAudioLifecycle != (Object)null)
			{
				chaseAudioLifecycle.Release("initialization-failed");
			}
			else
			{
				Object.Destroy((Object)(object)val2);
			}
			((BaseUnityPlugin)plugin).Logger.LogError((object)("Could not create isolated Sonic chase source: " + ex));
		}
	}

	private static void EatPlayerPostfix(CrawlerAI __instance, bool __state)
	{
		if (__state && (Object)(object)instance != (Object)null)
		{
			instance.StopCrawler(__instance, "eat");
		}
	}

	private static void CrawlerKilledPostfix(CrawlerAI __instance)
	{
		if ((Object)(object)instance != (Object)null && (Object)(object)__instance != (Object)null && ((EnemyAI)__instance).isEnemyDead)
		{
			instance.StopCrawler(__instance, "death");
		}
	}

	private ChaseAudioLifecycle FindSource(CrawlerAI crawler)
	{
		foreach (ChaseAudioLifecycle activeSource in activeSources)
		{
			if ((Object)(object)activeSource != (Object)null && (Object)(object)activeSource.Owner == (Object)(object)crawler)
			{
				return activeSource;
			}
		}
		return null;
	}

	private void StopCrawler(CrawlerAI crawler, string reason)
	{
		if (!((Object)(object)crawler == (Object)null))
		{
			ChaseAudioLifecycle chaseAudioLifecycle = FindSource(crawler);
			if ((Object)(object)chaseAudioLifecycle != (Object)null)
			{
				chaseAudioLifecycle.Release(reason);
			}
		}
	}

	internal void Register(ChaseAudioLifecycle source)
	{
		activeSources.Add(source);
		((BaseUnityPlugin)this).Logger.LogDebug((object)("Sonic chase created; active=" + activeSources.Count));
	}

	internal void Unregister(ChaseAudioLifecycle source, string reason)
	{
		activeSources.Remove(source);
		((BaseUnityPlugin)this).Logger.LogDebug((object)("Sonic chase released (" + reason + "); active=" + activeSources.Count));
	}

	private void OnSceneUnloaded(Scene scene)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		foreach (ChaseAudioLifecycle item in new List<ChaseAudioLifecycle>(activeSources))
		{
			if (!((Object)(object)item != (Object)null))
			{
				continue;
			}
			if (!((Object)(object)item.Owner == (Object)null))
			{
				Scene scene2 = ((Component)item.Owner).gameObject.scene;
				if (((Scene)(ref scene2)).handle != ((Scene)(ref scene)).handle)
				{
					continue;
				}
			}
			item.Release("scene-unloaded");
		}
	}

	private void OnDestroy()
	{
		Shutdown();
	}

	private void Shutdown()
	{
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		ready = false;
		if (object.ReferenceEquals(instance, this))
		{
			instance = null;
		}
		SceneManager.sceneUnloaded -= OnSceneUnloaded;
		foreach (ChaseAudioLifecycle item in new List<ChaseAudioLifecycle>(activeSources))
		{
			if ((Object)(object)item != (Object)null)
			{
				item.Release("plugin-shutdown");
			}
		}
		activeSources.Clear();
		angeredAudioField = null;
		rpcExecStageField = null;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		foreach (RemovedPostfix removed in removedPostfixes)
		{
			try
			{
				Patches patchInfo = Harmony.GetPatchInfo(removed.Target);
				if (patchInfo == null || !patchInfo.Postfixes.Any((Patch p) => p.owner == removed.Owner && p.PatchMethod == removed.Method.method))
				{
					new Harmony(removed.Owner).Patch(removed.Target, (HarmonyMethod)null, removed.Method, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not restore original Sonic postfix: " + ex));
			}
		}
		removedPostfixes.Clear();
	}
}
public sealed class ChaseAudioLifecycle : MonoBehaviour
{
	private Plugin plugin;

	private AudioSource source;

	private bool released;

	internal CrawlerAI Owner { get; private set; }

	internal void Initialize(Plugin ownerPlugin, CrawlerAI crawler, AudioClip clip)
	{
		//IL_00bc: 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_0100: Invalid comparison between Unknown and I4
		plugin = ownerPlugin;
		Owner = crawler;
		source = ((Component)this).gameObject.AddComponent<AudioSource>();
		source.playOnAwake = false;
		source.loop = false;
		source.volume = plugin.Volume;
		AudioSource creatureSFX = ((EnemyAI)crawler).creatureSFX;
		if ((Object)(object)creatureSFX != (Object)null)
		{
			source.outputAudioMixerGroup = creatureSFX.outputAudioMixerGroup;
			source.spatialBlend = creatureSFX.spatialBlend;
			source.spatialize = creatureSFX.spatialize;
			source.dopplerLevel = creatureSFX.dopplerLevel;
			source.spread = creatureSFX.spread;
			source.rolloffMode = creatureSFX.rolloffMode;
			source.minDistance = creatureSFX.minDistance;
			source.maxDistance = creatureSFX.maxDistance;
			source.priority = creatureSFX.priority;
			if ((int)creatureSFX.rolloffMode == 2)
			{
				source.SetCustomCurve((AudioSourceCurveType)0, creatureSFX.GetCustomCurve((AudioSourceCurveType)0));
			}
		}
		source.clip = clip;
		plugin.Register(this);
		source.Play();
	}

	private void LateUpdate()
	{
		if (!released)
		{
			if ((Object)(object)Owner == (Object)null || (Object)(object)plugin == (Object)null)
			{
				Release("owner-destroyed");
			}
			else if (((EnemyAI)Owner).isEnemyDead)
			{
				Release("death");
			}
			else if (!((NetworkBehaviour)Owner).IsSpawned)
			{
				Release("despawn");
			}
			else if (((EnemyAI)Owner).currentBehaviourStateIndex != 1)
			{
				Release("chase-ended");
			}
			else if ((Object)(object)source == (Object)null || !source.isPlaying)
			{
				Release("clip-finished");
			}
			else
			{
				source.volume = plugin.Volume;
			}
		}
	}

	private void OnDisable()
	{
		Release("disabled");
	}

	private void OnDestroy()
	{
		Release("destroyed");
	}

	internal void Release(string reason)
	{
		if (!released)
		{
			released = true;
			if ((Object)(object)source != (Object)null)
			{
				source.Stop();
				source.clip = null;
			}
			source = null;
			Plugin plugin = this.plugin;
			this.plugin = null;
			Owner = null;
			if ((Object)(object)plugin != (Object)null)
			{
				plugin.Unregister(this, reason);
			}
			if ((Object)(object)((Component)this).gameObject != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
}