diff --git a/HomoglyphConverter/confusables.txt b/.resources/confusables.txt similarity index 100% rename from HomoglyphConverter/confusables.txt rename to .resources/confusables.txt diff --git a/.resources/cpu_tier_list.conf b/.resources/cpu_tier_list.conf new file mode 100644 index 00000000..42a62020 --- /dev/null +++ b/.resources/cpu_tier_list.conf @@ -0,0 +1,174 @@ +; v2.5.2 https://docs.google.com/spreadsheets/d/1Rpq_2D4Rf3g6O-x2R1fwTSKWvJH7X63kExsVxHnT2Mc/view + +; Model names from this list are matched to formatted system info string in bot log +; e.g.: AMD Ryzen 7 9700X | 8 Threads | 31.11 GiB RAM | AVX-512+ | FMA3 +; PAY ATTENTION to model name spelling (e.g. there's no - in ryzen models) + +; Spaces in this list are treated as .* in regex, use \s for space +; e.g: "i9-12900K AVX-512" will generate regex "i9-12900K.*AVX-512" + +; Models are matching as regex as a result (ignoring the letter case) +; e.g.: 12900K will match 12900KF or 12900KS too, but not 12900 + +[S] +Ryzen 9 9950X3D +Ryzen 7 9800X3D +i9-12900K AVX-512 +i7-12700K AVX-512 +Ryzen 9 9950X +Ryzen 7 9700X +i9-14900K +i9-13900KS +Ultra 9 285K +i9-13900K +i7-14700K +Ryzen 9 9900X +Ultra 7 265K +i7-13700K +Ryzen 9 7950X3D +Ryzen 9 7950X +Ryzen 7 7700X +Ryzen 9 7900X +Ryzen 7 7800X3D +Ultra 5 245K + +[A] +i5-14600K +i5-13600K +Ryzen 5 9600X +Ryzen 5 7600X +Ryzen 5 7500F +i7-12700 AVX-512 +i9-12900KS +i9-12900K +i5-12600K AVX-512 +i9-11900K +i7-11700K +i7-12700K +i7-12700 +i5-12600K +i5-12400 AVX-512 +Ryzen 9 7945HX +i9-14900HX +i9-13980HX +i7-14650HX +i7-13620H +i9-12900HX +i9-11980HK +i7-12650H +i9-11950H +i9-11900H +i7-11850H +i7-11800H + +[B] +Ryzen 7 5800X +Ryzen 9 5950X +Ryzen 9 5900X +i5-11600K +i5-13500 +Ryzen 7 5800X3D +Ryzen 7 5700X3D +i5-13400 +Ryzen 7 5700X +i5-12400 +i9-10900K +i7-10700K +i3-12100 AVX-512 +i9-9900K +i5-11400 +Ryzen 5 5600X +Ryzen 7 5700G +Ryzen 7 3800X +Ryzen 7 3700X +i5-10600K +i7-8700K +i3-12100 +Ryzen 9 3950X +Ryzen 9 3900X +Ryzen 5 5600G +Ryzen 5 3600 +i5-10400 +i7-11600H +i5-11400H +; GPD Win Max 2 +Ryzen 7 8840U +Ryzen 7 7840U +Ryzen 5 8640U +; Legion Go +; ROG Ally X +Ryzen Z1 Extreme +; ROG Ally +Ryzen Z1 +Ryzen 9 6900HX +Ryzen 7 6800H +i7-10875H +i7-10870H +i7-10850H +Ryzen 9 5980HX +Ryzen 9 5980HS +Ryzen 9 5900HX +Ryzen 7 5800H +Ryzen 7 5800HS +Ryzen 7 4800H +Ryzen 7 6800U +Ryzen 5 5600H +Ryzen 5 5600HS + +[C] +i5-9600K +i5-8600K +i5-9400 +i5-8400 +Ryzen 7 2700X +i7-7700K +i7-4790K +Ryzen 7 1700 +i7-1165G7 +i7-8750H +i5-8300H +i7-7700HQ +; Steam Deck OLED +; Steam Deck LCD +Custom APU 0405 +; "Intel 7000 - 4000 4c/8t" +; 4xxx-7xxx except U with 5-8 threads +Intel [4-7]\d{3}(?!U) \b[5-8]\sThreads +; "Ryzen 1000 - 2000 8c/16t" +; 1xxxx or 2xxxx with 13-16 threads +Ryzen [12]\d{3} 1[3-6]\sThreads + +[D] +Ryzen 5 2600 +Ryzen 5 1600AF +i5-7600k +i5-6600K +Ryzen 5 3400G +i5-4690K +i5-4690 +i5-1035G1 +i3-N305 +i7-4700MQ +i5-8250U +i5-7300HQ +; "Ryzen 1000 - 2000 6c/12t or worse" +; 1xxx or 2xxx with 1-9 or 10-12 threads +Ryzen [12]\d{3} \b([1-9]|1[0-2])\sThreads +; Any 4c/4t CPU +4\sThreads + +[F] +i3-1005G1 +i3-10110U +Intel N200 +Intel N100 +i5-4300M +Intel N50 +; "Intel 7000 - 100 U Series" +; 7xxx-9xxx or 10xxx or 1xxx +Intel ([7-9]|10?)\d{3}U +; Intel's 2nd and 3rd Gen +Intel [23]\d{3} +;AMD FX CPUs +AMD FX- +;Anything Older \ No newline at end of file diff --git a/fortunes.txt b/.resources/fortunes.txt similarity index 100% rename from fortunes.txt rename to .resources/fortunes.txt diff --git a/fortunes_fortuneandframe.txt b/.resources/fortunes_fortuneandframe.txt similarity index 100% rename from fortunes_fortuneandframe.txt rename to .resources/fortunes_fortuneandframe.txt diff --git a/metacritic_ps3.json b/.resources/metacritic_ps3.json similarity index 100% rename from metacritic_ps3.json rename to .resources/metacritic_ps3.json diff --git a/names_anidb.txt b/.resources/names_anidb.txt similarity index 100% rename from names_anidb.txt rename to .resources/names_anidb.txt diff --git a/names_anilist.txt b/.resources/names_anilist.txt similarity index 100% rename from names_anilist.txt rename to .resources/names_anilist.txt diff --git a/names_anime.txt b/.resources/names_anime.txt similarity index 100% rename from names_anime.txt rename to .resources/names_anime.txt diff --git a/win32_error_codes_v22.0.txt b/.resources/win32_error_codes_v23.0.txt similarity index 99% rename from win32_error_codes_v22.0.txt rename to .resources/win32_error_codes_v23.0.txt index 42379025..47d9d817 100644 --- a/win32_error_codes_v22.0.txt +++ b/.resources/win32_error_codes_v23.0.txt @@ -1,4 +1,4 @@ -0x00000000 +0x00000000 ERROR_SUCCESS The operation completed successfully. 0x00000000 NERR_Success The operation completed successfully. diff --git a/Clients/CirrusCiClient/CirrusCiClient.csproj b/Clients/CirrusCiClient/CirrusCiClient.csproj index 14efd676..866fc26a 100644 --- a/Clients/CirrusCiClient/CirrusCiClient.csproj +++ b/Clients/CirrusCiClient/CirrusCiClient.csproj @@ -9,9 +9,9 @@ - - - + + + \ No newline at end of file diff --git a/Clients/CompatApiClient/CompatApiClient.csproj b/Clients/CompatApiClient/CompatApiClient.csproj index b32607b7..b822bc1e 100644 --- a/Clients/CompatApiClient/CompatApiClient.csproj +++ b/Clients/CompatApiClient/CompatApiClient.csproj @@ -8,7 +8,7 @@ - + diff --git a/Clients/GithubClient/GithubClient.csproj b/Clients/GithubClient/GithubClient.csproj index bfc4718c..3ef59637 100644 --- a/Clients/GithubClient/GithubClient.csproj +++ b/Clients/GithubClient/GithubClient.csproj @@ -5,7 +5,7 @@ enable - + diff --git a/Clients/IrdLibraryClient/IrdLibraryClient.csproj b/Clients/IrdLibraryClient/IrdLibraryClient.csproj index e9254496..ad06f2b2 100644 --- a/Clients/IrdLibraryClient/IrdLibraryClient.csproj +++ b/Clients/IrdLibraryClient/IrdLibraryClient.csproj @@ -5,9 +5,9 @@ enable - + - + diff --git a/Clients/PsnClient/PsnClient.csproj b/Clients/PsnClient/PsnClient.csproj index 5b7212a8..f447d2e9 100644 --- a/Clients/PsnClient/PsnClient.csproj +++ b/Clients/PsnClient/PsnClient.csproj @@ -12,7 +12,7 @@ - + diff --git a/CompatBot/CompatBot.csproj b/CompatBot/CompatBot.csproj index b733b7c6..1c32f7b4 100644 --- a/CompatBot/CompatBot.csproj +++ b/CompatBot/CompatBot.csproj @@ -31,37 +31,39 @@ - + PreserveNewest - - + + + + - - - + + + - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + diff --git a/CompatBot/Database/DbImporter.cs b/CompatBot/Database/DbImporter.cs index 940edf28..26c548c7 100644 --- a/CompatBot/Database/DbImporter.cs +++ b/CompatBot/Database/DbImporter.cs @@ -179,7 +179,7 @@ public static class DbImporter { Config.Log.Debug("Importing name pool…"); var rootDir = Environment.CurrentDirectory; - while (rootDir is not null && !Directory.EnumerateFiles(rootDir, "names_*.txt", SearchOption.TopDirectoryOnly).Any()) + while (rootDir is not null && !Directory.Exists(Path.Combine(rootDir, ".resources"))) rootDir = Path.GetDirectoryName(rootDir); if (rootDir is null) { @@ -187,7 +187,8 @@ public static class DbImporter return wdb.NamePool.Any(); } - var resources = Directory.GetFiles(rootDir, "names_*.txt", SearchOption.TopDirectoryOnly) + var resourcesDir = Path.Combine(rootDir, ".resources"); + var resources = Directory.GetFiles(resourcesDir, "names_*.txt", SearchOption.TopDirectoryOnly) .OrderBy(f => f) .ToList(); if (resources.Count == 0) diff --git a/CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs b/CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs index 0c16eee6..d2951d85 100644 --- a/CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs +++ b/CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs @@ -4,8 +4,8 @@ namespace CompatBot.EventHandlers.LogParsing; internal partial class LogParser { - private const RegexOptions DefaultOptions = RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.ExplicitCapture; - private const RegexOptions DefaultSingleLine = RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture; + private const RegexOptions DefaultOptions = RegexOptions.Multiline | RegexOptions.ExplicitCapture; + private const RegexOptions DefaultSingleLine = RegexOptions.Singleline | RegexOptions.ExplicitCapture; [GeneratedRegex(@"(^|.+\d:\d\d:\d\d\.\d{6})\s*(?RPCS3 [^\xC2\xB7]+?)\r?(\n·|$)", DefaultSingleLine)] private static partial Regex Rpcs3LogHeader(); diff --git a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.CurrentSettingsSections.cs b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.CurrentSettingsSections.cs index 8c40be0f..2bb60b50 100644 --- a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.CurrentSettingsSections.cs +++ b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.CurrentSettingsSections.cs @@ -137,9 +137,12 @@ internal static partial class LogParserResult } } var threadCountItem = items["thread_count"]?.Trim(); - systemInfo += $"{Environment.NewLine}{items["cpu_model"]} | {threadCountItem} Thread{(threadCountItem == "1" ? "" : "s")} | {items["memory_amount"]} GiB RAM"; + var cpuAndMemoryInfo = + $"{items["cpu_model"]} | {threadCountItem} Thread{(threadCountItem == "1" ? "" : "s")} | {items["memory_amount"]} GiB RAM"; if (!string.IsNullOrEmpty(items["cpu_extensions"])) - systemInfo += " | " + items["cpu_extensions"]; + cpuAndMemoryInfo += " | " + items["cpu_extensions"]; + systemInfo += $"{Environment.NewLine}{cpuAndMemoryInfo}"; + items["cpu_and_memory_info"] = cpuAndMemoryInfo; } if (items["gpu_info"] is string gpu) systemInfo += $"{Environment.NewLine}GPU: {gpu}"; diff --git a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.GeneralNotesSection.cs b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.GeneralNotesSection.cs index 133240f0..20bb1550 100644 --- a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.GeneralNotesSection.cs +++ b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.GeneralNotesSection.cs @@ -187,7 +187,32 @@ internal static partial class LogParserResult if (int.TryParse(items["thread_count"], out var threadCount) && threadCount < 4) notes.Add($"⚠️ This CPU only has {threadCount} hardware thread{(threadCount == 1 ? "" : "s")} enabled"); - if (items["cpu_model"] is string cpu) + var cpuModelMatched = false; + if (items["cpu_and_memory_info"] is string cpuAndMemoryInfo) + { + if (CpuTierList.List.FirstOrDefault(i => i.regex.IsMatch(cpuAndMemoryInfo)) is { tier: { Length: >0 } tier } match) + { + var status = items["game_status"] ?? "unknown"; + var msg = (tier, status) switch + { + ("S" or "A", _) => $"ℹ️ This is an **{tier}** Tier CPU", + ("B", "ingame") => "⚠️ This is a **B** Tier CPU, and may not be sufficient for some ingame titles", + ("B", _) => "ℹ️ This is a **B** Tier CPU", + ("C", "playable") => "⚠️ This is a **C** Tier CPU, which is below the recommended system requirements", + ("C", _) => "⚠️ This is a **C** Tier CPU, please stick to the playable game titles", + ("D", "playable") => "⚠️ This is a **D** Tier CPU, only lighter playable game titles will work", + ("D", _) => "⚠️ This is a **D** Tier CPU, please stick to the lighter playable game titles", + ("F", _) => "❌ This is an **F** Tier CPU, which is below the minimum system requirements", + _ => "", + }; + if (msg is {Length: >0}) + { + notes.Add($"{msg}"); + cpuModelMatched = true; + } + } + } + if (!cpuModelMatched && items["cpu_model"] is string cpu) { if (cpu.StartsWith("AMD")) { @@ -383,7 +408,7 @@ internal static partial class LogParserResult // this is a common scenario now that Mega did the version merge from param.sfo /* if (items["game_category"] == "GD") - notes.Add($"❔ Game was booted through the Game Data"); + notes.Add($"❓ Game was booted through the Game Data"); */ if (category is "DG" or "GD") // only disc games should install game data { diff --git a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.WeirdSettingsSection.cs b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.WeirdSettingsSection.cs index a68b399a..ca039627 100644 --- a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.WeirdSettingsSection.cs +++ b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.WeirdSettingsSection.cs @@ -42,7 +42,7 @@ internal static partial class LogParserResult } /* if (items["spu_lower_thread_priority"] == EnabledMark && threadCount > 4) - notes.Add("❔ `Lower SPU thread priority` is enabled on a CPU with enough threads"); + notes.Add("❓ `Lower SPU thread priority` is enabled on a CPU with enough threads"); */ if (items["cpu_model"] is string cpu) { @@ -74,7 +74,7 @@ internal static partial class LogParserResult var isAppleGpu = items["gpu_info"] is string gpuInfoApple && gpuInfoApple.Contains("Apple", StringComparison.OrdinalIgnoreCase); var canUseRelaxedZcull = items["renderer"] is not "Vulkan" || multiItems["vk_ext"].Contains("VK_EXT_depth_range_unrestricted"); if (items["llvm_arch"] is string llvmArch) - notes.Add($"❔ LLVM target CPU architecture override is set to `{llvmArch.Sanitize(replaceBackTicks: true)}`"); + notes.Add($"❓ LLVM target CPU architecture override is set to `{llvmArch.Sanitize(replaceBackTicks: true)}`"); if (items["renderer"] is "D3D12") notes.Add("💢 Do **not** use DX12 renderer"); if (items["renderer"] is "OpenGL" @@ -291,7 +291,7 @@ internal static partial class LogParserResult && int.TryParse(resScale, out var resScaleFactor)) { if (resScaleFactor < 100) - notes.Add($"❔ `Resolution Scale` is `{resScale}%`; this will not increase performance"); + notes.Add($"❓ `Resolution Scale` is `{resScale}%`; this will not increase performance"); if (resScaleFactor != 100 && items["texture_scale_threshold"] is string thresholdStr && int.TryParse(thresholdStr, out var threshold) @@ -335,7 +335,7 @@ internal static partial class LogParserResult notes.Add("⚠️ `Frame Skip` is enabled, please disable"); if (items["cpu_blit"] is EnabledMark && items["write_color_buffers"] is DisabledMark) - notes.Add("❔ `Force CPU Blit` is enabled, but `Write Color Buffers` is disabled"); + notes.Add("❓ `Force CPU Blit` is enabled, but `Write Color Buffers` is disabled"); if (items["zcull_status"] is not null and not "Full" && !canUseRelaxedZcull) notes.Add("⚠️ This GPU does not support `VK_EXT_depth_range_unrestricted` extension, please disable `Relaxed ZCull Sync`"); @@ -432,7 +432,7 @@ internal static partial class LogParserResult if (items["hook_static_functions"] is EnabledMark) notes.Add("⚠️ `Hook Static Functions` is enabled, please disable"); if (items["host_root"] is EnabledMark) - notes.Add("❔ `/host_root/` is enabled"); + notes.Add("❓ `/host_root/` is enabled"); if (items["ppu_threads"] is string ppuThreads && ppuThreads != "2") notes.Add($"⚠️ `PPU Threads` is set to `{ppuThreads.Sanitize()}`; please change it back to `2`"); @@ -455,7 +455,7 @@ internal static partial class LogParserResult else if (af is "Disabled") notes.Add("❌ `Anisotropic Filter` is `Disabled`, please use `Auto` instead"); else if (af is not "Auto" and not "16") - notes.Add($"❔ `Anisotropic Filter` is set to `{af}x`, which makes little sense over `16x` or `Auto`"); + notes.Add($"❓ `Anisotropic Filter` is set to `{af}x`, which makes little sense over `16x` or `Auto`"); } if (items["shader_mode"]?.Contains("Interpreter") is true && isAppleGpu) @@ -463,7 +463,7 @@ internal static partial class LogParserResult else if (items["shader_mode"] == "Interpreter only") notes.Add("⚠️ `Shader Interpreter Only` mode is not accurate and very demanding"); else if (items["shader_mode"]?.StartsWith("Async") is false && !isAppleGpu) - notes.Add("❔ Async shader compilation is disabled"); + notes.Add("❓ Async shader compilation is disabled"); if (items["driver_recovery_timeout"] is string driverRecoveryTimeout && int.TryParse(driverRecoveryTimeout, out var drtValue) && drtValue != 1000000) @@ -551,9 +551,9 @@ internal static partial class LogParserResult } if (items["auto_start_on_boot"] == DisabledMark) - notes.Add("❔ `Automatically start games after boot` is disabled"); + notes.Add("❓ `Automatically start games after boot` is disabled"); else if (items["always_start_on_boot"] == DisabledMark) - notes.Add("❔ `Always start after boot` is disabled"); + notes.Add("❓ `Always start after boot` is disabled"); if (items["custom_config"] != null && notes.Any()) generalNotes.Add("⚠️ To change custom configuration, **Right-click on the game**, then `Configure`"); diff --git a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.cs b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.cs index 5889d63e..cb5ed515 100644 --- a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.cs +++ b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.cs @@ -408,7 +408,7 @@ internal static partial class LogParserResult private static readonly TimeSpan PrehistoricBuild = TimeSpan.FromDays(365); private static readonly char[] PrioritySeparator = [' ']; - private static readonly string[] EmojiPriority = new[]{ "😱", "💢", "‼️", "❗", "❌", "⁉️", "⚠️", "❔", "✅", "ℹ️" } + private static readonly string[] EmojiPriority = new[]{ "😱", "💢", "‼️", "❗", "❌", "⁉️", "⚠️", "❓", "❔", "✅", "ℹ️" } .Select(e => e.TrimEnd('\ufe0f')) .ToArray(); private const string EnabledMark = "[x]"; diff --git a/HomoglyphConverter/HomoglyphConverter.csproj b/HomoglyphConverter/HomoglyphConverter.csproj index 3d78965e..cc6d2575 100644 --- a/HomoglyphConverter/HomoglyphConverter.csproj +++ b/HomoglyphConverter/HomoglyphConverter.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/README.md b/README.md index 53f1d624..1757373b 100644 --- a/README.md +++ b/README.md @@ -72,4 +72,5 @@ External resources that need manual updates ------------------------------------------- * [Unicode Confusables](http://www.unicode.org/Public/security/latest/confusables.txt), for Homoglyph checks * [Windows Error Codes](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/), for error decoding on non-Windows host +* [CPU Tier List](https://rpcs3.net/cputierlist), for CPU model ranking * Optionally pool of names (one name per line), files named as `names_.txt` diff --git a/SourceGenerators/ConfusablesSourceGenerator.cs b/SourceGenerators/ConfusablesSourceGenerator.cs index 7455b8d4..e37c72b3 100644 --- a/SourceGenerators/ConfusablesSourceGenerator.cs +++ b/SourceGenerators/ConfusablesSourceGenerator.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Text; namespace SourceGenerators; [Generator(LanguageNames.CSharp)] -public class ConfusablesSourceGenerator : IIncrementalGenerator +public class ConfusablesSourceGenerator: IIncrementalGenerator { private static readonly char[] CommentSplitter = ['#']; private static readonly char[] FieldSplitter = [';']; @@ -102,25 +102,29 @@ public class ConfusablesSourceGenerator : IIncrementalGenerator if (!Version.TryParse(version, out _)) version = ""; - var result = new StringBuilder() - .AppendLine("using System;") - .AppendLine("using System.Collections.Generic;") - .AppendLine() - .AppendLine($"namespace {ns}") - .AppendLine("{") - .AppendLine($" internal static class {cn}") - .AppendLine(" {") - .AppendLine($" public const string Version = \"{version}\";") - .AppendLine() - .AppendLine($" public const string Date = \"{date}\";") - .AppendLine() - .AppendLine(" public static readonly Dictionary Mapping = new()") - .AppendLine(" {"); + var result = new StringBuilder().AppendLine($$""" + using System; + using System.Collections.Generic; + + namespace {{ns}}; + + internal static class {{cn}} + { + public const string Version = "{{version}}"; + public const string Date = "{{date}}"; + public static readonly Dictionary Mapping = new() + { + """ + ); foreach (var kvp in mapping.OrderBy(i => i.Key)) - result.AppendLine($@" [0x{kvp.Key:X5}u] = new[] {{ {string.Join(", ", kvp.Value!.OrderBy(i => i).Select(n => $"0x{n:X5}u"))} }},"); - result.AppendLine(" };") - .AppendLine(" }") - .AppendLine("}"); + result.AppendLine($""" + [0x{kvp.Key:X5}u] = [{string.Join(", ", kvp.Value!.OrderBy(i => i).Select(n => $"0x{n:X5}u"))}], + """); + result.AppendLine(""" + }; + } + """ + ); context.AddSource($"{cn}.Generated.cs", SourceText.From(result.ToString(), Encoding.UTF8)); diff --git a/SourceGenerators/CpuTierListGenerator.cs b/SourceGenerators/CpuTierListGenerator.cs new file mode 100644 index 00000000..1b375f09 --- /dev/null +++ b/SourceGenerators/CpuTierListGenerator.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Text; + +namespace SourceGenerators; + +[Generator(LanguageNames.CSharp)] +public class CpuTierListGenerator: IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var resourceProvider = context.AdditionalTextsProvider.Where( + static f => Path.GetFileName(f.Path) is {} fname + && fname.StartsWith("cpu_tier_list") + && fname.EndsWith(".conf") + ); + var dataProvider = resourceProvider.Combine(context.AnalyzerConfigOptionsProvider.Combine(context.CompilationProvider)); + context.RegisterSourceOutput(dataProvider, Execute); + } + + private static void Execute(SourceProductionContext context, (AdditionalText resource, (AnalyzerConfigOptionsProvider configOptions, Compilation compilation) generatorContext) args) + { + var resource = args.resource; + using var stream = File.Open(resource.Path, FileMode.Open, FileAccess.Read, FileShare.Read); + if (stream is null) + throw new InvalidOperationException("Failed to open {resource.Path}"); + + if (!args.generatorContext.configOptions.GlobalOptions.TryGetValue("build_property.RootNamespace", out var ns)) + ns = args.generatorContext.compilation.AssemblyName; + const string cn = "CpuTierList"; + var result = new StringBuilder().AppendLine($$""" + using System; + using System.Text.RegularExpressions; + + namespace {{ns}}; + + internal static class {{cn}} + { + private const RegexOptions DefaultOptions = RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Compiled; + """ + ); + using var reader = new StreamReader(stream, Encoding.UTF8, false); + var currentTier = "unknown"; + var idx = 0; + List<(string model, string tier)> tierMap = []; + while (reader.ReadLine() is string line) + { + line = line.Trim(); + if (string.IsNullOrEmpty(line) || line.StartsWith(";") || line.StartsWith("#")) + continue; + + if (line.StartsWith("[")) + { + currentTier = line.Substring(1, line.Length - 2); + result.AppendLine($""" + + // {currentTier} Tier + """ + ); + continue; + } + + tierMap.Add((line, currentTier)); + line = line.Replace(" ", ".*"); + // todo: use generated regex when it's possible https://github.com/dotnet/roslyn/discussions/48358 + /* + result.AppendLine($""" + [GeneratedRegex(@"{line}", DefaultOptions)] + private static partial Regex Model{i++}(); + """ + ); + */ + result.AppendLine($""" + private static readonly Regex Model{idx++} = new(@"{line}", DefaultOptions); + """ + ); + } + result.AppendLine($""" + + public static readonly List<(string model, string tier, Regex regex)> List = [ + """ + ); + for (var i=0; i Map = new()") - .AppendLine($"{Indent}{Indent}{{"); + const string cn = "Win32ErrorCodes"; + var result = new StringBuilder().AppendLine($$""" + using System.Collections.Generic; + + namespace {{ns}}; + + public static class {{cn}} + { + public static readonly Dictionary Map = new() + { + """ + ); var previousPos = 0; var line = 0; - var codeLine = 0; - var descLine = 0; using var reader = new StreamReader(stream, Encoding.UTF8, false); while (reader.ReadLine() is string errorCodeLine) { @@ -66,14 +65,14 @@ public class Win32ErrorsSourceGenerator : IIncrementalGenerator if (string.IsNullOrWhiteSpace(errorCodeLine)) continue; - codeLine = line - 1; + var codeLine = line - 1; string? errorNameAndDescriptionLine; do { errorNameAndDescriptionLine = reader.ReadLine(); line++; } while (string.IsNullOrWhiteSpace(errorNameAndDescriptionLine)); - descLine = line - 1; + var descLine = line - 1; var nameDescParts = errorNameAndDescriptionLine.Split(Separator, 2); if (nameDescParts.Length != 2 || !Regex.IsMatch(errorCodeLine, @"0x[0-9a-f]+")) @@ -99,13 +98,16 @@ public class Win32ErrorsSourceGenerator : IIncrementalGenerator var name = nameDescParts[0]; var desc = nameDescParts[1].Replace(@"\", @"\\").Replace("\"", "\\\""); - result.AppendLine($"{Indent}{Indent}{Indent}[{errorCodeLine.Trim()}] = (\"{name.Trim()}\", \"{desc.Trim()}\"),"); + result.AppendLine($""" + [{errorCodeLine.Trim()}] = ("{name.Trim()}", "{desc.Trim()}"), + """ + ); } - - result.AppendLine($"{Indent}{Indent}}};") - .AppendLine($"{Indent}}}") - .AppendLine("}"); - + result.AppendLine(""" + }; + } + """ + ); context.AddSource($"{cn}.Generated.cs", SourceText.From(result.ToString(), Encoding.UTF8)); } } \ No newline at end of file diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index e2411ff2..2789c59b 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -7,7 +7,7 @@ - + diff --git a/discord-bot-net.sln b/discord-bot-net.sln index 70bdaae3..28b0b0e3 100644 --- a/discord-bot-net.sln +++ b/discord-bot-net.sln @@ -43,6 +43,19 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGenerators", "SourceG EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CirrusCiClient", "Clients\CirrusCiClient\CirrusCiClient.csproj", "{897476B0-B80A-4134-A576-8CAEAEA14A28}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resources", "Resources", "{519297F9-DE0B-48EE-85B6-0DB6B065760E}" + ProjectSection(SolutionItems) = preProject + .resources\confusables.txt = .resources\confusables.txt + .resources\fortunes.txt = .resources\fortunes.txt + .resources\fortunes_fortuneandframe.txt = .resources\fortunes_fortuneandframe.txt + .resources\metacritic_ps3.json = .resources\metacritic_ps3.json + .resources\names_anidb.txt = .resources\names_anidb.txt + .resources\names_anilist.txt = .resources\names_anilist.txt + .resources\names_anime.txt = .resources\names_anime.txt + .resources\win32_error_codes_v23.0.txt = .resources\win32_error_codes_v23.0.txt + .resources\cpu_tier_list.conf = .resources\cpu_tier_list.conf + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU