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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Networking;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("LC_CruiserTunes")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LC_CruiserTunes")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("98830a3d-1b1a-47c1-bd5a-429e781a4830")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
public class CarPatch
{
public static float checkTimer;
public static Type type = typeof(VehicleController);
public static FieldInfo radioOnField = type.GetField("radioOn", BindingFlags.Instance | BindingFlags.NonPublic);
[HarmonyPatch(typeof(VehicleController), "Awake")]
[HarmonyPostfix]
public static void AwakePatch(VehicleController __instance)
{
if (CruiserTunesMod.HasSongs)
{
AudioClip[] source = ((!CruiserTunesMod.IncludeOriginal.Value) ? CruiserTunesMod.CustomSongs : __instance.radioClips.Concat(CruiserTunesMod.CustomSongs).ToArray());
source = source.OrderByDescending((AudioClip str) => GetAsciiSum(((Object)str).name)).ToArray();
__instance.radioClips = source;
__instance.radioAudio.loop = CruiserTunesMod.DoLoop.Value;
((MonoBehaviour)__instance).StartCoroutine(AudioSourceListener(__instance.radioAudio, __instance));
}
static int GetAsciiSum(string str)
{
return str.Sum((char c) => c);
}
}
public static void UpdateLooping(object sender, EventArgs e)
{
Object.FindObjectOfType<VehicleController>().radioAudio.loop = CruiserTunesMod.DoLoop.Value;
}
public static void ChangeVolume(object sender, EventArgs e)
{
Object.FindObjectOfType<VehicleController>().radioAudio.volume = Mathf.Clamp(CruiserTunesMod.Volume.Value, 0f, 1.25f);
}
[HarmonyPatch(typeof(VehicleController), "ChangeRadioStation")]
[HarmonyPostfix]
public static void ChangeRadioStationPatch(VehicleController __instance)
{
if (!CruiserTunesMod.DoRandomTime.Value)
{
__instance.radioAudio.time = 0f;
}
}
[HarmonyPatch(typeof(VehicleController), "SetRadioOnLocalClient")]
[HarmonyPrefix]
public static void SetOnClientPatch(VehicleController __instance)
{
Type type = ((object)__instance).GetType();
FieldInfo field = type.GetField("currentRadioClip", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(__instance, (int)field.GetValue(__instance) % __instance.radioClips.Length);
if (!CruiserTunesMod.DoRandomTime.Value)
{
__instance.radioAudio.time = 0f;
}
}
[HarmonyPatch(typeof(VehicleController), "SetRadioValues")]
[HarmonyPrefix]
public static void SetRadioValuesPatch(VehicleController __instance)
{
if (CruiserTunesMod.GoodQuality.Value)
{
__instance.radioAudio.volume = 1f;
__instance.radioInterference.volume = 0f;
}
}
[HarmonyPatch(typeof(VehicleController), "SwitchRadio")]
[HarmonyPrefix]
public static void SwitchRadioPatch(VehicleController __instance)
{
if (!CruiserTunesMod.DoRandomTime.Value)
{
__instance.radioAudio.time = 0f;
}
}
[HarmonyPatch(typeof(VehicleController), "SetRadioStationClientRpc")]
[HarmonyPostfix]
public static void SetRadioStationPatch(ref int radioStation, VehicleController __instance)
{
__instance.radioAudio.clip = __instance.radioClips[radioStation];
__instance.radioAudio.Play();
}
public static IEnumerator AudioSourceListener(AudioSource radio, VehicleController instance)
{
while (true)
{
AudioClip clip = radio.clip;
instance.radioAudio.loop = CruiserTunesMod.DoLoop.Value;
yield return null;
if ((Object)(object)clip != (Object)(object)radio.clip)
{
if (!CruiserTunesMod.DoRandomTime.Value)
{
radio.time = 0f;
}
if (CruiserTunesMod.GoodQuality.Value)
{
radio.volume = 1f;
instance.radioInterference.volume = 0f;
}
((MonoBehaviour)instance).StartCoroutine(PlayNotification(instance));
}
}
}
public static IEnumerator PlayNotification(VehicleController instance)
{
if (CruiserTunesMod.DoMessage.Value)
{
AudioClip clip = instance.radioAudio.clip;
yield return (object)new WaitForSeconds(2f);
if ((Object)(object)clip == (Object)(object)instance.radioAudio.clip && Vector3.Distance(((Component)StartOfRound.Instance.localPlayerController).transform.position, ((Component)instance).transform.position) < 10f)
{
HUDManager.Instance.DisplayTip("Now Playing:", ((Object)clip).name.Replace("Radio_", "") + " - " + FormatLength(clip.length), false, false, "LC_Tip1");
}
}
}
public static string FormatLength(float lengthInSeconds)
{
int num = Mathf.FloorToInt(lengthInSeconds / 3600f);
int num2 = Mathf.FloorToInt(lengthInSeconds % 3600f / 60f);
int num3 = Mathf.FloorToInt(lengthInSeconds % 60f);
return $"{num:00}:{num2:00}:{num3:00}";
}
public static void ChangeRadioStationWithoutServer(VehicleController instance)
{
Type type = ((object)instance).GetType();
FieldInfo field = type.GetField("radioSignalDecreaseThreshold", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field2 = type.GetField("radioSignalQuality", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field3 = type.GetField("currentRadioClip", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field4 = type.GetField("currentSongTime", BindingFlags.Instance | BindingFlags.NonPublic);
int num = ((int)field3.GetValue(instance) + 1) % instance.radioClips.Length;
field3.SetValue(instance, num);
instance.radioAudio.clip = instance.radioClips[num];
instance.radioAudio.time = Mathf.Clamp((float)field4.GetValue(instance) % instance.radioAudio.clip.length, 0.01f, instance.radioAudio.clip.length - 0.1f);
instance.radioAudio.Play();
float num2 = 10f;
float num3 = (float)field2.GetValue(instance);
switch ((int)Mathf.Round(num3))
{
case 3:
num3 = 1f;
num2 = 10f;
break;
case 0:
num3 = 3f;
num2 = 90f;
break;
case 1:
num3 = 2f;
num2 = 70f;
break;
case 2:
num3 = 1f;
num2 = 30f;
break;
}
field2.SetValue(instance, num3);
field.SetValue(instance, num2);
ChangeRadioStationPatch(instance);
}
}
[BepInPlugin("Mellowdy.CruiserTunes", "CruiserTunes", "1.3.0")]
public class CruiserTunesMod : BaseUnityPlugin
{
private const string modGUID = "Mellowdy.CruiserTunes";
private const string modName = "CruiserTunes";
private const string modVersion = "1.3.0";
private readonly Harmony harmony = new Harmony("Mellowdy.CruiserTunes");
public static ManualLogSource mls;
public static CruiserTunesMod instance;
public static ConfigEntry<bool> IncludeOriginal;
public static ConfigEntry<bool> DoMessage;
public static ConfigEntry<bool> DoLoop;
public static ConfigEntry<bool> DoRandomTime;
public static ConfigEntry<bool> GoodQuality;
public static ConfigEntry<float> Volume;
public static bool HasSongs;
public static AudioClip[] CustomSongs;
private const string supportedAudioFileTypes = ".mp3 or .wav or .ogg";
private string folderName = "CustomSongs";
private string altFolderName = "Custom Songs";
private List<AudioClip> SongList = new List<AudioClip>();
private bool[] loadingList;
private void Awake()
{
if ((Object)(object)instance == (Object)null)
{
instance = this;
}
mls = Logger.CreateLogSource("Mellowdy.CruiserTunes");
mls.LogInfo((object)"Loading...");
Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
IncludeOriginal = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Include Original Songs", true, "The radio is able to play the orignal songs");
DoMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Notify When New Song", true, "The radio notifies nearby players what song is now playing");
DoLoop = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Loop", false, "The radio loops songs upon completion");
DoLoop.SettingChanged += CarPatch.UpdateLooping;
DoRandomTime = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Random Start Time", false, "The randomly picks a point in the song to start playing when switching channels");
GoodQuality = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Always have good quality", true, "When switching between channels the quality will remain good");
Volume = ((BaseUnityPlugin)this).Config.Bind<float>("Settings", "Volume", 0.75f, "Volume of the radio (does not require restart)");
Volume.SettingChanged += CarPatch.ChangeVolume;
string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string text = Path.Combine(directoryName, folderName);
List<string> list = new List<string>();
List<string> list2 = new List<string>();
string text2 = Path.Combine(Directory.GetParent(directoryName).FullName, folderName);
string text3 = Path.Combine(Directory.GetParent(directoryName).FullName, altFolderName);
if (Directory.Exists(text2))
{
list.Add(text2);
}
else if (Directory.Exists(text3))
{
list.Add(text3);
}
string text4 = Path.Combine(Directory.GetParent(directoryName).Parent.FullName, altFolderName);
if (Directory.Exists(text4))
{
list.Add(text4);
}
string[] directories = Directory.GetDirectories(Directory.GetParent(directoryName).FullName);
foreach (string path in directories)
{
string text5 = Path.Combine(path, folderName);
if (Directory.Exists(text5))
{
list.Add(text5);
}
}
if (list.Count == 0)
{
Directory.CreateDirectory(text);
mls.LogWarning((object)("Folder not found. One has been created at: '" + text + "'"));
return;
}
foreach (string item in list)
{
list2.AddRange(Directory.GetFiles(item));
}
list2 = RemoveDuplicateFiles(list2);
bool flag = false;
loadingList = new bool[list2.Count];
for (int j = 0; j < list2.Count; j++)
{
string text6 = list2[j];
loadingList[j] = false;
string fileName = Path.GetFileName(text6);
string text7 = Path.GetExtension(text6).ToLower();
if (text7 == ".mp3" || text7 == ".wav" || text7 == ".ogg")
{
((MonoBehaviour)this).StartCoroutine(LoadAudioClip(text6, j, text7));
continue;
}
loadingList[j] = true;
if (text7 != ".old")
{
mls.LogWarning((object)(fileName + " is of invalid extention. Must be a .mp3 or .wav or .ogg file or .old file"));
if (!flag)
{
mls.LogWarning((object)".old files ignore this message being printed.");
}
flag = true;
}
}
if (loadingList.Length == 0)
{
mls.LogError((object)"No songs found");
}
harmony.PatchAll();
harmony.PatchAll(typeof(CarPatch));
((MonoBehaviour)this).StartCoroutine(EndOfPatch());
}
private static IEnumerator EndOfPatch()
{
mls.LogInfo((object)("Loading " + instance.loadingList.Length + " songs"));
bool finishedLoading = false;
while (!finishedLoading)
{
finishedLoading = true;
bool[] array = instance.loadingList;
for (int i = 0; i < array.Length; i++)
{
if (!array[i])
{
finishedLoading = false;
break;
}
}
if (!finishedLoading)
{
yield return null;
}
}
instance.loadingList = null;
mls.LogInfo((object)("Finished loading songs, final song count at:" + instance.SongList.Count));
if (instance.SongList.Count == 0)
{
string currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string path = Path.Combine(currentDirectory, instance.folderName).Replace("\\", "/");
mls.LogError((object)"No songs found in folder");
mls.LogError((object)("Make sure to add any .mp3 or .wav or .ogg files you want as songs to: '" + path + "'"));
}
CustomSongs = instance.SongList.ToArray();
instance.SongList.Clear();
HasSongs = CustomSongs.Length != 0 || IncludeOriginal.Value;
mls.LogInfo((object)"CruiserTunes has been loaded");
}
private static IEnumerator LoadAudioClip(string filePath, int index, string fileType)
{
float loadingTime = Time.time;
float maxLoading = 5f;
string fileName = Path.GetFileName(filePath);
mls.LogInfo((object)("Loading " + fileName));
AudioType audioType = GetAudioType(fileType);
UnityWebRequest loader = UnityWebRequestMultimedia.GetAudioClip(filePath, audioType);
try
{
loader.SendWebRequest();
while (!loader.isDone)
{
if (loadingTime + maxLoading < Time.time)
{
mls.LogError((object)("Error loading clip from path: " + fileName));
instance.loadingList[index] = true;
yield break;
}
yield return null;
}
instance.loadingList[index] = true;
if (loader.error != null)
{
mls.LogError((object)("Error loading clip from path: " + fileName + "\n" + loader.error));
yield break;
}
AudioClip content = DownloadHandlerAudioClip.GetContent(loader);
((Object)content).name = fileName;
instance.SongList.Add(content);
}
finally
{
((IDisposable)loader)?.Dispose();
}
}
public static AudioType GetAudioType(string fileType)
{
//IL_0030: 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_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_003f: Unknown result type (might be due to invalid IL or missing references)
return (AudioType)(fileType switch
{
".mp3" => 13,
".wav" => 20,
".ogg" => 14,
_ => 13,
});
}
public static List<string> RemoveDuplicateFiles(List<string> filePaths)
{
HashSet<string> hashSet = new HashSet<string>();
List<string> list = new List<string>();
foreach (string filePath in filePaths)
{
string fileName = Path.GetFileName(filePath);
if (!hashSet.Contains(fileName))
{
hashSet.Add(fileName);
list.Add(filePath);
}
}
return list;
}
}