diff --git a/CompatBot/Commands/Antipiracy.cs b/CompatBot/Commands/Antipiracy.cs index e1610485..67677e01 100644 --- a/CompatBot/Commands/Antipiracy.cs +++ b/CompatBot/Commands/Antipiracy.cs @@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore; namespace CompatBot.Commands { - [Group("piracy"), RequiresBotModRole, RequiresDm] + [Group("piracy"), RequiresBotSudoerRole, RequiresDm] [Description("Used to manage piracy filters **in DM**")] internal sealed class Antipiracy: BaseCommandModuleCustom { diff --git a/CompatBot/Commands/Converters/CustomDiscordChannelConverter.cs b/CompatBot/Commands/Converters/CustomDiscordChannelConverter.cs index 2f229dc1..00ff116f 100644 --- a/CompatBot/Commands/Converters/CustomDiscordChannelConverter.cs +++ b/CompatBot/Commands/Converters/CustomDiscordChannelConverter.cs @@ -28,7 +28,7 @@ namespace CompatBot.Commands.Converters from g in guildList from ch in g.Channels select ch - ).FirstOrDefault(xc => xc.Id == cid); + ).FirstOrDefault(xc => xc.Id == cid && !xc.IsCategory); var ret = result == null ? Optional.FromNoValue() : Optional.FromValue(result); return ret; } @@ -40,7 +40,7 @@ namespace CompatBot.Commands.Converters from g in guildList from ch in g.Channels select ch - ).FirstOrDefault(xc => xc.Id == cid); + ).FirstOrDefault(xc => xc.Id == cid && !xc.IsCategory); var ret = result != null ? Optional.FromValue(result) : Optional.FromNoValue(); return ret; } @@ -52,7 +52,7 @@ namespace CompatBot.Commands.Converters from g in guildList from ch in g.Channels select ch - ).FirstOrDefault(xc => xc.Name.ToLowerInvariant() == value); + ).FirstOrDefault(xc => xc.Name.ToLowerInvariant() == value && !xc.IsCategory); return chn != null ? Optional.FromValue(chn) : Optional.FromNoValue(); } } diff --git a/CompatBot/Commands/Misc.cs b/CompatBot/Commands/Misc.cs index 19a2f6a3..af44b199 100644 --- a/CompatBot/Commands/Misc.cs +++ b/CompatBot/Commands/Misc.cs @@ -381,7 +381,7 @@ namespace CompatBot.Commands statsBuilder.AppendLine($@"Longest between warnings: {TimeSpan.FromTicks(longestGapBetweenWarning.Value).AsShortTimespan()}"); if (lastWarn.HasValue) statsBuilder.AppendLine($@"Time since last warning: {(DateTime.UtcNow - lastWarn.Value.AsUtc()).AsShortTimespan()}"); - statsBuilder.Append($"Warnings in the last day: {warnCount}"); + statsBuilder.Append($"Warnings in the last 24h: {warnCount}"); if (warnCount == 0) statsBuilder.Append(" ").Append(BotReactionsHandler.RandomPositiveReaction); embed.AddField("Warning stats", statsBuilder.ToString().TrimEnd(), true); diff --git a/CompatBot/Commands/Psn.Check.cs b/CompatBot/Commands/Psn.Check.cs index e9618112..3a6834a7 100644 --- a/CompatBot/Commands/Psn.Check.cs +++ b/CompatBot/Commands/Psn.Check.cs @@ -8,6 +8,7 @@ using CompatBot.Utils; using CompatBot.Utils.ResultFormatters; using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Interactivity; using PsnClient; namespace CompatBot.Commands @@ -24,11 +25,21 @@ namespace CompatBot.Commands [Description("Checks if specified product has any updates")] public async Task Updates(CommandContext ctx, [RemainingText, Description("Product code such as `BLUS12345`")] string productCode) { + var id = ProductCodeLookup.GetProductIds(productCode).FirstOrDefault(); if (string.IsNullOrEmpty(id)) { - await ctx.RespondAsync($"`{productCode.Sanitize()}` is not a valid product code (e.g. BLUS12345 or NPEB98765)").ConfigureAwait(false); - return; + var botMsg = await ctx.RespondAsync("Please specify a valid product code (e.g. BLUS12345 or NPEB98765)").ConfigureAwait(false); + var interact = ctx.Client.GetInteractivity(); + var msg = await interact.WaitForMessageAsync(m => m.Author == ctx.User && !string.IsNullOrEmpty(m.Content)).ConfigureAwait(false); + await botMsg.DeleteAsync().ConfigureAwait(false); + + id = ProductCodeLookup.GetProductIds(msg.Message?.Content).FirstOrDefault(); + if (string.IsNullOrEmpty(id)) + { + await ctx.ReactWithAsync(Config.Reactions.Failure, $"`{(msg.Message?.Content ?? productCode).Trim(10).Sanitize()}` is not a valid product code").ConfigureAwait(false); + return; + } } var updateInfo = await Client.GetTitleUpdatesAsync(id, Config.Cts.Token).ConfigureAwait(false); diff --git a/CompatBot/CompatBot.csproj b/CompatBot/CompatBot.csproj index f170c7f6..461747e7 100644 --- a/CompatBot/CompatBot.csproj +++ b/CompatBot/CompatBot.csproj @@ -15,6 +15,17 @@ latest + + + + + + + + + + + diff --git a/CompatBot/EventHandlers/LogParsing/LogParser.LogSections.cs b/CompatBot/EventHandlers/LogParsing/LogParser.LogSections.cs index 7072ca46..e11b6e8e 100644 --- a/CompatBot/EventHandlers/LogParsing/LogParser.LogSections.cs +++ b/CompatBot/EventHandlers/LogParsing/LogParser.LogSections.cs @@ -106,9 +106,17 @@ namespace CompatBot.EventHandlers.LogParsing }, EndTrigger = "Audio:", }, - new LogSection + new LogSection // Audio, Input/Output, System, Net, Miscellaneous { EndTrigger = "Log:", + }, + new LogSection + { + Extractors = new Dictionary + { + ["Log:"] = new Regex(@"Log:\s*\r?\n?\s*\{(?.*?)\}\r?$", DefaultOptions), + }, + EndTrigger = "·", OnSectionEnd = MarkAsComplete, }, new LogSection diff --git a/CompatBot/EventHandlers/ProductCodeLookup.cs b/CompatBot/EventHandlers/ProductCodeLookup.cs index 5cfe2cb8..1b751e9d 100644 --- a/CompatBot/EventHandlers/ProductCodeLookup.cs +++ b/CompatBot/EventHandlers/ProductCodeLookup.cs @@ -103,6 +103,9 @@ namespace CompatBot.EventHandlers public static List GetProductIds(string input) { + if (string.IsNullOrEmpty(input)) + return new List(0); + return ProductCode.Matches(input) .Select(match => (match.Groups["letters"].Value + match.Groups["numbers"]).ToUpper()) .Distinct() diff --git a/CompatBot/EventHandlers/UnknownCommandHandler.cs b/CompatBot/EventHandlers/UnknownCommandHandler.cs index e31c8dc0..372537d1 100644 --- a/CompatBot/EventHandlers/UnknownCommandHandler.cs +++ b/CompatBot/EventHandlers/UnknownCommandHandler.cs @@ -24,7 +24,9 @@ namespace CompatBot.EventHandlers if (string.IsNullOrEmpty(cnfe.CommandName)) return; - if (e.Context.Prefix != Config.CommandPrefix && e.Context.CommandsNext.RegisteredCommands.TryGetValue("8ball", out var cmd)) + if (e.Context.Prefix != Config.CommandPrefix + && e.Context.RawArgumentString.EndsWith("?") + && e.Context.CommandsNext.RegisteredCommands.TryGetValue("8ball", out var cmd)) { var updatedContext = e.Context.CommandsNext.CreateContext( e.Context.Message, @@ -40,7 +42,10 @@ namespace CompatBot.EventHandlers if (pos < 0) return; - var gameTitle = e.Context.Message.Content.Substring(pos).Trim(40); + var gameTitle = e.Context.Message.Content.Substring(pos).TrimEager().Trim(40); + if (string.IsNullOrEmpty(gameTitle) || char.IsPunctuation(gameTitle[0])) + return; + var term = gameTitle.ToLowerInvariant(); var lookup = await Explain.LookupTerm(term).ConfigureAwait(false); if (lookup.score > 0.5 && lookup.explanation != null) diff --git a/CompatBot/Utils/DiscordClientExtensions.cs b/CompatBot/Utils/DiscordClientExtensions.cs index 8d3a5880..7696a5cc 100644 --- a/CompatBot/Utils/DiscordClientExtensions.cs +++ b/CompatBot/Utils/DiscordClientExtensions.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using CompatApiClient; using CompatApiClient.Utils; using DSharpPlus; using DSharpPlus.CommandsNext; diff --git a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.cs b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.cs index a123bcba..0c8facd6 100644 --- a/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.cs +++ b/CompatBot/Utils/ResultFormatters/LogParserResultFormatter.cs @@ -29,7 +29,9 @@ namespace CompatBot.Utils.ResultFormatters // RPCS3 v0.0.4-6422-95c6ac699 Alpha | HEAD // RPCS3 v0.0.5-7104-a19113025 Alpha | HEAD // RPCS3 v0.0.5-42b4ce13a Alpha | minor - private static readonly Regex BuildInfoInLog = new Regex(@"RPCS3 v(?(\d|\.)+)(-(?\d+))?-(?[0-9a-f]+) (?\w+) \| (?.*?)\r?$", + private static readonly Regex BuildInfoInLog = new Regex( + @"RPCS3 v(?(?(\d|\.)+)(-(?\d+))?-(?[0-9a-f]+)) (?\w+) \| (?[^|]+)( \| Firmware version: (?[^|\r\n]+)( \| (?.*))?)?\r?\n" + + @"(?[^|@]+)(@\s*(?.+)\s*GHz\s*)? \| (?\d+) Threads \| (?[0-9\.\,]+) GiB RAM( \| (?.*?))?\r?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Multiline); // rpcs3-v0.0.5-7105-064d0619_win64.7z @@ -40,6 +42,7 @@ namespace CompatBot.Utils.ResultFormatters private static readonly Version MinimumOpenGLVersion = new Version(4, 3); private static readonly Version RecommendedOpenGLVersion = new Version(4, 5); + private static readonly Version MinimumFirmwareVersion = new Version(4, 80); private static readonly Dictionary KnownDiscOnPsnIds = new Dictionary(StringComparer.InvariantCultureIgnoreCase) { @@ -114,6 +117,18 @@ namespace CompatBot.Utils.ResultFormatters Color = Config.Colors.LogResultFailed, }; } + if (message != null) + { + var author = message.Author; + var member = client.GetMember(message.Channel?.Guild, author); + if (member != null) + //builder.WithFooter("Log information for " + member.DisplayName.Sanitize(), member.AvatarUrl ?? member.DefaultAvatarUrl); + builder.WithFooter($"Log from {member.DisplayName.Sanitize()} | {member.Id}"); + else + //builder.WithFooter("Log information for " + author.Username.Sanitize(), author.AvatarUrl ?? author.DefaultAvatarUrl); + builder.WithFooter($"Log from {author.Username.Sanitize()} | {author.Id}"); + } + return builder.Build(); } @@ -193,13 +208,30 @@ namespace CompatBot.Utils.ResultFormatters private static void BuildInfoSection(DiscordEmbedBuilder builder, NameValueCollection items) { - var systemInfo = $"{items["build_and_specs"]}"; - if (!string.IsNullOrEmpty(items["os_path"]) && !string.IsNullOrEmpty(systemInfo)) + var systemInfo = items["build_and_specs"] ?? ""; + var m = BuildInfoInLog.Match(systemInfo); + if (m.Success) { - var sysInfoParts = systemInfo.Split(new[] {'\r', '\n'}, 2, StringSplitOptions.RemoveEmptyEntries); - systemInfo = $"{sysInfoParts[0]} | {items["os_path"]}"; - if (sysInfoParts.Length > 1) - systemInfo += Environment.NewLine + sysInfoParts[1]; + items["build_branch"] = m.Groups["branch"].Value.Trim(); + items["build_commit"] = m.Groups["commit"].Value.Trim(); + items["installed_fw_version"] = m.Groups["installed_fw_version"].Value; + items["cpu_model"] = m.Groups["cpu_model"].Value + .Replace("(R)", "", StringComparison.InvariantCultureIgnoreCase) + .Replace("®", "", StringComparison.InvariantCultureIgnoreCase) + .Replace("(TM)", "", StringComparison.InvariantCultureIgnoreCase) + .Replace("™", "", StringComparison.InvariantCultureIgnoreCase) + .Replace(" CPU", ""); + items["thread_count"] = m.Groups["thread_count"].Value; + items["memory_amount"] = m.Groups["memory_amount"].Value; + items["cpu_extensions"] = m.Groups["cpu_extensions"].Value; + systemInfo = $"RPCS3 v{m.Groups["version_string"].Value} {m.Groups["stage"].Value} | {m.Groups["branch"].Value}"; + if (!string.IsNullOrEmpty(items["installed_fw_version"])) + systemInfo += " | FW " + items["installed_fw_version"]; + if (!string.IsNullOrEmpty(items["os_path"])) + systemInfo += " | " + items["os_path"]; + systemInfo += $"{Environment.NewLine}{items["cpu_model"]} | {items["thread_count"]} Threads | {items["memory_amount"]} GiB RAM"; + if (!string.IsNullOrEmpty(items["cpu_extensions"])) + systemInfo += " | " + items["cpu_extensions"]; } if (items["gpu_info"] is string gpu) systemInfo += $"{Environment.NewLine}GPU: {gpu}"; @@ -302,6 +334,8 @@ namespace CompatBot.Utils.ResultFormatters private static void BuildWeirdSettingsSection(DiscordEmbedBuilder builder, NameValueCollection items) { var notes = new List(); + if (!string.IsNullOrWhiteSpace(items["log_disabled_channels"])) + notes.Add("❗ Some logging priorities were modified, please reset and upload a new log"); if (!string.IsNullOrEmpty(items["resolution"]) && items["resolution"] != "1280x720") notes.Add("⚠ `Resolution` was changed from the recommended `1280x720`"); if (items["hook_static_functions"] is string hookStaticFunctions && hookStaticFunctions == TrueMark) @@ -318,7 +352,7 @@ namespace CompatBot.Utils.ResultFormatters notes.Add($"❔ `Anisotropic Filter` is set to `{af}x`, which makes little sense over `16x` or `Auto`"); } if (items["resolution_scale"] is string resScale && int.TryParse(resScale, out var resScaleFactor) && resScaleFactor < 100) - notes.Add($"❔ `Resolution Scale` is `{resScale}%`."); + notes.Add($"❔ `Resolution Scale` is `{resScale}%`; this will not increase performance"); if (items["cpu_blit"] is string cpuBlit && cpuBlit == TrueMark && items["write_color_buffers"] is string wcb && wcb == FalseMark) notes.Add("⚠ `Force CPU Blit` is enabled, but `Write Color Buffers` is disabled"); if (items["zcull"] is string zcull && zcull == TrueMark) @@ -452,6 +486,17 @@ namespace CompatBot.Utils.ResultFormatters notes.Add("❌ Some game files are missing or corrupted, please re-dump and validate."); else if (irdChecked) notes.Add("✅ Checked missing files against IRD"); + if (items["installed_fw_version"] is string fw && !string.IsNullOrEmpty(fw)) + { + if (Version.TryParse(fw, out var fwv)) + { + if (fwv < MinimumFirmwareVersion) + notes.Add($"⚠ Firmware version {MinimumFirmwareVersion} or later is recommended"); + } + else + notes.Add("⚠ Custom firmware is not supported, please use the latest official one"); + } + if (!string.IsNullOrEmpty(items["host_root_in_boot"]) && isEboot) notes.Add("❌ Retail game booted as an ELF through the `/root_host/`, probably due to passing path as an argument; please boot through the game library list for now"); if (!string.IsNullOrEmpty(items["serial"]) && isElf) @@ -467,6 +512,20 @@ namespace CompatBot.Utils.ResultFormatters notes.Add("ℹ Please boot the game and upload a new log"); } + if (items["cpu_model"] is string cpu) + { + if (cpu.StartsWith("AMD")) + { + if (!cpu.Contains("Ryzen")) + notes.Add("⚠ AMD CPUs before Ryzen are too weak for PS3 emulation"); + } + if (cpu.StartsWith("Intel")) + { + if (cpu.Contains("Core2") || cpu.Contains("Celeron") || cpu.Contains("Atom")) + notes.Add("⚠ This CPU is too old and/or too weak for PS3 emulation"); + } + } + var supportedGpu = true; Version oglVersion = null; if (items["opengl_version"] is string oglVersionString) @@ -542,8 +601,8 @@ namespace CompatBot.Utils.ResultFormatters notes.Add("❌ PS3 firmware is missing or corrupted"); var updateInfo = await CheckForUpdateAsync(items).ConfigureAwait(false); - var buildBranch = items["build_branch"]; - if (updateInfo != null && (buildBranch == "head" || buildBranch == "spu_perf")) + var buildBranch = items["build_branch"]?.ToLowerInvariant(); + if (updateInfo != null && (buildBranch == "head" || buildBranch == "spu_perf")) { string prefix = "⚠"; string timeDeltaStr; @@ -596,11 +655,10 @@ namespace CompatBot.Utils.ResultFormatters return null; var buildInfo = BuildInfoInLog.Match(buildAndSpecs.ToLowerInvariant()); - items["build_branch"] = buildInfo.Groups["branch"].Value; if (!buildInfo.Success) return null; - var currentBuildCommit = buildInfo.Groups["commit"].Value; + var currentBuildCommit = items["build_commit"]; if (string.IsNullOrEmpty(currentBuildCommit)) currentBuildCommit = null; var updateInfo = await compatClient.GetUpdateAsync(Config.Cts.Token, currentBuildCommit).ConfigureAwait(false);