using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; 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: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("RadioPlus")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+11ff202d8a61f880a82902b780d183bc232704c2")] [assembly: AssemblyProduct("RadioPlus")] [assembly: AssemblyTitle("RadioPlus")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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; } } } namespace RadioPlus { [HarmonyPatch(typeof(AudioLoader), "LoadAudio")] public static class LoadAudioPatch { private static readonly HashSet Known = new HashSet { ".mp3", ".wav", ".ogg", ".flac", ".aiff", ".aif", ".m4a", ".opus", ".mod", ".it", ".s3m", ".xm" }; private static readonly HashSet Skip = new HashSet { ".meta", ".txt", ".ini", ".json", ".jpg", ".jpeg", ".png", ".gif", ".pdf", ".zip", ".rar", ".7z", ".exe", ".dll", ".lnk", ".db", ".url", ".cue", ".log", ".m3u", ".m3u8" }; private static bool Prefix(AudioLoader __instance, string path, ref IEnumerator __result) { __result = Replacement(__instance, path); return false; } private static IEnumerator Replacement(AudioLoader loader, string path) { string fileName = Path.GetFileName(path); string ext = Path.GetExtension(path).ToLowerInvariant(); if (ext.Length == 0 || Skip.Contains(ext)) { Plugin.Log.LogInfo((object)("Ignoring " + fileName)); yield break; } if (!Known.Contains(ext)) { Plugin.Log.LogInfo((object)("Trying " + fileName + " (unrecognized extension)")); } UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip("file://" + path, GuessType(ext)); try { ((DownloadHandlerAudioClip)req.downloadHandler).streamAudio = true; yield return req.SendWebRequest(); if ((int)req.result != 1) { Plugin.Log.LogWarning((object)("Skipping " + fileName + ": " + req.error)); yield break; } AudioClip clip = DownloadHandlerAudioClip.GetContent(req); if ((Object)(object)clip == (Object)null) { Plugin.Log.LogWarning((object)("Skipping " + fileName + ": no clip")); yield break; } ((Object)clip).name = fileName; loader.tracks.Add(clip); Plugin.Log.LogInfo((object)$"Loaded {fileName} — {clip.length:F2}s, {clip.samples} samples, {clip.frequency}Hz, {clip.channels}ch, state={clip.loadState}"); } finally { ((IDisposable)req)?.Dispose(); } } private static AudioType GuessType(string ext) { //IL_0012: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) return (AudioType)(ext switch { ".mp3" => 13, ".ogg" => 14, ".wav" => 20, _ => 0, }); } } [BepInPlugin("com.figrindan.radioplus", "Radio Plus", "1.0.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static ConfigEntry Shuffle; internal static ConfigEntry UnlockCustom; private void Awake() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Shuffle = ((BaseUnityPlugin)this).Config.Bind("Radio", "Shuffle", true, "Shuffle the custom radio playlist."); UnlockCustom = ((BaseUnityPlugin)this).Config.Bind("Radio", "UnlockCustomStation", true, "Give the custom radio station (88.1) full signal from the start, without activating the radio tower. Note, driving next to towers that haven't yet been activated will interrupt your listening :)"); new Harmony("com.figrindan.radioplus").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Radio Plus loaded"); } } [HarmonyPatch(typeof(RadioChannel), "GetRandomizedClone")] public static class ShufflePatch { private static readonly Random rng = new Random(); private static void Postfix(AudioClip[] __result) { if (Plugin.Shuffle.Value && __result != null && __result.Length >= 2) { for (int num = __result.Length - 1; num > 0; num--) { int num2 = rng.Next(num + 1); ref AudioClip reference = ref __result[num]; ref AudioClip reference2 = ref __result[num2]; AudioClip val = __result[num2]; AudioClip val2 = __result[num]; reference = val; reference2 = val2; } } } } [HarmonyPatch(typeof(sRadioSystem), "GetStartTimeAndClip")] public static class StartTimePatch { private static readonly ConditionalWeakTable lengthCache = new ConditionalWeakTable(); private static bool Prefix(RadioChannel channel, ref AudioClip clip, ref float __result) { if ((Object)(object)channel == (Object)null || channel.queue == null || channel.queue.Length == 0) { clip = null; __result = -1f; return false; } AudioClip[] queue = channel.queue; float num; if (lengthCache.TryGetValue(queue, out var value)) { num = (float)value; } else { num = 0f; for (int i = 0; i < queue.Length; i++) { num += queue[i].length; } lengthCache.Add(queue, num); } if (num <= 0f) { clip = null; __result = -1f; return false; } float num2 = Time.unscaledTime % num; for (int j = 0; j < queue.Length; j++) { if (num2 <= queue[j].length) { clip = queue[j]; __result = num2; return false; } num2 -= queue[j].length; } clip = null; __result = -1f; return false; } } [HarmonyPatch(typeof(RadioSignalManager), "CheckStation")] public static class UnlockPatch { private static void Postfix(RadioSignalManager __instance, int index) { if (!Plugin.UnlockCustom.Value) { return; } object? value = AccessTools.Field(typeof(RadioSignalManager), "radio").GetValue(__instance); sRadioSystem val = (sRadioSystem)((value is sRadioSystem) ? value : null); if (!((Object)(object)val == (Object)null) && index < val.channels.Count) { RadioChannel val2 = val.channels[index]; if (val2.externalTracks != null && val2.externalTracks.Count != 0) { val2.signal = 1f; } } } } }