Decompiled source of RabbitDirector v1.0.1

Mods\RabbitDirector.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BoneLib;
using BoneLib.BoneMenu;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.VRMK;
using LabFusion.Entities;
using MelonLoader;
using MelonLoader.Preferences;
using RabbitDirector;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(RabbitDirectorMod), "Rabbit Director", "1.0.1", "EQUALIZER", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RabbitDirector;

public sealed class RabbitDirectorMod : MelonMod
{
	private enum VoiceTopic
	{
		Behind,
		Threat,
		Chase,
		Search
	}

	private const int VoiceLineCount = 30;

	private static readonly int[] DefaultFavorites = new int[8] { 1, 7, 8, 15, 17, 24, 27, 30 };

	private const float WheelDeadzone = 0.52f;

	private const float WheelActivationSeconds = 0.25f;

	private const float WheelHandDistance = 0.32f;

	private const float WheelDirectionDistance = 0.18f;

	private static readonly Dictionary<VoiceTopic, int[]> TopicLines = new Dictionary<VoiceTopic, int[]>
	{
		[VoiceTopic.Behind] = new int[9] { 2, 3, 6, 9, 13, 15, 18, 27, 29 },
		[VoiceTopic.Threat] = new int[10] { 1, 4, 7, 11, 12, 22, 23, 25, 28, 30 },
		[VoiceTopic.Chase] = new int[6] { 10, 14, 16, 19, 21, 26 },
		[VoiceTopic.Search] = new int[5] { 5, 8, 17, 20, 24 }
	};

	private static readonly Dictionary<int, string> LineTexts = new Dictionary<int, string>
	{
		[1] = "Mr. and Mrs. Waterman, were very, very bad people.",
		[2] = "Happy Halloween from the Waterman's",
		[3] = "This year's harvest will be so pleasant!",
		[4] = "A new year, more bunnies for the slaughter.",
		[5] = "My victims are never forgotten.",
		[6] = "This Year's haunt will be so delightful",
		[7] = "I will rip, and I will cut, and I will punish you.",
		[8] = "Such naughty bunnies, I will find you",
		[9] = "Let's go trick-or-treating.",
		[10] = "Ready or not, here I come",
		[11] = "You will be punished.",
		[12] = "You won't feel a thing.",
		[13] = "Here's your treat.",
		[14] = "You shouldn't run from me.",
		[15] = "*laugh*",
		[16] = "Oh, you're in trouble now!",
		[17] = "It's fun when you hide, but now I seek.",
		[18] = "Trick-or-treat",
		[19] = "What a naughty bunny",
		[20] = "You shouldn't be here.",
		[21] = "You stay put",
		[22] = "It's time to join the fair eye.",
		[23] = "See, doesn't that feel better?",
		[24] = "And you look like a scarecrow.",
		[25] = "...And bunnies must be punished",
		[26] = "Playtime is over",
		[27] = "*laugh*",
		[28] = "The boogieman claims his victims",
		[29] = "Here's your trick.",
		[30] = "You'll be with us forever"
	};

	private readonly MelonPreferences_Entry<int>[] _favoriteEntries = new MelonPreferences_Entry<int>[8];

	private readonly FunctionElement[] _quickButtons = (FunctionElement[])(object)new FunctionElement[8];

	private MelonPreferences_Category _preferences;

	private Hand _maskHand;

	private Transform _physicalMask;

	private Renderer _physicalMaskRenderer;

	private Transform _maskGrabPoint;

	private Transform _maskHomeParent;

	private Transform _wornMaskBone;

	private Vector3 _maskHomePosition;

	private Quaternion _maskHomeRotation;

	private Vector3 _maskHomeScale;

	private int _boundAvatarId;

	private float _maskTakenAt;

	private readonly Random _random = new Random();

	private readonly Dictionary<VoiceTopic, int> _lastTopicLine = new Dictionary<VoiceTopic, int>();

	private GameObject _wheelRoot;

	private readonly Dictionary<VoiceTopic, TextMesh> _wheelLabels = new Dictionary<VoiceTopic, TextMesh>();

	private TextMesh _wheelCenter;

	private bool _wheelHeld;

	private VoiceTopic? _wheelSelection;

	private float _wheelActivationStartedAt = -1f;

	private Transform _wheelLeftPalm;

	private Transform _wheelRightPalm;

	public override void OnInitializeMelon()
	{
		CreatePreferences();
		CreateMenu();
		((MelonBase)this).LoggerInstance.Msg("Rabbit Director ready: voice library, mask hand-follow and visibility controls.");
	}

	public override void OnUpdate()
	{
		UpdateVoiceWheel();
		RefreshMaskReferences();
		if ((Object)(object)_maskHand == (Object)null)
		{
			if (!TryTakeMask(Player.LeftHand))
			{
				TryTakeMask(Player.RightHand);
			}
			return;
		}
		BaseController controller = _maskHand.Controller;
		if ((Object)(object)controller == (Object)null)
		{
			ReturnMask();
		}
		else if (Time.time > _maskTakenAt + 0.12f && controller.isBelowGripThreshold)
		{
			ReturnMask();
		}
	}

	private void CreatePreferences()
	{
		_preferences = MelonPreferences.CreateCategory("RabbitDirector", "Rabbit Director");
		for (int i = 0; i < _favoriteEntries.Length; i++)
		{
			_favoriteEntries[i] = _preferences.CreateEntry<int>($"Favorite_{i + 1}", DefaultFavorites[i], $"Favorite {i + 1}", (string)null, false, false, (ValueValidator)null, (string)null);
			_favoriteEntries[i].Value = ClampLine(_favoriteEntries[i].Value);
		}
	}

	private void CreateMenu()
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: 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_007b: 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)
		//IL_00ae: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: 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_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: 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_02a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_0307: Unknown result type (might be due to invalid IL or missing references)
		Color val = default(Color);
		((Color)(ref val))..ctor(0.92f, 0.36f, 0.08f);
		Color val2 = default(Color);
		((Color)(ref val2))..ctor(0.95f, 0.87f, 0.68f);
		Color val3 = default(Color);
		((Color)(ref val3))..ctor(0.72f, 0.06f, 0.05f);
		Page val4 = Page.Root.CreatePage("Rabbit Director", val, 0, true);
		Page val5 = val4.CreatePage("Quick Voice Lines", val, 0, true);
		Page val6 = val4.CreatePage("Voice Wheel Topics", val, 0, true);
		Page val7 = val4.CreatePage("All 30 Voice Lines", val2, 8, true);
		Page val8 = val4.CreatePage("Edit Favorites", Color.yellow, 0, true);
		val4.CreateFunction("INVISIBLE", new Color(0.35f, 0.35f, 0.35f), (Action)delegate
		{
			TriggerNamedEvent("VisibilityControl", menuTap: false);
		});
		val4.CreateFunction("VISIBLE", Color.white, (Action)delegate
		{
			TriggerNamedEvent("VisibilityControl", menuTap: true);
		});
		val4.CreateFunction("RETURN MASK NOW", val2, (Action)ReturnMask);
		val6.CreateFunction("BEHIND - random", val, (Action)delegate
		{
			PlayRandomTopic(VoiceTopic.Behind);
		});
		val6.CreateFunction("THREAT - random", val3, (Action)delegate
		{
			PlayRandomTopic(VoiceTopic.Threat);
		});
		val6.CreateFunction("CHASE - random", Color.yellow, (Action)delegate
		{
			PlayRandomTopic(VoiceTopic.Chase);
		});
		val6.CreateFunction("SEARCH - random", Color.cyan, (Action)delegate
		{
			PlayRandomTopic(VoiceTopic.Search);
		});
		val6.CreateFunction("VR WHEEL: hold left Y + right stick", val2, (Action)delegate
		{
			((MelonBase)this).LoggerInstance.Msg("Voice wheel: hold left Y, point the right stick at a topic, then release Y.");
		});
		for (int num = 0; num < _quickButtons.Length; num++)
		{
			int capturedSlot = num;
			_quickButtons[num] = val5.CreateFunction(QuickButtonName(num), val, (Action)delegate
			{
				PlayLine(_favoriteEntries[capturedSlot].Value);
			});
		}
		val5.CreateFunction("STOP VOICE", val3, (Action)StopVoice);
		for (int num2 = 1; num2 <= 30; num2++)
		{
			int capturedLine = num2;
			val7.CreateFunction(MenuLineName(num2), val2, (Action)delegate
			{
				PlayLine(capturedLine);
			});
		}
		for (int num3 = 0; num3 < _favoriteEntries.Length; num3++)
		{
			int capturedSlot2 = num3;
			val8.CreateInt($"Slot {num3 + 1}: {LineId(_favoriteEntries[num3].Value)}", Color.yellow, _favoriteEntries[num3].Value, 1, 1, 30, (Action<int>)delegate(int value)
			{
				SetFavorite(capturedSlot2, value);
			});
		}
		val4.CreateFunction("STOP VOICE", val3, (Action)StopVoice);
		val4.CreateFunction("Rescan Avatar Audio", Color.cyan, (Action)delegate
		{
			int count = FindAudioEvents().Count;
			((MelonBase)this).LoggerInstance.Msg($"Rabbit Director found {count}/31 audio events on the avatar.");
		});
	}

	private void SetFavorite(int slot, int value)
	{
		value = ClampLine(value);
		_favoriteEntries[slot].Value = value;
		((Element)_quickButtons[slot]).ElementName = QuickButtonName(slot);
		MelonPreferences.Save();
	}

	private string QuickButtonName(int slot)
	{
		return $"{slot + 1}. {LineId(_favoriteEntries[slot].Value)}";
	}

	private static string MenuLineName(int line)
	{
		return LineId(line) + " - " + LineTexts[line];
	}

	private void PlayLine(int line)
	{
		TriggerEvent("AudioEvent_" + LineId(ClampLine(line)));
	}

	private void PlayRandomTopic(VoiceTopic topic)
	{
		int[] array = TopicLines[topic];
		int value;
		int num = (_lastTopicLine.TryGetValue(topic, out value) ? value : (-1));
		int num2;
		do
		{
			num2 = array[_random.Next(array.Length)];
		}
		while (array.Length > 1 && num2 == num);
		_lastTopicLine[topic] = num2;
		((MelonBase)this).LoggerInstance.Msg($"Voice wheel: {TopicName(topic)} -> {LineId(num2)} {LineTexts[num2]}");
		PlayLine(num2);
	}

	private void UpdateVoiceWheel()
	{
		if (!_wheelHeld)
		{
			if (!TryGetWheelActivationPose(out var leftPalm, out var rightPalm))
			{
				_wheelActivationStartedAt = -1f;
				return;
			}
			if (_wheelActivationStartedAt < 0f)
			{
				_wheelActivationStartedAt = Time.time;
			}
			if (!(Time.time < _wheelActivationStartedAt + 0.25f))
			{
				_wheelHeld = true;
				_wheelLeftPalm = leftPalm;
				_wheelRightPalm = rightPalm;
				_wheelSelection = null;
				ShowVoiceWheel(null);
			}
		}
		else if ((Object)(object)_wheelLeftPalm == (Object)null || (Object)(object)_wheelRightPalm == (Object)null || (Object)(object)_wheelLeftPalm == (Object)(object)_wheelRightPalm)
		{
			CancelVoiceWheel();
		}
		else
		{
			Hand leftHand = Player.LeftHand;
			BaseController val = ((leftHand != null) ? leftHand.Controller : null);
			if ((Object)(object)val == (Object)null)
			{
				CancelVoiceWheel();
				return;
			}
			if (val.isBelowGripThreshold)
			{
				FinishVoiceWheel();
				return;
			}
			_wheelSelection = TopicFromHandPosition(_wheelLeftPalm, _wheelRightPalm);
			ShowVoiceWheel(_wheelSelection);
		}
	}

	private static bool TryGetWheelActivationPose(out Transform leftPalm, out Transform rightPalm)
	{
		//IL_00a0: 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_00fa: 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)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		leftPalm = null;
		rightPalm = null;
		Hand leftHand = Player.LeftHand;
		Hand rightHand = Player.RightHand;
		if ((Object)(object)leftHand == (Object)null || (Object)(object)rightHand == (Object)null || leftHand.HasAttachedObject() || rightHand.HasAttachedObject())
		{
			return false;
		}
		BaseController controller = leftHand.Controller;
		leftPalm = (((Object)(object)leftHand.palmPositionTransform != (Object)null) ? leftHand.palmPositionTransform : ((Component)leftHand).transform);
		rightPalm = (((Object)(object)rightHand.palmPositionTransform != (Object)null) ? rightHand.palmPositionTransform : ((Component)rightHand).transform);
		if ((Object)(object)controller == (Object)null || controller.isBelowGripThreshold || (Object)(object)leftPalm == (Object)null || (Object)(object)rightPalm == (Object)null || Vector3.Distance(leftPalm.position, rightPalm.position) > 0.32f)
		{
			return false;
		}
		Camera val = Camera.main ?? ((IEnumerable<Camera>)Camera.allCameras).FirstOrDefault((Func<Camera, bool>)((Camera active) => ((Behaviour)active).enabled));
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		Vector3 val2 = (leftPalm.position + rightPalm.position) * 0.5f - ((Component)val).transform.position;
		if (((Vector3)(ref val2)).sqrMagnitude > 0.09f)
		{
			return Vector3.Dot(((Component)val).transform.forward, ((Vector3)(ref val2)).normalized) > 0.2f;
		}
		return false;
	}

	private static VoiceTopic? TopicFromHandPosition(Transform leftPalm, Transform rightPalm)
	{
		//IL_0047: 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_0052: 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_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: 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_0078: 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)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		Camera val = Camera.main ?? ((IEnumerable<Camera>)Camera.allCameras).FirstOrDefault((Func<Camera, bool>)((Camera active) => ((Behaviour)active).enabled));
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		Vector3 val2 = rightPalm.position - leftPalm.position;
		Vector2 val3 = default(Vector2);
		((Vector2)(ref val3))..ctor(Vector3.Dot(val2, ((Component)val).transform.right) / 0.18f, Vector3.Dot(val2, ((Component)val).transform.up) / 0.18f);
		if (((Vector2)(ref val3)).magnitude < 0.52f)
		{
			return null;
		}
		if (Mathf.Abs(val3.y) >= Mathf.Abs(val3.x))
		{
			return (!(val3.y >= 0f)) ? VoiceTopic.Chase : VoiceTopic.Behind;
		}
		return (val3.x >= 0f) ? VoiceTopic.Threat : VoiceTopic.Search;
	}

	private void FinishVoiceWheel()
	{
		HideVoiceWheel();
		_wheelHeld = false;
		_wheelActivationStartedAt = -1f;
		_wheelLeftPalm = null;
		_wheelRightPalm = null;
		if (_wheelSelection.HasValue)
		{
			PlayRandomTopic(_wheelSelection.Value);
		}
		_wheelSelection = null;
	}

	private void CancelVoiceWheel()
	{
		HideVoiceWheel();
		_wheelHeld = false;
		_wheelSelection = null;
		_wheelActivationStartedAt = -1f;
		_wheelLeftPalm = null;
		_wheelRightPalm = null;
	}

	private void ShowVoiceWheel(VoiceTopic? selected)
	{
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: 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_0091: 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_00a3: 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_00ae: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		EnsureVoiceWheel();
		Camera val = Camera.main ?? ((IEnumerable<Camera>)Camera.allCameras).FirstOrDefault((Func<Camera, bool>)((Camera active) => ((Behaviour)active).enabled));
		if ((Object)(object)val == (Object)null || (Object)(object)_wheelRoot == (Object)null)
		{
			return;
		}
		_wheelRoot.SetActive(true);
		Transform transform = ((Component)val).transform;
		Transform val2 = (((Object)(object)_wheelLeftPalm != (Object)null) ? _wheelLeftPalm : transform);
		Vector3 val3 = transform.position - val2.position;
		Vector3 normalized = ((Vector3)(ref val3)).normalized;
		_wheelRoot.transform.position = val2.position + normalized * 0.08f;
		_wheelRoot.transform.rotation = Quaternion.LookRotation(transform.forward, transform.up);
		foreach (KeyValuePair<VoiceTopic, TextMesh> wheelLabel in _wheelLabels)
		{
			wheelLabel.Deconstruct(out var key, out var value);
			VoiceTopic voiceTopic = key;
			TextMesh obj = value;
			VoiceTopic? voiceTopic2 = selected;
			key = voiceTopic;
			obj.color = ((voiceTopic2 == key) ? Color.white : TopicColor(voiceTopic));
		}
		_wheelCenter.text = (selected.HasValue ? (TopicName(selected.Value) + "\nrelease Y") : "VOICE\nchoose a direction");
	}

	private void HideVoiceWheel()
	{
		if ((Object)(object)_wheelRoot != (Object)null)
		{
			_wheelRoot.SetActive(false);
		}
	}

	private void EnsureVoiceWheel()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Expected O, but got Unknown
		//IL_003d: 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_0058: 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_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_wheelRoot != (Object)null))
		{
			_wheelRoot = new GameObject("RabbitDirectorVoiceWheel")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)(object)_wheelRoot);
			_wheelRoot.transform.localScale = Vector3.one * 0.04f;
			_wheelCenter = CreateWheelText("Center", Vector3.zero, "VOICE\nMOVE RIGHT HAND", 0.025f);
			_wheelLabels[VoiceTopic.Behind] = CreateWheelText("Behind", Vector3.up * 4.2f, "UP\nBEHIND", 0.032f);
			_wheelLabels[VoiceTopic.Threat] = CreateWheelText("Threat", Vector3.right * 5.4f, "RIGHT\nTHREAT", 0.032f);
			_wheelLabels[VoiceTopic.Chase] = CreateWheelText("Chase", Vector3.down * 4.2f, "DOWN\nCHASE", 0.032f);
			_wheelLabels[VoiceTopic.Search] = CreateWheelText("Search", Vector3.left * 5.4f, "LEFT\nSEARCH", 0.032f);
			HideVoiceWheel();
		}
	}

	private TextMesh CreateWheelText(string objectName, Vector3 localPosition, string text, float size)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: 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)
		GameObject val = new GameObject(objectName);
		val.transform.SetParent(_wheelRoot.transform, false);
		val.transform.localPosition = localPosition;
		TextMesh obj = val.AddComponent<TextMesh>();
		obj.text = text;
		obj.anchor = (TextAnchor)4;
		obj.alignment = (TextAlignment)1;
		obj.characterSize = size;
		obj.fontSize = 64;
		obj.color = new Color(0.92f, 0.36f, 0.08f);
		return obj;
	}

	private static Color TopicColor(VoiceTopic topic)
	{
		//IL_0027: 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_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: 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_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: 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_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: 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)
		return (Color)(topic switch
		{
			VoiceTopic.Behind => new Color(0.78f, 0.32f, 0.95f), 
			VoiceTopic.Threat => new Color(0.86f, 0.08f, 0.08f), 
			VoiceTopic.Chase => new Color(0.95f, 0.75f, 0.12f), 
			VoiceTopic.Search => new Color(0.12f, 0.75f, 0.92f), 
			_ => Color.white, 
		});
	}

	private static string TopicName(VoiceTopic topic)
	{
		return topic switch
		{
			VoiceTopic.Behind => "BEHIND", 
			VoiceTopic.Threat => "THREAT", 
			VoiceTopic.Chase => "CHASE", 
			VoiceTopic.Search => "SEARCH", 
			_ => "VOICE", 
		};
	}

	private void StopVoice()
	{
		TriggerEvent("AudioEvent_STOP_ALL");
	}

	private void TriggerEvent(string objectName)
	{
		SimpleGripEvents val = ((IEnumerable<SimpleGripEvents>)FindAvatarEvents()).FirstOrDefault((Func<SimpleGripEvents, bool>)((SimpleGripEvents component) => ((Object)((Component)component).gameObject).name == objectName));
		if ((Object)(object)val == (Object)null)
		{
			((MelonBase)this).LoggerInstance.Warning("'" + objectName + "' was not found. Equip PumpkinRabbit_TEST_MIN and try again.");
			return;
		}
		UnityEvent onIndexDown = val.OnIndexDown;
		if (onIndexDown != null)
		{
			onIndexDown.Invoke();
		}
		TryRelayFusionEvent(val, "TRIGGER_DOWN");
	}

	private void TriggerNamedEvent(string objectName, bool menuTap)
	{
		SimpleGripEvents val = ((IEnumerable<SimpleGripEvents>)FindAvatarEvents()).FirstOrDefault((Func<SimpleGripEvents, bool>)((SimpleGripEvents component) => ((Object)((Component)component).gameObject).name == objectName));
		if ((Object)(object)val == (Object)null)
		{
			((MelonBase)this).LoggerInstance.Warning("'" + objectName + "' was not found on the equipped avatar.");
		}
		else if (menuTap)
		{
			UnityEvent onMenuTapDown = val.OnMenuTapDown;
			if (onMenuTapDown != null)
			{
				onMenuTapDown.Invoke();
			}
			TryRelayFusionEvent(val, "MENU_TAP");
		}
		else
		{
			UnityEvent onIndexDown = val.OnIndexDown;
			if (onIndexDown != null)
			{
				onIndexDown.Invoke();
			}
			TryRelayFusionEvent(val, "TRIGGER_DOWN");
		}
	}

	private void RefreshMaskReferences()
	{
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: 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_015d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Player.RigManager == (Object)null)
		{
			ClearMaskReferences();
			return;
		}
		Avatar val = null;
		try
		{
			val = Player.Avatar;
		}
		catch
		{
			ClearMaskReferences();
			return;
		}
		if ((Object)(object)val == (Object)null)
		{
			ClearMaskReferences();
			return;
		}
		int instanceID = ((Object)val).GetInstanceID();
		if (_boundAvatarId == instanceID && (Object)(object)_physicalMask != (Object)null && (Object)(object)_maskGrabPoint != (Object)null)
		{
			return;
		}
		ClearMaskReferences();
		Transform val2 = FindDeep(((Component)val).transform, "PhysicalMaskAccessory");
		if (!((Object)(object)val2 == (Object)null))
		{
			_physicalMask = FindDeep(val2, "PhysicalMask");
			_maskGrabPoint = FindDeep(val2, "MaskGrabPoint");
			_wornMaskBone = FindDeep(((Component)val).transform, "Mask");
			Transform physicalMask = _physicalMask;
			_physicalMaskRenderer = ((physicalMask != null) ? ((Component)physicalMask).GetComponent<Renderer>() : null);
			if ((Object)(object)_physicalMask == (Object)null || (Object)(object)_maskGrabPoint == (Object)null || (Object)(object)_wornMaskBone == (Object)null || (Object)(object)_physicalMaskRenderer == (Object)null)
			{
				ClearMaskReferences();
				return;
			}
			_boundAvatarId = instanceID;
			_maskHomeParent = _physicalMask.parent;
			_maskHomePosition = _physicalMask.localPosition;
			_maskHomeRotation = _physicalMask.localRotation;
			_maskHomeScale = _physicalMask.localScale;
			_physicalMaskRenderer.enabled = false;
			((MelonBase)this).LoggerInstance.Msg("Mask proximity control bound to Pumpkin Rabbit avatar.");
		}
	}

	private bool TryTakeMask(Hand hand)
	{
		//IL_0070: 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_00b2: 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)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)hand == (Object)null || (Object)(object)_physicalMask == (Object)null || (Object)(object)_maskGrabPoint == (Object)null)
		{
			return false;
		}
		BaseController controller = hand.Controller;
		Transform val = (((Object)(object)hand.palmPositionTransform != (Object)null) ? hand.palmPositionTransform : ((Component)hand).transform);
		if ((Object)(object)controller == (Object)null || controller.isBelowGripThreshold || (Object)(object)val == (Object)null || hand.HasAttachedObject())
		{
			return false;
		}
		if (Vector3.Distance(val.position, _maskGrabPoint.position) > 0.18f)
		{
			return false;
		}
		_maskHand = hand;
		_maskTakenAt = Time.time;
		TriggerNamedEvent("PhysicalMaskAccessory", menuTap: false);
		_wornMaskBone.localScale = Vector3.one * 0.1f;
		_physicalMaskRenderer.enabled = true;
		_physicalMask.SetParent(val, true);
		((MelonBase)this).LoggerInstance.Msg($"Mask taken with {hand.handedness} hand; grab distance={Vector3.Distance(val.position, _maskGrabPoint.position):F3}m.");
		return true;
	}

	private void ReturnMask()
	{
		//IL_004f: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_physicalMaskRenderer != (Object)null)
		{
			_physicalMaskRenderer.enabled = false;
		}
		if ((Object)(object)_physicalMask != (Object)null && (Object)(object)_maskHomeParent != (Object)null)
		{
			_physicalMask.SetParent(_maskHomeParent, false);
			_physicalMask.localPosition = _maskHomePosition;
			_physicalMask.localRotation = _maskHomeRotation;
			_physicalMask.localScale = _maskHomeScale;
		}
		bool num = (Object)(object)_maskHand != (Object)null;
		_maskHand = null;
		if (num)
		{
			if ((Object)(object)_wornMaskBone != (Object)null)
			{
				_wornMaskBone.localScale = Vector3.one;
			}
			TriggerNamedEvent("MaskReturnSyncEvent", menuTap: false);
			((MelonBase)this).LoggerInstance.Msg("Mask returned after controller grip release.");
		}
	}

	private void ClearMaskReferences()
	{
		_maskHand = null;
		_physicalMask = null;
		_physicalMaskRenderer = null;
		_maskGrabPoint = null;
		_maskHomeParent = null;
		_wornMaskBone = null;
		_boundAvatarId = 0;
		_maskTakenAt = 0f;
	}

	private List<SimpleGripEvents> FindAudioEvents()
	{
		return (from component in FindAvatarEvents()
			where ((Object)((Component)component).gameObject).name.StartsWith("AudioEvent_", StringComparison.Ordinal)
			select component).ToList();
	}

	private List<SimpleGripEvents> FindAvatarEvents()
	{
		List<SimpleGripEvents> list = new List<SimpleGripEvents>();
		if ((Object)(object)Player.Avatar == (Object)null)
		{
			return list;
		}
		foreach (SimpleGripEvents componentsInChild in ((Component)Player.Avatar).GetComponentsInChildren<SimpleGripEvents>(true))
		{
			if ((Object)(object)componentsInChild != (Object)null)
			{
				list.Add(componentsInChild);
			}
		}
		return list;
	}

	private void TryRelayFusionEvent(SimpleGripEvents source, string eventName)
	{
		try
		{
			Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly assembly2) => assembly2.GetName().Name == "BonelabSupport");
			if (assembly == null)
			{
				return;
			}
			Type type = assembly.GetType("MarrowFusion.Bonelab.Extenders.SimpleGripEventsExtender");
			Type type2 = assembly.GetType("MarrowFusion.Bonelab.Patching.SimpleGripEventsPatches");
			Type type3 = assembly.GetType("MarrowFusion.Bonelab.Messages.SimpleGripEventType");
			if (type == null || type2 == null || type3 == null)
			{
				return;
			}
			object obj = type.GetField("Cache", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
			if (obj == null)
			{
				return;
			}
			MethodInfo methodInfo = obj.GetType().GetMethods().First((MethodInfo method) => method.Name == "TryGet" && method.GetParameters().Length == 2);
			object[] array = new object[2] { source, null };
			if (!(bool)methodInfo.Invoke(obj, array))
			{
				return;
			}
			object obj2 = array[1];
			NetworkEntity val = (NetworkEntity)((obj2 is NetworkEntity) ? obj2 : null);
			if (val == null)
			{
				return;
			}
			object extender = val.GetExtender(type);
			if (extender != null)
			{
				object obj3 = extender.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).First((MethodInfo method) => method.Name == "GetIndex" && method.GetParameters().Length == 1)
					.Invoke(extender, new object[1] { source });
				if (obj3 != null)
				{
					byte b = checked((byte)Convert.ToInt32(obj3));
					object obj4 = Enum.Parse(type3, eventName);
					type2.GetMethod("SendGripEvent", BindingFlags.Static | BindingFlags.NonPublic)?.Invoke(null, new object[3] { val.ID, b, obj4 });
				}
			}
		}
		catch (Exception ex)
		{
			((MelonBase)this).LoggerInstance.Warning("Local avatar event worked, but Fusion relay failed: " + ex.Message);
		}
	}

	private static int ClampLine(int value)
	{
		return Math.Clamp(value, 1, 30);
	}

	private static string LineId(int line)
	{
		return $"PR_{line:000}";
	}

	private static Transform FindDeep(Transform parent, string objectName)
	{
		foreach (Transform componentsInChild in ((Component)parent).GetComponentsInChildren<Transform>(true))
		{
			if (((Object)componentsInChild).name == objectName)
			{
				return componentsInChild;
			}
		}
		return null;
	}
}