using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Steamworks; 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("PlaylistFromCollection")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("PlaylistFromCollection")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4989fb15-1650-4253-90f9-444ecbcf43a2")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace PlaylistFromCollection { public static class CollectionHandler { public static bool ValidateUrl(string url, out string errorMessage) { if (url.StartsWith("https://steamcommunity.com/sharedfiles/filedetails/?id=")) { Regex regex = new Regex("^(https:\\/\\/steamcommunity\\.com\\/sharedfiles\\/filedetails\\/\\?id=)\\d*$"); if (regex.IsMatch(url)) { errorMessage = "THERE WAS NO ERROR YIPPEE!!!"; return true; } errorMessage = "THIS STEAM LINK IS NOT A WORKSHOP ITEM"; return false; } if (url.StartsWith("https:")) { errorMessage = "THIS LINK IS NOT A VALID LINK"; return false; } if (url == "") { errorMessage = "YOU DIDN'T SUBMIT ANYTHING"; return false; } errorMessage = "CANNOT PARSE. PLEASE TRY AGAIN"; return false; } public static IEnumerator ParseCollection(string url) { MenuPanelManager MPM = G.Sys.MenuPanelManager_; SteamworksUGC UGC = G.Sys.SteamworksManager_.UGC_; UGC.SetupSteamProgressText("Downloading Playlist..."); UGC.progressBar_.value = 0f; UnityWebRequest request = new UnityWebRequest(url); request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); request.method = "GET"; yield return request.Send(); if (request.isError) { Mod.Log.LogError((object)"Failed to request the link!"); string error = request.error; if (error == null) { error = "Unknown Error!"; } Mod.Log.LogError((object)error); MPM.ShowError("Failed to connect to the web page", "Error", (OnButtonClicked)null, (Pivot)4); MPM.MenuInputEnabled_ = true; UGC.DestroySteamProgressText(); yield break; } UGC.ProgressTextLabel_.text = "Parsing the web page..."; UGC.progressBar_.value = 0.5f; Mod.Instance.collectionIDs = new Dictionary(); Mod.Instance.playlistTitle = string.Empty; try { string requestHTML = request.downloadHandler.text; if (!requestHTML.Contains("Collections")) { MPM.ShowError("This Workshop link is not a Distance Workshop Collection link! \nPlease submit a link that is a Distance Workshop Collection", "Error", (OnButtonClicked)null, (Pivot)4); MPM.MenuInputEnabled_ = true; UGC.DestroySteamProgressText(); yield break; } Regex MatchAllIDs = new Regex("(?<={\"id\":\")\\d*"); if (MatchAllIDs.IsMatch(requestHTML)) { MatchCollection matchIDs = MatchAllIDs.Matches(requestHTML); WorkshopLevelInfo wInfo = default(WorkshopLevelInfo); foreach (Match mID in matchIDs) { Mod.Log.LogInfo((object)("ID Found: " + mID.Value)); bool levelInstalled = false; try { levelInstalled = UGC.storedPublishedFileIDs_.TryGetWorkshopLevelInfo((ulong)Convert.ToInt64(mID.Value), ref wInfo); if (!string.IsNullOrEmpty(wInfo.title_)) { Mod.Log.LogInfo((object)("Level Already Installed: " + wInfo.title_)); } } catch (Exception) { Mod.Log.LogWarning((object)"Level is not already installed: Will attempt to download"); } Mod.Instance.collectionIDs.Add((ulong)Convert.ToInt64(mID.Value), levelInstalled); wInfo = null; } } else { Mod.Log.LogWarning((object)"Failed to find any level IDs in the collection"); } Regex matchTitle = new Regex("(?<=
).*(?=
)"); if (matchTitle.IsMatch(requestHTML)) { Match mTitle = matchTitle.Match(requestHTML); Mod.Log.LogInfo((object)("Title: " + mTitle.Value)); Mod.Instance.playlistTitle = mTitle.Value; } if (Mod.Instance.collectionIDs.Count == 0) { MPM.ShowError("This collection has no levels!", "Error", (OnButtonClicked)null, (Pivot)4); MPM.MenuInputEnabled_ = true; UGC.DestroySteamProgressText(); yield break; } } catch (Exception ex2) { Exception e = ex2; Mod.Log.LogError((object)"Encountered an error when parsing the link!"); string error2 = e.ToString(); if (error2 == null) { error2 = "Unknown Error!"; } Mod.Log.LogError((object)error2); MPM.ShowError("Failed to parse the web page", "Error", (OnButtonClicked)null, (Pivot)4); MPM.MenuInputEnabled_ = true; UGC.DestroySteamProgressText(); yield break; } List pFileIds = new List(); foreach (KeyValuePair kvp in Mod.Instance.collectionIDs) { if (!kvp.Value) { Mod.Log.LogInfo((object)("Level ID to Download: " + kvp.Key)); pFileIds.Add(new PublishedFileId_t(kvp.Key)); } } if (pFileIds.Count > 0) { Mod.Log.LogInfo((object)"Beginning download process..."); UGC.StartWorkshopLevelsUpdate((WorkshopUpdateType)1, pFileIds.ToArray(), new OnPanelPop(ConvertLevelsToPlaylist), (OnPanelPop)delegate { MPM.ShowError("Failed to download workshop levels from the collection", "Error", (OnButtonClicked)null, (Pivot)4); }); } else { ConvertLevelsToPlaylist(); } MPM.MenuInputEnabled_ = true; UGC.DestroySteamProgressText(); } private static void ConvertLevelsToPlaylist() { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) MenuPanelManager menuPanelManager_ = G.Sys.MenuPanelManager_; SteamworksUGC uGC_ = G.Sys.SteamworksManager_.UGC_; List list = new List(); Mod.Log.LogInfo((object)"Preparing to create playlist..."); WorkshopLevelInfo val = default(WorkshopLevelInfo); foreach (KeyValuePair collectionID in Mod.Instance.collectionIDs) { uGC_.storedPublishedFileIDs_.TryGetWorkshopLevelInfo(collectionID.Key, ref val); if (val.tags_.Contains(((object)Unsafe.As(ref Mod.Instance.playlistGameMode)/*cast due to .constrained prefix*/).ToString())) { Mod.Log.LogInfo((object)("Level Title: " + val.title_ + " Path: " + Resource.GetAbsoluteLevelPath(val.relativePath_))); list.Add(new LevelNameAndPathPair(val.title_, Resource.GetAbsoluteLevelPath(val.relativePath_))); continue; } Mod.Log.LogWarning((object)("Level " + val.title_ + " is not " + ((object)Unsafe.As(ref Mod.Instance.playlistGameMode)/*cast due to .constrained prefix*/).ToString() + " Mode. Skipping")); } if (list.Count > 0) { Mod.Log.LogInfo((object)"Creating Playlist..."); LevelSet val2 = new LevelSet(); val2.resourcesLevelNameAndPathPairsInSet_ = list; LevelPlaylist val3 = LevelPlaylist.Create(val2, Mod.Instance.playlistTitle, Mod.Instance.playlistGameMode); val3.Awake(); val3.Save(); menuPanelManager_.ShowError("Return to the main menu to refresh the menu list", "Playlist Installed", (OnButtonClicked)null, (Pivot)4); } else { Mod.Log.LogWarning((object)"None of the levels were the correct mode! No Playlist Created"); menuPanelManager_.ShowError("The collection had no " + ((object)Unsafe.As(ref Mod.Instance.playlistGameMode)/*cast due to .constrained prefix*/).ToString() + " Mode levels.", "Playlist Error", (OnButtonClicked)null, (Pivot)4); } } } [BepInPlugin("Distance.PlaylistFromCollection", "Playlist From Collection", "1.0.0")] public class Mod : BaseUnityPlugin { private const string modGUID = "Distance.PlaylistFromCollection"; private const string modName = "Playlist From Collection"; private const string modVersion = "1.0.0"; public string playlistTitle; public GameModeID playlistGameMode = (GameModeID)1; private static readonly Harmony harmony = new Harmony("Distance.PlaylistFromCollection"); public static ManualLogSource Log = new ManualLogSource("Playlist From Collection"); public static Mod Instance; public Dictionary collectionIDs { get; set; } = new Dictionary(); private void Awake() { Object.DontDestroyOnLoad((Object)(object)this); if ((Object)(object)Instance == (Object)null) { Instance = this; } Log = Logger.CreateLogSource("Distance.PlaylistFromCollection"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Initializing Playlist From Collections..."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading..."); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded!"); } public void OnConfigChanged(object sender, EventArgs e) { SettingChangedEventArgs e2 = (SettingChangedEventArgs)(object)((e is SettingChangedEventArgs) ? e : null); if (e2 != null) { } } } } namespace PlaylistFromCollection.Patches { [HarmonyPatch(typeof(LevelGridMenu), "CreateEntries")] internal static class LevelGridMenu__CreateEntries { private class AddPlaylistEntry : PlaylistEntry { private LevelGridMenu gridMenu; public AddPlaylistEntry(LevelGridMenu menu, LevelPlaylist playlist) : base(menu, "Add Playlist", playlist, (Type)0, false, (UnlockStyle)7, true) { gridMenu = menu; } public override void OnClick() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0024: Expected O, but got Unknown InputPromptPanel.Create(new OnSubmit(SearchCollectionOnSteam), new OnPop(InputPop), "Enter Playlist Link:", (string)null); ((Component)gridMenu).gameObject.SetActive(false); } private bool SearchCollectionOnSteam(out string errorMessage, string input) { if (CollectionHandler.ValidateUrl(input, out errorMessage)) { ((MonoBehaviour)Mod.Instance).StartCoroutine(CollectionHandler.ParseCollection(input)); return true; } return false; } private void InputPop() { ((Component)gridMenu).gameObject.SetActive(true); } } [HarmonyPostfix] internal static void CustomPlaylist(LevelGridMenu __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Invalid comparison between Unknown and I4 //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Invalid comparison between Unknown and I4 //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Invalid comparison between Unknown and I4 //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_010f: 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_0134: Unknown result type (might be due to invalid IL or missing references) bool flag = (int)((LevelSelectMenuAbstract)__instance).displayType_ == 0 || (int)((LevelSelectMenuAbstract)__instance).displayType_ == 1; bool flag2 = (int)((LevelSelectMenuAbstract)__instance).displayType_ == 2; bool flag3 = (int)__instance.modeID_ == 1; bool flag4 = (int)__instance.modeID_ == 8; bool flag5 = (int)__instance.modeID_ == 2; bool flag6 = (int)__instance.modeID_ == 5; bool flag7 = (int)__instance.modeID_ == 13; if (!flag) { return; } string[] legacyFileNames_ = G.Sys.LevelSets_.LegacyFileNames_; List allLevelNameAndPathPairs = G.Sys.LevelSets_.GetSet((GameModeID)1).GetAllLevelNameAndPathPairs(); LevelSet val = new LevelSet(); for (int i = 0; i < allLevelNameAndPathPairs.Count; i++) { string fileNameWithoutExtension = Resource.GetFileNameWithoutExtension(allLevelNameAndPathPairs[i].levelPath_); if (legacyFileNames_.Contains(fileNameWithoutExtension)) { val.AddLevel(allLevelNameAndPathPairs[i].levelName_, Resource.GetAbsoluteOfficialLevelPath(fileNameWithoutExtension), (LevelType)2, (string)null); break; } } if (val.ResourcesLevelsCount_ > 0) { __instance.AddEntry((PlaylistEntry)(object)new AddPlaylistEntry(__instance, LevelPlaylist.Create(val, "Add Playlist", __instance.modeID_)), ""); Mod.Instance.playlistGameMode = __instance.modeID_; Mod.Log.LogInfo((object)("Mode ID: " + ((object)Unsafe.As(ref __instance.modeID_)/*cast due to .constrained prefix*/).ToString())); } ((UIExButtonContainer)__instance.buttonList_).SortAndUpdateVisibleButtons(); } } }