Decompiled source of Playlist From Collection v1.0.0

PlaylistFromCollection.dll

Decompiled 3 hours ago
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<ulong, bool>();
			Mod.Instance.playlistTitle = string.Empty;
			try
			{
				string requestHTML = request.downloadHandler.text;
				if (!requestHTML.Contains("<span class=\"breadcrumb_separator\">&gt;&nbsp;</span><a data-panel=\"{&quot;noFocusRing&quot;:true}\" href=\"https://steamcommunity.com/workshop/browse/?section=collections&appid=233610\">Collections</a>"))
				{
					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("(?<=<div class=\"workshopItemTitle\">).*(?=</div>)");
				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<PublishedFileId_t> pFileIds = new List<PublishedFileId_t>();
			foreach (KeyValuePair<ulong, bool> 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<LevelNameAndPathPair> list = new List<LevelNameAndPathPair>();
			Mod.Log.LogInfo((object)"Preparing to create playlist...");
			WorkshopLevelInfo val = default(WorkshopLevelInfo);
			foreach (KeyValuePair<ulong, bool> collectionID in Mod.Instance.collectionIDs)
			{
				uGC_.storedPublishedFileIDs_.TryGetWorkshopLevelInfo(collectionID.Key, ref val);
				if (val.tags_.Contains(((object)Unsafe.As<GameModeID, GameModeID>(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<GameModeID, GameModeID>(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<GameModeID, GameModeID>(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<ulong, bool> collectionIDs { get; set; } = new Dictionary<ulong, bool>();

		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<LevelNameAndPathPair> 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<GameModeID, GameModeID>(ref __instance.modeID_)/*cast due to .constrained prefix*/).ToString()));
			}
			((UIExButtonContainer)__instance.buttonList_).SortAndUpdateVisibleButtons();
		}
	}
}