Decompiled source of Tailwind v1.0.7

Tailwind.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 BepInEx;
using HarmonyLib;
using Jotunn;
using Jotunn.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Tailwind")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Tailwind")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4e327c88-7b4a-4569-8bbc-a67aaad1a422")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Tailwind;

[BepInPlugin("vaffle.Tailwind", "Tailwind", "1.0.2")]
public class Class1 : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Player), "StartDoodadControl")]
	private static class AddMusic_Ship
	{
		[CompilerGenerated]
		private sealed class <LoadAndPlayMusicFromFolder>d__1 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			private string <randomMp3Path>5__1;

			private UnityWebRequest <www>5__2;

			private AudioClip <clip>5__3;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<randomMp3Path>5__1 = null;
				<www>5__2 = null;
				<clip>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_011c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0122: Invalid comparison between Unknown and I4
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						if (!Directory.Exists(musicFolderPath))
						{
							Logger.LogError((object)("Music folder not found at: " + musicFolderPath));
							return false;
						}
						mp3Files = Directory.GetFiles(musicFolderPath, "*.mp3");
						Logger.LogWarning((object)$"Found {mp3Files.Length} .mp3 files");
						if (mp3Files.Length == 0)
						{
							Logger.LogError((object)("No .mp3 files found in " + musicFolderPath));
							return false;
						}
						<randomMp3Path>5__1 = mp3Files[Random.Range(0, mp3Files.Length)];
						<www>5__2 = UnityWebRequestMultimedia.GetAudioClip("file://" + <randomMp3Path>5__1, (AudioType)13);
						<>1__state = -3;
						<>2__current = <www>5__2.SendWebRequest();
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -3;
						if ((int)<www>5__2.result == 1)
						{
							<clip>5__3 = DownloadHandlerAudioClip.GetContent(<www>5__2);
							((Object)<clip>5__3).name = Path.GetFileNameWithoutExtension(<randomMp3Path>5__1);
							audioSource.clip = <clip>5__3;
							audioSource.Play();
							isPlaying = true;
							UpdateMusicNameDisplay(((Object)<clip>5__3).name);
							Logger.LogWarning((object)("Now playing: " + ((Object)<clip>5__3).name));
							<clip>5__3 = null;
						}
						else
						{
							Logger.LogError((object)("Failed to load audio clip: " + <www>5__2.error));
						}
						<>m__Finally1();
						<www>5__2 = null;
						return false;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<www>5__2 != null)
				{
					((IDisposable)<www>5__2).Dispose();
				}
			}

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

		private static void Postfix(Player __instance, IDoodadController shipControl)
		{
			LoadUIPrefab();
			Ship localShip = Ship.GetLocalShip();
			Transform? obj = ((IEnumerable<Transform>)((Component)((Component)localShip).transform).GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "InWaterSounds"));
			GameObject val = ((obj != null) ? ((Component)((IEnumerable<Transform>)((Component)((Component)obj).gameObject.transform).GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "Decksound"))).gameObject : null);
			if ((Object)(object)val == (Object)null)
			{
				Logger.LogWarning((object)"Music piece (Decksound) not found!");
				return;
			}
			if ((Object)(object)audioSource == (Object)null)
			{
				audioSource = val.AddComponent<AudioSource>();
				Logger.LogWarning((object)"AudioSource added");
			}
			else
			{
				Logger.LogWarning((object)"AudioSource already exists");
			}
			((MonoBehaviour)__instance).StartCoroutine(LoadAndPlayMusicFromFolder());
		}

		[IteratorStateMachine(typeof(<LoadAndPlayMusicFromFolder>d__1))]
		private static IEnumerator LoadAndPlayMusicFromFolder()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadAndPlayMusicFromFolder>d__1(0);
		}
	}

	[HarmonyPatch(typeof(Player), "StopDoodadControl")]
	private static class RemoveUI_ShipEffects
	{
		private static void Postfix(Player __instance)
		{
			Object.Destroy((Object)(object)uiPanel);
			audioSource.Stop();
			Object.Destroy((Object)(object)audioSource);
		}
	}

	[CompilerGenerated]
	private sealed class <FadeOutText>d__14 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public TextMeshProUGUI text;

		public float duration;

		private float <elapsedTime>5__1;

		private Color <originalColor>5__2;

		private float <alpha>5__3;

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

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

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

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

		private bool MoveNext()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<elapsedTime>5__1 = 0f;
				<originalColor>5__2 = ((Graphic)text).color;
				<originalColor>5__2.a = 1f;
				break;
			case 1:
				<>1__state = -1;
				break;
			}
			if (<elapsedTime>5__1 < duration)
			{
				<elapsedTime>5__1 += Time.deltaTime;
				<alpha>5__3 = 1f - <elapsedTime>5__1 / duration;
				((Graphic)text).color = new Color(<originalColor>5__2.r, <originalColor>5__2.g, <originalColor>5__2.b, <alpha>5__3);
				<>2__current = null;
				<>1__state = 1;
				return true;
			}
			((Graphic)text).color = new Color(<originalColor>5__2.r, <originalColor>5__2.g, <originalColor>5__2.b, 0f);
			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();
		}
	}

	[CompilerGenerated]
	private sealed class <LoadAndSwitchTrack>d__16 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public string mp3Path;

		private UnityWebRequest <www>5__1;

		private AudioClip <clip>5__2;

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

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

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

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || num == 1)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<www>5__1 = null;
			<clip>5__2 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Invalid comparison between Unknown and I4
			try
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<www>5__1 = UnityWebRequestMultimedia.GetAudioClip("file://" + mp3Path, (AudioType)13);
					<>1__state = -3;
					<>2__current = <www>5__1.SendWebRequest();
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -3;
					if ((int)<www>5__1.result == 1)
					{
						<clip>5__2 = DownloadHandlerAudioClip.GetContent(<www>5__1);
						((Object)<clip>5__2).name = Path.GetFileNameWithoutExtension(mp3Path);
						audioSource.clip = <clip>5__2;
						audioSource.Play();
						isPlaying = true;
						UpdateMusicNameDisplay(((Object)<clip>5__2).name);
						Logger.LogWarning((object)("Now playing: " + ((Object)<clip>5__2).name));
						<clip>5__2 = null;
					}
					else
					{
						Logger.LogError((object)("Failed to load audio clip: " + <www>5__1.error));
					}
					<>m__Finally1();
					<www>5__1 = null;
					return false;
				}
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
		}

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

		private void <>m__Finally1()
		{
			<>1__state = -1;
			if (<www>5__1 != null)
			{
				((IDisposable)<www>5__1).Dispose();
			}
		}

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

	private static AudioSource audioSource;

	private static bool isPlaying = false;

	private static string musicFolderPath = Path.Combine(Paths.PluginPath, "Shanty");

	private static GameObject uiPanel;

	private static TextMeshProUGUI musicNameText;

	private static Button skipButton;

	private static Button pauseButton;

	private static string[] mp3Files;

	private void Awake()
	{
		Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
	}

	private void Update()
	{
		if (Input.GetKeyDown((KeyCode)284) && (Object)(object)audioSource != (Object)null)
		{
			if (isPlaying)
			{
				PauseMusic();
				Logger.LogWarning((object)"Music paused with F3");
			}
			else
			{
				ResumeMusic();
			}
		}
		if (Input.GetKeyDown((KeyCode)285) && (Object)(object)audioSource != (Object)null)
		{
			SwitchTrack();
			Logger.LogWarning((object)"Track switched with F4");
		}
	}

	private static void LoadUIPrefab()
	{
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Expected O, but got Unknown
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Expected O, but got Unknown
		AssetBundle val = AssetUtils.LoadAssetBundleFromResources("tailwind", Assembly.GetExecutingAssembly());
		if ((Object)(object)val == (Object)null)
		{
			Logger.LogError((object)"Failed to load tailwindbundle AssetBundle!");
			return;
		}
		GameObject val2 = val.LoadAsset<GameObject>("Tailwind");
		if ((Object)(object)val2 == (Object)null)
		{
			Logger.LogError((object)"Tailwind prefab not found in AssetBundle!");
			val.Unload(false);
			return;
		}
		uiPanel = Object.Instantiate<GameObject>(val2);
		((Object)uiPanel).name = "TailwindUI";
		Object.DontDestroyOnLoad((Object)(object)uiPanel);
		Transform obj = uiPanel.transform.Find("MusicNameBackground/MusicName");
		musicNameText = ((obj != null) ? ((Component)obj).GetComponent<TextMeshProUGUI>() : null);
		Transform obj2 = uiPanel.transform.Find("SkipButton");
		skipButton = ((obj2 != null) ? ((Component)obj2).GetComponent<Button>() : null);
		Transform obj3 = uiPanel.transform.Find("PauseButton");
		pauseButton = ((obj3 != null) ? ((Component)obj3).GetComponent<Button>() : null);
		if ((Object)(object)musicNameText == (Object)null)
		{
			Logger.LogWarning((object)"MusicName text not found!");
		}
		if ((Object)(object)skipButton == (Object)null)
		{
			Logger.LogWarning((object)"SkipButton not found!");
		}
		if ((Object)(object)pauseButton == (Object)null)
		{
			Logger.LogWarning((object)"PauseButton not found!");
		}
		if ((Object)(object)skipButton != (Object)null)
		{
			((UnityEvent)skipButton.onClick).AddListener(new UnityAction(SwitchTrack));
		}
		if ((Object)(object)pauseButton != (Object)null)
		{
			((UnityEvent)pauseButton.onClick).AddListener(new UnityAction(PauseMusic));
		}
		val.Unload(false);
	}

	private static void UpdateMusicNameDisplay(string trackName)
	{
		if ((Object)(object)musicNameText != (Object)null)
		{
			((TMP_Text)musicNameText).text = trackName;
			((TMP_Text)musicNameText).alpha = 1f;
			MonoBehaviour val = Object.FindObjectOfType<MonoBehaviour>();
			val.StartCoroutine(FadeOutText(musicNameText, 3f));
		}
	}

	[IteratorStateMachine(typeof(<FadeOutText>d__14))]
	private static IEnumerator FadeOutText(TextMeshProUGUI text, float duration)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <FadeOutText>d__14(0)
		{
			text = text,
			duration = duration
		};
	}

	private static void SwitchTrack()
	{
		if (mp3Files == null || mp3Files.Length == 0)
		{
			Logger.LogError((object)"No tracks available to switch!");
			return;
		}
		string text = (((Object)(object)audioSource.clip != (Object)null) ? ((Object)audioSource.clip).name : "");
		string text2;
		do
		{
			text2 = mp3Files[Random.Range(0, mp3Files.Length)];
		}
		while (Path.GetFileNameWithoutExtension(text2) == text && mp3Files.Length > 1);
		MonoBehaviour val = Object.FindObjectOfType<MonoBehaviour>();
		val.StartCoroutine(LoadAndSwitchTrack(text2));
	}

	[IteratorStateMachine(typeof(<LoadAndSwitchTrack>d__16))]
	private static IEnumerator LoadAndSwitchTrack(string mp3Path)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <LoadAndSwitchTrack>d__16(0)
		{
			mp3Path = mp3Path
		};
	}

	public static void PauseMusic()
	{
		if ((Object)(object)audioSource != (Object)null && isPlaying)
		{
			audioSource.Pause();
			isPlaying = false;
			Logger.LogWarning((object)"Music paused");
		}
	}

	public static void ResumeMusic()
	{
		if ((Object)(object)audioSource != (Object)null && !isPlaying)
		{
			audioSource.UnPause();
			isPlaying = true;
			Logger.LogWarning((object)"Music resumed");
		}
	}

	public static void StopMusic()
	{
		if ((Object)(object)audioSource != (Object)null && isPlaying)
		{
			audioSource.Stop();
			isPlaying = false;
			Logger.LogWarning((object)"Music stopped");
		}
	}
}