Decompiled source of RandomFoxyJumpscare v1.0.2

Mods/RandomFoxyJumpscare.dll

Decompiled 15 hours 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 System.Text;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using MelonLoader;
using MelonLoader.Utils;
using RandomFoxyJumpscare;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "RandomFoxyJumpscare", "1.0.2", "Supercopia", null)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("RandomFoxyJumpscare")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RandomFoxyJumpscare")]
[assembly: AssemblyTitle("RandomFoxyJumpscare")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace RandomFoxyJumpscare;

public class Core : MelonMod
{
	private GameObject _jumpscareQuad;

	private GameObject _testQuad;

	private MeshRenderer _renderer;

	private MeshRenderer _testRenderer;

	private readonly List<Texture2D> _frames = new List<Texture2D>();

	private Texture2D _testTexture;

	private Camera _vrCamera;

	private AudioClip _scareClip;

	private AudioSource _audioSource;

	private float _jumpscareTimer;

	private int _currentFrame;

	private bool _jumpscareActive;

	private bool _ready;

	private bool _testMode;

	private long _lastCheckedSecond;

	private const int CHANCE = 10000;

	private const float FRAME_FPS = 24f;

	private const float FRAME_DURATION = 1f / 24f;

	private const float DISTANCE = 0.2f;

	private const float SIZE = 0.386f;

	public override void OnSceneWasLoaded(int buildIndex, string sceneName)
	{
		Cleanup();
		if (!(sceneName != "Gym") || !(sceneName != "Map0") || !(sceneName != "Map1") || !(sceneName != "Park"))
		{
			MelonCoroutines.Start(SetupDelayed());
		}
	}

	private IEnumerator SetupDelayed()
	{
		yield return (object)new WaitForSeconds(2f);
		if (!LoadFrames())
		{
			yield break;
		}
		_vrCamera = Camera.main;
		if ((Object)(object)_vrCamera == (Object)null)
		{
			Il2CppReferenceArray<Camera> allCameras = Camera.allCameras;
			for (int i = 0; i < ((Il2CppArrayBase<Camera>)(object)allCameras).Count; i++)
			{
				if ((Object)(object)((Il2CppArrayBase<Camera>)(object)allCameras)[i] != (Object)null && ((Behaviour)((Il2CppArrayBase<Camera>)(object)allCameras)[i]).isActiveAndEnabled)
				{
					_vrCamera = ((Il2CppArrayBase<Camera>)(object)allCameras)[i];
					break;
				}
			}
		}
		if ((Object)(object)_vrCamera == (Object)null)
		{
			((MelonBase)this).LoggerInstance.Warning("No camera found — jumpscare disabled");
			yield break;
		}
		CreateJumpscareQuad();
		if ((Object)(object)_scareClip != (Object)null && (Object)(object)_vrCamera != (Object)null)
		{
			_audioSource = ((Component)_vrCamera).gameObject.AddComponent<AudioSource>();
		}
		_jumpscareActive = false;
		_ready = true;
		((MelonBase)this).LoggerInstance.Msg($"Jumpscare ready! {_frames.Count} frames, 1/{10000} chance per second");
	}

	private bool LoadFrames()
	{
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Expected O, but got Unknown
		string text = Path.Combine(MelonEnvironment.UserDataDirectory, "RandomFoxyJumpscare");
		if (!Directory.Exists(text))
		{
			Directory.CreateDirectory(text);
			((MelonBase)this).LoggerInstance.Warning("Place frame_0.png, frame_1.png, etc. in: " + text);
			return false;
		}
		string path = Path.Combine(text, "scare.wav");
		if (File.Exists(path))
		{
			_scareClip = LoadWavAsClip(path);
			if ((Object)(object)_scareClip != (Object)null)
			{
				((MelonBase)this).LoggerInstance.Msg("Scare sound loaded");
			}
			else
			{
				((MelonBase)this).LoggerInstance.Warning("Failed to parse scare.wav");
			}
		}
		else
		{
			((MelonBase)this).LoggerInstance.Warning("scare.wav not found — jumpscare will be silent");
		}
		int num = 0;
		while (true)
		{
			string text2 = Path.Combine(text, $"frame_{num}.png");
			if (!File.Exists(text2))
			{
				break;
			}
			try
			{
				byte[] array = File.ReadAllBytes(text2);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				Il2CppStructArray<byte> val2 = new Il2CppStructArray<byte>((long)array.Length);
				Marshal.Copy(array, 0, ((Il2CppObjectBase)val2).Pointer + 4 * IntPtr.Size, array.Length);
				if (ImageConversion.LoadImage(val, val2, false))
				{
					((Texture)val).filterMode = (FilterMode)0;
					_frames.Add(val);
				}
				else
				{
					((MelonBase)this).LoggerInstance.Warning("Failed to load: " + text2);
					Object.Destroy((Object)(object)val);
				}
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Error loading " + text2 + ": " + ex.Message);
			}
			num++;
		}
		if (_frames.Count == 0 && (Object)(object)_testTexture == (Object)null)
		{
			((MelonBase)this).LoggerInstance.Warning("No frames found in " + text);
			return false;
		}
		((MelonBase)this).LoggerInstance.Msg($"Loaded {_frames.Count} jumpscare frames" + (_testMode ? " + test frame" : ""));
		return true;
	}

	private GameObject CreateQuad(string name, Texture2D texture, int renderQueue)
	{
		//IL_0050: 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_0091: 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_00f9: Expected O, but got Unknown
		GameObject val = GameObject.CreatePrimitive((PrimitiveType)5);
		((Object)val).name = name;
		Collider component = val.GetComponent<Collider>();
		if ((Object)(object)component != (Object)null)
		{
			Object.Destroy((Object)(object)component);
		}
		val.transform.SetParent(((Component)_vrCamera).transform, false);
		val.transform.localPosition = new Vector3(0f, 0f, 0.2f);
		float num = (float)((Texture)texture).width / (float)((Texture)texture).height;
		val.transform.localScale = new Vector3(0.386f * num, 0.386f, 1f);
		val.transform.localRotation = Quaternion.identity;
		Shader val2 = Shader.Find("Sprites/Default") ?? Shader.Find("UI/Default") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Unlit/Transparent");
		if ((Object)(object)val2 == (Object)null)
		{
			((MelonBase)this).LoggerInstance.Error("No suitable transparent shader found!");
			Object.Destroy((Object)(object)val);
			return null;
		}
		Material val3 = new Material(val2);
		val3.mainTexture = (Texture)(object)texture;
		val3.renderQueue = renderQueue;
		((Renderer)val.GetComponent<MeshRenderer>()).material = val3;
		return val;
	}

	private void CreateJumpscareQuad()
	{
		if (_testMode && (Object)(object)_testTexture != (Object)null)
		{
			_testQuad = CreateQuad("TestFrame", _testTexture, 3999);
			if ((Object)(object)_testQuad != (Object)null)
			{
				_testRenderer = _testQuad.GetComponent<MeshRenderer>();
				_testQuad.SetActive(true);
			}
		}
		if (_frames.Count > 0)
		{
			_jumpscareQuad = CreateQuad("FoxyJumpscare", _frames[0], 4000);
			if ((Object)(object)_jumpscareQuad != (Object)null)
			{
				_renderer = _jumpscareQuad.GetComponent<MeshRenderer>();
				_jumpscareQuad.SetActive(false);
			}
		}
	}

	public override void OnUpdate()
	{
		if (!_ready || (Object)(object)_jumpscareQuad == (Object)null || _frames.Count == 0)
		{
			return;
		}
		if (_jumpscareActive)
		{
			_jumpscareTimer += Time.deltaTime;
			int num = (int)(_jumpscareTimer / (1f / 24f));
			if (num >= _frames.Count)
			{
				_jumpscareActive = false;
				_jumpscareQuad.SetActive(false);
			}
			else if (num != _currentFrame)
			{
				_currentFrame = num;
				((Renderer)_renderer).material.mainTexture = (Texture)(object)_frames[_currentFrame];
				((Renderer)_renderer).material.SetTexture("_BaseMap", (Texture)(object)_frames[_currentFrame]);
			}
			return;
		}
		long num2 = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
		if (num2 == _lastCheckedSecond)
		{
			return;
		}
		_lastCheckedSecond = num2;
		if (new Random((int)(num2 * 2654435761u >> 16)).Next(10000) == 0)
		{
			((MelonBase)this).LoggerInstance.Msg("Boo!");
			if ((Object)(object)_scareClip != (Object)null && (Object)(object)_audioSource != (Object)null)
			{
				_audioSource.PlayOneShot(_scareClip);
			}
			_jumpscareActive = true;
			_jumpscareTimer = 0f;
			_currentFrame = 0;
			((Renderer)_renderer).material.mainTexture = (Texture)(object)_frames[0];
			((Renderer)_renderer).material.SetTexture("_BaseMap", (Texture)(object)_frames[0]);
			_jumpscareQuad.SetActive(true);
		}
	}

	private AudioClip LoadWavAsClip(string path)
	{
		try
		{
			byte[] array = File.ReadAllBytes(path);
			int num = BitConverter.ToInt16(array, 22);
			int num2 = BitConverter.ToInt32(array, 24);
			int num3 = BitConverter.ToInt16(array, 34);
			int num4;
			for (int i = 12; i < array.Length - 8; i += 8 + num4)
			{
				string @string = Encoding.ASCII.GetString(array, i, 4);
				num4 = BitConverter.ToInt32(array, i + 4);
				if (!(@string == "data"))
				{
					continue;
				}
				i += 8;
				int num5 = Math.Min(num4, array.Length - i);
				int num6 = num3 / 8;
				int num7 = num5 / num6;
				float[] array2 = new float[num7];
				for (int j = 0; j < num7; j++)
				{
					int num8 = i + j * num6;
					switch (num3)
					{
					case 16:
						array2[j] = (float)BitConverter.ToInt16(array, num8) / 32768f;
						break;
					case 24:
					{
						int num9 = array[num8] | (array[num8 + 1] << 8) | (array[num8 + 2] << 16);
						if (num9 >= 8388608)
						{
							num9 -= 16777216;
						}
						array2[j] = (float)num9 / 8388608f;
						break;
					}
					case 32:
						array2[j] = (float)BitConverter.ToInt32(array, num8) / 2.1474836E+09f;
						break;
					default:
						array2[j] = (float)(array[num8] - 128) / 128f;
						break;
					}
				}
				int num10 = num7 / num;
				AudioClip obj = AudioClip.Create("ScareSound", num10, num, num2, false);
				Il2CppStructArray<float> val = new Il2CppStructArray<float>((long)array2.Length);
				Marshal.Copy(array2, 0, ((Il2CppObjectBase)val).Pointer + 4 * IntPtr.Size, array2.Length);
				obj.SetData(val, 0);
				return obj;
			}
			((MelonBase)this).LoggerInstance.Error("WAV file has no data chunk");
			return null;
		}
		catch (Exception ex)
		{
			((MelonBase)this).LoggerInstance.Error("Error parsing WAV: " + ex.Message);
			return null;
		}
	}

	private void Cleanup()
	{
		_ready = false;
		_jumpscareActive = false;
		if ((Object)(object)_jumpscareQuad != (Object)null)
		{
			Object.Destroy((Object)(object)_jumpscareQuad);
			_jumpscareQuad = null;
		}
		if ((Object)(object)_testQuad != (Object)null)
		{
			Object.Destroy((Object)(object)_testQuad);
			_testQuad = null;
		}
		foreach (Texture2D frame in _frames)
		{
			if ((Object)(object)frame != (Object)null)
			{
				Object.Destroy((Object)(object)frame);
			}
		}
		_frames.Clear();
		if ((Object)(object)_testTexture != (Object)null)
		{
			Object.Destroy((Object)(object)_testTexture);
			_testTexture = null;
		}
		if ((Object)(object)_audioSource != (Object)null)
		{
			Object.Destroy((Object)(object)_audioSource);
			_audioSource = null;
		}
		if ((Object)(object)_scareClip != (Object)null)
		{
			Object.Destroy((Object)(object)_scareClip);
			_scareClip = null;
		}
		_renderer = null;
		_testRenderer = null;
		_vrCamera = null;
	}

	public override void OnDeinitializeMelon()
	{
		Cleanup();
	}
}