Decompiled source of QuickFoxy v1.0.1

Mods/QuickFoxy.dll

Decompiled 9 hours ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BoneLib;
using BoneLib.BoneMenu;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using QuickFoxy;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.XR;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(QuickFoxyMod), "QuickFoxy", "1.0.1", "nontendo", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("QuickFoxy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("QuickFoxy")]
[assembly: AssemblyTitle("QuickFoxy")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace QuickFoxy
{
	public static class FoxyController
	{
		private const int FrameCount = 13;

		private const float FrameTime = 0.06f;

		private static Texture2D[]? _frames;

		private static AudioClip? _clip;

		private static bool _loadTried;

		private static GameObject? _quad;

		private static MeshRenderer? _mr;

		private static Material? _mat;

		private static AudioSource? _src;

		private static float _rollTimer;

		private static bool _scaring;

		private static float _scareStart;

		private static float _scareLen = 1.8f;

		public static void Update()
		{
			if (!FoxySettings.Enabled)
			{
				if (_scaring)
				{
					EndScare();
				}
				return;
			}
			if (_scaring)
			{
				UpdateScare();
				return;
			}
			_rollTimer += Time.deltaTime;
			if (!(_rollTimer < 1f))
			{
				_rollTimer -= 1f;
				int num = Mathf.Max(1, FoxySettings.Odds);
				if (Random.Range(0, num) == 0)
				{
					Trigger();
				}
			}
		}

		public static void Trigger()
		{
			EnsureAssets();
			if (_frames != null && !((Object)(object)_quad == (Object)null))
			{
				_scaring = true;
				_scareStart = Time.time;
				if ((Object)(object)_src != (Object)null && (Object)(object)_clip != (Object)null)
				{
					_scareLen = Mathf.Max(0.8f, _clip.length);
					_src.clip = _clip;
					_src.volume = Mathf.Clamp01(FoxySettings.Volume);
					_src.Play();
				}
				_quad.SetActive(true);
				Rumble();
				UpdateScare();
			}
		}

		private static void Rumble()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			XRNode[] array = (XRNode[])(object)new XRNode[2]
			{
				(XRNode)4,
				(XRNode)5
			};
			for (int i = 0; i < array.Length; i++)
			{
				InputDevice deviceAtXRNode = InputDevices.GetDeviceAtXRNode(array[i]);
				try
				{
					if (((InputDevice)(ref deviceAtXRNode)).isValid)
					{
						((InputDevice)(ref deviceAtXRNode)).SendHapticImpulse(0u, 1f, _scareLen);
					}
				}
				catch
				{
				}
			}
		}

		private static void UpdateScare()
		{
			//IL_0041: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0071: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			float num = Time.time - _scareStart;
			if (num >= _scareLen)
			{
				EndScare();
				return;
			}
			Transform head = Player.Head;
			if ((Object)(object)head != (Object)null && (Object)(object)_quad != (Object)null)
			{
				_quad.transform.position = head.position + head.forward * 0.32f;
				_quad.transform.rotation = Quaternion.LookRotation(head.forward, head.up);
				_quad.transform.localScale = new Vector3(0.85f, 0.64f, 1f);
			}
			if ((Object)(object)_mr != (Object)null && _frames != null)
			{
				int num2 = (int)(num / 0.06f) % 13;
				Texture2D val = _frames[num2];
				if ((Object)(object)val != (Object)null)
				{
					((Renderer)_mr).material.mainTexture = (Texture)(object)val;
				}
			}
		}

		private static void EndScare()
		{
			_scaring = false;
			if ((Object)(object)_quad != (Object)null)
			{
				_quad.SetActive(false);
			}
			if ((Object)(object)_src != (Object)null)
			{
				try
				{
					_src.Stop();
				}
				catch
				{
				}
			}
		}

		private static void EnsureAssets()
		{
			if (_loadTried)
			{
				return;
			}
			_loadTried = true;
			try
			{
				string path = Path.Combine(MelonEnvironment.UserDataDirectory, "QuickFoxy");
				LoadFrames(Path.Combine(path, "frames"));
				_clip = LoadWav(Path.Combine(path, "foxy.wav"));
				BuildObjects();
				MelonLogger.Msg($"[QuickFoxy] loaded {((_frames != null) ? _frames.Length : 0)} frames, clip={(Object)(object)_clip != (Object)null}");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[QuickFoxy] asset load failed: " + ex.Message);
			}
		}

		private static void LoadFrames(string framesDir)
		{
			//IL_0071: 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_007f: Expected O, but got Unknown
			Texture2D[] array = (Texture2D[])(object)new Texture2D[13];
			for (int i = 0; i < 13; i++)
			{
				string text = Path.Combine(framesDir, $"foxy_{i:00}.png");
				if (!File.Exists(text))
				{
					MelonLogger.Warning("[QuickFoxy] missing frame " + text);
					continue;
				}
				byte[] array2 = File.ReadAllBytes(text);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
				{
					wrapMode = (TextureWrapMode)1
				};
				ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array2));
				array[i] = val;
			}
			_frames = array;
		}

		private static void BuildObjects()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_00a5: 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_00b0: Expected O, but got Unknown
			_quad = GameObject.CreatePrimitive((PrimitiveType)5);
			((Object)_quad).name = "[QuickFoxy] Jumpscare";
			Object.DontDestroyOnLoad((Object)(object)_quad);
			Collider component = _quad.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			_mr = _quad.GetComponent<MeshRenderer>();
			_mat = new Material(Shader.Find("Sprites/Default"));
			_mat.renderQueue = 5000;
			((Renderer)_mr).material = _mat;
			((Renderer)_mr).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)_mr).receiveShadows = false;
			_quad.SetActive(false);
			GameObject val = new GameObject("[QuickFoxy] Audio");
			Object.DontDestroyOnLoad((Object)val);
			_src = val.AddComponent<AudioSource>();
			_src.playOnAwake = false;
			_src.spatialBlend = 0f;
		}

		private static AudioClip? LoadWav(string path)
		{
			if (!File.Exists(path))
			{
				MelonLogger.Warning("[QuickFoxy] missing " + path);
				return null;
			}
			byte[] array = File.ReadAllBytes(path);
			int num = BitConverter.ToInt16(array, 22);
			int num2 = BitConverter.ToInt32(array, 24);
			int num3 = BitConverter.ToInt16(array, 34);
			int i = 12;
			int num4 = -1;
			int num5 = 0;
			int num6;
			for (; i + 8 <= array.Length; i += 8 + num6 + (num6 & 1))
			{
				string text = Encoding.ASCII.GetString(array, i, 4);
				num6 = BitConverter.ToInt32(array, i + 4);
				if (text == "data")
				{
					num4 = i + 8;
					num5 = num6;
					break;
				}
			}
			if (num4 < 0 || num3 != 16)
			{
				MelonLogger.Warning("[QuickFoxy] unsupported wav");
				return null;
			}
			int num7 = num5 / 2;
			float[] array2 = new float[num7];
			for (int j = 0; j < num7; j++)
			{
				array2[j] = (float)BitConverter.ToInt16(array, num4 + j * 2) / 32768f;
			}
			int num8 = num7 / Mathf.Max(1, num);
			AudioClip obj = AudioClip.Create("foxy_scream", num8, num, num2, false);
			obj.SetData(new Il2CppStructArray<float>(array2), 0);
			return obj;
		}
	}
	public static class FoxySettings
	{
		private static MelonPreferences_Category _cat;

		private static MelonPreferences_Entry<bool> _enabled;

		private static MelonPreferences_Entry<int> _odds;

		private static MelonPreferences_Entry<float> _volume;

		public static bool Enabled
		{
			get
			{
				return _enabled.Value;
			}
			set
			{
				_enabled.Value = value;
				Save();
			}
		}

		public static int Odds
		{
			get
			{
				return _odds.Value;
			}
			set
			{
				_odds.Value = value;
				Save();
			}
		}

		public static float Volume
		{
			get
			{
				return _volume.Value;
			}
			set
			{
				_volume.Value = value;
				Save();
			}
		}

		public static void Initialize()
		{
			_cat = MelonPreferences.CreateCategory("QuickFoxy");
			_enabled = _cat.CreateEntry<bool>("Enabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_odds = _cat.CreateEntry<int>("Odds", 10000, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_volume = _cat.CreateEntry<float>("Volume", 1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
		}

		private static void Save()
		{
			_cat.SaveToFile(false);
		}
	}
	public class QuickFoxyMod : MelonMod
	{
		public override void OnInitializeMelon()
		{
			FoxySettings.Initialize();
			SetupMenu();
			((MelonBase)this).LoggerInstance.Msg("QuickFoxy loaded! (1 in " + FoxySettings.Odds + "/sec)");
		}

		public override void OnUpdate()
		{
			FoxyController.Update();
		}

		private static Page GetOrCreateQuickModsPage()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			object? data = AppDomain.CurrentDomain.GetData("QuickMods.RootPage");
			Page val = (Page)((data is Page) ? data : null);
			if (val != null)
			{
				return val;
			}
			Page val2 = Page.Root.CreatePage("Quick Mods", new Color(0.35f, 0.27f, 0.9f), 0, true);
			AppDomain.CurrentDomain.SetData("QuickMods.RootPage", val2);
			return val2;
		}

		private static void SetupMenu()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			Page obj = GetOrCreateQuickModsPage().CreatePage("QuickFoxy", new Color(0.9f, 0.35f, 0.1f), 0, true);
			obj.CreateBool("Enabled", Color.white, FoxySettings.Enabled, (Action<bool>)delegate(bool v)
			{
				FoxySettings.Enabled = v;
			});
			obj.CreateInt("1 in (per second)", new Color(1f, 0.6f, 0.2f), FoxySettings.Odds, 500, 1, 1000000, (Action<int>)delegate(int v)
			{
				FoxySettings.Odds = v;
			});
			obj.CreateFloat("Volume", Color.white, FoxySettings.Volume, 0.05f, 0f, 1f, (Action<float>)delegate(float v)
			{
				FoxySettings.Volume = v;
			});
			obj.CreateFunction("Test Jumpscare", new Color(1f, 0.2f, 0.2f), (Action)delegate
			{
				FoxyController.Trigger();
			});
		}
	}
}