mirror of
https://github.com/RPCS3/discord-bot.git
synced 2026-01-31 01:25:22 +01:00
Some performance and code optimizations (#955)
* upgrade deps, remove wrong ppu hashes * upgrade compiler packages will require container pull after build * replace Regex with compiler-generated versions * use new collection initialization syntax * configure global defaults for regex * bump min amd driver version fixes #950 * add macos version check fixes #948 * fix #954 (!sudo log date)
This commit is contained in:
@@ -11,6 +11,6 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="StrawberryShake.Server" Version="13.8.1" />
|
||||
<PackageReference Include="StrawberryShake.Server" Version="13.9.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -30,12 +30,12 @@ public static class ApiConfig
|
||||
{-3, (false, false, false, "Illegal characters found, please try again with a different search term.") },
|
||||
};
|
||||
|
||||
public static readonly List<int> ResultAmount = new(){25, 50, 100, 200};
|
||||
public static readonly List<int> ResultAmount = [25, 50, 100, 200];
|
||||
|
||||
public static readonly Dictionary<char, string[]> Directions = new()
|
||||
{
|
||||
{'a', new []{"a", "asc", "ascending"}},
|
||||
{'d', new []{"d", "desc", "descending"} },
|
||||
{'a', ["a", "asc", "ascending"] },
|
||||
{'d', ["d", "desc", "descending"] },
|
||||
};
|
||||
|
||||
public static readonly Dictionary<string, int> Statuses = new()
|
||||
@@ -58,8 +58,8 @@ public static class ApiConfig
|
||||
|
||||
public static readonly Dictionary<char, string[]> ReleaseTypes = new()
|
||||
{
|
||||
{'b', new[] {"b", "d", "disc", "disk", "bluray", "blu-ray"}},
|
||||
{'n', new[] {"n", "p", "PSN"}},
|
||||
{'b', ["b", "d", "disc", "disk", "bluray", "blu-ray"] },
|
||||
{'n', ["n", "p", "PSN"] },
|
||||
};
|
||||
|
||||
public static readonly Dictionary<string, char> ReverseDirections;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
|
||||
<PackageReference Include="NLog" Version="5.2.8" />
|
||||
<PackageReference Include="NLog" Version="5.3.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -11,7 +11,7 @@ public class CompressionMessageHandler : DelegatingHandler
|
||||
{
|
||||
public ICollection<ICompressor> Compressors { get; }
|
||||
public static readonly string PostCompressionFlag = "X-Set-Content-Encoding";
|
||||
public static readonly string[] DefaultContentEncodings = { "gzip", "deflate" };
|
||||
public static readonly string[] DefaultContentEncodings = ["gzip", "deflate"];
|
||||
public static readonly string DefaultAcceptEncodings = "gzip, deflate";
|
||||
|
||||
private readonly bool isServer;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
||||
<PackageReference Include="Octokit" Version="9.1.2" />
|
||||
<PackageReference Include="Octokit" Version="11.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CompatApiClient\CompatApiClient.csproj" />
|
||||
|
||||
@@ -24,7 +24,6 @@ public class IrdClient
|
||||
|
||||
private readonly HttpClient client;
|
||||
private readonly JsonSerializerOptions jsonOptions;
|
||||
private static readonly Regex IrdFilename = new(@"ird/(?<filename>\w{4}\d{5}-[A-F0-9]+\.ird)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
|
||||
|
||||
public IrdClient()
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscUtils.OpticalDisk" Version="0.16.13" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.59" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.61" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
|
||||
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -17,7 +17,7 @@ using MediafireClient.POCOs;
|
||||
|
||||
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*""(?<security_token>.+)""", 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*""(?<direct_link>https?://download\d+\.mediafire\.com/.+)""");
|
||||
[GeneratedRegex(@"(var\s+optDirectURL|href)\s*=\s*""(?<direct_link>https?://download\d+\.mediafire\.com/.+)""")]
|
||||
private static partial Regex DirectUrlRegex();
|
||||
|
||||
public Client()
|
||||
{
|
||||
@@ -81,7 +82,7 @@ public sealed class 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);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ using PsnClient.Utils;
|
||||
|
||||
namespace PsnClient;
|
||||
|
||||
public class Client
|
||||
public partial class Client
|
||||
{
|
||||
private readonly HttpClient client;
|
||||
private readonly JsonSerializerOptions dashedJson;
|
||||
@@ -28,23 +28,27 @@ 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(@"(?<id>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",
|
||||
"en-KW", "en-LB", "en-MT", "en-MY", "en-NO", "en-NZ", "en-OM", "en-PL", "en-QA", "en-RO", "en-SA", "en-SE", "en-SG", "en-SI", "en-SK", "en-TH", "en-TR", "en-TW", "en-ZA", "ja-JP",
|
||||
"ar-AE", "ar-BH", "ar-KW", "ar-LB", "ar-OM", "ar-QA", "ar-SA", "da-DK", "de-AT", "de-CH", "de-DE", "de-LU", "es-AR", "es-BO", "es-CL", "es-CO", "es-CR", "es-EC", "es-ES", "es-GT",
|
||||
"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(@"(?<id>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=(?<dest>\d+);ImageVersion=(?<image>[0-9a-f]+);SystemSoftwareVersion=(?<version>\d+\.\d+);CDN=(?<url>http[^;]+);CDN_Timeout=(?<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", };
|
||||
private static readonly string[] KnownFwLocales = ["jp", "us", "eu", "kr", "uk", "mx", "au", "sa", "tw", "ru", "cn", "br",];
|
||||
|
||||
public Client()
|
||||
{
|
||||
@@ -117,7 +121,7 @@ public class Client
|
||||
tries++;
|
||||
}
|
||||
if (response.StatusCode == HttpStatusCode.Redirect)
|
||||
return new(0);
|
||||
return [];
|
||||
}
|
||||
|
||||
using (response)
|
||||
@@ -125,7 +129,7 @@ public class 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<string>();
|
||||
foreach (Match m in matches)
|
||||
if (m.Groups["id"].Value is {Length: >0} id)
|
||||
@@ -345,7 +349,7 @@ public class Client
|
||||
|
||||
allVersions = allVersions.OrderByDescending(fwi => fwi.Version).ToList();
|
||||
if (allVersions.Count == 0)
|
||||
return new(0);
|
||||
return [];
|
||||
|
||||
var maxFw = allVersions.First();
|
||||
var result = allVersions.Where(fwi => fwi.Version == maxFw.Version).ToList();
|
||||
@@ -419,7 +423,7 @@ public class Client
|
||||
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;
|
||||
|
||||
@@ -18,7 +18,7 @@ public static class TmdbHasher
|
||||
public static byte[] FromHexString(this string hexString)
|
||||
{
|
||||
if (hexString.Length == 0)
|
||||
return Array.Empty<byte>();
|
||||
return [];
|
||||
|
||||
if (hexString.Length % 2 != 0)
|
||||
throw new ArgumentException("Invalid hex string format: odd number of octets", nameof(hexString));
|
||||
|
||||
@@ -308,7 +308,7 @@ internal sealed class BotStats: BaseCommandModuleCustom
|
||||
}
|
||||
}
|
||||
|
||||
internal static readonly string[] GoodDog = {"🐶", "🐕", "🐩", "🐕🦺",};
|
||||
internal static readonly string[] GoodKot = {"😸", "😺", "😻", "😽",};
|
||||
private static readonly string[] MeanKot = {"🙀", "😿", "😾",};
|
||||
internal static readonly string[] GoodDog = ["🐶", "🐕", "🐩", "🐕🦺",];
|
||||
internal static readonly string[] GoodKot = ["😸", "😺", "😻", "😽",];
|
||||
private static readonly string[] MeanKot = ["🙀", "😿", "😾",];
|
||||
}
|
||||
@@ -32,7 +32,7 @@ using Microsoft.TeamFoundation.Build.WebApi;
|
||||
|
||||
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(?<version>\d+\.\d+\.\d+)-(?<build>\d+)-(?<commit>[0-9a-f]+)\b",
|
||||
RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture
|
||||
);
|
||||
[GeneratedRegex(@"v(?<version>\d+\.\d+\.\d+)-(?<build>\d+)-(?<commit>[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 @@ internal sealed class CompatList : BaseCommandModuleCustom
|
||||
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();
|
||||
@@ -430,7 +430,7 @@ internal sealed class CompatList : BaseCommandModuleCustom
|
||||
#endif
|
||||
var channel = await ctx.GetChannelForSpamAsync().ConfigureAwait(false);
|
||||
if (result?.Results?.Count == 1)
|
||||
await ProductCodeLookup.LookupAndPostProductCodeEmbedAsync(ctx.Client, ctx.Message, ctx.Channel, new(result.Results.Keys)).ConfigureAwait(false);
|
||||
await ProductCodeLookup.LookupAndPostProductCodeEmbedAsync(ctx.Client, ctx.Message, ctx.Channel, [..result.Results.Keys]).ConfigureAwait(false);
|
||||
else if (result != null)
|
||||
foreach (var msg in FormatSearchResults(ctx, result))
|
||||
await channel.SendAutosplitMessageAsync(msg, blockStart: "", blockEnd: "").ConfigureAwait(false);
|
||||
@@ -597,7 +597,7 @@ internal sealed class CompatList : BaseCommandModuleCustom
|
||||
}
|
||||
}
|
||||
|
||||
var scoreList = JsonSerializer.Deserialize<List<Metacritic>>(json) ?? new();
|
||||
var scoreList = JsonSerializer.Deserialize<List<Metacritic>>(json) ?? [];
|
||||
|
||||
Config.Log.Debug($"Importing {scoreList.Count} Metacritic items");
|
||||
var duplicates = new List<Metacritic>();
|
||||
@@ -666,7 +666,7 @@ internal sealed class CompatList : BaseCommandModuleCustom
|
||||
.Where(i => i.coef > 0.85)
|
||||
.OrderByDescending(i => i.coef)
|
||||
.ToList()
|
||||
?? new List<(string productCode, TitleInfo titleInfo, double coef)>();
|
||||
?? [];
|
||||
if (compatListMatches.Any(i => i.coef > 0.99))
|
||||
compatListMatches = compatListMatches.Where(i => i.coef > 0.99).ToList();
|
||||
else if (compatListMatches.Any(i => i.coef > 0.95))
|
||||
@@ -697,7 +697,7 @@ internal sealed class CompatList : BaseCommandModuleCustom
|
||||
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)
|
||||
|
||||
@@ -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 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 @@ internal sealed class ContentFilters: BaseCommandModuleCustom
|
||||
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 @@ internal sealed class ContentFilters: BaseCommandModuleCustom
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -10,9 +10,10 @@ using DSharpPlus.Entities;
|
||||
|
||||
namespace CompatBot.Commands.Converters;
|
||||
|
||||
internal sealed class TextOnlyDiscordChannelConverter : IArgumentConverter<DiscordChannel>
|
||||
internal sealed partial class TextOnlyDiscordChannelConverter : IArgumentConverter<DiscordChannel>
|
||||
{
|
||||
private static Regex ChannelRegex { get; } = new(@"^<#(\d+)>$", RegexOptions.ECMAScript | RegexOptions.Compiled);
|
||||
[GeneratedRegex(@"^<#(\d+)>$", RegexOptions.ECMAScript)]
|
||||
private static partial Regex ChannelRegex();
|
||||
|
||||
Task<Optional<DiscordChannel>> IArgumentConverter<DiscordChannel>.ConvertAsync(string value, CommandContext ctx)
|
||||
=> ConvertAsync(value, ctx);
|
||||
@@ -20,7 +21,7 @@ internal sealed class TextOnlyDiscordChannelConverter : IArgumentConverter<Disco
|
||||
public static async Task<Optional<DiscordChannel>> ConvertAsync(string value, CommandContext ctx)
|
||||
{
|
||||
var guildList = new List<DiscordGuild>(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 @@ internal sealed class TextOnlyDiscordChannelConverter : IArgumentConverter<Disco
|
||||
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 = (
|
||||
|
||||
@@ -19,11 +19,12 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
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(@"((?<days>\d+)(\.|d\s*))?((?<hours>\d+)(\:|h\s*))?((?<mins>\d+)m?)?",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture);
|
||||
|
||||
[GeneratedRegex(@"((?<days>\d+)(\.|d\s*))?((?<hours>\d+)(\:|h\s*))?((?<mins>\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 @@ internal class EventsBaseCommand: BaseCommandModuleCustom
|
||||
|
||||
private static async Task<TimeSpan?> TryParseTimeSpanAsync(CommandContext ctx, string duration, bool react = true)
|
||||
{
|
||||
var d = Duration.Match(duration);
|
||||
var d = Duration().Match(duration);
|
||||
if (!d.Success)
|
||||
{
|
||||
if (react)
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
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 @@ internal sealed class Explain: BaseCommandModuleCustom
|
||||
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);
|
||||
|
||||
@@ -49,12 +49,12 @@ internal sealed class ForcedNicknames : BaseCommandModuleCustom
|
||||
List<DiscordGuild> guilds;
|
||||
if (ctx.Guild == null)
|
||||
{
|
||||
guilds = ctx.Client.Guilds?.Values.ToList() ?? new List<DiscordGuild>(0);
|
||||
guilds = ctx.Client.Guilds?.Values.ToList() ?? [];
|
||||
if (guilds.Count > 1)
|
||||
await ctx.Channel.SendMessageAsync($"{discordUser.Mention} will be renamed in all {guilds.Count} servers").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
guilds = new(){ctx.Guild};
|
||||
guilds = [ctx.Guild];
|
||||
|
||||
int changed = 0, noPermissions = 0, failed = 0;
|
||||
await using var db = new BotDb();
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace CompatBot.Commands;
|
||||
[Description("Generates a minesweeper field with specified parameters")]
|
||||
internal sealed class Minesweeper : BaseCommandModuleCustom
|
||||
{
|
||||
//private static readonly string[] Numbers = {"0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣",};
|
||||
private static readonly string[] Numbers = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",};
|
||||
private static readonly string[] Bombs = {"*", "◎"};
|
||||
//private static readonly string[] Numbers = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣"];
|
||||
private static readonly string[] Numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
|
||||
private static readonly string[] Bombs = ["*", "◎"];
|
||||
private static readonly int MaxBombLength;
|
||||
|
||||
static Minesweeper()
|
||||
|
||||
@@ -16,12 +16,12 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CompatBot.Commands;
|
||||
|
||||
internal sealed class Misc: BaseCommandModuleCustom
|
||||
internal sealed partial class Misc: BaseCommandModuleCustom
|
||||
{
|
||||
private static readonly Random rng = new();
|
||||
|
||||
private static readonly List<string> EightBallAnswers = new()
|
||||
{
|
||||
private static readonly List<string> EightBallAnswers =
|
||||
[
|
||||
// keep this at 2:1:1 ratio
|
||||
// 70
|
||||
"It is certain", "It is decidedly so", "Without a doubt", "Yes definitely", "You may rely on it",
|
||||
@@ -55,11 +55,11 @@ internal sealed class Misc: BaseCommandModuleCustom
|
||||
"Nein!", "I think not", "I'm afraid not", "Nay", "Yesn't",
|
||||
"No way", "Certainly not", "I must say no", "Nah", "Negative", // 30
|
||||
"Definitely not", "No way, Jose", "Not today", "No no no no no no no no no no. No.", "Not in a million years",
|
||||
"I'm afraid I can't let you do that Dave.", "This mission is too important for me to allow you to jeopardize it.", "Oh, I don't think so", "By *no* means", "👎", // 40
|
||||
};
|
||||
"I'm afraid I can't let you do that Dave.", "This mission is too important for me to allow you to jeopardize it.", "Oh, I don't think so", "By *no* means", "👎" // 40
|
||||
];
|
||||
|
||||
private static readonly List<string> EightBallSnarkyComments = new()
|
||||
{
|
||||
private static readonly List<string> EightBallSnarkyComments =
|
||||
[
|
||||
"Can't answer the question that wasn't asked",
|
||||
"Having issues with my mind reading attachment, you'll have to state your question explicitly",
|
||||
"Bad reception on your brain waves today, can't read the question",
|
||||
@@ -67,18 +67,17 @@ internal sealed class Misc: BaseCommandModuleCustom
|
||||
"In Discord no one can read your question if you don't type it",
|
||||
"In space no one can hear you scream; that's what you're doing right now",
|
||||
"Unfortunately there's no technology to transmit your question telepathically just yet",
|
||||
"I'd say maybe, but I'd need to see your question first",
|
||||
};
|
||||
"I'd say maybe, but I'd need to see your question first"
|
||||
];
|
||||
|
||||
private static readonly List<string> EightBallTimeUnits = new()
|
||||
{
|
||||
private static readonly List<string> EightBallTimeUnits =
|
||||
[
|
||||
"second", "minute", "hour", "day", "week", "month", "year", "decade", "century", "millennium",
|
||||
"night", "moon cycle", "solar eclipse", "blood moon", "complete emulator rewrite",
|
||||
};
|
||||
"night", "moon cycle", "solar eclipse", "blood moon", "complete emulator rewrite"
|
||||
];
|
||||
|
||||
private static readonly List<string> RateAnswers = new()
|
||||
{
|
||||
// 60
|
||||
private static readonly List<string> RateAnswers =
|
||||
[
|
||||
"Not so bad", "I likesss!", "Pretty good", "Guchi gud", "Amazing!",
|
||||
"Glorious!", "Very good", "Excellent...", "Magnificent", "Rate bot says he likes, so you like too",
|
||||
"If you reorganize the words it says \"pretty cool\"", "I approve", "<:morgana_sparkle:315899996274688001> やるじゃねーか!", "Not half bad 👍", "Belissimo!",
|
||||
@@ -109,11 +108,11 @@ internal sealed class Misc: BaseCommandModuleCustom
|
||||
"Boring", "Easily forgettable", "An Abomination", "A Monstrosity", "Truly horrific",
|
||||
"Filled with despair!", "Eroded by despair", "Hopeless…", "It's pretty foolish to want to rate this", "Cursed with misfortune",
|
||||
"Nothing but terror", "Not good, at all", "A waste of time",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly char[] Separators = { ' ', ' ', '\r', '\n' };
|
||||
private static readonly char[] Suffixes = {',', '.', ':', ';', '!', '?', ')', '}', ']', '>', '+', '-', '/', '*', '=', '"', '\'', '`'};
|
||||
private static readonly char[] Prefixes = {'@', '(', '{', '[', '<', '!', '`', '"', '\'', '#'};
|
||||
private static readonly char[] Separators = [' ', ' ', '\r', '\n'];
|
||||
private static readonly char[] Suffixes = [',', '.', ':', ';', '!', '?', ')', '}', ']', '>', '+', '-', '/', '*', '=', '"', '\'', '`'];
|
||||
private static readonly char[] Prefixes = ['@', '(', '{', '[', '<', '!', '`', '"', '\'', '#'];
|
||||
private static readonly char[] EveryTimable = Separators.Concat(Suffixes).Concat(Prefixes).Distinct().ToArray();
|
||||
|
||||
private static readonly HashSet<string> Me = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
@@ -126,9 +125,12 @@ internal sealed class Misc: BaseCommandModuleCustom
|
||||
"your", "you're", "yor", "ur", "yours", "your's",
|
||||
};
|
||||
|
||||
private static readonly HashSet<char> Vowels = new() {'a', 'e', 'i', 'o', 'u'};
|
||||
private static readonly HashSet<char> Vowels = ['a', 'e', 'i', 'o', 'u'];
|
||||
|
||||
private static readonly Regex Instead = new("rate (?<instead>.+) instead", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline);
|
||||
[GeneratedRegex("rate (?<instead>.+) instead", RegexOptions.ExplicitCapture | RegexOptions.Singleline)]
|
||||
private static partial Regex Instead();
|
||||
[GeneratedRegex(@"(?<num>\d+)?d(?<face>\d+)(?:\+(?<mod>\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 +157,7 @@ internal sealed class Misc: BaseCommandModuleCustom
|
||||
{
|
||||
var result = "";
|
||||
var embed = new DiscordEmbedBuilder();
|
||||
if (dices is string dice && Regex.Matches(dice, @"(?<num>\d+)?d(?<face>\d+)(?:\+(?<mod>\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)
|
||||
@@ -241,7 +243,7 @@ internal sealed class Misc: BaseCommandModuleCustom
|
||||
return;
|
||||
}
|
||||
|
||||
await ProductCodeLookup.LookupAndPostProductCodeEmbedAsync(ctx.Client, ctx.Message, ctx.Channel, new() {productCode.ProductCode}).ConfigureAwait(false);
|
||||
await ProductCodeLookup.LookupAndPostProductCodeEmbedAsync(ctx.Client, ctx.Message, ctx.Channel, [productCode.ProductCode]).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -318,7 +320,7 @@ internal sealed class Misc: BaseCommandModuleCustom
|
||||
var choiceFlags = new HashSet<char>();
|
||||
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();
|
||||
|
||||
@@ -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;
|
||||
@@ -107,15 +108,15 @@ internal sealed partial class Psn
|
||||
catch (Exception e)
|
||||
{
|
||||
Config.Log.Warn(e, "Failed to get title update info");
|
||||
embeds = new()
|
||||
{
|
||||
embeds =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Color = Config.Colors.Maintenance,
|
||||
Title = "Service is unavailable",
|
||||
Description = "There was an error communicating with the service. Try again in a few minutes.",
|
||||
}
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
if (ctx.IsOnionLike()
|
||||
@@ -158,7 +159,7 @@ internal sealed partial class Psn
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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 @@ internal sealed partial class Psn: BaseCommandModuleCustom
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,9 @@ internal partial class Sudo
|
||||
[Description("Commands to manage dotnet")]
|
||||
public sealed partial class Dotnet : BaseCommandModuleCustom
|
||||
{
|
||||
[GeneratedRegex(@"\.NET( Core)? (?<major>\d+)\.(?<minor>\d+)\.(?<patch>\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 @@ internal partial class Sudo
|
||||
|
||||
if (string.IsNullOrEmpty(version))
|
||||
{
|
||||
var versionMatch = Regex.Match(
|
||||
System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription,
|
||||
@"\.NET( Core)? (?<major>\d+)\.(?<minor>\d+)\.(?<patch>\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 @@ internal partial class Sudo
|
||||
|
||||
return (true, stdout);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,7 @@ internal sealed partial class Sudo
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -135,18 +135,21 @@ internal sealed partial class Sudo : BaseCommandModuleCustom
|
||||
try
|
||||
{
|
||||
Config.Log.Factory.Flush();
|
||||
var logPath = Config.CurrentLogPath;
|
||||
string[] logPaths = [Config.CurrentLogPath];
|
||||
if (DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var logDate))
|
||||
logPath = Path.Combine(Config.LogPath, $"bot.{logDate:yyyyMMdd}.*.log");
|
||||
if (!File.Exists(logPath))
|
||||
{
|
||||
await ctx.ReactWithAsync(Config.Reactions.Failure, "Log file does not exist for specified day", true).ConfigureAwait(false);
|
||||
var enumOptions = new EnumerationOptions { IgnoreInaccessible = true, RecurseSubdirectories = false, };
|
||||
logPaths = Directory.GetFiles(Config.LogPath, $"bot.{logDate:yyyyMMdd}.*.log", enumOptions);
|
||||
}
|
||||
if (logPaths.Length is 0)
|
||||
{
|
||||
await ctx.ReactWithAsync(Config.Reactions.Failure, "Log files do not exist for specified day", true).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await using var result = Config.MemoryStreamManager.GetStream();
|
||||
using (var zip = new ZipWriter(result, new(CompressionType.LZMA){DeflateCompressionLevel = CompressionLevel.Default}))
|
||||
foreach (var fname in Directory.EnumerateFiles(Config.LogPath, Path.GetFileName(logPath), new EnumerationOptions { IgnoreInaccessible = true, RecurseSubdirectories = false, }))
|
||||
foreach (var fname in logPaths)
|
||||
{
|
||||
await using var log = File.Open(fname, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
zip.Write(Path.GetFileName(fname), log);
|
||||
@@ -155,7 +158,7 @@ internal sealed partial class Sudo : BaseCommandModuleCustom
|
||||
if (result.Length <= ctx.GetAttachmentSizeLimit())
|
||||
{
|
||||
result.Seek(0, SeekOrigin.Begin);
|
||||
await ctx.Channel.SendMessageAsync(new DiscordMessageBuilder().AddFile(Path.GetFileName(logPath) + ".zip", result)).ConfigureAwait(false);
|
||||
await ctx.Channel.SendMessageAsync(new DiscordMessageBuilder().AddFile(Path.GetFileName(logPaths[0]) + ".zip", result)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await ctx.ReactWithAsync(Config.Reactions.Failure, "Compressed log size is too large, ask 13xforever for help :(", true).ConfigureAwait(false);
|
||||
|
||||
@@ -49,26 +49,26 @@ internal sealed class Vision: BaseCommandModuleCustom
|
||||
{
|
||||
["cat"] = BotStats.GoodKot,
|
||||
["dog"] = BotStats.GoodDog,
|
||||
["hedgehog"] = new[] {"🦔"},
|
||||
["flower"] = new[] {"🌷", "🌸", "🌹", "🌺", "🌼", "🥀", "💐", "🌻", "💮",},
|
||||
["lizard"] = new[] {"🦎",},
|
||||
["bird"] = new[] {"🐦", "🕊", "🦜", "🦆", "🦅", "🐓", "🐤", "🦩",},
|
||||
["duck"] = new[] {"🦆",},
|
||||
["eagle"] = new[] {"🦅",},
|
||||
["turkey"] = new[] {"🦃",},
|
||||
["turtle"] = new[] {"🐢",},
|
||||
["bear"] = new[] {"🐻", "🐼",},
|
||||
["panda"] = new[] {"🐼",},
|
||||
["fox"] = new[] {"🦊",},
|
||||
["pig"] = new[] {"🐷", "🐖", "🐽", "🐗",},
|
||||
["primate"] = new[] {"🐵", "🐒", "🙊", "🙉", "🙈",},
|
||||
["fish"] = new[] {"🐟", "🐠", "🐡", "🦈",},
|
||||
["car"] = new[] {"🚗", "🏎", "🚙", "🚓", "🚘", "🚔",},
|
||||
["banana"] = new[] {"🍌"},
|
||||
["fruit"] = new[] {"🍇", "🍈", "🍉", "🍊", "🍍", "🍑", "🍒", "🍓", "🍋", "🍐", "🍎", "🍏", "🥑", "🥝", "🥭", "🍅",},
|
||||
["vegetable"] = new[] {"🍠", "🍅", "🍆", "🥔", "🥕", "🥒",},
|
||||
["watermelon"] = new[] {"🍉",},
|
||||
["strawberry"] = new[] {"🍓",},
|
||||
["hedgehog"] = ["🦔",],
|
||||
["flower"] = ["🌷", "🌸", "🌹", "🌺", "🌼", "🥀", "💐", "🌻", "💮",],
|
||||
["lizard"] = ["🦎",],
|
||||
["bird"] = ["🐦", "🕊", "🦜", "🦆", "🦅", "🐓", "🐤", "🦩",],
|
||||
["duck"] = ["🦆",],
|
||||
["eagle"] = ["🦅",],
|
||||
["turkey"] = ["🦃",],
|
||||
["turtle"] = ["🐢",],
|
||||
["bear"] = ["🐻", "🐼",],
|
||||
["panda"] = ["🐼",],
|
||||
["fox"] = ["🦊",],
|
||||
["pig"] = ["🐷", "🐖", "🐽", "🐗",],
|
||||
["primate"] = ["🐵", "🐒", "🙊", "🙉", "🙈",],
|
||||
["fish"] = ["🐟", "🐠", "🐡", "🦈",],
|
||||
["car"] = ["🚗", "🏎", "🚙", "🚓", "🚘", "🚔",],
|
||||
["banana"] = ["🍌",],
|
||||
["fruit"] = ["🍇", "🍈", "🍉", "🍊", "🍍", "🍑", "🍒", "🍓", "🍋", "🍐", "🍎", "🍏", "🥑", "🥝", "🥭", "🍅",],
|
||||
["vegetable"] = ["🍠", "🍅", "🍆", "🥔", "🥕", "🥒",],
|
||||
["watermelon"] = ["🍉",],
|
||||
["strawberry"] = ["🍓",],
|
||||
};
|
||||
|
||||
[Command("describe"), TriggersTyping]
|
||||
|
||||
@@ -43,32 +43,32 @@
|
||||
<PackageReference Include="DSharpPlus.CommandsNext" Version="4.4.6" />
|
||||
<PackageReference Include="DSharpPlus.Interactivity" Version="4.4.6" />
|
||||
<PackageReference Include="DSharpPlus.SlashCommands" Version="4.4.6" />
|
||||
<PackageReference Include="Google.Apis.Drive.v3" Version="1.66.0.3309" />
|
||||
<PackageReference Include="Google.Apis.Drive.v3" Version="1.68.0.3373" />
|
||||
<PackageReference Include="ksemenenko.ColorThief" Version="1.1.1.4" />
|
||||
<PackageReference Include="MathParser.org-mXparser" Version="5.2.1" />
|
||||
<PackageReference Include="MegaApiClient" Version="1.10.4" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.22.0" />
|
||||
<PackageReference Include="Microsoft.Azure.CognitiveServices.Vision.ComputerVision" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.2">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
|
||||
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="16.205.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
|
||||
<PackageReference Include="Nerdbank.Streams" Version="2.10.72" />
|
||||
<PackageReference Include="NLog" Version="5.2.8" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.8" />
|
||||
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||
<PackageReference Include="Nerdbank.Streams" Version="2.11.74" />
|
||||
<PackageReference Include="NLog" Version="5.3.2" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.11" />
|
||||
<PackageReference Include="NReco.Text.AhoCorasickDoubleArrayTrie" Version="1.1.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.36.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.1" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.2" />
|
||||
<PackageReference Include="SharpCompress" Version="0.37.2" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.3" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.5" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Clients\CirrusCiClient\CirrusCiClient.csproj" />
|
||||
|
||||
@@ -96,8 +96,8 @@ internal static class Config
|
||||
|
||||
internal static class AllowedMentions
|
||||
{
|
||||
internal static readonly IMention[] UsersOnly = { UserMention.All };
|
||||
internal static readonly IMention[] Nothing = Array.Empty<IMention>();
|
||||
internal static readonly IMention[] UsersOnly = [UserMention.All];
|
||||
internal static readonly IMention[] Nothing = [];
|
||||
}
|
||||
|
||||
internal static string CurrentLogPath => Path.GetFullPath(Path.Combine(LogPath, "bot.log"));
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace CompatBot.Database.Migrations
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "event_schedule_year_event_name",
|
||||
table: "event_schedule",
|
||||
columns: new[] { "year", "event_name" });
|
||||
columns: ["year", "event_name"]);
|
||||
|
||||
migrationBuilder.Sql("INSERT INTO event_schedule SELECT id, year, start, end, name, 'E3' AS event_name FROM e3_schedule");
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace CompatBot.Database.Migrations
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "stats_category_key",
|
||||
table: "stats",
|
||||
columns: new[] { "category", "key" },
|
||||
columns: ["category", "key"],
|
||||
unique: true);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace CompatBot.Database.Migrations
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "forced_nickname_guild_id_user_id",
|
||||
table: "forced_nicknames",
|
||||
columns: new[] { "guild_id", "user_id" },
|
||||
columns: ["guild_id", "user_id"],
|
||||
unique: true);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace CompatBot.Database.Migrations
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "stats_category_bucket_key",
|
||||
table: "stats",
|
||||
columns: new[] { "category", "bucket", "key" },
|
||||
columns: ["category", "bucket", "key"],
|
||||
unique: true);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace CompatBot.Database.Migrations
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "stats_category_key",
|
||||
table: "stats",
|
||||
columns: new[] { "category", "key" },
|
||||
columns: ["category", "key"],
|
||||
unique: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +50,9 @@ internal static class HwInfoProvider
|
||||
|
||||
if (gpuStringParts[0].ToLower() is not ("nvidia" or "amd" or "ati" or "intel" or "apple"))
|
||||
if (LogParserResult.IsNvidia(gpuString))
|
||||
gpuStringParts = new[] { "NVIDIA", gpuString };
|
||||
gpuStringParts = ["NVIDIA", gpuString];
|
||||
else if (LogParserResult.IsAmd(gpuString))
|
||||
gpuStringParts = new[] { "AMD", gpuString };
|
||||
gpuStringParts = ["AMD", gpuString];
|
||||
else
|
||||
{
|
||||
Config.Log.Warn($"Unknown GPU maker {gpuStringParts[0]}, plz fix");
|
||||
|
||||
@@ -20,11 +20,11 @@ internal static class StatsStorage
|
||||
private static readonly SemaphoreSlim Barrier = new(1, 1);
|
||||
private static readonly SemaphoreSlim BucketLock = new(1, 1);
|
||||
private static readonly (string name, MemoryCache cache)[] AllCaches =
|
||||
{
|
||||
[
|
||||
(nameof(CmdStatCache), CmdStatCache),
|
||||
(nameof(ExplainStatCache), ExplainStatCache),
|
||||
(nameof(GameStatCache), GameStatCache),
|
||||
};
|
||||
];
|
||||
|
||||
private static ((int y, int m, int d, int h) Key, string Value) bucketPrefix = ((0, 0, 0, 0), "");
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace CompatBot.EventHandlers
|
||||
{
|
||||
internal static class BotReactionsHandler
|
||||
internal static partial class BotReactionsHandler
|
||||
{
|
||||
private static readonly AhoCorasickDoubleArrayTrie<bool> ChillCheck = new(new[]
|
||||
{
|
||||
@@ -47,10 +47,10 @@ namespace CompatBot.EventHandlers
|
||||
}.Select(DiscordEmoji.FromUnicode).ToArray();
|
||||
|
||||
private static readonly string[] SadMessages =
|
||||
{
|
||||
[
|
||||
"Okay (._.)", "As you wish", "My bad", "I only wanted to help", "Dobby will learn, master",
|
||||
"Sorry...", "I'll try to be smarter next time", "Your wish is my command", "Done.",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly DiscordEmoji[] ThankYouReactions = new[]
|
||||
{
|
||||
@@ -63,15 +63,14 @@ namespace CompatBot.EventHandlers
|
||||
}.Select(DiscordEmoji.FromUnicode).ToArray();
|
||||
|
||||
private static readonly string[] ThankYouMessages =
|
||||
{
|
||||
[
|
||||
"Aww", "I'm here to help", "Always a pleasure", "Thank you", "Good word is always appreciated",
|
||||
"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>kot(to)?)|(?<doggo>doggo|jarves))\b",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture
|
||||
);
|
||||
|
||||
[GeneratedRegex(@"\b((?<kot>kot(to)?)|(?<doggo>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 @@ namespace CompatBot.EventHandlers
|
||||
}
|
||||
#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
|
||||
|
||||
@@ -18,10 +18,14 @@ using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
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)/(?<invite_id>[a-z0-9\-]+))|(\.me/(?<me_id>.*?))(\s|>|$))", DefaultOptions);
|
||||
[GeneratedRegex(@"(https?://)?discord((((app)?\.com/invite|\.gg)/(?<invite_id>[a-z0-9\-]+))|(\.me/(?<me_id>.*?))(\s|>|$))", RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Multiline)]
|
||||
private static partial Regex InviteLink();
|
||||
[GeneratedRegex(@"name=""csrf-token"" content=""(?<csrf_token>\w+)""")]
|
||||
private static partial Regex CsrfTokenPattern();
|
||||
[GeneratedRegex(@"name=""serverEid"" value=""(?<server_eid>\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 @@ internal static class DiscordInviteFilter
|
||||
if (string.IsNullOrEmpty(message))
|
||||
return (false, false, new(0));
|
||||
|
||||
var inviteCodes = new HashSet<string>(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<string>(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<string>? recentInvites) && recentInvites is not null)
|
||||
{
|
||||
@@ -232,8 +236,8 @@ internal static class DiscordInviteFilter
|
||||
continue;
|
||||
|
||||
hasInvalidInvites = true;
|
||||
var csrfTokenMatch = Regex.Match(html, @"name=""csrf-token"" content=""(?<csrf_token>\w+)""");
|
||||
var serverEidMatch = Regex.Match(html, @"name=""serverEid"" value=""(?<server_eid>\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")
|
||||
|
||||
@@ -11,13 +11,17 @@ using DSharpPlus.EventArgs;
|
||||
|
||||
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(@"(?<issue_mention>\b(issue|pr|pull[ \-]request|bug)\s*#?\s*(?<number>\d+)|\B#(?<also_number>1?\d{4})|(https?://)github.com/RPCS3/rpcs3/(issues|pull)/(?<another_number>\d+)(#issuecomment-(?<comment_id>\d+))?)\b", DefaultOptions);
|
||||
public static readonly Regex CommitMention = new(@"(?<commit_mention>(https?://)github.com/RPCS3/rpcs3/commit/(?<commit_hash>[0-9a-f]+))\b", DefaultOptions);
|
||||
public static readonly Regex ImageMarkup = new(@"(?<img_markup>!\[(?<img_caption>[^\]]+)\]\((?<img_link>\w+://[^\)]+)\))", DefaultOptions);
|
||||
private static readonly Regex IssueLink = new(@"github.com/RPCS3/rpcs3/issues/(?<number>\d+)", DefaultOptions);
|
||||
private const RegexOptions DefaultOptions = RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture;
|
||||
[GeneratedRegex(@"(?<issue_mention>\b(issue|pr|pull[ \-]request|bug)\s*#?\s*(?<number>\d+)|\B#(?<also_number>1?\d{4})|(https?://)github.com/RPCS3/rpcs3/(issues|pull)/(?<another_number>\d+)(#issuecomment-(?<comment_id>\d+))?)\b", DefaultOptions)]
|
||||
internal static partial Regex IssueMention();
|
||||
[GeneratedRegex(@"(?<commit_mention>(https?://)github.com/RPCS3/rpcs3/commit/(?<commit_hash>[0-9a-f]+))\b", DefaultOptions)]
|
||||
internal static partial Regex CommitMention();
|
||||
[GeneratedRegex(@"(?<img_markup>!\[(?<img_caption>[^\]]+)\]\((?<img_link>\w+://[^\)]+)\))", DefaultOptions)]
|
||||
internal static partial Regex ImageMarkup();
|
||||
[GeneratedRegex(@"github.com/RPCS3/rpcs3/issues/(?<number>\d+)", DefaultOptions)]
|
||||
internal static partial Regex IssueLink();
|
||||
|
||||
public static async Task OnMessageCreated(DiscordClient c, MessageCreateEventArgs args)
|
||||
{
|
||||
@@ -72,7 +76,7 @@ internal static class GithubLinksHandler
|
||||
|
||||
public static List<int> GetIssueIds(string input)
|
||||
{
|
||||
return IssueMention.Matches(input)
|
||||
return IssueMention().Matches(input)
|
||||
.SelectMany(match => new[]
|
||||
{
|
||||
match.Groups["number"].Value,
|
||||
@@ -86,13 +90,16 @@ internal static class GithubLinksHandler
|
||||
}
|
||||
public static HashSet<int> GetIssueIdsFromLinks(string input)
|
||||
{
|
||||
return new(
|
||||
IssueLink.Matches(input)
|
||||
return
|
||||
[
|
||||
|
||||
..IssueLink().Matches(input)
|
||||
.Select(match =>
|
||||
{
|
||||
_ = int.TryParse(match.Groups["number"].Value, out var n);
|
||||
return n;
|
||||
})
|
||||
);
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -17,15 +17,15 @@ using DSharpPlus.EventArgs;
|
||||
|
||||
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+)(?<game_title_1>.+?)\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+)(?<game_title_2>.+?)(\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+)(?<game_title_1>.+?)\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+)(?<game_title_2>.+?)(\s+((now|currently|at all|possibly|fully)\s+)?((it?s )?playable|work(s|ing)?|on (it|this))\b|\?|$))"+
|
||||
@"|(^(?<game_title_3>.+?)\s+((is )?(playable|work(s|ing)?))\?)",
|
||||
DefaultOptions
|
||||
);
|
||||
RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture
|
||||
)]
|
||||
private static partial Regex GameNameStatusMention();
|
||||
private static readonly ConcurrentDictionary<ulong, DateTime> CooldownBuckets = new();
|
||||
private static readonly TimeSpan CooldownThreshold = TimeSpan.FromSeconds(5);
|
||||
private static readonly Client Client = new();
|
||||
@@ -48,7 +48,7 @@ internal static class IsTheGamePlayableHandler
|
||||
return;
|
||||
#endif
|
||||
|
||||
var matches = GameNameStatusMention1.Matches(args.Message.Content);
|
||||
var matches = GameNameStatusMention().Matches(args.Message.Content);
|
||||
if (!matches.Any())
|
||||
return;
|
||||
|
||||
@@ -65,7 +65,7 @@ internal static class IsTheGamePlayableHandler
|
||||
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);
|
||||
|
||||
@@ -10,9 +10,10 @@ using DSharpPlus.EventArgs;
|
||||
|
||||
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 @@ internal static class LogAsTextMonitor
|
||||
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 = "";
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace CompatBot.EventHandlers.LogParsing.ArchiveHandlers;
|
||||
|
||||
internal sealed class GzipHandler: IArchiveHandler
|
||||
{
|
||||
private static readonly byte[] Header = { 0x1F, 0x8B, 0x08 };
|
||||
private static readonly byte[] Header = [0x1F, 0x8B, 0x08];
|
||||
|
||||
public long LogSize { get; private set; }
|
||||
public long SourcePosition { get; private set; }
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace CompatBot.EventHandlers.LogParsing.ArchiveHandlers;
|
||||
|
||||
internal sealed class RarHandler: IArchiveHandler
|
||||
{
|
||||
private static readonly byte[] Header = {0x52, 0x61, 0x72, 0x21, 0x1A, 0x07};
|
||||
private static readonly byte[] Header = [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07]; // Rar!..
|
||||
|
||||
public long LogSize { get; private set; }
|
||||
public long SourcePosition { get; private set; }
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace CompatBot.EventHandlers.LogParsing.ArchiveHandlers;
|
||||
|
||||
internal sealed class SevenZipHandler: IArchiveHandler
|
||||
{
|
||||
private static readonly byte[] Header = {0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C};
|
||||
private static readonly byte[] Header = [0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C]; //7z....
|
||||
|
||||
public long LogSize { get; private set; }
|
||||
public long SourcePosition { get; private set; }
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace CompatBot.EventHandlers.LogParsing.ArchiveHandlers;
|
||||
|
||||
internal sealed class ZipHandler: IArchiveHandler
|
||||
{
|
||||
private static readonly byte[] Header = { 0x50, 0x4B, 0x03, 0x04 };
|
||||
private static readonly byte[] Header = [0x50, 0x4B, 0x03, 0x04]; //PK..
|
||||
|
||||
public long LogSize { get; private set; }
|
||||
public long SourcePosition { get; private set; }
|
||||
|
||||
@@ -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
|
||||
*
|
||||
@@ -23,228 +18,232 @@ internal partial class LogParser
|
||||
* If any data was captured, it will be stored in the current collection of items with the key of the explicit capture group of regex
|
||||
*
|
||||
*/
|
||||
private static readonly List<LogSection> LogSections = new()
|
||||
{
|
||||
private static readonly List<LogSection> LogSections =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Extractors = new()
|
||||
{
|
||||
["RPCS3 v"] = new(@"(^|.+\d:\d\d:\d\d\.\d{6})\s*(?<build_and_specs>RPCS3 [^\xC2\xB7]+?)\r?(\n·|$)", DefaultSingleLineOptions),
|
||||
["0:00:00.0"] = new(@"(?<first_unicode_dot>·).+\r?$", DefaultOptions),
|
||||
["Operating system:"] = LogParserResult.OsInfoInLog,
|
||||
["Current Time:"] = new(@"Current Time: (?<log_start_timestamp>.+)\r?$", DefaultOptions),
|
||||
["Installation ID:"] = new(@"Installation ID: (?<hw_id>.+)\r?$", DefaultOptions),
|
||||
["Physical device in"] = new(@"Physical device ini?tialized\. GPU=(?<vulkan_gpu>.+), driver=(?<vulkan_driver_version_raw>-?\d+)\r?$", DefaultOptions),
|
||||
["Found vulkan-compatible GPU:"] = new(@"Found [Vv]ulkan-compatible GPU: (?<vulkan_found_device>'(?<vulkan_compatible_device_name>.+)' running.+)\r?$", DefaultOptions),
|
||||
["Finished reading database from file:"] = new(@"Finished reading database from file: (?<compat_database_path>.*compat_database.dat).*\r?$", DefaultOptions),
|
||||
["Database file not found:"] = new(@"Database file not found: (?<compat_database_path>.*compat_database.dat).*\r?$", DefaultOptions),
|
||||
["Successfully installed PS3 firmware"] = new(@"(?<fw_installed_message>Successfully installed PS3 firmware) version (?<fw_version_installed>\d+\.\d+).*\r?$", DefaultOptions),
|
||||
["Firmware version:"] = new(@"Firmware version: (?<fw_version_installed>\d+\.\d+).*\r?$", DefaultOptions),
|
||||
["Title:"] = new(@"(?:LDR|SYS): Title: (?<game_title>.*)?\r?$", DefaultOptions),
|
||||
["Serial:"] = new(@"Serial: (?<serial>[A-z]{4}\d{5})\r?$", DefaultOptions),
|
||||
["Category:"] = new(@"Category: (?<game_category>.*)?\r?$", DefaultOptions),
|
||||
["LDR: Version:"] = new(@"Version: (?<disc_app_version>\S+) / (?<disc_package_version>\S+).*?\r?$", DefaultOptions),
|
||||
["SYS: Version:"] = new(@"Version: (APP_VER=)?(?<disc_app_version>\S+) (/ |VERSION=)(?<disc_package_version>\S+).*?\r?$", DefaultOptions),
|
||||
["LDR: Cache"] = new(@"Cache: ((?<win_path>\w:/)|(?<lin_path>/[^/])).*?\r?$", DefaultOptions),
|
||||
["SYS: Cache"] = new(@"Cache: ((?<win_path>\w:/)|(?<lin_path>/[^/])).*?\r?$", DefaultOptions),
|
||||
["LDR: Path"] = new(@"Path: ((?<win_path>\w:/)|(?<lin_path>/[^/])).*?\r?$", DefaultOptions),
|
||||
["SYS: Path"] = new(@"Path: ((?<win_path>\w:/)|(?<lin_path>/[^/])).*?\r?$", DefaultOptions),
|
||||
["LDR: Path:"] = new(@"Path: (?<ldr_path_full>.*(?<ldr_path>/dev_hdd0/game/(?<ldr_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions),
|
||||
["SYS: Path:"] = new(@"Path: (?<ldr_path_full>.*(?<ldr_path>/dev_hdd0/game/(?<ldr_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions),
|
||||
["custom config:"] = new(@"custom config: (?<custom_config>.*?)\r?$", DefaultOptions),
|
||||
["patch_log: Failed to load patch file"] = new(@"patch_log: Failed to load patch file (?<patch_error_file>\S*)\r?\n.* line (?<patch_error_line>\d+), column (?<patch_error_column>\d+): (?<patch_error_text>.*?)$", 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:"},
|
||||
EndTrigger = ["Used configuration:"],
|
||||
},
|
||||
|
||||
new()
|
||||
{
|
||||
Extractors = new()
|
||||
{
|
||||
["PPU Decoder:"] = new(@"PPU Decoder: (?<ppu_decoder>.*?)\r?$", DefaultOptions),
|
||||
["PPU Threads:"] = new(@"PPU Threads: (?<ppu_threads>.*?)\r?$", DefaultOptions),
|
||||
["Use LLVM CPU:"] = new("Use LLVM CPU: \\\"?(?<llvm_arch>.*?)\\\"?\r?$", DefaultOptions),
|
||||
["thread scheduler"] = new(@"[Ss]cheduler( Mode)?: (?<thread_scheduler>.*?)\r?$", DefaultOptions),
|
||||
["SPU Decoder:"] = new(@"SPU Decoder: (?<spu_decoder>.*?)\r?$", DefaultOptions),
|
||||
["secondary cores:"] = new(@"secondary cores: (?<spu_secondary_cores>.*?)\r?$", DefaultOptions),
|
||||
//["priority:"] = new(@"priority: (?<spu_lower_thread_priority>.*?)\r?$", DefaultOptions),
|
||||
["SPU Threads:"] = new(@"SPU Threads: (?<spu_threads>.*?)\r?$", DefaultOptions),
|
||||
["SPU delay penalty:"] = new(@"SPU delay penalty: (?<spu_delay_penalty>.*?)\r?$", DefaultOptions),
|
||||
["SPU loop detection:"] = new(@"SPU loop detection: (?<spu_loop_detection>.*?)\r?$", DefaultOptions),
|
||||
["Max SPURS Threads:"] = new(@"Max SPURS Threads: (?<spurs_threads>\d*?)\r?$", DefaultOptions),
|
||||
["SPU Block Size:"] = new(@"SPU Block Size: (?<spu_block_size>.*?)\r?$", DefaultOptions),
|
||||
["Enable TSX:"] = new(@"Enable TSX: (?<enable_tsx>.*?)\r?$", DefaultOptions),
|
||||
["Accurate xfloat:"] = new(@"Accurate xfloat: (?<accurate_xfloat>.*?)\r?$", DefaultOptions),
|
||||
["Approximate xfloat:"] = new(@"Approximate xfloat: (?<approximate_xfloat>.*?)\r?$", DefaultOptions),
|
||||
["Relaxed xfloat:"] = new(@"Relaxed xfloat: (?<relaxed_xfloat>.*?)\r?$", DefaultOptions),
|
||||
["XFloat Accuracy:"] = new(@"XFloat Accuracy: (?<xfloat_mode>.*?)\r?$", DefaultOptions),
|
||||
["Accurate GETLLAR:"] = new(@"Accurate GETLLAR: (?<accurate_getllar>.*?)\r?$", DefaultOptions),
|
||||
["Accurate PUTLLUC:"] = new(@"Accurate PUTLLUC: (?<accurate_putlluc>.*?)\r?$", DefaultOptions),
|
||||
["Accurate RSX reservation access:"] = new(@"Accurate RSX reservation access: (?<accurate_rsx_reservation>.*?)\r?$", DefaultOptions),
|
||||
["RSX FIFO Accuracy:"] = new(@"RSX FIFO Accuracy: (?<rsx_fifo_mode>.*?)\r?$", DefaultOptions),
|
||||
["Debug Console Mode:"] = new(@"Debug Console Mode: (?<debug_console_mode>.*?)\r?$", DefaultOptions),
|
||||
["Lib Loader:"] = new(@"[Ll]oader: (?<lib_loader>.*?)\r?$", DefaultOptions),
|
||||
["Hook static functions:"] = new(@"Hook static functions: (?<hook_static_functions>.*?)\r?$", DefaultOptions),
|
||||
["Load libraries:"] = new(@"libraries:\r?\n(?<library_list>(.*?(- .*?|\[\])\r?\n)+)", DefaultOptions),
|
||||
["Libraries Control:"] = new(@"Libraries Control:\r?\n(?<library_list>(.*?(- .*?|\[\])\r?\n)+)", DefaultOptions),
|
||||
["HLE lwmutex:"] = new(@"HLE lwmutex: (?<hle_lwmutex>.*?)\r?$", DefaultOptions),
|
||||
["Clocks scale:"] = new(@"Clocks scale: (?<clock_scale>.*?)\r?$", DefaultOptions),
|
||||
["Max CPU Preempt Count:"] = new(@"Max CPU Preempt Count: (?<cpu_preempt_count>.*?)\r?$", DefaultOptions),
|
||||
["Sleep Timers Accuracy:"] = new(@"Sleep Timers Accuracy: (?<sleep_timer>.*?)\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:"},
|
||||
EndTrigger = ["VFS:"],
|
||||
},
|
||||
|
||||
new()
|
||||
{
|
||||
Extractors = new()
|
||||
{
|
||||
["Enable /host_root/:"] = new(@"Enable /host_root/: (?<host_root>.*?)\r?$", DefaultOptions),
|
||||
["Enable /host_root/:"] = EnableHostRoot(),
|
||||
},
|
||||
EndTrigger = new[] {"Video:"},
|
||||
EndTrigger = ["Video:"],
|
||||
},
|
||||
|
||||
new()
|
||||
{
|
||||
Extractors = new()
|
||||
{
|
||||
["Renderer:"] = new("Renderer: (?<renderer>.*?)\r?$", DefaultOptions),
|
||||
["Resolution:"] = new("Resolution: (?<resolution>.*?)\r?$", DefaultOptions),
|
||||
["Aspect ratio:"] = new("Aspect ratio: (?<aspect_ratio>.*?)\r?$", DefaultOptions),
|
||||
["Frame limit:"] = new("Frame limit: (?<frame_limit>.*?)\r?$", DefaultOptions),
|
||||
["MSAA:"] = new("MSAA: (?<msaa>.*?)\r?$", DefaultOptions),
|
||||
["Write Color Buffers:"] = new("Write Color Buffers: (?<write_color_buffers>.*?)\r?$", DefaultOptions),
|
||||
["Write Depth Buffer:"] = new("Write Depth Buffer: (?<write_depth_buffer>.*?)\r?$", DefaultOptions),
|
||||
["Read Color Buffers:"] = new("Read Color Buffers: (?<read_color_buffers>.*?)\r?$", DefaultOptions),
|
||||
["Read Depth Buffer:"] = new("Read Depth Buffer: (?<read_depth_buffer>.*?)\r?$", DefaultOptions),
|
||||
["VSync:"] = new("VSync: (?<vsync>.*?)\r?$", DefaultOptions),
|
||||
["GPU texture scaling:"] = new("Use GPU texture scaling: (?<gpu_texture_scaling>.*?)\r?$", DefaultOptions),
|
||||
["Stretch To Display Area:"] = new("Stretch To Display Area: (?<stretch_to_display>.*?)\r?$", DefaultOptions),
|
||||
["Strict Rendering Mode:"] = new("Strict Rendering Mode: (?<strict_rendering_mode>.*?)\r?$", DefaultOptions),
|
||||
["Occlusion Queries:"] = new("Occlusion Queries: (?<zcull>.*?)\r?$", DefaultOptions),
|
||||
["Vertex Cache:"] = new("Disable Vertex Cache: (?<vertex_cache>.*?)\r?$", DefaultOptions),
|
||||
["Frame Skip:"] = new("Enable Frame Skip: (?<frame_skip>.*?)\r?$", DefaultOptions),
|
||||
["Blit:"] = new("Blit: (?<cpu_blit>.*?)\r?$", DefaultOptions),
|
||||
["Disable Asynchronous Shader Compiler:"] = new("Disable Asynchronous Shader Compiler: (?<disable_async_shaders>.*?)\r?$", DefaultOptions),
|
||||
["Shader Mode:"] = new("Shader Mode: (?<shader_mode>.*?)\r?$", DefaultOptions),
|
||||
["Disable native float16 support:"] = new("Disable native float16 support: (?<disable_native_float16>.*?)\r?$", DefaultOptions),
|
||||
["Multithreaded RSX:"] = new("Multithreaded RSX: (?<mtrsx>.*?)\r?$", DefaultOptions),
|
||||
["Relaxed ZCULL Sync:"] = new("Relaxed ZCULL Sync: (?<relaxed_zcull>.*?)\r?$", DefaultOptions),
|
||||
["Resolution Scale:"] = new("Resolution Scale: (?<resolution_scale>.*?)\r?$", DefaultOptions),
|
||||
["Anisotropic Filter"] = new("Anisotropic Filter Override: (?<af_override>.*?)\r?$", DefaultOptions),
|
||||
["Scalable Dimension:"] = new("Minimum Scalable Dimension: (?<texture_scale_threshold>.*?)\r?$", DefaultOptions),
|
||||
["Driver Recovery Timeout:"] = new("Driver Recovery Timeout: (?<driver_recovery_timeout>.*?)\r?$", DefaultOptions),
|
||||
["Driver Wake-Up Delay:"] = new("Driver Wake-Up Delay: (?<driver_wakeup_delay>.*?)\r?$", DefaultOptions),
|
||||
["Vblank Rate:"] = new("Vblank Rate: (?<vblank_rate>.*?)\r?$", DefaultOptions),
|
||||
["12:"] = new(@"(D3D12|DirectX 12):\s*\r?\n\s*Adapter: (?<d3d_gpu>.*?)\r?$", DefaultOptions),
|
||||
["Vulkan:"] = new(@"Vulkan:\s*\r?\n\s*Adapter: (?<vulkan_gpu>.*?)\r?$", DefaultOptions),
|
||||
["Force FIFO present mode:"] = new(@"Force FIFO present mode: (?<force_fifo_present>.*?)\r?$", DefaultOptions),
|
||||
["Asynchronous Texture Streaming"] = new(@"Asynchronous Texture Streaming( 2)?: (?<async_texture_streaming>.*?)\r?$", DefaultOptions),
|
||||
["Asynchronous Queue Scheduler:"] = new(@"Asynchronous Queue Scheduler: (?<async_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:"},
|
||||
EndTrigger = ["Audio:"],
|
||||
},
|
||||
|
||||
new() // Audio, Input/Output, System, Net, Miscellaneous
|
||||
{
|
||||
Extractors = new()
|
||||
{
|
||||
["Renderer:"] = new("Renderer: (?<audio_backend>.*?)\r?$", DefaultOptions),
|
||||
["Downmix to Stereo:"] = new("Downmix to Stereo: (?<audio_stereo>.*?)\r?$", DefaultOptions),
|
||||
["Master Volume:"] = new("Master Volume: (?<audio_volume>.*?)\r?$", DefaultOptions),
|
||||
["Enable Buffering:"] = new("Enable Buffering: (?<audio_buffering>.*?)\r?$", DefaultOptions),
|
||||
["Desired Audio Buffer Duration:"] = new("Desired Audio Buffer Duration: (?<audio_buffer_duration>.*?)\r?$", DefaultOptions),
|
||||
["Enable Time Stretching:"] = new("Enable Time Stretching: (?<audio_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: (?<pad_handler>.*?)\r?$", DefaultOptions),
|
||||
["Pad:"] = GamepadType(),
|
||||
|
||||
["Automatically start games after boot:"] = new("Automatically start games after boot: (?<auto_start_on_boot>.*?)\r?$", DefaultOptions),
|
||||
["Always start after boot:"] = new("Always start after boot: (?<always_start_on_boot>.*?)\r?$", DefaultOptions),
|
||||
["Use native user interface:"] = new("Use native user interface: (?<native_ui>.*?)\r?$", DefaultOptions),
|
||||
["Silence All Logs:"] = new("Silence All Logs: (?<disable_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:"},
|
||||
EndTrigger = ["Log:"],
|
||||
},
|
||||
|
||||
new()
|
||||
{
|
||||
Extractors = new()
|
||||
{
|
||||
["Log:"] = new(@"Log:\s*\r?\n?\s*(\{(?<log_disabled_channels>.*?)\}|(?<log_disabled_channels_multiline>(\s+\w+\:\s*\w+\r?\n)+))\r?$", DefaultOptions),
|
||||
["Log:"] = LogChannelList(),
|
||||
},
|
||||
EndTrigger = new[] {"·"},
|
||||
EndTrigger = ["·"],
|
||||
OnSectionEnd = MarkAsComplete,
|
||||
},
|
||||
|
||||
new()
|
||||
{
|
||||
Extractors = new()
|
||||
{
|
||||
["LDR: Game:"] = new(@"Game: (?<ldr_game_full>.*(?<ldr_game>/dev_hdd0/game/(?<ldr_game_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions),
|
||||
["LDR: Disc"] = new(@"Disc( path)?: (?<ldr_disc_full>.*(?<ldr_disc>/dev_hdd0/game/(?<ldr_disc_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions),
|
||||
["LDR: Path:"] = new(@"Path: (?<ldr_path_full>.*(?<ldr_path>/dev_hdd0/game/(?<ldr_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions),
|
||||
["LDR: Boot path:"] = new(@"Boot path: (?<ldr_boot_path_full>.*(?<ldr_boot_path>/dev_hdd0/game/(?<ldr_boot_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions),
|
||||
["SYS: Game:"] = new(@"Game: (?<ldr_game_full>.*(?<ldr_game>/dev_hdd0/game/(?<ldr_game_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions),
|
||||
["SYS: Path:"] = new(@"Path: (?<ldr_path_full>.*(?<ldr_path>/dev_hdd0/game/(?<ldr_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions),
|
||||
["SYS: Boot path:"] = new(@"Boot path: (?<ldr_boot_path_full>.*(?<ldr_boot_path>/dev_hdd0/game/(?<ldr_boot_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions),
|
||||
["Elf path:"] = new(@"Elf path: (?<host_root_in_boot>/host_root/)?(?<elf_boot_path_full>(?<elf_boot_path>/dev_hdd0/game/(?<elf_boot_path_serial>[^/\r\n]+)/USRDIR/EBOOT\.BIN|.*?))\r?$", DefaultOptions),
|
||||
["VFS: Mounted path \"/dev_bdvd\""] = new(@"Mounted path ""/dev_bdvd"" to ""(?<mounted_dev_bdvd>[^""]+)""", DefaultOptions),
|
||||
["Invalid or unsupported file format:"] = new(@"Invalid or unsupported file format: (?<failed_to_boot>.*?)\r?$", DefaultOptions),
|
||||
["SELF:"] = new(@"(?<failed_to_decrypt>Failed to decrypt)? SELF: (?<failed_to_decrypt>Failed to (decrypt|load SELF))?.*\r?$", DefaultOptions),
|
||||
["SYS: Version:"] = new(@"Version: (APP_VER=)?(?<disc_app_version>\S+) (/ |VERSION=)(?<disc_package_version>\S+).*?\r?$", DefaultOptions),
|
||||
["sceNp: npDrmIsAvailable(): Failed to verify"] = new(@"Failed to verify (?<failed_to_verify_npdrm>(sce|npd)) file.*\r?$", DefaultOptions),
|
||||
["{rsx::thread} RSX: 4"] = new(@"RSX:(\d|\.|\s|\w|-)* (?<driver_version>(\d+\.)*\d+)\r?\n[^\n]*?" +
|
||||
@"RSX: [^\n]+\r?\n[^\n]*?" +
|
||||
@"RSX: (?<driver_manuf>.*?)\r?\n[^\n]*?" +
|
||||
@"RSX: Supported texel buffer size", DefaultOptions),
|
||||
["GL RENDERER:"] = new(@"GL RENDERER: (?<driver_manuf_new>.*?)\r?$", DefaultOptions),
|
||||
["GL VERSION:"] = new(@"GL VERSION: (?<opengl_version>(\d|\.)+)(\d|\.|\s|\w|-)*?( (?<driver_version_new>(\d+\.)*\d+))?\r?$", DefaultOptions),
|
||||
["GLSL VERSION:"] = new(@"GLSL VERSION: (?<glsl_version>(\d|\.)+).*?\r?$", DefaultOptions),
|
||||
["texel buffer size reported:"] = new(@"RSX: Supported texel buffer size reported: (?<texel_buffer_size_new>\d*?) bytes", DefaultOptions),
|
||||
["Physical device in"] = new(@"Physical device ini?tialized\. GPU=(?<vulkan_gpu>.+), driver=(?<vulkan_driver_version_raw>-?\d+)\r?$", DefaultOptions),
|
||||
["Found vulkan-compatible GPU:"] = new(@"Found [Vv]ulkan-compatible GPU: (?<vulkan_found_device>.+)\r?$", DefaultOptions),
|
||||
["Renderer initialized on device"] = new(@"Renderer initialized on device '(?<vulkan_initialized_device>.+)'\r?$", DefaultOptions),
|
||||
["RSX: Failed to compile shader"] = new(@"RSX: Failed to compile shader: ERROR: (?<shader_compile_error>.+?)\r?$", DefaultOptions),
|
||||
["RSX: Compilation failed"] = new(@"RSX: Compilation failed: ERROR: (?<shader_compile_error>.+?)\r?$", DefaultOptions),
|
||||
["RSX: Linkage failed"] = new(@"RSX: Linkage failed: (?<shader_compile_error>.+?)\r?$", DefaultOptions),
|
||||
["RSX: Unsupported device"] = new(@"RSX: Unsupported device: (?<rsx_unsupported_gpu>.+)\..+?\r?$", DefaultOptions),
|
||||
["RSX: Your GPU does not support"] = new(@"RSX: Your GPU does not support (?<rsx_not_supported_feature>.+)\..+?\r?$", DefaultOptions),
|
||||
["RSX: GPU/driver lacks support"] = new(@"RSX: GPU/driver lacks support for (?<rsx_not_supported_feature>.+)\..+?\r?$", DefaultOptions),
|
||||
["RSX: Swapchain:"] = new(@"RSX: Swapchain: present mode (?<rsx_swapchain_mode>\d+?) in use.+?\r?$", DefaultOptions),
|
||||
["F "] = new(@"F \d+:\d+:\d+\.\d+ (({(?<fatal_error_context>[^}]+)} )?(\w+:\s*(Thread terminated due to fatal error: )?|(\w+:\s*)?(class [^\r\n]+ thrown: ))\r?\n?)(?<fatal_error>.*?)(\r?\n)(\r?\n|·|$)", DefaultSingleLineOptions),
|
||||
["Failed to load RAP file:"] = new(@"Failed to load RAP file: (?<rap_file>.*?\.rap).*\r?$", DefaultOptions),
|
||||
["Rap file not found:"] = new(@"Rap file not found: “?(?<rap_file>.*?\.rap)”?\r?$", DefaultOptions),
|
||||
["Pad handler expected but none initialized"] = new(@"(?<native_ui_input>Pad handler expected but none initialized).*?\r?$", DefaultOptions),
|
||||
["Failed to bind device"] = new(@"Failed to bind device (?<failed_pad>.+) to handler (?<failed_pad_handler>.+).*\r?$", DefaultOptions),
|
||||
["Input:"] = new(@"Input: (?<pad_handler>.*?) device .+ connected\r?$", DefaultOptions),
|
||||
["XAudio2Thread"] = new(@"XAudio2Thread\s*: (?<xaudio_init_error>.+failed\s*\((?<xaudio_error_code>0x.+)\).*)\r?$", DefaultOptions),
|
||||
["cellAudio Thread"] = new(@"XAudio2Backend\s*: (?<xaudio_init_error>.+failed\s*\((?<xaudio_error_code>0x.+)\).*)\r?$", DefaultOptions),
|
||||
["using a Null renderer instead"] = new(@"Audio renderer (?<audio_backend_init_error>.+) could not be initialized\r?$", DefaultOptions),
|
||||
["PPU executable hash:"] = new(@"PPU executable hash: PPU-(?<ppu_patch>\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions),
|
||||
["OVL executable hash:"] = new(@"OVL executable hash: OVL-(?<ovl_patch>\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions),
|
||||
["SPU executable hash:"] = new(@"SPU executable hash: SPU-(?<spu_patch>\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions),
|
||||
["PRX library hash:"] = new(@"PRX library hash: PRX-(?<prx_patch>\w+-\d+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions),
|
||||
["OVL hash of"] = new(@"OVL hash of (\w|[\.\[\]])+: OVL-(?<ovl_patch>\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions),
|
||||
["PRX hash of"] = new(@"PRX hash of (\w|[\.\[\]])+: PRX-(?<prx_patch>\w+-\d+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions),
|
||||
[": Applied patch"] = new(@"Applied patch \(hash='(?:\w{3}-\w+(-\d+)?)', description='(?<patch_desc>.+?)', author='(?:.+?)', patch_version='(?:.+?)', file_version='(?:.+?)'\) \(<- (?:[1-9]\d*)\).*\r?$", DefaultOptions),
|
||||
["Loaded SPU image:"] = new(@"Loaded SPU image: SPU-(?<spu_patch>\w+ \(<-\s*\d+\)).*?\r?$", DefaultOptions),
|
||||
["'sys_fs_stat' failed"] = new(@"'sys_fs_stat' failed (?!with 0x8001002c).+“(/dev_bdvd/(?<broken_filename_or_dir>.+)|/dev_hdd0/game/NP\w+/(?<broken_digital_filename>.+))”.*?\r?$", DefaultOptions),
|
||||
["'sys_fs_open' failed"] = new(@"'sys_fs_open' failed (?!with 0x8001002c).+“(/dev_bdvd/(?<broken_filename>.+)|/dev_hdd0/game/NP\w+/(?<broken_digital_filename>.+))”.*?\r?$", DefaultOptions),
|
||||
["'sys_fs_opendir' failed"] = new(@"'sys_fs_opendir' failed .+“/dev_bdvd/(?<broken_directory>.+)”.*?\r?$", DefaultOptions),
|
||||
["EDAT: "] = new(@"EDAT: Block at offset (?<edat_block_offset>0x[0-9a-f]+) has invalid hash!.*?\r?$", DefaultOptions),
|
||||
["PS3 firmware is not installed"] = new(@"(?<fw_missing_msg>PS3 firmware is not installed.+)\r?$", DefaultOptions),
|
||||
["do you have the PS3 firmware installed"] = new(@"(?<fw_missing_something>do you have the PS3 firmware installed.*)\r?$", DefaultOptions),
|
||||
["Unimplemented syscall"] = new(@"U \d+:\d+:\d+\.\d+ ({(?<unimplemented_syscall_context>.+?)} )?.*Unimplemented syscall (?<unimplemented_syscall>.*)\r?$", DefaultOptions),
|
||||
["Could not enqueue"] = new(@"cellAudio: Could not enqueue buffer onto audio backend(?<enqueue_buffer_error>.).*\r?$", DefaultOptions),
|
||||
["{PPU["] = new(@"{PPU\[.+\]} (?<log_channel>[^ :]+)( TODO)?: (?!“)(?<syscall_name>[^ :]+?)\(.*\r?$", DefaultOptions),
|
||||
["Verification failed"] = new(@"Verification failed.+\(e=0x(?<verification_error_hex>[0-9a-f]+)\[(?<verification_error>\d+)\]\)", DefaultOptions),
|
||||
["sys_tty_write():"] = new(@"sys_tty_write\(\)\: “(?<tty_line>.*?)”\r?(\n|$)", DefaultSingleLineOptions),
|
||||
["⁂"] = new(@"⁂ (?<syscall_name>[^ :\[]+?) .*\r?$", DefaultOptions),
|
||||
["undub"] = new(@"(\b|_)(?<game_mod>(undub|translation patch))(\b|_)", DefaultOptions | RegexOptions.IgnoreCase),
|
||||
["Input: Pad"] = new(@"Input: Pad (?<pad_id>\d): device='(?<pad_controller_name>(?!Null).+?)', handler=(?<pad_handler>.+?), VID=.+?\r?$", DefaultOptions),
|
||||
["SDL: Found game controller"] = new(@"Found game controller \d: .+ has_accel=(?<pad_has_accel>.+?), has_gyro=(?<pad_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"},
|
||||
EndTrigger = ["Stopping emulator...", "All threads stopped...", "LDR: Booting from"],
|
||||
}
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> MultiValueItems = new()
|
||||
{
|
||||
private static readonly HashSet<string> MultiValueItems =
|
||||
[
|
||||
"pad_handler",
|
||||
"pad_controller_name",
|
||||
"pad_has_gyro",
|
||||
@@ -268,9 +267,9 @@ internal partial class LogParser
|
||||
"verification_error_hex",
|
||||
"verification_error",
|
||||
"tty_line",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly string[] CountValueItems = {"enqueue_buffer_error"};
|
||||
private static readonly string[] CountValueItems = ["enqueue_buffer_error"];
|
||||
|
||||
private static async Task PiracyCheckAsync(string line, LogParseState state)
|
||||
{
|
||||
@@ -326,7 +325,7 @@ internal partial class LogParser
|
||||
state.WipMultiValueCollection[key] = collection;
|
||||
}
|
||||
}
|
||||
state.WipCollection = new();
|
||||
state.WipCollection = [];
|
||||
state.WipMultiValueCollection = new();
|
||||
Copy(
|
||||
"build_and_specs", "fw_version_installed",
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace CompatBot.EventHandlers.LogParsing;
|
||||
|
||||
internal static partial class LogParser
|
||||
{
|
||||
private static readonly byte[] Bom = {0xEF, 0xBB, 0xBF};
|
||||
private static readonly byte[] Bom = [0xEF, 0xBB, 0xBF];
|
||||
private static readonly PoorMansTaskScheduler<LogParseState> TaskScheduler = new();
|
||||
|
||||
public static async Task<LogParseState> ReadPipeAsync(PipeReader reader, CancellationToken cancellationToken)
|
||||
|
||||
344
CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs
Normal file
344
CompatBot/EventHandlers/LogParsing/LogParser.RegexPatterns.cs
Normal file
@@ -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*(?<build_and_specs>RPCS3 [^\xC2\xB7]+?)\r?(\n·|$)", DefaultSingleLine)]
|
||||
private static partial Regex Rpcs3LogHeader();
|
||||
[GeneratedRegex(@"(?<first_unicode_dot>·).+\r?$", DefaultOptions)]
|
||||
private static partial Regex FirstLineWithDot();
|
||||
[GeneratedRegex(@"Operating system: (?<os_type>[^,]+), (Name: (?<posix_name>[^,]+), Release: (?<posix_release>[^,]+), Version: (?<posix_version>[^\r\n]+)|Major: (?<os_version_major>\d+), Minor: (?<os_version_minor>\d+), Build: (?<os_version_build>\d+), Service Pack: (?<os_service_pack>[^,]+), Compatibility mode: (?<os_compat_mode>[^,\r\n]+)|Version: (?<macos_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: (?<log_start_timestamp>.+)\r?$", DefaultOptions)]
|
||||
private static partial Regex CurrentTime();
|
||||
[GeneratedRegex(@"Installation ID: (?<hw_id>.+)\r?$", DefaultOptions)]
|
||||
private static partial Regex InstallationId();
|
||||
[GeneratedRegex(@"Physical device ini?tialized\. GPU=(?<vulkan_gpu>.+), driver=(?<vulkan_driver_version_raw>-?\d+)\r?$", DefaultOptions)]
|
||||
private static partial Regex PhysicalDeviceName();
|
||||
[GeneratedRegex(@"Found [Vv]ulkan-compatible GPU: (?<vulkan_found_device>'(?<vulkan_compatible_device_name>.+)' running.+)\r?$", DefaultOptions)]
|
||||
private static partial Regex VulkanDeviceName();
|
||||
[GeneratedRegex(@"Finished reading database from file: (?<compat_database_path>.*compat_database.dat).*\r?$", DefaultOptions)]
|
||||
private static partial Regex CompatDbFoundPath();
|
||||
[GeneratedRegex(@"Database file not found: (?<compat_database_path>.*compat_database.dat).*\r?$", DefaultOptions)]
|
||||
private static partial Regex CompatDbNotFoundPath();
|
||||
[GeneratedRegex(@"(?<fw_installed_message>Successfully installed PS3 firmware) version (?<fw_version_installed>\d+\.\d+).*\r?$", DefaultOptions)]
|
||||
private static partial Regex FwInstallMessage();
|
||||
[GeneratedRegex(@"Firmware version: (?<fw_version_installed>\d+\.\d+).*\r?$", DefaultOptions)]
|
||||
private static partial Regex FwVersion();
|
||||
[GeneratedRegex(@"(?:LDR|SYS): Title: (?<game_title>.*)?\r?$", DefaultOptions)]
|
||||
private static partial Regex GameTitle();
|
||||
[GeneratedRegex(@"Serial: (?<serial>[A-z]{4}\d{5})\r?$", DefaultOptions)]
|
||||
private static partial Regex GameSerial();
|
||||
[GeneratedRegex(@"Category: (?<game_category>.*)?\r?$", DefaultOptions)]
|
||||
private static partial Regex GameCategory();
|
||||
[GeneratedRegex(@"Version: (?<disc_app_version>\S+) / (?<disc_package_version>\S+).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex DiscVersionLdr();
|
||||
[GeneratedRegex(@"Version: (APP_VER=)?(?<disc_app_version>\S+) (/ |VERSION=)(?<disc_package_version>\S+).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex DiscVersionSys();
|
||||
[GeneratedRegex(@"Cache: ((?<win_path>\w:/)|(?<lin_path>/[^/])).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex CachePathLdr();
|
||||
[GeneratedRegex(@"Cache: ((?<win_path>\w:/)|(?<lin_path>/[^/])).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex CachePathSys();
|
||||
[GeneratedRegex(@"Path: ((?<win_path>\w:/)|(?<lin_path>/[^/])).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex BootPathLdr();
|
||||
[GeneratedRegex(@"Path: ((?<win_path>\w:/)|(?<lin_path>/[^/])).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex BootPathSys();
|
||||
[GeneratedRegex(@"Path: (?<ldr_path_full>.*(?<ldr_path>/dev_hdd0/game/(?<ldr_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex BootPathDigitalLdr();
|
||||
[GeneratedRegex(@"Path: (?<ldr_path_full>.*(?<ldr_path>/dev_hdd0/game/(?<ldr_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex BootPathDigitalSys();
|
||||
[GeneratedRegex(@"custom config: (?<custom_config>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex CustomConfigPath();
|
||||
[GeneratedRegex(@"patch_log: Failed to load patch file (?<patch_error_file>\S*)\r?\n.* line (?<patch_error_line>\d+), column (?<patch_error_column>\d+): (?<patch_error_text>.*?)$", DefaultOptions)]
|
||||
private static partial Regex FailedPatchPath();
|
||||
|
||||
[GeneratedRegex(@"PPU Decoder: (?<ppu_decoder>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex PpuDecoderType();
|
||||
[GeneratedRegex(@"PPU Threads: (?<ppu_threads>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex PpuThreadCount();
|
||||
[GeneratedRegex("Use LLVM CPU: \\\"?(?<llvm_arch>.*?)\\\"?\r?$", DefaultOptions)]
|
||||
private static partial Regex LlvmCpuArch();
|
||||
[GeneratedRegex(@"[Ss]cheduler( Mode)?: (?<thread_scheduler>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex ThreadSchedulerMode();
|
||||
[GeneratedRegex(@"SPU Decoder: (?<spu_decoder>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SpuDecoderType();
|
||||
[GeneratedRegex(@"secondary cores: (?<spu_secondary_cores>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SecondaryCores();
|
||||
[GeneratedRegex(@"priority: (?<spu_lower_thread_priority>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex LowerThreadPriority();
|
||||
[GeneratedRegex(@"SPU Threads: (?<spu_threads>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SpuThreadCount();
|
||||
[GeneratedRegex(@"SPU delay penalty: (?<spu_delay_penalty>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SpuDelayPenalty();
|
||||
[GeneratedRegex(@"SPU loop detection: (?<spu_loop_detection>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SpuLoopDetection();
|
||||
[GeneratedRegex(@"Max SPURS Threads: (?<spurs_threads>\d*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SpursThreadCount();
|
||||
[GeneratedRegex(@"SPU Block Size: (?<spu_block_size>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SpuBlockSize();
|
||||
[GeneratedRegex(@"Enable TSX: (?<enable_tsx>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex TsxMode();
|
||||
[GeneratedRegex(@"Accurate xfloat: (?<accurate_xfloat>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AccurateXfloat();
|
||||
[GeneratedRegex(@"Approximate xfloat: (?<approximate_xfloat>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex ApproximateXfloat();
|
||||
[GeneratedRegex(@"Relaxed xfloat: (?<relaxed_xfloat>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex RelaxedXfloat();
|
||||
[GeneratedRegex(@"XFloat Accuracy: (?<xfloat_mode>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex XfloatMode();
|
||||
[GeneratedRegex(@"Accurate GETLLAR: (?<accurate_getllar>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex GetLlarMode();
|
||||
[GeneratedRegex(@"Accurate PUTLLUC: (?<accurate_putlluc>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex PutLlucMode();
|
||||
[GeneratedRegex(@"Accurate RSX reservation access: (?<accurate_rsx_reservation>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex RsxReservationAccessMode();
|
||||
[GeneratedRegex(@"RSX FIFO Accuracy: (?<rsx_fifo_mode>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex RsxFifoMode();
|
||||
[GeneratedRegex(@"Debug Console Mode: (?<debug_console_mode>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex DebugConsoleMode();
|
||||
[GeneratedRegex(@"[Ll]oader: (?<lib_loader>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex LibLoaderMode();
|
||||
[GeneratedRegex(@"Hook static functions: (?<hook_static_functions>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex HookStaticFunctions();
|
||||
[GeneratedRegex(@"libraries:\r?\n(?<library_list>(.*?(- .*?|\[\])\r?\n)+)", DefaultOptions)]
|
||||
private static partial Regex LoadLibrariesList();
|
||||
[GeneratedRegex(@"Libraries Control:\r?\n(?<library_list>(.*?(- .*?|\[\])\r?\n)+)", DefaultOptions)]
|
||||
private static partial Regex LibrariesControlList();
|
||||
[GeneratedRegex(@"HLE lwmutex: (?<hle_lwmutex>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex HleLwmutex();
|
||||
[GeneratedRegex(@"Clocks scale: (?<clock_scale>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex ClockScale();
|
||||
[GeneratedRegex(@"Max CPU Preempt Count: (?<cpu_preempt_count>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex CpuPreemptCount();
|
||||
[GeneratedRegex(@"Sleep Timers Accuracy: (?<sleep_timer>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SleepTimersMode();
|
||||
|
||||
[GeneratedRegex(@"Enable /host_root/: (?<host_root>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex EnableHostRoot();
|
||||
|
||||
[GeneratedRegex("Renderer: (?<renderer>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex RendererBackend();
|
||||
[GeneratedRegex("Resolution: (?<resolution>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex ResolutionMode();
|
||||
[GeneratedRegex("Aspect ratio: (?<aspect_ratio>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AspectRatioMode();
|
||||
[GeneratedRegex("Frame limit: (?<frame_limit>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex FrameLimit();
|
||||
[GeneratedRegex("MSAA: (?<msaa>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex MsaaMode();
|
||||
[GeneratedRegex("Write Color Buffers: (?<write_color_buffers>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex Wcb();
|
||||
[GeneratedRegex("Write Depth Buffer: (?<write_depth_buffer>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex Wdb();
|
||||
[GeneratedRegex("Read Color Buffers: (?<read_color_buffers>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex Rcb();
|
||||
[GeneratedRegex("Read Depth Buffer: (?<read_depth_buffer>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex Rdb();
|
||||
[GeneratedRegex("VSync: (?<vsync>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex VsyncMode();
|
||||
[GeneratedRegex("Use GPU texture scaling: (?<gpu_texture_scaling>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex GpuTextureScaling();
|
||||
[GeneratedRegex("Stretch To Display Area: (?<stretch_to_display>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex StretchToDisplay();
|
||||
[GeneratedRegex("Strict Rendering Mode: (?<strict_rendering_mode>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex StrictRendering();
|
||||
[GeneratedRegex("Occlusion Queries: (?<zcull>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex OcclusionQueriesMode();
|
||||
[GeneratedRegex("Disable Vertex Cache: (?<vertex_cache>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex VertexCache();
|
||||
[GeneratedRegex("Enable Frame Skip: (?<frame_skip>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex FrameSkip();
|
||||
[GeneratedRegex("Blit: (?<cpu_blit>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex BlitMode();
|
||||
[GeneratedRegex("Disable Asynchronous Shader Compiler: (?<disable_async_shaders>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex DisableAsyncShaders();
|
||||
[GeneratedRegex("Shader Mode: (?<shader_mode>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex ShaderMode();
|
||||
[GeneratedRegex("Disable native float16 support: (?<disable_native_float16>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex DisableNativeF16();
|
||||
[GeneratedRegex("Multithreaded RSX: (?<mtrsx>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex RsxMultithreadMode();
|
||||
[GeneratedRegex("Relaxed ZCULL Sync: (?<relaxed_zcull>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex RelaxedZcull();
|
||||
[GeneratedRegex("Resolution Scale: (?<resolution_scale>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex ResolutionScaling();
|
||||
[GeneratedRegex("Anisotropic Filter Override: (?<af_override>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AnisoFilter();
|
||||
[GeneratedRegex("Minimum Scalable Dimension: (?<texture_scale_threshold>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex ScalableDimensions();
|
||||
[GeneratedRegex("Driver Recovery Timeout: (?<driver_recovery_timeout>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex DriverRecoveryTimeout();
|
||||
[GeneratedRegex("Driver Wake-Up Delay: (?<driver_wakeup_delay>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex DriverWakeupDelay();
|
||||
[GeneratedRegex("Vblank Rate: (?<vblank_rate>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex VblankRate();
|
||||
[GeneratedRegex(@"(D3D12|DirectX 12):\s*\r?\n\s*Adapter: (?<d3d_gpu>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SelectedD3d12Device();
|
||||
[GeneratedRegex(@"Vulkan:\s*\r?\n\s*Adapter: (?<vulkan_gpu>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SelectedVulkanDevice();
|
||||
[GeneratedRegex(@"Force FIFO present mode: (?<force_fifo_present>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex FifoPresentMode();
|
||||
[GeneratedRegex(@"Asynchronous Texture Streaming( 2)?: (?<async_texture_streaming>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AsyncTextureStreaming();
|
||||
[GeneratedRegex(@"Asynchronous Queue Scheduler: (?<async_queue_scheduler>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AsyncQueueScheduler();
|
||||
|
||||
[GeneratedRegex("Renderer: (?<audio_backend>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AudioBackend();
|
||||
[GeneratedRegex("Downmix to Stereo: (?<audio_stereo>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex DownmixToStereo();
|
||||
[GeneratedRegex("Master Volume: (?<audio_volume>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex MasterVolume();
|
||||
[GeneratedRegex("Enable Buffering: (?<audio_buffering>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AudioBuffering();
|
||||
[GeneratedRegex("Desired Audio Buffer Duration: (?<audio_buffer_duration>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AudioBufferLength();
|
||||
[GeneratedRegex("Enable Time Stretching: (?<audio_stretching>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AudioTimeStretching();
|
||||
[GeneratedRegex("Pad: (?<pad_handler>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex GamepadType();
|
||||
[GeneratedRegex("Automatically start games after boot: (?<auto_start_on_boot>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AutoStartAfterBoot();
|
||||
[GeneratedRegex("Always start after boot: (?<always_start_on_boot>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex AlwaysStartAfterBoot();
|
||||
[GeneratedRegex("Use native user interface: (?<native_ui>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex NativeUIMode();
|
||||
[GeneratedRegex("Silence All Logs: (?<disable_logs>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SilenceAllLogs();
|
||||
|
||||
[GeneratedRegex(@"Log:\s*\r?\n?\s*(\{(?<log_disabled_channels>.*?)\}|(?<log_disabled_channels_multiline>(\s+\w+\:\s*\w+\r?\n)+))\r?$", DefaultOptions)]
|
||||
private static partial Regex LogChannelList();
|
||||
|
||||
[GeneratedRegex(@"Game: (?<ldr_game_full>.*(?<ldr_game>/dev_hdd0/game/(?<ldr_game_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex GamePathLdr();
|
||||
[GeneratedRegex(@"Disc( path)?: (?<ldr_disc_full>.*(?<ldr_disc>/dev_hdd0/game/(?<ldr_disc_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex DiscPathLdr();
|
||||
[GeneratedRegex(@"Path: (?<ldr_path_full>.*(?<ldr_path>/dev_hdd0/game/(?<ldr_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex DigitalPathLdr();
|
||||
[GeneratedRegex(@"Boot path: (?<ldr_boot_path_full>.*(?<ldr_boot_path>/dev_hdd0/game/(?<ldr_boot_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex BootPathInBodyLdr();
|
||||
[GeneratedRegex(@"Game: (?<ldr_game_full>.*(?<ldr_game>/dev_hdd0/game/(?<ldr_game_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex GamePathSys();
|
||||
[GeneratedRegex(@"Path: (?<ldr_path_full>.*(?<ldr_path>/dev_hdd0/game/(?<ldr_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex DigitalPathSys();
|
||||
[GeneratedRegex(@"Boot path: (?<ldr_boot_path_full>.*(?<ldr_boot_path>/dev_hdd0/game/(?<ldr_boot_path_serial>[^/\r\n]+)).*|.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex BootPathInBodySys();
|
||||
[GeneratedRegex(@"Elf path: (?<host_root_in_boot>/host_root/)?(?<elf_boot_path_full>(?<elf_boot_path>/dev_hdd0/game/(?<elf_boot_path_serial>[^/\r\n]+)/USRDIR/EBOOT\.BIN|.*?))\r?$", DefaultOptions)]
|
||||
private static partial Regex ElfPath();
|
||||
[GeneratedRegex(@"Mounted path ""/dev_bdvd"" to ""(?<mounted_dev_bdvd>[^""]+)""", DefaultOptions)]
|
||||
private static partial Regex VfsMountPath();
|
||||
[GeneratedRegex(@"Invalid or unsupported file format: (?<failed_to_boot>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex InvalidFileFormat();
|
||||
[GeneratedRegex(@"(?<failed_to_decrypt>Failed to decrypt)? SELF: (?<failed_to_decrypt>Failed to (decrypt|load SELF))?.*\r?$", DefaultOptions)]
|
||||
private static partial Regex DecryptFailedSelfPath();
|
||||
[GeneratedRegex(@"Version: (APP_VER=)?(?<disc_app_version>\S+) (/ |VERSION=)(?<disc_package_version>\S+).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex GameVersion();
|
||||
[GeneratedRegex(@"Failed to verify (?<failed_to_verify_npdrm>(sce|npd)) file.*\r?$", DefaultOptions)]
|
||||
private static partial Regex FailedToVerifyNpDrm();
|
||||
[GeneratedRegex(
|
||||
@"RSX:(\d|\.|\s|\w|-)* (?<driver_version>(\d+\.)*\d+)\r?\n[^\n]*?"+
|
||||
@"RSX: [^\n]+\r?\n[^\n]*?RSX: (?<driver_manuf>.*?)\r?\n[^\n]*?"+
|
||||
@"RSX: Supported texel buffer size",
|
||||
DefaultOptions
|
||||
)]
|
||||
private static partial Regex RsxDriverInfoLegacy();
|
||||
[GeneratedRegex(@"GL RENDERER: (?<driver_manuf_new>.*?)\r?$", DefaultOptions)]
|
||||
private static partial Regex GlRenderer();
|
||||
[GeneratedRegex(@"GL VERSION: (?<opengl_version>(\d|\.)+)(\d|\.|\s|\w|-)*?( (?<driver_version_new>(\d+\.)*\d+))?\r?$", DefaultOptions)]
|
||||
private static partial Regex GlVersion();
|
||||
[GeneratedRegex(@"GLSL VERSION: (?<glsl_version>(\d|\.)+).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex GlslVersion();
|
||||
[GeneratedRegex(@"RSX: Supported texel buffer size reported: (?<texel_buffer_size_new>\d*?) bytes", DefaultOptions)]
|
||||
private static partial Regex GlTexelBufferSize();
|
||||
[GeneratedRegex(@"Physical device ini?tialized\. GPU=(?<vulkan_gpu>.+), driver=(?<vulkan_driver_version_raw>-?\d+)\r?$", DefaultOptions)]
|
||||
private static partial Regex PhysicalDeviceFound();
|
||||
[GeneratedRegex(@"Found [Vv]ulkan-compatible GPU: (?<vulkan_found_device>.+)\r?$", DefaultOptions)]
|
||||
private static partial Regex VulkanDeviceFound();
|
||||
[GeneratedRegex(@"Renderer initialized on device '(?<vulkan_initialized_device>.+)'\r?$", DefaultOptions)]
|
||||
private static partial Regex RenderDeviceInitialized();
|
||||
[GeneratedRegex(@"RSX: Failed to compile shader: ERROR: (?<shader_compile_error>.+?)\r?$", DefaultOptions)]
|
||||
private static partial Regex FailedToCompileShader();
|
||||
[GeneratedRegex(@"RSX: Compilation failed: ERROR: (?<shader_compile_error>.+?)\r?$", DefaultOptions)]
|
||||
private static partial Regex ShaderCompilationFailed();
|
||||
[GeneratedRegex(@"RSX: Linkage failed: (?<shader_compile_error>.+?)\r?$", DefaultOptions)]
|
||||
private static partial Regex ShaderLinkageFailed();
|
||||
[GeneratedRegex(@"RSX: Unsupported device: (?<rsx_unsupported_gpu>.+)\..+?\r?$", DefaultOptions)]
|
||||
private static partial Regex UnsupportedDevice();
|
||||
[GeneratedRegex(@"RSX: Your GPU does not support (?<rsx_not_supported_feature>.+)\..+?\r?$", DefaultOptions)]
|
||||
private static partial Regex UnsupportedDeviceFeatures();
|
||||
[GeneratedRegex(@"RSX: GPU/driver lacks support for (?<rsx_not_supported_feature>.+)\..+?\r?$", DefaultOptions)]
|
||||
private static partial Regex UnsupportedDriverFeatures();
|
||||
[GeneratedRegex(@"RSX: Swapchain: present mode (?<rsx_swapchain_mode>\d+?) in use.+?\r?$", DefaultOptions)]
|
||||
private static partial Regex SwapchainMode();
|
||||
[GeneratedRegex(@"F \d+:\d+:\d+\.\d+ (({(?<fatal_error_context>[^}]+)} )?(\w+:\s*(Thread terminated due to fatal error: )?|(\w+:\s*)?(class [^\r\n]+ thrown: ))\r?\n?)(?<fatal_error>.*?)(\r?\n)(\r?\n|·|$)", DefaultSingleLine)]
|
||||
private static partial Regex FatalError();
|
||||
[GeneratedRegex(@"Failed to load RAP file: (?<rap_file>.*?\.rap).*\r?$", DefaultOptions)]
|
||||
private static partial Regex FailedToLoadRap();
|
||||
[GeneratedRegex(@"Rap file not found: “?(?<rap_file>.*?\.rap)”?\r?$", DefaultOptions)]
|
||||
private static partial Regex RapNotFound();
|
||||
[GeneratedRegex(@"(?<native_ui_input>Pad handler expected but none initialized).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex MissingGamepad();
|
||||
[GeneratedRegex(@"Failed to bind device (?<failed_pad>.+) to handler (?<failed_pad_handler>.+).*\r?$", DefaultOptions)]
|
||||
private static partial Regex FailedToBindGamepad();
|
||||
[GeneratedRegex(@"Input: (?<pad_handler>.*?) device .+ connected\r?$", DefaultOptions)]
|
||||
private static partial Regex InputDeviceConnected();
|
||||
[GeneratedRegex(@"XAudio2Thread\s*: (?<xaudio_init_error>.+failed\s*\((?<xaudio_error_code>0x.+)\).*)\r?$", DefaultOptions)]
|
||||
private static partial Regex XAudio2Thread();
|
||||
[GeneratedRegex(@"XAudio2Backend\s*: (?<xaudio_init_error>.+failed\s*\((?<xaudio_error_code>0x.+)\).*)\r?$", DefaultOptions)]
|
||||
private static partial Regex CellAudioThread();
|
||||
[GeneratedRegex(@"Audio renderer (?<audio_backend_init_error>.+) could not be initialized\r?$", DefaultOptions)]
|
||||
private static partial Regex AudioBackendFailed();
|
||||
[GeneratedRegex(@"PPU executable hash: PPU-(?<ppu_patch>\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex PpuHash();
|
||||
[GeneratedRegex(@"OVL executable hash: OVL-(?<ovl_patch>\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex OvlHash();
|
||||
[GeneratedRegex(@"SPU executable hash: SPU-(?<spu_patch>\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex SpuHash();
|
||||
[GeneratedRegex(@"PRX library hash: PRX-(?<prx_patch>\w+-\d+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex PrxHash();
|
||||
[GeneratedRegex(@"OVL hash of (\w|[\.\[\]])+: OVL-(?<ovl_patch>\w+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex OvlHash2();
|
||||
[GeneratedRegex(@"PRX hash of (\w|[\.\[\]])+: PRX-(?<prx_patch>\w+-\d+( \(<-\s*\d+\))?).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex PrxHash2();
|
||||
[GeneratedRegex(@"Applied patch \(hash='(?:\w{3}-\w+(-\d+)?)', description='(?<patch_desc>.+?)', author='(?:.+?)', patch_version='(?:.+?)', file_version='(?:.+?)'\) \(<- (?:[1-9]\d*)\).*\r?$", DefaultOptions)]
|
||||
private static partial Regex AppliedPatch();
|
||||
[GeneratedRegex(@"Loaded SPU image: SPU-(?<spu_patch>\w+ \(<-\s*\d+\)).*?\r?$", DefaultOptions)]
|
||||
private static partial Regex SpuImageLoad();
|
||||
[GeneratedRegex(@"'sys_fs_stat' failed (?!with 0x8001002c).+“(/dev_bdvd/(?<broken_filename_or_dir>.+)|/dev_hdd0/game/NP\w+/(?<broken_digital_filename>.+))”.*?\r?$", DefaultOptions)]
|
||||
private static partial Regex SysFsStatFailed();
|
||||
[GeneratedRegex(@"'sys_fs_open' failed (?!with 0x8001002c).+“(/dev_bdvd/(?<broken_filename>.+)|/dev_hdd0/game/NP\w+/(?<broken_digital_filename>.+))”.*?\r?$", DefaultOptions)]
|
||||
private static partial Regex SysFsOpenFailed();
|
||||
[GeneratedRegex(@"'sys_fs_opendir' failed .+“/dev_bdvd/(?<broken_directory>.+)”.*?\r?$", DefaultOptions)]
|
||||
private static partial Regex SysFsOpenDirFailed();
|
||||
[GeneratedRegex(@"EDAT: Block at offset (?<edat_block_offset>0x[0-9a-f]+) has invalid hash!.*?\r?$", DefaultOptions)]
|
||||
private static partial Regex InvalidEdat();
|
||||
[GeneratedRegex(@"(?<fw_missing_msg>PS3 firmware is not installed.+)\r?$", DefaultOptions)]
|
||||
private static partial Regex FwNotInstalled();
|
||||
[GeneratedRegex(@"(?<fw_missing_something>do you have the PS3 firmware installed.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex FwNotInstalled2();
|
||||
[GeneratedRegex(@"U \d+:\d+:\d+\.\d+ ({(?<unimplemented_syscall_context>.+?)} )?.*Unimplemented syscall (?<unimplemented_syscall>.*)\r?$", DefaultOptions)]
|
||||
private static partial Regex UnimplementedSyscall();
|
||||
[GeneratedRegex(@"cellAudio: Could not enqueue buffer onto audio backend(?<enqueue_buffer_error>.).*\r?$", DefaultOptions)]
|
||||
private static partial Regex CellAudioEnqueueFailed();
|
||||
[GeneratedRegex(@"{PPU\[.+\]} (?<log_channel>[^ :]+)( TODO)?: (?!“)(?<syscall_name>[^ :]+?)\(.*\r?$", DefaultOptions)]
|
||||
private static partial Regex PpuSyscallTodo();
|
||||
[GeneratedRegex(@"Verification failed.+\(e=0x(?<verification_error_hex>[0-9a-f]+)\[(?<verification_error>\d+)\]\)", DefaultOptions)]
|
||||
private static partial Regex VerificationFailed();
|
||||
[GeneratedRegex(@"sys_tty_write\(\)\: “(?<tty_line>.*?)”\r?(\n|$)", DefaultSingleLine)]
|
||||
private static partial Regex SysTtyWrite();
|
||||
[GeneratedRegex(@"⁂ (?<syscall_name>[^ :\[]+?) .*\r?$", DefaultOptions)]
|
||||
private static partial Regex SyscallDump();
|
||||
[GeneratedRegex(@"(\b|_)(?<game_mod>(undub|translation patch))(\b|_)", RegexOptions.IgnoreCase | DefaultOptions)]
|
||||
private static partial Regex UndubFlag();
|
||||
[GeneratedRegex(@"Input: Pad (?<pad_id>\d): device='(?<pad_controller_name>(?!Null).+?)', handler=(?<pad_handler>.+?), VID=.+?\r?$", DefaultOptions)]
|
||||
private static partial Regex InputDeviceGamepad();
|
||||
[GeneratedRegex(@"Found game controller \d: .+ has_accel=(?<pad_has_accel>.+?), has_gyro=(?<pad_has_gyro>.+?)\r?$", DefaultOptions)]
|
||||
private static partial Regex SdlControllerName();
|
||||
}
|
||||
@@ -13,17 +13,18 @@ using CompatApiClient.Utils;
|
||||
|
||||
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(@"(?<dropbox_link>(https?://)?(www\.)?dropbox\.com/s/(?<dropbox_id>[^/\s]+)/(?<filename>[^/\?\s])(/dl=[01])?)", DefaultOptions);
|
||||
[GeneratedRegex(@"(?<dropbox_link>(https?://)?(www\.)?dropbox\.com/s/(?<dropbox_id>[^/\s]+)/(?<filename>[^/\?\s])(/dl=[01])?)", DefaultOptions)]
|
||||
private static partial Regex ExternalLink();
|
||||
|
||||
public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection<IArchiveHandler> 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);
|
||||
|
||||
|
||||
@@ -12,16 +12,17 @@ using System.Threading;
|
||||
|
||||
namespace CompatBot.EventHandlers.LogParsing.SourceHandlers;
|
||||
|
||||
internal sealed class GenericLinkHandler : BaseSourceHandler
|
||||
internal sealed partial class GenericLinkHandler : BaseSourceHandler
|
||||
{
|
||||
private static readonly Regex ExternalLink = new(@"(?<link>(https?://)?(github\.com/RPCS3/rpcs3|cdn\.discordapp\.com/attachments)/.*/(?<filename>[^/\?\s]+\.(gz|zip|rar|7z|log)))", DefaultOptions);
|
||||
[GeneratedRegex(@"(?<link>(https?://)?(github\.com/RPCS3/rpcs3|cdn\.discordapp\.com/attachments)/.*/(?<filename>[^/\?\s]+\.(gz|zip|rar|7z|log)))", DefaultOptions)]
|
||||
private static partial Regex ExternalLink();
|
||||
|
||||
public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection<IArchiveHandler> 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);
|
||||
|
||||
|
||||
@@ -16,10 +16,11 @@ using FileMeta = Google.Apis.Drive.v3.Data.File;
|
||||
|
||||
namespace CompatBot.EventHandlers.LogParsing.SourceHandlers;
|
||||
|
||||
internal sealed class GoogleDriveHandler: BaseSourceHandler
|
||||
internal sealed partial class GoogleDriveHandler: BaseSourceHandler
|
||||
{
|
||||
private static readonly Regex ExternalLink = new(@"(?<gdrive_link>(https?://)?drive\.google\.com/(open\?id=|file/d/)(?<gdrive_id>[^/>\s]+))", DefaultOptions);
|
||||
private static readonly string[] Scopes = { DriveService.Scope.DriveReadonly };
|
||||
[GeneratedRegex(@"(?<gdrive_link>(https?://)?drive\.google\.com/(open\?id=|file/d/)(?<gdrive_id>[^/>\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";
|
||||
|
||||
public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection<IArchiveHandler> handlers)
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -13,10 +13,11 @@ using MediafireClient;
|
||||
|
||||
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(@"(?<mediafire_link>(https?://)?(www\.)?mediafire\.com/file/(?<quick_key>[^/\s]+)/(?<filename>[^/\?\s]+)(/file)?)", DefaultOptions);
|
||||
[GeneratedRegex(@"(?<mediafire_link>(https?://)?(www\.)?mediafire\.com/file/(?<quick_key>[^/\s]+)/(?<filename>[^/\?\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<IArchiveHandler> 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);
|
||||
|
||||
|
||||
@@ -11,11 +11,12 @@ using System.Threading;
|
||||
|
||||
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(@"(?<mega_link>(https?://)?mega(\.co)?\.nz/(#(?<mega_id>[^/>\s]+)|file/(?<new_mega_id>[^/>\s]+)))", DefaultOptions);
|
||||
[GeneratedRegex(@"(?<mega_link>(https?://)?mega(\.co)?\.nz/(#(?<mega_id>[^/>\s]+)|file/(?<new_mega_id>[^/>\s]+)))", DefaultOptions)]
|
||||
private static partial Regex ExternalLink();
|
||||
private static readonly IProgress<double> Doodad = new Progress<double>(_ => { });
|
||||
|
||||
public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection<IArchiveHandler> 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);
|
||||
|
||||
|
||||
@@ -13,9 +13,10 @@ using OneDriveClient.POCOs;
|
||||
|
||||
namespace CompatBot.EventHandlers.LogParsing.SourceHandlers;
|
||||
|
||||
internal sealed class OneDriveSourceHandler : BaseSourceHandler
|
||||
internal sealed partial class OneDriveSourceHandler : BaseSourceHandler
|
||||
{
|
||||
private static readonly Regex ExternalLink = new(@"(?<onedrive_link>(https?://)?(1drv\.ms|onedrive\.live\.com)/[^>\s]+)", DefaultOptions);
|
||||
[GeneratedRegex(@"(?<onedrive_link>(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<IArchiveHandler> 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);
|
||||
|
||||
|
||||
@@ -11,16 +11,17 @@ using System.Threading;
|
||||
|
||||
namespace CompatBot.EventHandlers.LogParsing.SourceHandlers;
|
||||
|
||||
internal sealed class PastebinHandler : BaseSourceHandler
|
||||
internal sealed partial class PastebinHandler : BaseSourceHandler
|
||||
{
|
||||
private static readonly Regex ExternalLink = new(@"(?<pastebin_link>(https?://)pastebin.com/(raw/)?(?<pastebin_id>[^/>\s]+))", DefaultOptions);
|
||||
[GeneratedRegex(@"(?<pastebin_link>(https?://)pastebin.com/(raw/)?(?<pastebin_id>[^/>\s]+))", DefaultOptions)]
|
||||
private static partial Regex ExternalLink();
|
||||
|
||||
public override async Task<(ISource? source, string? failReason)> FindHandlerAsync(DiscordMessage message, ICollection<IArchiveHandler> 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);
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@ using YandexDiskClient;
|
||||
|
||||
namespace CompatBot.EventHandlers.LogParsing.SourceHandlers;
|
||||
|
||||
internal sealed class YandexDiskHandler: BaseSourceHandler
|
||||
internal sealed partial class YandexDiskHandler: BaseSourceHandler
|
||||
{
|
||||
private static readonly Regex ExternalLink = new(@"(?<yadisk_link>(https?://)?(www\.)?yadi\.sk/d/(?<share_key>[^/>\s]+))\b", DefaultOptions);
|
||||
[GeneratedRegex(@"(?<yadisk_link>(https?://)?(www\.)?yadi\.sk/d/(?<share_key>[^/>\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<IArchiveHandler> 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);
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace CompatBot.EventHandlers;
|
||||
|
||||
public static class LogParsingHandler
|
||||
{
|
||||
private static readonly char[] LinkSeparator = { ' ', '>', '\r', '\n' };
|
||||
private static readonly char[] LinkSeparator = [' ', '>', '\r', '\n'];
|
||||
private static readonly ISourceHandler[] SourceHandlers =
|
||||
{
|
||||
[
|
||||
new DiscordAttachmentHandler(),
|
||||
new GoogleDriveHandler(),
|
||||
new DropboxHandler(),
|
||||
@@ -39,15 +39,15 @@ public static class LogParsingHandler
|
||||
new MediafireHandler(),
|
||||
new GenericLinkHandler(),
|
||||
new PastebinHandler(),
|
||||
};
|
||||
];
|
||||
private static readonly IArchiveHandler[] ArchiveHandlers =
|
||||
{
|
||||
[
|
||||
new GzipHandler(),
|
||||
new ZipHandler(),
|
||||
new RarHandler(),
|
||||
new SevenZipHandler(),
|
||||
new PlainTextHandler(),
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly SemaphoreSlim QueueLimiter = new(Math.Max(1, Environment.ProcessorCount / 2), Math.Max(1, Environment.ProcessorCount / 2));
|
||||
private delegate void OnLog(DiscordClient client, DiscordChannel channel, DiscordMessage message, DiscordMember? requester = null, bool checkExternalLinks = false, bool force = false);
|
||||
|
||||
@@ -11,9 +11,10 @@ using DSharpPlus.EventArgs;
|
||||
|
||||
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 @@ internal static class NewBuildsMonitor
|
||||
&& !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");
|
||||
|
||||
@@ -12,10 +12,13 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
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((?<vulkan>(vul[ck][ae]n(-?1)?))|(?<help>(post|upload|send|give)(ing)?\s+((a|the|rpcs3('s)?|your|you're|ur|my|full|game)\s+)*\blogs?))\b", DefaultOptions);
|
||||
[GeneratedRegex(
|
||||
@"\b((?<vulkan>(vul[ck][ae]n(-?1)?))|(?<help>(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<string, Explanation> DefaultExplanation = new()
|
||||
@@ -36,7 +39,7 @@ internal static class PostLogHelpHandler
|
||||
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;
|
||||
|
||||
|
||||
@@ -16,10 +16,11 @@ using DSharpPlus.EventArgs;
|
||||
|
||||
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(@"(?<letters>(?:[BPSUVX][CL]|P[ETU]|NP)[AEHJKPUIX][ABDJKLMPQRSTX]|MRTC)[ \-]?(?<numbers>\d{5})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
[GeneratedRegex(@"(?<letters>(?:[BPSUVX][CL]|P[ETU]|NP)[AEHJKPUIX][ABDJKLMPQRSTX]|MRTC)[ \-]?(?<numbers>\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 @@ internal static class ProductCodeLookup
|
||||
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();
|
||||
|
||||
@@ -12,9 +12,11 @@ using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace CompatBot.EventHandlers;
|
||||
|
||||
internal static class TableFlipMonitor
|
||||
internal static partial class TableFlipMonitor
|
||||
{
|
||||
private static readonly char[] OpenParen = {'(', '(', 'ʕ'};
|
||||
[GeneratedRegex(@"(🎲|\s)+")]
|
||||
private static partial Regex DiceRoll();
|
||||
private static readonly char[] OpenParen = ['(', '(', 'ʕ'];
|
||||
|
||||
public static async Task OnMessageCreated(DiscordClient _, MessageCreateEventArgs args)
|
||||
{
|
||||
@@ -38,8 +40,7 @@ internal static class TableFlipMonitor
|
||||
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("🎲");
|
||||
|
||||
@@ -13,12 +13,13 @@ using DSharpPlus.Interactivity.Extensions;
|
||||
|
||||
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 @@ internal static class UnknownCommandHandler
|
||||
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(
|
||||
|
||||
@@ -15,10 +15,10 @@ namespace CompatBot.EventHandlers;
|
||||
|
||||
public static class UsernameZalgoMonitor
|
||||
{
|
||||
private static readonly HashSet<char> OversizedChars = new()
|
||||
{
|
||||
private static readonly HashSet<char> OversizedChars =
|
||||
[
|
||||
'꧁', '꧂', '⎝', '⎠', '⧹', '⧸', '⎛', '⎞', '﷽', '⸻', 'ဪ', '꧅', '꧄', '˞',
|
||||
};
|
||||
];
|
||||
|
||||
public static async Task OnUserUpdated(DiscordClient c, UserUpdateEventArgs args)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CompatBot.Commands;
|
||||
@@ -38,6 +39,9 @@ internal static class Program
|
||||
{
|
||||
Config.TelemetryClient?.TrackEvent("startup");
|
||||
|
||||
//AppDomain.CurrentDomain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT", TimeSpan.FromMilliseconds(100));
|
||||
Regex.CacheSize = 200; // default is 15, we need more for content filter
|
||||
|
||||
Console.WriteLine("Confinement: " + SandboxDetector.Detect());
|
||||
if (args.Length > 0 && args[0] == "--dry-run")
|
||||
{
|
||||
|
||||
@@ -16,14 +16,15 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
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(
|
||||
@"(?<cover_link>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<string> PreferredOrder = new List<string>{"coverHQ", "coverM", "cover"};
|
||||
|
||||
public static async Task RunAsync(CancellationToken cancellationToken)
|
||||
@@ -50,7 +51,7 @@ internal static class GameTdbScraper
|
||||
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 @@ internal static class GameTdbScraper
|
||||
continue;
|
||||
|
||||
var productId = (await xmlReader.ReadElementContentAsStringAsync().ConfigureAwait(false)).ToUpperInvariant();
|
||||
if (!ProductCodeLookup.ProductCode.IsMatch(productId))
|
||||
if (!ProductCodeLookup.Pattern().IsMatch(productId))
|
||||
continue;
|
||||
|
||||
string? title = null;
|
||||
|
||||
@@ -14,15 +14,17 @@ using PsnClient.Utils;
|
||||
|
||||
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(
|
||||
|
||||
[GeneratedRegex(
|
||||
@"(?<content_id>(?<service_id>(?<service_letters>\w\w)(?<service_number>\d{4}))-(?<product_id>(?<product_letters>\w{4})(?<product_number>\d{5}))_(?<part>\d\d)-(?<label>\w{16}))",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture
|
||||
);
|
||||
RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture
|
||||
)]
|
||||
public static partial Regex ContentIdMatcher();
|
||||
private static readonly SemaphoreSlim LockObj = new(1, 1);
|
||||
private static List<string> psnStores = new();
|
||||
private static List<string> psnStores = [];
|
||||
private static DateTime storeRefreshTimestamp = DateTime.MinValue;
|
||||
private static readonly SemaphoreSlim QueueLimiter = new(32, 32);
|
||||
|
||||
@@ -52,7 +54,7 @@ internal sealed class PsnScraper
|
||||
if (string.IsNullOrEmpty(contentId))
|
||||
return;
|
||||
|
||||
var match = ContentIdMatcher.Match(contentId);
|
||||
var match = ContentIdMatcher().Match(contentId);
|
||||
if (!match.Success)
|
||||
return;
|
||||
|
||||
@@ -66,7 +68,7 @@ internal sealed class PsnScraper
|
||||
await LockObj.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
storesToScrape = new(psnStores);
|
||||
storesToScrape = [..psnStores];
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -129,7 +131,7 @@ internal sealed class PsnScraper
|
||||
await LockObj.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
storesToScrape = new(psnStores);
|
||||
storesToScrape = [..psnStores];
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -329,7 +331,7 @@ internal sealed class PsnScraper
|
||||
.Concat(item.Attributes?.Entitlements ?? Enumerable.Empty<GameSkuRelation>())
|
||||
.Select(sku => sku.Id)
|
||||
.Distinct()
|
||||
.Where(id => ProductCodeLookup.ProductCode.IsMatch(id) && NeedLookup(id))
|
||||
.Where(id => ProductCodeLookup.Pattern().IsMatch(id) && NeedLookup(id))
|
||||
.ToList();
|
||||
foreach (var relatedSku in relatedSkus)
|
||||
{
|
||||
@@ -344,12 +346,12 @@ internal sealed class PsnScraper
|
||||
|
||||
private static async Task AddOrUpdateThumbnailAsync(string contentId, string? name, string? url, CancellationToken cancellationToken)
|
||||
{
|
||||
var match = ContentIdMatcher.Match(contentId);
|
||||
var match = ContentIdMatcher().Match(contentId);
|
||||
if (!match.Success)
|
||||
return;
|
||||
|
||||
var productCode = match.Groups["product_id"].Value;
|
||||
if (!ProductCodeLookup.ProductCode.IsMatch(productCode))
|
||||
if (!ProductCodeLookup.Pattern().IsMatch(productCode))
|
||||
return;
|
||||
|
||||
name = string.IsNullOrEmpty(name) ? null : name;
|
||||
|
||||
@@ -8,9 +8,13 @@ using DSharpPlus.Entities;
|
||||
|
||||
namespace CompatBot.Utils;
|
||||
|
||||
public static class CommandContextExtensions
|
||||
public static partial class CommandContextExtensions
|
||||
{
|
||||
internal static readonly Regex MessageLinkRegex = new(@"(?:https?://)?discord(app)?\.com/channels/(?<guild>\d+)/(?<channel>\d+)/(?<message>\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
[GeneratedRegex(
|
||||
@"(?:https?://)?discord(app)?\.com/channels/(?<guild>\d+)/(?<channel>\d+)/(?<message>\d+)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Singleline
|
||||
)]
|
||||
internal static partial Regex MessageLinkPattern();
|
||||
|
||||
public static async Task<DiscordMember?> ResolveMemberAsync(this CommandContext ctx, string word)
|
||||
{
|
||||
@@ -37,7 +41,7 @@ public static class CommandContextExtensions
|
||||
|
||||
public static Task<DiscordMessage?> GetMessageAsync(this CommandContext ctx, string messageLink)
|
||||
{
|
||||
if (MessageLinkRegex.Match(messageLink) is Match m
|
||||
if (MessageLinkPattern().Match(messageLink) is Match m
|
||||
&& ulong.TryParse(m.Groups["guild"].Value, out var guildId)
|
||||
&& ulong.TryParse(m.Groups["channel"].Value, out var channelId)
|
||||
&& ulong.TryParse(m.Groups["message"].Value, out var msgId)
|
||||
|
||||
@@ -11,7 +11,7 @@ using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace CompatBot.Utils;
|
||||
|
||||
public static class StringUtils
|
||||
public static partial class StringUtils
|
||||
{
|
||||
public static readonly Encoding Utf8 = new UTF8Encoding(false);
|
||||
private static readonly MemoryCache FuzzyPairCache = new(new MemoryCacheOptions {ExpirationScanFrequency = TimeSpan.FromMinutes(10)});
|
||||
@@ -19,9 +19,11 @@ public static class StringUtils
|
||||
private const char StrikeThroughChar = '\u0336'; // 0x0335 = short dash, 0x0336 = long dash, 0x0337 = short slash, 0x0338 = long slash
|
||||
public const char InvisibleSpacer = '\u206a';
|
||||
public const char Nbsp = '\u00a0';
|
||||
[GeneratedRegex(@"\b(?<cat>cat)s?\b", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture)]
|
||||
private static partial Regex KotFixPattern();
|
||||
|
||||
internal static readonly HashSet<char> SpaceCharacters = new()
|
||||
{
|
||||
internal static readonly HashSet<char> SpaceCharacters =
|
||||
[
|
||||
'\u00a0',
|
||||
'\u2002', '\u2003', '\u2004', '\u2005', '\u2006',
|
||||
'\u2007', '\u2008', '\u2009', '\u200a', '\u200b',
|
||||
@@ -33,7 +35,7 @@ public static class StringUtils
|
||||
'\u2069', '\u206a', '\u206b', '\u206c', '\u206d',
|
||||
'\u206e', '\u206f',
|
||||
'\u3000', '\u303f',
|
||||
};
|
||||
];
|
||||
|
||||
public static string StripMarks(this string str)
|
||||
{
|
||||
@@ -103,7 +105,7 @@ public static class StringUtils
|
||||
|
||||
public static string FixKot(this string str)
|
||||
{
|
||||
var matches = Regex.Matches(str, @"\b(?<cat>cat)s?\b", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
|
||||
var matches = KotFixPattern().Matches(str);
|
||||
foreach (Match m in matches)
|
||||
{
|
||||
var idx = m.Index;
|
||||
|
||||
@@ -9,7 +9,7 @@ public static class PathUtils
|
||||
public static string[] GetSegments(string? path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return Array.Empty<string>();
|
||||
return [];
|
||||
|
||||
var result = new List<string>();
|
||||
string segment;
|
||||
|
||||
@@ -8,13 +8,11 @@ using PsnClient.POCOs;
|
||||
|
||||
namespace CompatBot.Utils.ResultFormatters;
|
||||
|
||||
internal static class FwInfoFormatter
|
||||
internal static partial class FwInfoFormatter
|
||||
{
|
||||
//2019_0828_c975768e5d70e105a72656f498cc9be9/PS3UPDAT.PUP
|
||||
private static readonly Regex FwLinkInfo = new(
|
||||
@"(?<year>\d{4})_(?<month>\d\d)(?<day>\d\d)_(?<md5>[0-9a-f]+)",
|
||||
RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.IgnoreCase
|
||||
);
|
||||
[GeneratedRegex(@"(?<year>\d{4})_(?<month>\d\d)(?<day>\d\d)_(?<md5>[0-9a-f]+)", RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.IgnoreCase)]
|
||||
private static partial Regex FwLinkInfo();
|
||||
private static readonly Dictionary<string, string> RegionToFlagMap = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
["us"] = "🇺🇸",
|
||||
@@ -39,7 +37,7 @@ internal static class FwInfoFormatter
|
||||
.WithColor(Config.Colors.DownloadLinks);
|
||||
|
||||
if (fwInfoList.Count > 0
|
||||
&& fwInfoList.Select(fwi => FwLinkInfo.Match(fwi.DownloadUrl)).FirstOrDefault(m => m.Success) is Match info)
|
||||
&& fwInfoList.Select(fwi => FwLinkInfo().Match(fwi.DownloadUrl)).FirstOrDefault(m => m.Success) is Match info)
|
||||
{
|
||||
result.Description = $"Latest version is **{fwInfoList[0].Version}** released on {info.Groups["year"].Value}-{info.Groups["month"].Value}-{info.Groups["day"].Value}\n" +
|
||||
$"It is available in {fwInfoList.Count} region{(fwInfoList.Count == 1 ? "" : "s")} out of {RegionToFlagMap.Count}";
|
||||
|
||||
@@ -28,7 +28,7 @@ public static class IrdSearchResultFormatter
|
||||
|
||||
string[] parts = item.Filename.Split('-');
|
||||
if (parts.Length == 1)
|
||||
parts = new[] {"", item.Filename};
|
||||
parts = ["", item.Filename];
|
||||
result.AddField(
|
||||
$"[{parts[0]} v{item.GameVersion}] {item.Title?.Sanitize().Trim(EmbedPager.MaxFieldTitleLength)}",
|
||||
$"[⏬ `{parts[1].Sanitize().Trim(200)}`]({IrdClient.GetDownloadLink(item.Filename)})"
|
||||
|
||||
@@ -3,7 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using CompatApiClient.Utils;
|
||||
using CompatBot.EventHandlers.LogParsing;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
namespace CompatBot.Utils.ResultFormatters;
|
||||
@@ -27,9 +29,9 @@ internal static partial class LogParserResult
|
||||
systemInfo = systemInfo[..idxStart] + systemInfo[idxEnd..];
|
||||
}
|
||||
var sysInfoParts = systemInfo.Split(NewLineChars, StringSplitOptions.RemoveEmptyEntries);
|
||||
var buildInfo = sysInfoParts.Length > 0 ? BuildInfoInLog.Match(sysInfoParts[0]) : BuildInfoInLog.Match(systemInfo);
|
||||
var cpuInfo = sysInfoParts.Length > 1 ? CpuInfoInLog.Match(sysInfoParts[1]) : CpuInfoInLog.Match(systemInfo);
|
||||
var osInfo = sysInfoParts.Length > 2 ? OsInfoInLog.Match(sysInfoParts[2]) : OsInfoInLog.Match(systemInfo);
|
||||
var buildInfo = BuildInfoInLog().Match(sysInfoParts.Length > 0 ? sysInfoParts[0] : systemInfo);
|
||||
var cpuInfo = CpuInfoInLog().Match(sysInfoParts.Length > 1 ? sysInfoParts[1] : systemInfo);
|
||||
var osInfo = LogParser.OsInfo().Match(sysInfoParts.Length > 2 ? sysInfoParts[2] : systemInfo);
|
||||
if (buildInfo.Success)
|
||||
{
|
||||
items["build_version"] = buildInfo.Groups["version"].Value.Trim();
|
||||
|
||||
@@ -24,6 +24,11 @@ internal static partial class LogParserResult
|
||||
private static readonly Version DecompilerIssueStartVersion = new(0, 0, 9, 10307);
|
||||
private static readonly Version DecompilerIssueEndVersion = new(0, 0, 10, 10346);
|
||||
|
||||
[GeneratedRegex(@"\(e(rror)?=(0x(?<verification_error_hex>[0-9a-f]+)|(?<verification_error>\d+))(\[\d+\])?\)")]
|
||||
private static partial Regex VerificationErrorPattern();
|
||||
[GeneratedRegex(@"Xeon (([EXLW]C?|LV )?\d+|(E\d|AWS)-\d+\w?( (v[2-4]|0))?|D-1.+)( \(ES\))?$", DefaultSingleLine)]
|
||||
private static partial Regex XeonModelPattern();
|
||||
|
||||
private static async Task BuildNotesSectionAsync(DiscordEmbedBuilder builder, LogParseState state, DiscordClient discordClient)
|
||||
{
|
||||
var items = state.CompletedCollection!;
|
||||
@@ -143,7 +148,7 @@ internal static partial class LogParserResult
|
||||
}
|
||||
|
||||
var category = items["game_category"];
|
||||
if (category is "PE" or "PP" || serial.StartsWith('U') && ProductCodeLookup.ProductCode.IsMatch(serial))
|
||||
if (category is "PE" or "PP" || serial.StartsWith('U') && ProductCodeLookup.Pattern().IsMatch(serial))
|
||||
{
|
||||
builder.Color = Config.Colors.CompatStatusNothing;
|
||||
notes.Add("❌ PSP software is not supported");
|
||||
@@ -161,7 +166,7 @@ internal static partial class LogParserResult
|
||||
|
||||
if (items["compat_database_path"] is string compatDbPath)
|
||||
{
|
||||
if (InstallPath.Match(compatDbPath.Replace('\\', '/').Replace("//", "/").Trim()) is { Success: true } installPathMatch)
|
||||
if (InstallPath().Match(compatDbPath.Replace('\\', '/').Replace("//", "/").Trim()) is { Success: true } installPathMatch)
|
||||
{
|
||||
var rpcs3FolderMissing = string.IsNullOrEmpty(installPathMatch.Groups["rpcs3_folder"].Value);
|
||||
var desktop = !string.IsNullOrEmpty(installPathMatch.Groups["desktop"].Value);
|
||||
@@ -222,7 +227,7 @@ internal static partial class LogParserResult
|
||||
|| cpu.EndsWith('M')
|
||||
|| cpu.Contains('Y')
|
||||
|| cpu[^2] == 'G'
|
||||
|| Regex.IsMatch(cpu, @"Xeon (([EXLW]C?|LV )?\d+|(E\d|AWS)-\d+\w?( (v[2-4]|0))?|D-1.+)( \(ES\))?$", DefaultSingleLine)
|
||||
|| XeonModelPattern().IsMatch(cpu)
|
||||
|| threadCount < 6))
|
||||
notes.Add("⚠️ This CPU is too weak and/or too old for PS3 emulation");
|
||||
}
|
||||
@@ -253,15 +258,19 @@ internal static partial class LogParserResult
|
||||
}
|
||||
}
|
||||
|
||||
if (items["os_type"] == "Windows"
|
||||
if (items["os_type"] is "Windows"
|
||||
&& Version.TryParse(items["os_version"], out var winVersion)
|
||||
&& (winVersion is { Major: < 10 } or { Build: < 19045 or (> 20000 and < 22621) }))
|
||||
notes.Add("⚠️ Please [upgrade your Windows](https://www.microsoft.com/en-us/software-download/windows11) to currently supported version");
|
||||
else if (items["os_type"] is "MacOS"
|
||||
&& Version.TryParse(items["os_version"], out var macVersion)
|
||||
&& macVersion is {Major: 14, Minor: >=0 and <=2})
|
||||
notes.Add("❌️ Please update your OS to version 14.3 or newer");
|
||||
|
||||
var gpuInfo = items["gpu_info"] ?? items["discrete_gpu_info"];
|
||||
if (supportedGpu && !string.IsNullOrEmpty(gpuInfo))
|
||||
{
|
||||
if (IntelGpuModel.Match(gpuInfo) is {Success: true} intelMatch)
|
||||
if (IntelGpuModel().Match(gpuInfo) is {Success: true} intelMatch)
|
||||
{
|
||||
var family = intelMatch.Groups["gpu_family"].Value.TrimEnd();
|
||||
var modelNumber = intelMatch.Groups["gpu_model_number"].Value;
|
||||
@@ -289,7 +298,7 @@ internal static partial class LogParserResult
|
||||
if (IsNvidia(gpuInfo))
|
||||
{
|
||||
var isWindows = items["os_type"] is not null and not "Linux";
|
||||
var minVersion = isWindows ? NvidiaRecommendedWindowsVersion : NvidiaRecommendedLinuxVersion;
|
||||
var minVersion = isWindows ? NvidiaRecommendedWindowsDriverVersion : NvidiaRecommendedLinuxDriverVersion;
|
||||
if (driverVersion < minVersion)
|
||||
notes.Add($"❗ Please update your nVidia GPU driver to at least version {minVersion}");
|
||||
if (driverVersion >= NvidiaTextureMemoryBugMinVersion
|
||||
@@ -306,14 +315,14 @@ internal static partial class LogParserResult
|
||||
}
|
||||
else if (IsAmd(gpuInfo) && items["os_type"] == "Windows")
|
||||
{
|
||||
if (driverVersion < AmdRecommendedOldWindowsVersion)
|
||||
notes.Add($"❗ Please update your AMD GPU driver to at least version {AmdRecommendedOldWindowsVersion}");
|
||||
if (driverVersion < AmdRecommendedWindowsDriverVersion)
|
||||
notes.Add($"❗ Please update your AMD GPU driver to at least version {AmdRecommendedWindowsDriverVersion}");
|
||||
}
|
||||
}
|
||||
else if (driverVersionString.Contains("older than", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
if (IsAmd(gpuInfo))
|
||||
notes.Add($"❗ Please update your AMD GPU driver to version {AmdRecommendedOldWindowsVersion} or newer");
|
||||
notes.Add($"❗ Please update your AMD GPU driver to version {AmdRecommendedWindowsDriverVersion} or newer");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,7 +458,7 @@ internal static partial class LogParserResult
|
||||
notes.Add(msg);
|
||||
}
|
||||
if (multiItems["ppu_patch"] is [string firstPpuPatch, ..]
|
||||
&& ProgramHashPatch.Match(firstPpuPatch) is { Success: true } m
|
||||
&& ProgramHashPatch().Match(firstPpuPatch) is { Success: true } m
|
||||
&& m.Groups["hash"].Value is string firstPpuHash)
|
||||
{
|
||||
var exe = Path.GetFileName(items["elf_boot_path"] ?? "");
|
||||
@@ -577,7 +586,7 @@ internal static partial class LogParserResult
|
||||
#else
|
||||
: $"Fatal Error (x{count})";
|
||||
#endif
|
||||
if (Regex.Match(fatalError, @"\(e(rror)?=(0x(?<verification_error_hex>[0-9a-f]+)|(?<verification_error>\d+))(\[\d+\])?\)") is {Success: true} match)
|
||||
if (VerificationErrorPattern().Match(fatalError) is {Success: true} match)
|
||||
{
|
||||
if (int.TryParse(match.Groups["verification_error"].Value, out var decCode))
|
||||
win32ErrorCodes.Add(decCode);
|
||||
|
||||
@@ -13,6 +13,9 @@ namespace CompatBot.Utils.ResultFormatters;
|
||||
|
||||
internal static partial class LogParserResult
|
||||
{
|
||||
[GeneratedRegex(@"Radeon RX 5\d{3}", RegexOptions.IgnoreCase)]
|
||||
private static partial Regex RadeonRx5xxPattern();
|
||||
|
||||
private static void BuildWeirdSettingsSection(DiscordEmbedBuilder builder, LogParseState state, List<string> generalNotes)
|
||||
{
|
||||
var items = state.CompletedCollection!;
|
||||
@@ -187,7 +190,7 @@ internal static partial class LogParserResult
|
||||
}
|
||||
var isWireframeBugPossible = items["gpu_info"] is string gpuInfo
|
||||
&& buildVersion < RdnaMsaaFixedVersion
|
||||
&& Regex.IsMatch(gpuInfo, @"Radeon RX 5\d{3}", RegexOptions.IgnoreCase) // RX 590 is a thing 😔
|
||||
&& RadeonRx5xxPattern().IsMatch(gpuInfo) // RX 590 is a thing 😔
|
||||
&& !gpuInfo.Contains("RADV");
|
||||
if (items["msaa"] == "Disabled")
|
||||
{
|
||||
@@ -534,11 +537,11 @@ internal static partial class LogParserResult
|
||||
PageSection(builder, notesContent.ToString().Trim(), "Important Settings to Review");
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> P5Ids = new()
|
||||
{
|
||||
private static readonly HashSet<string> P5Ids =
|
||||
[
|
||||
"BLES02247", "BLUS31604", "BLJM61346",
|
||||
"NPEB02436", "NPUB31848", "NPJB00769",
|
||||
};
|
||||
];
|
||||
|
||||
|
||||
private static readonly HashSet<string> KnownP5Patches = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
@@ -627,11 +630,11 @@ internal static partial class LogParserResult
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> AllStarBattleIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> AllStarBattleIds =
|
||||
[
|
||||
"BLES01986", "BLUS31405", "BLJS10217",
|
||||
"NPEB01922", "NPUB31391", "NPJB00331",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownJojoPatches = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
@@ -758,23 +761,23 @@ internal static partial class LogParserResult
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> Gow3Ids = new()
|
||||
{
|
||||
private static readonly HashSet<string> Gow3Ids =
|
||||
[
|
||||
"BCAS25003", "BCES00510", "BCES00516", "BCES00799", "BCJS37001", "BCUS98111", "BCKS15003",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> GowHDIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> GowHDIds =
|
||||
[
|
||||
"BCAS20102", "BCES00791", "BCES00800", "BLJM60200", "BCUS98229", // collection except volume II
|
||||
"NPUA80491", "NPUA80490", "NPEA00255", "NPEA00256", "NPJA00062", "NPJA00061", "NPJA00066",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> GowAscIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> GowAscIds =
|
||||
[
|
||||
"BCAS25016", "BCES01741", "BCES01742", "BCUS98232",
|
||||
"NPEA00445", "NPEA90123", "NPUA70216", "NPUA70269", "NPUA80918",
|
||||
"NPHA80258",
|
||||
};
|
||||
];
|
||||
|
||||
private static void CheckGoWSettings(string serial, NameValueCollection items, List<string> notes, List<string> generalNotes)
|
||||
{
|
||||
@@ -787,12 +790,12 @@ internal static partial class LogParserResult
|
||||
generalNotes.Add("ℹ️ This game is known to be very unstable");
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> DesIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> DesIds =
|
||||
[
|
||||
"BLES00932", "BLUS30443", "BCJS30022", "BCAS20071",
|
||||
"NPEB01202", "NPUB30910", "NPJA00102",
|
||||
"BLUD80018", // trade demo
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownDesPatches = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
@@ -862,13 +865,13 @@ internal static partial class LogParserResult
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> Dod3Ids = new()
|
||||
{
|
||||
private static readonly HashSet<string> Dod3Ids =
|
||||
[
|
||||
"BLUS31197", "NPUB31251",
|
||||
"NPEB01407",
|
||||
"BLJM61043", "NPJB00380",
|
||||
"BCAS20311", "NPHB00633", "NPHB00639",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownDod3Patches = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
@@ -877,13 +880,11 @@ internal static partial class LogParserResult
|
||||
"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
|
||||
@@ -923,16 +924,16 @@ internal static partial class LogParserResult
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> TlouIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> TlouIds =
|
||||
[
|
||||
"BCAS20270", "BCES01584", "BCES01585", "BCJS37010", "BCUS98174",
|
||||
"NPEA00435", "NPJA00096", "NPHA80243", "NPUA80960",
|
||||
"NPEA00521", "NPJA00129", "NPHA80279", "NPUA81175", // left behind
|
||||
"NPEA90122", "NPHA80246", "NPUA70257", // demos
|
||||
"NPEA00454", "NPUA30134", "NPEA00517", // soundtrack
|
||||
"NPJM00012", // bonus video
|
||||
"NPUO30130" // manual
|
||||
};
|
||||
"NPUO30130", // manual
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownTlouPatches = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
@@ -1003,11 +1004,11 @@ internal static partial class LogParserResult
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> Killzone3Ids = new()
|
||||
{
|
||||
private static readonly HashSet<string> Killzone3Ids =
|
||||
[
|
||||
"BCAS20157", "BCAS25008", "BCES01007", "BCJS30066", "BCJS37003", "BCJS70016", "BCJS75002", "BCUS98234",
|
||||
"NPEA00321", "NPEA90084", "NPEA90085", "NPEA90086", "NPHA80140", "NPJA90178", "NPUA70133",
|
||||
};
|
||||
];
|
||||
|
||||
private static void CheckKillzone3Settings(string serial, NameValueCollection items, List<string> notes, UniqueList<string> patchNames)
|
||||
{
|
||||
@@ -1025,13 +1026,13 @@ internal static partial class LogParserResult
|
||||
notes.Add("⚠️ Please enable MLAA patch (recommended) or `Write Color Buffers`");
|
||||
}
|
||||
}
|
||||
private static readonly HashSet<string> RdrIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> RdrIds =
|
||||
[
|
||||
"BLAS50296", "BLES00680", "BLES01179", "BLES01294", "BLUS30418", "BLUS30711", "BLUS30758",
|
||||
"BLJM60314", "BLJM60403", "BLJM61181", "BLKS20315",
|
||||
"NPEB00833", "NPHB00465", "NPHB00466", "NPUB30638", "NPUB30639",
|
||||
"NPUB50139", // max payne 3 / rdr bundle???
|
||||
};
|
||||
];
|
||||
|
||||
private static void CheckRdrSettings(string serial, NameValueCollection items, List<string> notes)
|
||||
{
|
||||
@@ -1042,13 +1043,13 @@ internal static partial class LogParserResult
|
||||
notes.Add("ℹ️ `Write Color Buffers` is required for proper visuals at night");
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> Mgs4Ids = new()
|
||||
{
|
||||
private static readonly HashSet<string> Mgs4Ids =
|
||||
[
|
||||
"BLAS55005", "BLES00246", "BLJM57001", "BLJM67001", "BLKS25001", "BLUS30109", "BLUS30148",
|
||||
"NPEB02182", "NPJB00698", "NPUB31633",
|
||||
"NPEB90116", "NPHB00065", "NPHB00067", "NPJB90149", "NPUB90176", // demos
|
||||
"NPEB00027", "NPJB90113", "NPUB90126", // database
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownMgs4Patches = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
@@ -1091,11 +1092,11 @@ internal static partial class LogParserResult
|
||||
generalNotes.Add("🤔 Very interesting version of the game you got there");
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> PdfIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> PdfIds =
|
||||
[
|
||||
"BLJM60527", "BLUS31319", "BLAS50576",
|
||||
"NPEB01393", "NPUB31241", "NPHB00559", "NPJB00287",
|
||||
};
|
||||
];
|
||||
|
||||
|
||||
private static readonly HashSet<string> KnownPdfPatches = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
@@ -1105,11 +1106,11 @@ internal static partial class LogParserResult
|
||||
"1105af0a4d6a4a1481930c6f3090c476cde06c4c",
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> Pdf2ndIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> Pdf2ndIds =
|
||||
[
|
||||
"BCAS50693", "BLAS50693", "BLES02029", "BLJM61079",
|
||||
"NPUB31488", "NPHB00671", "NPHB00662", "NPEB02013", "NPJB00435",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownPdf2ndPatches = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
@@ -1142,15 +1143,15 @@ internal static partial class LogParserResult
|
||||
generalNotes.Add("🤔 Very interesting version of the game you got there");
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> Gt5Ids = new()
|
||||
{
|
||||
private static readonly HashSet<string> Gt5Ids =
|
||||
[
|
||||
"BCAS20108", "BCAS20151", "BCAS20154", "BCAS20164", "BCAS20229", "BCAS20267",
|
||||
"BCES00569",
|
||||
"BCJS30001", "BCJS30050", "BCJS30100",
|
||||
"BCUS98114", "BCUS98272", "BCUS98394",
|
||||
"NPEA90052", "NPHA80080", "NPUA70087", // time trial
|
||||
"NPUA70115", // kiosk demo
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownGt5Patches = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
@@ -1179,12 +1180,12 @@ internal static partial class LogParserResult
|
||||
generalNotes.Add("ℹ️ Game versions between 1.05 and 1.10 can fail to boot with HDD space error");
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> Gt6Ids = new()
|
||||
{
|
||||
private static readonly HashSet<string> Gt6Ids =
|
||||
[
|
||||
"BCAS20519", "BCAS20520", "BCAS20521", "BCAS25018", "BCAS25019",
|
||||
"BCES01893", "BCES01905", "BCJS37016", "BCUS98296", "BCUS99247",
|
||||
"NPEA00502", "NPJA00113", "NPUA81049",
|
||||
};
|
||||
];
|
||||
|
||||
private static void CheckGt6Settings(string serial, NameValueCollection items, List<string> notes, List<string> generalNotes)
|
||||
{
|
||||
@@ -1251,19 +1252,19 @@ internal static partial class LogParserResult
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> RatchetToDIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> RatchetToDIds =
|
||||
[
|
||||
"BCAS20045", "BCES00052", "BCJS30014", "BCJS70004", "BCJS70012", "BCKS10054", "BCUS98127", "BCUS98153",
|
||||
"NPEA00452", "NPEA90017", "NPHA20002", "NPUA80965", "NPUA98153",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> Sly4Ids = new()
|
||||
{
|
||||
private static readonly HashSet<string> Sly4Ids =
|
||||
[
|
||||
"BCES01284", "BCUS98247", "BCUS99142",
|
||||
"NPEA00429", "NPUA80875",
|
||||
"NPEA90120", "NPUA70250", // demos
|
||||
"NPUA30123", // soundtrack ???
|
||||
};
|
||||
];
|
||||
|
||||
private static void CheckSly4Settings(string serial, NameValueCollection items, List<string> notes)
|
||||
{
|
||||
@@ -1279,11 +1280,11 @@ internal static partial class LogParserResult
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> DragonsCrownIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> DragonsCrownIds =
|
||||
[
|
||||
"BCAS20290", "BCAS20298", "BLES01950", "BLJM61041", "BLUS30767",
|
||||
"NPEB01836", "NPUB31235",
|
||||
};
|
||||
];
|
||||
|
||||
private static void CheckDragonsCrownSettings(string serial, NameValueCollection items, List<string> notes)
|
||||
{
|
||||
@@ -1294,29 +1295,33 @@ internal static partial class LogParserResult
|
||||
notes.Add("⚠️ Please disable `SPU Loop Detection` for this game");
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> Lbp1Ids = new()
|
||||
{
|
||||
"BCAS20058", "BCAS20078", "BCAS20091", "BCES00611", "BCES00141", "BCJS70009", "BCKS10059", "BCUS98148", "BCUS98199", "BCUS98208",
|
||||
private static readonly HashSet<string> Lbp1Ids =
|
||||
[
|
||||
"BCAS20058", "BCAS20078", "BCAS20091", "BCES00611", "BCES00141", "BCJS70009", "BCKS10059", "BCUS98148",
|
||||
"BCUS98199", "BCUS98208",
|
||||
"NPEA00241", "NPHA80093", "NPUA80472", "NPUA80479",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> Lbp2Ids = new()
|
||||
{
|
||||
"BCAS20201", "BCES00850", "BCES01086", "BCES01345", "BCES01346", "BCES01693", "BCES01694", "BCJS70024", "BCUS90260", "BCUS98249", "BCUS98372",
|
||||
private static readonly HashSet<string> Lbp2Ids =
|
||||
[
|
||||
"BCAS20201", "BCES00850", "BCES01086", "BCES01345", "BCES01346", "BCES01693", "BCES01694", "BCJS70024",
|
||||
"BCUS90260", "BCUS98249", "BCUS98372",
|
||||
"NPEA00324", "NPHA80161", "NPUA80662",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> Lbp3Ids = new()
|
||||
{
|
||||
private static readonly HashSet<string> Lbp3Ids =
|
||||
[
|
||||
"BCAS20322", "BCES01663", "BCES02068", "BCUS98245", "BCUS98362",
|
||||
"NPEA00515", "NPHA80277", "NPUA81116",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> AllLbpGames = new(Lbp1Ids.Concat(Lbp2Ids).Concat(Lbp3Ids))
|
||||
{
|
||||
"NPEA00147", "NPJA90074", "NPJA90097", "NPUA70045", // lbp1 demos and betas
|
||||
private static readonly HashSet<string> AllLbpGames =
|
||||
[
|
||||
..Lbp1Ids, ..Lbp2Ids, ..Lbp3Ids,
|
||||
"NPEA00147", "NPJA90074", "NPJA90097",
|
||||
"NPUA70045", // lbp1 demos and betas
|
||||
"NPUA70117", "NPHA80163", // lbp2 demo and beta
|
||||
};
|
||||
];
|
||||
|
||||
private static void CheckLbpSettings(string serial, NameValueCollection items, List<string> generalNotes)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -25,34 +24,32 @@ internal static partial class LogParserResult
|
||||
private static readonly IrdClient IrdClient = new();
|
||||
private static readonly PsnClient.Client PsnClient = new();
|
||||
|
||||
private static readonly RegexOptions DefaultSingleLine = RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Singleline;
|
||||
private const RegexOptions DefaultSingleLine = RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Singleline;
|
||||
// RPCS3 v0.0.3-3-3499d08 Alpha | HEAD
|
||||
// RPCS3 v0.0.4-6422-95c6ac699 Alpha | HEAD
|
||||
// RPCS3 v0.0.5-7104-a19113025 Alpha | HEAD
|
||||
// RPCS3 v0.0.5-42b4ce13a Alpha | minor
|
||||
// RPCS3 v0.0.18-local_build Alpha | local_build
|
||||
private static readonly Regex BuildInfoInLog = new(
|
||||
@"RPCS3 v(?<version_string>(?<version>(\d|\.)+)(-(?<build>\d+))?-(?<commit>[0-9a-z_]+|unknown))( (?<stage>\w+))?( \| (?<branch>[^|\r\n]+))?( \| Firmware version: (?<fw_version_installed>[^|\r\n]+))?( \| (?<unknown>.*))?\r?$",
|
||||
DefaultSingleLine);
|
||||
private static readonly Regex CpuInfoInLog = new(
|
||||
@"(\d{1,2}(th|rd|nd|st) Gen)?(?<cpu_model>[^|@]+?)\s*(((CPU\s*)?@\s*(?<cpu_speed>.+)\s*GHz\s*)|((APU with|(with )?Radeon|R\d, \d+ Compute) [^|]+)|((\w+[\- ]Core )?Processor))?\s* \| (?<thread_count>\d+) Threads \| (?<memory_amount>[0-9\.\,]+) GiB RAM( \| TSC: (?<tsc>\S+))?( \| (?<cpu_extensions>.*?))?\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 readonly Regex OsInfoInLog = new(
|
||||
@"Operating system: (?<os_type>[^,]+), (Name: (?<posix_name>[^,]+), Release: (?<posix_release>[^,]+), Version: (?<posix_version>[^\r\n]+)|Major: (?<os_version_major>\d+), Minor: (?<os_version_minor>\d+), Build: (?<os_version_build>\d+), Service Pack: (?<os_service_pack>[^,]+), Compatibility mode: (?<os_compat_mode>[^,\r\n]+)|Version: (?<macos_version>[^\r\n]+))\r?$",
|
||||
DefaultSingleLine);
|
||||
private static readonly Regex LinuxKernelVersion = new(@"(?<version>\d+\.\d+\.\d+)", DefaultSingleLine);
|
||||
private static readonly Regex ProgramHashPatch = new(@"(?<hash>\w+(-\d+)?)( \(<-\s*(?<patch_count>\d+)\))?", DefaultSingleLine);
|
||||
private static readonly char[] NewLineChars = {'\r', '\n'};
|
||||
|
||||
[GeneratedRegex(@"RPCS3 v(?<version_string>(?<version>(\d|\.)+)(-(?<build>\d+))?-(?<commit>[0-9a-z_]+|unknown))( (?<stage>\w+))?( \| (?<branch>[^|\r\n]+))?( \| Firmware version: (?<fw_version_installed>[^|\r\n]+))?( \| (?<unknown>.*))?\r?$", DefaultSingleLine)]
|
||||
private static partial Regex BuildInfoInLog();
|
||||
[GeneratedRegex(@"(\d{1,2}(th|rd|nd|st) Gen)?(?<cpu_model>[^|@]+?)\s*(((CPU\s*)?@\s*(?<cpu_speed>.+)\s*GHz\s*)|((APU with|(with )?Radeon|R\d, \d+ Compute) [^|]+)|((\w+[\- ]Core )?Processor))?\s* \| (?<thread_count>\d+) Threads \| (?<memory_amount>[0-9\.\,]+) GiB RAM( \| TSC: (?<tsc>\S+))?( \| (?<cpu_extensions>.*?))?\r?$", DefaultSingleLine)]
|
||||
private static partial Regex CpuInfoInLog();
|
||||
[GeneratedRegex(@"(?<version>\d+\.\d+\.\d+)", DefaultSingleLine)]
|
||||
private static partial Regex LinuxKernelVersion();
|
||||
[GeneratedRegex(@"(?<hash>\w+(-\d+)?)( \(<-\s*(?<patch_count>\d+)\))?", DefaultSingleLine)]
|
||||
private static partial Regex ProgramHashPatch();
|
||||
// rpcs3-v0.0.5-7105-064d0619_win64.7z
|
||||
// rpcs3-v0.0.5-7105-064d0619_linux64.AppImage
|
||||
private static readonly Regex BuildInfoInUpdate = new(@"rpcs3-v(?<version>(\d|\.)+)(-(?<build>\d+))?-(?<commit>[0-9a-f]+)_", DefaultSingleLine);
|
||||
private static readonly Regex VulkanDeviceInfo = new(@"'(?<device_name>.+)' running on driver (?<version>.+)\r?$", DefaultSingleLine);
|
||||
private static readonly Regex IntelGpuModel = new(@"Intel\s?(®|\(R\))? (?<gpu_model>((?<gpu_family>(\w|®| )+) Graphics)( (?<gpu_model_number>P?\d+))?)(\s+\(|$)", DefaultSingleLine);
|
||||
private static readonly Regex InstallPath = new(@"[A-Z]:/(?<program_files>Program Files( \(x86\))?/)?(?<desktop>([^/]+/)+Desktop/)?(?<rpcs3_folder>[^/]+/)*GuiConfigs/", DefaultSingleLine);
|
||||
[GeneratedRegex(@"rpcs3-v(?<version>(\d|\.)+)(-(?<build>\d+))?-(?<commit>[0-9a-f]+)_", DefaultSingleLine)]
|
||||
private static partial Regex BuildInfoInUpdate();
|
||||
[GeneratedRegex(@"'(?<device_name>.+)' running on driver (?<version>.+)\r?$", DefaultSingleLine)]
|
||||
private static partial Regex VulkanDeviceInfo();
|
||||
[GeneratedRegex(@"Intel\s?(®|\(R\))? (?<gpu_model>((?<gpu_family>(\w|®| )+) Graphics)( (?<gpu_model_number>P?\d+))?)(\s+\(|$)", DefaultSingleLine)]
|
||||
private static partial Regex IntelGpuModel();
|
||||
[GeneratedRegex(@"[A-Z]:/(?<program_files>Program Files( \(x86\))?/)?(?<desktop>([^/]+/)+Desktop/)?(?<rpcs3_folder>[^/]+/)*GuiConfigs/", DefaultSingleLine)]
|
||||
private static partial Regex InstallPath();
|
||||
|
||||
private static readonly char[] NewLineChars = ['\r', '\n'];
|
||||
|
||||
private static readonly Version MinimumOpenGLVersion = new(4, 3);
|
||||
private static readonly Version MinimumFirmwareVersion = new(4, 80);
|
||||
@@ -62,10 +59,9 @@ internal static partial class LogParserResult
|
||||
private static readonly Version NvidiaTextureMemoryBugMinVersion = new(526, 0);
|
||||
private static readonly Version NvidiaTextureMemoryBugMaxVersion = new(526, 99);
|
||||
|
||||
private static readonly Version NvidiaRecommendedWindowsVersion = new(512, 16);
|
||||
private static readonly Version NvidiaRecommendedLinuxVersion = new(515, 57);
|
||||
|
||||
private static readonly Version AmdRecommendedOldWindowsVersion = new(23, 2, 1);
|
||||
private static readonly Version NvidiaRecommendedWindowsDriverVersion = new(512, 16);
|
||||
private static readonly Version NvidiaRecommendedLinuxDriverVersion = new(515, 57);
|
||||
private static readonly Version AmdRecommendedWindowsDriverVersion = new(24, 2, 1);
|
||||
|
||||
private static readonly Version NvidiaFullscreenBugFixed = new(0, 0, 6, 8204);
|
||||
private static readonly Version TsxFaFixedVersion = new(0, 0, 12, 10995);
|
||||
@@ -108,35 +104,35 @@ internal static partial class LogParserResult
|
||||
};
|
||||
|
||||
private static readonly string[] Known1080pIds =
|
||||
{
|
||||
[
|
||||
"NPEB00258", "NPUB30162", "NPJB00068", // scott pilgrim
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly string[] KnownDisableVertexCacheIds =
|
||||
{
|
||||
[
|
||||
"NPEB00258", "NPUB30162", "NPJB00068", // scott pilgrim
|
||||
"NPEB00303", "NPUB30242", "NPHB00229", // crazy taxi
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownNoRelaxedXFloatIds = new();
|
||||
private static readonly HashSet<string> KnownNoRelaxedXFloatIds = [];
|
||||
|
||||
private static readonly HashSet<string> KnownNoApproximateXFloatIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> KnownNoApproximateXFloatIds =
|
||||
[
|
||||
"BLES02247", "BLUS31604", "BLJM61346", "NPEB02436", "NPUB31848", "NPJB00769", // p5
|
||||
"BLES00932", "BLUS30443", // DeS
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownFpsUnlockPatchIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> KnownFpsUnlockPatchIds =
|
||||
[
|
||||
"BLES00932", "BLUS30443", // DeS
|
||||
"BLUS30481", "BLES00826", "BLJM60223", // Nier
|
||||
"BLUS31197", "NPUB31251", "NPEB01407", "BLJM61043", "BCAS20311", // DoD3
|
||||
"BLUS31405", // jojo asb
|
||||
"BLJS10318", // jojo eoh
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownWriteColorBuffersIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> KnownWriteColorBuffersIds =
|
||||
[
|
||||
"BLUS30235", "BLES00453", // AC/DC Live: Rock Band Track Pack
|
||||
"BLUS30399", "BCJS30021", "BCAS20050", // Afrika
|
||||
"BLUS30607", "BLES0126", "NPUB30545", "BLJM60359", // Alice: Madness Returns
|
||||
@@ -158,7 +154,7 @@ internal static partial class LogParserResult
|
||||
"BLES00286", "BLUS30154", "NPEB90097", "NPUB90151", // Beijing 2008
|
||||
"NPEB00435", "NPUB30394", // Beyond Good & Evil HD
|
||||
"BCAS25017", "BCES01121", "BCES01122", "BCES01123", "BCUS98298", "BCUS99134", "BCJS37009", "NPEA00513", "NPUA81087", "NPHA80260", "BCES01888", "NPUA81088", "NPJA00097", "NPEA90127", "NPJA90259", "NPUA72074", // Beyond: Two Souls
|
||||
"BLES01397", "BLUS30831", "NPEB01119", "NPEB90417", // Birds of Steel
|
||||
"BLES01397", "BLUS30831", "NPEB01119", "NPEB90417", // Birds of Steel
|
||||
"BLES00759", "BLUS30295", "BLJM60244", "NPEB90250", "NPUB90428", // Blur
|
||||
"NPUB30505", "NPEB00563", // Castlevania: Harmony of Despair
|
||||
"NPUB30722", // Closure
|
||||
@@ -268,40 +264,40 @@ internal static partial class LogParserResult
|
||||
"BLES01721", "BLUS31168", "NPEB01072", "NPUB31153", "BLJM60575", "NPEB90467", // WRC 3: FIA World Rally Championship
|
||||
"BLES01874", "BLUS31509", "NPEB01381", "NPUB31452", "NPJB00624", "BLJM61195", "NPEB90523", // WRC 4: FIA World Rally Championship
|
||||
"BLES01937", "NPEB01815", "BLUS31277", // WWE 2K14
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownResScaleThresholdIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> KnownResScaleThresholdIds =
|
||||
[
|
||||
"BCAS20270", "BCES01584", "BCES01585", "BCJS37010", "BCUS98174", // The Last of Us
|
||||
"NPEA00435", "NPEA90122", "NPHA80243", "NPHA80279", "NPJA00096", "NPJA00129", "NPUA70257", "NPUA80960", "NPUA81175",
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownMotionControlsIds = new()
|
||||
{
|
||||
private static readonly HashSet<string> KnownMotionControlsIds =
|
||||
[
|
||||
"BCES00797", "BCES00802", "BCUS98164", "BCJS30040", "NPEA90053", "NPEA90076", "NPUA70088", "NPUA70112", // heavy rain
|
||||
"BCAS25017", "BCES01121", "BCES01122", "BCES01123", "BCUS98298", "NPEA00513", "NPUA81087", "NPEA90127", "NPJA90259", "NPUA72074", "NPJA00097", // beyond two souls
|
||||
"NPEA00094", "NPEA00250", "NPJA00039", "NPUA80083", // flower
|
||||
"NPEA00036", "NPUA80069", "NPJA00004", // locoroco
|
||||
"BCES01284", "BCUS98247", "BCUS99142", "NPEA00429", "NPUA80875", "NPEA90120", "NPUA70250", // sly cooper 4
|
||||
"BCAS20112", "BCAS20189", "BCKS10112", "BLES01101", "BLJS10072", "BLJS10114", "BLJS50026", "BLUS30652", "NPEB90321", // no more heroes
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownGamesThatRequireInterpreter = new()
|
||||
{
|
||||
private static readonly HashSet<string> KnownGamesThatRequireInterpreter =
|
||||
[
|
||||
"NPEB00630", "NPUB30493", "NPJB00161", // daytona usa
|
||||
"BCAS25017", "BCES01121", "BCES01122", "BCES01123", "BCUS98298", "NPEA00513", "NPUA81087", "NPEA90127", "NPJA90259", "NPUA72074", "NPJA00097", // beyond two souls
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownGamesThatRequireAccurateXfloat = new()
|
||||
{
|
||||
private static readonly HashSet<string> KnownGamesThatRequireAccurateXfloat =
|
||||
[
|
||||
"BLES00229", "BLES00258", "BLES00887", "BLES01128", // gta4 + efls
|
||||
"BLJM55011", "BLJM60235", "BLJM60459", "BLJM60525", "BLJM61180", "BLKS20073", "BLKS20198", // gta4 + efls
|
||||
"BLUS30127", "BLUS30149", "BLUS30524", "BLUS30682", // gta4 + efls
|
||||
"NPEB00882", "NPUB30702", "NPUB30704", "NPEB00511", // gta4 + efls
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownGamesThatWorkWithRelaxedZcull = new()
|
||||
{
|
||||
private static readonly HashSet<string> KnownGamesThatWorkWithRelaxedZcull =
|
||||
[
|
||||
"BLAS50296", "BLES00680", "BLES01179", "BLES01294", "BLUS30418", "BLUS30711", "BLUS30758", //rdr
|
||||
"BLJM60314", "BLJM60403", "BLJM61181", "BLKS20315",
|
||||
"NPEB00833", "NPHB00465", "NPHB00466", "NPUB30638", "NPUB30639",
|
||||
@@ -310,7 +306,7 @@ internal static partial class LogParserResult
|
||||
"NPEB00027", "NPEB02182", "NPEB90116", "NPJB00698", "NPJB90149", "NPUB31633",
|
||||
"NPHB00065", "NPHB00067",
|
||||
"BCAS20100", "BCES00664", "NPEA00057", "NPJA00031", "NPUA80105", // wipeout hd
|
||||
};
|
||||
];
|
||||
|
||||
private static readonly HashSet<string> KnownBogusLicenses = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
@@ -354,7 +350,7 @@ internal static partial class LogParserResult
|
||||
private static readonly TimeSpan AncientBuild = TimeSpan.FromDays(180);
|
||||
private static readonly TimeSpan PrehistoricBuild = TimeSpan.FromDays(365);
|
||||
|
||||
private static readonly char[] PrioritySeparator = {' '};
|
||||
private static readonly char[] PrioritySeparator = [' '];
|
||||
private static readonly string[] EmojiPriority = new[]{ "😱", "💢", "‼️", "❗", "❌", "⁉️", "⚠️", "❔", "✅", "ℹ️" }
|
||||
.Select(e => e.TrimEnd('\ufe0f'))
|
||||
.ToArray();
|
||||
@@ -734,7 +730,7 @@ internal static partial class LogParserResult
|
||||
if (string.IsNullOrEmpty(link))
|
||||
return null;
|
||||
|
||||
var latestBuildInfo = BuildInfoInUpdate.Match(link.ToLowerInvariant());
|
||||
var latestBuildInfo = BuildInfoInUpdate().Match(link.ToLowerInvariant());
|
||||
if (latestBuildInfo.Success && VersionIsTooOld(items, latestBuildInfo, updateInfo))
|
||||
return updateInfo;
|
||||
|
||||
@@ -796,7 +792,7 @@ internal static partial class LogParserResult
|
||||
return null;
|
||||
|
||||
var info = (from line in foundDevices
|
||||
let m = VulkanDeviceInfo.Match(line)
|
||||
let m = VulkanDeviceInfo().Match(line)
|
||||
where m.Success
|
||||
select m
|
||||
).FirstOrDefault(m => m.Groups["device_name"].Value == gpu);
|
||||
@@ -978,7 +974,7 @@ internal static partial class LogParserResult
|
||||
return null;
|
||||
|
||||
var kernelVersion = release;
|
||||
if (LinuxKernelVersion.Match(release) is {Success: true} m)
|
||||
if (LinuxKernelVersion().Match(release) is {Success: true} m)
|
||||
kernelVersion = m.Groups["version"].Value;
|
||||
if (version.Contains("Ubuntu", StringComparison.OrdinalIgnoreCase))
|
||||
return "Ubuntu " + kernelVersion;
|
||||
@@ -1096,7 +1092,7 @@ internal static partial class LogParserResult
|
||||
var result = new Dictionary<string, int>(patchList.Count);
|
||||
foreach (var patch in patchList)
|
||||
{
|
||||
var match = ProgramHashPatch.Match(patch);
|
||||
var match = ProgramHashPatch().Match(patch);
|
||||
if (match.Success)
|
||||
{
|
||||
_ = int.TryParse(match.Groups["patch_count"].Value, out var pCount);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using CompatBot.Database.Providers;
|
||||
using CompatBot.ThumbScrapper;
|
||||
@@ -74,7 +75,7 @@ internal static class TitlePatchFormatter
|
||||
var fname = Path.GetFileName(link);
|
||||
try
|
||||
{
|
||||
var match = PsnScraper.ContentIdMatcher.Match(fname);
|
||||
var match = PsnScraper.ContentIdMatcher().Match(fname);
|
||||
if (match.Success)
|
||||
return fname[20..];
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ internal static class UpdateInfoFormatter
|
||||
desc = desc?.Trim();
|
||||
if (!string.IsNullOrEmpty(desc))
|
||||
{
|
||||
if (GithubLinksHandler.IssueMention.Matches(desc) is { Count: >0 } issueMatches)
|
||||
if (GithubLinksHandler.IssueMention().Matches(desc) is { Count: >0 } issueMatches)
|
||||
{
|
||||
var uniqueLinks = new HashSet<string>(10);
|
||||
foreach (Match m in issueMatches)
|
||||
@@ -84,7 +84,7 @@ internal static class UpdateInfoFormatter
|
||||
}
|
||||
}
|
||||
}
|
||||
if (GithubLinksHandler.CommitMention.Matches(desc) is { Count: >0 } commitMatches)
|
||||
if (GithubLinksHandler.CommitMention().Matches(desc) is { Count: >0 } commitMatches)
|
||||
{
|
||||
var uniqueLinks = new HashSet<string>(2);
|
||||
foreach (Match m in commitMatches)
|
||||
@@ -102,7 +102,7 @@ internal static class UpdateInfoFormatter
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(desc) && GithubLinksHandler.ImageMarkup.Matches(desc) is {Count: >0} imgMatches)
|
||||
if (!string.IsNullOrEmpty(desc) && GithubLinksHandler.ImageMarkup().Matches(desc) is {Count: >0} imgMatches)
|
||||
{
|
||||
var uniqueLinks = new HashSet<string>(10);
|
||||
foreach (Match m in imgMatches)
|
||||
|
||||
@@ -10,14 +10,14 @@ public static class TimeParser
|
||||
|
||||
public static readonly Dictionary<string, string[]> TimeZoneAcronyms = new()
|
||||
{
|
||||
["PT"] = new[] { "Pacific Standard Time", "America/Los_Angeles" },
|
||||
["PST"] = new[] { "Pacific Standard Time", "America/Los_Angeles" },
|
||||
["PDT"] = new[] { "Pacific Standard Time", "Pacific Daylight Time", "America/Los_Angeles" },
|
||||
["EST"] = new[] { "Eastern Standard Time", "America/New_York" },
|
||||
["EDT"] = new[] { "Eastern Standard Time", "Eastern Daylight Time", "America/New_York" },
|
||||
["CEST"] = new[] { "Central European Standard Time", "Europe/Berlin" },
|
||||
["BST"] = new[] { "British Summer Time", "GMT Standard Time", "Europe/London" },
|
||||
["JST"] = new[] { "Japan Standard Time", "Tokyo Standard Time", "Asia/Tokyo" },
|
||||
["PT"] = ["Pacific Standard Time", "America/Los_Angeles"],
|
||||
["PST"] = ["Pacific Standard Time", "America/Los_Angeles"],
|
||||
["PDT"] = ["Pacific Standard Time", "Pacific Daylight Time", "America/Los_Angeles"],
|
||||
["EST"] = ["Eastern Standard Time", "America/New_York"],
|
||||
["EDT"] = ["Eastern Standard Time", "Eastern Daylight Time", "America/New_York"],
|
||||
["CEST"] = ["Central European Standard Time", "Europe/Berlin"],
|
||||
["BST"] = ["British Summer Time", "GMT Standard Time", "Europe/London"],
|
||||
["JST"] = ["Japan Standard Time", "Tokyo Standard Time", "Asia/Tokyo"],
|
||||
};
|
||||
|
||||
static TimeParser()
|
||||
|
||||
@@ -22,7 +22,8 @@ public class AttributeUsageAnalyzer : DiagnosticAnalyzer
|
||||
description: "GroupCommand methods will silently ignore any access check attributes, so instead create an instance of the required check attribute and call it explicitly inside the method."
|
||||
);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(AccessCheckAttributeOnGroupCommandRule);
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
|
||||
[AccessCheckAttributeOnGroupCommandRule];
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace SourceGenerators;
|
||||
[Generator]
|
||||
public class ConfusablesSourceGenerator : ISourceGenerator
|
||||
{
|
||||
private static readonly char[] CommentSplitter = {'#'};
|
||||
private static readonly char[] FieldSplitter = {';'};
|
||||
private static readonly char[] PairSplitter = {' '};
|
||||
private static readonly char[] CommentSplitter = ['#'];
|
||||
private static readonly char[] FieldSplitter = [';'];
|
||||
private static readonly char[] PairSplitter = [' '];
|
||||
|
||||
private static readonly DiagnosticDescriptor ConfusablesCheckWarning = new(
|
||||
id: "CONFUSABLES001",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace SourceGenerators;
|
||||
public class Win32ErrorsSourceGenerator : ISourceGenerator
|
||||
{
|
||||
private const string Indent = " ";
|
||||
private static readonly char[] Separator = {'\t'};
|
||||
private static readonly char[] Separator = ['\t'];
|
||||
|
||||
private static readonly DiagnosticDescriptor Win32ErrorFormatError = new(
|
||||
id: "WIN32CODE001",
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace Tests;
|
||||
public class LogParsingProfiler
|
||||
{
|
||||
private static readonly IArchiveHandler[] ArchiveHandlers =
|
||||
{
|
||||
[
|
||||
new GzipHandler(),
|
||||
new ZipHandler(),
|
||||
new RarHandler(),
|
||||
new SevenZipHandler(),
|
||||
new PlainTextHandler(),
|
||||
};
|
||||
];
|
||||
|
||||
[Explicit("For performance profiling only")]
|
||||
[TestCase(@"C:\Documents\Downloads\RPCS3_20.log", TestName = "Plaintext")]
|
||||
|
||||
@@ -5,17 +5,20 @@ using CompatBot.Utils;
|
||||
namespace Tests;
|
||||
|
||||
[TestFixture]
|
||||
public class RegexTest
|
||||
public partial class RegexTest
|
||||
{
|
||||
[GeneratedRegex(@"Rap file not found: (\xE2\x80\x9C)?(?<rap_file>.*?)(\xE2\x80\x9D)?\r?$", RegexOptions.Multiline | RegexOptions.ExplicitCapture)]
|
||||
private static partial Regex RapFileMissingLogLine();
|
||||
|
||||
[Test]
|
||||
public void Utf8AsAsciiRegexTest()
|
||||
{
|
||||
const string input = @"·W 0:09:45.540824 {PPU[0x1000016] Thread (addContSyncThread) [HLE:0x01245834, LR:0x0019b834]} sceNp: npDrmIsAvailable(): Rap file not found: “/dev_hdd0/home/00000001/exdata/EP4062-NPEB02436_00-ADDCONTENT000001.rap”
|
||||
·W 0:09:45.540866 {PPU[0x1000016] Thread (addContSyncThread) [HLE:0x01245834, LR:0x0019b834]} sceNp: sceNpDrmIsAvailable2(k_licensee=*0xd521b0, drm_path=*0xd00ddac0)";
|
||||
const RegexOptions DefaultOptions = RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.ExplicitCapture;
|
||||
|
||||
const string input = """
|
||||
·W 0:09:45.540824 {PPU[0x1000016] Thread (addContSyncThread) [HLE:0x01245834, LR:0x0019b834]} sceNp: npDrmIsAvailable(): Rap file not found: “/dev_hdd0/home/00000001/exdata/EP4062-NPEB02436_00-ADDCONTENT000001.rap”
|
||||
·W 0:09:45.540866 {PPU[0x1000016] Thread (addContSyncThread) [HLE:0x01245834, LR:0x0019b834]} sceNp: sceNpDrmIsAvailable2(k_licensee=*0xd521b0, drm_path=*0xd00ddac0)
|
||||
""";
|
||||
var latin = input.ToLatin8BitEncoding();
|
||||
var match = Regex.Match(latin, @"Rap file not found: (\xE2\x80\x9C)?(?<rap_file>.*?)(\xE2\x80\x9D)?\r?$", DefaultOptions);
|
||||
var match = RapFileMissingLogLine().Match(latin);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(match.Success, Is.True);
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DuoVia.FuzzyStrings" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="NUnit" Version="4.1.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -108,7 +108,7 @@ internal class UserInfo
|
||||
Username = parts[0],
|
||||
Nickname = parts[1],
|
||||
JoinDate = DateTime.Parse(parts[2], CultureInfo.InvariantCulture),
|
||||
Roles = parts[3]?.Split(',', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>(),
|
||||
Roles = parts[3]?.Split(',', StringSplitOptions.RemoveEmptyEntries) ?? [],
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user