using System; using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Mono.Cecil; using Raylib_CsLo; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; [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("Preloading_Splash_Preloader")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Preloading_Splash_Preloader")] [assembly: AssemblyTitle("Preloading_Splash_Preloader")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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; } } } public static class QADLogger { [Conditional("DEBUG")] public static void Log(object message) { Console.WriteLine(message.ToString()); } } public class SplashWindow { public static float Progress = 0f; public static bool Close = false; public static bool TestMode = false; public static string Message = "Loading..."; private int _width; private int _height; private int _fps; private bool _showLoadingBar; private bool _showLoadingInfo; private float _windowScale; private float _loadingTextScale; public static string ConfigFolderPath => Path.Combine(Paths.ConfigPath, "PreloadingSplash"); public static string VertexShaderPath => Path.Combine(ConfigFolderPath, "vertex.vs"); public static string FragmentShaderPath => Path.Combine(ConfigFolderPath, "fragment.fs"); public static string ConfigPath => Path.Combine(ConfigFolderPath, "Config.txt"); public static string FontPath => Path.Combine(ConfigFolderPath, "Font.ttf"); public static string CoversPath => Path.Combine(ConfigFolderPath, "Covers"); public static bool ForceWait { get; internal set; } = false; public static bool IsDone { get; internal set; } = false; public bool IsAlive { get; protected set; } public bool Loaded { get; protected set; } public void RecalculateSize(int imageWidth, int imageHeight) { int currentMonitor = Raylib.GetCurrentMonitor(); int monitorWidth = Raylib.GetMonitorWidth(currentMonitor); int monitorHeight = Raylib.GetMonitorHeight(currentMonitor); float num = (float)monitorWidth / Math.Clamp(imageWidth, 1f, float.MaxValue); float num2 = (float)imageWidth * num; float num3 = (float)imageHeight * num; float num4 = (float)monitorHeight / Math.Clamp(imageHeight, 1f, float.MaxValue); float num5 = (float)imageWidth * num4; float num6 = (float)imageHeight * num4; if (num2 > (float)monitorWidth || num3 > (float)monitorHeight) { _width = (int)(num2 * _windowScale); _height = (int)(num3 * _windowScale); } else { _width = (int)(num5 * _windowScale); _height = (int)(num6 * _windowScale); } _width = Math.Clamp(_width, 1, int.MaxValue); _height = Math.Clamp(_height, 1, int.MaxValue); Raylib.SetWindowSize(_width, _height); Vector2 monitorPosition = Raylib.GetMonitorPosition(currentMonitor); Raylib.SetWindowPosition((int)(monitorPosition.X + (float)monitorWidth / 2f - (float)_width / 2f), (int)(monitorPosition.Y + (float)monitorHeight / 2f - (float)_height / 2f)); } public unsafe SplashWindow() { //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_044d: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_04ac: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_08ca: Unknown result type (might be due to invalid IL or missing references) //IL_08d7: Unknown result type (might be due to invalid IL or missing references) //IL_0524: Unknown result type (might be due to invalid IL or missing references) //IL_0529: Unknown result type (might be due to invalid IL or missing references) //IL_08f0: Unknown result type (might be due to invalid IL or missing references) //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_0659: Unknown result type (might be due to invalid IL or missing references) //IL_0682: Unknown result type (might be due to invalid IL or missing references) //IL_0662: Unknown result type (might be due to invalid IL or missing references) //IL_0669: Unknown result type (might be due to invalid IL or missing references) //IL_0735: Unknown result type (might be due to invalid IL or missing references) //IL_0742: Unknown result type (might be due to invalid IL or missing references) //IL_074f: Unknown result type (might be due to invalid IL or missing references) //IL_075c: Unknown result type (might be due to invalid IL or missing references) //IL_0769: Unknown result type (might be due to invalid IL or missing references) //IL_0776: Unknown result type (might be due to invalid IL or missing references) //IL_0783: Unknown result type (might be due to invalid IL or missing references) //IL_0790: Unknown result type (might be due to invalid IL or missing references) //IL_079d: Unknown result type (might be due to invalid IL or missing references) //IL_07b0: Unknown result type (might be due to invalid IL or missing references) //IL_07b8: Unknown result type (might be due to invalid IL or missing references) //IL_07e4: Unknown result type (might be due to invalid IL or missing references) //IL_07e6: Unknown result type (might be due to invalid IL or missing references) //IL_07e8: Unknown result type (might be due to invalid IL or missing references) //IL_07f9: Unknown result type (might be due to invalid IL or missing references) //IL_05b2: Unknown result type (might be due to invalid IL or missing references) //IL_084d: Unknown result type (might be due to invalid IL or missing references) //IL_085f: Unknown result type (might be due to invalid IL or missing references) //IL_08a3: Unknown result type (might be due to invalid IL or missing references) IsAlive = true; Loaded = false; ValidateConfig(); string[] array = File.ReadAllLines(ConfigPath); if (array.Length < 6) { SaveConfig(); } for (int i = 0; i < array.Length; i++) { string text = array[i]; int num = text.IndexOf('#'); if (num >= 0) { text = text.Substring(0, num); } text = text.TrimEnd(); array[i] = text; } _fps = int.Parse(array[0]); _showLoadingBar = bool.Parse(array[1]); _showLoadingInfo = bool.Parse(array[2]); _windowScale = Math.Clamp(float.Parse(array[3]), 0.1f, 8f); ForceWait = bool.Parse(array[4]); _loadingTextScale = float.Parse(array[5]); string[] array2 = Directory.EnumerateFiles(CoversPath, "*.*", SearchOption.AllDirectories).ToArray(); bool flag = false; int num2 = 0; Texture[] array3 = (Texture[])(object)new Texture[array2.Length]; for (int j = 0; j < array3.Length; j++) { Texture val = array3[j]; val.width = -1; array3[j] = val; } Raylib.InitWindow(1, 1, "Splash"); Raylib.SetWindowState((ConfigFlags)16); Raylib.SetWindowState((ConfigFlags)2048); Raylib.SetWindowState((ConfigFlags)8); Raylib.SetWindowState((ConfigFlags)256); Raylib.SetWindowState((ConfigFlags)4096); Raylib.ClearWindowState((ConfigFlags)4096); Raylib.SetTargetFPS(1000); Raylib.BeginDrawing(); Raylib.ClearBackground(Raylib.BLANK); Raylib.EndDrawing(); float num3 = 0f; Image rawGif = null; float num4 = 0f; int num5 = 0; int num6 = 0; Random random = new Random(DateTimeOffset.Now.ToUnixTimeSeconds().GetHashCode()); if (array2.Any((string f) => f.EndsWith(".gif", StringComparison.CurrentCultureIgnoreCase))) { num3 = -1f; flag = true; List list = new List(); string[] array4 = array2; foreach (string text2 in array4) { if (text2.EndsWith(".gif", StringComparison.CurrentCultureIgnoreCase)) { list.Add(text2); } } string text3 = list[random.Next(0, list.Count)]; rawGif = Image.Load(text3); num5 = ((Image)rawGif).Width; num6 = ((Image)rawGif).Height; num2 = ((ImageFrameCollection)rawGif.Frames).Count; Image val2 = Raylib.GenImageColor(num5, num6, Raylib.PURPLE); array3[0] = Raylib.LoadTextureFromImage(val2); Raylib.UnloadImage(val2); RecalculateSize(num5, num6); } else { num2 = 1; List list2 = new List(); string[] array4 = array2; foreach (string text4 in array4) { bool num8 = text4.EndsWith(".png", StringComparison.CurrentCultureIgnoreCase); bool flag2 = text4.EndsWith(".bmp", StringComparison.CurrentCultureIgnoreCase); bool flag3 = text4.EndsWith(".tga", StringComparison.CurrentCultureIgnoreCase); bool flag4 = text4.EndsWith(".jpg", StringComparison.CurrentCultureIgnoreCase) | text4.EndsWith(".jpeg", StringComparison.CurrentCultureIgnoreCase); if (num8 || flag2 || flag3 || flag4) { list2.Add(text4); } } if (list2.Count == 0) { Console.WriteLine("[Preloading Splash] No files!"); Raylib.CloseWindow(); return; } string text5 = list2[random.Next(0, list2.Count)]; array3[0] = Raylib.LoadTexture(text5); _width = Math.Max(array3[0].width, _width); _height = Math.Max(array3[0].height, _height); } Font val3 = Raylib.LoadFont(FontPath); Shader val4 = Raylib.LoadShader(VertexShaderPath, FragmentShaderPath); int shaderLocation = Raylib.GetShaderLocation(val4, "iCoverFrame"); int shaderLocation2 = Raylib.GetShaderLocation(val4, "iResolution"); int shaderLocation3 = Raylib.GetShaderLocation(val4, "iFrame"); int shaderLocation4 = Raylib.GetShaderLocation(val4, "iFrameDelta"); int shaderLocation5 = Raylib.GetShaderLocation(val4, "iFrameRate"); int shaderLocation6 = Raylib.GetShaderLocation(val4, "iTime"); int shaderLocation7 = Raylib.GetShaderLocation(val4, "iMouse"); int shaderLocation8 = Raylib.GetShaderLocation(val4, "iDate"); if (_fps < 1 && !flag) { num3 = new Random((int)(DateTimeOffset.Now.ToUnixTimeSeconds() / 60)).Next(0, array3.Length); } if (!flag) { int num9 = (int)Math.Clamp(num3, 0f, num2 - 1); Texture val5 = array3[num9]; RecalculateSize(val5.width, val5.height); } int targetFPS = Math.Clamp(_fps, 60, 240); Raylib.SetTargetFPS(targetFPS); Vector2 vector = default(Vector2); int num10 = 0; Raylib.ClearWindowState((ConfigFlags)2048); if (!TestMode) { Raylib.SetWindowState((ConfigFlags)4096); } else { Raylib.ClearWindowState((ConfigFlags)4096); } Loaded = true; Memory memory = default(Memory); Rectangle val7 = default(Rectangle); Rectangle val8 = default(Rectangle); while (!Raylib.WindowShouldClose() && !Close) { num10++; Texture val6 = array3[0]; if (flag) { num4 -= Raylib.GetFrameTime(); if ((int)num3 == -1 || num4 <= 0f) { num3 += 1f; if (num3 > (float)(num2 - 1)) { num3 = 0f; IsDone = true; } num4 = GetGifFrameDelay((int)num3) / 1000f; Console.WriteLine(num3); Console.WriteLine(num4); if (!rawGif.Frames[(int)num3].DangerousTryGetSinglePixelMemory(ref memory)) { num4 = 0f; continue; } using MemoryHandle memoryHandle = memory.Pin(); Raylib.UpdateTexture(val6, memoryHandle.Pointer); } } else { IsDone = true; int num11; int num12; if (num2 <= 1) { num3 = 0f; num11 = 0; num12 = 0; } else { num11 = (int)Math.Clamp(num3, 0f, num2 - 1); num3 += Raylib.GetFrameTime() * (float)_fps; if (num3 > (float)(num2 - 4)) { IsDone = true; } if (num3 > (float)num2) { num3 = 0f; } num12 = (int)Math.Clamp(num3, 0f, num2 - 1); } val6 = array3[num12]; if (num11 != num12) { RecalculateSize(val6.width, val6.height); } } Raylib.BeginDrawing(); Raylib.ClearBackground(new Color(0, 0, 0, 255)); if (Raylib.IsMouseButtonDown((MouseButton)0)) { vector = Raylib.GetMousePosition(); } float num13 = (float)Raylib.GetTime(); Vector3 vector2 = new Vector3(_width, _height, _width / _height); float frameTime = Raylib.GetFrameTime(); Vector4 vector3 = new Vector4(Raylib.GetMouseX(), Raylib.GetMouseY(), vector.X, vector.Y); DateTime now = DateTime.Now; Vector4 vector4 = new Vector4(now.Year, now.Month, now.Day, now.Hour * 60 * 60 + now.Minute * 60 + now.Second); Raylib.SetShaderValue(val4, shaderLocation, &num3, (ShaderUniformDataType)0); Raylib.SetShaderValue(val4, shaderLocation2, &vector2, (ShaderUniformDataType)2); Raylib.SetShaderValue(val4, shaderLocation3, &num10, (ShaderUniformDataType)0); Raylib.SetShaderValue(val4, shaderLocation4, &frameTime, (ShaderUniformDataType)0); Raylib.SetShaderValue(val4, shaderLocation5, &targetFPS, (ShaderUniformDataType)0); Raylib.SetShaderValue(val4, shaderLocation6, &num13, (ShaderUniformDataType)0); Raylib.SetShaderValue(val4, shaderLocation7, &vector3, (ShaderUniformDataType)3); Raylib.SetShaderValue(val4, shaderLocation8, &vector4, (ShaderUniformDataType)3); Raylib.BeginShaderMode(val4); ((Rectangle)(ref val7))..ctor(0f, 0f, (float)val6.width, (float)val6.height); ((Rectangle)(ref val8))..ctor(0f, 0f, (float)_width, (float)_height); Raylib.DrawTexturePro(val6, val7, val8, default(Vector2), 0f, Raylib.WHITE); Raylib.EndShaderMode(); if (_showLoadingBar) { Raylib.DrawRectangle(0, _height - 12, (int)((float)_width * Math.Clamp(Progress, 0f, 1f)), 12, new Color(255, 255, 255, 255)); } if (_showLoadingInfo) { Raylib.DrawTextEx(val3, Message, new Vector2(4f, (float)_height - _loadingTextScale - 16f), _loadingTextScale, 1f, new Color(255, 255, 255, 255)); } Raylib.EndDrawing(); } IsAlive = false; Raylib.UnloadShader(val4); if (flag) { Raylib.UnloadTexture(array3[0]); } else { Texture[] array5 = array3; for (int num7 = 0; num7 < array5.Length; num7++) { Raylib.UnloadTexture(array5[num7]); } } Raylib.CloseWindow(); float GetGifFrameDelay(int gifFrame) { return ((ImageFrame)rawGif.Frames[gifFrame]).Metadata.GetFormatMetadata((IImageFormat)(object)GifFormat.Instance).FrameDelay * 10; } } public static void ValidateConfig() { if (!Directory.Exists(ConfigFolderPath)) { Directory.CreateDirectory(ConfigFolderPath); } if (!Directory.Exists(CoversPath)) { Directory.CreateDirectory(CoversPath); } if (Directory.GetFiles(CoversPath).Length == 0) { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Preloading_Splash.0.png"); using FileStream destination = new FileStream(Path.Combine(CoversPath, "0.png"), FileMode.Create, FileAccess.Write); stream?.CopyTo(destination); } if (!File.Exists(FontPath)) { using Stream stream2 = Assembly.GetExecutingAssembly().GetManifestResourceStream("Preloading_Splash.Font.ttf"); using FileStream destination2 = new FileStream(FontPath, FileMode.Create, FileAccess.Write); stream2?.CopyTo(destination2); } if (!File.Exists(ConfigPath)) { SaveConfig(0f, loadingBar: true, loadingText: true, 16f, 0.3f, forcewait: false, validate: false); } if (!File.Exists(VertexShaderPath)) { File.WriteAllText(VertexShaderPath, "#version 330\n// fyi raylib is the internal render-er\n\nin vec3 vertexPosition;\nin vec2 vertexTexCoord;\nin vec4 vertexColor;\n\nout vec2 fragTexCoord;\nout vec4 fragColor;\n\nuniform mat4 mvp;\n\nvoid main()\n{\n fragTexCoord = vertexTexCoord;\n fragColor = vertexColor;\n gl_Position = mvp * vec4(vertexPosition, 1.0);\n}"); } if (!File.Exists(FragmentShaderPath)) { File.WriteAllText(FragmentShaderPath, "#version 330\n// fyi raylib is the internal render-er\n\nin vec2 fragTexCoord;\nin vec4 fragColor;\n\nuniform sampler2D texture0;\nuniform vec4 colDiffuse;\n\n// shadertoy-sorta-compatable-uniforms to help with adding cool shaders\n// altho u cant just paste a shadertoy shader in you wll need to tweak it for it to work\n// also no channel support sry\nuniform float iCoverFrame;\nuniform vec3 iResolution;\nuniform float iFrame;\nuniform float iFrameDelta;\nuniform float iFrameRate;\nuniform float iTime;\nuniform vec4 iMouse;\nuniform vec4 iDate;\n\nout vec4 finalColor;\n\nvoid main()\n{\n vec4 texelColor = texture(texture0, fragTexCoord);\n \n finalColor = texelColor * fragColor * colDiffuse;\n}"); } } public static void SaveConfig(float fps = 0f, bool loadingBar = true, bool loadingText = true, float loadingTextScale = 16f, float scale = 0.3f, bool forcewait = false, bool validate = true) { if (validate) { ValidateConfig(); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(((int)fps).ToString()); stringBuilder.AppendLine(" # cover art fps 0 = pick random, >0 = animate from covers in covers folder (must be indexed properly)"); stringBuilder.Append(loadingBar.ToString()); stringBuilder.AppendLine(" # show loading bar"); stringBuilder.Append(loadingText.ToString()); stringBuilder.AppendLine(" # show loading text"); stringBuilder.Append(scale.ToString(CultureInfo.CurrentCulture)); stringBuilder.AppendLine(" # window scale"); stringBuilder.Append(forcewait.ToString()); stringBuilder.AppendLine(" # wait for the current splash animation to finish first"); stringBuilder.Append(loadingTextScale.ToString()); stringBuilder.AppendLine(" # loading text scale"); File.WriteAllText(ConfigPath, stringBuilder.ToString()); } } public static class SplashPatcher { internal class LogListener : ILogListener, IDisposable { public void Dispose() { } public void LogEvent(object sender, LogEventArgs eventArgs) { bool flag = eventArgs.Source.SourceName == "BepInEx"; ILogSource val = (ILogSource)((sender is ILogSource) ? sender : null); if (val != null) { flag = val.SourceName == "BepInEx"; } if (!flag) { return; } SplashWindow.Message = eventArgs.Data.ToString(); if (SplashWindow.Message.Contains("Loading")) { SplashWindow.Progress = (float)_loadedPluginCount / (float)_pluginCount; _loadedPluginCount++; } if (!SplashWindow.Message.Contains("Chainloader", StringComparison.CurrentCultureIgnoreCase) || !SplashWindow.Message.Contains("Complete", StringComparison.CurrentCultureIgnoreCase)) { return; } SplashWindow.Message = "All mods loaded!"; SplashWindow.Progress = 1f; _loadedPluginCount = _pluginCount; if (SplashWindow.ForceWait) { while (!SplashWindow.IsDone) { Thread.Sleep(1); } } } } private static int _pluginCount = 0; private static int _loadedPluginCount = 0; private static readonly string CurrentAssemblyName = Assembly.GetAssembly(typeof(Logger)).GetName().Name; public static IEnumerable TargetDLLs { get; } = new string[1] { "Assembly-CSharp.dll" }; public static void Patch(AssemblyDefinition assembly) { } private static bool HasBepinPlugins(AssemblyDefinition ass) { if (((IEnumerable)ass.MainModule.AssemblyReferences).All((AssemblyNameReference r) => r.Name != CurrentAssemblyName)) { return false; } if (ass.MainModule.GetTypeReferences().All((TypeReference r) => ((MemberReference)r).FullName != typeof(BepInPlugin).FullName)) { return false; } return true; } public static void Initialize() { Logger.Listeners.Add((ILogListener)(object)new LogListener()); if (!Directory.Exists(Path.Combine(Paths.ConfigPath, "PreloadingSplash"))) { SplashWindow.SaveConfig(); } Task.Run(delegate { new SplashWindow(); }).ContinueWith(delegate { }, TaskContinuationOptions.OnlyOnFaulted); } public static void Finish() { Dictionary> dictionary = TypeLoader.FindPluginTypes(Paths.PluginPath, (Func)Chainloader.ToPluginInfo, (Func)HasBepinPlugins, "chainloader"); HashSet hashSet = new HashSet(); foreach (KeyValuePair> item in dictionary) { foreach (PluginInfo item2 in item.Value) { if (!hashSet.Contains(item2)) { hashSet.Add(item2); } } } _pluginCount = hashSet.Count; } }