Decompiled source of Virtuoso v0.3.1

plugins/com.github.mondash.Virtuoso.dll

Decompiled 19 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;
using Virtuoso.Audio;
using Virtuoso.Behaviour;
using Virtuoso.Config;
using Virtuoso.Data;
using Virtuoso.Event;
using Virtuoso.Input;
using Virtuoso.Runtime;
using Virtuoso.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.mondash.Virtuoso")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.1.0")]
[assembly: AssemblyInformationalVersion("0.3.1+3c45e2ed3eef365c1b2beae79cb6154ed4f13559")]
[assembly: AssemblyProduct("com.github.mondash.Virtuoso")]
[assembly: AssemblyTitle("Virtuoso")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Virtuoso
{
	[BepInPlugin("com.github.mondash.Virtuoso", "Virtuoso", "0.3.1")]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony? _harmony;

		public const string Id = "com.github.mondash.Virtuoso";

		internal static ManualLogSource Log { get; private set; }

		public static string Name => "Virtuoso";

		public static string Version => "0.3.1";

		private void Awake()
		{
			//IL_0054: 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_005b: Expected O, but got Unknown
			//IL_0060: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Plugin waking...");
			Log.LogDebug((object)"Loading configuration...");
			BugleConfig.Bind(((BaseUnityPlugin)this).Config);
			Log.LogDebug((object)"Applying harmony patches...");
			Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
			Harmony val2 = val;
			_harmony = val;
			val2.PatchAll();
			Log.LogDebug((object)"Adding runtime components...");
			((Component)this).gameObject.AddComponent<BugleUILoader>();
			Log.LogInfo((object)"Plugin awake!");
		}

		private void OnDestroy()
		{
			Log.LogInfo((object)"Plugin destroying...");
			Log.LogDebug((object)"Disconnecting custom bugle behaviour...");
			BugleBehaviour.DisconnectAll();
			Log.LogDebug((object)"Removing harmony patches...");
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Log.LogInfo((object)"Plugin destroyed!");
		}
	}
}
namespace Virtuoso.UI
{
	internal class BugleNote
	{
		private static readonly string[] NoteNames = new string[12]
		{
			"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A",
			"A#", "B"
		};

		public static string FromSemitone(float semitone)
		{
			int num = Mathf.RoundToInt(semitone) + 69;
			num = Mathf.Clamp(num, 0, 127);
			int num2 = num / 12 - 1;
			int num3 = num % 12;
			return $"{NoteNames[num3]}{num2}";
		}
	}
	internal class BugleUI : MonoBehaviour
	{
		private static BugleUI? _instance;

		private static bool _visible = true;

		private static KeyCode ToggleUIKey => BugleConfig.ToggleUIKey.Value;

		private static bool IsPaused => GUIManager.instance.pauseMenu.activeSelf;

		public static void Initialize(GameObject gameObject)
		{
			if (!Object.op_Implicit((Object)(object)_instance))
			{
				_instance = gameObject.AddComponent<BugleUI>();
				Plugin.Log.LogInfo((object)"BugleUI initialized");
			}
		}

		public static void DestroyInstance()
		{
			if (Object.op_Implicit((Object)(object)_instance))
			{
				Object.Destroy((Object)(object)_instance);
				_instance = null;
				Plugin.Log.LogInfo((object)"BugleUI destroyed");
			}
		}

		private void Update()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(ToggleUIKey))
			{
				_visible = !_visible;
			}
		}

		private void OnGUI()
		{
			if (!_visible || IsPaused)
			{
				return;
			}
			Character localCharacter = Character.localCharacter;
			if (!Object.op_Implicit((Object)(object)localCharacter))
			{
				return;
			}
			Item currentItem = localCharacter.data.currentItem;
			BugleSFX val = default(BugleSFX);
			if (!Object.op_Implicit((Object)(object)currentItem) || !((Component)currentItem).TryGetComponent<BugleSFX>(ref val))
			{
				return;
			}
			Camera main = Camera.main;
			if (!Object.op_Implicit((Object)(object)main))
			{
				return;
			}
			float maxAngle = BuglePartial.MaxAngle;
			int partials = BuglePartial.Partials;
			int num = partials - 1;
			float y = localCharacter.data.lookValues.y;
			float fieldOfView = main.fieldOfView;
			float num2 = fieldOfView * 0.5f * (MathF.PI / 180f);
			float num3 = Screen.height;
			float num4 = Screen.width;
			for (int i = 1; i <= num; i++)
			{
				float num5 = (float)i / (float)partials;
				float num6 = Mathf.Lerp(0f - maxAngle, maxAngle, num5);
				float num7 = num6 - y;
				float num8 = num7 * (MathF.PI / 180f);
				if (!(Mathf.Abs(num8) > num2))
				{
					float num9 = 0.5f - Mathf.Tan(num8) / Mathf.Tan(num2);
					float y2 = num9 * num3;
					float x = (num4 - 20f) * 0.5f;
					DrawLine(x, y2, 20f);
				}
			}
		}

		private static void DrawLine(float x, float y, float width)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			Color color = GUI.color;
			GUI.color = Color.white;
			GUI.DrawTexture(new Rect(x, y, width, 5f), (Texture)(object)Texture2D.whiteTexture);
			GUI.color = color;
		}
	}
}
namespace Virtuoso.Runtime
{
	internal class BugleUILoader : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <LoadUI>d__3 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public BugleUILoader <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Expected O, but got Unknown
				int num = <>1__state;
				BugleUILoader bugleUILoader = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					Plugin.Log.LogInfo((object)"Bugle UI loader routine started");
					<>2__current = (object)new WaitUntil((Func<bool>)bugleUILoader.ReadyOrDisabled);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (((Behaviour)bugleUILoader).isActiveAndEnabled)
					{
						BugleUI.Initialize(((Component)bugleUILoader).gameObject);
					}
					Plugin.Log.LogInfo((object)"Bugle UI loader routine finished");
					return false;
				}
			}

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

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

		private void OnEnable()
		{
			((MonoBehaviour)this).StartCoroutine(LoadUI());
		}

		private void OnDisable()
		{
			BugleUI.DestroyInstance();
		}

		private bool ReadyOrDisabled()
		{
			if (!Object.op_Implicit((Object)(object)Character.localCharacter))
			{
				return !((Behaviour)this).isActiveAndEnabled;
			}
			return true;
		}

		[IteratorStateMachine(typeof(<LoadUI>d__3))]
		private IEnumerator LoadUI()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadUI>d__3(0)
			{
				<>4__this = this
			};
		}
	}
}
namespace Virtuoso.Patching
{
	[HarmonyPatch(typeof(BugleSFX))]
	internal static class BugleSFX_Patch
	{
		private static void SetTooting(BugleSFX instance)
		{
			((object)instance).GetType().GetField("t", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(instance, true);
		}

		[HarmonyPatch("RPC_StartToot")]
		[HarmonyPostfix]
		private static void RPC_StartToot_Postfix(BugleSFX __instance, int clip, float pitch)
		{
			SetTooting(__instance);
			BugleBehaviour.Connect(__instance);
			BugleHub.RaiseTootStarted(__instance);
		}

		[HarmonyPatch("RPC_EndToot")]
		[HarmonyPostfix]
		private static void RPC_EndToot_Postfix(BugleSFX __instance)
		{
			BugleHub.RaiseTootStopped(__instance);
		}
	}
}
namespace Virtuoso.Input
{
	public static class BugleBend
	{
		private static float? _initialAngle;

		private static float MaxAngle => BugleConfig.MaxBendAngle.Value;

		private static float MaxSemitones => BugleConfig.MaxBendSemitones.Value;

		private static float CurrentAngle
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)Character.localCharacter))
				{
					return 0f;
				}
				return Character.localCharacter.data.lookValues.x;
			}
		}

		public static float Semitones()
		{
			if (!_initialAngle.HasValue)
			{
				return 0f;
			}
			float num = Mathf.DeltaAngle(_initialAngle.Value, CurrentAngle);
			float num2 = Mathf.Clamp(num / MaxAngle, -1f, 1f);
			return num2 * MaxSemitones;
		}

		public static void Reset()
		{
			_initialAngle = null;
		}

		public static void SetInitialAngle()
		{
			_initialAngle = CurrentAngle;
		}
	}
	internal static class BuglePartial
	{
		private const float SmoothStrength = 300f;

		private static readonly float[] RealisticHarmonics = new float[7] { 12f, 19.02f, 24f, 27.86f, 31.02f, 33.69f, 36f };

		private static readonly float[] IdealHarmonics = new float[7] { 12f, 19f, 24f, 28f, 31f, 34f, 36f };

		private static float? _smoothAngle;

		private static float SmoothSpeed => 300f * BugleConfig.HarmonicSmoothMult.Value;

		public static float MaxAngle => BugleConfig.MaxPartialAngle.Value;

		private static bool Ideal => BugleConfig.UseIdealHarmonics.Value;

		private static float[] Harmonics
		{
			get
			{
				if (!Ideal)
				{
					return RealisticHarmonics;
				}
				return IdealHarmonics;
			}
		}

		public static int Partials => Harmonics.Length;

		private static float CurrentAngle
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)Character.localCharacter))
				{
					return 0f;
				}
				return Character.localCharacter.data.lookValues.y;
			}
		}

		public static float Semitones()
		{
			float num = _smoothAngle ?? CurrentAngle;
			float num2 = Mathf.InverseLerp(0f - MaxAngle, MaxAngle, num);
			int num3 = Mathf.FloorToInt(num2 * (float)Partials);
			int num4 = Mathf.Clamp(num3, 0, Partials - 1);
			return Harmonics[num4];
		}

		public static void Reset()
		{
			_smoothAngle = null;
		}

		public static void Smooth(float delta)
		{
			_smoothAngle = (_smoothAngle.HasValue ? Mathf.MoveTowards(_smoothAngle.Value, CurrentAngle, delta * SmoothSpeed) : CurrentAngle);
		}
	}
	internal static class TrumpetValves
	{
		private static readonly Dictionary<int, float> RealisticOffsets = new Dictionary<int, float>
		{
			[0] = -0f,
			[2] = -1f,
			[1] = -2f,
			[4] = -2.95f,
			[3] = -3f,
			[6] = -4f,
			[5] = -5.35f,
			[7] = -6.75f
		};

		private static readonly Dictionary<int, float> IdealOffsets = new Dictionary<int, float>
		{
			[0] = -0f,
			[2] = -1f,
			[1] = -2f,
			[4] = -3f,
			[3] = -3f,
			[6] = -4f,
			[5] = -5f,
			[7] = -6f
		};

		private static bool Ideal => BugleConfig.UseIdealValves.Value;

		private static KeyCode Valve1Key => BugleConfig.Valve1Key.Value;

		private static KeyCode Valve2Key => BugleConfig.Valve2Key.Value;

		private static KeyCode Valve3Key => BugleConfig.Valve3Key.Value;

		private static Dictionary<int, float> Offsets
		{
			get
			{
				if (!Ideal)
				{
					return RealisticOffsets;
				}
				return IdealOffsets;
			}
		}

		public static float Semitones()
		{
			//IL_0002: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			if (Input.GetKey(Valve1Key))
			{
				num |= 1;
			}
			if (Input.GetKey(Valve2Key))
			{
				num |= 2;
			}
			if (Input.GetKey(Valve3Key))
			{
				num |= 4;
			}
			return Offsets.GetValueOrDefault(num, 0f);
		}
	}
}
namespace Virtuoso.Event
{
	internal sealed class BugleHub
	{
		private readonly HashSet<IBugleListener> _listeners = new HashSet<IBugleListener>();

		private static readonly ConditionalWeakTable<BugleSFX, BugleHub> Registry = new ConditionalWeakTable<BugleSFX, BugleHub>();

		private event Action? TootStarted;

		private event Action? TootStopped;

		private event Action<BuglePitchFrame>? Frame;

		public Action Subscribe(IBugleListener listener)
		{
			IBugleListener listener2 = listener;
			if (!_listeners.Add(listener2))
			{
				return delegate
				{
				};
			}
			TootStarted += listener2.HandleTootStarted;
			TootStopped += listener2.HandleTootStopped;
			Frame += listener2.HandleFrame;
			return delegate
			{
				Unsubscribe(listener2);
			};
		}

		private void Unsubscribe(IBugleListener listener)
		{
			if (_listeners.Remove(listener))
			{
				TootStarted -= listener.HandleTootStarted;
				TootStopped -= listener.HandleTootStopped;
				Frame -= listener.HandleFrame;
			}
		}

		private void RaiseTootStarted()
		{
			this.TootStarted?.Invoke();
		}

		private void RaiseTootStopped()
		{
			this.TootStopped?.Invoke();
		}

		public void RaiseFrame(BuglePitchFrame frame)
		{
			this.Frame?.Invoke(frame);
		}

		public static BugleHub Get(BugleSFX sfx)
		{
			return Registry.GetValue(sfx, (BugleSFX _) => new BugleHub());
		}

		public static void RaiseTootStarted(BugleSFX sfx)
		{
			Get(sfx).RaiseTootStarted();
		}

		public static void RaiseTootStopped(BugleSFX sfx)
		{
			Get(sfx).RaiseTootStopped();
		}
	}
	internal interface IBugleListener
	{
		void HandleTootStarted();

		void HandleTootStopped();

		void HandleFrame(BuglePitchFrame frame);
	}
}
namespace Virtuoso.Data
{
	internal readonly struct BuglePitchFrame
	{
		public readonly float Valves;

		public readonly float Partial;

		public readonly float Bend;

		public object Data => new object[3] { Valves, Partial, Bend };

		public float Semitone => Valves + Partial + Bend;

		public float Pitch => Mathf.Pow(2f, Semitone / 12f);

		public BuglePitchFrame(float valves, float partial, float bend)
		{
			Valves = valves;
			Partial = partial;
			Bend = bend;
		}

		public BuglePitchFrame()
			: this(TrumpetValves.Semitones(), BuglePartial.Semitones(), BugleBend.Semitones())
		{
		}

		public BuglePitchFrame(object[] data)
			: this((float)data[0], (float)data[1], (float)data[2])
		{
		}

		public bool Approximately(BuglePitchFrame other, float bendThreshold = 0.05f)
		{
			if (Mathf.Approximately(Valves, other.Valves) && Mathf.Approximately(Partial, other.Partial))
			{
				return Mathf.Abs(Bend - other.Bend) < bendThreshold;
			}
			return false;
		}

		public float Smooth(float current, float delta, float speed = 100f)
		{
			return Mathf.MoveTowards(current, Pitch, delta * speed);
		}
	}
}
namespace Virtuoso.Config
{
	internal static class BugleConfig
	{
		public static ConfigEntry<float> MaxBendAngle;

		public static ConfigEntry<float> MaxBendSemitones;

		public static ConfigEntry<bool> UseIdealHarmonics;

		public static ConfigEntry<float> MaxPartialAngle;

		public static ConfigEntry<float> HarmonicSmoothMult;

		public static ConfigEntry<float> PitchSmoothMult;

		public static ConfigEntry<float> SyncInterval;

		public static ConfigEntry<KeyCode> ToggleUIKey;

		public static ConfigEntry<bool> UseIdealValves;

		public static ConfigEntry<KeyCode> Valve1Key;

		public static ConfigEntry<KeyCode> Valve2Key;

		public static ConfigEntry<KeyCode> Valve3Key;

		public static void Bind(ConfigFile config)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			MaxBendAngle = config.Bind<float>("Bend", "MaxBendAngle", 80f, new ConfigDescription("Maximum left/right view angle (in degrees) allowed to bend pitch", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 170f), Array.Empty<object>()));
			MaxBendSemitones = config.Bind<float>("Bend", "MaxBendSemitones", 2f, new ConfigDescription("Maximum pitch bending amount in semitones", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 12f), Array.Empty<object>()));
			UseIdealHarmonics = config.Bind<bool>("Harmonics", "UseIdealHarmonics", true, "If true, uses mathematically ideal harmonics");
			MaxPartialAngle = config.Bind<float>("Harmonics", "MaxPartialAngle", 80f, new ConfigDescription("Vertical angle span (in degrees) allocated to partial selection", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 90f), Array.Empty<object>()));
			HarmonicSmoothMult = config.Bind<float>("Smoothing", "HarmonicSmoothMult", 1f, new ConfigDescription("How quickly harmonic partials react, higher values reacting quicker", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.125f, 8f), Array.Empty<object>()));
			PitchSmoothMult = config.Bind<float>("Smoothing", "PitchSmoothMult", 1f, new ConfigDescription("How quickly pitch changes are smoothed, higher values smoothing quicker", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.125f, 8f), Array.Empty<object>()));
			SyncInterval = config.Bind<float>("Sync", "SyncInterval", 0.1f, new ConfigDescription("Time (in seconds) between bugle sync frames", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			ToggleUIKey = config.Bind<KeyCode>("UI", "ToggleUIKey", (KeyCode)117, "Keyboard shortcut to toggle the bugle UI visibility");
			UseIdealValves = config.Bind<bool>("Valves", "UseIdealValves", true, "If true, uses mathematically ideal tuning offsets for valve combinations");
			Valve1Key = config.Bind<KeyCode>("Valves", "Valve1Key", (KeyCode)122, "Keyboard key for Valve 1");
			Valve2Key = config.Bind<KeyCode>("Valves", "Valve2Key", (KeyCode)120, "Keyboard key for Valve 2");
			Valve3Key = config.Bind<KeyCode>("Valves", "Valve3Key", (KeyCode)99, "Keyboard key for Valve 3");
		}
	}
}
namespace Virtuoso.Behaviour
{
	[DefaultExecutionOrder(2)]
	internal class BugleAudio : BugleBehaviour
	{
		[CompilerGenerated]
		private sealed class <StopRoutine>d__11 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public BugleAudio <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				int num = <>1__state;
				BugleAudio bugleAudio = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitWhile((Func<bool>)bugleAudio.SourceActive);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (Object.op_Implicit((Object)(object)bugleAudio.Source) && bugleAudio.Source.isPlaying)
					{
						bugleAudio.Source.Stop();
					}
					bugleAudio._stopRoutine = null;
					return false;
				}
			}

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

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

		private const float VolumeEpsilon = 0.001f;

		private const float SmoothStrength = 100f;

		private bool _newToot;

		private BuglePitchFrame _frame;

		private Coroutine? _stopRoutine;

		private static float SmoothSpeed => 100f * BugleConfig.PitchSmoothMult.Value;

		private AudioSource Source => base.Sfx.buglePlayer;

		protected override bool ShouldUpdate
		{
			get
			{
				if (!base.ShouldUpdate)
				{
					return Source.isPlaying;
				}
				return true;
			}
		}

		protected override void OnTootStarted()
		{
			Source.clip = BugleClip.Pinched();
			Source.loop = true;
			_newToot = true;
		}

		private bool SourceActive()
		{
			if (((Behaviour)this).isActiveAndEnabled)
			{
				AudioSource source = Source;
				if (source != null && source.isPlaying)
				{
					return source.volume > 0.001f;
				}
				return false;
			}
			return false;
		}

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

		protected override void OnTootStopped()
		{
			if (_stopRoutine == null)
			{
				_stopRoutine = ((MonoBehaviour)this).StartCoroutine(StopRoutine());
			}
		}

		protected override void OnFrame(BuglePitchFrame frame)
		{
			_frame = frame;
		}

		private bool Pause()
		{
			if (Time.timeScale != 0f)
			{
				return false;
			}
			if (Source.isPlaying)
			{
				Source.Stop();
			}
			return true;
		}

		protected override void OnUpdate()
		{
			if (!Pause())
			{
				Source.pitch = (_newToot ? _frame.Pitch : _frame.Smooth(Source.pitch, Time.deltaTime, SmoothSpeed));
				if (!Source.isPlaying)
				{
					Source.Play();
				}
				_newToot = false;
			}
		}
	}
	[RequireComponent(typeof(BugleSFX))]
	internal abstract class BugleBehaviour : MonoBehaviour, IBugleListener
	{
		private Action? _unsubscribe;

		private bool _implementsOnTootStarted;

		private bool _implementsOnTootStopped;

		private bool _implementsOnFrame;

		private bool _implementsOnUpdate;

		protected string Name { get; private set; }

		protected BugleSFX Sfx { get; private set; }

		protected BugleHub Hub { get; private set; }

		protected bool IsMine => ((MonoBehaviourPun)Sfx).photonView.IsMine;

		protected int ViewID => ((MonoBehaviourPun)Sfx).photonView.ViewID;

		protected virtual bool ShouldHandleTootStarted => true;

		protected virtual bool ShouldHandleTootStopped => true;

		protected virtual bool ShouldHandleFrame => true;

		protected virtual bool ShouldUpdate
		{
			get
			{
				if (Sfx.hold)
				{
					return Time.timeScale > 0f;
				}
				return false;
			}
		}

		private static T Connect<T>(BugleSFX sfx) where T : BugleBehaviour
		{
			T result = default(T);
			if (!((Component)sfx).TryGetComponent<T>(ref result))
			{
				return ((Component)sfx).gameObject.AddComponent<T>();
			}
			return result;
		}

		public static void Connect(BugleSFX sfx)
		{
			Connect<BugleInput>(sfx);
			Connect<BugleAudio>(sfx);
			Connect<BugleSync>(sfx);
			Connect<BugleDrop>(sfx);
		}

		protected static void Disconnect(BugleSFX sfx)
		{
			((Component)sfx).GetComponents<BugleBehaviour>().ToList().ForEach((Action<BugleBehaviour>)Object.Destroy);
		}

		public static void DisconnectAll()
		{
			Object.FindObjectsByType<BugleBehaviour>((FindObjectsSortMode)0).ToList().ForEach((Action<BugleBehaviour>)Object.Destroy);
		}

		private static bool ImplementsHandler(Type type, string name)
		{
			MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method != null)
			{
				return method.DeclaringType != typeof(BugleBehaviour);
			}
			return false;
		}

		private void Awake()
		{
			Type type = ((object)this).GetType();
			_implementsOnTootStarted = ImplementsHandler(type, "OnTootStarted");
			_implementsOnTootStopped = ImplementsHandler(type, "OnTootStopped");
			_implementsOnFrame = ImplementsHandler(type, "OnFrame");
			_implementsOnUpdate = ImplementsHandler(type, "OnUpdate");
			Name = type.Name;
			Sfx = ((Component)this).GetComponent<BugleSFX>();
			Hub = BugleHub.Get(Sfx);
		}

		protected virtual void OnEnable()
		{
			if (_unsubscribe == null)
			{
				_unsubscribe = Hub.Subscribe(this);
			}
			Plugin.Log.LogInfo((object)$"Enabled {Name} for view {ViewID}");
		}

		protected virtual void OnDisable()
		{
			_unsubscribe?.Invoke();
			_unsubscribe = null;
			Plugin.Log.LogInfo((object)$"Disabled {Name} for view {ViewID}");
		}

		protected virtual void OnTootStarted()
		{
		}

		protected virtual void OnTootStopped()
		{
		}

		protected virtual void OnFrame(BuglePitchFrame f)
		{
		}

		protected virtual void OnUpdate()
		{
		}

		void IBugleListener.HandleTootStarted()
		{
			if (_implementsOnTootStarted && ShouldHandleTootStarted)
			{
				Plugin.Log.LogDebug((object)$"{Name} handling toot start for view {ViewID}");
				OnTootStarted();
			}
		}

		void IBugleListener.HandleTootStopped()
		{
			if (_implementsOnTootStopped && ShouldHandleTootStopped)
			{
				Plugin.Log.LogDebug((object)$"{Name} handling toot stop for view {ViewID}");
				OnTootStopped();
			}
		}

		void IBugleListener.HandleFrame(BuglePitchFrame frame)
		{
			if (_implementsOnFrame && ShouldHandleFrame)
			{
				Plugin.Log.LogDebug((object)$"{Name} handling frame for view {ViewID}");
				OnFrame(frame);
			}
		}

		private void Update()
		{
			if (_implementsOnUpdate && ShouldUpdate)
			{
				Plugin.Log.LogDebug((object)$"{Name} handling update for view {ViewID}");
				OnUpdate();
			}
		}
	}
	[DefaultExecutionOrder(4)]
	internal class BugleDrop : BugleBehaviour
	{
		protected override void OnEnable()
		{
			Item item = base.Sfx.item;
			item.OnStateChange = (Action<ItemState>)Delegate.Combine(item.OnStateChange, new Action<ItemState>(DisconnectOnDrop));
			base.OnEnable();
		}

		protected override void OnDisable()
		{
			Item item = base.Sfx.item;
			item.OnStateChange = (Action<ItemState>)Delegate.Remove(item.OnStateChange, new Action<ItemState>(DisconnectOnDrop));
			base.OnDisable();
		}

		private void DisconnectOnDrop(ItemState state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)state != 1)
			{
				BugleBehaviour.Disconnect(base.Sfx);
			}
		}
	}
	[DefaultExecutionOrder(1)]
	internal class BugleInput : BugleBehaviour
	{
		protected override bool ShouldHandleTootStarted
		{
			get
			{
				if (base.ShouldHandleTootStarted)
				{
					return base.IsMine;
				}
				return false;
			}
		}

		protected override bool ShouldHandleTootStopped
		{
			get
			{
				if (base.ShouldHandleTootStopped)
				{
					return base.IsMine;
				}
				return false;
			}
		}

		protected override bool ShouldUpdate
		{
			get
			{
				if (base.ShouldUpdate)
				{
					return base.IsMine;
				}
				return false;
			}
		}

		protected override void OnTootStarted()
		{
			BugleBend.SetInitialAngle();
			base.Hub.RaiseFrame(new BuglePitchFrame());
		}

		protected override void OnTootStopped()
		{
			BugleBend.Reset();
			BuglePartial.Reset();
		}

		protected override void OnUpdate()
		{
			BuglePartial.Smooth(Time.deltaTime);
			base.Hub.RaiseFrame(new BuglePitchFrame());
		}
	}
	[DefaultExecutionOrder(3)]
	internal class BugleSync : BugleBehaviour
	{
		private float _since;

		private BuglePitchFrame _lastLocal;

		private BuglePitchFrame _lastSent;

		private static float SyncInterval => BugleConfig.SyncInterval.Value;

		protected override bool ShouldHandleFrame
		{
			get
			{
				if (base.ShouldHandleFrame)
				{
					return base.IsMine;
				}
				return false;
			}
		}

		protected override bool ShouldUpdate
		{
			get
			{
				if (base.ShouldUpdate)
				{
					return base.IsMine;
				}
				return false;
			}
		}

		protected override void OnFrame(BuglePitchFrame frame)
		{
			_lastLocal = frame;
		}

		protected override void OnUpdate()
		{
			_since += Time.deltaTime;
			if (!(_since < SyncInterval) || !_lastSent.Approximately(_lastLocal))
			{
				SyncBuglePitchFrame(_lastLocal);
			}
		}

		private void SyncBuglePitchFrame(BuglePitchFrame frame)
		{
			((MonoBehaviourPun)base.Sfx).photonView.RPC("RPC_SyncBuglePitchFrame", (RpcTarget)1, new object[1] { frame.Data });
			Plugin.Log.LogDebug((object)$"Sent frame sync from view {base.ViewID}");
			_lastSent = frame;
			_since = 0f;
		}

		[PunRPC]
		private void RPC_SyncBuglePitchFrame(object[] data, PhotonMessageInfo info)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogDebug((object)$"Received frame sync from actor {info.Sender.ActorNumber}");
			base.Hub.RaiseFrame(new BuglePitchFrame(data));
		}
	}
}
namespace Virtuoso.Audio
{
	internal static class BugleClip
	{
		private const float Frequency = 58.27f;

		private static AudioClip? _clip;

		public static AudioClip Brass()
		{
			if (Object.op_Implicit((Object)(object)_clip))
			{
				return _clip;
			}
			Plugin.Log.LogInfo((object)"Generating bugle brass clip");
			float[] array = new float[7568];
			for (int i = 0; i < 7568; i++)
			{
				float num = 366.12122f * (float)i / 44100f;
				float num2 = (Mathf.Sin(num) + 0.7f * Mathf.Sin(2f * num) + 0.5f * Mathf.Sin(3f * num) + 0.4f * Mathf.Sin(4f * num) + 0.3f * Mathf.Sin(5f * num) + 0.2f * Mathf.Sin(6f * num) + 0.15f * Mathf.Sin(7f * num) + 0.1f * Mathf.Sin(8f * num)) * 0.2f;
				float num3 = 0.02f * (Random.value - 0.5f);
				array[i] = num2 + num3;
			}
			_clip = AudioClip.Create("BugleBrassClip", 7568, 1, 44100, false);
			_clip.SetData(array, 0);
			return _clip;
		}

		public static AudioClip Brassier()
		{
			if (Object.op_Implicit((Object)(object)_clip))
			{
				return _clip;
			}
			Plugin.Log.LogInfo((object)"Generating brassier clip");
			float[] array = new float[7568];
			for (int i = 0; i < 7568; i++)
			{
				float num = 366.12122f * (float)i / 44100f;
				float num2 = 1f * Mathf.Sin(num) + 0.8f * Mathf.Sin(2f * num) + 1.2f * Mathf.Sin(3f * num) + 0.6f * Mathf.Sin(4f * num) + 0.4f * Mathf.Sin(5f * num) + 0.8f * Mathf.Sin(6f * num) + 0.2f * Mathf.Sin(7f * num) + 0.1f * Mathf.Sin(8f * num);
				num2 *= 0.15f;
				float num3 = 0.01f * (Random.value - 0.5f);
				array[i] = num2 + num3;
			}
			_clip = AudioClip.Create("BugleBrassierClip", 7568, 1, 44100, false);
			_clip.SetData(array, 0);
			return _clip;
		}

		public static AudioClip Sawtooth()
		{
			if (Object.op_Implicit((Object)(object)_clip))
			{
				return _clip;
			}
			Plugin.Log.LogInfo((object)"Generating sawtooth clip");
			float[] array = new float[7568];
			for (int i = 0; i < 7568; i++)
			{
				float num = 366.12122f * (float)i / 44100f;
				float num2 = 366.85345f * (float)i / 44100f;
				float num3 = 0f;
				for (int j = 1; j <= 20; j++)
				{
					float num4 = 1f / (float)j * Mathf.Exp(-0.05f * (float)j);
					if (j >= 5 && j <= 7)
					{
						num4 *= 1.5f;
					}
					float num5 = (float)i / 7568f;
					float num6 = 1f + 0.05f * Mathf.Sin(MathF.PI * 2f * (float)j * num5);
					num3 += num4 * num6 * (Mathf.Sin((float)j * num) + 0.3f * Mathf.Sin((float)j * num2));
				}
				num3 *= 0.2f;
				float num7 = 0.01f * (Random.value - 0.5f);
				array[i] = num3 + num7;
			}
			_clip = AudioClip.Create("BugleSawtoothClip", 7568, 1, 44100, false);
			_clip.SetData(array, 0);
			return _clip;
		}

		public static AudioClip Pinched()
		{
			if (Object.op_Implicit((Object)(object)_clip))
			{
				return _clip;
			}
			Plugin.Log.LogInfo((object)"Generating fixed pinched brass clip");
			float[] array = new float[7568];
			for (int i = 0; i < 7568; i++)
			{
				float num = (float)i / 44100f;
				float num2 = 366.12122f * num;
				float num3 = 0f;
				for (int j = 1; j <= 20; j++)
				{
					float num4 = num2 * (float)j;
					float num5 = Mathf.Sin(num4);
					float num6 = Mathf.Sign(num5) * Mathf.Pow(Mathf.Abs(num5), 1.1f);
					float num7 = 1f / (float)j * Mathf.Exp(-0.045f * (float)j);
					if (j >= 5 && j <= 7)
					{
						num7 *= 1.5f;
					}
					num3 += num7 * num6;
				}
				num3 += 0.15f * Mathf.Pow(num3, 3f);
				float num8 = 0.005f * (Random.value - 0.5f);
				array[i] = num3 * 0.3f + num8;
			}
			_clip = AudioClip.Create("BuglePinchedClip", 7568, 1, 44100, false);
			_clip.SetData(array, 0);
			return _clip;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}