Merge pull request #1002 from 13xforever/vnext

Add CPU tier list info
This commit is contained in:
Ilya
2025-07-12 18:22:02 +05:00
committed by GitHub
28 changed files with 408 additions and 84 deletions

View File

@@ -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

View File

@@ -1,4 +1,4 @@
0x00000000
0x00000000
ERROR_SUCCESS The operation completed successfully.
0x00000000
NERR_Success The operation completed successfully.

View File

@@ -9,9 +9,9 @@
<ProjectReference Include="..\CompatApiClient\CompatApiClient.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.7" />
<PackageReference Include="StrawberryShake.Server" Version="15.1.7" />
</ItemGroup>
</Project>

View File

@@ -8,7 +8,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.7" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageReference Include="NLog" Version="6.0.1" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.7" />
<PackageReference Include="Octokit" Version="14.0.0" />
<PackageReference Include="SharpCompress" Version="0.40.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.3" />

View File

@@ -5,9 +5,9 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LTRData.DiscUtils.OpticalDisk" Version="1.0.61" />
<PackageReference Include="LTRData.DiscUtils.OpticalDisk" Version="1.0.62" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageReference Include="System.IO.Hashing" Version="9.0.6" />
<PackageReference Include="System.IO.Hashing" Version="9.0.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CompatApiClient\CompatApiClient.csproj" />

View File

@@ -12,7 +12,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.7" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -31,37 +31,39 @@
</None>
</ItemGroup>
<ItemGroup>
<Content Include="..\metacritic_ps3.json" Link="metacritic_ps3.json">
<Content Include="..\.resources\metacritic_ps3.json" Link="metacritic_ps3.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Remove="..\win32_error_codes*.txt" />
<AdditionalFiles Include="..\win32_error_codes*.txt" />
<None Remove="..\.resources\win32_error_codes*.txt" />
<None Remove="..\.resources\cpu_tier_list*.conf" />
<AdditionalFiles Include="..\.resources\win32_error_codes*.txt" />
<AdditionalFiles Include="..\.resources\cpu_tier_list*.conf" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Blurhash.ImageSharp" Version="4.0.0" />
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.0" />
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02520" />
<PackageReference Include="DSharpPlus.Commands" Version="5.0.0-nightly-02520" />
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02520" />
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02531" />
<PackageReference Include="DSharpPlus.Commands" Version="5.0.0-nightly-02531" />
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02531" />
<PackageReference Include="DSharpPlus.Natives.Zstd" Version="1.5.7.21" />
<PackageReference Include="Florence2" Version="24.11.53800" />
<PackageReference Include="Google.Apis.Drive.v3" Version="1.69.0.3783" />
<PackageReference Include="Google.Apis.Drive.v3" Version="1.70.0.3834" />
<PackageReference Include="MathParser.org-mXparser" Version="6.1.0" />
<PackageReference Include="MegaApiClient" Version="1.10.4" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.23.0" />
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.23.0" />
<PackageReference Include="Microsoft.Azure.CognitiveServices.Vision.ComputerVision" Version="7.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.6">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.7" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />

View File

@@ -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)

View File

@@ -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*(?<build_and_specs>RPCS3 [^\xC2\xB7]+?)\r?(\n·|$)", DefaultSingleLine)]
private static partial Regex Rpcs3LogHeader();

View File

@@ -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}";

View File

@@ -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
{

View File

@@ -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`");

View File

@@ -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]";

View File

@@ -12,8 +12,8 @@
</ItemGroup>
<ItemGroup>
<None Remove="confusables.txt" />
<AdditionalFiles Include="confusables.txt" />
<None Remove="..\.resources\confusables.txt" />
<AdditionalFiles Include="..\.resources\confusables.txt" />
</ItemGroup>
<ItemGroup>

View File

@@ -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_<category>.txt`

View File

@@ -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<uint, uint[]> 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<uint, uint[]> 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));

View File

@@ -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<idx; i++)
result.AppendLine($"""
(@"{tierMap[i].model}", "{tierMap[i].tier}", Model{i}),
"""
);
result.AppendLine("""
];
}
"""
);
context.AddSource($"{cn}.Patterns.Generated.cs", SourceText.From(result.ToString(), Encoding.UTF8));
}
}

View File

@@ -10,9 +10,8 @@ using Microsoft.CodeAnalysis.Text;
namespace SourceGenerators;
[Generator(LanguageNames.CSharp)]
public class Win32ErrorsSourceGenerator : IIncrementalGenerator
public class Win32ErrorsSourceGenerator: IIncrementalGenerator
{
private const string Indent = " ";
private static readonly char[] Separator = ['\t'];
private static readonly DiagnosticDescriptor Win32ErrorFormatError = new(
@@ -44,21 +43,21 @@ public class Win32ErrorsSourceGenerator : IIncrementalGenerator
if (!args.generatorContext.configOptions.GlobalOptions.TryGetValue("build_property.RootNamespace", out var ns))
ns = args.generatorContext.compilation.AssemblyName;
var cn = "Win32ErrorCodes";
var result = new StringBuilder()
.AppendLine("using System.Collections.Generic;")
.AppendLine()
.AppendLine($"namespace {ns}")
.AppendLine("{")
.AppendLine($"{Indent}public static class {cn}")
.AppendLine($"{Indent}{{")
.AppendLine($"{Indent}{Indent}public static readonly Dictionary<int, (string name, string description)> 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<int, (string name, string description)> 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));
}
}

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DuoVia.FuzzyStrings" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="NUnit" Version="4.3.2" />
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0">

View File

@@ -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