Decompiled source of AlicesLowLatencyTromboning v0.1.4

BepInEx/plugins/AlicesLowLatencyTromboning.dll

Decompiled a week ago
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BaboonAPI.Hooks.Initializer;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("AlicesLowLatencyTromboning")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AlicesLowLatencyTromboning")]
[assembly: AssemblyTitle("AlicesLowLatencyTromboning")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NativeIntegerAttribute : Attribute
	{
		public readonly bool[] TransformFlags;

		public NativeIntegerAttribute()
		{
			TransformFlags = new bool[1] { true };
		}

		public NativeIntegerAttribute(bool[] P_0)
		{
			TransformFlags = P_0;
		}
	}
}
namespace AlicesLowLatencyTromboning
{
	internal class AlltPlayer : IDisposable
	{
		private readonly IntPtr _inner;

		[DllImport("allt_playback.dll")]
		private static extern IntPtr allt_player_new();

		[DllImport("allt_playback.dll", CharSet = CharSet.Ansi, EntryPoint = "allt_player_load")]
		private static extern IntPtr allt_player_load_char(string configDir);

		[DllImport("allt_playback.dll", CharSet = CharSet.Unicode, EntryPoint = "allt_player_load")]
		private static extern IntPtr allt_player_load_wchar(string configDir);

		[DllImport("allt_playback.dll")]
		private static extern IntPtr allt_player_tick(IntPtr player);

		[DllImport("allt_playback.dll")]
		private static extern bool allt_player_start_playback(IntPtr player);

		[DllImport("allt_playback.dll")]
		private static extern void allt_player_stop_playback(IntPtr player);

		[DllImport("allt_playback.dll")]
		private static extern void allt_player_drop(IntPtr player);

		[DllImport("allt_playback.dll")]
		private static extern bool allt_player_push_play(IntPtr player);

		[DllImport("allt_playback.dll")]
		private static extern bool allt_player_push_stop(IntPtr player);

		[DllImport("allt_playback.dll")]
		private static extern bool allt_player_push_set_pitch_multiplier(IntPtr player, float multiplier);

		[DllImport("allt_playback.dll")]
		private static extern bool allt_player_push_fade_out(IntPtr player);

		[DllImport("allt_playback.dll")]
		private static extern bool allt_player_push_set_num_trombone_clips(IntPtr player, nuint num);

		[DllImport("allt_playback.dll")]
		private static extern bool allt_player_push_set_trombone_clip_samples(IntPtr player, nuint index, IntPtr samples, nuint numSamples, nuint channels);

		[DllImport("allt_playback.dll")]
		private static extern bool allt_player_push_set_clip_to_play(IntPtr player, nuint index);

		[DllImport("allt_playback.dll")]
		private static extern bool allt_player_open_config_ui(IntPtr player);

		internal AlltPlayer()
		{
			_inner = allt_player_new();
		}

		private AlltPlayer(string configDir)
		{
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				_inner = allt_player_load_wchar(configDir);
			}
			else
			{
				_inner = allt_player_load_char(configDir);
			}
		}

		internal static AlltPlayer Load()
		{
			return new AlltPlayer(Paths.ConfigPath);
		}

		~AlltPlayer()
		{
			ReleaseUnmanagedResources();
		}

		private void ReleaseUnmanagedResources()
		{
			allt_player_drop(_inner);
		}

		public void Dispose()
		{
			ReleaseUnmanagedResources();
			GC.SuppressFinalize(this);
		}

		internal void Tick()
		{
			allt_player_tick(_inner);
		}

		internal void StartPlayback()
		{
			if (!allt_player_start_playback(_inner))
			{
				AlltPlugin.Instance.Logger.LogError((object)"Failed to start playback");
			}
		}

		internal void StopPlayback()
		{
			allt_player_stop_playback(_inner);
		}

		internal void PushPlay()
		{
			if (!allt_player_push_play(_inner))
			{
				AlltPlugin.Instance.Logger.LogError((object)"Error pushing play event");
			}
		}

		internal void PushStop()
		{
			if (!allt_player_push_stop(_inner))
			{
				AlltPlugin.Instance.Logger.LogError((object)"Error pushing stop event");
			}
		}

		internal void PushSetPitchMultiplier(float multiplier)
		{
			if (!allt_player_push_set_pitch_multiplier(_inner, multiplier))
			{
				AlltPlugin.Instance.Logger.LogError((object)"Error pushing set pitch multiplier event");
			}
		}

		internal void PushFadeOut()
		{
			if (!allt_player_push_fade_out(_inner))
			{
				AlltPlugin.Instance.Logger.LogError((object)"Error pushing fade out event");
			}
		}

		internal void PushSetNumTromboneClips(nuint num)
		{
			if (!allt_player_push_set_num_trombone_clips(_inner, num))
			{
				AlltPlugin.Instance.Logger.LogError((object)"Error pushing set num trombone clips event");
			}
		}

		internal unsafe void PushSetTromboneClipSamples(nuint index, float[] samples, nuint channels)
		{
			fixed (float* ptr = samples)
			{
				if (!allt_player_push_set_trombone_clip_samples(_inner, index, (IntPtr)ptr, (nuint)samples.Length, channels))
				{
					AlltPlugin.Instance.Logger.LogError((object)"Error pushing set trombone clip samples event");
				}
			}
		}

		internal void PushSetClipToPlay(nuint index)
		{
			if (!allt_player_push_set_clip_to_play(_inner, index))
			{
				AlltPlugin.Instance.Logger.LogError((object)"Error pushing set clip to play event");
			}
		}

		internal void OpenConfigUi()
		{
			if (!allt_player_open_config_ui(_inner))
			{
				AlltPlugin.Instance.Logger.LogError((object)"Failed to open config UI");
			}
		}
	}
	[BepInPlugin("craftedcart.low_latency_tromboning", "Alice's Low Latency Tromboning", "0.1.4.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class AlltPlugin : BaseUnityPlugin
	{
		private static AlltPlugin? _instance;

		private AlltPlayer? _player;

		private readonly Harmony _harmony = new Harmony("craftedcart.low_latency_tromboning");

		internal static AlltPlugin Instance
		{
			get
			{
				if (_instance == null)
				{
					throw new NullReferenceException("Instance not initialized - accessing too early?");
				}
				return _instance;
			}
		}

		internal ManualLogSource Logger => ((BaseUnityPlugin)this).Logger;

		internal AlltPlayer Player
		{
			get
			{
				if (_player == null)
				{
					throw new NullReferenceException("Player not initialized - accessing too early?");
				}
				return _player;
			}
		}

		[DllImport("allt_playback.dll")]
		private static extern void allt_init_logging();

		private void Awake()
		{
			_instance = this;
			GameInitializationEvent.Register(((BaseUnityPlugin)this).Info, (Action)TryInitialize);
		}

		private void TryInitialize()
		{
			allt_init_logging();
			_harmony.PatchAll(typeof(GameControllerPatch));
			SceneManager.activeSceneChanged += GameControllerPatch.OnSceneChanged;
			SceneManager.activeSceneChanged += OnSceneChanged;
			_player = AlltPlayer.Load();
		}

		private void Update()
		{
			_player?.Tick();
		}

		private void OnSceneChanged(Scene oldScene, Scene newScene)
		{
			//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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: 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_011a: 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_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			if (!(((Scene)(ref newScene)).name == "home"))
			{
				return;
			}
			GameObject val = ((Scene)(ref newScene)).GetRootGameObjects().First((GameObject go) => ((Object)go).name == "MainCanvas");
			if ((Object)(object)val == (Object)null)
			{
				Logger.LogError((object)"Failed to find main canvas");
				return;
			}
			Transform val2 = val.transform.Find("SettingsPanel/Settings/TIMING");
			if ((Object)(object)val2 == (Object)null)
			{
				Logger.LogError((object)"Failed to find timing panel to add settings button to");
				return;
			}
			GameObject val3 = new GameObject("AlltSettingsButton", new Type[3]
			{
				typeof(RectTransform),
				typeof(Button),
				typeof(Image)
			});
			RectTransform val4 = (RectTransform)val3.transform;
			Button component = val3.GetComponent<Button>();
			Image component2 = val3.GetComponent<Image>();
			((Transform)val4).SetParent(((Component)val2).transform, false);
			val4.anchorMin = new Vector2(1f, 0f);
			val4.anchorMax = new Vector2(1f, 0f);
			val4.offsetMin = new Vector2(-208f, 8f);
			val4.offsetMax = new Vector2(-25f, 42f);
			((Selectable)component).targetGraphic = (Graphic)(object)component2;
			((Graphic)component2).color = new Color(0.914f, 0.212f, 0.337f, 1f);
			((UnityEvent)component.onClick).AddListener(new UnityAction(LaunchAlltConfigUi));
			RectTransform val5 = (RectTransform)new GameObject("AlltSettingsButtonText", new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			}).transform;
			((Transform)val5).SetParent((Transform)(object)val4, false);
			val5.anchorMin = new Vector2(0.5f, 0.5f);
			val5.anchorMax = new Vector2(0.5f, 0.5f);
			TextMeshProUGUI component3 = ((Component)val5).GetComponent<TextMeshProUGUI>();
			((TMP_Text)component3).text = "ALLT Settings";
			((Graphic)component3).color = Color.white;
			((TMP_Text)component3).enableWordWrapping = false;
			((TMP_Text)component3).alignment = (TextAlignmentOptions)514;
			((TMP_Text)component3).fontSize = 24f;
		}

		private void LaunchAlltConfigUi()
		{
			Window.Minimize();
			Player.OpenConfigUi();
		}
	}
	public class GameControllerPatch
	{
		[HarmonyPatch(typeof(GameController), "Start")]
		[HarmonyPostfix]
		private static void Start_Post(GameController __instance)
		{
			AlltPlayer player = AlltPlugin.Instance.Player;
			player.StartPlayback();
			AlltPlugin.Instance.Logger.LogInfo((object)"Sending trombone clip samples to ALLT Playback");
			AudioClipsTromb component = ((Component)__instance.soundSets.transform.GetChild(0)).gameObject.GetComponent<AudioClipsTromb>();
			player.PushSetNumTromboneClips((nuint)component.tclips.Length);
			for (int i = 0; i < component.tclips.Length; i++)
			{
				AudioClip val = component.tclips[i];
				float[] array = new float[val.samples * val.channels];
				if (val.GetData(array, 0))
				{
					player.PushSetTromboneClipSamples((nuint)i, array, (nuint)val.channels);
				}
				else
				{
					AlltPlugin.Instance.Logger.LogError((object)$"Failed to get trombone clip {i} samples");
				}
			}
		}

		[HarmonyPatch(typeof(GameController), "playNote")]
		[HarmonyPostfix]
		private static void PlayNote_Post(GameController __instance)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			float num = 9999f;
			int num2 = 0;
			for (int i = 0; i < 15; i++)
			{
				float num3 = Mathf.Abs(__instance.notelinepos[i] - __instance.pointer.transform.localPosition.y);
				if (num3 < num)
				{
					num = num3;
					num2 = i;
				}
			}
			int num4 = Mathf.Abs(num2 - 14);
			AlltPlayer player = AlltPlugin.Instance.Player;
			player.PushSetClipToPlay((nuint)num4);
			player.PushSetPitchMultiplier(__instance.currentnotesound.pitch);
			player.PushPlay();
			__instance.currentnotesound.Stop();
		}

		[HarmonyPatch(typeof(GameController), "stopNote")]
		[HarmonyPostfix]
		private static void StopNote_Post()
		{
			AlltPlugin.Instance.Player.PushStop();
		}

		[HarmonyPatch(typeof(GameController), "Update")]
		[HarmonyPostfix]
		private static void Update_Post(GameController __instance)
		{
			AlltPlayer player = AlltPlugin.Instance.Player;
			if ((Object)(object)__instance.currentnotesound != (Object)null)
			{
				player.PushSetPitchMultiplier(__instance.currentnotesound.pitch);
			}
			if (!__instance.noteplaying)
			{
				player.PushFadeOut();
			}
		}

		internal static void OnSceneChanged(Scene oldScene, Scene newScene)
		{
			AlltPlugin.Instance.Player.StopPlayback();
		}
	}
	internal static class Window
	{
		private const int SW_SHOWMINIMIZED = 2;

		private const int SW_RESTORE = 9;

		[DllImport("user32.dll")]
		private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

		[DllImport("user32.dll")]
		private static extern IntPtr GetActiveWindow();

		internal static void Minimize()
		{
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				ShowWindow(GetActiveWindow(), 2);
			}
			else
			{
				AlltPlugin.Instance.Logger.LogWarning((object)"Window.Minimize() not supported on this platform");
			}
		}

		internal static void Restore()
		{
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				ShowWindow(GetActiveWindow(), 9);
			}
			else
			{
				AlltPlugin.Instance.Logger.LogWarning((object)"Window.Restore() not supported on this platform");
			}
		}
	}
}