Decompiled source of BlueprintSort v1.0.1

plugins/BlueprintSort.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
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.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BlueprintSort")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("BlueprintSort")]
[assembly: AssemblyTitle("BlueprintSort")]
[assembly: AssemblyVersion("1.0.1.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 BlueprintSort
{
	public enum SortMode
	{
		Name,
		Updated,
		Created
	}
	[BepInPlugin("com.quantumcreation.dsp.blueprintsort", "Blueprint Sort", "1.0.1")]
	[BepInProcess("DSPGAME.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.quantumcreation.dsp.blueprintsort";

		public const string Version = "1.0.1";

		internal static ManualLogSource Log;

		internal static ConfigEntry<SortMode> Mode;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Mode = ((BaseUnityPlugin)this).Config.Bind<SortMode>("General", "SortOrder", SortMode.Updated, "Order of the Blueprint Library. Name = the game's alphabetical order, Updated = most recently saved first, Created = most recently created first. The Sort button in the library cycles through these.");
			Harmony.CreateAndPatchAll(typeof(BrowserPatch), "com.quantumcreation.dsp.blueprintsort");
		}
	}
	[HarmonyPatch(typeof(UIBlueprintBrowser))]
	internal static class BrowserPatch
	{
		private static Button sortButton;

		private static Text sortLabel;

		[HarmonyTranspiler]
		[HarmonyPatch("SetCurrentDirectory")]
		private static IEnumerable<CodeInstruction> SortListings(IEnumerable<CodeInstruction> instructions)
		{
			Type[] array = new Type[3]
			{
				typeof(string),
				typeof(string),
				typeof(SearchOption)
			};
			MethodInfo getDirs = AccessTools.Method(typeof(Directory), "GetDirectories", array, (Type[])null);
			MethodInfo getFiles = AccessTools.Method(typeof(Directory), "GetFiles", array, (Type[])null);
			int replaced = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, getDirs))
				{
					instruction.operand = AccessTools.Method(typeof(BrowserPatch), "GetDirectories", (Type[])null, (Type[])null);
					replaced++;
				}
				else if (CodeInstructionExtensions.Calls(instruction, getFiles))
				{
					instruction.operand = AccessTools.Method(typeof(BrowserPatch), "GetFiles", (Type[])null, (Type[])null);
					replaced++;
				}
				yield return instruction;
			}
			if (replaced != 2)
			{
				Plugin.Log.LogWarning((object)$"Expected 2 directory listings in SetCurrentDirectory, patched {replaced}");
			}
		}

		public static string[] GetDirectories(string path, string pattern, SearchOption option)
		{
			return Sort(Directory.GetDirectories(path, pattern, option), isDir: true);
		}

		public static string[] GetFiles(string path, string pattern, SearchOption option)
		{
			return Sort(Directory.GetFiles(path, pattern, option), isDir: false);
		}

		private static string[] Sort(string[] paths, bool isDir)
		{
			SortMode mode = Plugin.Mode.Value;
			if (mode == SortMode.Name || paths.Length < 2)
			{
				return paths;
			}
			try
			{
				return paths.OrderByDescending((string p) => Stamp(p, isDir, mode)).ThenBy<string, string>((string p) => p, StringComparer.OrdinalIgnoreCase).ToArray();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Sorting failed, keeping name order: " + ex.Message));
				return paths;
			}
		}

		private static DateTime Stamp(string path, bool isDir, SortMode mode)
		{
			if (!isDir)
			{
				return Time(new FileInfo(path), mode);
			}
			DirectoryInfo directoryInfo = new DirectoryInfo(path);
			DateTime dateTime = Time(directoryInfo, mode);
			FileInfo[] files = directoryInfo.GetFiles("*.txt", SearchOption.AllDirectories);
			for (int i = 0; i < files.Length; i++)
			{
				DateTime dateTime2 = Time(files[i], mode);
				if (dateTime2 > dateTime)
				{
					dateTime = dateTime2;
				}
			}
			return dateTime;
		}

		private static DateTime Time(FileSystemInfo info, SortMode mode)
		{
			if (mode != SortMode.Created)
			{
				return info.LastWriteTimeUtc;
			}
			return info.CreationTimeUtc;
		}

		[HarmonyPostfix]
		[HarmonyPriority(200)]
		[HarmonyPatch("_OnCreate")]
		private static void AddSortButton(UIBlueprintBrowser __instance)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Expected O, but got Unknown
			Button val = ((IEnumerable<Button>)((Component)__instance).GetComponentsInChildren<Button>(true)).FirstOrDefault((Func<Button, bool>)IsShowInExplorer);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Show in Explorer button not found; sort only via config");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent, false);
			((Object)val2).name = "blueprint-sort-button";
			Localizer[] componentsInChildren = val2.GetComponentsInChildren<Localizer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			RectTransform val3 = (RectTransform)val2.transform;
			RectTransform val4 = (RectTransform)((Component)val).transform;
			Rect rect = val4.rect;
			float num = ((Rect)(ref rect)).width + 6f;
			val3.anchoredPosition = val4.anchoredPosition - new Vector2(num, 0f);
			if (!((Transform)val4).IsChildOf((Transform)(object)__instance.addrTrans))
			{
				RectTransform addrTrans = __instance.addrTrans;
				addrTrans.offsetMax -= new Vector2(num, 0f);
			}
			UIButton component = val2.GetComponent<UIButton>();
			if ((Object)(object)component != (Object)null)
			{
				component.tips.tipTitle = "Blueprint sort order";
				component.tips.tipText = "Click to switch between name, last updated and date created.";
			}
			sortButton = val2.GetComponent<Button>();
			sortButton.onClick = new ButtonClickedEvent();
			((UnityEvent)sortButton.onClick).AddListener((UnityAction)delegate
			{
				Cycle(__instance);
			});
			sortLabel = val2.GetComponentInChildren<Text>(true);
			UpdateLabel();
		}

		private static bool IsShowInExplorer(Button b)
		{
			for (int i = 0; i < ((UnityEventBase)b.onClick).GetPersistentEventCount(); i++)
			{
				if (((UnityEventBase)b.onClick).GetPersistentMethodName(i) == "ShowInExplorer")
				{
					return true;
				}
			}
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch("_OnOpen")]
		private static void OnOpen()
		{
			UpdateLabel();
		}

		private static void Cycle(UIBlueprintBrowser browser)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Mode.Value = (SortMode)((int)(Plugin.Mode.Value + 1) % 3);
			UpdateLabel();
			if (browser.currentDirectoryInfo != null)
			{
				browser.SetCurrentDirectory(browser.currentDirectoryInfo.FullName);
			}
			VFAudio.Create("ui-click-1", (Transform)null, Vector3.zero, true, 1, -1, -1L);
		}

		private static void UpdateLabel()
		{
			if (!((Object)(object)sortLabel == (Object)null))
			{
				switch (Plugin.Mode.Value)
				{
				case SortMode.Updated:
					sortLabel.text = "Sort: Updated";
					break;
				case SortMode.Created:
					sortLabel.text = "Sort: Created";
					break;
				default:
					sortLabel.text = "Sort: Name";
					break;
				}
			}
		}
	}
}