Decompiled source of Instruments v0.2.0

BepInEx/plugins/Instruments/Instruments.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using HarmonyLib;
using Instruments.Content;
using Instruments.Performance;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Instruments")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+8d150ac7af5086147b4e3dc6d3099c9dfbfac8b2")]
[assembly: AssemblyProduct("Instruments")]
[assembly: AssemblyTitle("Instruments")]
[assembly: AssemblyVersion("0.2.0.0")]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Instruments
{
	[BepInPlugin("com.igentuman.instruments", "Instruments", "0.2.0")]
	[BepInDependency("com.jotunn.jotunn", "2.30.2")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.igentuman.instruments";

		public const string PluginName = "Instruments";

		public const string PluginVersion = "0.2.0";

		private Harmony? harmony;

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			InstrumentAudio.Initialize(delegate(string message)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)message);
			});
			InstrumentLocalization.Register();
			InstrumentRegistry.Register();
			PerformanceRegistry.Initialize();
			harmony = new Harmony("com.igentuman.instruments");
			harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Instruments 0.2.0 loaded.");
		}

		private void OnDestroy()
		{
			InstrumentRegistry.Unregister();
			InstrumentPlayer[] array = Object.FindObjectsByType<InstrumentPlayer>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)array[i]);
			}
			PerformanceRegistry.Clear();
			InstrumentAudio.Clear();
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
}
namespace Instruments.Performance
{
	internal sealed class BowedPerformance : IInstrumentPerformance, IDisposable, IPitchedInstrumentPerformance, ITremoloInstrumentPerformance
	{
		private const float FadeInDuration = 0.04f;

		private const float FadeOutDuration = 0.08f;

		private const float AttackBend = 0.012f;

		private const float ReleaseBend = -0.018f;

		private const float AttackRelaxDuration = 0.1f;

		private const float TremoloDepth = 0.25f;

		private const float TremoloBlendDuration = 0.08f;

		private const float TremoloRateDuration = 0.06f;

		private const float BowChangeDuration = 0.055f;

		private readonly GameObject audio;

		private readonly AudioSource[] sources = (AudioSource[])(object)new AudioSource[3];

		private readonly BowedVoiceFilter[] filters = new BowedVoiceFilter[3];

		private readonly bool[] held = new bool[3];

		private readonly float[] gains = new float[3];

		private readonly float[] bends = new float[3];

		private readonly BowedPose pose;

		private float pitch = 1f;

		private float targetTremoloRate;

		private float tremoloRate = 4f;

		private float tremoloDepth;

		private float tremoloPhase;

		private float bowElapsed;

		private float bowDuration = 1.15f;

		private float bowTime;

		private bool bowForward = true;

		private bool disposed;

		internal BowedPerformance(Player player)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			pose = new BowedPose(player);
			AudioClip[] array = (AudioClip[])(object)new AudioClip[3]
			{
				InstrumentAudio.Load("bowed/violin.wav"),
				InstrumentAudio.Load("bowed/violin2.wav"),
				InstrumentAudio.Load("bowed/violin3.wav")
			};
			audio = new GameObject("Instruments_BowedAudio");
			audio.transform.SetParent(((Component)player).transform, false);
			audio.transform.localPosition = new Vector3(0f, 1.2f, 0.4f);
			for (int i = 0; i < sources.Length; i++)
			{
				GameObject val = new GameObject("Voice_" + i);
				val.transform.SetParent(audio.transform, false);
				AudioSource val2 = val.AddComponent<AudioSource>();
				val2.playOnAwake = false;
				val2.clip = array[i];
				val2.loop = true;
				val2.volume = 0f;
				val2.spatialBlend = 1f;
				val2.reverbZoneMix = 0.28f;
				val2.rolloffMode = (AudioRolloffMode)1;
				val2.minDistance = 5f;
				val2.maxDistance = 35f;
				val2.dopplerLevel = 0f;
				sources[i] = val2;
				filters[i] = val.AddComponent<BowedVoiceFilter>();
				filters[i].Initialize(i);
			}
		}

		public void SetPitch(float offset)
		{
			pitch = 1f + offset;
		}

		public void SetTremolo(float rate)
		{
			targetTremoloRate = rate;
		}

		public void OnNote(NoteEvent kind, int note)
		{
			switch (kind)
			{
			case NoteEvent.Release:
				held[note] = false;
				break;
			case NoteEvent.Press:
			{
				if (held[note])
				{
					break;
				}
				held[note] = true;
				if (sources[note].isPlaying)
				{
					break;
				}
				bool flag = false;
				AudioSource[] array = sources;
				foreach (AudioSource val in array)
				{
					flag |= val.isPlaying;
				}
				if (!flag)
				{
					tremoloPhase = (tremoloDepth = 0f);
					bowElapsed = (bowTime = 0f);
					bowDuration = 1.15f;
					bowForward = true;
					if (targetTremoloRate > 0f)
					{
						tremoloRate = targetTremoloRate;
					}
				}
				gains[note] = 0f;
				bends[note] = 0.012f;
				sources[note].volume = 0f;
				sources[note].pitch = pitch * (1f + bends[note]);
				sources[note].Play();
				break;
			}
			}
		}

		public void LateUpdate()
		{
			UpdateAudio();
		}

		internal bool UpdateAudio()
		{
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			bool flag = false;
			bool flag2 = false;
			for (int i = 0; i < sources.Length; i++)
			{
				flag |= held[i];
				flag2 |= sources[i].isPlaying;
			}
			if (!flag2)
			{
				return false;
			}
			bowTime += unscaledDeltaTime;
			bowElapsed += unscaledDeltaTime;
			while (bowElapsed >= bowDuration)
			{
				bowElapsed -= bowDuration;
				bowForward = !bowForward;
				bowDuration = (bowForward ? 1.15f : 1.32f) + 0.06f * Mathf.Sin(bowTime * 1.7f);
			}
			float num = bowElapsed / bowDuration;
			float num2 = Mathf.SmoothStep(0f, 1f, Mathf.Min(bowElapsed, bowDuration - bowElapsed) / 0.055f);
			float num3 = 0.9f + 0.08f * Mathf.Sin(num * MathF.PI);
			float num4 = 0.008f * Mathf.Sin(bowTime * 43.7f) + 0.006f * Mathf.Sin(bowTime * 71.3f);
			float num5 = Mathf.Lerp(0.82f, 1f, num2) * (num3 + num4);
			float num6 = 0.0015f * Mathf.Sin(num * MathF.PI) + (bowForward ? 0.002f : (-0.002f)) * (1f - num2);
			float contactNoise = (flag ? (0.06f + 0.25f * (1f - num2)) : 0f);
			bool flag3 = targetTremoloRate > 0f;
			if (flag3)
			{
				tremoloRate = Mathf.MoveTowards(tremoloRate, targetTremoloRate, 6f * unscaledDeltaTime / 0.06f);
			}
			tremoloDepth = Mathf.MoveTowards(tremoloDepth, flag3 ? 0.25f : 0f, 0.25f * unscaledDeltaTime / 0.08f);
			tremoloPhase = Mathf.Repeat(tremoloPhase + tremoloRate * unscaledDeltaTime, 1f);
			float num7 = 1f - tremoloDepth * (0.5f - 0.5f * Mathf.Cos(tremoloPhase * 2f * MathF.PI));
			float num8 = Mathf.Sqrt(AudioMan.GetSFXVolume()) * num7 * num5;
			bool result = false;
			for (int j = 0; j < sources.Length; j++)
			{
				AudioSource val = sources[j];
				if (val.isPlaying)
				{
					filters[j].SetBow(num3 + (bowForward ? 0.04f : (-0.04f)), contactNoise);
					float num9 = (held[j] ? 0.04f : 0.08f);
					gains[j] = Mathf.MoveTowards(gains[j], (float)(held[j] ? 1 : 0), unscaledDeltaTime / num9);
					bends[j] = Mathf.MoveTowards(bends[j], held[j] ? 0f : (-0.018f), unscaledDeltaTime * (held[j] ? 0.12f : 0.375f));
					val.pitch = pitch * (1f + bends[j] + num6 + num4 * 0.06f);
					val.volume = num8 * Mathf.SmoothStep(0f, 1f, gains[j]);
					if (!held[j] && gains[j] == 0f)
					{
						val.Stop();
					}
					else
					{
						result = true;
					}
				}
			}
			return result;
		}

		public void OnAnimatorIK()
		{
			bool flag = false;
			for (int i = 0; i < held.Length; i++)
			{
				flag |= held[i];
			}
			pose.Apply(flag, bowElapsed / bowDuration, bowForward);
		}

		public void Dispose()
		{
			if (!disposed)
			{
				disposed = true;
				pose.Dispose();
				for (int i = 0; i < held.Length; i++)
				{
					held[i] = false;
				}
				targetTremoloRate = 0f;
				if (Object.op_Implicit((Object)(object)audio))
				{
					audio.AddComponent<BowedRelease>().Initialize(this);
				}
			}
		}
	}
	internal sealed class BowedRelease : MonoBehaviour
	{
		private BowedPerformance performance;

		internal void Initialize(BowedPerformance performer)
		{
			performance = performer;
		}

		private void LateUpdate()
		{
			if (!performance.UpdateAudio())
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	internal sealed class BowedPose : IDisposable
	{
		private const float ContactDuration = 0.18f;

		private const float RecoveryDuration = 0.26f;

		private static readonly Vector3 ShoulderRest = new Vector3(0f, 0.045f, 0.018f);

		private static readonly Vector3 BowGrip = new Vector3(0f, 0.04f, 0f);

		private static readonly Quaternion AcrossStrings = Quaternion.LookRotation(Vector3.down, Vector3.right);

		private static readonly Quaternion BowRoll = Quaternion.Euler(0f, 180f, 0f);

		private static readonly FieldRef<VisEquipment, GameObject> HeldItem = AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_rightItemInstance");

		private static readonly FieldRef<VisEquipment, int> HeldHash = AccessTools.FieldRefAccess<VisEquipment, int>("m_currentRightItemHash");

		private static readonly int InstrumentHash = StringExtensionMethods.GetStableHashCode("Instruments_BowedInstrument");

		private readonly Player player;

		private readonly Animator animator;

		private readonly AnimatorCullingMode cullingMode;

		private readonly Transform visual;

		private readonly Transform? chest;

		private readonly Transform? head;

		private readonly Quaternion headNeutralRotation;

		private readonly InstrumentArm left;

		private readonly InstrumentArm right;

		private readonly InstrumentFingerPose fingers;

		private Transform? attach;

		private Transform? model;

		private Transform? bow;

		private InstrumentBowHandVisual? bowVisual;

		private Transform? originalParent;

		private Vector3 originalPosition;

		private Quaternion originalRotation;

		private Vector3 originalScale;

		private Vector3 originalModelPosition;

		private Quaternion originalModelRotation;

		private float contact;

		private float stroke;

		private int lastFrame = -1;

		internal BowedPose(Player player)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			this.player = player;
			animator = ((Component)player).GetComponentInChildren<Animator>();
			visual = ((Component)animator).transform;
			cullingMode = animator.cullingMode;
			animator.cullingMode = (AnimatorCullingMode)0;
			if (animator.isHuman)
			{
				chest = animator.GetBoneTransform((HumanBodyBones)8);
				head = animator.GetBoneTransform((HumanBodyBones)10);
			}
			headNeutralRotation = NeutralHeadRotation();
			left = new InstrumentArm(animator, left: true);
			right = new InstrumentArm(animator, left: false);
			fingers = new InstrumentFingerPose(animator, -0.55f, -0.25f);
		}

		internal void Apply(bool playing, float progress, bool forward)
		{
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			//IL_0437: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_044a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			//IL_045a: Unknown result type (might be due to invalid IL or missing references)
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0473: Unknown result type (might be due to invalid IL or missing references)
			//IL_0478: Unknown result type (might be due to invalid IL or missing references)
			//IL_047d: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			//IL_0489: Unknown result type (might be due to invalid IL or missing references)
			//IL_048e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0493: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a9: Unknown result type (might be due to invalid IL or missing references)
			InstrumentAnimationPatch.ClearHandIK(animator);
			VisEquipment visEquipment = ((Humanoid)player).GetVisEquipment();
			GameObject val = (Object.op_Implicit((Object)(object)visEquipment) ? HeldItem.Invoke(visEquipment) : null);
			if (!Object.op_Implicit((Object)(object)head) || !Object.op_Implicit((Object)(object)chest) || !Object.op_Implicit((Object)(object)val) || !val.activeInHierarchy || HeldHash.Invoke(visEquipment) != InstrumentHash || ((Character)player).IsDead() || ((Character)player).InCutscene() || ((Character)player).IsTeleporting() || ((Character)player).InBed() || ((Character)player).InDodge() || ((Character)player).IsStaggering() || ((Character)player).IsSwimming() || ((Character)player).IsAttached() || ((Character)player).InEmote())
			{
				RestoreAttachment();
				contact = (stroke = 0f);
				return;
			}
			if ((Object)(object)attach != (Object)(object)val.transform)
			{
				Bind(val.transform);
			}
			if (Object.op_Implicit((Object)(object)attach) && Object.op_Implicit((Object)(object)model) && Object.op_Implicit((Object)(object)bow))
			{
				if (lastFrame != Time.frameCount)
				{
					lastFrame = Time.frameCount;
					float unscaledDeltaTime = Time.unscaledDeltaTime;
					contact = Mathf.MoveTowards(contact, (float)(playing ? 1 : 0), unscaledDeltaTime / (playing ? 0.18f : 0.26f));
					float num = Mathf.SmoothStep(0f, 1f, progress);
					float num2 = ((!playing) ? 0f : (forward ? num : (1f - num)));
					stroke = Mathf.MoveTowards(stroke, num2, unscaledDeltaTime * (playing ? 1.8f : 3.846154f));
				}
				float num3 = Mathf.SmoothStep(0f, 1f, contact);
				animator.SetLookAtWeight(0f);
				Quaternion val2 = visual.rotation * Quaternion.Euler(8f, 16f, -10f) * headNeutralRotation;
				animator.SetBoneLocalRotation((HumanBodyBones)10, Quaternion.Inverse(head.parent.rotation) * val2);
				Vector3 val3 = default(Vector3);
				((Vector3)(ref val3))..ctor(0.62f, 0f, 0.78f);
				Quaternion val4 = visual.rotation * Quaternion.LookRotation(Vector3.down, val3) * Quaternion.Euler(Mathf.Lerp(9f, 6f, num3), 0f, 0f);
				Vector3 val5 = head.position + visual.rotation * new Vector3(0.08f, -0.135f, 0.1f);
				attach.SetPositionAndRotation(val5, val4);
				right.Pose(model, new Vector3(0.035f, 0.265f, 0.005f), Quaternion.LookRotation(Vector3.down, Vector3.back), new Vector3(0.13f, 0.18f, 0.17f));
				Quaternion val6 = model.rotation * AcrossStrings * Quaternion.Euler(0f, 0f, -10f * (1f - num3)) * BowRoll;
				Vector3 val7 = model.TransformPoint(new Vector3(0f, 0.135f + 0.025f * (1f - num3), -0.031f - 0.025f * (1f - num3)));
				Vector3 val8 = default(Vector3);
				((Vector3)(ref val8))..ctor(0.011f, Mathf.Lerp(0.13f, 0.25f, stroke), 0f);
				Vector3 val9 = val7 - val6 * Vector3.Scale(val8, bow.lossyScale);
				if (Object.op_Implicit((Object)(object)bowVisual))
				{
					bowVisual.SetPerformancePose(val9, val6);
				}
				else
				{
					bow.SetPositionAndRotation(val9, val6);
				}
				Quaternion val10 = Quaternion.Inverse(BowRoll);
				left.Pose(bow, val10 * (BowGrip + new Vector3(0.012f, 0f, 0.018f)), val10 * Quaternion.LookRotation(Vector3.left, Vector3.back), val10 * new Vector3(-0.13f, -0.04f, 0.11f));
				fingers.Apply(animator);
			}
		}

		private void Bind(Transform held)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			RestoreAttachment();
			Transform val = held.Find("model");
			Transform val2 = (Object.op_Implicit((Object)(object)val) ? val.Find("bow") : null);
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2))
			{
				attach = held;
				model = val;
				bow = val2;
				bowVisual = ((Component)bow).GetComponent<InstrumentBowHandVisual>();
				originalParent = held.parent;
				originalPosition = held.localPosition;
				originalRotation = held.localRotation;
				originalScale = held.localScale;
				originalModelPosition = val.localPosition;
				originalModelRotation = val.localRotation;
				held.SetParent(chest, true);
				val.localRotation = Quaternion.identity;
				val.localPosition = -Vector3.Scale(ShoulderRest, val.localScale);
			}
		}

		private Quaternion NeutralHeadRotation()
		{
			//IL_00c3: 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)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			VisEquipment visEquipment = ((Humanoid)player).GetVisEquipment();
			SkinnedMeshRenderer val = (Object.op_Implicit((Object)(object)visEquipment) ? visEquipment.m_bodyModel : null);
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)head))
			{
				Transform[] bones = val.bones;
				Matrix4x4[] bindposes = val.sharedMesh.bindposes;
				for (int i = 0; i < bones.Length && i < bindposes.Length; i++)
				{
					if ((Object)(object)bones[i] == (Object)(object)head)
					{
						Matrix4x4 val2 = visual.worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix * ((Matrix4x4)(ref bindposes[i])).inverse;
						return ((Matrix4x4)(ref val2)).rotation;
					}
				}
			}
			if (!Object.op_Implicit((Object)(object)head))
			{
				return Quaternion.identity;
			}
			return Quaternion.Inverse(visual.rotation) * head.rotation;
		}

		private void RestoreAttachment()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)attach) && Object.op_Implicit((Object)(object)originalParent))
			{
				attach.SetParent(originalParent, false);
				attach.localPosition = originalPosition;
				attach.localRotation = originalRotation;
				attach.localScale = originalScale;
			}
			if (Object.op_Implicit((Object)(object)model))
			{
				model.localPosition = originalModelPosition;
				model.localRotation = originalModelRotation;
			}
			if (Object.op_Implicit((Object)(object)bowVisual))
			{
				bowVisual.ClearPerformancePose();
			}
			attach = (model = (bow = (originalParent = null)));
			bowVisual = null;
		}

		public void Dispose()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			RestoreAttachment();
			if (Object.op_Implicit((Object)(object)animator))
			{
				animator.cullingMode = cullingMode;
			}
		}
	}
	internal sealed class BowedVoiceFilter : MonoBehaviour
	{
		private readonly float[] body = new float[8];

		private readonly float[] energy = new float[8];

		private volatile float targetPressure;

		private volatile float targetScrape;

		private volatile bool initialized;

		private float pressure;

		private float scrape;

		private float noiseLow;

		private float noiseHigh;

		private float bodyCoefficient;

		private float noiseLowCoefficient;

		private float noiseHighCoefficient;

		private float smoothing;

		private uint random;

		internal void Initialize(int note)
		{
			int outputSampleRate = AudioSettings.outputSampleRate;
			bodyCoefficient = Coefficient(900f, outputSampleRate);
			noiseLowCoefficient = Coefficient(5500f, outputSampleRate);
			noiseHighCoefficient = Coefficient(1200f, outputSampleRate);
			smoothing = 1f - (float)Math.Exp(-1.0 / (0.012 * (double)outputSampleRate));
			random = (uint)(-1640531527 + note);
			initialized = true;
		}

		private static float Coefficient(float frequency, int rate)
		{
			return 1f - (float)Math.Exp(Math.PI * -2.0 * (double)frequency / (double)rate);
		}

		internal void SetBow(float bowPressure, float contactNoise)
		{
			targetPressure = bowPressure;
			targetScrape = contactNoise;
		}

		private void OnAudioFilterRead(float[] data, int channels)
		{
			if (!initialized || channels < 1 || channels > body.Length)
			{
				return;
			}
			float num = targetPressure;
			float num2 = targetScrape;
			for (int i = 0; i < data.Length; i += channels)
			{
				pressure += (num - pressure) * smoothing;
				scrape += (num2 - scrape) * smoothing;
				random ^= random << 13;
				random ^= random >> 17;
				random ^= random << 5;
				float num3 = (float)(random & 0xFFFFFF) / 8388608f - 1f;
				noiseLow += (num3 - noiseLow) * noiseLowCoefficient;
				noiseHigh += (num3 - noiseHigh) * noiseHighCoefficient;
				for (int j = 0; j < channels; j++)
				{
					int num4 = i + j;
					float num5 = data[num4];
					energy[j] += (num5 * num5 - energy[j]) * smoothing;
					float num6 = (noiseLow - noiseHigh) * 3f * (float)Math.Sqrt(Math.Max(0f, energy[j])) * scrape;
					body[j] += (num5 - body[j]) * bodyCoefficient;
					float num7 = num5 + (num5 - body[j]) * (0.08f + 0.12f * pressure);
					float num8 = num7 * (1.2f + 0.3f * pressure);
					float num9 = num8 / (1f + Math.Abs(num8));
					data[num4] = num7 * 0.75f + num9 * 0.25f + num6;
				}
			}
		}
	}
	internal static class CameraPitch
	{
		internal const float StepAngle = 10f;

		internal const float MaxOffset = 0.25f;

		internal static float FromElevation(float degrees)
		{
			if (!(degrees < -10f))
			{
				if (!(degrees > 10f))
				{
					return 0f;
				}
				return 0.25f;
			}
			return -0.25f;
		}

		internal static bool IsValid(float offset)
		{
			if (offset != -0.25f && offset != 0f)
			{
				return offset == 0.25f;
			}
			return true;
		}
	}
	internal static class CameraTremolo
	{
		internal const float FastRate = 10f;

		internal const float SlowRate = 4f;

		private const float MinimumAngularSpeed = 12f;

		internal static float FromMovement(float previousYaw, float yaw, float deltaTime)
		{
			if (deltaTime <= 0f)
			{
				return 0f;
			}
			float num = Mathf.DeltaAngle(previousYaw, yaw) / deltaTime;
			if (Mathf.Abs(num) < 12f)
			{
				return 0f;
			}
			if (!(num < 0f))
			{
				return 4f;
			}
			return 10f;
		}

		internal static bool IsValid(float rate)
		{
			if (rate != 0f && rate != 4f)
			{
				return rate == 10f;
			}
			return true;
		}
	}
	internal sealed class DrumArm
	{
		private readonly InstrumentArm arm;

		private readonly bool isLeft;

		internal DrumArm(Animator animator, bool left)
		{
			arm = new InstrumentArm(animator, left);
			isLeft = left;
		}

		internal void Pose(Transform drum, float x, float lift)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			arm.Pose(drum, new Vector3(x, 0.24f + lift, -0.04f - lift * 0.2f), Quaternion.LookRotation(Vector3.forward, isLeft ? Vector3.left : Vector3.right), new Vector3(isLeft ? (-0.42f) : 0.42f, 0.35f + lift * 0.5f, -0.2f));
		}
	}
	internal sealed class DrumPerformance : IInstrumentPerformance, IDisposable
	{
		private const float WindupDuration = 0.2f;

		private const float DownstrokeDuration = 0.09f;

		private const float StrikeDelay = 0.29000002f;

		private const float RecoveryDuration = 0.18f;

		private const float RestLift = 0.08f;

		private const float SwingLift = 0.38f;

		private const float HitGain = 1.5f;

		private static readonly FieldRef<VisEquipment, GameObject> HeldItem = AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_rightItemInstance");

		private static readonly FieldRef<VisEquipment, int> HeldHash = AccessTools.FieldRefAccess<VisEquipment, int>("m_currentRightItemHash");

		private static readonly int DrumHash = StringExtensionMethods.GetStableHashCode("Instruments_Drum");

		private readonly Player player;

		private readonly AudioSource source;

		private readonly AudioClip[] clips;

		private readonly Animator animator;

		private readonly AnimatorCullingMode cullingMode;

		private readonly DrumArm left;

		private readonly DrumArm right;

		private readonly InstrumentFingerPose fists;

		private readonly List<(float Impact, int Note)> pendingHits = new List<(float, int)>();

		private float leftContact = float.NegativeInfinity;

		private float rightContact = float.NegativeInfinity;

		internal DrumPerformance(Player player)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			this.player = player;
			clips = (AudioClip[])(object)new AudioClip[3]
			{
				InstrumentAudio.Load("drum/drum_hit.wav"),
				InstrumentAudio.Load("drum/drum-hit-hi.wav"),
				InstrumentAudio.Load("drum/drum-hit-low.wav")
			};
			GameObject val = new GameObject("Instruments_DrumAudio");
			val.transform.SetParent(((Component)player).transform, false);
			val.transform.localPosition = new Vector3(0f, 1.2f, 0.4f);
			source = val.AddComponent<AudioSource>();
			source.playOnAwake = false;
			source.volume = Mathf.Sqrt(AudioMan.GetSFXVolume());
			source.spatialBlend = 1f;
			source.reverbZoneMix = 0.28f;
			source.rolloffMode = (AudioRolloffMode)1;
			source.minDistance = 5f;
			source.maxDistance = 35f;
			source.dopplerLevel = 0f;
			source.pitch = 1f;
			animator = ((Component)player).GetComponentInChildren<Animator>();
			cullingMode = animator.cullingMode;
			animator.cullingMode = (AnimatorCullingMode)0;
			left = new DrumArm(animator, left: true);
			right = new DrumArm(animator, left: false);
			fists = new InstrumentFingerPose(animator);
		}

		public void OnNote(NoteEvent kind, int note)
		{
			if (kind != NoteEvent.Release)
			{
				pendingHits.Add((Time.time + 0.29000002f, note));
			}
		}

		public void LateUpdate()
		{
			source.volume = Mathf.Sqrt(AudioMan.GetSFXVolume());
			while (pendingHits.Count > 0 && Time.time >= pendingHits[0].Impact)
			{
				(float, int) tuple = pendingHits[0];
				source.PlayOneShot(clips[tuple.Item2], 1.5f);
				if (UsesHand(tuple.Item2, left: true))
				{
					(leftContact, _) = tuple;
				}
				if (UsesHand(tuple.Item2, left: false))
				{
					(rightContact, _) = tuple;
				}
				pendingHits.RemoveAt(0);
			}
		}

		public void OnAnimatorIK()
		{
			InstrumentAnimationPatch.ClearHandIK(animator);
			if (!((Character)player).IsDead() && !((Character)player).InCutscene() && !((Character)player).InDodge() && !((Character)player).IsStaggering() && !((Character)player).IsSwimming() && !((Character)player).IsAttached())
			{
				VisEquipment visEquipment = ((Humanoid)player).GetVisEquipment();
				GameObject val = HeldItem.Invoke(visEquipment);
				if (HeldHash.Invoke(visEquipment) == DrumHash && Object.op_Implicit((Object)(object)val) && !(((Object)val.transform.parent).name != "Spine"))
				{
					left.Pose(val.transform, -0.11f, Lift(leftHand: true, leftContact));
					right.Pose(val.transform, 0.11f, Lift(leftHand: false, rightContact));
					fists.Apply(animator);
				}
			}
		}

		private static bool UsesHand(int note, bool left)
		{
			if (note != 2)
			{
				return note == ((!left) ? 1 : 0);
			}
			return true;
		}

		private float Lift(bool leftHand, float lastContact)
		{
			foreach (var pendingHit in pendingHits)
			{
				if (UsesHand(pendingHit.Note, leftHand))
				{
					if (Time.time >= pendingHit.Impact)
					{
						return RecoveryLift(Time.time - pendingHit.Impact);
					}
					float num = Mathf.Max(pendingHit.Impact - 0.29000002f, lastContact);
					float num2 = pendingHit.Impact - num;
					float num3 = num2 * 0.6896551f;
					float num4 = Time.time - num;
					float num5 = 0.38f * Mathf.Clamp01(num2 / 0.29000002f);
					if (num4 < num3)
					{
						return Mathf.Lerp(RecoveryLift(num - lastContact), num5, Mathf.SmoothStep(0f, 1f, num4 / num3));
					}
					return Mathf.Lerp(num5, 0f, Mathf.SmoothStep(0f, 1f, (num4 - num3) / (num2 - num3)));
				}
			}
			return RecoveryLift(Time.time - lastContact);
		}

		private static float RecoveryLift(float elapsed)
		{
			return 0.08f * Mathf.SmoothStep(0f, 1f, elapsed / 0.18f);
		}

		public void Dispose()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			pendingHits.Clear();
			if (Object.op_Implicit((Object)(object)animator))
			{
				animator.cullingMode = cullingMode;
			}
			if (Object.op_Implicit((Object)(object)source))
			{
				Object.Destroy((Object)(object)((Component)source).gameObject, Mathf.Max(new float[3]
				{
					clips[0].length,
					clips[1].length,
					clips[2].length
				}));
			}
		}
	}
	internal sealed class GusliArm
	{
		private const float StrumDuration = 0.16f;

		private const float RecoveryDuration = 0.24f;

		private readonly InstrumentArm arm;

		private readonly Vector3 ready;

		private readonly Vector3 contact;

		private readonly Vector3 elbow;

		private readonly Quaternion readyRotation;

		private readonly Quaternion contactRotation;

		private Vector3 start;

		private Quaternion startRotation;

		private Vector3 end;

		private Quaternion endRotation;

		private float started = float.NegativeInfinity;

		internal GusliArm(Animator animator, bool left)
		{
			//IL_0039: 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_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_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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			arm = new InstrumentArm(animator, left);
			float num = ((!left) ? 1 : (-1));
			ready = new Vector3(0.12f, num * 0.22f, -0.12f);
			contact = new Vector3(0.06f, num * 0.07f, -0.085f);
			elbow = new Vector3(0.28f, num * 0.44f, 0.18f);
			readyRotation = Quaternion.LookRotation(new Vector3(-1f, (0f - num) * 0.35f, 0f), Vector3.back);
			contactRotation = Quaternion.LookRotation(new Vector3(-1f, num * 0.15f, 0f), Vector3.back);
			end = contact;
			endRotation = contactRotation;
		}

		internal void Strum(bool continuous = false, bool reverse = false)
		{
			//IL_0067: 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_0073: 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_0042: 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_0047: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			Evaluate(out start, out startRotation);
			if (continuous)
			{
				end = (Vector3)(reverse ? new Vector3(contact.x, ready.y, contact.z) : contact);
				endRotation = (reverse ? readyRotation : contactRotation);
			}
			else
			{
				end = contact;
				endRotation = contactRotation;
			}
			started = Time.time;
		}

		internal void Pose(Transform instrument)
		{
			//IL_0011: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			Evaluate(out var wrist, out var rotation);
			arm.Pose(instrument, wrist, rotation, elbow);
		}

		private void Evaluate(out Vector3 wrist, out Quaternion rotation)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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)
			//IL_00c3: 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)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_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)
			float num = Time.time - started;
			if (num < 0.16f)
			{
				float num2 = Mathf.SmoothStep(0f, 1f, num / 0.16f);
				wrist = Vector3.Lerp(start, end, num2);
				rotation = Quaternion.Slerp(startRotation, endRotation, num2);
			}
			else
			{
				float num3 = Mathf.Clamp01((num - 0.16f) / 0.24f);
				float num4 = Mathf.SmoothStep(0f, 1f, num3);
				wrist = Vector3.Lerp(end, ready, num4);
				wrist.z -= 0.04f * Mathf.Sin(num3 * MathF.PI);
				rotation = Quaternion.Slerp(endRotation, readyRotation, num4);
			}
		}
	}
	internal sealed class GusliPerformance : IInstrumentPerformance, IDisposable, IPitchedInstrumentPerformance
	{
		private const double BlockStrumInterval = 0.16;

		private readonly AudioSource source;

		private readonly AudioClip[] clips;

		private readonly AudioClip reverseBlockClip;

		private readonly float tailDuration;

		private readonly GusliPose pose;

		private float pitch = 1f;

		private int heldMask;

		private double nextBlockStrum;

		private bool nextBlockReverse;

		internal GusliPerformance(Player player)
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			pose = new GusliPose(player);
			clips = (AudioClip[])(object)new AudioClip[3]
			{
				InstrumentAudio.Load("gusli/gusli-C.wav"),
				InstrumentAudio.Load("gusli/gusli-F.wav"),
				InstrumentAudio.Load("gusli/gusli-G.wav")
			};
			reverseBlockClip = InstrumentAudio.Load("gusli/gusli-F-reverse.wav");
			tailDuration = Mathf.Max(new float[4]
			{
				clips[0].length,
				clips[1].length,
				clips[2].length,
				reverseBlockClip.length
			});
			GameObject val = new GameObject("Instruments_GusliAudio");
			val.transform.SetParent(((Component)player).transform, false);
			val.transform.localPosition = new Vector3(0f, 1f, 0.4f);
			source = val.AddComponent<AudioSource>();
			source.playOnAwake = false;
			source.volume = Mathf.Sqrt(AudioMan.GetSFXVolume());
			source.spatialBlend = 1f;
			source.reverbZoneMix = 0.28f;
			source.rolloffMode = (AudioRolloffMode)1;
			source.minDistance = 5f;
			source.maxDistance = 35f;
			source.dopplerLevel = 0f;
			source.pitch = 1f;
		}

		public void SetPitch(float offset)
		{
			pitch = 1f + offset;
			if (heldMask != 0)
			{
				source.pitch = pitch;
			}
		}

		public void OnNote(NoteEvent kind, int note)
		{
			if ((uint)note >= clips.Length)
			{
				return;
			}
			if (kind == NoteEvent.Release)
			{
				heldMask &= ~(1 << note);
				return;
			}
			bool flag = (heldMask & (1 << note)) != 0;
			heldMask |= 1 << note;
			if (note == 1)
			{
				if (flag)
				{
					return;
				}
				nextBlockStrum = Time.timeAsDouble + 0.16;
				nextBlockReverse = true;
			}
			Strum(note);
		}

		private void Strum(int note, bool reverse = false)
		{
			source.pitch = pitch;
			source.PlayOneShot((note == 1 && reverse) ? reverseBlockClip : clips[note], (note == 1) ? 0.8f : 1f);
			pose.Strum(note, reverse);
		}

		public void LateUpdate()
		{
			source.volume = Mathf.Sqrt(AudioMan.GetSFXVolume());
			if ((heldMask & 2) != 0 && !(Time.timeAsDouble < nextBlockStrum))
			{
				double timeAsDouble = Time.timeAsDouble;
				nextBlockStrum += (Math.Floor((timeAsDouble - nextBlockStrum) / 0.16) + 1.0) * 0.16;
				Strum(1, nextBlockReverse);
				nextBlockReverse = !nextBlockReverse;
			}
		}

		public void OnAnimatorIK()
		{
			pose.Apply();
		}

		public void Dispose()
		{
			pose.Dispose();
			if (Object.op_Implicit((Object)(object)source))
			{
				Object.Destroy((Object)(object)((Component)source).gameObject, tailDuration / source.pitch);
			}
		}
	}
	internal sealed class GusliPose : IDisposable
	{
		private static readonly FieldRef<VisEquipment, GameObject> HeldItem = AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_rightItemInstance");

		private static readonly FieldRef<VisEquipment, int> HeldHash = AccessTools.FieldRefAccess<VisEquipment, int>("m_currentRightItemHash");

		private static readonly int GusliHash = StringExtensionMethods.GetStableHashCode("Instruments_Gusli");

		private readonly Player player;

		private readonly Animator animator;

		private readonly AnimatorCullingMode cullingMode;

		private readonly GusliArm left;

		private readonly GusliArm right;

		private readonly InstrumentFingerPose fingers;

		internal GusliPose(Player player)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			this.player = player;
			animator = ((Component)player).GetComponentInChildren<Animator>();
			cullingMode = animator.cullingMode;
			animator.cullingMode = (AnimatorCullingMode)0;
			left = new GusliArm(animator, left: true);
			right = new GusliArm(animator, left: false);
			fingers = new InstrumentFingerPose(animator, 0.2f, 0.1f);
		}

		internal void Strum(int note, bool reverse = false)
		{
			if ((note == 0 || note == 2) ? true : false)
			{
				left.Strum();
			}
			if ((uint)(note - 1) <= 1u)
			{
				right.Strum(note == 1, reverse);
			}
		}

		internal void Apply()
		{
			InstrumentAnimationPatch.ClearHandIK(animator);
			if (((Character)player).IsDead() || ((Character)player).InCutscene() || ((Character)player).IsTeleporting() || ((Character)player).InBed() || ((Character)player).InDodge() || ((Character)player).IsStaggering() || ((Character)player).IsSwimming() || ((Character)player).IsAttached() || ((Character)player).InEmote())
			{
				return;
			}
			VisEquipment visEquipment = ((Humanoid)player).GetVisEquipment();
			if (visEquipment != null && Object.op_Implicit((Object)(object)visEquipment))
			{
				GameObject val = HeldItem.Invoke(visEquipment);
				if (Object.op_Implicit((Object)(object)val) && val.activeInHierarchy && HeldHash.Invoke(visEquipment) == GusliHash && Object.op_Implicit((Object)(object)val.transform.parent) && !(((Object)val.transform.parent).name != "Spine"))
				{
					left.Pose(val.transform);
					right.Pose(val.transform);
					fingers.Apply(animator);
				}
			}
		}

		public void Dispose()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)animator))
			{
				animator.cullingMode = cullingMode;
			}
		}
	}
	internal sealed class HornPerformance : IInstrumentPerformance, IDisposable, IPitchedInstrumentPerformance
	{
		private const float FadeInDuration = 0.04f;

		private const float FadeOutDuration = 0.06f;

		private readonly GameObject audio;

		private readonly AudioSource[] sources = (AudioSource[])(object)new AudioSource[3];

		private readonly bool[] held = new bool[3];

		private readonly float[] gains = new float[3];

		private readonly HornPose pose;

		internal HornPerformance(Player player)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			pose = new HornPose(player);
			AudioClip[] array = (AudioClip[])(object)new AudioClip[3]
			{
				InstrumentAudio.Load("horn/horn1.wav"),
				InstrumentAudio.Load("horn/horn2.wav"),
				InstrumentAudio.Load("horn/horn3.wav")
			};
			audio = new GameObject("Instruments_HornAudio");
			audio.transform.SetParent(((Component)player).transform, false);
			audio.transform.localPosition = new Vector3(0f, 1.5f, 0.4f);
			for (int i = 0; i < sources.Length; i++)
			{
				AudioSource val = audio.AddComponent<AudioSource>();
				val.playOnAwake = false;
				val.clip = array[i];
				val.loop = true;
				val.volume = 0f;
				val.spatialBlend = 1f;
				val.reverbZoneMix = 0.28f;
				val.rolloffMode = (AudioRolloffMode)1;
				val.minDistance = 5f;
				val.maxDistance = 35f;
				val.dopplerLevel = 0f;
				val.pitch = 1f;
				sources[i] = val;
			}
		}

		public void SetPitch(float offset)
		{
			AudioSource[] array = sources;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].pitch = 1f + offset;
			}
		}

		public void OnNote(NoteEvent kind, int note)
		{
			switch (kind)
			{
			case NoteEvent.Release:
				held[note] = false;
				break;
			case NoteEvent.Press:
				if (!held[note])
				{
					held[note] = true;
					if (!sources[note].isPlaying)
					{
						gains[note] = 0f;
						sources[note].volume = 0f;
						sources[note].Play();
					}
				}
				break;
			}
		}

		public void LateUpdate()
		{
			float num = Mathf.Sqrt(AudioMan.GetSFXVolume());
			for (int i = 0; i < sources.Length; i++)
			{
				float num2 = (held[i] ? 0.04f : 0.06f);
				gains[i] = Mathf.MoveTowards(gains[i], (float)(held[i] ? 1 : 0), Time.unscaledDeltaTime / num2);
				sources[i].volume = num * gains[i];
				if (!held[i] && gains[i] == 0f)
				{
					sources[i].Stop();
				}
			}
		}

		public void OnAnimatorIK()
		{
			bool flag = false;
			for (int i = 0; i < held.Length; i++)
			{
				flag |= held[i];
			}
			pose.Apply(flag);
		}

		public void Dispose()
		{
			pose.Dispose();
			if (Object.op_Implicit((Object)(object)audio))
			{
				audio.AddComponent<HornFadeOut>().Initialize(sources, 0.06f);
			}
		}
	}
	internal sealed class HornFadeOut : MonoBehaviour
	{
		private AudioSource[] sources;

		private float[] volumes;

		private float duration;

		private float elapsed;

		internal void Initialize(AudioSource[] voices, float fadeDuration)
		{
			sources = voices;
			duration = fadeDuration;
			volumes = new float[voices.Length];
			for (int i = 0; i < voices.Length; i++)
			{
				volumes[i] = voices[i].volume;
			}
		}

		private void Update()
		{
			elapsed += Time.unscaledDeltaTime;
			float num = Mathf.Clamp01(1f - elapsed / duration);
			for (int i = 0; i < sources.Length; i++)
			{
				sources[i].volume = volumes[i] * num;
			}
			if (elapsed >= duration)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	internal sealed class HornPose : IDisposable
	{
		private const float RaiseDuration = 0.2f;

		private const float LowerDuration = 0.24f;

		private const float HeadPitch = 8f;

		private static readonly Vector3 Mouthpiece = new Vector3(-0.224f, 0.138f, 0f);

		private static readonly Vector3 MouthOffset = new Vector3(0f, 0.025f, 0.1f);

		private static readonly Vector3 ReadyOffset = new Vector3(0.03f, -0.08f, 0.18f);

		private static readonly FieldRef<VisEquipment, GameObject> HeldItem = AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_rightItemInstance");

		private static readonly FieldRef<VisEquipment, int> HeldHash = AccessTools.FieldRefAccess<VisEquipment, int>("m_currentRightItemHash");

		private static readonly int HornHash = StringExtensionMethods.GetStableHashCode("Instruments_Horn");

		private readonly Player player;

		private readonly Animator animator;

		private readonly AnimatorCullingMode cullingMode;

		private readonly Transform visual;

		private readonly Transform? chest;

		private readonly Transform? head;

		private readonly Quaternion headNeutralRotation;

		private readonly InstrumentArm left;

		private readonly InstrumentArm right;

		private readonly InstrumentFingerPose fingers;

		private Transform? attach;

		private Transform? model;

		private Transform? originalParent;

		private Vector3 originalPosition;

		private Quaternion originalRotation;

		private Vector3 originalScale;

		private Vector3 originalModelPosition;

		private Quaternion originalModelRotation;

		private float raised;

		private int lastFrame = -1;

		internal HornPose(Player player)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			this.player = player;
			animator = ((Component)player).GetComponentInChildren<Animator>();
			visual = ((Component)animator).transform;
			cullingMode = animator.cullingMode;
			animator.cullingMode = (AnimatorCullingMode)0;
			if (animator.isHuman)
			{
				chest = animator.GetBoneTransform((HumanBodyBones)8);
				head = animator.GetBoneTransform((HumanBodyBones)10);
			}
			headNeutralRotation = NeutralHeadRotation();
			left = new InstrumentArm(animator, left: true);
			right = new InstrumentArm(animator, left: false);
			fingers = new InstrumentFingerPose(animator, -0.65f, -0.35f);
		}

		internal void Apply(bool playing)
		{
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: 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_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: 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_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			InstrumentAnimationPatch.ClearHandIK(animator);
			VisEquipment visEquipment = ((Humanoid)player).GetVisEquipment();
			GameObject val = (Object.op_Implicit((Object)(object)visEquipment) ? HeldItem.Invoke(visEquipment) : null);
			int num = (Object.op_Implicit((Object)(object)visEquipment) ? HeldHash.Invoke(visEquipment) : 0);
			if (!Object.op_Implicit((Object)(object)head) || !Object.op_Implicit((Object)(object)chest) || !Object.op_Implicit((Object)(object)val) || !val.activeInHierarchy || num != HornHash || ((Character)player).IsDead() || ((Character)player).InCutscene() || ((Character)player).InDodge() || ((Character)player).IsStaggering() || ((Character)player).IsSwimming() || ((Character)player).IsAttached() || ((Character)player).InBed() || ((Character)player).InEmote())
			{
				RestoreAttachment();
				raised = 0f;
				return;
			}
			if ((Object)(object)attach != (Object)(object)val.transform)
			{
				Bind(val.transform);
			}
			if (Object.op_Implicit((Object)(object)attach) && Object.op_Implicit((Object)(object)model))
			{
				if (lastFrame != Time.frameCount)
				{
					lastFrame = Time.frameCount;
					raised = Mathf.MoveTowards(raised, (float)(playing ? 1 : 0), Time.deltaTime / (playing ? 0.2f : 0.24f));
				}
				float num2 = Mathf.SmoothStep(0f, 1f, raised);
				Quaternion val2 = Quaternion.Euler(-8f * num2, 0f, 0f);
				if (playing || raised > 0f)
				{
					animator.SetLookAtWeight(0f);
					Quaternion val3 = visual.rotation * val2 * headNeutralRotation;
					animator.SetBoneLocalRotation((HumanBodyBones)10, Quaternion.Inverse(head.parent.rotation) * val3);
				}
				Vector3 val4 = head.position + visual.rotation * ReadyOffset;
				Vector3 val5 = head.position + visual.rotation * val2 * MouthOffset;
				Quaternion val6 = visual.rotation * Quaternion.Euler(Mathf.Lerp(3f, -8f, num2), 22f, 0f) * Quaternion.Euler(0f, -90f, 0f);
				attach.SetPositionAndRotation(Vector3.Lerp(val4, val5, num2), val6);
				right.Pose(model, new Vector3(-0.14f, 0.035f, -0.04f), Quaternion.LookRotation(Vector3.up, Vector3.back), new Vector3(-0.2f, -0.16f, -0.23f));
				left.Pose(model, new Vector3(-0.025f, -0.005f, 0.045f), Quaternion.LookRotation(Vector3.up, Vector3.forward), new Vector3(-0.19f, -0.17f, 0.24f));
				fingers.Apply(animator);
			}
		}

		private void Bind(Transform held)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_007f: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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)
			RestoreAttachment();
			Transform val = held.Find("model");
			if (Object.op_Implicit((Object)(object)val))
			{
				attach = held;
				model = val;
				originalParent = held.parent;
				originalPosition = held.localPosition;
				originalRotation = held.localRotation;
				originalScale = held.localScale;
				originalModelPosition = val.localPosition;
				originalModelRotation = val.localRotation;
				held.SetParent(chest, true);
				val.localRotation = Quaternion.identity;
				val.localPosition = -Vector3.Scale(Mouthpiece, val.localScale);
			}
		}

		private Quaternion NeutralHeadRotation()
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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)
			//IL_006f: 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)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			SkinnedMeshRenderer bodyModel = ((Humanoid)player).GetVisEquipment().m_bodyModel;
			if (Object.op_Implicit((Object)(object)bodyModel) && Object.op_Implicit((Object)(object)head))
			{
				Transform[] bones = bodyModel.bones;
				Matrix4x4[] bindposes = bodyModel.sharedMesh.bindposes;
				for (int i = 0; i < bones.Length && i < bindposes.Length; i++)
				{
					if ((Object)(object)bones[i] == (Object)(object)head)
					{
						Matrix4x4 val = visual.worldToLocalMatrix * ((Component)bodyModel).transform.localToWorldMatrix * ((Matrix4x4)(ref bindposes[i])).inverse;
						return ((Matrix4x4)(ref val)).rotation;
					}
				}
			}
			if (!Object.op_Implicit((Object)(object)head))
			{
				return Quaternion.identity;
			}
			return Quaternion.Inverse(visual.rotation) * head.rotation;
		}

		private void RestoreAttachment()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)attach) && Object.op_Implicit((Object)(object)originalParent))
			{
				attach.SetParent(originalParent, false);
				attach.localPosition = originalPosition;
				attach.localRotation = originalRotation;
				attach.localScale = originalScale;
			}
			if (Object.op_Implicit((Object)(object)model))
			{
				model.localPosition = originalModelPosition;
				model.localRotation = originalModelRotation;
			}
			attach = null;
			model = null;
			originalParent = null;
		}

		public void Dispose()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			RestoreAttachment();
			if (Object.op_Implicit((Object)(object)animator))
			{
				animator.cullingMode = cullingMode;
			}
		}
	}
	internal sealed class InstrumentArm
	{
		private readonly Animator animator;

		private readonly Transform hand;

		private readonly Transform? fingers;

		private readonly Transform? index;

		private readonly Transform? pinky;

		private readonly bool isLeft;

		internal InstrumentArm(Animator animator, bool left)
		{
			isLeft = left;
			this.animator = animator;
			hand = Utils.GetBoneTransform(animator, (HumanBodyBones)(left ? 17 : 18));
			fingers = Utils.FindChild(((Component)animator).transform, left ? "LeftHandMiddle1" : "RightHandMiddle1", (IterativeSearchType)0);
			index = Utils.FindChild(((Component)animator).transform, left ? "LeftHandIndex1" : "RightHandIndex1", (IterativeSearchType)0);
			pinky = Utils.FindChild(((Component)animator).transform, left ? "LeftHandPinky1" : "RightHandPinky1", (IterativeSearchType)0);
		}

		internal void Pose(Transform instrument, Vector3 wrist, Quaternion palmFrame, Vector3 elbow)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_003c: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: 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_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_0113: 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)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)hand) || !animator.isHuman)
			{
				return;
			}
			AvatarIKGoal val = (AvatarIKGoal)(isLeft ? 2 : 3);
			AvatarIKHint val2 = (AvatarIKHint)(isLeft ? 2 : 3);
			Vector3 val3 = instrument.TransformPoint(wrist);
			Vector3 iKPosition = animator.GetIKPosition(val);
			Quaternion iKRotation = animator.GetIKRotation(val);
			Quaternion val4 = Quaternion.identity;
			if (Object.op_Implicit((Object)(object)fingers) && Object.op_Implicit((Object)(object)index) && Object.op_Implicit((Object)(object)pinky))
			{
				Vector3 val5 = fingers.position - hand.position;
				Vector3 val6 = Vector3.Cross(val5, index.position - pinky.position) * (float)(isLeft ? 1 : (-1));
				if (((Vector3)(ref val5)).sqrMagnitude > 1E-06f && ((Vector3)(ref val6)).sqrMagnitude > 1E-06f)
				{
					val4 = instrument.rotation * palmFrame * Quaternion.Inverse(Quaternion.LookRotation(val5, val6));
				}
			}
			animator.SetIKPositionWeight(val, 1f);
			animator.SetIKPosition(val, val3 + val4 * (iKPosition - hand.position));
			animator.SetIKHintPositionWeight(val2, 1f);
			animator.SetIKHintPosition(val2, instrument.TransformPoint(elbow));
			animator.SetIKRotationWeight(val, 1f);
			animator.SetIKRotation(val, val4 * iKRotation);
		}
	}
	internal static class InstrumentAudio
	{
		private static readonly Dictionary<string, AudioClip> Clips = new Dictionary<string, AudioClip>();

		private static InstrumentSoundFiles files = null;

		private static Action<string> warn = null;

		internal static void Initialize(Action<string> logWarning)
		{
			warn = logWarning;
			files = new InstrumentSoundFiles(Path.Combine(Paths.ConfigPath, "Instruments", "sounds"), typeof(Plugin).Assembly, warn);
			files.ExtractDefaults();
		}

		internal static AudioClip Load(string resource)
		{
			if (Clips.TryGetValue(resource, out AudioClip value))
			{
				return value;
			}
			string path = files.GetPath(resource);
			AudioClip val;
			try
			{
				using Stream stream = files.Open(resource);
				val = Decode(stream, resource);
			}
			catch (Exception ex) when (ex is IOException || ex is InvalidDataException || ex is UnauthorizedAccessException || ex is OverflowException)
			{
				using Stream stream2 = files.OpenDefault(resource);
				if (stream2 == null)
				{
					throw new InvalidDataException("Cannot load instrument sample: " + path, ex);
				}
				warn("Cannot load sound '" + path + "': " + ex.Message + ". Using the bundled sample; the file was left unchanged. Expected mono PCM 16-bit WAV.");
				val = Decode(stream2, resource);
			}
			Clips.Add(resource, val);
			return val;
		}

		private static AudioClip Decode(Stream stream, string resource)
		{
			using BinaryReader binaryReader = new BinaryReader(stream);
			if (new string(binaryReader.ReadChars(4)) != "RIFF")
			{
				throw new InvalidDataException(resource);
			}
			binaryReader.ReadUInt32();
			if (new string(binaryReader.ReadChars(4)) != "WAVE")
			{
				throw new InvalidDataException(resource);
			}
			int num = 0;
			int num2 = 0;
			byte[] array = null;
			while (stream.Position + 8 <= stream.Length)
			{
				string text = new string(binaryReader.ReadChars(4));
				uint num3 = binaryReader.ReadUInt32();
				long num4 = stream.Position + num3;
				if (num4 > stream.Length)
				{
					throw new InvalidDataException(resource);
				}
				if (text == "fmt ")
				{
					if (num3 < 16 || binaryReader.ReadUInt16() != 1)
					{
						throw new InvalidDataException("Expected PCM: " + resource);
					}
					num = binaryReader.ReadUInt16();
					num2 = binaryReader.ReadInt32();
					binaryReader.ReadUInt32();
					binaryReader.ReadUInt16();
					if (binaryReader.ReadUInt16() != 16)
					{
						throw new InvalidDataException("Expected 16-bit WAV: " + resource);
					}
				}
				else if (text == "data")
				{
					array = binaryReader.ReadBytes(checked((int)num3));
				}
				stream.Position = num4 + (num3 & 1);
			}
			if (array == null || array.Length == 0 || num != 1 || num2 <= 0 || array.Length % 2 != 0)
			{
				throw new InvalidDataException("Expected mono WAV: " + resource);
			}
			float[] array2 = new float[array.Length / 2];
			for (int i = 0; i < array2.Length; i++)
			{
				array2[i] = (float)(short)(array[i * 2] | (array[i * 2 + 1] << 8)) / 32768f;
			}
			AudioClip obj = AudioClip.Create(resource, array2.Length, num, num2, false);
			obj.SetData(array2, 0);
			return obj;
		}

		internal static void Clear()
		{
			foreach (AudioClip value in Clips.Values)
			{
				Object.Destroy((Object)(object)value);
			}
			Clips.Clear();
		}
	}
	internal sealed class InstrumentFingerPose
	{
		private readonly List<(HumanBodyBones Bone, Quaternion Rotation)> rotations = new List<(HumanBodyBones, Quaternion)>();

		internal InstrumentFingerPose(Animator animator, float fingerStretch = -1f, float thumbStretch = -0.5f)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_00a3: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			if (!animator.isHuman)
			{
				return;
			}
			HumanPoseHandler val = new HumanPoseHandler(animator.avatar, ((Component)animator).transform);
			try
			{
				HumanPose val2 = default(HumanPose);
				val.GetHumanPose(ref val2);
				HumanPose val3 = val2;
				val3.muscles = (float[])val2.muscles.Clone();
				string[] muscleName = HumanTrait.MuscleName;
				for (int i = 0; i < muscleName.Length; i++)
				{
					if (muscleName[i].EndsWith(" Stretched", StringComparison.Ordinal))
					{
						val3.muscles[i] = ((muscleName[i].IndexOf("Thumb", StringComparison.Ordinal) >= 0) ? thumbStretch : fingerStretch);
					}
					else if (muscleName[i].EndsWith(" Spread", StringComparison.Ordinal))
					{
						val3.muscles[i] = 0f;
					}
				}
				try
				{
					val.SetHumanPose(ref val3);
					for (int j = 24; j <= 53; j++)
					{
						HumanBodyBones val4 = (HumanBodyBones)j;
						Transform boneTransform = animator.GetBoneTransform(val4);
						if (Object.op_Implicit((Object)(object)boneTransform))
						{
							rotations.Add((val4, boneTransform.localRotation));
						}
					}
				}
				finally
				{
					val.SetHumanPose(ref val2);
				}
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}

		internal void Apply(Animator animator)
		{
			//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)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			foreach (var (val, val2) in rotations)
			{
				animator.SetBoneLocalRotation(val, val2);
			}
		}
	}
	internal sealed class InstrumentPlayer : MonoBehaviour
	{
		internal const string RpcName = "Instruments_Note_v2";

		internal const string PitchRpcName = "Instruments_Pitch_v1";

		internal const string BowedNoteRpcName = "Instruments_BowedNote_v1";

		internal const string ExpressionRpcName = "Instruments_Expression_v1";

		private const float PitchSendInterval = 0.05f;

		private const float PitchSendThreshold = 0.001f;

		private static readonly Func<PlayerController, bool, bool> TakeInput = AccessTools.MethodDelegate<Func<PlayerController, bool, bool>>(AccessTools.Method(typeof(PlayerController), "TakeInput", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<PlayerController, bool> InInventory = AccessTools.MethodDelegate<Func<PlayerController, bool>>(AccessTools.Method(typeof(PlayerController), "InInventoryEtc", (Type[])null, (Type[])null), (object)null, true);

		private Player player;

		private ZNetView view;

		private PlayerController? controller;

		private PerformanceDefinition? definition;

		private IInstrumentPerformance? performance;

		private NoteInput? input;

		private bool wasOwner;

		private float lastReceived;

		private bool resetHandIK;

		private float pitch;

		private float sentPitch;

		private float lastPitchSent;

		private float tremolo;

		private float sentTremolo;

		private float previousYaw;

		private bool hasPreviousYaw;

		private float lastCameraMovement;

		private const float CameraMovementGrace = 0.06f;

		internal void Initialize(Player target, ZNetView network)
		{
			player = target;
			view = network;
			controller = ((Component)target).GetComponent<PlayerController>();
			wasOwner = view.IsOwner();
			view.Register<int, int, int, float>("Instruments_Note_v2", (Method<int, int, int, float>)Receive);
			view.Register<int, float>("Instruments_Pitch_v1", (Action<long, int, float>)ReceivePitch);
			view.Register<int, int, int, float, float>("Instruments_BowedNote_v1", (Method<int, int, int, float, float>)ReceiveBowedNote);
			view.Register<int, float, float>("Instruments_Expression_v1", (Action<long, int, float, float>)ReceiveExpression);
		}

		private void Update()
		{
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid())
			{
				Reset();
				return;
			}
			bool flag = view.IsOwner();
			if (wasOwner != flag)
			{
				Reset();
				wasOwner = flag;
			}
			int num = ((!flag) ? view.GetZDO().GetInt(ZDOVars.s_rightItem, 0) : (Object.op_Implicit((Object)(object)((Humanoid)player).RightItem?.m_dropPrefab) ? StringExtensionMethods.GetStableHashCode(((Object)((Humanoid)player).RightItem.m_dropPrefab).name) : 0));
			if (flag || definition == null || num == definition.PrefabHash || Time.time - lastReceived > 1f)
			{
				Select(PerformanceRegistry.Find(num));
			}
			if (!flag || input == null)
			{
				return;
			}
			bool flag2 = CanPlay();
			int num2 = (flag2 ? ReadButtons() : 0);
			if (flag2 && definition.UsesCameraPitch)
			{
				float degrees = Mathf.Asin(Mathf.Clamp(((Character)player).m_eye.forward.y, -1f, 1f)) * 57.29578f;
				pitch = CameraPitch.FromElevation(degrees);
				(performance as IPitchedInstrumentPerformance)?.SetPitch(pitch);
			}
			if (definition.UsesCameraTremolo)
			{
				if (flag2)
				{
					Quaternion rotation = ((Character)player).m_eye.rotation;
					float y = ((Quaternion)(ref rotation)).eulerAngles.y;
					float num3 = (hasPreviousYaw ? CameraTremolo.FromMovement(previousYaw, y, Time.unscaledDeltaTime) : 0f);
					previousYaw = y;
					hasPreviousYaw = true;
					if (num3 > 0f)
					{
						tremolo = num3;
						lastCameraMovement = Time.unscaledTime;
					}
					else if (Time.unscaledTime - lastCameraMovement >= 0.06f)
					{
						tremolo = 0f;
					}
				}
				else
				{
					hasPreviousYaw = false;
					tremolo = 0f;
				}
				(performance as ITremoloInstrumentPerformance)?.SetTremolo(tremolo);
			}
			input.Update(num2, Time.timeAsDouble);
			if (num2 != 0 && definition.UsesCameraPitch && Time.unscaledTime - lastPitchSent >= 0.05f && (Mathf.Abs(pitch - sentPitch) >= 0.001f || tremolo != sentTremolo))
			{
				if (definition.UsesCameraTremolo)
				{
					view.InvokeRPC(ZNetView.Everybody, "Instruments_Expression_v1", new object[3] { definition.PrefabHash, pitch, tremolo });
				}
				else
				{
					view.InvokeRPC(ZNetView.Everybody, "Instruments_Pitch_v1", new object[2] { definition.PrefabHash, pitch });
				}
				sentPitch = pitch;
				sentTremolo = tremolo;
				lastPitchSent = Time.unscaledTime;
			}
		}

		private bool CanPlay()
		{
			if ((Object)(object)player == (Object)(object)Player.m_localPlayer && Object.op_Implicit((Object)(object)controller) && ((Behaviour)controller).isActiveAndEnabled && Application.isFocused && !PlayerController.HasInputDelay && TakeInput(controller, arg2: false) && !InInventory(controller) && !Hud.InRadial() && !((Character)player).IsDead() && !((Character)player).InCutscene() && !((Character)player).IsTeleporting() && !((Character)player).InBed() && !((Character)player).InDodge() && !((Character)player).IsStaggering() && !((Character)player).IsSwimming() && !((Character)player).IsAttached())
			{
				return !((Character)player).InEmote();
			}
			return false;
		}

		private static int ReadButtons()
		{
			int num = 0;
			if (ZInput.GetButton("Attack") || ZInput.GetButton("JoyAttack"))
			{
				num |= 1;
			}
			if (ZInput.GetButton("Block") || ZInput.GetButton("JoyBlock"))
			{
				num |= 2;
			}
			if (ZInput.GetButton("SecondaryAttack") || ZInput.GetButton("JoySecondaryAttack"))
			{
				num |= 4;
			}
			return num;
		}

		private void Select(PerformanceDefinition? next)
		{
			if (definition == next)
			{
				return;
			}
			Reset();
			definition = next;
			if (next != null)
			{
				if (!ZNet.instance.IsDedicated())
				{
					performance = next.Create(player);
				}
				input = new NoteInput(next.RepeatInterval, Send);
			}
		}

		private void Send(NoteEvent kind, int note)
		{
			if (definition != null && Object.op_Implicit((Object)(object)view) && view.IsValid() && view.IsOwner())
			{
				performance?.OnNote(kind, note);
				if (definition.UsesCameraTremolo)
				{
					view.InvokeRPC(ZNetView.Everybody, "Instruments_BowedNote_v1", new object[5]
					{
						definition.PrefabHash,
						(int)kind,
						note,
						pitch,
						tremolo
					});
				}
				else
				{
					view.InvokeRPC(ZNetView.Everybody, "Instruments_Note_v2", new object[4]
					{
						definition.PrefabHash,
						(int)kind,
						note,
						pitch
					});
				}
				sentPitch = pitch;
				sentTremolo = tremolo;
				lastPitchSent = Time.unscaledTime;
			}
		}

		private void Receive(long sender, int hash, int kind, int note, float offset)
		{
			ReceiveNote(sender, hash, kind, note, offset, 0f);
		}

		private void ReceiveBowedNote(long sender, int hash, int kind, int note, float offset, float rate)
		{
			if (CameraTremolo.IsValid(rate))
			{
				PerformanceDefinition? performanceDefinition = PerformanceRegistry.Find(hash);
				if (performanceDefinition != null && performanceDefinition.UsesCameraTremolo)
				{
					ReceiveNote(sender, hash, kind, note, offset, rate);
				}
			}
		}

		private void ReceiveNote(long sender, int hash, int kind, int note, float offset, float rate)
		{
			if (view.IsValid() && !view.IsOwner() && sender == view.GetZDO().GetOwner() && (uint)note < 3u && (uint)kind <= 2u && CameraPitch.IsValid(offset))
			{
				PerformanceDefinition performanceDefinition = PerformanceRegistry.Find(hash);
				if (performanceDefinition != null && (kind != 2 || definition == performanceDefinition))
				{
					lastReceived = Time.time;
					Select(performanceDefinition);
					(performance as IPitchedInstrumentPerformance)?.SetPitch(offset);
					(performance as ITremoloInstrumentPerformance)?.SetTremolo(rate);
					performance?.OnNote((NoteEvent)kind, note);
				}
			}
		}

		private void ReceiveExpression(long sender, int hash, float offset, float rate)
		{
			if (view.IsValid() && !view.IsOwner() && sender == view.GetZDO().GetOwner() && definition != null && definition.PrefabHash == hash && definition.UsesCameraTremolo && CameraPitch.IsValid(offset) && CameraTremolo.IsValid(rate))
			{
				lastReceived = Time.time;
				(performance as IPitchedInstrumentPerformance)?.SetPitch(offset);
				(performance as ITremoloInstrumentPerformance)?.SetTremolo(rate);
			}
		}

		private void ReceivePitch(long sender, int hash, float offset)
		{
			if (view.IsValid() && !view.IsOwner() && sender == view.GetZDO().GetOwner() && definition != null && definition.PrefabHash == hash && definition.UsesCameraPitch && CameraPitch.IsValid(offset))
			{
				lastReceived = Time.time;
				(performance as IPitchedInstrumentPerformance)?.SetPitch(offset);
			}
		}

		private void LateUpdate()
		{
			performance?.LateUpdate();
		}

		internal void ApplyAnimationIK(Animator animator)
		{
			if (resetHandIK)
			{
				InstrumentAnimationPatch.ClearHandIK(animator);
				resetHandIK = false;
			}
			performance?.OnAnimatorIK();
		}

		private void Reset()
		{
			input?.ReleaseAll();
			input = null;
			if (performance != null)
			{
				resetHandIK = true;
			}
			performance?.Dispose();
			performance = null;
			definition = null;
			pitch = (sentPitch = (lastPitchSent = 0f));
			tremolo = (sentTremolo = (previousYaw = (lastCameraMovement = 0f)));
			hasPreviousYaw = false;
		}

		private void OnDisable()
		{
			Reset();
		}

		private void OnDestroy()
		{
			Reset();
			if (Object.op_Implicit((Object)(object)view))
			{
				view.Unregister("Instruments_Note_v2");
				view.Unregister("Instruments_Pitch_v1");
				view.Unregister("Instruments_BowedNote_v1");
				view.Unregister("Instruments_Expression_v1");
			}
		}
	}
	[HarmonyPatch(typeof(CharacterAnimEvent), "OnAnimatorIK")]
	internal static class InstrumentAnimationPatch
	{
		internal static void ClearHandIK(Animator animator)
		{
			animator.SetIKPositionWeight((AvatarIKGoal)2, 0f);
			animator.SetIKPositionWeight((AvatarIKGoal)3, 0f);
			animator.SetIKRotationWeight((AvatarIKGoal)2, 0f);
			animator.SetIKRotationWeight((AvatarIKGoal)3, 0f);
			animator.SetIKHintPositionWeight((AvatarIKHint)2, 0f);
			animator.SetIKHintPositionWeight((AvatarIKHint)3, 0f);
		}

		private static void Postfix(Character ___m_character, Animator ___m_animator)
		{
			Player val = (Player)(object)((___m_character is Player) ? ___m_character : null);
			if (val != null)
			{
				((Component)val).GetComponent<InstrumentPlayer>()?.ApplyAnimationIK(___m_animator);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Awake")]
	internal static class InstrumentPlayerPatch
	{
		private static void Postfix(Player __instance, ZNetView ___m_nview)
		{
			if (Object.op_Implicit((Object)(object)___m_nview) && ___m_nview.IsValid())
			{
				((Component)__instance).gameObject.AddComponent<InstrumentPlayer>().Initialize(__instance, ___m_nview);
			}
		}
	}
	internal sealed class InstrumentSoundFiles
	{
		internal const string ResourcePrefix = "Instruments.Sounds/";

		private readonly string root;

		private readonly Assembly assembly;

		private readonly Action<string> warn;

		internal InstrumentSoundFiles(string root, Assembly assembly, Action<string> warn)
		{
			this.root = Path.GetFullPath(root);
			this.assembly = assembly;
			this.warn = warn;
		}

		internal void ExtractDefaults()
		{
			string[] manifestResourceNames = assembly.GetManifestResourceNames();
			foreach (string text in manifestResourceNames)
			{
				if (text.StartsWith("Instruments.Sounds/", StringComparison.Ordinal))
				{
					string relativePath = text.Substring("Instruments.Sounds/".Length);
					try
					{
						EnsureDefault(relativePath);
					}
					catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
					{
						warn("Cannot extract sound '" + GetPath(relativePath) + "': " + ex.Message);
					}
				}
			}
		}

		internal string GetPath(string relativePath)
		{
			if (string.IsNullOrWhiteSpace(relativePath) || Path.IsPathRooted(relativePath) || relativePath.IndexOf('\\') >= 0 || relativePath.IndexOf(':') >= 0 || !relativePath.EndsWith(".wav", StringComparison.OrdinalIgnoreCase))
			{
				throw new ArgumentException("Expected a relative WAV path: " + relativePath, "relativePath");
			}
			string[] array = relativePath.Split('/');
			foreach (string text in array)
			{
				if (text.Length == 0 || text == "." || text == "..")
				{
					throw new ArgumentException("Invalid sound path: " + relativePath, "relativePath");
				}
			}
			return Path.Combine(root, relativePath.Replace('/', Path.DirectorySeparatorChar));
		}

		internal Stream Open(string relativePath)
		{
			EnsureDefault(relativePath);
			return File.OpenRead(GetPath(relativePath));
		}

		internal Stream? OpenDefault(string relativePath)
		{
			GetPath(relativePath);
			return assembly.GetManifestResourceStream("Instruments.Sounds/" + relativePath);
		}

		private void EnsureDefault(string relativePath)
		{
			string path = GetPath(relativePath);
			if (File.Exists(path))
			{
				return;
			}
			using Stream stream = OpenDefault(relativePath);
			if (stream == null)
			{
				return;
			}
			Directory.CreateDirectory(Path.GetDirectoryName(path));
			string text = path + "." + Guid.NewGuid().ToString("N") + ".tmp";
			try
			{
				using (FileStream destination = new FileStream(text, FileMode.CreateNew, FileAccess.Write))
				{
					stream.CopyTo(destination);
				}
				try
				{
					File.Move(text, path);
				}
				catch (IOException) when (File.Exists(path))
				{
				}
			}
			finally
			{
				if (File.Exists(text))
				{
					File.Delete(text);
				}
			}
		}
	}
	internal enum NoteEvent
	{
		Press,
		Repeat,
		Release
	}
	internal sealed class NoteInput
	{
		internal const int NoteCount = 3;

		private readonly bool[] held = new bool[3];

		private readonly double[] next = new double[3];

		private readonly double? interval;

		private readonly Action<NoteEvent, int> emit;

		internal NoteInput(double? interval, Action<NoteEvent, int> emit)
		{
			if (interval.HasValue && (interval.Value <= 0.0 || double.IsNaN(interval.Value) || double.IsInfinity(interval.Value)))
			{
				throw new ArgumentOutOfRangeException("interval");
			}
			this.interval = interval;
			this.emit = emit;
		}

		internal void Update(int mask, double time)
		{
			for (int i = 0; i < 3; i++)
			{
				bool flag = (mask & (1 << i)) != 0;
				if (flag != held[i])
				{
					held[i] = flag;
					next[i] = time + interval.GetValueOrDefault();
					emit((!flag) ? NoteEvent.Release : NoteEvent.Press, i);
				}
				else if (flag && interval.HasValue && time >= next[i])
				{
					next[i] += (Math.Floor((time - next[i]) / interval.Value) + 1.0) * interval.Value;
					emit(NoteEvent.Repeat, i);
				}
			}
		}

		internal void ReleaseAll()
		{
			Update(0, 0.0);
		}
	}
	internal interface IInstrumentPerformance : IDisposable
	{
		void OnNote(NoteEvent kind, int note);

		void OnAnimatorIK();

		void LateUpdate();
	}
	internal interface IPitchedInstrumentPerformance
	{
		void SetPitch(float offset);
	}
	internal interface ITremoloInstrumentPerformance
	{
		void SetTremolo(float rate);
	}
	internal sealed class PerformanceDefinition
	{
		internal readonly int PrefabHash;

		internal readonly double? RepeatInterval;

		internal readonly Func<Player, IInstrumentPerformance> Create;

		internal readonly bool UsesCameraPitch;

		internal readonly bool UsesCameraTremolo;

		internal PerformanceDefinition(string prefab, double? repeatInterval, Func<Player, IInstrumentPerformance> create, bool usesCameraPitch = false, bool usesCameraTremolo = false)
		{
			PrefabHash = StringExtensionMethods.GetStableHashCode(prefab);
			RepeatInterval = repeatInterval;
			Create = create;
			UsesCameraPitch = usesCameraPitch;
			UsesCameraTremolo = usesCameraTremolo;
		}
	}
	internal static class PerformanceRegistry
	{
		private static readonly Dictionary<int, PerformanceDefinition> Definitions = new Dictionary<int, PerformanceDefinition>();

		internal static void Register(PerformanceDefinition definition)
		{
			Definitions.Add(definition.PrefabHash, definition);
		}

		internal static PerformanceDefinition? Find(int hash)
		{
			if (!Definitions.TryGetValue(hash, out PerformanceDefinition value))
			{
				return null;
			}
			return value;
		}

		internal static void Initialize()
		{
			Register(new PerformanceDefinition("Instruments_Drum", 1.0, (Player player) => new DrumPerformance(player)));
			Register(new PerformanceDefinition("Instruments_Gusli", 0.5, (Player player) => new GusliPerformance(player), usesCameraPitch: true));
			Register(new PerformanceDefinition("Instruments_Horn", null, (Player player) => new HornPerformance(player), usesCameraPitch: true));
			Register(new PerformanceDefinition("Instruments_BowedInstrument", null, (Player player) => new BowedPerformance(player), usesCameraPitch: true, usesCameraTremolo: true));
		}

		internal static void Clear()
		{
			Definitions.Clear();
		}
	}
}
namespace Instruments.Content
{
	[HarmonyPatch(typeof(VisEquipment), "AttachItem")]
	internal static class BowedInstrumentEquipmentPatch
	{
		private static readonly int InstrumentHash = StringExtensionMethods.GetStableHashCode("Instruments_BowedInstrument");

		private static void Postfix(VisEquipment __instance, int itemHash, Transform joint, bool backAttach, GameObject? __result)
		{
			if (!(itemHash != InstrumentHash || backAttach) && !((Object)(object)joint != (Object)(object)__instance.m_rightHand) && __instance.m_isPlayer && Object.op_Implicit((Object)(object)__instance.m_leftHand) && Object.op_Implicit((Object)(object)__result))
			{
				Transform val = __result.transform.Find("model/bow");
				if (Object.op_Implicit((Object)(object)val))
				{
					((Component)val).gameObject.AddComponent<InstrumentBowHandVisual>().Bind(__instance.m_leftHand);
				}
			}
		}
	}
	internal sealed class InstrumentBowHandVisual : MonoBehaviour
	{
		private Transform? hand;

		private float scale;

		private bool performancePose;

		private static readonly Vector3 Grip = new Vector3(0f, 0.04f, 0f);

		private static readonly Quaternion GripRotation = Quaternion.Euler(90f, 0f, 0f) * Quaternion.Euler(0f, 180f, 0f);

		internal void Bind(Transform target)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			hand = target;
			scale = ((Component)this).transform.lossyScale.x;
			LateUpdate();
		}

		internal void SetPerformancePose(Vector3 position, Quaternion rotation)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			performancePose = true;
			((Component)this).transform.SetPositionAndRotation(position, rotation);
		}

		internal void ClearPerformancePose()
		{
			performancePose = false;
			LateUpdate();
		}

		private void LateUpdate()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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)
			if (Object.op_Implicit((Object)(object)hand) && !performancePose)
			{
				Quaternion val = hand.rotation * GripRotation;
				((Component)this).transform.SetPositionAndRotation(hand.position - val * Grip * scale, val);
			}
		}
	}
	internal sealed class InstrumentAssets
	{
		private readonly List<(Mesh Mesh, Material Material)> parts = new List<(Mesh, Material)>();

		private static readonly Dictionary<string, Texture2D> Textures = new Dictionary<string, Texture2D>();

		internal Bounds Bounds { get; private set; }

		internal InstrumentAssets(string model, Shader shader)
		{
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to inval