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");
}
}
}