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