Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Modlist v0.3.0
Silksong.Modlist.dll
Decompiled 3 months agousing 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 System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using GlobalEnums; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Silksong.Modlist")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.0.0")] [assembly: AssemblyInformationalVersion("0.3.0+a19c8eeee9871e6970d1a696d952dd2e9626ca64")] [assembly: AssemblyProduct("Silksong.Modlist")] [assembly: AssemblyTitle("Modlist")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/silksong-modding/Silksong.Modlist")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Microsoft.CodeAnalysis.Embedded] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Microsoft.CodeAnalysis.Embedded] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Microsoft.CodeAnalysis { [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace Silksong.Modlist { public static class FileTree { public static int MAX_DEPTH = 3; private static readonly Func<string, bool>[] _excludes = new Func<string, bool>[6] { (string s) => s.EndsWith(".old"), (string s) => s == "manifest.json", (string s) => s == "icon.png", (string s) => s == "README.md", (string s) => s == "CHANGELOG.md", (string s) => s == "LICENSE" }; public static StringBuilder RenderTree(string dir, StringBuilder? builder = null, string prefix = "", int depth = 0) { if (builder == null) { builder = new StringBuilder(); } if (depth >= MAX_DEPTH) { return builder; } List<FileSystemInfo> list = (from f in new DirectoryInfo(dir).GetFileSystemInfos() orderby f.Name select f).ToList(); foreach (FileSystemInfo item in list.Take(list.Count - 1)) { RenderItem(item, builder, lastItem: false, prefix, depth); } FileSystemInfo fileSystemInfo = list.LastOrDefault(); if (fileSystemInfo != null) { RenderItem(fileSystemInfo, builder, lastItem: true, prefix, depth); } return builder; } private static bool DirContainsOnlyExcluded(DirectoryInfo dir) { if (dir.GetDirectories().Length == 0) { return dir.GetFiles().All((FileInfo info) => _excludes.Any((Func<string, bool> ex) => ex(info.Name))); } return false; } private static void RenderItem(FileSystemInfo item, StringBuilder builder, bool lastItem, string prefix = "", int depth = 0) { FileSystemInfo item2 = item; if (!_excludes.Any((Func<string, bool> ex) => ex(item2.Name.TrimEnd())) && (!item2.IsDirectory() || !DirContainsOnlyExcluded((DirectoryInfo)item2))) { string text = (item2.IsDirectory() ? "/" : null); string text2 = (lastItem ? "└── " : "├── "); builder.AppendLine(prefix + text2 + item2.Name + text); if (item2.IsDirectory()) { RenderTree(item2.FullName, builder, prefix + (lastItem ? " " : "│ "), depth + 1); } } } } public static class FileSystemInfoExtensions { public static bool IsDirectory(this FileSystemInfo listing) { return listing.Attributes.HasFlag(FileAttributes.Directory); } } public class ModListDraw : MonoBehaviour { private static readonly GUIStyle Style = new GUIStyle(GUIStyle.none); private const int DesignFontSize = 15; internal string MenuDrawString = ""; internal string PauseDrawString = ""; private string DrawString { get { //IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 UIState uiState = UIManager.instance.uiState; if ((int)uiState != 1) { if ((int)uiState == 5) { return PauseDrawString; } return ""; } return MenuDrawString; } } private static float HScale => (float)Screen.width / 1920f; private static float VScale => (float)Screen.height / 1080f; private static float ScaleFactor { get { if (!(HScale < VScale)) { return VScale; } return HScale; } } private static int ScaledFontSize => (int)(15f * ScaleFactor); private void Start() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown Style.normal.textColor = Color.white; Style.alignment = (TextAnchor)0; Style.padding = new RectOffset(5, 5, 5, 5); } public void OnGUI() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)UIManager._instance == (Object)null)) { UIState uiState = UIManager.instance.uiState; if (((int)uiState == 1 || (int)uiState == 5) ? true : false) { Style.fontSize = ScaledFontSize; GUI.Label(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), DrawString, Style); } } } } public static class Constants { public const string Guid = "org.silksong-modding.modlist"; } internal enum DisplayMode { Full, Reduced, Hidden } internal record struct PatcherMeta { public string CleanAsmName => AsmOverrides.GetValueOrDefault(AsmName, AsmName); private static Dictionary<string, string> AsmOverrides = new Dictionary<string, string> { { "0.com.github.MonoDetour.BepInEx.5", "MonoDetour" }, { "BepInEx.MonoMod.AutoHookGenPatcher", "AutoHookGenPatcher" }, { "Hamunii.DetourContext.Dispose_Fix", "DetourCtxDisposeFix" } }; public string AsmName; public string AsmVersion; public string TypeName; [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { builder.Append("AsmName = "); builder.Append((object?)AsmName); builder.Append(", AsmVersion = "); builder.Append((object?)AsmVersion); builder.Append(", TypeName = "); builder.Append((object?)TypeName); builder.Append(", CleanAsmName = "); builder.Append((object?)CleanAsmName); return true; } } [BepInPlugin("org.silksong-modding.modlist", "Modlist", "0.3.0")] public class ModlistPlugin : BaseUnityPlugin { private List<BepInPlugin> _majors = new List<BepInPlugin>(); private List<BepInPlugin> _minors = new List<BepInPlugin>(); private List<PatcherMeta> _patchers = new List<PatcherMeta>(); private GameObject? _modListGO; private ModListDraw? _modListDraw; internal ConfigEntry<DisplayMode> DisplayMode; internal ConfigEntry<bool> LogFileTree; public const string Id = "org.silksong-modding.modlist"; public string GameVersion => Constants.GetConstantValue<string>("GAME_VERSION"); public static ModlistPlugin Instance { get; private set; } public string ReducedListString => $"{ModListPrefix}\n{MajorListJoined}\n+ {_minors.Count} others\n& {_patchers.Count} patchers"; public string FullListString => ModListPrefix + "\n" + PatcherListJoined + "\n" + MajorListJoined + "\n" + MinorListJoined; private string ModListPrefix => "v" + GameVersion + "-" + Version; public List<string> MajorList => _majors.Select((BepInPlugin plugin) => $"{plugin.Name}: {plugin.Version}").ToList(); public List<string> MinorList => _minors.Select((BepInPlugin plugin) => $"{plugin.Name}: {plugin.Version}").ToList(); public List<string> PatcherList => _patchers.Select((PatcherMeta patcher) => patcher.CleanAsmName + " * : " + patcher.AsmVersion).ToList(); private string MajorListJoined => string.Join("\n", MajorList); private string MinorListJoined => string.Join("\n", MinorList); private string PatcherListJoined => string.Join("\n", PatcherList); internal string MajorNamesJoined => string.Join(", ", _majors.Select((BepInPlugin plugin) => plugin.Name ?? "")); public int ModCount => _majors.Count + _minors.Count + _patchers.Count + 1; public static string Name => "Modlist"; public static string Version => "0.3.0"; private void Awake() { Instance = this; DisplayMode = ((BaseUnityPlugin)this).Config.Bind<DisplayMode>("General", "DisplayMode", Silksong.Modlist.DisplayMode.Full, "How to display the top-left mod list. The mod count on the title screen will always be visible."); LogFileTree = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogModFiles", true, "Whether to include a filetree in LogOutput.log for troubleshooting."); _patchers = GetPatchers(); } private void Start() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Harmony.CreateAndPatchAll(typeof(ModlistPatches), (string)null); _modListGO = new GameObject("Silksong.ModList"); _modListDraw = _modListGO.AddComponent<ModListDraw>(); Object.DontDestroyOnLoad((Object)(object)_modListGO); DisplayMode.SettingChanged += delegate { GenerateModList(); }; GenerateModList(); ((BaseUnityPlugin)this).Logger.LogInfo((object)LogModLists()); if (LogFileTree.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugins Directory:\n" + FileTree.RenderTree(Paths.PluginPath))); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Patchers Directory:\n" + FileTree.RenderTree(Paths.PatcherPluginPath))); } } private string LogModLists() { StringBuilder stringBuilder = new StringBuilder("\n\n======== Modlist ========\nSilksong version: " + GameVersion + "\n"); stringBuilder.AppendLine($"PLUGINS: {_majors.Count + _minors.Count} ({_majors.Count} depend on Modlist)"); foreach (BepInPlugin item in _majors.OrderBy((BepInPlugin x) => x.Name)) { stringBuilder.AppendLine(("[ " + item.Name).PadRight(20) + $": {item.Version}".PadRight(8) + "] " + item.GUID); } foreach (BepInPlugin item2 in _minors.OrderBy((BepInPlugin x) => x.Name)) { stringBuilder.AppendLine(("[ " + item2.Name).PadRight(20) + $": {item2.Version}".PadRight(8) + "] " + item2.GUID); } stringBuilder.AppendLine($"PATCHERS: {_patchers.Count}"); foreach (PatcherMeta item3 in _patchers.OrderBy((PatcherMeta x) => x.AsmName)) { stringBuilder.AppendLine(("[ " + item3.AsmName).PadRight(40) + (": " + item3.AsmVersion).PadRight(10) + "]::" + item3.TypeName); } stringBuilder.AppendLine("========================="); return stringBuilder.ToString(); } private void GenerateModList() { (_majors, _minors) = GetPlugins(); ((Behaviour)_modListDraw).enabled = DisplayMode.Value != Silksong.Modlist.DisplayMode.Hidden; ModListDraw modListDraw = _modListDraw; modListDraw.MenuDrawString = DisplayMode.Value switch { Silksong.Modlist.DisplayMode.Hidden => "", Silksong.Modlist.DisplayMode.Reduced => ReducedListString, _ => FullListString, }; ModListDraw? modListDraw2 = _modListDraw; string pauseDrawString = ((DisplayMode.Value != Silksong.Modlist.DisplayMode.Hidden) ? ReducedListString : ""); modListDraw2.PauseDrawString = pauseDrawString; } private List<PatcherMeta> GetPatchers() { List<PatcherMeta> list = new List<PatcherMeta>(); string[] files = Directory.GetFiles(Path.GetFullPath(Paths.PatcherPluginPath), "*.dll", SearchOption.AllDirectories); foreach (string text in files) { try { AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(text, TypeLoader.ReaderParameters); IEnumerable<PatcherMeta> collection = ((IEnumerable<TypeDefinition>)asm.MainModule.Types).Where(delegate(TypeDefinition typeDef) { if (typeDef.IsInterface || (typeDef.IsAbstract && !typeDef.IsSealed)) { return false; } MethodDefinition val = ((IEnumerable<MethodDefinition>)typeDef.Methods).FirstOrDefault((Func<MethodDefinition, bool>)((MethodDefinition m) => ((MemberReference)m).Name.Equals("get_TargetDLLs", StringComparison.InvariantCultureIgnoreCase) && m.IsPublic && m.IsStatic)); return val != null && !(((MemberReference)((MethodReference)val).ReturnType).FullName != "System.Collections.Generic.IEnumerable`1<System.String>") && ((IEnumerable<MethodDefinition>)typeDef.Methods).FirstOrDefault((Func<MethodDefinition, bool>)((MethodDefinition m) => ((MemberReference)m).Name.Equals("Patch") && m.IsPublic && m.IsStatic && ((MemberReference)((MethodReference)m).ReturnType).FullName == "System.Void" && ((MethodReference)m).Parameters.Count == 1 && (((MemberReference)((ParameterReference)((MethodReference)m).Parameters[0]).ParameterType).FullName == "Mono.Cecil.AssemblyDefinition&" || ((MemberReference)((ParameterReference)((MethodReference)m).Parameters[0]).ParameterType).FullName == "Mono.Cecil.AssemblyDefinition"))) != null; }).Select(delegate(TypeDefinition typeDef) { PatcherMeta result = default(PatcherMeta); result.AsmName = ((AssemblyNameReference)asm.Name).Name; result.AsmVersion = ((AssemblyNameReference)asm.Name).Version.ToString(); result.TypeName = ((MemberReference)typeDef).Name; return result; }); list.AddRange(collection); } catch (BadImageFormatException ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Skipping loading " + text + " because it's not a valid .NET assembly. Full error: " + ex.Message)); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)ex2.ToString()); } } return list; } private (List<BepInPlugin>, List<BepInPlugin>) GetPlugins() { Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos; List<BepInPlugin> list = new List<BepInPlugin>(); List<BepInPlugin> list2 = new List<BepInPlugin>(); foreach (var (text2, val2) in pluginInfos) { if (val2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Plugin " + text2 + " has no PluginInfo, ignoring...")); } else if (!(text2 == "org.silksong-modding.modlist")) { Attribute? customAttribute = Attribute.GetCustomAttribute(((object)val2.Instance).GetType(), typeof(BepInPlugin)); BepInPlugin item = (BepInPlugin)(object)((customAttribute is BepInPlugin) ? customAttribute : null); if (val2.Dependencies.FirstOrDefault((Func<BepInDependency, bool>)((BepInDependency x) => ((Enum)x.Flags).HasFlag((Enum)(object)(DependencyFlags)1) && x.DependencyGUID == "org.silksong-modding.modlist")) != null) { list.Add(item); } else { list2.Add(item); } } } list.Sort((BepInPlugin a, BepInPlugin b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal)); list2.Sort((BepInPlugin a, BepInPlugin b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal)); return (list, list2); } } public static class ModlistPatches { [HarmonyPatch(typeof(SetVersionNumber), "Start")] [HarmonyPostfix] public static void SetVersionNumber_Start(SetVersionNumber __instance) { string text = __instance.textUi.text; text += $" | {ModlistPlugin.Instance.ModCount} Mods\n{ModlistPlugin.Instance.MajorNamesJoined}"; __instance.textUi.text = text; } } }