Decompiled source of CarlUnleashedMod v1.0.2

CarlUnleashedMod.dll

Decompiled 15 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CarlUnleashedMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CarlUnleashedMod")]
[assembly: AssemblyTitle("CarlUnleashedMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 CarlUnleashedMod
{
	internal static class BingBongFace
	{
		public const string ObjectName = "CarlBingBongFace";

		public const string ImageName = "carl_face.png";

		private static Texture2D texture;

		private static Material material;

		private static readonly Dictionary<int, Mesh> meshes = new Dictionary<int, Mesh>();

		private static readonly List<GameObject> spawned = new List<GameObject>();

		private static readonly List<Renderer> hiddenLips = new List<Renderer>();

		private static readonly HashSet<string> described = new HashSet<string>();

		private const int GridSteps = 12;

		private const float ScanSeconds = 2f;

		private static float nextScan;

		public static void Load(string modFolder)
		{
			texture = LoadTexture(modFolder);
			if ((Object)(object)texture == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[BingBongFace] No face image; Bing Bong keeps his own.");
			}
			else
			{
				Plugin.Log.LogInfo((object)$"[BingBongFace] Loaded {((Texture)texture).width}x{((Texture)texture).height} face.");
			}
		}

		private static Texture2D LoadTexture(string modFolder)
		{
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			byte[] array = null;
			string text = Path.Combine(modFolder, "carl_face.png");
			if (File.Exists(text))
			{
				try
				{
					array = File.ReadAllBytes(text);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("[BingBongFace] " + text + ": " + ex.Message));
				}
			}
			if (array == null)
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				string text2 = executingAssembly.GetManifestResourceNames().FirstOrDefault((string n) => n.EndsWith("carl_face.png", StringComparison.OrdinalIgnoreCase));
				if (text2 == null)
				{
					return null;
				}
				using Stream stream = executingAssembly.GetManifestResourceStream(text2);
				if (stream == null)
				{
					return null;
				}
				array = new byte[stream.Length];
				int num2;
				for (int num = 0; num < array.Length; num += num2)
				{
					num2 = stream.Read(array, num, array.Length - num);
					if (num2 <= 0)
					{
						break;
					}
				}
				text = text2;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array))
			{
				Plugin.Log.LogError((object)("[BingBongFace] Could not decode " + text + "."));
				Object.Destroy((Object)(object)val);
				return null;
			}
			((Object)val).name = "CarlBingBongFace";
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).anisoLevel = 4;
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		public static void Tick()
		{
			if ((Object)(object)texture == (Object)null || Plugin.BoundConfig == null)
			{
				return;
			}
			if (!Plugin.BoundConfig.Enabled.Value)
			{
				Clear();
				return;
			}
			for (int num = spawned.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)spawned[num] == (Object)null)
				{
					spawned.RemoveAt(num);
				}
			}
			if (!(Time.unscaledTime < nextScan))
			{
				nextScan = Time.unscaledTime + 2f;
				Action_AskBingBong[] array = Object.FindObjectsByType<Action_AskBingBong>((FindObjectsInactive)1, (FindObjectsSortMode)0);
				foreach (Action_AskBingBong bb in array)
				{
					Ensure(bb);
				}
			}
		}

		private static void Clear()
		{
			if (spawned.Count == 0 && hiddenLips.Count == 0)
			{
				return;
			}
			foreach (GameObject item in spawned)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
			spawned.Clear();
			foreach (Renderer hiddenLip in hiddenLips)
			{
				if ((Object)(object)hiddenLip != (Object)null)
				{
					hiddenLip.enabled = true;
				}
			}
			hiddenLips.Clear();
		}

		public static void Ensure(Action_AskBingBong bb)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			if ((Object)(object)bb == (Object)null || (Object)(object)texture == (Object)null || Plugin.BoundConfig == null || !Plugin.BoundConfig.Enabled.Value)
			{
				return;
			}
			Transform transform = ((Component)bb).transform;
			Item componentInParent = ((Component)bb).GetComponentInParent<Item>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				if ((Object)(object)componentInParent.mainRenderer == (Object)null)
				{
					return;
				}
				transform = ((Component)componentInParent).transform;
			}
			if (((Component)transform).GetComponentsInChildren<Transform>(true).Any((Transform t) => ((Object)t).name == "CarlBingBongFace"))
			{
				return;
			}
			Renderer val = PickBody(transform);
			if (!((Object)(object)val == (Object)null))
			{
				if (Plugin.BoundConfig.DebugLog.Value)
				{
					Describe(transform);
				}
				GameObject val2 = new GameObject("CarlBingBongFace");
				val2.transform.SetParent(((Component)val).transform, false);
				val2.layer = ((Component)val).gameObject.layer;
				val2.AddComponent<MeshFilter>();
				MeshRenderer val3 = val2.AddComponent<MeshRenderer>();
				((Renderer)val3).sharedMaterial = GetMaterial(val);
				((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)val3).receiveShadows = true;
				((Renderer)val3).reflectionProbeUsage = (ReflectionProbeUsage)0;
				Place(val2.transform, val, transform);
				HideLips(transform);
				spawned.Add(val2);
			}
		}

		private static Renderer PickBody(Transform root)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			Renderer val = null;
			Renderer val2 = null;
			float num = -1f;
			float num2 = -1f;
			Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren)
			{
				if ((Object)(object)val3 == (Object)null || ((Object)((Component)val3).transform).name == "CarlBingBongFace" || (!(val3 is MeshRenderer) && !(val3 is SkinnedMeshRenderer)))
				{
					continue;
				}
				Bounds val4 = LocalBounds(val3);
				Vector3 size = ((Bounds)(ref val4)).size;
				float num3 = size.x * size.y * size.z;
				if (num3 <= 0f)
				{
					continue;
				}
				string text = (((Object)(object)val3.sharedMaterial != (Object)null) ? ((Object)val3.sharedMaterial).name : "");
				if (text.IndexOf("BingBong", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					if (num3 > num)
					{
						num = num3;
						val = val3;
					}
				}
				else if (text.IndexOf("M_Player", StringComparison.OrdinalIgnoreCase) < 0 && num3 > num2)
				{
					num2 = num3;
					val2 = val3;
				}
			}
			return val ?? val2;
		}

		private static Bounds LocalBounds(Renderer r)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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)
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((r is SkinnedMeshRenderer) ? r : null);
			if ((Object)(object)val != (Object)null && (Object)(object)val.sharedMesh != (Object)null)
			{
				return val.sharedMesh.bounds;
			}
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null)
			{
				return component.sharedMesh.bounds;
			}
			Bounds bounds = r.bounds;
			return new Bounds(((Component)r).transform.InverseTransformPoint(((Bounds)(ref bounds)).center), ((Component)r).transform.InverseTransformVector(((Bounds)(ref bounds)).size));
		}

		private static bool TryFindMouth(Transform root, Renderer body, out Vector3 mouth)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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_0099: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			mouth = Vector3.zero;
			Vector3 val = Vector3.zero;
			int num = 0;
			Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null) && !(((Object)((Component)val2).transform).name == "CarlBingBongFace"))
				{
					string text = ((Object)val2).name.ToLowerInvariant();
					if (text.Contains("lip") || text.Contains("mouth"))
					{
						Transform transform = ((Component)val2).transform;
						Bounds val3 = LocalBounds(val2);
						Vector3 val4 = transform.TransformPoint(((Bounds)(ref val3)).center);
						val += ((Component)body).transform.InverseTransformPoint(val4);
						num++;
					}
				}
			}
			if (num == 0)
			{
				return false;
			}
			mouth = val / (float)num;
			return true;
		}

		private static void Place(Transform decal, Renderer body, Transform root)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: 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_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			Bounds val = LocalBounds(body);
			Vector3 extents = ((Bounds)(ref val)).extents;
			int num = ((!(extents.x <= extents.y) || !(extents.x <= extents.z)) ? ((extents.y <= extents.z) ? 1 : 2) : 0);
			Vector3 val2 = Vector3.zero;
			Vector3 mouth;
			bool flag = TryFindMouth(root, body, out mouth);
			int num2;
			float num3;
			if (flag)
			{
				val2 = mouth - ((Bounds)(ref val)).center;
				Vector3 val3 = default(Vector3);
				((Vector3)(ref val3))..ctor(val2.x / Mathf.Max(extents.x, 0.0001f), val2.y / Mathf.Max(extents.y, 0.0001f), val2.z / Mathf.Max(extents.z, 0.0001f));
				num2 = ((!(Mathf.Abs(val3.x) >= Mathf.Abs(val3.y)) || !(Mathf.Abs(val3.x) >= Mathf.Abs(val3.z))) ? ((Mathf.Abs(val3.y) >= Mathf.Abs(val3.z)) ? 1 : 2) : 0);
				num3 = ((((Vector3)(ref val3))[num2] >= 0f) ? 1f : (-1f));
			}
			else
			{
				num2 = num;
				num3 = Mathf.Sign(1f);
				Plugin.Log.LogInfo((object)"[BingBongFace] No lips found; using his thinnest axis.");
			}
			Vector3 val4 = (Vector3)(num2 switch
			{
				1 => Vector3.up, 
				0 => Vector3.right, 
				_ => Vector3.forward, 
			}) * num3;
			float num4 = num2 switch
			{
				1 => Mathf.Min(extents.x, extents.z), 
				0 => Mathf.Min(extents.y, extents.z), 
				_ => Mathf.Min(extents.x, extents.y), 
			};
			float num5 = Mathf.Max(2f * num4 * 0.525f, 0.0001f);
			float num6 = Mathf.Max(((Vector3)(ref extents))[num2], 0.0001f);
			Vector3 val5 = ((num2 == 1) ? Vector3.forward : Vector3.up);
			Quaternion val6 = Quaternion.LookRotation(val4, val5) * Quaternion.Euler(0f, 0f, -90f);
			Vector3 val7 = (flag ? (val2 - val4 * Vector3.Dot(val2, val4) + val6 * Vector3.up * (num5 * 0.2f)) : Vector3.zero);
			decal.localPosition = ((Bounds)(ref val)).center + val4 * num6 * 1.02f + val7;
			decal.localRotation = val6;
			decal.localScale = Vector3.one * num5;
			SetMesh(decal, (num6 * num6 + num4 * num4) / (2f * num6) / num5);
			Plugin.Log.LogInfo((object)("[BingBongFace] Face on '" + ((Object)root).name + "' at '" + ((Object)body).name + "', " + (flag ? "over his lips" : "on his broad side") + ", " + string.Format("axis {0}{1}, size {2:0.00}, ", (num3 < 0f) ? "-" : "+", "XYZ"[num2], num5) + $"body {((Bounds)(ref val)).size}."));
		}

		private static void HideLips(Transform root)
		{
			if (!Tuning.FaceHideLips)
			{
				return;
			}
			Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !(((Object)((Component)val).transform).name == "CarlBingBongFace") && val.enabled)
				{
					string text = ((Object)val).name.ToLowerInvariant();
					if (text.Contains("lip") || text.Contains("mouth"))
					{
						val.enabled = false;
						hiddenLips.Add(val);
					}
				}
			}
		}

		private static void SetMesh(Transform decal, float bulgeRadius)
		{
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Expected O, but got Unknown
			MeshFilter component = ((Component)decal).GetComponent<MeshFilter>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			float num = ((((Texture)texture).height > 0) ? ((float)((Texture)texture).width / (float)((Texture)texture).height) : 1f);
			float num2 = Mathf.Sqrt(0.25f * num * num + 0.25f);
			float num3 = Mathf.Max(bulgeRadius, num2 * 1.05f);
			float num4 = Mathf.Clamp01(0.9f);
			int key = Mathf.RoundToInt(num3 * 100f);
			if (meshes.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
			{
				component.sharedMesh = value;
				return;
			}
			int num5 = 13;
			Vector3[] array = (Vector3[])(object)new Vector3[num5 * num5];
			Vector2[] array2 = (Vector2[])(object)new Vector2[num5 * num5];
			Vector3[] array3 = (Vector3[])(object)new Vector3[num5 * num5];
			for (int i = 0; i < num5; i++)
			{
				for (int j = 0; j < num5; j++)
				{
					float num6 = (float)j / 12f;
					float num7 = (float)i / 12f;
					float num8 = (num6 - 0.5f) * num;
					float num9 = num7 - 0.5f;
					float num10 = Mathf.Sqrt(num8 * num8 + num9 * num9);
					float num11 = Mathf.Sqrt(Mathf.Max(0f, num3 * num3 - num10 * num10));
					int num12 = i * num5 + j;
					array[num12] = new Vector3(num8, num9, (0f - (num3 - num11)) * num4);
					array2[num12] = new Vector2(1f - num6, num7);
					Vector3 forward = Vector3.forward;
					Vector3 val = new Vector3(num8, num9, num11);
					array3[num12] = Vector3.Slerp(forward, ((Vector3)(ref val)).normalized, num4);
				}
			}
			int[] array4 = new int[864];
			int num13 = 0;
			for (int k = 0; k < 12; k++)
			{
				for (int l = 0; l < 12; l++)
				{
					int num14 = k * num5 + l;
					array4[num13++] = num14;
					array4[num13++] = num14 + num5;
					array4[num13++] = num14 + 1;
					array4[num13++] = num14 + 1;
					array4[num13++] = num14 + num5;
					array4[num13++] = num14 + num5 + 1;
				}
			}
			Mesh val2 = new Mesh
			{
				name = "CarlBingBongFace",
				hideFlags = (HideFlags)61,
				vertices = array,
				uv = array2,
				normals = array3,
				triangles = array4
			};
			val2.RecalculateBounds();
			meshes[key] = val2;
			component.sharedMesh = val2;
		}

		private static Material GetMaterial(Renderer donor)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)material != (Object)null)
			{
				return material;
			}
			Shader val = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Sprites/Default");
			if ((Object)(object)val == (Object)null && (Object)(object)donor != (Object)null && (Object)(object)donor.sharedMaterial != (Object)null)
			{
				val = donor.sharedMaterial.shader;
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"[BingBongFace] No usable shader found.");
				return null;
			}
			material = new Material(val)
			{
				name = "CarlBingBongFace",
				hideFlags = (HideFlags)61
			};
			string[] array = new string[2] { "_BaseMap", "_MainTex" };
			foreach (string text in array)
			{
				if (material.HasProperty(text))
				{
					material.SetTexture(text, (Texture)(object)texture);
				}
			}
			string[] array2 = new string[2] { "_BaseColor", "_Color" };
			foreach (string text2 in array2)
			{
				if (material.HasProperty(text2))
				{
					material.SetColor(text2, Color.white);
				}
			}
			if (material.HasProperty("_AlphaClip"))
			{
				material.SetFloat("_AlphaClip", 1f);
			}
			if (material.HasProperty("_Cutoff"))
			{
				material.SetFloat("_Cutoff", 0.35f);
			}
			if (material.HasProperty("_Smoothness"))
			{
				material.SetFloat("_Smoothness", 0f);
			}
			if (material.HasProperty("_Metallic"))
			{
				material.SetFloat("_Metallic", 0f);
			}
			if (material.HasProperty("_Cull"))
			{
				material.SetFloat("_Cull", 0f);
			}
			material.EnableKeyword("_ALPHATEST_ON");
			material.SetOverrideTag("RenderType", "TransparentCutout");
			material.renderQueue = 2450;
			return material;
		}

		private static void Describe(Transform root)
		{
			if (described.Add(((Object)root).name))
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("[BingBongFace] hierarchy of '" + ((Object)root).name + "':");
				Walk(root, 0, stringBuilder);
				Plugin.Log.LogInfo((object)stringBuilder.ToString());
			}
		}

		private static void Walk(Transform t, int depth, StringBuilder sb)
		{
			//IL_0034: 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)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			sb.Append(new string(' ', depth * 2)).Append(((Object)t).name);
			Renderer component = ((Component)t).GetComponent<Renderer>();
			if ((Object)(object)component != (Object)null)
			{
				Bounds val = LocalBounds(component);
				sb.Append($"  [{((object)component).GetType().Name} size={((Bounds)(ref val)).size} center={((Bounds)(ref val)).center}");
				Material sharedMaterial = component.sharedMaterial;
				if ((Object)(object)sharedMaterial != (Object)null)
				{
					sb.Append(" mat=" + ((Object)sharedMaterial).name + " shader=" + (((Object)(object)sharedMaterial.shader != (Object)null) ? ((Object)sharedMaterial.shader).name : "?"));
				}
				SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((component is SkinnedMeshRenderer) ? component : null);
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMesh != (Object)null)
				{
					for (int i = 0; i < val2.sharedMesh.blendShapeCount; i++)
					{
						sb.Append(" blendshape=\"" + val2.sharedMesh.GetBlendShapeName(i) + "\"");
					}
				}
				sb.Append(']');
			}
			sb.AppendLine();
			for (int j = 0; j < t.childCount; j++)
			{
				Walk(t.GetChild(j), depth + 1, sb);
			}
		}
	}
	internal class BingBongFaceTicker : MonoBehaviour
	{
		private void Update()
		{
			try
			{
				BingBongFace.Tick();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[BingBongFace] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(ItemActionBase), "Start")]
	public static class PatchBingBongFaceSpawn
	{
		private static void Postfix(ItemActionBase __instance)
		{
			Action_AskBingBong val = (Action_AskBingBong)(object)((__instance is Action_AskBingBong) ? __instance : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				BingBongFace.Ensure(val);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[BingBongFace] {arg}");
			}
		}
	}
	internal static class BingBongSounds
	{
		public const string FolderName = "bingbong";

		public const string IdPrefix = "CARLBB";

		private static readonly List<AudioClip> clips = new List<AudioClip>();

		private static readonly List<string> texts = new List<string>();

		private static readonly Dictionary<string, string> byId = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<Action_AskBingBong> injected = new HashSet<Action_AskBingBong>();

		private static readonly Dictionary<string, string> sidecar = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		public static int Count => clips.Count;

		private static void LoadSidecar(string dir)
		{
			sidecar.Clear();
			string text = ClipLayout.Sidecar(dir, "bingbong", "subtitles.tsv");
			if (text == null || !File.Exists(text))
			{
				return;
			}
			try
			{
				string[] array = File.ReadAllLines(text);
				foreach (string text2 in array)
				{
					if (text2.Length != 0 && text2[0] != '#')
					{
						int num = text2.IndexOf('\t');
						if (num > 0)
						{
							sidecar[text2.Substring(0, num)] = text2.Substring(num + 1).Trim();
						}
					}
				}
				Plugin.Log.LogInfo((object)$"[BingBong] {sidecar.Count} subtitle(s) from sidecar.");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[BingBong] subtitles.tsv: {arg}");
			}
		}

		public static void Load(string modFolder)
		{
			clips.Clear();
			texts.Clear();
			byId.Clear();
			injected.Clear();
			string text = Path.Combine(modFolder, "bingbong");
			string[] array = ClipLayout.Files(modFolder, "bingbong");
			if (array.Length == 0)
			{
				Plugin.Log.LogInfo((object)"[BingBong] no 'bingbong' clips; answers untouched.");
				return;
			}
			LoadSidecar(modFolder);
			foreach (string item in array.OrderBy((string x) => x))
			{
				AudioClip val = WavLoader.Load(item);
				if (!((Object)(object)val == (Object)null))
				{
					string text2 = ClipLayout.Stem(item);
					if (!sidecar.TryGetValue(text2, out var value) || string.IsNullOrEmpty(value))
					{
						value = text2.Replace('_', ' ').Trim();
					}
					string text3 = "CARLBB" + clips.Count;
					clips.Add(val);
					texts.Add(value);
					byId[text3] = value;
					Plugin.Log.LogInfo((object)("[BingBong] " + text3 + " <- " + Path.GetFileName(item)));
				}
			}
			Plugin.Log.LogInfo((object)$"[BingBong] {clips.Count} answer(s) loaded.");
		}

		public static bool TryText(string id, out string text)
		{
			return byId.TryGetValue(id, out text);
		}

		public static void Ensure(Action_AskBingBong bb)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			if (!((Object)(object)bb == (Object)null) && clips.Count != 0 && !injected.Contains(bb))
			{
				injected.Add(bb);
				List<BingBongResponse> list = ((IEnumerable<BingBongResponse>)(((object)bb.responses) ?? ((object)new BingBongResponse[0]))).ToList();
				int count = list.Count;
				for (int i = 0; i < count; i++)
				{
					SFX_Instance val = ScriptableObject.CreateInstance<SFX_Instance>();
					AudioClip val2 = clips[i % clips.Count];
					val.clips = (AudioClip[])(object)new AudioClip[1] { val2 };
					val.settings = new SFX_Settings
					{
						volume = ClipVolumes.Scaled(val2),
						volume_Variation = 0f,
						pitch = 1f,
						pitch_Variation = 0f,
						spatialBlend = 1f,
						range = 120f,
						dopplerLevel = 0f
					};
					list[i].subtitleID = "CARLBB" + i % clips.Count;
					list[i].sfx = val;
				}
				bb.responses = list.ToArray();
				Plugin.Log.LogInfo((object)($"[BingBong] replaced all {count} answer slot(s) with {clips.Count} clip(s)" + ((clips.Count != count) ? "  (cycled)" : "")));
			}
		}
	}
	[HarmonyPatch(typeof(Action_AskBingBong), "RunAction")]
	public static class PatchBingBongRun
	{
		private static void Prefix(Action_AskBingBong __instance)
		{
			try
			{
				BingBongSounds.Ensure(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[BingBong] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(Action_AskBingBong), "Ask")]
	public static class PatchBingBongAsk
	{
		private static void Prefix(Action_AskBingBong __instance)
		{
			try
			{
				BingBongSounds.Ensure(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[BingBong] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(LocalizedText), "GetText", new Type[]
	{
		typeof(string),
		typeof(bool)
	})]
	public static class PatchLocalizedText
	{
		private static bool Prefix(string id, ref string __result)
		{
			if (id == null || id.IndexOf("CARLBB", StringComparison.OrdinalIgnoreCase) != 0)
			{
				return true;
			}
			if (!BingBongSounds.TryText(id, out var text))
			{
				return true;
			}
			__result = text;
			return false;
		}
	}
	internal static class BingBongSubtitles
	{
		private const float VanillaSeconds = 1.8f;

		private const float HardCap = 30f;

		private const float StartGrace = 0.5f;

		public static IEnumerator Routine(Action_AskBingBong bb, string subtitleID)
		{
			yield return (object)new WaitForSeconds(0.19f);
			TextMeshPro label = (((Object)(object)bb != (Object)null) ? bb.subtitles : null);
			if (!((Object)(object)label == (Object)null))
			{
				((TMP_Text)label).text = LocalizedText.GetText(subtitleID, true);
				Fit(label);
				((Component)label).gameObject.SetActive(true);
				AudioSource src = bb.source;
				float pitch = (((Object)(object)src != (Object)null && src.pitch > 0.01f) ? src.pitch : 1f);
				float floor = 1.8f / pitch;
				float t = 0f;
				float waited = 0f;
				while ((Object)(object)src != (Object)null && !src.isPlaying && waited < 0.5f)
				{
					waited += Time.deltaTime;
					t += Time.deltaTime;
					Billboard(bb, label, t);
					yield return null;
				}
				while (t < 30f && (t < floor || ((Object)(object)src != (Object)null && src.isPlaying)))
				{
					t += Time.deltaTime;
					Billboard(bb, label, t);
					yield return null;
				}
				((Component)label).gameObject.SetActive(false);
			}
		}

		private static void Fit(TextMeshPro label)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((TMP_Text)label).overflowMode = (TextOverflowModes)0;
				((TMP_Text)label).maxVisibleCharacters = int.MaxValue;
				((TMP_Text)label).maxVisibleLines = int.MaxValue;
				RectTransform rectTransform = ((TMP_Text)label).rectTransform;
				if ((Object)(object)rectTransform != (Object)null)
				{
					float y = ((TMP_Text)label).GetPreferredValues(((TMP_Text)label).text, rectTransform.sizeDelta.x, 0f).y;
					if (y > rectTransform.sizeDelta.y)
					{
						rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, y + ((TMP_Text)label).fontSize);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[BingBong] subtitle fit: {arg}");
			}
		}

		private static void Billboard(Action_AskBingBong bb, TextMeshPro label, float t)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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)
			((TMP_Text)label).alpha = Mathf.Clamp01(t * 12f);
			Camera val = Camera.main;
			if ((Object)(object)val == (Object)null && (Object)(object)MainCamera.instance != (Object)null)
			{
				val = ((Component)MainCamera.instance).GetComponentInChildren<Camera>();
			}
			if (!((Object)(object)val == (Object)null))
			{
				if (bb.scaleCurve != null)
				{
					label.transform.localScale = Vector3.one * bb.scaleCurve.Evaluate(Vector3.Distance(label.transform.position, ((Component)val).transform.position));
				}
				label.transform.forward = ((Component)val).transform.forward;
			}
		}
	}
	[HarmonyPatch(typeof(Action_AskBingBong), "RunAction")]
	public static class PatchBingBongAskGate
	{
		private static bool Prefix(Action_AskBingBong __instance)
		{
			try
			{
				if (Plugin.BoundConfig == null || !Plugin.BoundConfig.Enabled.Value)
				{
					return true;
				}
				if (BingBongSounds.Count == 0)
				{
					return true;
				}
				AudioSource val = (((Object)(object)__instance != (Object)null) ? __instance.source : null);
				if ((Object)(object)val == (Object)null || !val.isPlaying)
				{
					return true;
				}
				Plugin.Log.LogInfo((object)"[BingBong] still answering; question ignored.");
				return false;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[BingBong] {arg}");
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Action_AskBingBong), "SubtitleRoutine")]
	public static class PatchBingBongSubtitle
	{
		private static bool Prefix(Action_AskBingBong __instance, string subtitleID, ref IEnumerator __result)
		{
			try
			{
				if (Plugin.BoundConfig == null || !Plugin.BoundConfig.Enabled.Value)
				{
					return true;
				}
				if (BingBongSounds.Count == 0)
				{
					return true;
				}
				__result = BingBongSubtitles.Routine(__instance, subtitleID);
				return false;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[BingBong] {arg}");
				return true;
			}
		}
	}
	internal static class ChatterSounds
	{
		public const string FolderName = "chatter";

		internal const byte ChatterEvent = 80;

		private static readonly List<AudioClip> clips = new List<AudioClip>();

		private static SFX_Instance sfx;

		private static float nextAt = -1f;

		private static float busyUntil;

		private static readonly Queue<int[]> waiting = new Queue<int[]>();

		public static int Count => clips.Count;

		public static void Load(string modFolder)
		{
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			clips.Clear();
			waiting.Clear();
			busyUntil = 0f;
			nextAt = -1f;
			string[] array = ClipLayout.Files(modFolder, "chatter");
			if (array.Length == 0)
			{
				Plugin.Log.LogInfo((object)"[Chatter] no 'chatter' clips; idle chatter off.");
				return;
			}
			foreach (string item in array.OrderBy<string, string>((string x) => x, StringComparer.Ordinal))
			{
				AudioClip val = WavLoader.Load(item);
				if ((Object)(object)val != (Object)null)
				{
					clips.Add(val);
				}
			}
			if (clips.Count > 0)
			{
				sfx = ScriptableObject.CreateInstance<SFX_Instance>();
				sfx.clips = (AudioClip[])(object)new AudioClip[0];
				sfx.settings = new SFX_Settings();
			}
			Plugin.Log.LogInfo((object)$"[Chatter] {clips.Count} clip(s) in the pool.");
		}

		private static Character PickSinger()
		{
			List<Character> list = new List<Character>();
			List<Character> allCharacters = Character.AllCharacters;
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.data == (Object)null) && !val.data.dead && val.IsPlayerControlled)
				{
					list.Add(val);
				}
			}
			if (list.Count == 0)
			{
				return null;
			}
			return list[Random.Range(0, list.Count)];
		}

		private static void Reschedule()
		{
			float value = Plugin.BoundConfig.ChatterMinSeconds.Value;
			float num = Mathf.Max(value, Plugin.BoundConfig.ChatterMaxSeconds.Value);
			int num2 = 1;
			try
			{
				if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null)
				{
					num2 = Mathf.Max(1, PhotonNetwork.CurrentRoom.PlayerCount);
				}
			}
			catch
			{
			}
			nextAt = Time.time + Random.Range(value, num) / Mathf.Pow((float)num2, 0.25f);
		}

		internal static void Tick()
		{
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Expected O, but got Unknown
			if ((Object)(object)sfx == (Object)null || Plugin.BoundConfig == null)
			{
				return;
			}
			if (!Plugin.BoundConfig.Enabled.Value || !Plugin.BoundConfig.ChatterEnabled.Value)
			{
				nextAt = -1f;
			}
			else if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
			{
				nextAt = -1f;
			}
			else if (nextAt < 0f)
			{
				Reschedule();
			}
			else
			{
				if (Time.time < nextAt)
				{
					return;
				}
				Reschedule();
				if (!SoundBus.Allows(SoundLane.Chatter))
				{
					return;
				}
				Character val = PickSinger();
				if (!((Object)(object)val == (Object)null))
				{
					int num = Random.Range(0, clips.Count);
					int num2 = (((Object)(object)((MonoBehaviourPun)val).photonView != (Object)null) ? ((MonoBehaviourPun)val).photonView.ViewID : 0);
					if (PhotonNetwork.OfflineMode || !PhotonNetwork.InRoom)
					{
						Enqueue(num, num2);
						return;
					}
					PhotonNetwork.RaiseEvent((byte)80, (object)new object[2] { num, num2 }, new RaiseEventOptions
					{
						Receivers = (ReceiverGroup)1
					}, SendOptions.SendReliable);
				}
			}
		}

		internal static void Enqueue(int index, int viewId)
		{
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)sfx == (Object)null) && index >= 0 && index < clips.Count)
			{
				AudioClip val = clips[index];
				Character val2 = default(Character);
				Character.GetCharacterWithPhotonID(viewId, ref val2);
				sfx.settings.volume = ClipVolumes.Scaled(val);
				sfx.settings.range = 120f;
				sfx.settings.volume_Variation = 0f;
				sfx.settings.pitch = 1f;
				sfx.settings.pitch_Variation = 0f;
				sfx.settings.dopplerLevel = 0f;
				sfx.settings.spatialBlend = 0.8f;
				sfx.clips = (AudioClip[])(object)new AudioClip[1] { val };
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Log.LogInfo((object)("[Chatter] '" + ((Object)val).name + "' skipped; the singer has gone."));
				}
				else if (!SoundBus.Play(sfx, val, val2.Center, SoundSource.Of(val2), SoundLane.Chatter))
				{
					Plugin.Log.LogInfo((object)$"[Chatter] '{((Object)val).name}' dropped; {SoundBus.Holder} has the floor");
				}
				else
				{
					Plugin.Log.LogInfo((object)$"[Chatter] {val2.characterName} sings '{((Object)val).name}' ({val.length:0.0}s)");
				}
			}
		}
	}
	internal class ChatterWatcher : MonoBehaviour, IOnEventCallback
	{
		private void OnEnable()
		{
			PhotonNetwork.AddCallbackTarget((object)this);
		}

		private void OnDisable()
		{
			PhotonNetwork.RemoveCallbackTarget((object)this);
		}

		private void Update()
		{
			try
			{
				ChatterSounds.Tick();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Chatter] {arg}");
			}
		}

		public void OnEvent(EventData photonEvent)
		{
			if (photonEvent.Code != 80)
			{
				return;
			}
			try
			{
				if (photonEvent.CustomData is object[] array && array.Length >= 2)
				{
					ChatterSounds.Enqueue(Convert.ToInt32(array[0]), Convert.ToInt32(array[1]));
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Chatter] {arg}");
			}
		}
	}
	internal static class ClipLayout
	{
		public const char Separator = '.';

		private static readonly HashSet<string> pools = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "state", "items", "ui", "progress", "cues", "chatter", "bingbong", "bugle" };

		public static string[] Files(string modFolder, string pool)
		{
			string value = pool + ".";
			List<string> list = new List<string>();
			string[] array = WavLoader.Files(modFolder);
			foreach (string text in array)
			{
				if (Path.GetFileName(text).StartsWith(value, StringComparison.OrdinalIgnoreCase))
				{
					list.Add(text);
				}
			}
			string text2 = Path.Combine(modFolder, pool);
			if (Directory.Exists(text2))
			{
				string[] array2 = WavLoader.Files(text2);
				foreach (string item in array2)
				{
					list.Add(item);
				}
			}
			return list.ToArray();
		}

		public static string Stem(string path)
		{
			string text = Path.GetFileNameWithoutExtension(path) ?? "";
			int num = text.IndexOf('.');
			if (num <= 0)
			{
				return text;
			}
			string s = text.Substring(0, num);
			return IsPool(s) ? text.Substring(num + 1) : text;
		}

		public static string Sidecar(string modFolder, string pool, string name)
		{
			string text = Path.Combine(modFolder, name);
			if (File.Exists(text))
			{
				return text;
			}
			string text2 = Path.Combine(modFolder, pool, name);
			return File.Exists(text2) ? text2 : null;
		}

		private static bool IsPool(string s)
		{
			return pools.Contains(s);
		}
	}
	internal static class ClipVolumes
	{
		public const string Section = "Volume Tuning";

		private static readonly Dictionary<string, ConfigEntry<float>> entries = new Dictionary<string, ConfigEntry<float>>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, ConfigEntry<bool>> plays = new Dictionary<string, ConfigEntry<bool>>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, AudioClip> byKey = new Dictionary<string, AudioClip>(StringComparer.OrdinalIgnoreCase);

		private static AudioSource speaker;

		private static float nextPoll;

		private static string playing;

		public static int Count => entries.Count;

		public static void Register(AudioClip clip)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			if (!((Object)(object)clip == (Object)null) && !((Object)(object)Plugin.Instance == (Object)null))
			{
				bool isFlat;
				string text = FlatClips.Strip(((Object)clip).name ?? "", out isFlat).Trim();
				if (text.Length != 0 && !entries.ContainsKey(text))
				{
					entries[text] = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<float>("Volume Tuning", text, 1f, new ConfigDescription("Trim for this one clip, on top of Master Volume. 1 = as cut, 0.5 = half, 2 = double. Unity clamps a source at full scale, so Master x trim can never exceed 1.0 - with Master at its default 0.5, a trim of 2 is already that ceiling. A clip that still wants to be louder has to be cut louder, not trimmed louder.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
					byKey[text] = clip;
					plays[text] = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Volume Tuning", text + " (play)", false, "Tick to hear this clip at its current trim. Unticks itself.");
				}
			}
		}

		public static float For(AudioClip clip)
		{
			if ((Object)(object)clip == (Object)null)
			{
				return 1f;
			}
			bool isFlat;
			string key = FlatClips.Strip(((Object)clip).name ?? "", out isFlat).Trim();
			ConfigEntry<float> value;
			return entries.TryGetValue(key, out value) ? value.Value : 1f;
		}

		internal static void Preview()
		{
			if (plays.Count == 0 || Time.unscaledTime < nextPoll)
			{
				return;
			}
			nextPoll = Time.unscaledTime + 0.1f;
			if (playing != null)
			{
				if (!plays.TryGetValue(playing, out var value) || !value.Value)
				{
					Stop();
					playing = null;
				}
				else
				{
					if (!((Object)(object)speaker == (Object)null) && speaker.isPlaying)
					{
						if (byKey.TryGetValue(playing, out var value2) && (Object)(object)value2 != (Object)null)
						{
							speaker.volume = Mathf.Clamp01(Scaled(value2));
						}
						return;
					}
					value.Value = false;
					playing = null;
				}
			}
			foreach (KeyValuePair<string, ConfigEntry<bool>> play in plays)
			{
				if (play.Value.Value)
				{
					if (byKey.TryGetValue(play.Key, out var value3) && !((Object)(object)value3 == (Object)null))
					{
						Play(value3);
						playing = play.Key;
						break;
					}
					play.Value.Value = false;
				}
			}
		}

		private static void Stop()
		{
			if ((Object)(object)speaker != (Object)null && speaker.isPlaying)
			{
				speaker.Stop();
			}
		}

		private static void Play(AudioClip clip)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			if ((Object)(object)speaker == (Object)null)
			{
				if ((Object)(object)Plugin.Instance == (Object)null)
				{
					return;
				}
				GameObject val = new GameObject("CarlVolumePreview");
				Object.DontDestroyOnLoad((Object)(object)val);
				((Object)val).hideFlags = (HideFlags)61;
				speaker = val.AddComponent<AudioSource>();
				speaker.playOnAwake = false;
				speaker.spatialBlend = 0f;
				speaker.dopplerLevel = 0f;
				speaker.bypassEffects = true;
				speaker.bypassListenerEffects = true;
				speaker.bypassReverbZones = true;
			}
			speaker.Stop();
			if (playing != null && plays.ContainsKey(playing))
			{
				plays[playing].Value = false;
			}
			speaker.clip = clip;
			speaker.volume = Mathf.Clamp01(Scaled(clip));
			speaker.Play();
			Plugin.Log.LogInfo((object)($"[Volume] preview '{((Object)clip).name}' at {speaker.volume:0.00} " + $"(master {Plugin.BoundConfig.MasterVolume.Value:0.00} x trim {For(clip):0.00})"));
		}

		public static float Scaled(AudioClip clip)
		{
			return Plugin.BoundConfig.MasterVolume.Value * For(clip);
		}
	}
	internal static class DownedCues
	{
		public const string FolderName = "cues";

		private static readonly Dictionary<string, List<AudioClip>> clips = new Dictionary<string, List<AudioClip>>(StringComparer.OrdinalIgnoreCase);

		private static SFX_Instance sfx;

		internal static readonly Dictionary<Character, float> DownedSince = new Dictionary<Character, float>();

		internal static readonly Dictionary<Character, int> Fired = new Dictionary<Character, int>();

		public static int Count => clips.Values.Sum((List<AudioClip> l) => l.Count);

		public static void Load(string modFolder)
		{
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected O, but got Unknown
			clips.Clear();
			string text = Path.Combine(modFolder, "cues");
			string[] array = ClipLayout.Files(modFolder, "cues");
			if (array.Length == 0)
			{
				Plugin.Log.LogInfo((object)"[Cues] no 'cues' clips; timed cues off.");
				return;
			}
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				bool isFlat;
				string text3 = FlatClips.Strip(ClipLayout.Stem(text2), out isFlat).ToLowerInvariant();
				string text4 = (text3.StartsWith("downed_10s") ? "downed_10s" : (text3.StartsWith("downed_2s") ? "downed_2s" : text3));
				AudioClip val = WavLoader.Load(text2);
				if (!((Object)(object)val == (Object)null))
				{
					FlatClips.Register(val, isFlat);
					if (!clips.TryGetValue(text4, out var value))
					{
						value = (clips[text4] = new List<AudioClip>());
					}
					value.Add(val);
					Plugin.Log.LogInfo((object)("[Cues] " + Path.GetFileName(text2) + " -> " + text4));
				}
			}
			if (clips.Count > 0)
			{
				sfx = ScriptableObject.CreateInstance<SFX_Instance>();
				sfx.clips = (AudioClip[])(object)new AudioClip[0];
				sfx.settings = new SFX_Settings();
			}
			Plugin.Log.LogInfo((object)$"[Cues] {Count} clip(s) across {clips.Count} cue(s).");
		}

		public static void Play(string key, Vector3 pos, Transform follow = null)
		{
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)sfx == (Object)null) && clips.TryGetValue(key, out var value) && value.Count != 0)
			{
				sfx.settings.volume = Plugin.BoundConfig.MasterVolume.Value;
				sfx.settings.range = 120f;
				sfx.settings.volume_Variation = 0f;
				sfx.settings.pitch = 1f;
				sfx.settings.pitch_Variation = 0f;
				sfx.settings.dopplerLevel = 0f;
				AudioClip val = value[Random.Range(0, value.Count)];
				sfx.settings.spatialBlend = FlatClips.Blend(val, 0.8f);
				sfx.clips = (AudioClip[])(object)new AudioClip[1] { val };
				sfx.settings.volume = ClipVolumes.Scaled(val);
				sfx.Play(pos, follow);
				Plugin.Log.LogInfo((object)("[Cues] " + key + " played"));
			}
		}

		internal static void Begin(Character c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				DownedSince[c] = Time.time;
				Fired[c] = 0;
			}
		}

		internal static void End(Character c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				DownedSince.Remove(c);
				Fired.Remove(c);
			}
		}

		internal static void Tick()
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if (DownedSince.Count == 0)
			{
				return;
			}
			float num = 2f;
			float num2 = 10f;
			Character[] array = DownedSince.Keys.ToArray();
			Character[] array2 = array;
			foreach (Character val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					DownedSince.Remove(val);
					Fired.Remove(val);
				}
				else if (!EventSounds.SleptOut(val))
				{
					float num3 = Time.time - DownedSince[val];
					int value;
					int num4 = (Fired.TryGetValue(val, out value) ? value : 0);
					if (num4 < 1 && num3 >= num)
					{
						Fired[val] = 1;
						Play("downed_2s", val.Center, SoundSource.Of(val));
					}
					else if (num4 < 2 && num3 >= num2)
					{
						Fired[val] = 2;
						Play("downed_10s", val.Center, SoundSource.Of(val));
					}
				}
			}
		}
	}
	internal class CueTicker : MonoBehaviour
	{
		private void Update()
		{
			try
			{
				DownedCues.Tick();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Cues] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(Character), "RPCA_PassOut")]
	public static class PatchPassOutCue
	{
		private static void Postfix(Character __instance)
		{
			DownedCues.Begin(__instance);
		}
	}
	[HarmonyPatch(typeof(Character), "RPCA_UnPassOut")]
	public static class PatchUnPassOutCue
	{
		private static void Postfix(Character __instance)
		{
			DownedCues.End(__instance);
		}
	}
	internal static class EventSounds
	{
		public const string AfflictionInjury = "affliction_injury";

		public const string AfflictionHunger = "affliction_hunger";

		public const string AfflictionCold = "affliction_cold";

		public const string AfflictionHot = "affliction_hot";

		public const string AfflictionPoison = "affliction_poison";

		public const string AfflictionThorns = "affliction_thorns";

		public const string AfflictionSpores = "affliction_spores";

		public const string LongFall = "long_fall";

		public const string Downed = "downed";

		public const string SleepyKo = "sleepy_ko";

		public const string FullyPassedOut = "fully_passed_out";

		public const string Revived = "revived";

		public const string Zombified = "zombified";

		public const string ZombieTalk = "zombie_talk";

		public const string Cannibalism = "cannibalism";

		public const string MiddleMousePing = "middle_mouse_ping";

		public const string RocketpackLaunch = "rocketpack_launch";

		public const string EnterAntigravity = "enter_antigravity";

		public const string PlayerJoined = "player_joined";

		public const string PlayerLeft = "player_left";

		private static readonly HashSet<string> Replaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "affliction_injury", "affliction_hunger", "affliction_cold", "affliction_hot", "affliction_poison", "affliction_thorns", "affliction_spores", "zombie_talk", "middle_mouse_ping" };

		internal static readonly HashSet<SFX_Instance> Muted = new HashSet<SFX_Instance>();

		private static readonly HashSet<Character> sleptOut = new HashSet<Character>();

		private static readonly HashSet<Character> fullyOut = new HashSet<Character>();

		public static bool ShouldReplace(string key)
		{
			return Replaces.Contains(key);
		}

		public static bool Fire(string key, Character who)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.BoundConfig == null || !Plugin.BoundConfig.Enabled.Value)
			{
				return true;
			}
			if (!StateSounds.Has(key))
			{
				return true;
			}
			Vector3 pos = (((Object)(object)who != (Object)null) ? who.Center : Vector3.zero);
			StateSounds.PlayAt(key, pos, -1f, SoundSource.Of(who));
			StateSounds.Schedule(key, pos, SoundSource.Of(who));
			return !ShouldReplace(key);
		}

		public static bool FireNet(string key, Character who)
		{
			if (Plugin.BoundConfig == null || !Plugin.BoundConfig.Enabled.Value)
			{
				return true;
			}
			if (!StateSounds.Has(key))
			{
				return true;
			}
			SoundNet.Fire(SoundPool.State, key, who);
			return !ShouldReplace(key);
		}

		public static bool FireAt(string key, Vector3 pos, bool flat = false)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.BoundConfig == null || !Plugin.BoundConfig.Enabled.Value)
			{
				return true;
			}
			if (!StateSounds.Has(key))
			{
				return true;
			}
			StateSounds.PlayAt(key, pos, -1f, null, flat ? 0f : (-1f));
			StateSounds.Schedule(key, pos);
			return !ShouldReplace(key);
		}

		public static bool SleptOut(Character c)
		{
			return (Object)(object)c != (Object)null && sleptOut.Contains(c);
		}

		internal static void MarkSleptOut(Character c, bool yes)
		{
			if (!((Object)(object)c == (Object)null))
			{
				if (yes)
				{
					sleptOut.Add(c);
				}
				else
				{
					sleptOut.Remove(c);
				}
			}
		}

		internal static void Tick()
		{
			if (Plugin.BoundConfig == null || !Plugin.BoundConfig.Enabled.Value || !StateSounds.Has("fully_passed_out"))
			{
				return;
			}
			List<Character> allCharacters = Character.AllCharacters;
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if ((Object)(object)val == (Object)null || (Object)(object)val.data == (Object)null)
				{
					continue;
				}
				if (val.data.fullyPassedOut)
				{
					if (fullyOut.Add(val))
					{
						Fire("fully_passed_out", val);
					}
				}
				else
				{
					fullyOut.Remove(val);
				}
			}
		}
	}
	[HarmonyPatch(typeof(SFX_Player), "PlaySFX")]
	public static class PatchMuteReplaced
	{
		private static bool Prefix(SFX_Instance SFX)
		{
			if ((Object)(object)SFX == (Object)null || EventSounds.Muted.Count == 0)
			{
				return true;
			}
			return !EventSounds.Muted.Contains(SFX);
		}
	}
	[HarmonyPatch(typeof(CharacterAfflictions), "StatusSFX")]
	public static class PatchStatusSFX
	{
		private static bool Prefix(CharacterAfflictions __instance, STATUSTYPE sT, float ammount)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = KeyFor(sT);
				if (text == null)
				{
					return true;
				}
				if ((int)sT == 0 && PatchLongFall.inside)
				{
					return true;
				}
				return EventSounds.Fire(text, ((Object)(object)__instance != (Object)null) ? __instance.character : null);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Event] {arg}");
				return true;
			}
		}

		private static string KeyFor(STATUSTYPE t)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected I4, but got Unknown
			return (int)t switch
			{
				0 => "affliction_injury", 
				1 => "affliction_hunger", 
				2 => "affliction_cold", 
				8 => "affliction_hot", 
				3 => "affliction_poison", 
				9 => "affliction_thorns", 
				10 => "affliction_spores", 
				_ => null, 
			};
		}
	}
	[HarmonyPatch(typeof(MushroomZombie), "RPC_PlaySFX")]
	public static class PatchZombieSFX
	{
		private static bool Prefix(MushroomZombie __instance)
		{
			try
			{
				Character who = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<Character>() : null);
				return EventSounds.Fire("zombie_talk", who);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Event] {arg}");
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(PointPing), "Awake")]
	public static class PatchPing
	{
		private static void Prefix(PointPing __instance)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					if (EventSounds.ShouldReplace("middle_mouse_ping") && (Object)(object)__instance.pingSound != (Object)null)
					{
						EventSounds.Muted.Add(__instance.pingSound);
					}
					EventSounds.FireAt("middle_mouse_ping", ((Component)__instance).transform.position);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Event] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(CharacterBackpackHandler), "RPCA_Fire")]
	public static class PatchRocketpackLaunch
	{
		private static void Postfix(CharacterBackpackHandler __instance)
		{
			try
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					Character who = ((Component)__instance).GetComponentInParent<Character>() ?? ((Component)__instance).GetComponent<Character>();
					EventSounds.Fire("rocketpack_launch", who);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Event] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(Character), "RPCA_PassOut")]
	public static class PatchPassOutEvent
	{
		private static void Postfix(Character __instance)
		{
			bool flag = false;
			try
			{
				flag = WentDownSleepy(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Event] {arg}");
			}
			EventSounds.MarkSleptOut(__instance, flag);
			EventSounds.Fire(flag ? "sleepy_ko" : "downed", __instance);
		}

		private static bool WentDownSleepy(Character c)
		{
			//IL_0098: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			CharacterAfflictions val = (((Object)(object)c != (Object)null && c.refs != null) ? c.refs.afflictions : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			float currentStatus = val.GetCurrentStatus((STATUSTYPE)6);
			if (currentStatus <= 0f)
			{
				return false;
			}
			float num = Time.time - val.LastAddedStatus((STATUSTYPE)6);
			bool flag = num <= 6f;
			float num2 = 0f;
			foreach (STATUSTYPE value in Enum.GetValues(typeof(STATUSTYPE)))
			{
				if ((int)value != 6)
				{
					float currentStatus2 = val.GetCurrentStatus(value);
					if (currentStatus2 > num2)
					{
						num2 = currentStatus2;
					}
				}
			}
			if (!flag && (currentStatus < 0.25f || currentStatus < num2))
			{
				return false;
			}
			Plugin.Log.LogInfo((object)($"[Event] {c.characterName} went down asleep - drowsy {currentStatus:0.00}, " + $"topped up {num:0.0}s ago, next highest {num2:0.00}."));
			return true;
		}
	}
	[HarmonyPatch(typeof(Character), "RPCA_UnPassOut")]
	public static class PatchUnPassOutEvent
	{
		private static void Postfix(Character __instance)
		{
			EventSounds.MarkSleptOut(__instance, yes: false);
			EventSounds.Fire("revived", __instance);
		}
	}
	[HarmonyPatch(typeof(Character), "RPCA_Zombify")]
	public static class PatchZombify
	{
		private static void Postfix(Character __instance)
		{
			EventSounds.Fire("zombified", __instance);
		}
	}
	[HarmonyPatch(typeof(CharacterInteractible), "GetEaten")]
	public static class PatchGetEaten
	{
		private static void Postfix(Character eater)
		{
			EventSounds.FireNet("cannibalism", eater);
		}
	}
	[HarmonyPatch(typeof(CharacterMovement), "CheckFallDamage")]
	public static class PatchLongFall
	{
		internal static bool inside;

		internal static bool armed;

		private static void Prefix(CharacterMovement __instance)
		{
			inside = true;
			armed = false;
			try
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					armed = __instance.sinceGrounded >= 4f && StateSounds.Has("long_fall");
				}
			}
			catch
			{
				armed = false;
			}
		}

		private static void Postfix()
		{
			inside = false;
			armed = false;
		}
	}
	[HarmonyPatch(typeof(CharacterAfflictions), "AddStatus")]
	public static class PatchFallInjury
	{
		private static void Postfix(CharacterAfflictions __instance, STATUSTYPE statusType, bool __result)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			try
			{
				if (PatchLongFall.inside && __result && (int)statusType <= 0 && PatchLongFall.armed)
				{
					EventSounds.FireNet("long_fall", ((Object)(object)__instance != (Object)null) ? __instance.character : null);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Event] {arg}");
			}
		}
	}
	internal static class ItHurtsBridge
	{
		public static bool SkipFallSound()
		{
			return !PatchLongFall.armed;
		}

		public static void Apply(Harmony harmony)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("ItHurts.Plugin");
				if (type == null)
				{
					Plugin.Log.LogInfo((object)"[Event] ItHurts not installed; nothing to quiet.");
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "RaiseFallSoundEvent", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Plugin.Log.LogWarning((object)"[Event] ItHurts found but RaiseFallSoundEvent is not where it was; leaving it alone.");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ItHurtsBridge), "SkipFallSound", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"[Event] ItHurts will stand aside on a long fall.");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Event] ItHurts bridge: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(AntiSphere), "OnTriggerEnter")]
	public static class PatchAntigravEnter
	{
		internal static readonly HashSet<Character> inside = new HashSet<Character>();

		private static void Postfix(Collider other)
		{
			try
			{
				Character val = default(Character);
				if (CharacterRagdoll.TryGetCharacterFromCollider(other, ref val) && !((Object)(object)val == (Object)null) && inside.Add(val))
				{
					EventSounds.Fire("enter_antigravity", val);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Event] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(AntiSphere), "OnTriggerExit")]
	public static class PatchAntigravExit
	{
		private static void Postfix(Collider other)
		{
			try
			{
				Character val = default(Character);
				if (CharacterRagdoll.TryGetCharacterFromCollider(other, ref val) && (Object)(object)val != (Object)null)
				{
					PatchAntigravEnter.inside.Remove(val);
				}
			}
			catch
			{
			}
		}
	}
	internal class RoomWatcher : MonoBehaviour, IInRoomCallbacks, IMatchmakingCallbacks
	{
		private void OnEnable()
		{
			PhotonNetwork.AddCallbackTarget((object)this);
		}

		private void OnDisable()
		{
			PhotonNetwork.RemoveCallbackTarget((object)this);
		}

		private void Update()
		{
			try
			{
				EventSounds.Tick();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Event] {arg}");
			}
		}

		public void OnPlayerEnteredRoom(Player newPlayer)
		{
			At("player_joined");
		}

		public void OnPlayerLeftRoom(Player otherPlayer)
		{
			At("player_left");
		}

		private static void At(string key)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Character localCharacter = Character.localCharacter;
			EventSounds.FireAt(key, ((Object)(object)localCharacter != (Object)null) ? localCharacter.Center : Vector3.zero, flat: true);
		}

		public void OnJoinedRoom()
		{
			At("player_joined");
		}

		public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
		{
		}

		public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
		{
		}

		public void OnMasterClientSwitched(Player newMasterClient)
		{
		}

		public void OnFriendListUpdate(List<FriendInfo> friendList)
		{
		}

		public void OnCreatedRoom()
		{
		}

		public void OnCreateRoomFailed(short returnCode, string message)
		{
		}

		public void OnJoinRoomFailed(short returnCode, string message)
		{
		}

		public void OnJoinRandomFailed(short returnCode, string message)
		{
		}

		public void OnLeftRoom()
		{
		}
	}
	internal static class FlatClips
	{
		public const string Marker = ".2d";

		private static readonly HashSet<AudioClip> flat = new HashSet<AudioClip>();

		public static int Count => flat.Count;

		public static string Strip(string stem, out bool isFlat)
		{
			isFlat = false;
			if (string.IsNullOrEmpty(stem))
			{
				return stem;
			}
			int num = stem.IndexOf(".2d", StringComparison.OrdinalIgnoreCase);
			if (num < 0)
			{
				return stem;
			}
			isFlat = true;
			return (stem.Substring(0, num) + stem.Substring(num + ".2d".Length)).Trim();
		}

		public static void Register(AudioClip clip, bool isFlat)
		{
			if ((Object)(object)clip != (Object)null && isFlat)
			{
				flat.Add(clip);
			}
		}

		public static bool Is(AudioClip clip)
		{
			return (Object)(object)clip != (Object)null && flat.Contains(clip);
		}

		public static void Clear()
		{
			flat.Clear();
		}

		public static float Blend(AudioClip clip, float configured)
		{
			return Is(clip) ? 0f : configured;
		}
	}
	internal static class ItemAudit
	{
		private static readonly Dictionary<string, string> known = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		public static int KnownCount => known.Count;

		private static void Collect()
		{
			known.Clear();
			Item[] array = Resources.FindObjectsOfTypeAll<Item>();
			foreach (Item val in array)
			{
				if ((Object)(object)val == (Object)null || val.UIData == null)
				{
					continue;
				}
				string itemName = val.UIData.itemName;
				if (!string.IsNullOrEmpty(itemName))
				{
					string text = ItemSounds.Norm(itemName);
					if (text.Length > 0 && !known.ContainsKey(text))
					{
						known[text] = itemName;
					}
				}
			}
		}

		public static IEnumerator RunLater()
		{
			yield return (object)new WaitForSeconds(5f);
			try
			{
				Run();
			}
			catch (Exception ex)
			{
				Exception ex2 = ex;
				Plugin.Log.LogError((object)$"[Audit] {ex2}");
			}
		}

		public static void Run()
		{
			Collect();
			if (known.Count == 0)
			{
				Plugin.Log.LogInfo((object)"[Audit] no item prefabs visible yet; skipping.");
				return;
			}
			List<string> list = new List<string>();
			int num = 0;
			foreach (string key in ItemSounds.Keys)
			{
				int num2 = key.IndexOf('|');
				if (num2 > 0)
				{
					string text = key.Substring(0, num2);
					string text2 = key.Substring(num2 + 1);
					if (text == "exit")
					{
						num++;
						continue;
					}
					if (known.ContainsKey(text2))
					{
						num++;
						continue;
					}
					list.Add(text + "_" + text2 + "   ->  did you mean \"" + Nearest(text2) + "\"?");
				}
			}
			Plugin.Log.LogInfo((object)($"[Audit] {num} item context(s) match a real item; {list.Count} do not " + $"(out of {known.Count} items in the game)."));
			foreach (string item in list)
			{
				Plugin.Log.LogWarning((object)("[Audit] " + item));
			}
			if (!Plugin.BoundConfig.DebugLog.Value)
			{
				return;
			}
			Plugin.Log.LogInfo((object)"[Audit] every item name the game knows:");
			foreach (string item2 in known.Values.OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase))
			{
				Plugin.Log.LogInfo((object)("[Audit]    " + item2));
			}
		}

		private static string Nearest(string item)
		{
			foreach (string key in known.Keys)
			{
				if (key.Contains(item) || item.Contains(key))
				{
					return known[key];
				}
			}
			string text = null;
			int num = int.MaxValue;
			foreach (string key2 in known.Keys)
			{
				int num2 = Distance(item, key2);
				if (num2 < num)
				{
					num = num2;
					text = known[key2];
				}
			}
			return text ?? "(nothing close)";
		}

		private static int Distance(string a, string b)
		{
			int[] array = new int[b.Length + 1];
			int[] array2 = new int[b.Length + 1];
			for (int i = 0; i <= b.Length; i++)
			{
				array[i] = i;
			}
			for (int j = 1; j <= a.Length; j++)
			{
				array2[0] = j;
				for (int k = 1; k <= b.Length; k++)
				{
					int num = ((a[j - 1] != b[k - 1]) ? 1 : 0);
					array2[k] = Mathf.Min(Mathf.Min(array2[k - 1] + 1, array[k] + 1), array[k - 1] + num);
				}
				int[] array3 = array;
				array = array2;
				array2 = array3;
			}
			return array[b.Length];
		}
	}
	internal static class ItemSounds
	{
		public const string ItemFolder = "items";

		public const string UIFolder = "ui";

		private const string PoolSep = "__";

		private static readonly Dictionary<string, List<AudioClip>> clips = new Dictionary<string, List<AudioClip>>(StringComparer.OrdinalIgnoreCase);

		private static SFX_Instance sfx;

		public static int Count => clips.Values.Sum((List<AudioClip> l) => l.Count);

		public static IEnumerable<string> Keys => clips.Keys;

		public static string Norm(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder(s.Length);
			foreach (char c in s)
			{
				if (char.IsLetterOrDigit(c))
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}

		public static void Load(string modFolder)
		{
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			clips.Clear();
			string[] array = new string[2] { "items", "ui" };
			foreach (string pool in array)
			{
				string[] array2 = ClipLayout.Files(modFolder, pool);
				foreach (string text in array2)
				{
					string text2 = FlatClips.Strip(ClipLayout.Stem(text), out var isFlat);
					int num = text2.IndexOf("__", StringComparison.Ordinal);
					if (num > 0)
					{
						text2 = text2.Substring(0, num);
					}
					int num2 = text2.IndexOf('_');
					text2 = ((num2 > 0) ? (text2.Substring(0, num2).ToLowerInvariant() + "|" + Norm(text2.Substring(num2 + 1))) : Norm(text2));
					AudioClip val = WavLoader.Load(text);
					if (!((Object)(object)val == (Object)null))
					{
						FlatClips.Register(val, isFlat);
						if (!clips.TryGetValue(text2, out var value))
						{
							value = (clips[text2] = new List<AudioClip>());
						}
						value.Add(val);
						Plugin.Log.LogInfo((object)("[Items] " + Path.GetFileName(text) + " -> " + text2));
					}
				}
			}
			if (clips.Count > 0)
			{
				sfx = ScriptableObject.CreateInstance<SFX_Instance>();
				sfx.clips = (AudioClip[])(object)new AudioClip[0];
				sfx.settings = new SFX_Settings();
			}
			Plugin.Log.LogInfo((object)$"[Items] {Count} clip(s) over {clips.Count} key(s).");
		}

		public static bool Has(string verb, string itemName)
		{
			return (Object)(object)sfx != (Object)null && clips.ContainsKey(verb + "|" + Norm(itemName));
		}

		public static void Play(string verb, string itemName, Vector3 pos, Transform follow = null)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)sfx == (Object)null))
			{
				StateSounds.Schedule(verb + "_" + Norm(itemName), pos, follow);
				PlayKey(verb + "|" + Norm(itemName), pos, follow);
			}
		}

		public static void PlayKey(string key, Vector3 pos, Transform follow = null)
		{
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sfx == (Object)null)
			{
				return;
			}
			if (!clips.TryGetValue(key, out var value) || value.Count == 0)
			{
				if (Plugin.BoundConfig.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("[Items] no clip for '" + key + "'"));
				}
				return;
			}
			sfx.settings.volume = Plugin.BoundConfig.MasterVolume.Value;
			sfx.settings.range = 120f;
			sfx.settings.volume_Variation = 0f;
			sfx.settings.pitch = 1f;
			sfx.settings.pitch_Variation = 0f;
			sfx.settings.dopplerLevel = 0f;
			AudioClip val = value[Random.Range(0, value.Count)];
			if (PlayGate.TryTake(key, follow, val))
			{
				sfx.settings.spatialBlend = FlatClips.Blend(val, 0.8f);
				sfx.clips = (AudioClip[])(object)new AudioClip[1] { val };
				sfx.settings.volume = ClipVolumes.Scaled(val);
				if (!SoundBus.Play(sfx, val, pos, follow, SoundLane.Normal))
				{
					Plugin.Log.LogInfo((object)$"[Items] {key} held back; {SoundBus.Holder} has the floor");
				}
				else
				{
					Plugin.Log.LogInfo((object)("[Items] " + key + " played"));
				}
			}
		}

		public static void PlayBare(string key, Vector3 pos, Transform follow = null)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sfx == (Object)null)
			{
				return;
			}
			StateSounds.Schedule(key.Replace('|', '_'), pos, follow);
			if (!clips.TryGetValue(key, out var value) || value.Count == 0)
			{
				return;
			}
			sfx.settings.volume = Plugin.BoundConfig.MasterVolume.Value;
			sfx.settings.range = 120f;
			sfx.settings.volume_Variation = 0f;
			sfx.settings.pitch = 1f;
			sfx.settings.pitch_Variation = 0f;
			sfx.settings.dopplerLevel = 0f;
			AudioClip val = value[Random.Range(0, value.Count)];
			if (PlayGate.TryTake(key, follow, val))
			{
				sfx.settings.spatialBlend = FlatClips.Blend(val, 0.8f);
				sfx.clips = (AudioClip[])(object)new AudioClip[1] { val };
				sfx.settings.volume = ClipVolumes.Scaled(val);
				if (!SoundBus.Play(sfx, val, pos, follow, SoundLane.Normal))
				{
					Plugin.Log.LogInfo((object)$"[Items] {key} held back; {SoundBus.Holder} has the floor");
				}
				else
				{
					Plugin.Log.LogInfo((object)("[Items] " + key + " played"));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Item), "FinishCastPrimary")]
	public static class PatchItemUse
	{
		private static void Postfix(Item __instance)
		{
			try
			{
				if (!((Object)(object)__instance == (Object)null) && __instance.UIData != null)
				{
					Character holderCharacter = __instance.holderCharacter;
					SoundNet.Fire(SoundPool.Items, "use|" + ItemSounds.Norm(__instance.UIData.itemName), holderCharacter);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Items] {arg}");
			}
		}
	}
	internal static class HeldItemWatcher
	{
		private static string last = "";

		internal static void Tick()
		{
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null)
			{
				return;
			}
			Item currentItem = localCharacter.data.currentItem;
			string text = (((Object)(object)currentItem != (Object)null && currentItem.UIData != null) ? currentItem.UIData.itemName : "");
			if (!(text == last))
			{
				last = text;
				if (!string.IsNullOrEmpty(text))
				{
					SoundNet.Fire(SoundPool.Items, "equip|" + ItemSounds.Norm(text), localCharacter);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemCooking), "FinishCookingRPC")]
	public static class PatchItemCooked
	{
		private static void Postfix(ItemCooking __instance)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Item val = (((Object)(object)__instance != (Object)null) ? ((ItemComponent)__instance).item : null);
				if (!((Object)(object)val == (Object)null) && val.UIData != null)
				{
					Character holderCharacter = val.holderCharacter;
					Vector3 pos = (((Object)(object)holderCharacter != (Object)null) ? holderCharacter.Center : ((Component)val).transform.position);
					Transform follow = (((Object)(object)holderCharacter != (Object)null) ? SoundSource.Of(holderCharacter) : ((Component)val).transform);
					ItemSounds.Play("cook", val.UIData.itemName, pos, follow);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Items] {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(PassportManager), "OnClose")]
	public static class PatchPassportClose
	{
		private static void Postfix()
		{
			try
			{
				Character localCharacter = Character.localCharacter;
				SoundNet.Fire(SoundPool.Items, "exit|passport", localCharacter);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Items] {arg}");
			}
		}
	}
	internal static class LoadingJingle
	{
		public const string Key = "run_start";

		public const string MusicTag = "Music";

		private static AudioSource speaker;

		private static readonly HashSet<int> reported = new HashSet<int>();

		internal static LoadingScreenType pending = (LoadingScreenType)0;

		private static bool singing;

		private static AudioSource Speaker()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			if ((Object)(object)speaker != (Object)null)
			{
				return speaker;
			}
			if ((Object)(object)Plugin.Instance == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("CarlLoadingJingle");
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).hideFlags = (HideFlags)61;
			speaker = val.AddComponent<AudioSource>();
			speaker.playOnAwake = false;
			speaker.loop = false;
			speaker.spatialBlend = 0f;
			speaker.dopplerLevel = 0f;
			speaker.ignoreListenerPause = true;
			speaker.outputAudioMixerGroup = null;
			speaker.bypassEffects = true;
			speaker.bypassListenerEffects = true;
			speaker.bypassReverbZones = true;
			return speaker;
		}

		public static void Take(LoadingScreen screen)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Invalid comparison between Unknown and I4
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)screen == (Object)null || Plugin.BoundConfig == null || !Plugin.BoundConfig.Enabled.Value)
			{
				return;
			}
			if ((int)pending != 1)
			{
				if (Plugin.BoundConfig.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)$"[Jingle] {pending} screen; left alone.");
				}
				return;
			}
			JingleWatcher.watchUntil = Time.unscaledTime + 3f;
			bool flag = (Object)(object)screen != (Object)null && reported.Add(((Object)screen).GetInstanceID());
			bool flag2 = Plugin.BoundConfig.DebugLog.Value && flag;
			int num = 0;
			foreach (AudioSource item in TaggedMusic(flag2))
			{
				if (!((Object)(object)item == (Object)null))
				{
					if (item.isPlaying)
					{
						item.Stop();
					}
					item.volume = 0f;
					num++;
				}
			}
			AudioSource[] componentsInChildren = ((Component)screen).GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !val.loop)
				{
					if (flag2)
					{
						Plugin.Log.LogInfo((object)("[Jingle] child " + ((Object)val).name + " clip=" + string.Format("{0} playing={1}", ((Object)(object)val.clip != (Object)null) ? ((Object)val.clip).name : "none", val.isPlaying)));
					}
					if (val.isPlaying)
					{
						val.Stop();
					}
					val.volume = 0f;
					num++;
				}
			}
			AudioClip[] array = StateSounds.Clips("run_start");
			if (array == null || array.Length == 0)
			{
				Plugin.Log.LogWarning((object)(string.Format("[Jingle] hushed {0} source(s) but found NO '{1}' clip in ", num, "run_start") + "state\\ - the loading screen will be silent. " + $"StateSounds holds {StateSounds.Count} clip(s)."));
				return;
			}
			AudioSource val2 = Speaker();
			if (!((Object)(object)val2 == (Object)null))
			{
				AudioClip val3 = (val2.clip = array[Random.Range(0, array.Length)]);
				val2.volume = ClipVolumes.Scaled(val3);
				val2.pitch = 1f;
				val2.Play();
				singing = true;
				Plugin.Log.LogInfo((object)(string.Format("[Jingle] {0} -> '{1}' {2:0.0}s at vol {3:0.00} ", "run_start", ((Object)val3).name, val3.length, val2.volume) + $"on {((Object)screen).name}; hushed {num} game source(s). " + $"playing={val2.isPlaying}"));
			}
		}

		internal static void EndWithScreen(float step)
		{
			if (singing && !((Object)(object)speaker == (Object)null) && !LoadingScreenHandler.loading)
			{
				AudioSource obj = speaker;
				obj.volume -= step;
				if (!(speaker.volume > 0f))
				{
					speaker.Stop();
					speaker.volume = 0f;
					singing = false;
					Plugin.Log.LogInfo((object)"[Jingle] loading finished; faded out.");
				}
			}
		}

		private static IEnumerable<AudioSource> TaggedMusic(bool log)
		{
			GameObject[] tagged;
			try
			{
				tagged = GameObject.FindGameObjectsWithTag("Music");
			}
			catch (Exception ex)
			{
				Exception ex2 = ex;
				if (log)
				{
					Plugin.Log.LogInfo((object)("[Jingle] no 'Music' tag: " + ex2.Message));
				}
				yield break;
			}
			GameObject[] array = tagged;
			foreach (GameObject go in array)
			{
				if ((Object)(object)go == (Object)null)
				{
					continue;
				}
				AudioSource[] componentsInChildren = go.GetComponentsInChildren<AudioSource>(true);
				foreach (AudioSource src in componentsInChildren)
				{
					if (log && (Object)(object)src != (Object)null)
					{
						Plugin.Log.LogInfo((object)("[Jingle] music " + ((Object)go).name + "/" + ((Object)src).name + " clip=" + (((Object)(object)src.clip != (Object)null) ? ((Object)src.clip).name : "none") + $" playing={src.isPlaying} loop={src.loop}"));
					}
					yield return src;
				}
			}
		}
	}
	[HarmonyPatch(typeof(LoadingScreenHandler), "GetLoadingScreenPrefab")]
	public static class PatchLoadingScreenType
	{
		private static void Postfix(LoadingScreenType type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			LoadingJingle.pending = type;
		}
	}
	[HarmonyPatch(typeof(LoadingScreen), "Awake")]
	public static class PatchLoadingScreen
	{
		private static void Postfix(LoadingScreen __instance)
		{
			try
			{
				LoadingJingle.Take(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Jingle] {arg}");
			}
		}
	}
	internal class JingleWatcher : MonoBehaviour
	{
		internal static float watchUntil;

		private const float FadeOut = 0.6f;

		private void Update()
		{
			LoadingJingle.EndWithScreen(Time.unscaledDeltaTime / 0.6f);
			if (Time.unscaledTime > watchUntil)
			{
				return;
			}
			try
			{
				GameObject[] array = GameObject.FindGameObjectsWithTag("Music");
				foreach (GameObject val in array)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					AudioSource[] componentsInChildren = val.GetComponentsInChildren<AudioSource>(true);
					foreach (AudioSource val2 in componentsInChildren)
					{
						if (!((Object)(object)val2 == (Object)null) && val2.isPlaying)
						{
							val2.Stop();
							val2.volume = 0f;
							Plugin.Log.LogInfo((object)("[Jingle] late music " + ((Object)val).name + "/" + ((Object)val2).name + " hushed."));
						}
					}
				}
			}
			catch
			{
			}
		}
	}
	internal static class LobbyMusic
	{
		public const string Key = "lobby_music";

		public const string AirportScene = "Airport";

		public const string MusicTag = "Music";

		private static AudioSource speaker;

		private static bool wasInAirport;

		private static float nextSweep;

		private static AudioSource Speaker()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			if ((Object)(object)speaker != (Object)null)
			{
				return speaker;
			}
			if ((Object)(object)Plugin.Instance == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("CarlLobbyMusic");
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).hideFlags = (HideFlags)61;
			speaker = val.AddComponent<AudioSource>();
			speaker.playOnAwake = false;
			speaker.loop = true;
			speaker.spatialBlend = 0f;
			speaker.dopplerLevel = 0f;
			speaker.bypassEffects = true;
			speaker.bypassListenerEffects = true;
			speaker.bypassReverbZones = true;
			return speaker;
		}

		internal static void Tick()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.BoundConfig == null)
			{
				return;
			}
			int num;
			if (Plugin.BoundConfig.Enabled.Value)
			{
				Scene activeScene = SceneManager.GetActiveScene();
				num = ((((Scene)(ref activeScene)).name == "Airport") ? 1 : 0);
			}
			else
			{
				num = 0;
			}
			bool flag = (byte)num != 0;
			if (flag != wasInAirport)
			{
				wasInAirport = flag;
				if (!flag)
				{
					Stop();
				}
			}
			if (flag && !(Time.unscaledTime < nextSweep))
			{
				nextSweep = Time.unscaledTime + 1f;
				if (StateSounds.Clips("lobby_music") != null)
				{
					Hush();
					Resume();
				}
			}
		}

		private static void Hush()
		{
			try
			{
				GameObject[] array = GameObject.FindGameObjectsWithTag("Music");
				foreach (GameObject val in array)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					AudioSource[] componentsInChildren = val.GetComponentsInChildren<AudioSource>(true);
					foreach (AudioSource val2 in componentsInChildren)
					{
						if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)speaker))
						{
							if (val2.isPlaying)
							{
								val2.Stop();
							}
							val2.volume = 0f;
						}
					}
				}
			}
			catch
			{
			}
		}

		private static void Resume()
		{
			AudioClip[] array = StateSounds.Clips("lobby_music");
			if (array == null || array.Length == 0)
			{
				return;
			}
			AudioSource val = Speaker();
			if (!((Object)(object)val == (Object)null))
			{
				if ((Object)(object)val.clip == (Object)null)
				{
					val.clip = array[Random.Range(0, array.Length)];
				}
				val.volume = ClipVolumes.Scaled(val.clip);
				if (!val.isPlaying)
				{
					val.Play();
					Plugin.Log.LogInfo((object)("[Lobby] lobby_music -> '" + ((Object)val.clip).name + "' looping in the airport."));
				}
			}
		}

		private static void Stop()
		{
			if (!((Object)(object)speaker == (Object)null))
			{
				if (speaker.isPlaying)
				{
					speaker.Stop();
				}
				speaker.clip = null;
				Plugin.Log.LogInfo((object)"[Lobby] left the airport; music stopped.");
			}
		}
	}
	internal class LobbyMusicTicker : MonoBehaviour
	{
		private void Update()
		{
			try
			{
				LobbyMusic.Tick();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Lobby] {arg}");
			}
		}
	}
	internal static class PlayGate
	{
		public const float AudibleOverlap = 0.5f;

		private static readonly Dictionary<long, float> until = new Dictionary<long, float>();

		private static float nextSweep;

		public static float TailOverlap => 0.65f;

		private static long Id(string key, Transform owner)
		{
			int num = (((Object)(object)owner != (Object)null) ? ((Object)owner).GetInstanceID() : 0);
			return ((long)num << 32) ^ (uint)key.GetHashCode();
		}

		public static bool TryTake(string key, Transform owner, AudioClip clip)
		{
			if (string.IsNullOrEmpty(key) || (Object)(object)clip == (Object)null)
			{
				return true;
			}
			float time = Time.time;
			Sweep(time);
			long key2 = Id(key, owner);
			if (until.TryGetValue(key2, out var value) && time < value)
			{
				return false;
			}
			float num = clip.length - TailOverlap;
			if (num <= 0f)
			{
				return true;
			}
			until[key2] = time + num;
			return true;
		}

		private static void Sweep(float now)
		{
			if (now < nextSweep)
			{
				return;
			}
			nextSweep = now + 30f;
			List<long> list = null;
			foreach (KeyValuePair<long, float> item in until)
			{
				if (now >= item.Value)
				{
					(list ?? (list = new List<long>())).Add(item.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (long item2 in list)
			{
				until.Remove(item2);
			}
		}

		public static void Clear()
		{
			until.Clear();
		}
	}
	public class ModConfig
	{
		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<float> MasterVolume;

		public readonly ConfigEntry<bool> DebugLog;

		public readonly ConfigEntry<bool> DumpSounds;

		public readonly ConfigEntry<bool> ChatterEnabled;

		public readonly ConfigEntry<float> ChatterMinSeconds;

		public readonly ConfigEntry<float> ChatterMaxSeconds;

		public ModConfig(ConfigFile cfg)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			cfg.SaveOnConfigSet = false;
			Enabled = cfg.Bind<bool>("CarlUnleashedMod", "Enabled", true, "Master switch for the whole mod.");
			MasterVolume = cfg.Bind<float>("CarlUnleashedMod", "Master Volume", 0.5f, new ConfigDescription("Scales every Carl clip. They are all loudness-matched to each other, so this moves them together against the game's own audio.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ChatterEnabled = cfg.Bind<bool>("Chatter", "Idle Chatter", true, "Every so often somebody bursts into song. The pool is every favourited clip with no context assigned, so it fills up as clips are picked out and empties as they get tagged for a specific moment.");
			ChatterMinSeconds = cfg.Bind<float>("Chatter", "Min Seconds", 40f, new ConfigDescription("Shortest wait between chatter lines. ONLY THE HOST'S VALUE MATTERS - the host schedules for the whole room, so your own setting does nothing unless you are hosting. Drop both to a second or two to audition the pool.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), Array.Empty<object>()));
			ChatterMaxSeconds = cfg.Bind<float>("Chatter", "Max Seconds", 100f, new ConfigDescription("Longest wait between chatter lines, host's value only. Each wait is picked at random between the two, then shortened slightly in a fuller lobby to offset how often other sounds crowd chatter out. A value below the minimum is treated as equal to it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), Array.Empty<object>()));
			DebugLog = cfg.Bind<bool>("Debug", "Debug Log", false, "Log every sound the game plays, with its name and pitch variation. Use it to find the exact name of a sound worth replacing.");
			DumpSounds = cfg.Bind<bool>("Debug", "Dump Sounds", false, "On next launch, export every sound effect in the game to a 'dumped_sounds' folder as .wav, then set this back to false.");
			ClearOrphanedEntries(cfg);
			cfg.Save();
			cfg.SaveOnConfigSet = true;
		}

		private static void ClearOrphanedEntries(ConfigFile cfg)
		{
			PropertyInfo propertyInfo = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries");
			Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)propertyInfo.GetValue(cfg);
			dictionary.Clear();
		}
	}
	[BepInPlugin("CarlUnleashedMod", "CarlUnleashedMod", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Id = "CarlUnleashedMod";

		private readonly Harmony harmony = new Harmony("CarlUnleashedMod");

		internal static ManualLogSource Log { get; private set; }

		internal static Plugin Instance { get; private set; }

		internal static ModConfig BoundConfig { get; private set; }

		private void Awake()
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			BoundConfig = new ModConfig(((BaseUnityPlugin)this).Config);
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			DownedCues.Load(directoryName);
			ProgressSounds.Load(directoryName);
			ItemSounds.Load(directoryName);
			BingBongSounds.Load(directoryName);
			StateSounds.Load(directoryName);
			ChatterSounds.Load(directoryName);
			BingBongFace.Load(directoryName);
			GameObject val = new GameObject("CarlUnleashed");
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<CueTicker>();
			val.AddComponent<ProgressClaimSync>();
			val.AddComponent<RoomWatcher>();
			val.AddComponent<JingleWatcher>();
			val.AddComponent<ChatterWatcher>();
			val.AddComponent<LobbyMusicTicker>();
			val.AddComponent<SoundNetWatcher>();
			val.AddComponent<StateTicker>();
			val.AddComponent<BingBongFaceTicker>();
			harmony.PatchAll();
			ItHurtsBridge.Apply(harmony);
			Log.LogInfo((object)($"CarlUnleashedMod loaded: {StateSounds.Count} state, {ItemSounds.Count} item, " + $"{ProgressSounds.Count} area, {DownedCues.Count} cue, " + $"{BingBongSounds.Count} Bing Bong clip(s). " + $"{FlatClips.Count} flagged 2D."));
			((MonoBehaviour)this).StartCoroutine(ItemAudit.RunLater());
			if (BoundConfig.DumpSounds.Value)
			{
				((MonoBehaviour)this).StartCoroutine(DumpAllSoundsDelayed());
			}
		}

		private IEnumerator Du