Decompiled source of Piano v1.0.1

PianoHints.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.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;
		}
	}
}
[BepInPlugin("com.igor.repo.pianohints", "Piano Hints", "1.0.0")]
public class PianoHintsPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.igor.repo.pianohints";

	public const string PluginName = "Piano Hints";

	public const string PluginVersion = "1.0.0";

	internal static ManualLogSource LogS;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<KeyboardShortcut> ToggleKey;

	internal static ConfigEntry<float> HeightOffset;

	internal static ConfigEntry<float> SquareSize;

	internal static ConfigEntry<float> KeyThickness;

	internal static ConfigEntry<float> KeyLength;

	internal static ConfigEntry<int> FontSize;

	internal static ConfigEntry<int> ColorCycle;

	internal static ConfigEntry<bool> Billboard;

	internal static ConfigEntry<float> MaxDrawDistance;

	internal static ConfigEntry<PianoLabelMode> LabelMode;

	internal static ConfigEntry<string> NoteNamesCSV;

	internal static ConfigEntry<int> NoteRootIndex;

	internal static ConfigEntry<int> BaseOctave;

	internal static ConfigEntry<float> LabelRotX;

	internal static ConfigEntry<float> LabelRotY;

	internal static ConfigEntry<float> LabelRotZ;

	internal static ConfigEntry<float> LabelLift;

	internal static ConfigEntry<bool> CompactSemitoneView;

	internal static ConfigEntry<float> KeySaturation;

	internal static ConfigEntry<float> KeyValue;

	internal static ConfigEntry<float> KeyAlpha;

	internal static ConfigEntry<KeyboardShortcut> TeacherStartKey;

	internal static ConfigEntry<int> TeacherStartKeyIndex;

	internal static ConfigEntry<string> TeacherSong;

	internal static ConfigEntry<string> TeacherHighlightColor;

	internal static ConfigEntry<string> TeacherScripts;

	private static Dictionary<string, List<int>> _songScripts = new Dictionary<string, List<int>>(StringComparer.OrdinalIgnoreCase);

	private void Awake()
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0326: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
		LogS = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turn the piano hint overlay on/off.");
		ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ToggleKey", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Toggle piano hints visibility.");
		HeightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "HeightOffset", 0.02f, "Vertical offset above the key line (meters).");
		SquareSize = ((BaseUnityPlugin)this).Config.Bind<float>("_Deprecated", "SquareSize", 0.08f, "Deprecated; use KeyThickness/KeyLength.");
		KeyThickness = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "KeyThickness", 0.025f, "Thickness of each key hint along the key row (meters).");
		KeyLength = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "KeyLength", 0.4f, "Length of each key hint into the piano (meters).");
		FontSize = ((BaseUnityPlugin)this).Config.Bind<int>("Visual", "FontSize", 64, "Font size for labels (TextMesh.fontSize).");
		ColorCycle = ((BaseUnityPlugin)this).Config.Bind<int>("Visual", "ColorCycle", 12, "Number of distinct colors to cycle through for keys.");
		Billboard = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "Billboard", true, "If true, hints face the main camera.");
		MaxDrawDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "MaxDrawDistance", 60f, "Do not show hints when the piano is farther than this (meters). 0 = always show.");
		LabelMode = ((BaseUnityPlugin)this).Config.Bind<PianoLabelMode>("Labels", "LabelMode", PianoLabelMode.None, "Label mode: None, Index, Note, NoteOctave, ClipName.");
		NoteNamesCSV = ((BaseUnityPlugin)this).Config.Bind<string>("Labels", "NoteNamesCSV", "C,C#,D,D#,E,F,F#,G,G#,A,A#,B", "Comma-separated base note names for one octave.");
		NoteRootIndex = ((BaseUnityPlugin)this).Config.Bind<int>("Labels", "NoteRootIndex", 0, "Index in NoteNames for the first base sample (0=C,1=C#,...).");
		BaseOctave = ((BaseUnityPlugin)this).Config.Bind<int>("Labels", "BaseOctave", 4, "Octave number for the first base sample (used by NoteOctave mode).");
		LabelRotX = ((BaseUnityPlugin)this).Config.Bind<float>("Labels", "LabelRotX", 0f, "Extra local X rotation applied to label text (degrees).");
		LabelRotY = ((BaseUnityPlugin)this).Config.Bind<float>("Labels", "LabelRotY", 0f, "Extra local Y rotation applied to label text (degrees).");
		LabelRotZ = ((BaseUnityPlugin)this).Config.Bind<float>("Labels", "LabelRotZ", 0f, "Extra local Z rotation applied to label text (degrees).");
		LabelLift = ((BaseUnityPlugin)this).Config.Bind<float>("Labels", "LabelLift", 0.003f, "Separation from key surface along key normal (meters). Helps avoid z-fighting.");
		CompactSemitoneView = ((BaseUnityPlugin)this).Config.Bind<bool>("_Deprecated", "CompactSemitoneView", false, "Deprecated; previously drew one bar per semitone group.");
		KeySaturation = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "KeySaturation", 0.5f, "Saturation (0..1) for key colors.");
		KeyValue = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "KeyValue", 0.8f, "Value/Brightness (0..1) for key colors.");
		KeyAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "KeyAlpha", 0.45f, "Alpha for key colors.");
		TeacherStartKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Teacher", "StartHotkey", new KeyboardShortcut((KeyCode)111, Array.Empty<KeyCode>()), "Press to start/stop the song helper.");
		TeacherStartKeyIndex = ((BaseUnityPlugin)this).Config.Bind<int>("Teacher", "StartKeyIndex", 0, "Absolute key index to use as the song's first note (S). 0 = beginning of keyboard.");
		TeacherSong = ((BaseUnityPlugin)this).Config.Bind<string>("Teacher", "Song", "happybirthday", "Default song id to use.");
		TeacherHighlightColor = ((BaseUnityPlugin)this).Config.Bind<string>("Teacher", "HighlightColor", "#FFD200FF", "RGBA hex for highlight color, e.g. #FFD200FF.");
		TeacherScripts = ((BaseUnityPlugin)this).Config.Bind<string>("Teacher", "Scripts", "birthday: 55,55,57,55,60,59,55,55,57,55,62,60; sunshine: 60,60,62,64,64,64,62,64,60,60,60,62,64,65,69,69,67,65,64,60,62,64,65,69,69,67,65,64,60,60,62,64,64,62,62,64,60; smoke: 19,22,24,19,22,25,24,19,22,24,22,19; elise: 64,63,64,63,64,59,62,60,57,48,52,57,59,52,56,59,60; korobeiniki: 64,58,60,62,60,58,56,56,60,64,62,60,58,60,62,64,60,56,56", "Song scripts. Format: name: comma-separated integer offsets per note; multiple lines or ';' separated pairs allowed.");
		try
		{
			ParseScripts(TeacherScripts.Value);
		}
		catch
		{
		}
		try
		{
			new Harmony("com.igor.repo.pianohints").PatchAll(typeof(PianoHintsPlugin).Assembly);
		}
		catch (Exception ex)
		{
			ManualLogSource logS = LogS;
			if (logS != null)
			{
				logS.LogWarning((object)("Harmony patch failed: " + ex.Message));
			}
		}
		BuildOrAttachHost();
	}

	private void Update()
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		KeyboardShortcut value = ToggleKey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			Enabled.Value = !Enabled.Value;
			ManualLogSource logS = LogS;
			if (logS != null)
			{
				logS.LogInfo((object)string.Format("[{0}] Enabled = {1}", "Piano Hints", Enabled.Value));
			}
			PianoHintsOverlay[] array = Object.FindObjectsOfType<PianoHintsOverlay>(true);
			for (int i = 0; i < array.Length; i++)
			{
				array[i].ApplyVisibility(Enabled.Value);
			}
		}
	}

	private void BuildOrAttachHost()
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		GameObject val = GameObject.Find("PianoHintsHost (BepInEx)");
		if ((Object)(object)val == (Object)null)
		{
			val = new GameObject("PianoHintsHost (BepInEx)");
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).hideFlags = (HideFlags)61;
			ManualLogSource logS = LogS;
			if (logS != null)
			{
				logS.LogInfo((object)"Created persistent PianoHints host GameObject.");
			}
		}
		if ((Object)(object)val.GetComponent<PianoHintsSweeper>() == (Object)null)
		{
			val.AddComponent<PianoHintsSweeper>();
			ManualLogSource logS2 = LogS;
			if (logS2 != null)
			{
				logS2.LogInfo((object)"Attached PianoHintsSweeper to host.");
			}
		}
	}

	private static void ParseScripts(string scripts)
	{
		_songScripts.Clear();
		if (string.IsNullOrWhiteSpace(scripts))
		{
			return;
		}
		string[] array = scripts.Replace("\r", "").Split(new char[2] { '\n', ';' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length == 0)
			{
				continue;
			}
			int num = text.IndexOf(':');
			if (num <= 0)
			{
				continue;
			}
			string text2 = text.Substring(0, num).Trim();
			string[] array2 = text.Substring(num + 1).Split(new char[3] { ',', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
			List<int> list = new List<int>(array2.Length);
			string[] array3 = array2;
			for (int j = 0; j < array3.Length; j++)
			{
				if (int.TryParse(array3[j].Trim(), out var result))
				{
					list.Add(result);
				}
			}
			if (text2.Length > 0 && list.Count > 0)
			{
				_songScripts[text2] = list;
			}
		}
		if (_songScripts.Count == 0)
		{
			_songScripts["happybirthday"] = new List<int>
			{
				0, 0, 2, 0, 5, 4, 0, 0, 2, 0,
				7, 5
			};
		}
	}

	internal static bool TryStartSongFromChat(string id)
	{
		//IL_008d: 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)
		try
		{
			if (string.IsNullOrWhiteSpace(id))
			{
				id = TeacherSong.Value;
			}
			if (string.IsNullOrWhiteSpace(id))
			{
				return false;
			}
			PianoSongTeacher[] array = Object.FindObjectsOfType<PianoSongTeacher>(true);
			if (array == null || array.Length == 0)
			{
				return false;
			}
			Transform val = (Object.op_Implicit((Object)(object)PlayerAvatar.instance) ? ((Component)PlayerAvatar.instance).transform : null);
			PianoSongTeacher pianoSongTeacher = array[0];
			float num = float.MaxValue;
			PianoSongTeacher[] array2 = array;
			foreach (PianoSongTeacher pianoSongTeacher2 in array2)
			{
				if (!((Object)(object)pianoSongTeacher2 == (Object)null))
				{
					float num2 = (Object.op_Implicit((Object)(object)val) ? Vector3.SqrMagnitude(((Component)pianoSongTeacher2).transform.position - val.position) : 0f);
					if (num2 < num)
					{
						num = num2;
						pianoSongTeacher = pianoSongTeacher2;
					}
				}
			}
			if ((Object)(object)pianoSongTeacher == (Object)null)
			{
				return false;
			}
			pianoSongTeacher.StartSongExternal(id, TeacherStartKeyIndex.Value);
			ManualLogSource logS = LogS;
			if (logS != null)
			{
				logS.LogInfo((object)("[Teacher] Starting song '" + id + "' from chat."));
			}
			return true;
		}
		catch (Exception ex)
		{
			ManualLogSource logS2 = LogS;
			if (logS2 != null)
			{
				logS2.LogWarning((object)("[Teacher] Start from chat failed: " + ex.Message));
			}
			return false;
		}
	}

	internal static bool TryGetSongOffsets(string id, out List<int> offsets)
	{
		if (_songScripts.TryGetValue(id ?? string.Empty, out offsets))
		{
			return true;
		}
		offsets = null;
		return false;
	}
}
internal static class PianoHintResources
{
	private static Material _hintMat;

	public static Material HintMat
	{
		get
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			if ((Object)(object)_hintMat == (Object)null)
			{
				Shader val = Shader.Find("Sprites/Default");
				if ((Object)(object)val == (Object)null)
				{
					val = Shader.Find("Unlit/Color");
				}
				_hintMat = new Material(val)
				{
					name = "PianoHintMat"
				};
				float num = 0.45f;
				try
				{
					num = Mathf.Clamp01(PianoHintsPlugin.KeyAlpha.Value);
				}
				catch
				{
				}
				_hintMat.color = new Color(1f, 1f, 1f, num);
			}
			return _hintMat;
		}
	}

	public static Color ColorForIndex(int i, int cycle)
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		if (cycle <= 0)
		{
			cycle = 12;
		}
		float num = (float)(i % cycle) / (float)cycle;
		float num2 = 0.5f;
		float num3 = 0.8f;
		float a = 0.45f;
		try
		{
			num2 = Mathf.Clamp01(PianoHintsPlugin.KeySaturation.Value);
		}
		catch
		{
		}
		try
		{
			num3 = Mathf.Clamp01(PianoHintsPlugin.KeyValue.Value);
		}
		catch
		{
		}
		try
		{
			a = Mathf.Clamp01(PianoHintsPlugin.KeyAlpha.Value);
		}
		catch
		{
		}
		Color result = Color.HSVToRGB(num, num2, num3);
		result.a = a;
		return result;
	}
}
public class PianoHintsSweeper : MonoBehaviour
{
	private readonly HashSet<int> _processed = new HashSet<int>();

	private float _nextScan;

	private void Update()
	{
		if (Time.unscaledTime < _nextScan)
		{
			return;
		}
		_nextScan = Time.unscaledTime + 1f;
		try
		{
			MusicalValuableLogic[] array = Object.FindObjectsOfType<MusicalValuableLogic>(true);
			foreach (MusicalValuableLogic val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				int instanceID = ((Object)val).GetInstanceID();
				if (_processed.Contains(instanceID))
				{
					continue;
				}
				if ((Object)(object)((Component)val).gameObject.GetComponent<PianoHintsOverlay>() == (Object)null)
				{
					((Component)val).gameObject.AddComponent<PianoHintsOverlay>().Initialize(val);
					ManualLogSource logS = PianoHintsPlugin.LogS;
					if (logS != null)
					{
						logS.LogInfo((object)("[PianoHints] Attached overlay to " + ((Object)((Component)val).gameObject).name));
					}
				}
				if ((Object)(object)((Component)val).gameObject.GetComponent<PianoSongTeacher>() == (Object)null)
				{
					((Component)val).gameObject.AddComponent<PianoSongTeacher>();
				}
				_processed.Add(instanceID);
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logS2 = PianoHintsPlugin.LogS;
			if (logS2 != null)
			{
				logS2.LogWarning((object)("[PianoHintsSweeper] " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}
}
public enum PianoLabelMode
{
	None,
	Index,
	Note,
	NoteOctave,
	ClipName
}
public class PianoHintsOverlay : MonoBehaviour
{
	private MusicalValuableLogic _logic;

	private Transform _start;

	private Transform _end;

	private Transform _root;

	private readonly List<Renderer> _renderers = new List<Renderer>();

	private readonly List<Component> _textComps = new List<Component>();

	private int _keyCount;

	private float _lastLayoutCheck;

	private List<string> _noteNames = new List<string>();

	private readonly List<Color> _defaultColors = new List<Color>();

	private readonly Dictionary<int, bool> _isHighlighted = new Dictionary<int, bool>();

	public int KeyCount => _keyCount;

	private int GroupSize()
	{
		return Mathf.Max(1, ((Object)(object)_logic != (Object)null) ? _logic.numberOfOctaves : 6);
	}

	public void Initialize(MusicalValuableLogic logic)
	{
		_logic = logic;
		_start = logic.musicKeysStart;
		_end = logic.musicKeysEnd;
		_keyCount = SafeComputeKeyCount(logic);
		_noteNames = ParseNoteNames(PianoHintsPlugin.NoteNamesCSV.Value);
		EnsureRoot();
		BuildOrRebuild();
		ApplyVisibility(PianoHintsPlugin.Enabled.Value);
	}

	private int SafeComputeKeyCount(MusicalValuableLogic logic)
	{
		try
		{
			int num = Mathf.Max(1, (logic.musicKeys != null) ? logic.musicKeys.Count : 0);
			int num2 = Mathf.Max(1, logic.numberOfOctaves);
			if (num == 0)
			{
				num = 12;
			}
			return num * num2;
		}
		catch
		{
			return 72;
		}
	}

	private void EnsureRoot()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		//IL_003e: 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_005e: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_root != (Object)null))
		{
			GameObject val = new GameObject("PianoHintsRoot");
			val.transform.SetParent(((Component)this).transform, false);
			_root = val.transform;
			_root.localPosition = Vector3.zero;
			_root.localRotation = Quaternion.identity;
			_root.localScale = Vector3.one;
		}
	}

	private void Clear()
	{
		for (int num = _root.childCount - 1; num >= 0; num--)
		{
			Transform child = _root.GetChild(num);
			try
			{
				Object.Destroy((Object)(object)((Component)child).gameObject);
			}
			catch
			{
			}
		}
		_renderers.Clear();
		_textComps.Clear();
	}

	private void BuildOrRebuild()
	{
		//IL_003d: 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_0049: 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_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_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: 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_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Expected O, but got Unknown
		//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_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_0210: Expected O, but got Unknown
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_start == (Object)null || (Object)(object)_end == (Object)null)
		{
			ManualLogSource logS = PianoHintsPlugin.LogS;
			if (logS != null)
			{
				logS.LogWarning((object)"[PianoHintsOverlay] musicKeysStart or musicKeysEnd is null; cannot build hints.");
			}
			return;
		}
		Clear();
		Vector3 position = _start.position;
		Vector3 val = _end.position - position;
		float magnitude = ((Vector3)(ref val)).magnitude;
		if (magnitude < 0.0001f)
		{
			return;
		}
		Vector3 val2 = val / magnitude;
		Material hintMat = PianoHintResources.HintMat;
		int cycle = Mathf.Max(2, PianoHintsPlugin.ColorCycle.Value);
		float num = Mathf.Max(0.003f, PianoHintsPlugin.KeyThickness.Value);
		float num2 = Mathf.Max(0.01f, PianoHintsPlugin.KeyLength.Value);
		float value = PianoHintsPlugin.HeightOffset.Value;
		Vector3 up = ((Component)this).transform.up;
		Vector3 val3 = Vector3.Cross(up, val2);
		Vector3 normalized = ((Vector3)(ref val3)).normalized;
		for (int i = 0; i < _keyCount; i++)
		{
			float num3 = ((float)i + 0.5f) / (float)_keyCount;
			Vector3 position2 = position + val2 * (num3 * magnitude) + ((Component)this).transform.up * value;
			GameObject val4 = GameObject.CreatePrimitive((PrimitiveType)5);
			((Object)val4).name = $"Hint_{i:000}";
			val4.transform.SetParent(_root, true);
			val4.transform.position = position2;
			val4.transform.rotation = Quaternion.LookRotation(up, normalized);
			val4.transform.localScale = new Vector3(num, num2, 1f);
			Collider component = val4.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Renderer component2 = val4.GetComponent<Renderer>();
			component2.sharedMaterial = hintMat;
			MaterialPropertyBlock val5 = new MaterialPropertyBlock();
			Color val6 = PianoHintResources.ColorForIndex(i, cycle);
			val5.SetColor("_Color", val6);
			component2.SetPropertyBlock(val5);
			_renderers.Add(component2);
			if (PianoHintsPlugin.LabelMode.Value != 0)
			{
				GameObject val7 = new GameObject("Label");
				val7.transform.SetParent(val4.transform, false);
				val7.transform.localPosition = new Vector3(0f, 0f, PianoHintsPlugin.LabelLift.Value);
				val7.transform.localRotation = Quaternion.Euler(PianoHintsPlugin.LabelRotX.Value, PianoHintsPlugin.LabelRotY.Value, PianoHintsPlugin.LabelRotZ.Value);
				if (PianoHintsPlugin.Billboard.Value)
				{
					val7.AddComponent<PianoHintBillboard>();
				}
				string labelForKey = GetLabelForKey(i);
				TryAddTextMesh(val7, labelForKey, num);
			}
		}
	}

	public void ApplyVisibility(bool visible)
	{
		if ((Object)(object)_root != (Object)null)
		{
			((Component)_root).gameObject.SetActive(visible);
		}
	}

	private void LateUpdate()
	{
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: 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_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0223: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0235: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: 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_025d: 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_0274: 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)
		if ((Object)(object)_logic == (Object)null || (Object)(object)_start == (Object)null || (Object)(object)_end == (Object)null)
		{
			return;
		}
		if (!PianoHintsPlugin.Enabled.Value)
		{
			if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf)
			{
				((Component)_root).gameObject.SetActive(false);
			}
			return;
		}
		if ((Object)(object)_root != (Object)null && !((Component)_root).gameObject.activeSelf)
		{
			((Component)_root).gameObject.SetActive(true);
		}
		float value = PianoHintsPlugin.MaxDrawDistance.Value;
		if (value > 0f)
		{
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null)
			{
				float num = Vector3.Distance(((Component)main).transform.position, ((Component)this).transform.position);
				((Component)_root).gameObject.SetActive(num <= value);
			}
		}
		if (!(Time.unscaledTime - _lastLayoutCheck > 0.5f))
		{
			return;
		}
		_lastLayoutCheck = Time.unscaledTime;
		int num2 = SafeComputeKeyCount(_logic);
		if (num2 != _keyCount)
		{
			_keyCount = num2;
			_noteNames = ParseNoteNames(PianoHintsPlugin.NoteNamesCSV.Value);
			BuildOrRebuild();
			return;
		}
		Vector3 position = _start.position;
		Vector3 val = _end.position - position;
		float magnitude = ((Vector3)(ref val)).magnitude;
		if (magnitude < 0.0001f)
		{
			return;
		}
		Vector3 val2 = val / magnitude;
		float num3 = Mathf.Max(0.003f, PianoHintsPlugin.KeyThickness.Value);
		float num4 = Mathf.Max(0.01f, PianoHintsPlugin.KeyLength.Value);
		float value2 = PianoHintsPlugin.HeightOffset.Value;
		Vector3 up = ((Component)this).transform.up;
		Vector3 val3 = Vector3.Cross(up, val2);
		Vector3 normalized = ((Vector3)(ref val3)).normalized;
		int num5 = Mathf.Min(_root.childCount, _keyCount);
		for (int i = 0; i < num5; i++)
		{
			float num6 = ((float)i + 0.5f) / (float)_keyCount;
			Vector3 position2 = position + val2 * (num6 * magnitude) + ((Component)this).transform.up * value2;
			Transform child = _root.GetChild(i);
			child.position = position2;
			child.rotation = Quaternion.LookRotation(up, normalized);
			child.localScale = new Vector3(num3, num4, 1f);
			if (child.childCount > 0)
			{
				child.GetChild(0).localPosition = new Vector3(0f, 0f, PianoHintsPlugin.LabelLift.Value);
			}
		}
	}

	private void CacheDefaultColorsIfNeeded()
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		if (_defaultColors.Count != _renderers.Count)
		{
			_defaultColors.Clear();
			for (int i = 0; i < _renderers.Count; i++)
			{
				int cycle = Mathf.Max(2, PianoHintsPlugin.ColorCycle.Value);
				_defaultColors.Add(PianoHintResources.ColorForIndex(i, cycle));
			}
		}
	}

	public void HighlightKey(int keyIndex, Color color)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		if (keyIndex >= 0 && keyIndex < _renderers.Count)
		{
			CacheDefaultColorsIfNeeded();
			Renderer obj = _renderers[keyIndex];
			MaterialPropertyBlock val = new MaterialPropertyBlock();
			obj.GetPropertyBlock(val);
			val.SetColor("_Color", color);
			obj.SetPropertyBlock(val);
			_isHighlighted[keyIndex] = true;
		}
	}

	public void ClearHighlight(int keyIndex)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		if (keyIndex >= 0 && keyIndex < _renderers.Count)
		{
			CacheDefaultColorsIfNeeded();
			Renderer obj = _renderers[keyIndex];
			MaterialPropertyBlock val = new MaterialPropertyBlock();
			obj.GetPropertyBlock(val);
			val.SetColor("_Color", _defaultColors[keyIndex]);
			obj.SetPropertyBlock(val);
			_isHighlighted.Remove(keyIndex);
		}
	}

	public void HighlightGroup(int groupIndex, Color color)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		if (groupIndex >= 0 && groupIndex < _renderers.Count)
		{
			HighlightKey(groupIndex, color);
		}
	}

	public void ClearHighlightGroup(int groupIndex)
	{
		if (groupIndex >= 0 && groupIndex < _renderers.Count)
		{
			ClearHighlight(groupIndex);
		}
	}

	private List<string> ParseNoteNames(string csv)
	{
		List<string> list = new List<string>();
		try
		{
			if (!string.IsNullOrWhiteSpace(csv))
			{
				string[] array = csv.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string text in array)
				{
					list.Add(text.Trim());
				}
			}
		}
		catch
		{
		}
		if (list.Count == 0)
		{
			list.AddRange(new string[12]
			{
				"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A",
				"A#", "B"
			});
		}
		return list;
	}

	private string GetLabelForKey(int key)
	{
		PianoLabelMode value = PianoHintsPlugin.LabelMode.Value;
		if (value == PianoLabelMode.Index)
		{
			return (key + 1).ToString();
		}
		int num = Mathf.Max(1, ((Object)(object)_logic != (Object)null) ? _logic.numberOfOctaves : 6);
		int num2 = key / num;
		int num3 = key % num;
		if (value == PianoLabelMode.ClipName)
		{
			try
			{
				List<Sound> musicKeys = _logic.musicKeys;
				if (musicKeys != null && musicKeys.Count > 0)
				{
					int num4 = Mathf.Clamp(num2, 0, musicKeys.Count - 1);
					Sound val = musicKeys[num4];
					if (val != null && ((object)val).GetType().GetField("Sounds", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val) is Array array && array.Length > 0)
					{
						object value2 = array.GetValue(0);
						if (value2 != null)
						{
							string text = (value2.GetType().GetProperty("name", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value2) as string) ?? value2.ToString();
							if (!string.IsNullOrEmpty(text))
							{
								return text;
							}
						}
						return $"Clip{num4}";
					}
				}
			}
			catch
			{
			}
			return (key + 1).ToString();
		}
		List<string> obj2 = ((_noteNames != null && _noteNames.Count > 0) ? _noteNames : ParseNoteNames(PianoHintsPlugin.NoteNamesCSV.Value));
		int count = obj2.Count;
		int num5 = Mathf.Clamp(PianoHintsPlugin.NoteRootIndex.Value, 0, count - 1);
		int num6 = num2 + num5;
		string text2 = obj2[num6 % count];
		if (value == PianoLabelMode.Note)
		{
			return text2;
		}
		int value3 = PianoHintsPlugin.BaseOctave.Value;
		int num7 = num6 / count;
		int num8 = Mathf.RoundToInt((float)num3 / Mathf.Max(1f, (float)num) * (float)count) / count;
		int num9 = value3 + num7 + num8;
		return $"{text2}{num9}";
	}

	private void TryAddTextMesh(GameObject go, string text, float thickness)
	{
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Type type = Type.GetType("UnityEngine.TextMesh, UnityEngine.TextRenderingModule") ?? Type.GetType("UnityEngine.TextMesh, UnityEngine") ?? null;
			if (type == null)
			{
				return;
			}
			Component val = go.AddComponent(type);
			_textComps.Add(val);
			PropertyInfo property = type.GetProperty("text");
			PropertyInfo? property2 = type.GetProperty("color");
			PropertyInfo? property3 = type.GetProperty("fontSize");
			PropertyInfo property4 = type.GetProperty("characterSize");
			PropertyInfo property5 = type.GetProperty("anchor");
			PropertyInfo property6 = type.GetProperty("alignment");
			property?.SetValue(val, text);
			property3?.SetValue(val, PianoHintsPlugin.FontSize.Value);
			property4?.SetValue(val, thickness * 0.5f);
			property2?.SetValue(val, Color.black);
			try
			{
				Type type2 = Type.GetType("UnityEngine.TextAnchor, UnityEngine.TextRenderingModule") ?? Type.GetType("UnityEngine.TextAnchor, UnityEngine") ?? null;
				if (type2 != null)
				{
					object value = Enum.Parse(type2, "MiddleCenter");
					property5?.SetValue(val, value);
				}
			}
			catch
			{
			}
			try
			{
				Type type3 = Type.GetType("UnityEngine.TextAlignment, UnityEngine.TextRenderingModule") ?? Type.GetType("UnityEngine.TextAlignment, UnityEngine") ?? null;
				if (type3 != null)
				{
					object value2 = Enum.Parse(type3, "Center");
					property6?.SetValue(val, value2);
				}
			}
			catch
			{
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logS = PianoHintsPlugin.LogS;
			if (logS != null)
			{
				logS.LogWarning((object)("[TryAddTextMesh] " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}
}
public class PianoHintBillboard : MonoBehaviour
{
	private void LateUpdate()
	{
		//IL_0016: 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_003c: 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_004c: 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_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_007c: 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)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		Camera main = Camera.main;
		if (!((Object)(object)main == (Object)null))
		{
			Vector3 val = ((Component)main).transform.position - ((Component)this).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude > 0.0001f)
			{
				Quaternion val2 = Quaternion.LookRotation(((Vector3)(ref val)).normalized, ((Component)main).transform.up);
				Quaternion val3 = Quaternion.Euler(PianoHintsPlugin.LabelRotX.Value, PianoHintsPlugin.LabelRotY.Value, PianoHintsPlugin.LabelRotZ.Value);
				((Component)this).transform.rotation = val2 * val3;
			}
		}
	}
}
public class PianoSongTeacher : MonoBehaviour
{
	private PianoHintsOverlay _overlay;

	private MusicalValuableLogic _logic;

	private bool _active;

	private List<int> _sequence = new List<int>();

	private int _cursor;

	private Color _hlColor = new Color(1f, 0.82f, 0.125f, 0.95f);

	private string _lastSongId = "";

	private int _lastStartKey;

	private void Awake()
	{
		_overlay = ((Component)this).GetComponent<PianoHintsOverlay>();
		_logic = ((Component)this).GetComponent<MusicalValuableLogic>();
		TryParseHighlightColor();
	}

	private void Update()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		if (PianoHintsPlugin.TeacherStartKey == null)
		{
			return;
		}
		KeyboardShortcut value = PianoHintsPlugin.TeacherStartKey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			if (!string.IsNullOrEmpty(_lastSongId))
			{
				StopTeaching();
				StartSongInternal(_lastSongId, _lastStartKey);
			}
			else
			{
				StopTeaching();
				StartSongInternal(PianoHintsPlugin.TeacherSong.Value, PianoHintsPlugin.TeacherStartKeyIndex.Value);
			}
		}
	}

	private void TryParseHighlightColor()
	{
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: 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_007b: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			string value = PianoHintsPlugin.TeacherHighlightColor.Value;
			if (!string.IsNullOrWhiteSpace(value))
			{
				value = value.Trim();
				if (value.StartsWith("#"))
				{
					value = value.Substring(1);
				}
				uint num = Convert.ToUInt32(value, 16);
				if (value.Length <= 6)
				{
					byte b = (byte)((num >> 16) & 0xFFu);
					byte b2 = (byte)((num >> 8) & 0xFFu);
					byte b3 = (byte)(num & 0xFFu);
					_hlColor = Color32.op_Implicit(new Color32(b, b2, b3, (byte)240));
				}
				else
				{
					byte b4 = (byte)((num >> 24) & 0xFFu);
					byte b5 = (byte)((num >> 16) & 0xFFu);
					byte b6 = (byte)((num >> 8) & 0xFFu);
					byte b7 = (byte)(num & 0xFFu);
					_hlColor = Color32.op_Implicit(new Color32(b4, b5, b6, b7));
				}
			}
		}
		catch
		{
		}
	}

	public void OnKeyPressed(int keyIndex)
	{
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		if (!_active || (Object)(object)_overlay == (Object)null || _cursor < 0 || _cursor >= _sequence.Count)
		{
			return;
		}
		int num = _sequence[_cursor];
		if (keyIndex == num)
		{
			_overlay.ClearHighlight(num);
			_cursor++;
			if (_cursor < _sequence.Count)
			{
				_overlay.HighlightKey(_sequence[_cursor], _hlColor);
			}
			else
			{
				StopTeaching();
			}
		}
	}

	private void StartTeaching()
	{
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		_sequence = BuildSong(PianoHintsPlugin.TeacherSong.Value, PianoHintsPlugin.TeacherStartKeyIndex.Value);
		if ((Object)(object)_overlay == (Object)null || _sequence.Count == 0)
		{
			ManualLogSource logS = PianoHintsPlugin.LogS;
			if (logS != null)
			{
				logS.LogWarning((object)"[Teacher] Unable to start; missing overlay/logic or sequence.");
			}
			return;
		}
		ClampToKeyboard(_sequence);
		_cursor = 0;
		_active = true;
		_overlay.HighlightKey(_sequence[_cursor], _hlColor);
		ManualLogSource logS2 = PianoHintsPlugin.LogS;
		if (logS2 != null)
		{
			logS2.LogInfo((object)$"[Teacher] Started song: {PianoHintsPlugin.TeacherSong.Value} with {_sequence.Count} notes.");
		}
	}

	internal void StartSongExternal(string id, int startKey)
	{
		StopTeaching();
		StartSongInternal(id, startKey);
	}

	private void StartSongInternal(string id, int startKey)
	{
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		_sequence = BuildSong(id, startKey);
		if ((Object)(object)_overlay == (Object)null || _sequence.Count == 0)
		{
			ManualLogSource logS = PianoHintsPlugin.LogS;
			if (logS != null)
			{
				logS.LogWarning((object)("[Teacher] Unable to start song '" + id + "'."));
			}
			return;
		}
		ClampToKeyboard(_sequence);
		_cursor = 0;
		_active = true;
		_lastSongId = id;
		_lastStartKey = startKey;
		_overlay.HighlightKey(_sequence[_cursor], _hlColor);
		ManualLogSource logS2 = PianoHintsPlugin.LogS;
		if (logS2 != null)
		{
			logS2.LogInfo((object)$"[Teacher] Started song: {id} with {_sequence.Count} notes.");
		}
	}

	private void StopTeaching()
	{
		if ((Object)(object)_overlay != (Object)null)
		{
			foreach (int item in _sequence)
			{
				_overlay.ClearHighlight(item);
			}
		}
		_sequence.Clear();
		_cursor = 0;
		_active = false;
		ManualLogSource logS = PianoHintsPlugin.LogS;
		if (logS != null)
		{
			logS.LogInfo((object)"[Teacher] Stopped.");
		}
	}

	private void ClampToKeyboard(List<int> seq)
	{
		int num = Mathf.Max(0, ((Object)(object)_overlay != (Object)null) ? _overlay.KeyCount : 0) - 1;
		for (int i = 0; i < seq.Count; i++)
		{
			seq[i] = Mathf.Clamp(seq[i], 0, num);
		}
	}

	private List<int> BuildSong(string id, int startKey)
	{
		List<int> list = new List<int>();
		if (PianoHintsPlugin.TryGetSongOffsets(id, out List<int> offsets) && offsets != null && offsets.Count > 0)
		{
			foreach (int item in offsets)
			{
				list.Add(startKey + item);
			}
			return list;
		}
		if (string.IsNullOrEmpty(id) || id.Equals("happybirthday", StringComparison.OrdinalIgnoreCase))
		{
			int[] array = new int[12]
			{
				0, 0, 2, 0, 5, 4, 0, 0, 2, 0,
				7, 5
			};
			foreach (int num in array)
			{
				list.Add(startKey + num);
			}
			return list;
		}
		return list;
	}
}
[HarmonyPatch(typeof(MusicalValuableLogic), "MusicKeyPressedRPC")]
internal static class PianoHints_KeyPressedPatch
{
	private static void Postfix(MusicalValuableLogic __instance, int keyIndex, int grabberID)
	{
		PianoSongTeacher component = ((Component)__instance).GetComponent<PianoSongTeacher>();
		if ((Object)(object)component != (Object)null)
		{
			component.OnKeyPressed(keyIndex);
		}
	}
}
[HarmonyPatch(typeof(PlayerAvatar), "ChatMessageSend")]
internal static class PianoHints_ChatCommandPatch
{
	private static bool Prefix(string _message)
	{
		try
		{
			if (!string.IsNullOrWhiteSpace(_message) && _message.StartsWith("/song ", StringComparison.OrdinalIgnoreCase))
			{
				string text = ((_message.Length > 5) ? _message.Substring(5).Trim() : PianoHintsPlugin.TeacherSong.Value);
				if (!string.IsNullOrWhiteSpace(text))
				{
					PianoHintsPlugin.TryStartSongFromChat(text);
				}
				return false;
			}
		}
		catch
		{
		}
		return true;
	}
}