Decompiled source of ThunderClap v1.1.0

Mods/ThunderClap.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BoneLib;
using BoneLib.BoneMenu;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Data;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.SDK.Modules;
using LabFusion.Utilities;
using MelonLoader;
using MelonLoader.Preferences;
using ThunderClapNS;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(ThunderClapMod), "ThunderClap", "2.0.0", "Dave", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: AssemblyTitle("FingerGun")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FingerGun")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ebaec34e-ce68-4a24-a6b0-f18b9a726e8b")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ThunderClapNS
{
	public class ThunderClapMod : MelonMod
	{
		[CompilerGenerated]
		private sealed class <PlayTinnitusCoroutine>d__30 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			private GameObject <tempObj>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PlayTinnitusCoroutine>d__30(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<tempObj>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Expected O, but got Unknown
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					AudioClip val = WavUtility.ToAudioClip(_tinnitusWavBytes, "tinnitus");
					if ((Object)(object)val == (Object)null)
					{
						return false;
					}
					<tempObj>5__2 = new GameObject("ThunderClap_TinnitusTemp");
					AudioSource obj = <tempObj>5__2.AddComponent<AudioSource>();
					obj.spatialBlend = 0f;
					obj.volume = 1f;
					obj.clip = val;
					obj.Play();
					MelonLogger.Msg("[ThunderClap] Tinnitus playing in headphones");
					<>2__current = (object)new WaitForSeconds(val.length);
					<>1__state = 1;
					return true;
				}
				case 1:
					<>1__state = -1;
					Object.Destroy((Object)(object)<tempObj>5__2);
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static bool Enabled = false;

		internal static float ExplosionForce = 30f;

		internal static float ExplosionRadius = 8f;

		internal static float NpcDamage = 200f;

		internal static float Cooldown = 1f;

		internal static float ClapThreshold = 0.15f;

		internal static float MinClapSpeed = 2f;

		internal static bool ShowShockwave = true;

		internal static float UpwardsMod = 0.3f;

		internal static bool TinnitusEnabled = true;

		internal static int TinnitusThreshold = 4;

		internal static float TinnitusWindow = 3f;

		private static List<float> _clapTimestamps = new List<float>();

		private static byte[] _tinnitusWavBytes = null;

		private static float _lastDist = 999f;

		private static float _cooldownTimer = 0f;

		private static bool _fusionReady = false;

		private static MelonPreferences_Category _cat;

		private static MelonPreferences_Entry<bool> _prefEnabled;

		private static MelonPreferences_Entry<float> _prefForce;

		private static MelonPreferences_Entry<float> _prefRadius;

		private static MelonPreferences_Entry<float> _prefDamage;

		public override void OnInitializeMelon()
		{
			//IL_00cd: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			_cat = MelonPreferences.CreateCategory("ThunderClap");
			_prefEnabled = _cat.CreateEntry<bool>("Enabled", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_prefForce = _cat.CreateEntry<float>("Force", 30f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_prefRadius = _cat.CreateEntry<float>("Radius", 8f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_prefDamage = _cat.CreateEntry<float>("Damage", 200f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			Enabled = _prefEnabled.Value;
			ExplosionForce = _prefForce.Value;
			ExplosionRadius = _prefRadius.Value;
			NpcDamage = _prefDamage.Value;
			Page obj = Page.Root.CreatePage("Thunder Clap", Color.yellow, 0, true);
			obj.CreateBool("Enabled", Color.green, Enabled, (Action<bool>)delegate(bool v)
			{
				Enabled = v;
				_prefEnabled.Value = v;
				Save();
			});
			obj.CreateFloat("Explosion Force", Color.yellow, ExplosionForce, 5f, 5f, 200f, (Action<float>)delegate(float v)
			{
				ExplosionForce = v;
				_prefForce.Value = v;
				Save();
			});
			obj.CreateFloat("Radius", Color.white, ExplosionRadius, 1f, 2f, 30f, (Action<float>)delegate(float v)
			{
				ExplosionRadius = v;
				_prefRadius.Value = v;
				Save();
			});
			obj.CreateFloat("NPC Damage", Color.red, NpcDamage, 50f, 0f, 5000f, (Action<float>)delegate(float v)
			{
				NpcDamage = v;
				_prefDamage.Value = v;
				Save();
			});
			obj.CreateFloat("Cooldown", Color.white, Cooldown, 0.25f, 0.25f, 5f, (Action<float>)delegate(float v)
			{
				Cooldown = v;
			});
			obj.CreateFloat("Min Clap Speed", Color.white, MinClapSpeed, 0.5f, 0.5f, 10f, (Action<float>)delegate(float v)
			{
				MinClapSpeed = v;
			});
			obj.CreateBool("Shockwave Visual", Color.cyan, ShowShockwave, (Action<bool>)delegate(bool v)
			{
				ShowShockwave = v;
			});
			obj.CreateBool("Tinnitus Effect", Color.magenta, TinnitusEnabled, (Action<bool>)delegate(bool v)
			{
				TinnitusEnabled = v;
			});
			obj.CreateFloat("Tinnitus Claps Needed", Color.white, (float)TinnitusThreshold, 1f, 2f, 10f, (Action<float>)delegate(float v)
			{
				TinnitusThreshold = (int)v;
			});
			MelonLogger.Msg("[ThunderClap] Loaded");
		}

		public override void OnLateInitializeMelon()
		{
			MelonLogger.Msg("[ThunderClap] OnLateInit starting...");
			try
			{
				MelonLogger.Msg("[ThunderClap] Calling LoadTinnitusClip...");
				LoadTinnitusClip();
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"[ThunderClap] WAV CRASH: {arg}");
			}
			try
			{
				RegisterFusion();
			}
			catch
			{
				MelonLogger.Msg("[ThunderClap] Fusion not found — local only");
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void RegisterFusion()
		{
			ModuleMessageManager.RegisterHandler<ThunderClapMessage>();
			_fusionReady = true;
			MelonLogger.Msg("[ThunderClap] Fusion synced");
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool HasFusionServer()
		{
			return NetworkInfo.HasServer;
		}

		private static void Save()
		{
			MelonPreferences.Save();
		}

		private static void LoadTinnitusClip()
		{
			MelonLogger.Msg("[ThunderClap] === LoadTinnitusClip entered ===");
			string text = "ThunderClap.wav.ThunderClap_tinnitus.wav";
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
				MelonLogger.Msg($"[ThunderClap] Embedded resources ({manifestResourceNames.Length}):");
				string[] array = manifestResourceNames;
				foreach (string text2 in array)
				{
					MelonLogger.Msg("[ThunderClap]   -> " + text2);
				}
				Stream manifestResourceStream = executingAssembly.GetManifestResourceStream(text);
				if (manifestResourceStream == null)
				{
					array = manifestResourceNames;
					foreach (string text3 in array)
					{
						if (text3.EndsWith(".wav"))
						{
							text = text3;
							manifestResourceStream = executingAssembly.GetManifestResourceStream(text3);
							break;
						}
					}
				}
				if (manifestResourceStream == null)
				{
					MelonLogger.Error("[ThunderClap] No WAV embedded!");
					return;
				}
				_tinnitusWavBytes = new byte[manifestResourceStream.Length];
				manifestResourceStream.Read(_tinnitusWavBytes, 0, _tinnitusWavBytes.Length);
				manifestResourceStream.Close();
				MelonLogger.Msg($"[ThunderClap] Tinnitus WAV cached: {_tinnitusWavBytes.Length} bytes from {text}");
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"[ThunderClap] WAV load error: {arg}");
			}
		}

		private static void OnClapOccurred(Vector3 clapPos)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			if (!TinnitusEnabled)
			{
				return;
			}
			if (_tinnitusWavBytes == null)
			{
				MelonLogger.Warning("[ThunderClap] No WAV data cached");
				return;
			}
			float now = Time.time;
			_clapTimestamps.Add(now);
			_clapTimestamps.RemoveAll((float t) => now - t > TinnitusWindow);
			MelonLogger.Msg($"[ThunderClap] Clap #{_clapTimestamps.Count}/{TinnitusThreshold}");
			if (_clapTimestamps.Count < TinnitusThreshold)
			{
				return;
			}
			_clapTimestamps.Clear();
			if (_fusionReady)
			{
				try
				{
					if (HasFusionServer())
					{
						SendTinnitusToNetwork(clapPos);
					}
				}
				catch
				{
				}
			}
			MelonLogger.Msg("[ThunderClap] TINNITUS sent to other players!");
		}

		internal static void PlayTinnitus()
		{
			if (_tinnitusWavBytes != null)
			{
				MelonCoroutines.Start(PlayTinnitusCoroutine());
			}
		}

		[IteratorStateMachine(typeof(<PlayTinnitusCoroutine>d__30))]
		private static IEnumerator PlayTinnitusCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PlayTinnitusCoroutine>d__30(0);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void SendTinnitusToNetwork(Vector3 pos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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)
			ThunderClapData obj = new ThunderClapData
			{
				X = pos.x,
				Y = pos.y,
				Z = pos.z,
				Mult = 0f,
				Radius = 0f
			};
			MessageRoute val = default(MessageRoute);
			((MessageRoute)(ref val))..ctor((RelayType)3, (NetworkChannel)0);
			MessageRelay.RelayModule<ThunderClapMessage, ThunderClapData>(obj, val);
		}

		public override void OnUpdate()
		{
			if (!Enabled)
			{
				return;
			}
			if (_cooldownTimer > 0f)
			{
				_cooldownTimer -= Time.deltaTime;
			}
			ShockwaveVisual.Tick();
			try
			{
				DetectClap();
			}
			catch
			{
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void DetectClap()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_008f: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			Hand leftHand = Player.LeftHand;
			Hand rightHand = Player.RightHand;
			if ((Object)(object)leftHand == (Object)null || (Object)(object)rightHand == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)leftHand).transform.position;
			Vector3 position2 = ((Component)rightHand).transform.position;
			float num = Vector3.Distance(position, position2);
			float num2 = (_lastDist - num) / Time.deltaTime;
			_lastDist = num;
			if (!(num < ClapThreshold) || !(num2 > MinClapSpeed) || !(_cooldownTimer <= 0f))
			{
				return;
			}
			Vector3 val = (position + position2) / 2f;
			float num3 = Mathf.Clamp(num2 / MinClapSpeed, 1f, 5f);
			DoExplosion(val, num3);
			OnClapOccurred(val);
			if (_fusionReady)
			{
				try
				{
					if (HasFusionServer())
					{
						SendToNetwork(val, num3);
					}
				}
				catch
				{
				}
			}
			_cooldownTimer = Cooldown;
			_lastDist = 999f;
			MelonLogger.Msg($"[ThunderClap] BOOM! {num2:F1} m/s  x{num3:F1}");
		}

		internal static void DoExplosion(Vector3 center, float mult)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			float num = ExplosionForce * mult;
			Collider[] array = Il2CppArrayBase<Collider>.op_Implicit((Il2CppArrayBase<Collider>)(object)Physics.OverlapSphere(center, ExplosionRadius, -1, (QueryTriggerInteraction)1));
			if (array == null)
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>();
			Collider[] array2 = array;
			foreach (Collider val in array2)
			{
				if ((Object)(object)val == (Object)null || val.isTrigger)
				{
					continue;
				}
				RigManager componentInParent = ((Component)val).GetComponentInParent<RigManager>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					try
					{
						if (FusionPlayer.IsLocalPlayer(componentInParent))
						{
							continue;
						}
					}
					catch
					{
					}
				}
				Rigidbody componentInParent2 = ((Component)val).GetComponentInParent<Rigidbody>();
				if ((Object)(object)componentInParent2 != (Object)null && !componentInParent2.isKinematic && hashSet.Add(((Object)componentInParent2).GetInstanceID()))
				{
					componentInParent2.AddExplosionForce(num, center, ExplosionRadius, UpwardsMod, (ForceMode)1);
				}
				if (!(NpcDamage > 0f))
				{
					continue;
				}
				PlayerDamageReceiver componentInParent3 = ((Component)val).GetComponentInParent<PlayerDamageReceiver>();
				if ((Object)(object)componentInParent3 != (Object)null && hashSet.Add(((Object)componentInParent3).GetInstanceID() + 100000))
				{
					float num2 = 1f - Mathf.Clamp01(Vector3.Distance(center, ((Component)val).transform.position) / ExplosionRadius);
					try
					{
						Attack val2 = new Attack
						{
							damage = NpcDamage * mult * num2
						};
						Vector3 val3 = ((Component)val).transform.position - center;
						val2.normal = ((Vector3)(ref val3)).normalized;
						val2.origin = center;
						val2.backFacing = false;
						val2.attackType = (AttackType)2;
						componentInParent3.ReceiveAttack(val2);
					}
					catch
					{
					}
				}
			}
			if (ShowShockwave)
			{
				ShockwaveVisual.Spawn(center, ExplosionRadius);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void SendToNetwork(Vector3 pos, float mult)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			ThunderClapData obj = new ThunderClapData
			{
				X = pos.x,
				Y = pos.y,
				Z = pos.z,
				Mult = mult,
				Radius = ExplosionRadius
			};
			MessageRoute val = default(MessageRoute);
			((MessageRoute)(ref val))..ctor((RelayType)3, (NetworkChannel)0);
			MessageRelay.RelayModule<ThunderClapMessage, ThunderClapData>(obj, val);
		}
	}
	public class ThunderClapData : INetSerializable
	{
		public float X;

		public float Y;

		public float Z;

		public float Mult;

		public float Radius;

		public int? GetSize()
		{
			return 20;
		}

		public void Serialize(INetSerializer s)
		{
			s.SerializeValue(ref X);
			s.SerializeValue(ref Y);
			s.SerializeValue(ref Z);
			s.SerializeValue(ref Mult);
			s.SerializeValue(ref Radius);
		}
	}
	public class ThunderClapMessage : ModuleMessageHandler
	{
		protected override void OnHandleMessage(ReceivedMessage received)
		{
			//IL_0090: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			ThunderClapData thunderClapData = ((ReceivedMessage)(ref received)).ReadData<ThunderClapData>();
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(thunderClapData.X, thunderClapData.Y, thunderClapData.Z);
			if (thunderClapData.Mult == 0f && thunderClapData.Radius == 0f)
			{
				if (ThunderClapMod.TinnitusEnabled)
				{
					ThunderClapMod.PlayTinnitus();
				}
				MelonLogger.Msg($"[ThunderClap] Remote TINNITUS at ({val.x:F1}, {val.y:F1}, {val.z:F1})");
			}
			else
			{
				if (ThunderClapMod.ShowShockwave)
				{
					ShockwaveVisual.Spawn(val, thunderClapData.Radius);
				}
				MelonLogger.Msg($"[ThunderClap] Remote shockwave at ({val.x:F1}, {val.y:F1}, {val.z:F1})");
			}
		}
	}
	public static class ShockwaveVisual
	{
		private static GameObject _obj = null;

		private static float _timer = 0f;

		private static float _scale = 0f;

		private static float _targetRadius = 8f;

		public static void Spawn(Vector3 pos, float radius)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_obj != (Object)null)
			{
				Object.Destroy((Object)(object)_obj);
			}
			_obj = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)_obj).name = "ThunderClap_Wave";
			_obj.transform.position = pos;
			_obj.transform.localScale = Vector3.one * 0.1f;
			Collider component = _obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			MeshRenderer component2 = _obj.GetComponent<MeshRenderer>();
			if ((Object)(object)component2 != (Object)null)
			{
				Material val = new Material(Shader.Find("Sprites/Default"));
				val.color = new Color(0.6f, 0.8f, 1f, 0.4f);
				val.SetFloat("_Mode", 3f);
				val.SetInt("_SrcBlend", 5);
				val.SetInt("_DstBlend", 10);
				val.SetInt("_ZWrite", 0);
				val.EnableKeyword("_ALPHABLEND_ON");
				val.renderQueue = 3000;
				((Renderer)component2).material = val;
			}
			_scale = 0.1f;
			_timer = 0.3f;
			_targetRadius = radius;
		}

		public static void Tick()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			if (_timer <= 0f)
			{
				return;
			}
			_timer -= Time.deltaTime;
			_scale += Time.deltaTime * _targetRadius * 3f;
			if ((Object)(object)_obj != (Object)null)
			{
				_obj.transform.localScale = Vector3.one * _scale;
				MeshRenderer component = _obj.GetComponent<MeshRenderer>();
				if ((Object)(object)component != (Object)null)
				{
					float num = Mathf.Clamp01(_timer / 0.3f) * 0.4f;
					((Renderer)component).material.color = new Color(0.6f, 0.8f, 1f, num);
				}
			}
			if (_timer <= 0f && (Object)(object)_obj != (Object)null)
			{
				Object.Destroy((Object)(object)_obj);
				_obj = null;
			}
		}
	}
	public static class WavUtility
	{
		public static AudioClip ToAudioClip(byte[] wav, string name = "WavClip")
		{
			try
			{
				if (wav == null || wav.Length < 44)
				{
					MelonLogger.Error("[WavUtility] WAV too small or null");
					return null;
				}
				if (wav[0] != 82 || wav[1] != 73 || wav[2] != 70 || wav[3] != 70)
				{
					MelonLogger.Error("[WavUtility] Not a valid WAV file (no RIFF header)");
					return null;
				}
				int num = BitConverter.ToInt16(wav, 22);
				int num2 = BitConverter.ToInt32(wav, 24);
				int num3 = BitConverter.ToInt16(wav, 34);
				MelonLogger.Msg($"[WavUtility] {num}ch, {num2}Hz, {num3}bit");
				int num4 = -1;
				int num5 = 0;
				for (int i = 12; i < wav.Length - 8; i++)
				{
					if (wav[i] == 100 && wav[i + 1] == 97 && wav[i + 2] == 116 && wav[i + 3] == 97)
					{
						num5 = BitConverter.ToInt32(wav, i + 4);
						num4 = i + 8;
						break;
					}
				}
				if (num4 < 0)
				{
					MelonLogger.Error("[WavUtility] No data chunk found");
					return null;
				}
				if (num4 + num5 > wav.Length)
				{
					num5 = wav.Length - num4;
				}
				float[] array;
				switch (num3)
				{
				case 16:
					array = Convert16BitToFloat(wav, num4, num5);
					break;
				case 8:
					array = Convert8BitToFloat(wav, num4, num5);
					break;
				case 32:
					array = Convert32BitToFloat(wav, num4, num5);
					break;
				default:
					MelonLogger.Error($"[WavUtility] Unsupported bit depth: {num3}");
					return null;
				}
				int num6 = array.Length / num;
				MelonLogger.Msg($"[WavUtility] {array.Length} samples, {num6} frames");
				AudioClip val = AudioClip.Create(name, num6, num, num2, false);
				if ((Object)(object)val == (Object)null)
				{
					MelonLogger.Error("[WavUtility] AudioClip.Create returned null");
					return null;
				}
				val.SetData(Il2CppStructArray<float>.op_Implicit(array), 0);
				MelonLogger.Msg($"[WavUtility] AudioClip created: {val.length:F2}s");
				return val;
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"[WavUtility] {arg}");
				return null;
			}
		}

		private static float[] Convert16BitToFloat(byte[] wav, int offset, int dataSize)
		{
			int num = dataSize / 2;
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				int num2 = offset + i * 2;
				if (num2 + 1 >= wav.Length)
				{
					break;
				}
				short num3 = (short)(wav[num2] | (wav[num2 + 1] << 8));
				array[i] = (float)num3 / 32768f;
			}
			return array;
		}

		private static float[] Convert8BitToFloat(byte[] wav, int offset, int dataSize)
		{
			float[] array = new float[dataSize];
			for (int i = 0; i < dataSize && offset + i < wav.Length; i++)
			{
				array[i] = (float)(wav[offset + i] - 128) / 128f;
			}
			return array;
		}

		private static float[] Convert32BitToFloat(byte[] wav, int offset, int dataSize)
		{
			int num = dataSize / 4;
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				int num2 = offset + i * 4;
				if (num2 + 3 >= wav.Length)
				{
					break;
				}
				array[i] = BitConverter.ToSingle(wav, num2);
			}
			return array;
		}
	}
}
namespace ThunderClapNS.Impl
{
	public class ThunderClapMod : MelonMod
	{
		[CompilerGenerated]
		private sealed class <PlayTinnitusCoroutine>d__30 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public bool localPlayer;

			public Vector3 pos;

			private GameObject <tempObj>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PlayTinnitusCoroutine>d__30(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<tempObj>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				//IL_00db: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e5: Expected O, but got Unknown
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					<tempObj>5__2 = new GameObject("ThunderClap_TinnitusTemp");
					AudioSource val = <tempObj>5__2.AddComponent<AudioSource>();
					val.spatialBlend = (localPlayer ? 0f : 1f);
					val.volume = 1f;
					val.clip = _tinnitusClip;
					if (!localPlayer)
					{
						<tempObj>5__2.transform.position = pos;
						val.minDistance = 1f;
						val.maxDistance = 15f;
						val.rolloffMode = (AudioRolloffMode)1;
					}
					val.Play();
					MelonLogger.Msg($"[ThunderClap] Playing tinnitus (local={localPlayer}, length={_tinnitusClip.length:F1}s)");
					<>2__current = (object)new WaitForSeconds(_tinnitusClip.length);
					<>1__state = 1;
					return true;
				}
				case 1:
					<>1__state = -1;
					Object.Destroy((Object)(object)<tempObj>5__2);
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static bool Enabled = false;

		internal static float ExplosionForce = 30f;

		internal static float ExplosionRadius = 8f;

		internal static float NpcDamage = 200f;

		internal static float Cooldown = 1f;

		internal static float ClapThreshold = 0.15f;

		internal static float MinClapSpeed = 2f;

		internal static bool ShowShockwave = true;

		internal static float UpwardsMod = 0.3f;

		internal static bool TinnitusEnabled = true;

		internal static int TinnitusThreshold = 4;

		internal static float TinnitusWindow = 3f;

		private static List<float> _clapTimestamps = new List<float>();

		private static AudioClip _tinnitusClip = null;

		private static float _lastDist = 999f;

		private static float _cooldownTimer = 0f;

		private static bool _fusionReady = false;

		private static MelonPreferences_Category _cat;

		private static MelonPreferences_Entry<bool> _prefEnabled;

		private static MelonPreferences_Entry<float> _prefForce;

		private static MelonPreferences_Entry<float> _prefRadius;

		private static MelonPreferences_Entry<float> _prefDamage;

		public override void OnInitializeMelon()
		{
			//IL_00cd: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			_cat = MelonPreferences.CreateCategory("ThunderClap");
			_prefEnabled = _cat.CreateEntry<bool>("Enabled", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_prefForce = _cat.CreateEntry<float>("Force", 30f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_prefRadius = _cat.CreateEntry<float>("Radius", 8f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_prefDamage = _cat.CreateEntry<float>("Damage", 200f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			Enabled = _prefEnabled.Value;
			ExplosionForce = _prefForce.Value;
			ExplosionRadius = _prefRadius.Value;
			NpcDamage = _prefDamage.Value;
			Page obj = Page.Root.CreatePage("Thunder Clap", Color.yellow, 0, true);
			obj.CreateBool("Enabled", Color.green, Enabled, (Action<bool>)delegate(bool v)
			{
				Enabled = v;
				_prefEnabled.Value = v;
				Save();
			});
			obj.CreateFloat("Explosion Force", Color.yellow, ExplosionForce, 5f, 5f, 200f, (Action<float>)delegate(float v)
			{
				ExplosionForce = v;
				_prefForce.Value = v;
				Save();
			});
			obj.CreateFloat("Radius", Color.white, ExplosionRadius, 1f, 2f, 30f, (Action<float>)delegate(float v)
			{
				ExplosionRadius = v;
				_prefRadius.Value = v;
				Save();
			});
			obj.CreateFloat("NPC Damage", Color.red, NpcDamage, 50f, 0f, 5000f, (Action<float>)delegate(float v)
			{
				NpcDamage = v;
				_prefDamage.Value = v;
				Save();
			});
			obj.CreateFloat("Cooldown", Color.white, Cooldown, 0.25f, 0.25f, 5f, (Action<float>)delegate(float v)
			{
				Cooldown = v;
			});
			obj.CreateFloat("Min Clap Speed", Color.white, MinClapSpeed, 0.5f, 0.5f, 10f, (Action<float>)delegate(float v)
			{
				MinClapSpeed = v;
			});
			obj.CreateBool("Shockwave Visual", Color.cyan, ShowShockwave, (Action<bool>)delegate(bool v)
			{
				ShowShockwave = v;
			});
			obj.CreateBool("Tinnitus Effect", Color.magenta, TinnitusEnabled, (Action<bool>)delegate(bool v)
			{
				TinnitusEnabled = v;
			});
			obj.CreateFloat("Tinnitus Claps Needed", Color.white, (float)TinnitusThreshold, 1f, 2f, 10f, (Action<float>)delegate(float v)
			{
				TinnitusThreshold = (int)v;
			});
			MelonLogger.Msg("[ThunderClap] Loaded");
		}

		public override void OnLateInitializeMelon()
		{
			try
			{
				LoadTinnitusClip();
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"[ThunderClap] WAV init error: {arg}");
			}
			try
			{
				RegisterFusion();
			}
			catch
			{
				MelonLogger.Msg("[ThunderClap] Fusion not found — local only");
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void RegisterFusion()
		{
			ModuleMessageManager.RegisterHandler<ThunderClapMessage>();
			_fusionReady = true;
			MelonLogger.Msg("[ThunderClap] Fusion synced");
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool HasFusionServer()
		{
			return NetworkInfo.HasServer;
		}

		private static void Save()
		{
			MelonPreferences.Save();
		}

		private static void LoadTinnitusClip()
		{
			string text = "ThunderClapNS.ThunderClap_tinnitus.wav";
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
				MelonLogger.Msg($"[ThunderClap] Embedded resources ({manifestResourceNames.Length}):");
				string[] array = manifestResourceNames;
				foreach (string text2 in array)
				{
					MelonLogger.Msg("[ThunderClap]   -> " + text2);
				}
				using (Stream stream = executingAssembly.GetManifestResourceStream(text))
				{
					if (stream == null)
					{
						array = manifestResourceNames;
						foreach (string text3 in array)
						{
							if (text3.EndsWith(".wav"))
							{
								text = text3;
								MelonLogger.Msg("[ThunderClap] Using found WAV resource: " + text);
								break;
							}
						}
						using Stream stream2 = executingAssembly.GetManifestResourceStream(text);
						if (stream2 == null)
						{
							MelonLogger.Error("[ThunderClap] No WAV resource found! Add the WAV to your project and set Build Action = Embedded Resource");
							return;
						}
						byte[] array2 = new byte[stream2.Length];
						stream2.Read(array2, 0, array2.Length);
						_tinnitusClip = WavUtility.ToAudioClip(array2);
					}
					else
					{
						byte[] array3 = new byte[stream.Length];
						stream.Read(array3, 0, array3.Length);
						MelonLogger.Msg($"[ThunderClap] Loaded {array3.Length} bytes from {text}");
						_tinnitusClip = WavUtility.ToAudioClip(array3);
					}
				}
				if ((Object)(object)_tinnitusClip != (Object)null)
				{
					MelonLogger.Msg($"[ThunderClap] Tinnitus audio READY: {_tinnitusClip.length:F1}s");
				}
				else
				{
					MelonLogger.Error("[ThunderClap] WavUtility returned null clip");
				}
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"[ThunderClap] WAV load error: {arg}");
			}
		}

		private static void OnClapOccurred(Vector3 clapPos)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			if (!TinnitusEnabled)
			{
				return;
			}
			if ((Object)(object)_tinnitusClip == (Object)null)
			{
				MelonLogger.Warning("[ThunderClap] Tinnitus clip null — WAV not loaded");
				return;
			}
			float now = Time.time;
			_clapTimestamps.Add(now);
			_clapTimestamps.RemoveAll((float t) => now - t > TinnitusWindow);
			MelonLogger.Msg($"[ThunderClap] Clap #{_clapTimestamps.Count}/{TinnitusThreshold} (need {TinnitusThreshold} in {TinnitusWindow}s)");
			if (_clapTimestamps.Count < TinnitusThreshold)
			{
				return;
			}
			_clapTimestamps.Clear();
			PlayTinnitus(clapPos, localPlayer: true);
			if (_fusionReady)
			{
				try
				{
					if (HasFusionServer())
					{
						SendTinnitusToNetwork(clapPos);
					}
				}
				catch
				{
				}
			}
			MelonLogger.Msg($"[ThunderClap] TINNITUS triggered after {TinnitusThreshold} rapid claps!");
		}

		internal static void PlayTinnitus(Vector3 pos, bool localPlayer = false)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_tinnitusClip == (Object)null)
			{
				MelonLogger.Warning("[ThunderClap] Tinnitus clip is null!");
			}
			else
			{
				MelonCoroutines.Start(PlayTinnitusCoroutine(pos, localPlayer));
			}
		}

		[IteratorStateMachine(typeof(<PlayTinnitusCoroutine>d__30))]
		private static IEnumerator PlayTinnitusCoroutine(Vector3 pos, bool localPlayer)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PlayTinnitusCoroutine>d__30(0)
			{
				pos = pos,
				localPlayer = localPlayer
			};
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void SendTinnitusToNetwork(Vector3 pos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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)
			ThunderClapData obj = new ThunderClapData
			{
				X = pos.x,
				Y = pos.y,
				Z = pos.z,
				Mult = 0f,
				Radius = 0f
			};
			MessageRoute val = default(MessageRoute);
			((MessageRoute)(ref val))..ctor((RelayType)3, (NetworkChannel)0);
			MessageRelay.RelayModule<ThunderClapMessage, ThunderClapData>(obj, val);
		}

		public override void OnUpdate()
		{
			if (!Enabled)
			{
				return;
			}
			if (_cooldownTimer > 0f)
			{
				_cooldownTimer -= Time.deltaTime;
			}
			ShockwaveVisual.Tick();
			try
			{
				DetectClap();
			}
			catch
			{
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void DetectClap()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_008f: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			Hand leftHand = Player.LeftHand;
			Hand rightHand = Player.RightHand;
			if ((Object)(object)leftHand == (Object)null || (Object)(object)rightHand == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)leftHand).transform.position;
			Vector3 position2 = ((Component)rightHand).transform.position;
			float num = Vector3.Distance(position, position2);
			float num2 = (_lastDist - num) / Time.deltaTime;
			_lastDist = num;
			if (!(num < ClapThreshold) || !(num2 > MinClapSpeed) || !(_cooldownTimer <= 0f))
			{
				return;
			}
			Vector3 val = (position + position2) / 2f;
			float num3 = Mathf.Clamp(num2 / MinClapSpeed, 1f, 5f);
			DoExplosion(val, num3);
			OnClapOccurred(val);
			if (_fusionReady)
			{
				try
				{
					if (HasFusionServer())
					{
						SendToNetwork(val, num3);
					}
				}
				catch
				{
				}
			}
			_cooldownTimer = Cooldown;
			_lastDist = 999f;
			MelonLogger.Msg($"[ThunderClap] BOOM! {num2:F1} m/s  x{num3:F1}");
		}

		internal static void DoExplosion(Vector3 center, float mult)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			float num = ExplosionForce * mult;
			Collider[] array = Il2CppArrayBase<Collider>.op_Implicit((Il2CppArrayBase<Collider>)(object)Physics.OverlapSphere(center, ExplosionRadius, -1, (QueryTriggerInteraction)1));
			if (array == null)
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>();
			Collider[] array2 = array;
			foreach (Collider val in array2)
			{
				if ((Object)(object)val == (Object)null || val.isTrigger)
				{
					continue;
				}
				RigManager componentInParent = ((Component)val).GetComponentInParent<RigManager>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					try
					{
						if (FusionPlayer.IsLocalPlayer(componentInParent))
						{
							continue;
						}
					}
					catch
					{
					}
				}
				Rigidbody componentInParent2 = ((Component)val).GetComponentInParent<Rigidbody>();
				if ((Object)(object)componentInParent2 != (Object)null && !componentInParent2.isKinematic && hashSet.Add(((Object)componentInParent2).GetInstanceID()))
				{
					componentInParent2.AddExplosionForce(num, center, ExplosionRadius, UpwardsMod, (ForceMode)1);
				}
				if (!(NpcDamage > 0f))
				{
					continue;
				}
				PlayerDamageReceiver componentInParent3 = ((Component)val).GetComponentInParent<PlayerDamageReceiver>();
				if ((Object)(object)componentInParent3 != (Object)null && hashSet.Add(((Object)componentInParent3).GetInstanceID() + 100000))
				{
					float num2 = 1f - Mathf.Clamp01(Vector3.Distance(center, ((Component)val).transform.position) / ExplosionRadius);
					try
					{
						Attack val2 = new Attack
						{
							damage = NpcDamage * mult * num2
						};
						Vector3 val3 = ((Component)val).transform.position - center;
						val2.normal = ((Vector3)(ref val3)).normalized;
						val2.origin = center;
						val2.backFacing = false;
						val2.attackType = (AttackType)2;
						componentInParent3.ReceiveAttack(val2);
					}
					catch
					{
					}
				}
			}
			if (ShowShockwave)
			{
				ShockwaveVisual.Spawn(center, ExplosionRadius);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void SendToNetwork(Vector3 pos, float mult)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			ThunderClapData obj = new ThunderClapData
			{
				X = pos.x,
				Y = pos.y,
				Z = pos.z,
				Mult = mult,
				Radius = ExplosionRadius
			};
			MessageRoute val = default(MessageRoute);
			((MessageRoute)(ref val))..ctor((RelayType)3, (NetworkChannel)0);
			MessageRelay.RelayModule<ThunderClapMessage, ThunderClapData>(obj, val);
		}
	}
	public class ThunderClapData : INetSerializable
	{
		public float X;

		public float Y;

		public float Z;

		public float Mult;

		public float Radius;

		public int? GetSize()
		{
			return 20;
		}

		public void Serialize(INetSerializer s)
		{
			s.SerializeValue(ref X);
			s.SerializeValue(ref Y);
			s.SerializeValue(ref Z);
			s.SerializeValue(ref Mult);
			s.SerializeValue(ref Radius);
		}
	}
	public class ThunderClapMessage : ModuleMessageHandler
	{
		protected override void OnHandleMessage(ReceivedMessage received)
		{
			//IL_0092: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_0059: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			ThunderClapData thunderClapData = ((ReceivedMessage)(ref received)).ReadData<ThunderClapData>();
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(thunderClapData.X, thunderClapData.Y, thunderClapData.Z);
			if (thunderClapData.Mult == 0f && thunderClapData.Radius == 0f)
			{
				if (ThunderClapMod.TinnitusEnabled)
				{
					ThunderClapMod.PlayTinnitus(val);
				}
				MelonLogger.Msg($"[ThunderClap] Remote TINNITUS at ({val.x:F1}, {val.y:F1}, {val.z:F1})");
			}
			else
			{
				if (ThunderClapMod.ShowShockwave)
				{
					ShockwaveVisual.Spawn(val, thunderClapData.Radius);
				}
				MelonLogger.Msg($"[ThunderClap] Remote shockwave at ({val.x:F1}, {val.y:F1}, {val.z:F1})");
			}
		}
	}
	public static class ShockwaveVisual
	{
		private static GameObject _obj = null;

		private static float _timer = 0f;

		private static float _scale = 0f;

		private static float _targetRadius = 8f;

		public static void Spawn(Vector3 pos, float radius)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_obj != (Object)null)
			{
				Object.Destroy((Object)(object)_obj);
			}
			_obj = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)_obj).name = "ThunderClap_Wave";
			_obj.transform.position = pos;
			_obj.transform.localScale = Vector3.one * 0.1f;
			Collider component = _obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			MeshRenderer component2 = _obj.GetComponent<MeshRenderer>();
			if ((Object)(object)component2 != (Object)null)
			{
				Material val = new Material(Shader.Find("Sprites/Default"));
				val.color = new Color(0.6f, 0.8f, 1f, 0.4f);
				val.SetFloat("_Mode", 3f);
				val.SetInt("_SrcBlend", 5);
				val.SetInt("_DstBlend", 10);
				val.SetInt("_ZWrite", 0);
				val.EnableKeyword("_ALPHABLEND_ON");
				val.renderQueue = 3000;
				((Renderer)component2).material = val;
			}
			_scale = 0.1f;
			_timer = 0.3f;
			_targetRadius = radius;
		}

		public static void Tick()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			if (_timer <= 0f)
			{
				return;
			}
			_timer -= Time.deltaTime;
			_scale += Time.deltaTime * _targetRadius * 3f;
			if ((Object)(object)_obj != (Object)null)
			{
				_obj.transform.localScale = Vector3.one * _scale;
				MeshRenderer component = _obj.GetComponent<MeshRenderer>();
				if ((Object)(object)component != (Object)null)
				{
					float num = Mathf.Clamp01(_timer / 0.3f) * 0.4f;
					((Renderer)component).material.color = new Color(0.6f, 0.8f, 1f, num);
				}
			}
			if (_timer <= 0f && (Object)(object)_obj != (Object)null)
			{
				Object.Destroy((Object)(object)_obj);
				_obj = null;
			}
		}
	}
	public static class WavUtility
	{
		public static AudioClip ToAudioClip(byte[] wav)
		{
			try
			{
				if (wav == null || wav.Length < 44)
				{
					MelonLogger.Error("[WavUtility] WAV too small or null");
					return null;
				}
				if (wav[0] != 82 || wav[1] != 73 || wav[2] != 70 || wav[3] != 70)
				{
					MelonLogger.Error("[WavUtility] Not a valid WAV file (no RIFF header)");
					return null;
				}
				int num = BitConverter.ToInt16(wav, 22);
				int num2 = BitConverter.ToInt32(wav, 24);
				int num3 = BitConverter.ToInt16(wav, 34);
				MelonLogger.Msg($"[WavUtility] {num}ch, {num2}Hz, {num3}bit");
				int num4 = -1;
				int num5 = 0;
				for (int i = 12; i < wav.Length - 8; i++)
				{
					if (wav[i] == 100 && wav[i + 1] == 97 && wav[i + 2] == 116 && wav[i + 3] == 97)
					{
						num5 = BitConverter.ToInt32(wav, i + 4);
						num4 = i + 8;
						break;
					}
				}
				if (num4 < 0)
				{
					MelonLogger.Error("[WavUtility] No data chunk found");
					return null;
				}
				if (num4 + num5 > wav.Length)
				{
					num5 = wav.Length - num4;
				}
				float[] array;
				switch (num3)
				{
				case 16:
					array = Convert16BitToFloat(wav, num4, num5);
					break;
				case 8:
					array = Convert8BitToFloat(wav, num4, num5);
					break;
				case 32:
					array = Convert32BitToFloat(wav, num4, num5);
					break;
				default:
					MelonLogger.Error($"[WavUtility] Unsupported bit depth: {num3}");
					return null;
				}
				int num6 = array.Length / num;
				MelonLogger.Msg($"[WavUtility] {array.Length} samples, {num6} frames");
				AudioClip val = AudioClip.Create("WavClip", num6, num, num2, false);
				if ((Object)(object)val == (Object)null)
				{
					MelonLogger.Error("[WavUtility] AudioClip.Create returned null");
					return null;
				}
				val.SetData(Il2CppStructArray<float>.op_Implicit(array), 0);
				MelonLogger.Msg($"[WavUtility] AudioClip created: {val.length:F2}s");
				return val;
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"[WavUtility] {arg}");
				return null;
			}
		}

		private static float[] Convert16BitToFloat(byte[] wav, int offset, int dataSize)
		{
			int num = dataSize / 2;
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				int num2 = offset + i * 2;
				if (num2 + 1 >= wav.Length)
				{
					break;
				}
				short num3 = (short)(wav[num2] | (wav[num2 + 1] << 8));
				array[i] = (float)num3 / 32768f;
			}
			return array;
		}

		private static float[] Convert8BitToFloat(byte[] wav, int offset, int dataSize)
		{
			float[] array = new float[dataSize];
			for (int i = 0; i < dataSize && offset + i < wav.Length; i++)
			{
				array[i] = (float)(wav[offset + i] - 128) / 128f;
			}
			return array;
		}

		private static float[] Convert32BitToFloat(byte[] wav, int offset, int dataSize)
		{
			int num = dataSize / 4;
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				int num2 = offset + i * 4;
				if (num2 + 3 >= wav.Length)
				{
					break;
				}
				array[i] = BitConverter.ToSingle(wav, num2);
			}
			return array;
		}
	}
}