Decompiled source of ShellShock v1.1.0

ShellShock.dll

Decompiled 2 days 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 Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using MelonLoader;
using ShellShock;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Main), "ShellShock", "1.0.0", "CooladTheGreat", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: AssemblyTitle("ShellShock")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ShellShock")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("241513f7-06c6-4c07-ba97-cf1bc358eabe")]
[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 ShellShock;

public class Main : MelonMod
{
	[CompilerGenerated]
	private sealed class <PlayHeartbeatCoroutine>d__13 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		private byte[] <wavData>5__1;

		private AudioClip <clip>5__2;

		private GameObject <audioObj>5__3;

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

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

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

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<wavData>5__1 = null;
			<clip>5__2 = null;
			<audioObj>5__3 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			if (<>1__state != 0)
			{
				return false;
			}
			<>1__state = -1;
			<wavData>5__1 = LoadEmbeddedWAV("ShellShock.Heartbeatsound.Heartbeat.wav");
			if (<wavData>5__1 == null)
			{
				return false;
			}
			<clip>5__2 = WavUtility.ToAudioClip(<wavData>5__1, "Heartbeat");
			if ((Object)(object)<clip>5__2 == (Object)null)
			{
				return false;
			}
			<audioObj>5__3 = new GameObject("ShellShock_Heartbeat");
			Object.DontDestroyOnLoad((Object)(object)<audioObj>5__3);
			heartbeatSource = <audioObj>5__3.AddComponent<AudioSource>();
			heartbeatSource.spatialBlend = 0f;
			heartbeatSource.volume = 1f;
			heartbeatSource.clip = <clip>5__2;
			heartbeatSource.loop = true;
			heartbeatSource.Play();
			MelonLogger.Msg("Heartbeat audio started (looping)");
			return false;
		}

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

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

	[CompilerGenerated]
	private sealed class <ShellshockWatcher>d__11 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		private float <currentHealth>5__1;

		private float <maxHealth>5__2;

		private float <thresholdHealth>5__3;

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

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

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

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

		private bool MoveNext()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				break;
			case 1:
				<>1__state = -1;
				if (!((Object)(object)Player.RigManager == (Object)null) && !((Object)(object)Player.RigManager.health == (Object)null))
				{
					<currentHealth>5__1 = Player.RigManager.health.curr_Health;
					<maxHealth>5__2 = Player.RigManager.health.max_Health;
					<thresholdHealth>5__3 = <maxHealth>5__2 * 0.4f;
					if (<currentHealth>5__1 <= <thresholdHealth>5__3 && !isShellshockActive)
					{
						isShellshockActive = true;
						MelonLogger.Msg("ShellShock active: Starting effects.");
						StartShellshockEffects();
					}
					else if (<currentHealth>5__1 > <thresholdHealth>5__3 && isShellshockActive)
					{
						isShellshockActive = false;
						MelonLogger.Msg("ShellShock deactivated: Stopping effects.");
						StopShellshockEffects();
					}
				}
				break;
			}
			<>2__current = (object)new WaitForEndOfFrame();
			<>1__state = 1;
			return true;
		}

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

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

	private static AudioLowPassFilter activeListenerFilter;

	private static AudioSource heartbeatSource;

	private const float ShellshockCutoffFrequency = 800f;

	private const float ShellshockThresholdPercent = 40f;

	private static bool isShellshockActive;

	private static GameObject listenerObject;

	private const string HeartbeatResource = "ShellShock.Heartbeatsound.Heartbeat.wav";

	public override void OnInitializeMelon()
	{
		MelonLogger.Msg("ShellShock mod initialized. Watching for low health...");
		MelonCoroutines.Start(ShellshockWatcher());
	}

	private static void FindListenerObject()
	{
		AudioListener val = Object.FindObjectOfType<AudioListener>();
		listenerObject = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null);
		if ((Object)(object)listenerObject == (Object)null)
		{
			MelonLogger.Error("Could not find the AudioListener.");
		}
	}

	private static void StartShellshockEffects()
	{
		if ((Object)(object)listenerObject == (Object)null)
		{
			FindListenerObject();
		}
		if (!((Object)(object)listenerObject == (Object)null))
		{
			if ((Object)(object)activeListenerFilter == (Object)null)
			{
				activeListenerFilter = listenerObject.AddComponent<AudioLowPassFilter>();
				activeListenerFilter.cutoffFrequency = 800f;
			}
			StartHeartbeatLoop();
		}
	}

	private static void StopShellshockEffects()
	{
		if ((Object)(object)activeListenerFilter != (Object)null)
		{
			Object.Destroy((Object)(object)activeListenerFilter);
			activeListenerFilter = null;
		}
		if ((Object)(object)heartbeatSource != (Object)null)
		{
			heartbeatSource.Stop();
			Object.Destroy((Object)(object)((Component)heartbeatSource).gameObject);
			heartbeatSource = null;
		}
	}

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

	private static void StartHeartbeatLoop()
	{
		if (!((Object)(object)heartbeatSource != (Object)null))
		{
			MelonCoroutines.Start(PlayHeartbeatCoroutine());
		}
	}

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

	private static byte[] LoadEmbeddedWAV(string resourceName)
	{
		try
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			MelonLogger.Msg("Looking for resource: " + resourceName);
			string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
			string[] array = manifestResourceNames;
			foreach (string text in array)
			{
				MelonLogger.Msg("Found resource: " + text);
			}
			using Stream stream = executingAssembly.GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				MelonLogger.Error("Resource '" + resourceName + "' not found!");
				return null;
			}
			byte[] array2 = new byte[stream.Length];
			stream.Read(array2, 0, array2.Length);
			MelonLogger.Msg($"Loaded WAV: {array2.Length} bytes");
			return array2;
		}
		catch (Exception arg)
		{
			MelonLogger.Error($"Error loading WAV: {arg}");
			return null;
		}
	}

	public override void OnDeinitializeMelon()
	{
		StopShellshockEffects();
		MelonLogger.Msg("ShellShock mod deinitialized.");
	}
}
public static class WavUtility
{
	public static AudioClip ToAudioClip(byte[] wavBytes, string name = "wav")
	{
		try
		{
			if (!IsValidWav(wavBytes))
			{
				Debug.LogError(Object.op_Implicit("Invalid WAV file format"));
				return null;
			}
			int num = BitConverter.ToInt16(wavBytes, 22);
			int num2 = BitConverter.ToInt32(wavBytes, 24);
			int num3 = BitConverter.ToInt16(wavBytes, 34);
			int num4 = FindDataChunk(wavBytes);
			if (num4 == -1)
			{
				Debug.LogError(Object.op_Implicit("Data chunk not found in WAV file"));
				return null;
			}
			int dataSize = BitConverter.ToInt32(wavBytes, num4 + 4);
			int startIndex = num4 + 8;
			float[] array;
			switch (num3)
			{
			case 16:
				array = Convert16BitToFloat(wavBytes, startIndex, dataSize);
				break;
			case 8:
				array = Convert8BitToFloat(wavBytes, startIndex, dataSize);
				break;
			case 32:
				array = Convert32BitToFloat(wavBytes, startIndex, dataSize);
				break;
			default:
				Debug.LogError(Object.op_Implicit($"Unsupported bit depth: {num3}"));
				return null;
			}
			AudioClip val = AudioClip.Create(name, array.Length / num, num, num2, false);
			val.SetData(Il2CppStructArray<float>.op_Implicit(array), 0);
			return val;
		}
		catch (Exception arg)
		{
			Debug.LogError(Object.op_Implicit($"Error converting WAV to AudioClip: {arg}"));
			return null;
		}
	}

	private static bool IsValidWav(byte[] wavBytes)
	{
		if (wavBytes.Length < 12)
		{
			return false;
		}
		if (wavBytes[0] != 82 || wavBytes[1] != 73 || wavBytes[2] != 70 || wavBytes[3] != 70)
		{
			return false;
		}
		if (wavBytes[8] != 87 || wavBytes[9] != 65 || wavBytes[10] != 86 || wavBytes[11] != 69)
		{
			return false;
		}
		return true;
	}

	private static int FindDataChunk(byte[] wavBytes)
	{
		int num;
		for (int i = 12; i < wavBytes.Length - 8; i += 8 + num)
		{
			if (wavBytes[i] == 100 && wavBytes[i + 1] == 97 && wavBytes[i + 2] == 116 && wavBytes[i + 3] == 97)
			{
				return i;
			}
			num = BitConverter.ToInt32(wavBytes, i + 4);
		}
		return -1;
	}

	private static float[] Convert16BitToFloat(byte[] bytes, int startIndex, int dataSize)
	{
		int num = dataSize / 2;
		float[] array = new float[num];
		for (int i = 0; i < num; i++)
		{
			short num2 = BitConverter.ToInt16(bytes, startIndex + i * 2);
			array[i] = (float)num2 / 32768f;
		}
		return array;
	}

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

	private static float[] Convert32BitToFloat(byte[] bytes, int startIndex, int dataSize)
	{
		int num = dataSize / 4;
		float[] array = new float[num];
		for (int i = 0; i < num; i++)
		{
			float num2 = BitConverter.ToSingle(bytes, startIndex + i * 4);
			array[i] = Mathf.Clamp(num2, -1f, 1f);
		}
		return array;
	}
}