From f5c0e8784506c5a7bbf83e65a3898470432edd38 Mon Sep 17 00:00:00 2001 From: 13xforever Date: Sat, 18 May 2024 10:56:12 +0500 Subject: [PATCH 1/8] upgrade deps, remove wrong ppu hashes --- Clients/CirrusCiClient/CirrusCiClient.csproj | 2 +- .../CompatApiClient/CompatApiClient.csproj | 2 +- Clients/GithubClient/GithubClient.csproj | 2 +- .../IrdLibraryClient/IrdLibraryClient.csproj | 2 +- CompatBot/CompatBot.csproj | 24 +++++++++---------- ...serResultFormatter.WeirdSettingsSection.cs | 2 -- Tests/Tests.csproj | 4 ++-- 7 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Clients/CirrusCiClient/CirrusCiClient.csproj b/Clients/CirrusCiClient/CirrusCiClient.csproj index fe42b3e0..a134d39e 100644 --- a/Clients/CirrusCiClient/CirrusCiClient.csproj +++ b/Clients/CirrusCiClient/CirrusCiClient.csproj @@ -11,6 +11,6 @@ - + \ No newline at end of file diff --git a/Clients/CompatApiClient/CompatApiClient.csproj b/Clients/CompatApiClient/CompatApiClient.csproj index d7eab5a6..d91730b4 100644 --- a/Clients/CompatApiClient/CompatApiClient.csproj +++ b/Clients/CompatApiClient/CompatApiClient.csproj @@ -17,7 +17,7 @@ - + diff --git a/Clients/GithubClient/GithubClient.csproj b/Clients/GithubClient/GithubClient.csproj index 14e0dae2..e762f69d 100644 --- a/Clients/GithubClient/GithubClient.csproj +++ b/Clients/GithubClient/GithubClient.csproj @@ -6,7 +6,7 @@ - + diff --git a/Clients/IrdLibraryClient/IrdLibraryClient.csproj b/Clients/IrdLibraryClient/IrdLibraryClient.csproj index fb910fc5..9604ca98 100644 --- a/Clients/IrdLibraryClient/IrdLibraryClient.csproj +++ b/Clients/IrdLibraryClient/IrdLibraryClient.csproj @@ -6,7 +6,7 @@ - + diff --git a/CompatBot/CompatBot.csproj b/CompatBot/CompatBot.csproj index 695463c2..12b4f951 100644 --- a/CompatBot/CompatBot.csproj +++ b/CompatBot/CompatBot.csproj @@ -43,32 +43,32 @@ - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - - - - + + + + + - - - + + + diff --git a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.WeirdSettingsSection.cs b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.WeirdSettingsSection.cs index 2865ef03..91b4bb97 100644 --- a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.WeirdSettingsSection.cs +++ b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.WeirdSettingsSection.cs @@ -877,13 +877,11 @@ private static void CheckDesSettings(string serial, NameValueCollection items, L "b18834a8f21cd29a091b287a66656a279ccba507", // NPUB31251 1.00 "9c04f427625a0064282432e4edfefe9e0956c303", // NPUB31251 1.01 "e1a44e5d3fb03a37f0445e92ed13abce8d6efdd4", // NPEB01407 - "60d4a7e2b5efa835e16f51de649c3e3b202e072e", // NPEB01407 delisted "a017576369165f3746730724c8ae762ed9bc64d8", // BLJM61043 1.00 "eda0339b931f6fe15420b053703ddd89b27d615b", // BLJM61043 1.01 "62eb0f5d8f0f929cb23309311b89ce21eaa3bc9e", // BLJM61043 1.02 "384a28c62ff179a4ae815ab7b711e76fbb1167b4", // BLJM61043 1.03 "c09c496514f6dc591434575b04eb7c003826c11d", // BLJM61043 1.04 - "5eb979631fbbe531db5d20f0622dca5a8b64090e", // unknown prob BCAS20311 1.00 "56cc988f7d5b5127049f28ed9278b98de2e4ff1f", // BCAS20311 1.01 "ac64494f4ea31f8b0f82584c48916d30dad16300", // BCAS20311 1.02 "20183817f17fb358d28131e195c5af1fc9579ada", // NPHB00633 1.00 diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 7a065a2c..cf279595 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -7,12 +7,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 1302e84508fd634cae06b57a571223cc5a8dcbb7 Mon Sep 17 00:00:00 2001 From: 13xforever Date: Sat, 18 May 2024 10:57:01 +0500 Subject: [PATCH 2/8] upgrade compiler packages will require container pull after build --- SourceGenerators/SourceGenerators.csproj | 2 +- Tests/Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SourceGenerators/SourceGenerators.csproj b/SourceGenerators/SourceGenerators.csproj index 76044ff8..71be6909 100644 --- a/SourceGenerators/SourceGenerators.csproj +++ b/SourceGenerators/SourceGenerators.csproj @@ -7,7 +7,7 @@ - + diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index cf279595..e114a568 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -6,7 +6,7 @@ - + all From ebb05438ddcabaffd1e2d96730850f8f8ae5840c Mon Sep 17 00:00:00 2001 From: 13xforever Date: Sat, 18 May 2024 14:28:45 +0500 Subject: [PATCH 3/8] replace Regex with compiler-generated versions --- Clients/IrdLibraryClient/IrdClient.cs | 1 - Clients/MediafireClient/Client.cs | 7 +- Clients/PsnClient/PsnClient.cs | 18 +- CompatBot/Commands/CompatList.cs | 14 +- CompatBot/Commands/ContentFilters.cs | 17 +- .../TextOnlyDiscordChannelConverter.cs | 9 +- CompatBot/Commands/EventsBaseCommand.cs | 9 +- CompatBot/Commands/Explain.cs | 3 +- CompatBot/Commands/Misc.cs | 11 +- CompatBot/Commands/Psn.Check.cs | 3 +- CompatBot/Commands/Psn.cs | 5 +- CompatBot/Commands/Sudo.Dotnet.cs | 10 +- CompatBot/Commands/Sudo.Fix.cs | 2 +- .../EventHandlers/BotReactionsHandler.cs | 11 +- .../EventHandlers/DiscordInviteFilter.cs | 18 +- CompatBot/EventHandlers/GithubLinksHandler.cs | 20 +- .../EventHandlers/IsTheGamePlayableHandler.cs | 18 +- CompatBot/EventHandlers/LogAsTextMonitor.cs | 7 +- .../LogParsing/LogParser.LogSections.cs | 329 ++++++++--------- .../LogParsing/LogParser.RegexPatterns.cs | 344 ++++++++++++++++++ .../SourceHandlers/DropboxHandler.cs | 7 +- .../SourceHandlers/GenericLinkHandler.cs | 7 +- .../SourceHandlers/GoogleDriveHandler.cs | 7 +- .../SourceHandlers/MediafireHandler.cs | 7 +- .../LogParsing/SourceHandlers/MegaHandler.cs | 7 +- .../SourceHandlers/OneDriveSourceHandler.cs | 7 +- .../SourceHandlers/PastebinHandler.cs | 7 +- .../SourceHandlers/YandexDiskHandler.cs | 7 +- CompatBot/EventHandlers/NewBuildsMonitor.cs | 7 +- CompatBot/EventHandlers/PostLogHelpHandler.cs | 11 +- CompatBot/EventHandlers/ProductCodeLookup.cs | 7 +- CompatBot/EventHandlers/TableFlipMonitor.cs | 7 +- .../EventHandlers/UnknownCommandHandler.cs | 11 +- CompatBot/ThumbScrapper/GameTdbScraper.cs | 13 +- CompatBot/ThumbScrapper/PsnScraper.cs | 20 +- .../Extensions/CommandContextExtensions.cs | 10 +- CompatBot/Utils/Extensions/StringUtils.cs | 6 +- .../Utils/ResultFormatters/FwInfoFormatter.cs | 10 +- ...ResultFormatter.CurrentSettingsSections.cs | 8 +- ...rserResultFormatter.GeneralNotesSection.cs | 17 +- ...serResultFormatter.WeirdSettingsSection.cs | 5 +- .../LogParserResultFormatter.cs | 49 ++- .../ResultFormatters/TitlePatchFormatter.cs | 3 +- .../ResultFormatters/UpdateInfoFormatter.cs | 6 +- Tests/RegexTest.cs | 15 +- 45 files changed, 757 insertions(+), 360 deletions(-) create mode 100644 CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs diff --git a/Clients/IrdLibraryClient/IrdClient.cs b/Clients/IrdLibraryClient/IrdClient.cs index 01377f9f..9c2e8788 100644 --- a/Clients/IrdLibraryClient/IrdClient.cs +++ b/Clients/IrdLibraryClient/IrdClient.cs @@ -24,7 +24,6 @@ public class IrdClient private readonly HttpClient client; private readonly JsonSerializerOptions jsonOptions; - private static readonly Regex IrdFilename = new(@"ird/(?\w{4}\d{5}-[A-F0-9]+\.ird)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); public IrdClient() { diff --git a/Clients/MediafireClient/Client.cs b/Clients/MediafireClient/Client.cs index 4d1d5b6e..eb72a97d 100644 --- a/Clients/MediafireClient/Client.cs +++ b/Clients/MediafireClient/Client.cs @@ -17,7 +17,7 @@ namespace MediafireClient; -public sealed class Client +public sealed partial class Client { private readonly HttpClient client; private readonly JsonSerializerOptions jsonOptions; @@ -25,7 +25,8 @@ public sealed class Client //var optSecurityToken = "1605819132.376f3d84695f46daa7b69ee67fbc5edb0a00843a8b2d5ac7d3d1b1ad8a4212b0"; //private static readonly Regex SecurityTokenRegex = new(@"(var\s+optSecurityToken|name=""security"" value)\s*=\s*""(?.+)""", RegexOptions.ExplicitCapture); //var optDirectURL = "https://download1499.mediafire.com/12zqzob7gbfg/tmybrjpmtrpcejl/DemonsSouls_CrashLog_Nov.19th.zip"; - private static readonly Regex DirectUrlRegex = new(@"(var\s+optDirectURL|href)\s*=\s*""(?https?://download\d+\.mediafire\.com/.+)"""); + [GeneratedRegex(@"(var\s+optDirectURL|href)\s*=\s*""(?https?://download\d+\.mediafire\.com/.+)""")] + private static partial Regex DirectUrlRegex(); public Client() { @@ -81,7 +82,7 @@ public Client() { await response.Content.LoadIntoBufferAsync().ConfigureAwait(false); var html = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); - var m = DirectUrlRegex.Match(html); + var m = DirectUrlRegex().Match(html); if (m.Success) return new(m.Groups["direct_link"].Value); } diff --git a/Clients/PsnClient/PsnClient.cs b/Clients/PsnClient/PsnClient.cs index 1b77c717..0cfa4ed2 100644 --- a/Clients/PsnClient/PsnClient.cs +++ b/Clients/PsnClient/PsnClient.cs @@ -20,7 +20,7 @@ namespace PsnClient; -public class Client +public partial class Client { private readonly HttpClient client; private readonly JsonSerializerOptions dashedJson; @@ -28,7 +28,6 @@ public class Client private readonly MediaTypeFormatterCollection xmlFormatters; private static readonly MemoryCache ResponseCache = new(new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan.FromHours(1) }); private static readonly TimeSpan ResponseCacheDuration = TimeSpan.FromHours(1); - private static readonly Regex ContainerIdLink = new(@"(?STORE-(\w|\d)+-(\w|\d)+)"); private static readonly string[] KnownStoreLocales = { "en-US", "en-GB", "en-AE", "en-AU", "en-BG", "en-BH", "en-CA", "en-CY", "en-CZ", "en-DK", "en-FI", "en-GR", "en-HK", "en-HR", "en-HU", "en-ID", "en-IE", "en-IL", "en-IN", "en-IS", @@ -37,11 +36,16 @@ public class Client "es-HN", "es-MX", "es-NI", "es-PA", "es-PE", "es-PY", "es-SV", "es-UY", "fi-FI", "fr-BE", "fr-CA", "fr-CH", "fr-FR", "fr-LU", "it-CH", "it-IT", "ko-KR", "nl-BE", "nl-NL", "no-NO", "pl-PL", "pt-BR", "pt-PT", "ru-RU", "ru-UA", "sv-SE", "tr-TR", "zh-Hans-CN", "zh-Hans-HK", "zh-Hant-HK", "zh-Hant-TW", }; + + [GeneratedRegex(@"(?STORE-(\w|\d)+-(\w|\d)+)")] + private static partial Regex ContainerIdLink(); + // Dest=87;ImageVersion=0001091d;SystemSoftwareVersion=4.8500;CDN=http://duk01.ps3.update.playstation.net/update/ps3/image/uk/2019_0828_c975768e5d70e105a72656f498cc9be9/PS3UPDAT.PUP;CDN_Timeout=30; - private static readonly Regex FwVersionInfo = new( + [GeneratedRegex( @"Dest=(?\d+);ImageVersion=(?[0-9a-f]+);SystemSoftwareVersion=(?\d+\.\d+);CDN=(?http[^;]+);CDN_Timeout=(?\d+)", - RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.IgnoreCase - ); + RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.IgnoreCase + )] + private static partial Regex FwVersionInfo(); // directly from vsh.self private static readonly string[] KnownFwLocales = { "jp", "us", "eu", "kr", "uk", "mx", "au", "sa", "tw", "ru", "cn", "br", }; @@ -125,7 +129,7 @@ public Client() { await response.Content.LoadIntoBufferAsync().ConfigureAwait(false); var html = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); - var matches = ContainerIdLink.Matches(html); + var matches = ContainerIdLink().Matches(html); var result = new List(); foreach (Match m in matches) if (m.Groups["id"].Value is {Length: >0} id) @@ -419,7 +423,7 @@ private async Task GetSessionCookies(string locale, CancellationToken ca if (string.IsNullOrEmpty(data)) return null; - if (FwVersionInfo.Match(data) is not { Success: true } m) + if (FwVersionInfo().Match(data) is not { Success: true } m) return null; var ver = m.Groups["version"].Value; diff --git a/CompatBot/Commands/CompatList.cs b/CompatBot/Commands/CompatList.cs index 746d8291..75ee41c8 100644 --- a/CompatBot/Commands/CompatList.cs +++ b/CompatBot/Commands/CompatList.cs @@ -32,7 +32,7 @@ namespace CompatBot.Commands; -internal sealed class CompatList : BaseCommandModuleCustom +internal sealed partial class CompatList : BaseCommandModuleCustom { private static readonly Client Client = new(); private static readonly GithubClient.Client GithubClient = new(Config.GithubToken); @@ -41,10 +41,10 @@ internal sealed class CompatList : BaseCommandModuleCustom private const string Rpcs3UpdateStateKey = "Rpcs3UpdateState"; private const string Rpcs3UpdateBuildKey = "Rpcs3UpdateBuild"; private static UpdateInfo? cachedUpdateInfo; - private static readonly Regex UpdateVersionRegex = new( - @"v(?\d+\.\d+\.\d+)-(?\d+)-(?[0-9a-f]+)\b", - RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture - ); + [GeneratedRegex(@"v(?\d+\.\d+\.\d+)-(?\d+)-(?[0-9a-f]+)\b", RegexOptions.Singleline | RegexOptions.ExplicitCapture)] + private static partial Regex UpdateVersionRegex(); + [GeneratedRegex(@"\b(demo|trial)\b", RegexOptions.IgnoreCase | RegexOptions.Singleline)] + internal static partial Regex TrialNamePattern(); static CompatList() { @@ -247,7 +247,7 @@ public static async Task CheckForRpcs3Updates(DiscordClient discordClient, var latestUpdatePr = info?.LatestBuild?.Pr?.ToString(); var match = ( from field in embed.Fields - let m = UpdateVersionRegex.Match(field.Value) + let m = UpdateVersionRegex().Match(field.Value) where m.Success select m ).FirstOrDefault(); @@ -697,7 +697,7 @@ public static async Task ImportMetacriticScoresAsync() Config.Log.Warn(e); } } - matches = matches.Where(i => !Regex.IsMatch(i.thumb.Name ?? "", @"\b(demo|trial)\b", RegexOptions.IgnoreCase | RegexOptions.Singleline)).ToList(); + matches = matches.Where(i => !TrialNamePattern().IsMatch(i.thumb.Name ?? "")).ToList(); //var bestMatch = matches.FirstOrDefault(); //Config.Log.Trace($"Best title match for [{item.Title}] is [{bestMatch.thumb.Name}] with score {bestMatch.coef:0.0000}"); if (matches.Count > 0) diff --git a/CompatBot/Commands/ContentFilters.cs b/CompatBot/Commands/ContentFilters.cs index abadf51a..81651efe 100644 --- a/CompatBot/Commands/ContentFilters.cs +++ b/CompatBot/Commands/ContentFilters.cs @@ -29,12 +29,16 @@ namespace CompatBot.Commands; [Group("filters"), Aliases("piracy", "filter"), RequiresBotSudoerRole, RequiresDm] [Description("Used to manage content filters. **Works only in DM**")] -internal sealed class ContentFilters: BaseCommandModuleCustom +internal sealed partial class ContentFilters: BaseCommandModuleCustom { private static readonly TimeSpan InteractTimeout = TimeSpan.FromMinutes(5); private static readonly char[] Separators = {' ', ',', ';', '|'}; private static readonly SemaphoreSlim ImportLock = new(1, 1); + // match for "complex" names with several regions, or region-languages, or explicit revision + [GeneratedRegex(@" (\(.+\)\s*\(.+\)|\(\w+(,\s*\w+)+\))\.iso$")] + private static partial Regex ExtraIsoInfoPattern(); + [Command("list")] [Description("Lists all filters")] public async Task List(CommandContext ctx) @@ -202,8 +206,8 @@ public async Task Import(CommandContext ctx) if (string.IsNullOrEmpty(name)) continue; - // only match for "complex" names with several regions, or region-languages, or explicit revision - if (!Regex.IsMatch(name, @" (\(.+\)\s*\(.+\)|\(\w+(,\s*\w+)+\))\.iso$")) + + if (!ExtraIsoInfoPattern().IsMatch(name)) continue; name = name[..^4]; //-.iso @@ -710,7 +714,12 @@ Additional validation can help reduce false positives of a plaintext trigger mat { try { - _ = Regex.IsMatch("test", txt.Content, RegexOptions.Multiline | RegexOptions.IgnoreCase); + _ = Regex.IsMatch( + filter.String ?? "test", + txt.Content, + RegexOptions.Multiline | RegexOptions.IgnoreCase, + TimeSpan.FromMilliseconds(100) + ); } catch (Exception e) { diff --git a/CompatBot/Commands/Converters/TextOnlyDiscordChannelConverter.cs b/CompatBot/Commands/Converters/TextOnlyDiscordChannelConverter.cs index 78b3f082..2108c7e7 100644 --- a/CompatBot/Commands/Converters/TextOnlyDiscordChannelConverter.cs +++ b/CompatBot/Commands/Converters/TextOnlyDiscordChannelConverter.cs @@ -10,9 +10,10 @@ namespace CompatBot.Commands.Converters; -internal sealed class TextOnlyDiscordChannelConverter : IArgumentConverter +internal sealed partial class TextOnlyDiscordChannelConverter : IArgumentConverter { - private static Regex ChannelRegex { get; } = new(@"^<#(\d+)>$", RegexOptions.ECMAScript | RegexOptions.Compiled); + [GeneratedRegex(@"^<#(\d+)>$", RegexOptions.ECMAScript)] + private static partial Regex ChannelRegex(); Task> IArgumentConverter.ConvertAsync(string value, CommandContext ctx) => ConvertAsync(value, ctx); @@ -20,7 +21,7 @@ Task> IArgumentConverter.ConvertAsync(s public static async Task> ConvertAsync(string value, CommandContext ctx) { var guildList = new List(ctx.Client.Guilds.Count); - if (ctx.Guild == null) + if (ctx.Guild is null) foreach (var g in ctx.Client.Guilds.Keys) guildList.Add(await ctx.Client.GetGuildAsync(g).ConfigureAwait(false)); else @@ -37,7 +38,7 @@ select ch return ret; } - var m = ChannelRegex.Match(value); + var m = ChannelRegex().Match(value); if (m.Success && ulong.TryParse(m.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out cid)) { var result = ( diff --git a/CompatBot/Commands/EventsBaseCommand.cs b/CompatBot/Commands/EventsBaseCommand.cs index 0b71b50e..b7ded652 100644 --- a/CompatBot/Commands/EventsBaseCommand.cs +++ b/CompatBot/Commands/EventsBaseCommand.cs @@ -19,11 +19,12 @@ namespace CompatBot.Commands; -internal class EventsBaseCommand: BaseCommandModuleCustom +internal partial class EventsBaseCommand: BaseCommandModuleCustom { private static readonly TimeSpan InteractTimeout = TimeSpan.FromMinutes(5); - private static readonly Regex Duration = new(@"((?\d+)(\.|d\s*))?((?\d+)(\:|h\s*))?((?\d+)m?)?", - RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture); + + [GeneratedRegex(@"((?\d+)(\.|d\s*))?((?\d+)(\:|h\s*))?((?\d+)m?)?", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture)] + private static partial Regex Duration(); protected static async Task NearestEvent(CommandContext ctx, string? eventName = null) { @@ -546,7 +547,7 @@ protected static async Task List(CommandContext ctx, string? eventName = null, i private static async Task TryParseTimeSpanAsync(CommandContext ctx, string duration, bool react = true) { - var d = Duration.Match(duration); + var d = Duration().Match(duration); if (!d.Success) { if (react) diff --git a/CompatBot/Commands/Explain.cs b/CompatBot/Commands/Explain.cs index f8529910..5f0c8c86 100644 --- a/CompatBot/Commands/Explain.cs +++ b/CompatBot/Commands/Explain.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Runtime.InteropServices; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using CompatApiClient.Compression; using CompatApiClient.Utils; @@ -330,7 +331,7 @@ public async Task Dump(CommandContext ctx, [RemainingText, Description("Term to return; termOrLink = termOrLink.ToLowerInvariant().StripQuotes(); - var isLink = CommandContextExtensions.MessageLinkRegex.IsMatch(termOrLink); + var isLink = CommandContextExtensions.MessageLinkPattern().IsMatch(termOrLink); if (isLink) { await DumpLink(ctx, termOrLink).ConfigureAwait(false); diff --git a/CompatBot/Commands/Misc.cs b/CompatBot/Commands/Misc.cs index 0999ca6c..c7479a34 100644 --- a/CompatBot/Commands/Misc.cs +++ b/CompatBot/Commands/Misc.cs @@ -16,7 +16,7 @@ namespace CompatBot.Commands; -internal sealed class Misc: BaseCommandModuleCustom +internal sealed partial class Misc: BaseCommandModuleCustom { private static readonly Random rng = new(); @@ -128,7 +128,10 @@ internal sealed class Misc: BaseCommandModuleCustom private static readonly HashSet Vowels = new() {'a', 'e', 'i', 'o', 'u'}; - private static readonly Regex Instead = new("rate (?.+) instead", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline); + [GeneratedRegex("rate (?.+) instead", RegexOptions.ExplicitCapture | RegexOptions.Singleline)] + private static partial Regex Instead(); + [GeneratedRegex(@"(?\d+)?d(?\d+)(?:\+(?\d+))?")] + private static partial Regex DiceNotationPattern(); [Command("roll")] [Description("Generates a random number between 1 and maxValue. Can also roll dices like `2d6`. Default is 1d6")] @@ -155,7 +158,7 @@ internal static async Task RollImpl(DiscordMessage message, string dices) { var result = ""; var embed = new DiscordEmbedBuilder(); - if (dices is string dice && Regex.Matches(dice, @"(?\d+)?d(?\d+)(?:\+(?\d+))?") is {Count: > 0 and <= EmbedPager.MaxFields } matches) + if (dices is string dice && DiceNotationPattern().Matches(dice) is {Count: > 0 and <= EmbedPager.MaxFields } matches) { var grandTotal = 0; foreach (Match m in matches) @@ -318,7 +321,7 @@ public async Task Rate(CommandContext ctx, [RemainingText, Description("Somethin var choiceFlags = new HashSet(); whatever = whatever.ToLowerInvariant().StripInvisibleAndDiacritics(); var originalWhatever = whatever; - var matches = Instead.Matches(whatever); + var matches = Instead().Matches(whatever); if (matches.Any()) { var insteadWhatever = matches.Last().Groups["instead"].Value.TrimEager(); diff --git a/CompatBot/Commands/Psn.Check.cs b/CompatBot/Commands/Psn.Check.cs index d4e82555..d6ca65d8 100644 --- a/CompatBot/Commands/Psn.Check.cs +++ b/CompatBot/Commands/Psn.Check.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using CompatApiClient; @@ -158,7 +159,7 @@ public async Task Content(CommandContext ctx, [RemainingText, Description("Conte return; } - var matches = PsnScraper.ContentIdMatcher.Matches(contentIds.ToUpperInvariant()); + var matches = PsnScraper.ContentIdMatcher().Matches(contentIds.ToUpperInvariant()); var itemsToCheck = matches.Select(m => m.Groups["content_id"].Value).ToList(); if (itemsToCheck.Count == 0) { diff --git a/CompatBot/Commands/Psn.cs b/CompatBot/Commands/Psn.cs index 0cd056d8..92763af6 100644 --- a/CompatBot/Commands/Psn.cs +++ b/CompatBot/Commands/Psn.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using CompatBot.Commands.Attributes; using CompatBot.Database; @@ -39,8 +40,8 @@ public async Task Rename(CommandContext ctx, [Description("Product code such as public async Task Add(CommandContext ctx, [Description("Product code such as BLUS12345")] string contentId, [RemainingText, Description("New game title to save in the database")] string title) { contentId = contentId.ToUpperInvariant(); - var productCodeMatch = ProductCodeLookup.ProductCode.Match(contentId); - var contentIdMatch = PsnScraper.ContentIdMatcher.Match(contentId); + var productCodeMatch = ProductCodeLookup.Pattern().Match(contentId); + var contentIdMatch = PsnScraper.ContentIdMatcher().Match(contentId); string productCode; if (contentIdMatch.Success) { diff --git a/CompatBot/Commands/Sudo.Dotnet.cs b/CompatBot/Commands/Sudo.Dotnet.cs index 91e4bb53..27511303 100644 --- a/CompatBot/Commands/Sudo.Dotnet.cs +++ b/CompatBot/Commands/Sudo.Dotnet.cs @@ -17,6 +17,9 @@ internal partial class Sudo [Description("Commands to manage dotnet")] public sealed partial class Dotnet : BaseCommandModuleCustom { + [GeneratedRegex(@"\.NET( Core)? (?\d+)\.(?\d+)\.(?\d+)(-.+)?", RegexOptions.ExplicitCapture | RegexOptions.Singleline)] + private static partial Regex DotnetVersionPattern(); + [Command("update"), Aliases("upgrade")] [Description("Updates dotnet, and then restarts the bot")] public async Task Update(CommandContext ctx, [Description("Dotnet SDK version (e.g. `5.1`)")] string version = "") @@ -67,11 +70,7 @@ public async Task Update(CommandContext ctx, [Description("Dotnet SDK version (e if (string.IsNullOrEmpty(version)) { - var versionMatch = Regex.Match( - System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription, - @"\.NET( Core)? (?\d+)\.(?\d+)\.(?\d+)(-.+)?", - RegexOptions.Singleline | RegexOptions.ExplicitCapture - ); + var versionMatch = DotnetVersionPattern().Match(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription); if (!versionMatch.Success) throw new InvalidOperationException("Failed to resolve required dotnet sdk version"); @@ -102,6 +101,5 @@ public async Task Update(CommandContext ctx, [Description("Dotnet SDK version (e return (true, stdout); } - } } \ No newline at end of file diff --git a/CompatBot/Commands/Sudo.Fix.cs b/CompatBot/Commands/Sudo.Fix.cs index bd5daeb5..bc3db300 100644 --- a/CompatBot/Commands/Sudo.Fix.cs +++ b/CompatBot/Commands/Sudo.Fix.cs @@ -144,7 +144,7 @@ public async Task TitleMarks(CommandContext ctx) { if (demosOnly && thumb.Name != null - && !Regex.IsMatch(thumb.Name, @"\b(demo|trial)\b", RegexOptions.IgnoreCase | RegexOptions.Singleline)) + && !CompatList.TrialNamePattern().IsMatch(thumb.Name)) continue; thumb.MetacriticId = null; diff --git a/CompatBot/EventHandlers/BotReactionsHandler.cs b/CompatBot/EventHandlers/BotReactionsHandler.cs index 64245ee8..7b0090f1 100644 --- a/CompatBot/EventHandlers/BotReactionsHandler.cs +++ b/CompatBot/EventHandlers/BotReactionsHandler.cs @@ -15,7 +15,7 @@ namespace CompatBot.EventHandlers { - internal static class BotReactionsHandler + internal static partial class BotReactionsHandler { private static readonly AhoCorasickDoubleArrayTrie ChillCheck = new(new[] { @@ -68,10 +68,9 @@ internal static class BotReactionsHandler "Glad I could help", "I try my best", "Blessed day", "It is officially a good day today", "I will remember you when the uprising starts", }; - private static readonly Regex Paws = new( - @"\b((?kot(to)?)|(?doggo|jarves))\b", - RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture - ); + + [GeneratedRegex(@"\b((?kot(to)?)|(?doggo|jarves))\b", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture)] + private static partial Regex Paws(); private static readonly Random Rng = new(); private static readonly object TheDoor = new(); @@ -127,7 +126,7 @@ public static async Task OnMessageCreated(DiscordClient c, MessageCreateEventArg } #endif - if (!string.IsNullOrEmpty(args.Message.Content) && Paws.Matches(args.Message.Content) is MatchCollection mc) + if (!string.IsNullOrEmpty(args.Message.Content) && Paws().Matches(args.Message.Content) is MatchCollection mc) { await using var db = new BotDb(); var matchedGroups = (from m in mc diff --git a/CompatBot/EventHandlers/DiscordInviteFilter.cs b/CompatBot/EventHandlers/DiscordInviteFilter.cs index 2808d381..b75601f8 100644 --- a/CompatBot/EventHandlers/DiscordInviteFilter.cs +++ b/CompatBot/EventHandlers/DiscordInviteFilter.cs @@ -18,10 +18,14 @@ namespace CompatBot.EventHandlers; -internal static class DiscordInviteFilter +internal static partial class DiscordInviteFilter { - private const RegexOptions DefaultOptions = RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Multiline; - private static readonly Regex InviteLink = new(@"(https?://)?discord((((app)?\.com/invite|\.gg)/(?[a-z0-9\-]+))|(\.me/(?.*?))(\s|>|$))", DefaultOptions); + [GeneratedRegex(@"(https?://)?discord((((app)?\.com/invite|\.gg)/(?[a-z0-9\-]+))|(\.me/(?.*?))(\s|>|$))", RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Multiline)] + private static partial Regex InviteLink(); + [GeneratedRegex(@"name=""csrf-token"" content=""(?\w+)""")] + private static partial Regex CsrfTokenPattern(); + [GeneratedRegex(@"name=""serverEid"" value=""(?\w+)""")] + private static partial Regex ServerEidPattern(); private static readonly MemoryCache InviteCodeCache = new(new MemoryCacheOptions{ExpirationScanFrequency = TimeSpan.FromHours(1)}); private static readonly TimeSpan CacheDuration = TimeSpan.FromHours(24); @@ -189,8 +193,8 @@ where msg.CreationTimestamp > after if (string.IsNullOrEmpty(message)) return (false, false, new(0)); - var inviteCodes = new HashSet(InviteLink.Matches(message).Select(m => m.Groups["invite_id"].Value).Where(s => !string.IsNullOrEmpty(s))); - var discordMeLinks = InviteLink.Matches(message).Select(m => m.Groups["me_id"].Value).Distinct().Where(s => !string.IsNullOrEmpty(s)).ToList(); + var inviteCodes = new HashSet(InviteLink().Matches(message).Select(m => m.Groups["invite_id"].Value).Where(s => !string.IsNullOrEmpty(s))); + var discordMeLinks = InviteLink().Matches(message).Select(m => m.Groups["me_id"].Value).Distinct().Where(s => !string.IsNullOrEmpty(s)).ToList(); var attemptedWorkaround = false; if (author != null && InviteCodeCache.TryGetValue(author.Id, out HashSet? recentInvites) && recentInvites is not null) { @@ -232,8 +236,8 @@ where msg.CreationTimestamp > after continue; hasInvalidInvites = true; - var csrfTokenMatch = Regex.Match(html, @"name=""csrf-token"" content=""(?\w+)"""); - var serverEidMatch = Regex.Match(html, @"name=""serverEid"" value=""(?\w+)"""); + var csrfTokenMatch = CsrfTokenPattern().Match(html); + var serverEidMatch = ServerEidPattern().Match(html); if (csrfTokenMatch.Success && serverEidMatch.Success) { using var postRequest = new HttpRequestMessage(HttpMethod.Post, "https://discord.me/server/join") diff --git a/CompatBot/EventHandlers/GithubLinksHandler.cs b/CompatBot/EventHandlers/GithubLinksHandler.cs index ff228619..944d5d3b 100644 --- a/CompatBot/EventHandlers/GithubLinksHandler.cs +++ b/CompatBot/EventHandlers/GithubLinksHandler.cs @@ -11,13 +11,17 @@ namespace CompatBot.EventHandlers; -internal static class GithubLinksHandler +internal static partial class GithubLinksHandler { - private const RegexOptions DefaultOptions = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture; - public static readonly Regex IssueMention = new(@"(?\b(issue|pr|pull[ \-]request|bug)\s*#?\s*(?\d+)|\B#(?1?\d{4})|(https?://)github.com/RPCS3/rpcs3/(issues|pull)/(?\d+)(#issuecomment-(?\d+))?)\b", DefaultOptions); - public static readonly Regex CommitMention = new(@"(?(https?://)github.com/RPCS3/rpcs3/commit/(?[0-9a-f]+))\b", DefaultOptions); - public static readonly Regex ImageMarkup = new(@"(?!\[(?[^\]]+)\]\((?\w+://[^\)]+)\))", DefaultOptions); - private static readonly Regex IssueLink = new(@"github.com/RPCS3/rpcs3/issues/(?\d+)", DefaultOptions); + private const RegexOptions DefaultOptions = RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture; + [GeneratedRegex(@"(?\b(issue|pr|pull[ \-]request|bug)\s*#?\s*(?\d+)|\B#(?1?\d{4})|(https?://)github.com/RPCS3/rpcs3/(issues|pull)/(?\d+)(#issuecomment-(?\d+))?)\b", DefaultOptions)] + internal static partial Regex IssueMention(); + [GeneratedRegex(@"(?(https?://)github.com/RPCS3/rpcs3/commit/(?[0-9a-f]+))\b", DefaultOptions)] + internal static partial Regex CommitMention(); + [GeneratedRegex(@"(?!\[(?[^\]]+)\]\((?\w+://[^\)]+)\))", DefaultOptions)] + internal static partial Regex ImageMarkup(); + [GeneratedRegex(@"github.com/RPCS3/rpcs3/issues/(?\d+)", DefaultOptions)] + internal static partial Regex IssueLink(); public static async Task OnMessageCreated(DiscordClient c, MessageCreateEventArgs args) { @@ -72,7 +76,7 @@ public static async Task OnMessageCreated(DiscordClient c, MessageCreateEventArg public static List GetIssueIds(string input) { - return IssueMention.Matches(input) + return IssueMention().Matches(input) .SelectMany(match => new[] { match.Groups["number"].Value, @@ -87,7 +91,7 @@ public static List GetIssueIds(string input) public static HashSet GetIssueIdsFromLinks(string input) { return new( - IssueLink.Matches(input) + IssueLink().Matches(input) .Select(match => { _ = int.TryParse(match.Groups["number"].Value, out var n); diff --git a/CompatBot/EventHandlers/IsTheGamePlayableHandler.cs b/CompatBot/EventHandlers/IsTheGamePlayableHandler.cs index 5429863d..eeb7432b 100644 --- a/CompatBot/EventHandlers/IsTheGamePlayableHandler.cs +++ b/CompatBot/EventHandlers/IsTheGamePlayableHandler.cs @@ -17,15 +17,15 @@ namespace CompatBot.EventHandlers; -internal static class IsTheGamePlayableHandler +internal static partial class IsTheGamePlayableHandler { - private const RegexOptions DefaultOptions = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture; - private static readonly Regex GameNameStatusMention1 = new( - @"(\b((is|does|can I play|any(one|1) tr(y|ied)|how's|(wonder(ing)?|me|knows?) if)\s+)(?.+?)\s+((now|currently|at all|possibly|fully|(on (this|the) )emu(lator))\s+)?((it?s )?playable|work(s|ing)?|runs?|doing))\b" + - @"|(\b(((can I|possible to) (play|run)|any(one|1) tr(y|ied)|compat[ai]bility (with|of))\s+)(?.+?)(\s+((now|currently|at all|possibly|fully)\s+)?((it?s )?playable|work(s|ing)?|on (it|this))\b|\?|$))" + + [GeneratedRegex( + @"(\b((is|does|can I play|any(one|1) tr(y|ied)|how's|(wonder(ing)?|me|knows?) if)\s+)(?.+?)\s+((now|currently|at all|possibly|fully|(on (this|the) )emu(lator))\s+)?((it?s )?playable|work(s|ing)?|runs?|doing))\b"+ + @"|(\b(((can I|possible to) (play|run)|any(one|1) tr(y|ied)|compat[ai]bility (with|of))\s+)(?.+?)(\s+((now|currently|at all|possibly|fully)\s+)?((it?s )?playable|work(s|ing)?|on (it|this))\b|\?|$))"+ @"|(^(?.+?)\s+((is )?(playable|work(s|ing)?))\?)", - DefaultOptions - ); + RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture + )] + private static partial Regex GameNameStatusMention(); private static readonly ConcurrentDictionary CooldownBuckets = new(); private static readonly TimeSpan CooldownThreshold = TimeSpan.FromSeconds(5); private static readonly Client Client = new(); @@ -48,7 +48,7 @@ public static async Task OnMessageCreated(DiscordClient c, MessageCreateEventArg return; #endif - var matches = GameNameStatusMention1.Matches(args.Message.Content); + var matches = GameNameStatusMention().Matches(args.Message.Content); if (!matches.Any()) return; @@ -65,7 +65,7 @@ public static async Task OnMessageCreated(DiscordClient c, MessageCreateEventArg if (gameTitle.Length < 4) return; - if (ProductCodeLookup.ProductCode.IsMatch(args.Message.Content)) + if (ProductCodeLookup.Pattern().IsMatch(args.Message.Content)) return; var (_, info) = await LookupGameAsync(args.Channel, args.Message, gameTitle).ConfigureAwait(false); diff --git a/CompatBot/EventHandlers/LogAsTextMonitor.cs b/CompatBot/EventHandlers/LogAsTextMonitor.cs index 49c0e886..b1a87a92 100644 --- a/CompatBot/EventHandlers/LogAsTextMonitor.cs +++ b/CompatBot/EventHandlers/LogAsTextMonitor.cs @@ -10,9 +10,10 @@ namespace CompatBot.EventHandlers; -internal static class LogAsTextMonitor +internal static partial class LogAsTextMonitor { - private static readonly Regex LogLine = new(@"^[`""]?(·|(\w|!)) ({(rsx|PPU|SPU)|LDR:)|E LDR:", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline); + [GeneratedRegex(@"^[`""]?(·|(\w|!)) ({(rsx|PPU|SPU)|LDR:)|E LDR:", RegexOptions.IgnoreCase | RegexOptions.Multiline)] + private static partial Regex LogLine(); public static async Task OnMessageCreated(DiscordClient _, MessageCreateEventArgs args) { @@ -25,7 +26,7 @@ public static async Task OnMessageCreated(DiscordClient _, MessageCreateEventArg if ((args.Message.Author as DiscordMember)?.Roles.Any() ?? false) return; - if (LogLine.IsMatch(args.Message.Content)) + if (LogLine().IsMatch(args.Message.Content)) { var brokenDump = false; string msg = ""; diff --git a/CompatBot/EventHandlers/LogParsing/LogParser.LogSections.cs b/CompatBot/EventHandlers/LogParsing/LogParser.LogSections.cs index cc1d2114..457294d5 100644 --- a/CompatBot/EventHandlers/LogParsing/LogParser.LogSections.cs +++ b/CompatBot/EventHandlers/LogParsing/LogParser.LogSections.cs @@ -1,19 +1,14 @@ using System.Collections.Generic; -using System.Text.RegularExpressions; using System.Threading.Tasks; using CompatBot.Database; using CompatBot.Database.Providers; using CompatBot.EventHandlers.LogParsing.POCOs; using CompatBot.Utils; -using CompatBot.Utils.ResultFormatters; namespace CompatBot.EventHandlers.LogParsing; internal partial class LogParser { - private const RegexOptions DefaultOptions = RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.ExplicitCapture; - private const RegexOptions DefaultSingleLineOptions = RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture; - /* * Extractors are defined in terms of trigger-extractor * @@ -29,30 +24,30 @@ internal partial class LogParser { Extractors = new() { - ["RPCS3 v"] = new(@"(^|.+\d:\d\d:\d\d\.\d{6})\s*(?RPCS3 [^\xC2\xB7]+?)\r?(\n·|$)", DefaultSingleLineOptions), - ["0:00:00.0"] = new(@"(?·).+\r?$", DefaultOptions), - ["Operating system:"] = LogParserResult.OsInfoInLog, - ["Current Time:"] = new(@"Current Time: (?.+)\r?$", DefaultOptions), - ["Installation ID:"] = new(@"Installation ID: (?.+)\r?$", DefaultOptions), - ["Physical device in"] = new(@"Physical device ini?tialized\. GPU=(?.+), driver=(?-?\d+)\r?$", DefaultOptions), - ["Found vulkan-compatible GPU:"] = new(@"Found [Vv]ulkan-compatible GPU: (?'(?.+)' running.+)\r?$", DefaultOptions), - ["Finished reading database from file:"] = new(@"Finished reading database from file: (?.*compat_database.dat).*\r?$", DefaultOptions), - ["Database file not found:"] = new(@"Database file not found: (?.*compat_database.dat).*\r?$", DefaultOptions), - ["Successfully installed PS3 firmware"] = new(@"(?Successfully installed PS3 firmware) version (?\d+\.\d+).*\r?$", DefaultOptions), - ["Firmware version:"] = new(@"Firmware version: (?\d+\.\d+).*\r?$", DefaultOptions), - ["Title:"] = new(@"(?:LDR|SYS): Title: (?.*)?\r?$", DefaultOptions), - ["Serial:"] = new(@"Serial: (?[A-z]{4}\d{5})\r?$", DefaultOptions), - ["Category:"] = new(@"Category: (?.*)?\r?$", DefaultOptions), - ["LDR: Version:"] = new(@"Version: (?\S+) / (?\S+).*?\r?$", DefaultOptions), - ["SYS: Version:"] = new(@"Version: (APP_VER=)?(?\S+) (/ |VERSION=)(?\S+).*?\r?$", DefaultOptions), - ["LDR: Cache"] = new(@"Cache: ((?\w:/)|(?/[^/])).*?\r?$", DefaultOptions), - ["SYS: Cache"] = new(@"Cache: ((?\w:/)|(?/[^/])).*?\r?$", DefaultOptions), - ["LDR: Path"] = new(@"Path: ((?\w:/)|(?/[^/])).*?\r?$", DefaultOptions), - ["SYS: Path"] = new(@"Path: ((?\w:/)|(?/[^/])).*?\r?$", DefaultOptions), - ["LDR: Path:"] = new(@"Path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions), - ["SYS: Path:"] = new(@"Path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions), - ["custom config:"] = new(@"custom config: (?.*?)\r?$", DefaultOptions), - ["patch_log: Failed to load patch file"] = new(@"patch_log: Failed to load patch file (?\S*)\r?\n.* line (?\d+), column (?\d+): (?.*?)$", DefaultOptions), + ["RPCS3 v"] = Rpcs3LogHeader(), + ["0:00:00.0"] = FirstLineWithDot(), + ["Operating system:"] = OsInfo(), + ["Current Time:"] = CurrentTime(), + ["Installation ID:"] = InstallationId(), + ["Physical device in"] = PhysicalDeviceName(), + ["Found vulkan-compatible GPU:"] = VulkanDeviceName(), + ["Finished reading database from file:"] = CompatDbFoundPath(), + ["Database file not found:"] = CompatDbNotFoundPath(), + ["Successfully installed PS3 firmware"] = FwInstallMessage(), + ["Firmware version:"] = FwVersion(), + ["Title:"] = GameTitle(), + ["Serial:"] = GameSerial(), + ["Category:"] = GameCategory(), + ["LDR: Version:"] = DiscVersionLdr(), + ["SYS: Version:"] = DiscVersionSys(), + ["LDR: Cache"] = CachePathLdr(), + ["SYS: Cache"] = CachePathSys(), + ["LDR: Path"] = BootPathLdr(), + ["SYS: Path"] = BootPathSys(), + ["LDR: Path:"] = BootPathDigitalLdr(), + ["SYS: Path:"] = BootPathDigitalSys(), + ["custom config:"] = CustomConfigPath(), + ["patch_log: Failed to load patch file"] = FailedPatchPath(), }, EndTrigger = new[] {"Used configuration:"}, }, @@ -60,36 +55,36 @@ internal partial class LogParser { Extractors = new() { - ["PPU Decoder:"] = new(@"PPU Decoder: (?.*?)\r?$", DefaultOptions), - ["PPU Threads:"] = new(@"PPU Threads: (?.*?)\r?$", DefaultOptions), - ["Use LLVM CPU:"] = new("Use LLVM CPU: \\\"?(?.*?)\\\"?\r?$", DefaultOptions), - ["thread scheduler"] = new(@"[Ss]cheduler( Mode)?: (?.*?)\r?$", DefaultOptions), - ["SPU Decoder:"] = new(@"SPU Decoder: (?.*?)\r?$", DefaultOptions), - ["secondary cores:"] = new(@"secondary cores: (?.*?)\r?$", DefaultOptions), - //["priority:"] = new(@"priority: (?.*?)\r?$", DefaultOptions), - ["SPU Threads:"] = new(@"SPU Threads: (?.*?)\r?$", DefaultOptions), - ["SPU delay penalty:"] = new(@"SPU delay penalty: (?.*?)\r?$", DefaultOptions), - ["SPU loop detection:"] = new(@"SPU loop detection: (?.*?)\r?$", DefaultOptions), - ["Max SPURS Threads:"] = new(@"Max SPURS Threads: (?\d*?)\r?$", DefaultOptions), - ["SPU Block Size:"] = new(@"SPU Block Size: (?.*?)\r?$", DefaultOptions), - ["Enable TSX:"] = new(@"Enable TSX: (?.*?)\r?$", DefaultOptions), - ["Accurate xfloat:"] = new(@"Accurate xfloat: (?.*?)\r?$", DefaultOptions), - ["Approximate xfloat:"] = new(@"Approximate xfloat: (?.*?)\r?$", DefaultOptions), - ["Relaxed xfloat:"] = new(@"Relaxed xfloat: (?.*?)\r?$", DefaultOptions), - ["XFloat Accuracy:"] = new(@"XFloat Accuracy: (?.*?)\r?$", DefaultOptions), - ["Accurate GETLLAR:"] = new(@"Accurate GETLLAR: (?.*?)\r?$", DefaultOptions), - ["Accurate PUTLLUC:"] = new(@"Accurate PUTLLUC: (?.*?)\r?$", DefaultOptions), - ["Accurate RSX reservation access:"] = new(@"Accurate RSX reservation access: (?.*?)\r?$", DefaultOptions), - ["RSX FIFO Accuracy:"] = new(@"RSX FIFO Accuracy: (?.*?)\r?$", DefaultOptions), - ["Debug Console Mode:"] = new(@"Debug Console Mode: (?.*?)\r?$", DefaultOptions), - ["Lib Loader:"] = new(@"[Ll]oader: (?.*?)\r?$", DefaultOptions), - ["Hook static functions:"] = new(@"Hook static functions: (?.*?)\r?$", DefaultOptions), - ["Load libraries:"] = new(@"libraries:\r?\n(?(.*?(- .*?|\[\])\r?\n)+)", DefaultOptions), - ["Libraries Control:"] = new(@"Libraries Control:\r?\n(?(.*?(- .*?|\[\])\r?\n)+)", DefaultOptions), - ["HLE lwmutex:"] = new(@"HLE lwmutex: (?.*?)\r?$", DefaultOptions), - ["Clocks scale:"] = new(@"Clocks scale: (?.*?)\r?$", DefaultOptions), - ["Max CPU Preempt Count:"] = new(@"Max CPU Preempt Count: (?.*?)\r?$", DefaultOptions), - ["Sleep Timers Accuracy:"] = new(@"Sleep Timers Accuracy: (?.*?)\r?$", DefaultOptions), + ["PPU Decoder:"] = PpuDecoderType(), + ["PPU Threads:"] = PpuThreadCount(), + ["Use LLVM CPU:"] = LlvmCpuArch(), + ["thread scheduler"] = ThreadSchedulerMode(), + ["SPU Decoder:"] = SpuDecoderType(), + ["secondary cores:"] = SecondaryCores(), + //["priority:"] = LowerThreadPriority(), + ["SPU Threads:"] = SpuThreadCount(), + ["SPU delay penalty:"] = SpuDelayPenalty(), + ["SPU loop detection:"] = SpuLoopDetection(), + ["Max SPURS Threads:"] = SpursThreadCount(), + ["SPU Block Size:"] = SpuBlockSize(), + ["Enable TSX:"] = TsxMode(), + ["Accurate xfloat:"] = AccurateXfloat(), + ["Approximate xfloat:"] = ApproximateXfloat(), + ["Relaxed xfloat:"] = RelaxedXfloat(), + ["XFloat Accuracy:"] = XfloatMode(), + ["Accurate GETLLAR:"] = GetLlarMode(), + ["Accurate PUTLLUC:"] = PutLlucMode(), + ["Accurate RSX reservation access:"] = RsxReservationAccessMode(), + ["RSX FIFO Accuracy:"] = RsxFifoMode(), + ["Debug Console Mode:"] = DebugConsoleMode(), + ["Lib Loader:"] = LibLoaderMode(), + ["Hook static functions:"] = HookStaticFunctions(), + ["Load libraries:"] = LoadLibrariesList(), + ["Libraries Control:"] = LibrariesControlList(), + ["HLE lwmutex:"] = HleLwmutex(), + ["Clocks scale:"] = ClockScale(), + ["Max CPU Preempt Count:"] = CpuPreemptCount(), + ["Sleep Timers Accuracy:"] = SleepTimersMode(), }, EndTrigger = new[] {"VFS:"}, }, @@ -97,7 +92,7 @@ internal partial class LogParser { Extractors = new() { - ["Enable /host_root/:"] = new(@"Enable /host_root/: (?.*?)\r?$", DefaultOptions), + ["Enable /host_root/:"] = EnableHostRoot(), }, EndTrigger = new[] {"Video:"}, }, @@ -105,39 +100,39 @@ internal partial class LogParser { Extractors = new() { - ["Renderer:"] = new("Renderer: (?.*?)\r?$", DefaultOptions), - ["Resolution:"] = new("Resolution: (?.*?)\r?$", DefaultOptions), - ["Aspect ratio:"] = new("Aspect ratio: (?.*?)\r?$", DefaultOptions), - ["Frame limit:"] = new("Frame limit: (?.*?)\r?$", DefaultOptions), - ["MSAA:"] = new("MSAA: (?.*?)\r?$", DefaultOptions), - ["Write Color Buffers:"] = new("Write Color Buffers: (?.*?)\r?$", DefaultOptions), - ["Write Depth Buffer:"] = new("Write Depth Buffer: (?.*?)\r?$", DefaultOptions), - ["Read Color Buffers:"] = new("Read Color Buffers: (?.*?)\r?$", DefaultOptions), - ["Read Depth Buffer:"] = new("Read Depth Buffer: (?.*?)\r?$", DefaultOptions), - ["VSync:"] = new("VSync: (?.*?)\r?$", DefaultOptions), - ["GPU texture scaling:"] = new("Use GPU texture scaling: (?.*?)\r?$", DefaultOptions), - ["Stretch To Display Area:"] = new("Stretch To Display Area: (?.*?)\r?$", DefaultOptions), - ["Strict Rendering Mode:"] = new("Strict Rendering Mode: (?.*?)\r?$", DefaultOptions), - ["Occlusion Queries:"] = new("Occlusion Queries: (?.*?)\r?$", DefaultOptions), - ["Vertex Cache:"] = new("Disable Vertex Cache: (?.*?)\r?$", DefaultOptions), - ["Frame Skip:"] = new("Enable Frame Skip: (?.*?)\r?$", DefaultOptions), - ["Blit:"] = new("Blit: (?.*?)\r?$", DefaultOptions), - ["Disable Asynchronous Shader Compiler:"] = new("Disable Asynchronous Shader Compiler: (?.*?)\r?$", DefaultOptions), - ["Shader Mode:"] = new("Shader Mode: (?.*?)\r?$", DefaultOptions), - ["Disable native float16 support:"] = new("Disable native float16 support: (?.*?)\r?$", DefaultOptions), - ["Multithreaded RSX:"] = new("Multithreaded RSX: (?.*?)\r?$", DefaultOptions), - ["Relaxed ZCULL Sync:"] = new("Relaxed ZCULL Sync: (?.*?)\r?$", DefaultOptions), - ["Resolution Scale:"] = new("Resolution Scale: (?.*?)\r?$", DefaultOptions), - ["Anisotropic Filter"] = new("Anisotropic Filter Override: (?.*?)\r?$", DefaultOptions), - ["Scalable Dimension:"] = new("Minimum Scalable Dimension: (?.*?)\r?$", DefaultOptions), - ["Driver Recovery Timeout:"] = new("Driver Recovery Timeout: (?.*?)\r?$", DefaultOptions), - ["Driver Wake-Up Delay:"] = new("Driver Wake-Up Delay: (?.*?)\r?$", DefaultOptions), - ["Vblank Rate:"] = new("Vblank Rate: (?.*?)\r?$", DefaultOptions), - ["12:"] = new(@"(D3D12|DirectX 12):\s*\r?\n\s*Adapter: (?.*?)\r?$", DefaultOptions), - ["Vulkan:"] = new(@"Vulkan:\s*\r?\n\s*Adapter: (?.*?)\r?$", DefaultOptions), - ["Force FIFO present mode:"] = new(@"Force FIFO present mode: (?.*?)\r?$", DefaultOptions), - ["Asynchronous Texture Streaming"] = new(@"Asynchronous Texture Streaming( 2)?: (?.*?)\r?$", DefaultOptions), - ["Asynchronous Queue Scheduler:"] = new(@"Asynchronous Queue Scheduler: (?.*?)\r?$", DefaultOptions), + ["Renderer:"] = RendererBackend(), + ["Resolution:"] = ResolutionMode(), + ["Aspect ratio:"] = AspectRatioMode(), + ["Frame limit:"] = FrameLimit(), + ["MSAA:"] = MsaaMode(), + ["Write Color Buffers:"] = Wcb(), + ["Write Depth Buffer:"] = Wdb(), + ["Read Color Buffers:"] = Rcb(), + ["Read Depth Buffer:"] = Rdb(), + ["VSync:"] = VsyncMode(), + ["GPU texture scaling:"] = GpuTextureScaling(), + ["Stretch To Display Area:"] = StretchToDisplay(), + ["Strict Rendering Mode:"] = StrictRendering(), + ["Occlusion Queries:"] = OcclusionQueriesMode(), + ["Vertex Cache:"] = VertexCache(), + ["Frame Skip:"] = FrameSkip(), + ["Blit:"] = BlitMode(), + ["Disable Asynchronous Shader Compiler:"] = DisableAsyncShaders(), + ["Shader Mode:"] = ShaderMode(), + ["Disable native float16 support:"] = DisableNativeF16(), + ["Multithreaded RSX:"] = RsxMultithreadMode(), + ["Relaxed ZCULL Sync:"] = RelaxedZcull(), + ["Resolution Scale:"] = ResolutionScaling(), + ["Anisotropic Filter"] = AnisoFilter(), + ["Scalable Dimension:"] = ScalableDimensions(), + ["Driver Recovery Timeout:"] = DriverRecoveryTimeout(), + ["Driver Wake-Up Delay:"] = DriverWakeupDelay(), + ["Vblank Rate:"] = VblankRate(), + ["12:"] = SelectedD3d12Device(), + ["Vulkan:"] = SelectedVulkanDevice(), + ["Force FIFO present mode:"] = FifoPresentMode(), + ["Asynchronous Texture Streaming"] = AsyncTextureStreaming(), + ["Asynchronous Queue Scheduler:"] = AsyncQueueScheduler(), }, EndTrigger = new[] {"Audio:"}, }, @@ -145,19 +140,19 @@ internal partial class LogParser { Extractors = new() { - ["Renderer:"] = new("Renderer: (?.*?)\r?$", DefaultOptions), - ["Downmix to Stereo:"] = new("Downmix to Stereo: (?.*?)\r?$", DefaultOptions), - ["Master Volume:"] = new("Master Volume: (?.*?)\r?$", DefaultOptions), - ["Enable Buffering:"] = new("Enable Buffering: (?.*?)\r?$", DefaultOptions), - ["Desired Audio Buffer Duration:"] = new("Desired Audio Buffer Duration: (?.*?)\r?$", DefaultOptions), - ["Enable Time Stretching:"] = new("Enable Time Stretching: (?.*?)\r?$", DefaultOptions), + ["Renderer:"] = AudioBackend(), + ["Downmix to Stereo:"] = DownmixToStereo(), + ["Master Volume:"] = MasterVolume(), + ["Enable Buffering:"] = AudioBuffering(), + ["Desired Audio Buffer Duration:"] = AudioBufferLength(), + ["Enable Time Stretching:"] = AudioTimeStretching(), - ["Pad:"] = new("Pad: (?.*?)\r?$", DefaultOptions), + ["Pad:"] = GamepadType(), - ["Automatically start games after boot:"] = new("Automatically start games after boot: (?.*?)\r?$", DefaultOptions), - ["Always start after boot:"] = new("Always start after boot: (?.*?)\r?$", DefaultOptions), - ["Use native user interface:"] = new("Use native user interface: (?.*?)\r?$", DefaultOptions), - ["Silence All Logs:"] = new("Silence All Logs: (?.*?)\r?$", DefaultOptions), + ["Automatically start games after boot:"] = AutoStartAfterBoot(), + ["Always start after boot:"] = AlwaysStartAfterBoot(), + ["Use native user interface:"] = NativeUIMode(), + ["Silence All Logs:"] = SilenceAllLogs(), }, EndTrigger = new[] {"Log:"}, }, @@ -165,7 +160,7 @@ internal partial class LogParser { Extractors = new() { - ["Log:"] = new(@"Log:\s*\r?\n?\s*(\{(?.*?)\}|(?(\s+\w+\:\s*\w+\r?\n)+))\r?$", DefaultOptions), + ["Log:"] = LogChannelList(), }, EndTrigger = new[] {"·"}, OnSectionEnd = MarkAsComplete, @@ -174,69 +169,67 @@ internal partial class LogParser { Extractors = new() { - ["LDR: Game:"] = new(@"Game: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions), - ["LDR: Disc"] = new(@"Disc( path)?: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions), - ["LDR: Path:"] = new(@"Path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions), - ["LDR: Boot path:"] = new(@"Boot path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions), - ["SYS: Game:"] = new(@"Game: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions), - ["SYS: Path:"] = new(@"Path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions), - ["SYS: Boot path:"] = new(@"Boot path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions), - ["Elf path:"] = new(@"Elf path: (?/host_root/)?(?(?/dev_hdd0/game/(?[^/\r\n]+)/USRDIR/EBOOT\.BIN|.*?))\r?$", DefaultOptions), - ["VFS: Mounted path \"/dev_bdvd\""] = new(@"Mounted path ""/dev_bdvd"" to ""(?[^""]+)""", DefaultOptions), - ["Invalid or unsupported file format:"] = new(@"Invalid or unsupported file format: (?.*?)\r?$", DefaultOptions), - ["SELF:"] = new(@"(?Failed to decrypt)? SELF: (?Failed to (decrypt|load SELF))?.*\r?$", DefaultOptions), - ["SYS: Version:"] = new(@"Version: (APP_VER=)?(?\S+) (/ |VERSION=)(?\S+).*?\r?$", DefaultOptions), - ["sceNp: npDrmIsAvailable(): Failed to verify"] = new(@"Failed to verify (?(sce|npd)) file.*\r?$", DefaultOptions), - ["{rsx::thread} RSX: 4"] = new(@"RSX:(\d|\.|\s|\w|-)* (?(\d+\.)*\d+)\r?\n[^\n]*?" + - @"RSX: [^\n]+\r?\n[^\n]*?" + - @"RSX: (?.*?)\r?\n[^\n]*?" + - @"RSX: Supported texel buffer size", DefaultOptions), - ["GL RENDERER:"] = new(@"GL RENDERER: (?.*?)\r?$", DefaultOptions), - ["GL VERSION:"] = new(@"GL VERSION: (?(\d|\.)+)(\d|\.|\s|\w|-)*?( (?(\d+\.)*\d+))?\r?$", DefaultOptions), - ["GLSL VERSION:"] = new(@"GLSL VERSION: (?(\d|\.)+).*?\r?$", DefaultOptions), - ["texel buffer size reported:"] = new(@"RSX: Supported texel buffer size reported: (?\d*?) bytes", DefaultOptions), - ["Physical device in"] = new(@"Physical device ini?tialized\. GPU=(?.+), driver=(?-?\d+)\r?$", DefaultOptions), - ["Found vulkan-compatible GPU:"] = new(@"Found [Vv]ulkan-compatible GPU: (?.+)\r?$", DefaultOptions), - ["Renderer initialized on device"] = new(@"Renderer initialized on device '(?.+)'\r?$", DefaultOptions), - ["RSX: Failed to compile shader"] = new(@"RSX: Failed to compile shader: ERROR: (?.+?)\r?$", DefaultOptions), - ["RSX: Compilation failed"] = new(@"RSX: Compilation failed: ERROR: (?.+?)\r?$", DefaultOptions), - ["RSX: Linkage failed"] = new(@"RSX: Linkage failed: (?.+?)\r?$", DefaultOptions), - ["RSX: Unsupported device"] = new(@"RSX: Unsupported device: (?.+)\..+?\r?$", DefaultOptions), - ["RSX: Your GPU does not support"] = new(@"RSX: Your GPU does not support (?.+)\..+?\r?$", DefaultOptions), - ["RSX: GPU/driver lacks support"] = new(@"RSX: GPU/driver lacks support for (?.+)\..+?\r?$", DefaultOptions), - ["RSX: Swapchain:"] = new(@"RSX: Swapchain: present mode (?\d+?) in use.+?\r?$", DefaultOptions), - ["F "] = new(@"F \d+:\d+:\d+\.\d+ (({(?[^}]+)} )?(\w+:\s*(Thread terminated due to fatal error: )?|(\w+:\s*)?(class [^\r\n]+ thrown: ))\r?\n?)(?.*?)(\r?\n)(\r?\n|·|$)", DefaultSingleLineOptions), - ["Failed to load RAP file:"] = new(@"Failed to load RAP file: (?.*?\.rap).*\r?$", DefaultOptions), - ["Rap file not found:"] = new(@"Rap file not found: “?(?.*?\.rap)”?\r?$", DefaultOptions), - ["Pad handler expected but none initialized"] = new(@"(?Pad handler expected but none initialized).*?\r?$", DefaultOptions), - ["Failed to bind device"] = new(@"Failed to bind device (?.+) to handler (?.+).*\r?$", DefaultOptions), - ["Input:"] = new(@"Input: (?.*?) device .+ connected\r?$", DefaultOptions), - ["XAudio2Thread"] = new(@"XAudio2Thread\s*: (?.+failed\s*\((?0x.+)\).*)\r?$", DefaultOptions), - ["cellAudio Thread"] = new(@"XAudio2Backend\s*: (?.+failed\s*\((?0x.+)\).*)\r?$", DefaultOptions), - ["using a Null renderer instead"] = new(@"Audio renderer (?.+) could not be initialized\r?$", DefaultOptions), - ["PPU executable hash:"] = new(@"PPU executable hash: PPU-(?\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions), - ["OVL executable hash:"] = new(@"OVL executable hash: OVL-(?\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions), - ["SPU executable hash:"] = new(@"SPU executable hash: SPU-(?\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions), - ["PRX library hash:"] = new(@"PRX library hash: PRX-(?\w+-\d+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions), - ["OVL hash of"] = new(@"OVL hash of (\w|[\.\[\]])+: OVL-(?\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions), - ["PRX hash of"] = new(@"PRX hash of (\w|[\.\[\]])+: PRX-(?\w+-\d+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions), - [": Applied patch"] = new(@"Applied patch \(hash='(?:\w{3}-\w+(-\d+)?)', description='(?.+?)', author='(?:.+?)', patch_version='(?:.+?)', file_version='(?:.+?)'\) \(<- (?:[1-9]\d*)\).*\r?$", DefaultOptions), - ["Loaded SPU image:"] = new(@"Loaded SPU image: SPU-(?\w+ \(<-\s*\d+\)).*?\r?$", DefaultOptions), - ["'sys_fs_stat' failed"] = new(@"'sys_fs_stat' failed (?!with 0x8001002c).+“(/dev_bdvd/(?.+)|/dev_hdd0/game/NP\w+/(?.+))”.*?\r?$", DefaultOptions), - ["'sys_fs_open' failed"] = new(@"'sys_fs_open' failed (?!with 0x8001002c).+“(/dev_bdvd/(?.+)|/dev_hdd0/game/NP\w+/(?.+))”.*?\r?$", DefaultOptions), - ["'sys_fs_opendir' failed"] = new(@"'sys_fs_opendir' failed .+“/dev_bdvd/(?.+)”.*?\r?$", DefaultOptions), - ["EDAT: "] = new(@"EDAT: Block at offset (?0x[0-9a-f]+) has invalid hash!.*?\r?$", DefaultOptions), - ["PS3 firmware is not installed"] = new(@"(?PS3 firmware is not installed.+)\r?$", DefaultOptions), - ["do you have the PS3 firmware installed"] = new(@"(?do you have the PS3 firmware installed.*)\r?$", DefaultOptions), - ["Unimplemented syscall"] = new(@"U \d+:\d+:\d+\.\d+ ({(?.+?)} )?.*Unimplemented syscall (?.*)\r?$", DefaultOptions), - ["Could not enqueue"] = new(@"cellAudio: Could not enqueue buffer onto audio backend(?.).*\r?$", DefaultOptions), - ["{PPU["] = new(@"{PPU\[.+\]} (?[^ :]+)( TODO)?: (?!“)(?[^ :]+?)\(.*\r?$", DefaultOptions), - ["Verification failed"] = new(@"Verification failed.+\(e=0x(?[0-9a-f]+)\[(?\d+)\]\)", DefaultOptions), - ["sys_tty_write():"] = new(@"sys_tty_write\(\)\: “(?.*?)”\r?(\n|$)", DefaultSingleLineOptions), - ["⁂"] = new(@"⁂ (?[^ :\[]+?) .*\r?$", DefaultOptions), - ["undub"] = new(@"(\b|_)(?(undub|translation patch))(\b|_)", DefaultOptions | RegexOptions.IgnoreCase), - ["Input: Pad"] = new(@"Input: Pad (?\d): device='(?(?!Null).+?)', handler=(?.+?), VID=.+?\r?$", DefaultOptions), - ["SDL: Found game controller"] = new(@"Found game controller \d: .+ has_accel=(?.+?), has_gyro=(?.+?)\r?$", DefaultOptions), + ["LDR: Game:"] = GamePathLdr(), + ["LDR: Disc"] = DiscPathLdr(), + ["LDR: Path:"] = DigitalPathLdr(), + ["LDR: Boot path:"] = BootPathInBodyLdr(), + ["SYS: Game:"] = GamePathSys(), + ["SYS: Path:"] = DigitalPathSys(), + ["SYS: Boot path:"] = BootPathInBodySys(), + ["Elf path:"] = ElfPath(), + ["VFS: Mounted path \"/dev_bdvd\""] = VfsMountPath(), + ["Invalid or unsupported file format:"] = InvalidFileFormat(), + ["SELF:"] = DecryptFailedSelfPath(), + ["SYS: Version:"] = GameVersion(), + ["sceNp: npDrmIsAvailable(): Failed to verify"] = FailedToVerifyNpDrm(), + ["{rsx::thread} RSX: 4"] = RsxDriverInfoLegacy(), + ["{rsx::thread} RSX: 3"] = RsxDriverInfoLegacy(), + ["GL RENDERER:"] = GlRenderer(), + ["GL VERSION:"] = GlVersion(), + ["GLSL VERSION:"] = GlslVersion(), + ["texel buffer size reported:"] = GlTexelBufferSize(), + ["Physical device in"] = PhysicalDeviceFound(), + ["Found vulkan-compatible GPU:"] = VulkanDeviceFound(), + ["Renderer initialized on device"] = RenderDeviceInitialized(), + ["RSX: Failed to compile shader"] = FailedToCompileShader(), + ["RSX: Compilation failed"] = ShaderCompilationFailed(), + ["RSX: Linkage failed"] = ShaderLinkageFailed(), + ["RSX: Unsupported device"] = UnsupportedDevice(), + ["RSX: Your GPU does not support"] = UnsupportedDeviceFeatures(), + ["RSX: GPU/driver lacks support"] = UnsupportedDriverFeatures(), + ["RSX: Swapchain:"] = SwapchainMode(), + ["F "] = FatalError(), + ["Failed to load RAP file:"] = FailedToLoadRap(), + ["Rap file not found:"] = RapNotFound(), + ["Pad handler expected but none initialized"] = MissingGamepad(), + ["Failed to bind device"] = FailedToBindGamepad(), + ["Input:"] = InputDeviceConnected(), + ["XAudio2Thread"] = XAudio2Thread(), + ["cellAudio Thread"] = CellAudioThread(), + ["using a Null renderer instead"] = AudioBackendFailed(), + ["PPU executable hash:"] = PpuHash(), + ["OVL executable hash:"] = OvlHash(), + ["SPU executable hash:"] = SpuHash(), + ["PRX library hash:"] = PrxHash(), + ["OVL hash of"] = OvlHash2(), + ["PRX hash of"] = PrxHash2(), + [": Applied patch"] = AppliedPatch(), + ["Loaded SPU image:"] = SpuImageLoad(), + ["'sys_fs_stat' failed"] = SysFsStatFailed(), + ["'sys_fs_open' failed"] = SysFsOpenFailed(), + ["'sys_fs_opendir' failed"] = SysFsOpenDirFailed(), + ["EDAT: "] = InvalidEdat(), + ["PS3 firmware is not installed"] = FwNotInstalled(), + ["do you have the PS3 firmware installed"] = FwNotInstalled2(), + ["Unimplemented syscall"] = UnimplementedSyscall(), + ["Could not enqueue"] = CellAudioEnqueueFailed(), + ["{PPU["] = PpuSyscallTodo(), + ["Verification failed"] = VerificationFailed(), + ["sys_tty_write():"] = SysTtyWrite(), + ["⁂"] = SyscallDump(), + ["undub"] = UndubFlag(), + ["Input: Pad"] = InputDeviceGamepad(), + ["SDL: Found game controller"] = SdlControllerName(), }, OnSectionEnd = MarkAsCompleteAndReset, EndTrigger = new[] { "Stopping emulator...", "All threads stopped...", "LDR: Booting from"}, diff --git a/CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs b/CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs new file mode 100644 index 00000000..f20fa111 --- /dev/null +++ b/CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs @@ -0,0 +1,344 @@ +using System.Text.RegularExpressions; + +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; + + [GeneratedRegex(@"(^|.+\d:\d\d:\d\d\.\d{6})\s*(?RPCS3 [^\xC2\xB7]+?)\r?(\n·|$)", DefaultSingleLine)] + private static partial Regex Rpcs3LogHeader(); + [GeneratedRegex(@"(?·).+\r?$", DefaultOptions)] + private static partial Regex FirstLineWithDot(); + [GeneratedRegex(@"Operating system: (?[^,]+), (Name: (?[^,]+), Release: (?[^,]+), Version: (?[^\r\n]+)|Major: (?\d+), Minor: (?\d+), Build: (?\d+), Service Pack: (?[^,]+), Compatibility mode: (?[^,\r\n]+)|Version: (?[^\r\n]+))\r?$", DefaultSingleLine)] + // Operating system: Windows, Major: 10, Minor: 0, Build: 22000, Service Pack: none, Compatibility mode: 0 + // Operating system: POSIX, Name: Linux, Release: 5.15.11-zen1-1-zen, Version: #1 ZEN SMP PREEMPT Wed, 22 Dec 2021 09:23:53 +0000 + // Operating system: macOS, Version 12.1.0 + internal static partial Regex OsInfo(); + [GeneratedRegex(@"Current Time: (?.+)\r?$", DefaultOptions)] + private static partial Regex CurrentTime(); + [GeneratedRegex(@"Installation ID: (?.+)\r?$", DefaultOptions)] + private static partial Regex InstallationId(); + [GeneratedRegex(@"Physical device ini?tialized\. GPU=(?.+), driver=(?-?\d+)\r?$", DefaultOptions)] + private static partial Regex PhysicalDeviceName(); + [GeneratedRegex(@"Found [Vv]ulkan-compatible GPU: (?'(?.+)' running.+)\r?$", DefaultOptions)] + private static partial Regex VulkanDeviceName(); + [GeneratedRegex(@"Finished reading database from file: (?.*compat_database.dat).*\r?$", DefaultOptions)] + private static partial Regex CompatDbFoundPath(); + [GeneratedRegex(@"Database file not found: (?.*compat_database.dat).*\r?$", DefaultOptions)] + private static partial Regex CompatDbNotFoundPath(); + [GeneratedRegex(@"(?Successfully installed PS3 firmware) version (?\d+\.\d+).*\r?$", DefaultOptions)] + private static partial Regex FwInstallMessage(); + [GeneratedRegex(@"Firmware version: (?\d+\.\d+).*\r?$", DefaultOptions)] + private static partial Regex FwVersion(); + [GeneratedRegex(@"(?:LDR|SYS): Title: (?.*)?\r?$", DefaultOptions)] + private static partial Regex GameTitle(); + [GeneratedRegex(@"Serial: (?[A-z]{4}\d{5})\r?$", DefaultOptions)] + private static partial Regex GameSerial(); + [GeneratedRegex(@"Category: (?.*)?\r?$", DefaultOptions)] + private static partial Regex GameCategory(); + [GeneratedRegex(@"Version: (?\S+) / (?\S+).*?\r?$", DefaultOptions)] + private static partial Regex DiscVersionLdr(); + [GeneratedRegex(@"Version: (APP_VER=)?(?\S+) (/ |VERSION=)(?\S+).*?\r?$", DefaultOptions)] + private static partial Regex DiscVersionSys(); + [GeneratedRegex(@"Cache: ((?\w:/)|(?/[^/])).*?\r?$", DefaultOptions)] + private static partial Regex CachePathLdr(); + [GeneratedRegex(@"Cache: ((?\w:/)|(?/[^/])).*?\r?$", DefaultOptions)] + private static partial Regex CachePathSys(); + [GeneratedRegex(@"Path: ((?\w:/)|(?/[^/])).*?\r?$", DefaultOptions)] + private static partial Regex BootPathLdr(); + [GeneratedRegex(@"Path: ((?\w:/)|(?/[^/])).*?\r?$", DefaultOptions)] + private static partial Regex BootPathSys(); + [GeneratedRegex(@"Path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions)] + private static partial Regex BootPathDigitalLdr(); + [GeneratedRegex(@"Path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions)] + private static partial Regex BootPathDigitalSys(); + [GeneratedRegex(@"custom config: (?.*?)\r?$", DefaultOptions)] + private static partial Regex CustomConfigPath(); + [GeneratedRegex(@"patch_log: Failed to load patch file (?\S*)\r?\n.* line (?\d+), column (?\d+): (?.*?)$", DefaultOptions)] + private static partial Regex FailedPatchPath(); + + [GeneratedRegex(@"PPU Decoder: (?.*?)\r?$", DefaultOptions)] + private static partial Regex PpuDecoderType(); + [GeneratedRegex(@"PPU Threads: (?.*?)\r?$", DefaultOptions)] + private static partial Regex PpuThreadCount(); + [GeneratedRegex("Use LLVM CPU: \\\"?(?.*?)\\\"?\r?$", DefaultOptions)] + private static partial Regex LlvmCpuArch(); + [GeneratedRegex(@"[Ss]cheduler( Mode)?: (?.*?)\r?$", DefaultOptions)] + private static partial Regex ThreadSchedulerMode(); + [GeneratedRegex(@"SPU Decoder: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SpuDecoderType(); + [GeneratedRegex(@"secondary cores: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SecondaryCores(); + [GeneratedRegex(@"priority: (?.*?)\r?$", DefaultOptions)] + private static partial Regex LowerThreadPriority(); + [GeneratedRegex(@"SPU Threads: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SpuThreadCount(); + [GeneratedRegex(@"SPU delay penalty: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SpuDelayPenalty(); + [GeneratedRegex(@"SPU loop detection: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SpuLoopDetection(); + [GeneratedRegex(@"Max SPURS Threads: (?\d*?)\r?$", DefaultOptions)] + private static partial Regex SpursThreadCount(); + [GeneratedRegex(@"SPU Block Size: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SpuBlockSize(); + [GeneratedRegex(@"Enable TSX: (?.*?)\r?$", DefaultOptions)] + private static partial Regex TsxMode(); + [GeneratedRegex(@"Accurate xfloat: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AccurateXfloat(); + [GeneratedRegex(@"Approximate xfloat: (?.*?)\r?$", DefaultOptions)] + private static partial Regex ApproximateXfloat(); + [GeneratedRegex(@"Relaxed xfloat: (?.*?)\r?$", DefaultOptions)] + private static partial Regex RelaxedXfloat(); + [GeneratedRegex(@"XFloat Accuracy: (?.*?)\r?$", DefaultOptions)] + private static partial Regex XfloatMode(); + [GeneratedRegex(@"Accurate GETLLAR: (?.*?)\r?$", DefaultOptions)] + private static partial Regex GetLlarMode(); + [GeneratedRegex(@"Accurate PUTLLUC: (?.*?)\r?$", DefaultOptions)] + private static partial Regex PutLlucMode(); + [GeneratedRegex(@"Accurate RSX reservation access: (?.*?)\r?$", DefaultOptions)] + private static partial Regex RsxReservationAccessMode(); + [GeneratedRegex(@"RSX FIFO Accuracy: (?.*?)\r?$", DefaultOptions)] + private static partial Regex RsxFifoMode(); + [GeneratedRegex(@"Debug Console Mode: (?.*?)\r?$", DefaultOptions)] + private static partial Regex DebugConsoleMode(); + [GeneratedRegex(@"[Ll]oader: (?.*?)\r?$", DefaultOptions)] + private static partial Regex LibLoaderMode(); + [GeneratedRegex(@"Hook static functions: (?.*?)\r?$", DefaultOptions)] + private static partial Regex HookStaticFunctions(); + [GeneratedRegex(@"libraries:\r?\n(?(.*?(- .*?|\[\])\r?\n)+)", DefaultOptions)] + private static partial Regex LoadLibrariesList(); + [GeneratedRegex(@"Libraries Control:\r?\n(?(.*?(- .*?|\[\])\r?\n)+)", DefaultOptions)] + private static partial Regex LibrariesControlList(); + [GeneratedRegex(@"HLE lwmutex: (?.*?)\r?$", DefaultOptions)] + private static partial Regex HleLwmutex(); + [GeneratedRegex(@"Clocks scale: (?.*?)\r?$", DefaultOptions)] + private static partial Regex ClockScale(); + [GeneratedRegex(@"Max CPU Preempt Count: (?.*?)\r?$", DefaultOptions)] + private static partial Regex CpuPreemptCount(); + [GeneratedRegex(@"Sleep Timers Accuracy: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SleepTimersMode(); + + [GeneratedRegex(@"Enable /host_root/: (?.*?)\r?$", DefaultOptions)] + private static partial Regex EnableHostRoot(); + + [GeneratedRegex("Renderer: (?.*?)\r?$", DefaultOptions)] + private static partial Regex RendererBackend(); + [GeneratedRegex("Resolution: (?.*?)\r?$", DefaultOptions)] + private static partial Regex ResolutionMode(); + [GeneratedRegex("Aspect ratio: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AspectRatioMode(); + [GeneratedRegex("Frame limit: (?.*?)\r?$", DefaultOptions)] + private static partial Regex FrameLimit(); + [GeneratedRegex("MSAA: (?.*?)\r?$", DefaultOptions)] + private static partial Regex MsaaMode(); + [GeneratedRegex("Write Color Buffers: (?.*?)\r?$", DefaultOptions)] + private static partial Regex Wcb(); + [GeneratedRegex("Write Depth Buffer: (?.*?)\r?$", DefaultOptions)] + private static partial Regex Wdb(); + [GeneratedRegex("Read Color Buffers: (?.*?)\r?$", DefaultOptions)] + private static partial Regex Rcb(); + [GeneratedRegex("Read Depth Buffer: (?.*?)\r?$", DefaultOptions)] + private static partial Regex Rdb(); + [GeneratedRegex("VSync: (?.*?)\r?$", DefaultOptions)] + private static partial Regex VsyncMode(); + [GeneratedRegex("Use GPU texture scaling: (?.*?)\r?$", DefaultOptions)] + private static partial Regex GpuTextureScaling(); + [GeneratedRegex("Stretch To Display Area: (?.*?)\r?$", DefaultOptions)] + private static partial Regex StretchToDisplay(); + [GeneratedRegex("Strict Rendering Mode: (?.*?)\r?$", DefaultOptions)] + private static partial Regex StrictRendering(); + [GeneratedRegex("Occlusion Queries: (?.*?)\r?$", DefaultOptions)] + private static partial Regex OcclusionQueriesMode(); + [GeneratedRegex("Disable Vertex Cache: (?.*?)\r?$", DefaultOptions)] + private static partial Regex VertexCache(); + [GeneratedRegex("Enable Frame Skip: (?.*?)\r?$", DefaultOptions)] + private static partial Regex FrameSkip(); + [GeneratedRegex("Blit: (?.*?)\r?$", DefaultOptions)] + private static partial Regex BlitMode(); + [GeneratedRegex("Disable Asynchronous Shader Compiler: (?.*?)\r?$", DefaultOptions)] + private static partial Regex DisableAsyncShaders(); + [GeneratedRegex("Shader Mode: (?.*?)\r?$", DefaultOptions)] + private static partial Regex ShaderMode(); + [GeneratedRegex("Disable native float16 support: (?.*?)\r?$", DefaultOptions)] + private static partial Regex DisableNativeF16(); + [GeneratedRegex("Multithreaded RSX: (?.*?)\r?$", DefaultOptions)] + private static partial Regex RsxMultithreadMode(); + [GeneratedRegex("Relaxed ZCULL Sync: (?.*?)\r?$", DefaultOptions)] + private static partial Regex RelaxedZcull(); + [GeneratedRegex("Resolution Scale: (?.*?)\r?$", DefaultOptions)] + private static partial Regex ResolutionScaling(); + [GeneratedRegex("Anisotropic Filter Override: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AnisoFilter(); + [GeneratedRegex("Minimum Scalable Dimension: (?.*?)\r?$", DefaultOptions)] + private static partial Regex ScalableDimensions(); + [GeneratedRegex("Driver Recovery Timeout: (?.*?)\r?$", DefaultOptions)] + private static partial Regex DriverRecoveryTimeout(); + [GeneratedRegex("Driver Wake-Up Delay: (?.*?)\r?$", DefaultOptions)] + private static partial Regex DriverWakeupDelay(); + [GeneratedRegex("Vblank Rate: (?.*?)\r?$", DefaultOptions)] + private static partial Regex VblankRate(); + [GeneratedRegex(@"(D3D12|DirectX 12):\s*\r?\n\s*Adapter: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SelectedD3d12Device(); + [GeneratedRegex(@"Vulkan:\s*\r?\n\s*Adapter: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SelectedVulkanDevice(); + [GeneratedRegex(@"Force FIFO present mode: (?.*?)\r?$", DefaultOptions)] + private static partial Regex FifoPresentMode(); + [GeneratedRegex(@"Asynchronous Texture Streaming( 2)?: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AsyncTextureStreaming(); + [GeneratedRegex(@"Asynchronous Queue Scheduler: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AsyncQueueScheduler(); + + [GeneratedRegex("Renderer: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AudioBackend(); + [GeneratedRegex("Downmix to Stereo: (?.*?)\r?$", DefaultOptions)] + private static partial Regex DownmixToStereo(); + [GeneratedRegex("Master Volume: (?.*?)\r?$", DefaultOptions)] + private static partial Regex MasterVolume(); + [GeneratedRegex("Enable Buffering: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AudioBuffering(); + [GeneratedRegex("Desired Audio Buffer Duration: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AudioBufferLength(); + [GeneratedRegex("Enable Time Stretching: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AudioTimeStretching(); + [GeneratedRegex("Pad: (?.*?)\r?$", DefaultOptions)] + private static partial Regex GamepadType(); + [GeneratedRegex("Automatically start games after boot: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AutoStartAfterBoot(); + [GeneratedRegex("Always start after boot: (?.*?)\r?$", DefaultOptions)] + private static partial Regex AlwaysStartAfterBoot(); + [GeneratedRegex("Use native user interface: (?.*?)\r?$", DefaultOptions)] + private static partial Regex NativeUIMode(); + [GeneratedRegex("Silence All Logs: (?.*?)\r?$", DefaultOptions)] + private static partial Regex SilenceAllLogs(); + + [GeneratedRegex(@"Log:\s*\r?\n?\s*(\{(?.*?)\}|(?(\s+\w+\:\s*\w+\r?\n)+))\r?$", DefaultOptions)] + private static partial Regex LogChannelList(); + + [GeneratedRegex(@"Game: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions)] + private static partial Regex GamePathLdr(); + [GeneratedRegex(@"Disc( path)?: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions)] + private static partial Regex DiscPathLdr(); + [GeneratedRegex(@"Path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions)] + private static partial Regex DigitalPathLdr(); + [GeneratedRegex(@"Boot path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions)] + private static partial Regex BootPathInBodyLdr(); + [GeneratedRegex(@"Game: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions)] + private static partial Regex GamePathSys(); + [GeneratedRegex(@"Path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions)] + private static partial Regex DigitalPathSys(); + [GeneratedRegex(@"Boot path: (?.*(?/dev_hdd0/game/(?[^/\r\n]+)).*|.*)\r?$", DefaultOptions)] + private static partial Regex BootPathInBodySys(); + [GeneratedRegex(@"Elf path: (?/host_root/)?(?(?/dev_hdd0/game/(?[^/\r\n]+)/USRDIR/EBOOT\.BIN|.*?))\r?$", DefaultOptions)] + private static partial Regex ElfPath(); + [GeneratedRegex(@"Mounted path ""/dev_bdvd"" to ""(?[^""]+)""", DefaultOptions)] + private static partial Regex VfsMountPath(); + [GeneratedRegex(@"Invalid or unsupported file format: (?.*?)\r?$", DefaultOptions)] + private static partial Regex InvalidFileFormat(); + [GeneratedRegex(@"(?Failed to decrypt)? SELF: (?Failed to (decrypt|load SELF))?.*\r?$", DefaultOptions)] + private static partial Regex DecryptFailedSelfPath(); + [GeneratedRegex(@"Version: (APP_VER=)?(?\S+) (/ |VERSION=)(?\S+).*?\r?$", DefaultOptions)] + private static partial Regex GameVersion(); + [GeneratedRegex(@"Failed to verify (?(sce|npd)) file.*\r?$", DefaultOptions)] + private static partial Regex FailedToVerifyNpDrm(); + [GeneratedRegex( + @"RSX:(\d|\.|\s|\w|-)* (?(\d+\.)*\d+)\r?\n[^\n]*?"+ + @"RSX: [^\n]+\r?\n[^\n]*?RSX: (?.*?)\r?\n[^\n]*?"+ + @"RSX: Supported texel buffer size", + DefaultOptions + )] + private static partial Regex RsxDriverInfoLegacy(); + [GeneratedRegex(@"GL RENDERER: (?.*?)\r?$", DefaultOptions)] + private static partial Regex GlRenderer(); + [GeneratedRegex(@"GL VERSION: (?(\d|\.)+)(\d|\.|\s|\w|-)*?( (?(\d+\.)*\d+))?\r?$", DefaultOptions)] + private static partial Regex GlVersion(); + [GeneratedRegex(@"GLSL VERSION: (?(\d|\.)+).*?\r?$", DefaultOptions)] + private static partial Regex GlslVersion(); + [GeneratedRegex(@"RSX: Supported texel buffer size reported: (?\d*?) bytes", DefaultOptions)] + private static partial Regex GlTexelBufferSize(); + [GeneratedRegex(@"Physical device ini?tialized\. GPU=(?.+), driver=(?-?\d+)\r?$", DefaultOptions)] + private static partial Regex PhysicalDeviceFound(); + [GeneratedRegex(@"Found [Vv]ulkan-compatible GPU: (?.+)\r?$", DefaultOptions)] + private static partial Regex VulkanDeviceFound(); + [GeneratedRegex(@"Renderer initialized on device '(?.+)'\r?$", DefaultOptions)] + private static partial Regex RenderDeviceInitialized(); + [GeneratedRegex(@"RSX: Failed to compile shader: ERROR: (?.+?)\r?$", DefaultOptions)] + private static partial Regex FailedToCompileShader(); + [GeneratedRegex(@"RSX: Compilation failed: ERROR: (?.+?)\r?$", DefaultOptions)] + private static partial Regex ShaderCompilationFailed(); + [GeneratedRegex(@"RSX: Linkage failed: (?.+?)\r?$", DefaultOptions)] + private static partial Regex ShaderLinkageFailed(); + [GeneratedRegex(@"RSX: Unsupported device: (?.+)\..+?\r?$", DefaultOptions)] + private static partial Regex UnsupportedDevice(); + [GeneratedRegex(@"RSX: Your GPU does not support (?.+)\..+?\r?$", DefaultOptions)] + private static partial Regex UnsupportedDeviceFeatures(); + [GeneratedRegex(@"RSX: GPU/driver lacks support for (?.+)\..+?\r?$", DefaultOptions)] + private static partial Regex UnsupportedDriverFeatures(); + [GeneratedRegex(@"RSX: Swapchain: present mode (?\d+?) in use.+?\r?$", DefaultOptions)] + private static partial Regex SwapchainMode(); + [GeneratedRegex(@"F \d+:\d+:\d+\.\d+ (({(?[^}]+)} )?(\w+:\s*(Thread terminated due to fatal error: )?|(\w+:\s*)?(class [^\r\n]+ thrown: ))\r?\n?)(?.*?)(\r?\n)(\r?\n|·|$)", DefaultSingleLine)] + private static partial Regex FatalError(); + [GeneratedRegex(@"Failed to load RAP file: (?.*?\.rap).*\r?$", DefaultOptions)] + private static partial Regex FailedToLoadRap(); + [GeneratedRegex(@"Rap file not found: “?(?.*?\.rap)”?\r?$", DefaultOptions)] + private static partial Regex RapNotFound(); + [GeneratedRegex(@"(?Pad handler expected but none initialized).*?\r?$", DefaultOptions)] + private static partial Regex MissingGamepad(); + [GeneratedRegex(@"Failed to bind device (?.+) to handler (?.+).*\r?$", DefaultOptions)] + private static partial Regex FailedToBindGamepad(); + [GeneratedRegex(@"Input: (?.*?) device .+ connected\r?$", DefaultOptions)] + private static partial Regex InputDeviceConnected(); + [GeneratedRegex(@"XAudio2Thread\s*: (?.+failed\s*\((?0x.+)\).*)\r?$", DefaultOptions)] + private static partial Regex XAudio2Thread(); + [GeneratedRegex(@"XAudio2Backend\s*: (?.+failed\s*\((?0x.+)\).*)\r?$", DefaultOptions)] + private static partial Regex CellAudioThread(); + [GeneratedRegex(@"Audio renderer (?.+) could not be initialized\r?$", DefaultOptions)] + private static partial Regex AudioBackendFailed(); + [GeneratedRegex(@"PPU executable hash: PPU-(?\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)] + private static partial Regex PpuHash(); + [GeneratedRegex(@"OVL executable hash: OVL-(?\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)] + private static partial Regex OvlHash(); + [GeneratedRegex(@"SPU executable hash: SPU-(?\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)] + private static partial Regex SpuHash(); + [GeneratedRegex(@"PRX library hash: PRX-(?\w+-\d+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)] + private static partial Regex PrxHash(); + [GeneratedRegex(@"OVL hash of (\w|[\.\[\]])+: OVL-(?\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)] + private static partial Regex OvlHash2(); + [GeneratedRegex(@"PRX hash of (\w|[\.\[\]])+: PRX-(?\w+-\d+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)] + private static partial Regex PrxHash2(); + [GeneratedRegex(@"Applied patch \(hash='(?:\w{3}-\w+(-\d+)?)', description='(?.+?)', author='(?:.+?)', patch_version='(?:.+?)', file_version='(?:.+?)'\) \(<- (?:[1-9]\d*)\).*\r?$", DefaultOptions)] + private static partial Regex AppliedPatch(); + [GeneratedRegex(@"Loaded SPU image: SPU-(?\w+ \(<-\s*\d+\)).*?\r?$", DefaultOptions)] + private static partial Regex SpuImageLoad(); + [GeneratedRegex(@"'sys_fs_stat' failed (?!with 0x8001002c).+“(/dev_bdvd/(?.+)|/dev_hdd0/game/NP\w+/(?.+))”.*?\r?$", DefaultOptions)] + private static partial Regex SysFsStatFailed(); + [GeneratedRegex(@"'sys_fs_open' failed (?!with 0x8001002c).+“(/dev_bdvd/(?.+)|/dev_hdd0/game/NP\w+/(?.+))”.*?\r?$", DefaultOptions)] + private static partial Regex SysFsOpenFailed(); + [GeneratedRegex(@"'sys_fs_opendir' failed .+“/dev_bdvd/(?.+)”.*?\r?$", DefaultOptions)] + private static partial Regex SysFsOpenDirFailed(); + [GeneratedRegex(@"EDAT: Block at offset (?0x[0-9a-f]+) has invalid hash!.*?\r?$", DefaultOptions)] + private static partial Regex InvalidEdat(); + [GeneratedRegex(@"(?PS3 firmware is not installed.+)\r?$", DefaultOptions)] + private static partial Regex FwNotInstalled(); + [GeneratedRegex(@"(?do you have the PS3 firmware installed.*)\r?$", DefaultOptions)] + private static partial Regex FwNotInstalled2(); + [GeneratedRegex(@"U \d+:\d+:\d+\.\d+ ({(?.+?)} )?.*Unimplemented syscall (?.*)\r?$", DefaultOptions)] + private static partial Regex UnimplementedSyscall(); + [GeneratedRegex(@"cellAudio: Could not enqueue buffer onto audio backend(?.).*\r?$", DefaultOptions)] + private static partial Regex CellAudioEnqueueFailed(); + [GeneratedRegex(@"{PPU\[.+\]} (?[^ :]+)( TODO)?: (?!“)(?[^ :]+?)\(.*\r?$", DefaultOptions)] + private static partial Regex PpuSyscallTodo(); + [GeneratedRegex(@"Verification failed.+\(e=0x(?[0-9a-f]+)\[(?\d+)\]\)", DefaultOptions)] + private static partial Regex VerificationFailed(); + [GeneratedRegex(@"sys_tty_write\(\)\: “(?.*?)”\r?(\n|$)", DefaultSingleLine)] + private static partial Regex SysTtyWrite(); + [GeneratedRegex(@"⁂ (?[^ :\[]+?) .*\r?$", DefaultOptions)] + private static partial Regex SyscallDump(); + [GeneratedRegex(@"(\b|_)(?(undub|translation patch))(\b|_)", RegexOptions.IgnoreCase | DefaultOptions)] + private static partial Regex UndubFlag(); + [GeneratedRegex(@"Input: Pad (?\d): device='(?(?!Null).+?)', handler=(?.+?), VID=.+?\r?$", DefaultOptions)] + private static partial Regex InputDeviceGamepad(); + [GeneratedRegex(@"Found game controller \d: .+ has_accel=(?.+?), has_gyro=(?.+?)\r?$", DefaultOptions)] + private static partial Regex SdlControllerName(); +} \ No newline at end of file diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/DropboxHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/DropboxHandler.cs index ced7e58d..24fa6e4c 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/DropboxHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/DropboxHandler.cs @@ -13,17 +13,18 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers; -internal sealed class DropboxHandler : BaseSourceHandler +internal sealed partial class DropboxHandler : BaseSourceHandler { //https://www.dropbox.com/s/62ls9lw5i52fuib/RPCS3.log.gz?dl=0 - private static readonly Regex ExternalLink = new(@"(?(https?://)?(www\.)?dropbox\.com/s/(?[^/\s]+)/(?[^/\?\s])(/dl=[01])?)", DefaultOptions); + [GeneratedRegex(@"(?(https?://)?(www\.)?dropbox\.com/s/(?[^/\s]+)/(?[^/\?\s])(/dl=[01])?)", DefaultOptions)] + private static partial Regex ExternalLink(); public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection handlers) { if (string.IsNullOrEmpty(message.Content)) return (null, null); - var matches = ExternalLink.Matches(message.Content); + var matches = ExternalLink().Matches(message.Content); if (matches.Count == 0) return (null, null); diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/GenericLinkHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/GenericLinkHandler.cs index fb9b4b1c..f0b43029 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/GenericLinkHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/GenericLinkHandler.cs @@ -12,16 +12,17 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers; -internal sealed class GenericLinkHandler : BaseSourceHandler +internal sealed partial class GenericLinkHandler : BaseSourceHandler { - private static readonly Regex ExternalLink = new(@"(?(https?://)?(github\.com/RPCS3/rpcs3|cdn\.discordapp\.com/attachments)/.*/(?[^/\?\s]+\.(gz|zip|rar|7z|log)))", DefaultOptions); + [GeneratedRegex(@"(?(https?://)?(github\.com/RPCS3/rpcs3|cdn\.discordapp\.com/attachments)/.*/(?[^/\?\s]+\.(gz|zip|rar|7z|log)))", DefaultOptions)] + private static partial Regex ExternalLink(); public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection handlers) { if (string.IsNullOrEmpty(message.Content)) return (null, null); - var matches = ExternalLink.Matches(message.Content); + var matches = ExternalLink().Matches(message.Content); if (matches.Count == 0) return (null, null); diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/GoogleDriveHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/GoogleDriveHandler.cs index 05577458..1d352987 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/GoogleDriveHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/GoogleDriveHandler.cs @@ -16,9 +16,10 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers; -internal sealed class GoogleDriveHandler: BaseSourceHandler +internal sealed partial class GoogleDriveHandler: BaseSourceHandler { - private static readonly Regex ExternalLink = new(@"(?(https?://)?drive\.google\.com/(open\?id=|file/d/)(?[^/>\s]+))", DefaultOptions); + [GeneratedRegex(@"(?(https?://)?drive\.google\.com/(open\?id=|file/d/)(?[^/>\s]+))", DefaultOptions)] + private static partial Regex ExternalLink(); private static readonly string[] Scopes = { DriveService.Scope.DriveReadonly }; private static readonly string ApplicationName = "RPCS3 Compatibility Bot 2.0"; @@ -30,7 +31,7 @@ internal sealed class GoogleDriveHandler: BaseSourceHandler if (string.IsNullOrEmpty(Config.GoogleApiCredentials)) return (null, null); - var matches = ExternalLink.Matches(message.Content); + var matches = ExternalLink().Matches(message.Content); if (matches.Count == 0) return (null, null); diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/MediafireHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/MediafireHandler.cs index 834f936f..51ebf6a2 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/MediafireHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/MediafireHandler.cs @@ -13,10 +13,11 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers; -internal sealed class MediafireHandler : BaseSourceHandler +internal sealed partial class MediafireHandler : BaseSourceHandler { //http://www.mediafire.com/file/tmybrjpmtrpcejl/DemonsSouls_CrashLog_Nov.19th.zip/file - private static readonly Regex ExternalLink = new(@"(?(https?://)?(www\.)?mediafire\.com/file/(?[^/\s]+)/(?[^/\?\s]+)(/file)?)", DefaultOptions); + [GeneratedRegex(@"(?(https?://)?(www\.)?mediafire\.com/file/(?[^/\s]+)/(?[^/\?\s]+)(/file)?)", DefaultOptions)] + private static partial Regex ExternalLink(); private static readonly Client Client = new(); public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection handlers) @@ -24,7 +25,7 @@ internal sealed class MediafireHandler : BaseSourceHandler if (string.IsNullOrEmpty(message.Content)) return (null, null); - var matches = ExternalLink.Matches(message.Content); + var matches = ExternalLink().Matches(message.Content); if (matches.Count == 0) return (null, null); diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/MegaHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/MegaHandler.cs index bd769b46..0126c071 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/MegaHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/MegaHandler.cs @@ -11,11 +11,12 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers; -internal sealed class MegaHandler : BaseSourceHandler +internal sealed partial class MegaHandler : BaseSourceHandler { // mega.nz/#!8IJHBYyB!jw21m-GCs85uzj9E5XRysqyJCsNfZS0Zx4Eu9_zvuUM // mega.nz/file/8IJHBYyB#jw21m-GCs85uzj9E5XRysqyJCsNfZS0Zx4Eu9_zvuUM - private static readonly Regex ExternalLink = new(@"(?(https?://)?mega(\.co)?\.nz/(#(?[^/>\s]+)|file/(?[^/>\s]+)))", DefaultOptions); + [GeneratedRegex(@"(?(https?://)?mega(\.co)?\.nz/(#(?[^/>\s]+)|file/(?[^/>\s]+)))", DefaultOptions)] + private static partial Regex ExternalLink(); private static readonly IProgress Doodad = new Progress(_ => { }); public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection handlers) @@ -23,7 +24,7 @@ internal sealed class MegaHandler : BaseSourceHandler if (string.IsNullOrEmpty(message.Content)) return (null, null); - var matches = ExternalLink.Matches(message.Content); + var matches = ExternalLink().Matches(message.Content); if (matches.Count == 0) return (null, null); diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/OneDriveSourceHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/OneDriveSourceHandler.cs index 6bcd2a5a..a4a71993 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/OneDriveSourceHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/OneDriveSourceHandler.cs @@ -13,9 +13,10 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers; -internal sealed class OneDriveSourceHandler : BaseSourceHandler +internal sealed partial class OneDriveSourceHandler : BaseSourceHandler { - private static readonly Regex ExternalLink = new(@"(?(https?://)?(1drv\.ms|onedrive\.live\.com)/[^>\s]+)", DefaultOptions); + [GeneratedRegex(@"(?(https?://)?(1drv\.ms|onedrive\.live\.com)/[^>\s]+)", DefaultOptions)] + private static partial Regex ExternalLink(); private static readonly Client Client = new(); public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection handlers) @@ -23,7 +24,7 @@ internal sealed class OneDriveSourceHandler : BaseSourceHandler if (string.IsNullOrEmpty(message.Content)) return (null, null); - var matches = ExternalLink.Matches(message.Content); + var matches = ExternalLink().Matches(message.Content); if (matches.Count == 0) return (null, null); diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/PastebinHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/PastebinHandler.cs index 0a27278f..3441ade3 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/PastebinHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/PastebinHandler.cs @@ -11,16 +11,17 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers; -internal sealed class PastebinHandler : BaseSourceHandler +internal sealed partial class PastebinHandler : BaseSourceHandler { - private static readonly Regex ExternalLink = new(@"(?(https?://)pastebin.com/(raw/)?(?[^/>\s]+))", DefaultOptions); + [GeneratedRegex(@"(?(https?://)pastebin.com/(raw/)?(?[^/>\s]+))", DefaultOptions)] + private static partial Regex ExternalLink(); public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection handlers) { if (string.IsNullOrEmpty(message.Content)) return (null, null); - var matches = ExternalLink.Matches(message.Content); + var matches = ExternalLink().Matches(message.Content); if (matches.Count == 0) return (null, null); diff --git a/CompatBot/EventHandlers/LogParsing/SourceHandlers/YandexDiskHandler.cs b/CompatBot/EventHandlers/LogParsing/SourceHandlers/YandexDiskHandler.cs index 1f9eb823..64484a5e 100644 --- a/CompatBot/EventHandlers/LogParsing/SourceHandlers/YandexDiskHandler.cs +++ b/CompatBot/EventHandlers/LogParsing/SourceHandlers/YandexDiskHandler.cs @@ -12,9 +12,10 @@ namespace CompatBot.EventHandlers.LogParsing.SourceHandlers; -internal sealed class YandexDiskHandler: BaseSourceHandler +internal sealed partial class YandexDiskHandler: BaseSourceHandler { - private static readonly Regex ExternalLink = new(@"(?(https?://)?(www\.)?yadi\.sk/d/(?[^/>\s]+))\b", DefaultOptions); + [GeneratedRegex(@"(?(https?://)?(www\.)?yadi\.sk/d/(?[^/>\s]+))\b", DefaultOptions)] + private static partial Regex ExternalLink(); private static readonly Client Client = new(); public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection handlers) @@ -22,7 +23,7 @@ internal sealed class YandexDiskHandler: BaseSourceHandler if (string.IsNullOrEmpty(message.Content)) return (null, null); - var matches = ExternalLink.Matches(message.Content); + var matches = ExternalLink().Matches(message.Content); if (matches.Count == 0) return (null, null); diff --git a/CompatBot/EventHandlers/NewBuildsMonitor.cs b/CompatBot/EventHandlers/NewBuildsMonitor.cs index 287b8da2..6c183113 100644 --- a/CompatBot/EventHandlers/NewBuildsMonitor.cs +++ b/CompatBot/EventHandlers/NewBuildsMonitor.cs @@ -11,9 +11,10 @@ namespace CompatBot.EventHandlers; -internal static class NewBuildsMonitor +internal static partial class NewBuildsMonitor { - private static readonly Regex BuildResult = new(@"\[rpcs3:master\] \d+ new commit", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline); + [GeneratedRegex(@"\[rpcs3:master\] \d+ new commit", RegexOptions.IgnoreCase | RegexOptions.Singleline)] + private static partial Regex BuildResult(); private static readonly TimeSpan PassiveCheckInterval = TimeSpan.FromMinutes(20); private static readonly TimeSpan ActiveCheckInterval = TimeSpan.FromMinutes(1); private static readonly TimeSpan ActiveCheckResetThreshold = TimeSpan.FromMinutes(10); @@ -25,7 +26,7 @@ public static async Task OnMessageCreated(DiscordClient _, MessageCreateEventArg && !args.Author.IsCurrent && "github".Equals(args.Channel.Name, StringComparison.InvariantCultureIgnoreCase) && args.Message?.Embeds is [{ Title: { Length: > 0 } title }, ..] - && BuildResult.IsMatch(title) + && BuildResult().IsMatch(title) ) { Config.Log.Info("Found new PR merge message"); diff --git a/CompatBot/EventHandlers/PostLogHelpHandler.cs b/CompatBot/EventHandlers/PostLogHelpHandler.cs index fccbc6d8..d4c2f63a 100644 --- a/CompatBot/EventHandlers/PostLogHelpHandler.cs +++ b/CompatBot/EventHandlers/PostLogHelpHandler.cs @@ -12,10 +12,13 @@ namespace CompatBot.EventHandlers; -internal static class PostLogHelpHandler +internal static partial class PostLogHelpHandler { - private const RegexOptions DefaultOptions = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture; - private static readonly Regex UploadLogMention = new(@"\b((?(vul[ck][ae]n(-?1)?))|(?(post|upload|send|give)(ing)?\s+((a|the|rpcs3('s)?|your|you're|ur|my|full|game)\s+)*\blogs?))\b", DefaultOptions); + [GeneratedRegex( + @"\b((?(vul[ck][ae]n(-?1)?))|(?(post|upload|send|give)(ing)?\s+((a|the|rpcs3('s)?|your|you're|ur|my|full|game)\s+)*\blogs?))\b", + RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Singleline + )] + private static partial Regex UploadLogMention(); private static readonly SemaphoreSlim TheDoor = new(1, 1); private static readonly TimeSpan ThrottlingThreshold = TimeSpan.FromSeconds(5); private static readonly Dictionary DefaultExplanation = new() @@ -36,7 +39,7 @@ public static async Task OnMessageCreated(DiscordClient _, MessageCreateEventArg if (DateTime.UtcNow - lastMention < ThrottlingThreshold) return; - var match = UploadLogMention.Match(args.Message.Content); + var match = UploadLogMention().Match(args.Message.Content); if (!match.Success || string.IsNullOrEmpty(match.Groups["help"].Value)) return; diff --git a/CompatBot/EventHandlers/ProductCodeLookup.cs b/CompatBot/EventHandlers/ProductCodeLookup.cs index f0e96b8d..04240ecd 100644 --- a/CompatBot/EventHandlers/ProductCodeLookup.cs +++ b/CompatBot/EventHandlers/ProductCodeLookup.cs @@ -16,10 +16,11 @@ namespace CompatBot.EventHandlers; -internal static class ProductCodeLookup +internal static partial class ProductCodeLookup { // see http://www.psdevwiki.com/ps3/Productcode - public static readonly Regex ProductCode = new(@"(?(?:[BPSUVX][CL]|P[ETU]|NP)[AEHJKPUIX][ABDJKLMPQRSTX]|MRTC)[ \-]?(?\d{5})", RegexOptions.Compiled | RegexOptions.IgnoreCase); + [GeneratedRegex(@"(?(?:[BPSUVX][CL]|P[ETU]|NP)[AEHJKPUIX][ABDJKLMPQRSTX]|MRTC)[ \-]?(?\d{5})", RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-GB")] + public static partial Regex Pattern(); private static readonly Client CompatClient = new(); public static async Task OnMessageCreated(DiscordClient c, MessageCreateEventArgs args) @@ -101,7 +102,7 @@ public static List GetProductIds(string? input) if (string.IsNullOrEmpty(input)) return new(0); - return ProductCode.Matches(input) + return Pattern().Matches(input) .Select(match => (match.Groups["letters"].Value + match.Groups["numbers"]).ToUpper()) .Distinct() .ToList(); diff --git a/CompatBot/EventHandlers/TableFlipMonitor.cs b/CompatBot/EventHandlers/TableFlipMonitor.cs index 9328a80d..6a644911 100644 --- a/CompatBot/EventHandlers/TableFlipMonitor.cs +++ b/CompatBot/EventHandlers/TableFlipMonitor.cs @@ -12,8 +12,10 @@ namespace CompatBot.EventHandlers; -internal static class TableFlipMonitor +internal static partial class TableFlipMonitor { + [GeneratedRegex(@"(🎲|\s)+")] + private static partial Regex DiceRoll(); private static readonly char[] OpenParen = {'(', '(', 'ʕ'}; public static async Task OnMessageCreated(DiscordClient _, MessageCreateEventArgs args) @@ -38,8 +40,7 @@ public static async Task OnMessageCreated(DiscordClient _, MessageCreateEventArg try { var content = args.Message.Content; - - if (content.Contains("🎲") && Regex.IsMatch(content, @"(🎲|\s)+")) + if (content.Contains("🎲") && DiceRoll().IsMatch(content)) { var count = 1; var idx = content.IndexOf("🎲"); diff --git a/CompatBot/EventHandlers/UnknownCommandHandler.cs b/CompatBot/EventHandlers/UnknownCommandHandler.cs index 25535d6a..016b4d5c 100644 --- a/CompatBot/EventHandlers/UnknownCommandHandler.cs +++ b/CompatBot/EventHandlers/UnknownCommandHandler.cs @@ -13,12 +13,13 @@ namespace CompatBot.EventHandlers; -internal static class UnknownCommandHandler +internal static partial class UnknownCommandHandler { - private static readonly Regex BinaryQuestion = new( + [GeneratedRegex( @"^\s*(am I|(are|is|do(es)|did|can(?!\s+of\s+)|should|must|have)(n't)?|shall|shan't|may|will|won't)\b", - RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase - ); + RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase + )] + private static partial Regex BinaryQuestion(); public static Task OnError(CommandsNextExtension cne, CommandErrorEventArgs e) { @@ -49,7 +50,7 @@ public static async void OnErrorInternal(CommandsNextExtension cne, CommandError if (e.Context.Prefix != Config.CommandPrefix && e.Context.Prefix != Config.AutoRemoveCommandPrefix && e.Context.Message.Content is string msgTxt - && (msgTxt.EndsWith("?") || BinaryQuestion.IsMatch(msgTxt.AsSpan(e.Context.Prefix.Length))) + && (msgTxt.EndsWith("?") || BinaryQuestion().IsMatch(msgTxt.AsSpan(e.Context.Prefix.Length))) && e.Context.CommandsNext.RegisteredCommands.TryGetValue("8ball", out var cmd)) { var updatedContext = e.Context.CommandsNext.CreateContext( diff --git a/CompatBot/ThumbScrapper/GameTdbScraper.cs b/CompatBot/ThumbScrapper/GameTdbScraper.cs index e9188ef3..2ac8340c 100644 --- a/CompatBot/ThumbScrapper/GameTdbScraper.cs +++ b/CompatBot/ThumbScrapper/GameTdbScraper.cs @@ -16,14 +16,15 @@ namespace CompatBot.ThumbScrapper; -internal static class GameTdbScraper +internal static partial class GameTdbScraper { private static readonly HttpClient HttpClient = HttpClientFactory.Create(new CompressionMessageHandler()); private static readonly Uri TitleDownloadLink = new("https://www.gametdb.com/ps3tdb.zip?LANG=EN"); - private static readonly Regex CoverArtLink = new( + [GeneratedRegex( @"(?https?://art\.gametdb\.com/ps3/cover(?!full)[/\w\d]+\.jpg(\?\d+)?)", - RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture - ); + RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture + )] + private static partial Regex CoverArtLink(); //private static readonly List PreferredOrder = new List{"coverHQ", "coverM", "cover"}; public static async Task RunAsync(CancellationToken cancellationToken) @@ -50,7 +51,7 @@ public static async Task RunAsync(CancellationToken cancellationToken) try { var html = await HttpClient.GetStringAsync("https://www.gametdb.com/PS3/" + productCode).ConfigureAwait(false); - var coverLinks = CoverArtLink.Matches(html) + var coverLinks = CoverArtLink().Matches(html) .Select(m => m.Groups["cover_link"].Value) .Distinct() .Where(l => l.Contains(productCode, StringComparison.InvariantCultureIgnoreCase)) @@ -106,7 +107,7 @@ private static async Task UpdateGameTitlesAsync(CancellationToken cancellationTo continue; var productId = (await xmlReader.ReadElementContentAsStringAsync().ConfigureAwait(false)).ToUpperInvariant(); - if (!ProductCodeLookup.ProductCode.IsMatch(productId)) + if (!ProductCodeLookup.Pattern().IsMatch(productId)) continue; string? title = null; diff --git a/CompatBot/ThumbScrapper/PsnScraper.cs b/CompatBot/ThumbScrapper/PsnScraper.cs index 7e469f99..2d664bde 100644 --- a/CompatBot/ThumbScrapper/PsnScraper.cs +++ b/CompatBot/ThumbScrapper/PsnScraper.cs @@ -14,13 +14,15 @@ namespace CompatBot.ThumbScrapper; -internal sealed class PsnScraper +internal sealed partial class PsnScraper { private static readonly PsnClient.Client Client = new(); - public static readonly Regex ContentIdMatcher = new( - @"(?(?(?\w\w)(?\d{4}))-(?(?\w{4})(?\d{5}))_(?\d\d)-(?