mirror of
https://github.com/RPCS3/discord-bot.git
synced 2026-01-31 01:25:22 +01:00
541 lines
26 KiB
C#
541 lines
26 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.Specialized;
|
||
using System.Linq;
|
||
using System.Text.RegularExpressions;
|
||
using System.Threading.Tasks;
|
||
using CompatApiClient;
|
||
using CompatApiClient.POCOs;
|
||
using CompatApiClient.Utils;
|
||
using CompatBot.Database.Providers;
|
||
using CompatBot.EventHandlers;
|
||
using CompatBot.EventHandlers.LogParsing.POCOs;
|
||
using CompatBot.EventHandlers.LogParsing.SourceHandlers;
|
||
using DSharpPlus;
|
||
using DSharpPlus.Entities;
|
||
using IrdLibraryClient;
|
||
|
||
namespace CompatBot.Utils.ResultFormatters
|
||
{
|
||
internal static partial class LogParserResult
|
||
{
|
||
private static readonly Client compatClient = new Client();
|
||
private static readonly IrdClient irdClient = new IrdClient();
|
||
|
||
private static readonly 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
|
||
private static readonly Regex BuildInfoInLog = new Regex(
|
||
@"RPCS3 v(?<version_string>(?<version>(\d|\.)+)(-(?<build>\d+))?-(?<commit>[0-9a-f]+)) (?<stage>\w+)( \| (?<branch>[^|]+))?( \| Firmware version: (?<fw_version_installed>[^|\r\n]+)( \| (?<unknown>.*))?)?\r?\n" +
|
||
@"(?<cpu_model>[^|@]+)(@\s*(?<cpu_speed>.+)\s*GHz\s*)? \| (?<thread_count>\d+) Threads \| (?<memory_amount>[0-9\.\,]+) GiB RAM( \| (?<cpu_extensions>.*?))?\r?$",
|
||
RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||
|
||
// rpcs3-v0.0.5-7105-064d0619_win64.7z
|
||
// rpcs3-v0.0.5-7105-064d0619_linux64.AppImage
|
||
private static readonly Regex BuildInfoInUpdate = new Regex(@"rpcs3-v(?<version>(\d|\.)+)(-(?<build>\d+))?-(?<commit>[0-9a-f]+)_", DefaultSingleLine);
|
||
private static readonly Regex VulkanDeviceInfo = new Regex(@"'(?<device_name>.+)' running on driver (?<version>.+)\r?$", DefaultSingleLine);
|
||
private static readonly Regex IntelGpuModel = new Regex(@"Intel\s?(®|\(R\))? (?<gpu_model>(?<gpu_family>(\w| )+Graphics)( (?<gpu_model_number>P?\d+))?)(\s+\(|$)", DefaultSingleLine);
|
||
|
||
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 Version NvidiaFullscreenBugMinVersion = new Version(400, 0);
|
||
private static readonly Version NvidiaFullscreenBugMaxVersion = new Version(499, 99);
|
||
private static readonly Version NvidiaRecommendedOldWindowsVersion = new Version(399, 24);
|
||
|
||
private static readonly Dictionary<string, string> KnownDiscOnPsnIds = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
|
||
{
|
||
{"BLES00932", "NPEB01202"},
|
||
{"BLUS30443", "NPUB30910"},
|
||
//{"BCJS30022", "NPJA00102"},
|
||
{"BCJS70013", "NPJA00102"},
|
||
};
|
||
|
||
private static readonly string[] KnownDisableVertexCacheIds =
|
||
{
|
||
"NPEB00258", "NPUB30162", "NPJB00068", // scott pilgrim
|
||
};
|
||
|
||
private static readonly string[] KnownMegaSpuBlockSizeIds =
|
||
{
|
||
"BLUS30481", "BLES00826", "BLJM60223", // nier
|
||
};
|
||
|
||
private static readonly HashSet<string> KnownWriteColorBuffersIds = new HashSet<string>
|
||
{
|
||
"BLES00932", "BLUS30443", "BCJS70013", "BCJS30022", // DeS
|
||
"BLUS30481", "BLES00826", "BLJM60223", // Nier
|
||
"BCES00510", "BCUS98111", "BCJS37001", "NPUA70080", // God of War 3 / Demo
|
||
};
|
||
|
||
private static readonly HashSet<string> KnownMotionControlsIds = new HashSet<string>
|
||
{
|
||
"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
|
||
};
|
||
|
||
private static readonly HashSet<string> KnownBogusLicenses = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
|
||
{
|
||
"UP0700-NPUB30932_00-NNKDLFULLGAMEPTB.rap",
|
||
"EP0700-NPEB01158_00-NNKDLFULLGAMEPTB.rap",
|
||
};
|
||
|
||
private static readonly TimeSpan OldBuild = TimeSpan.FromDays(30);
|
||
private static readonly TimeSpan VeryOldBuild = TimeSpan.FromDays(60);
|
||
//private static readonly TimeSpan VeryVeryOldBuild = TimeSpan.FromDays(90);
|
||
private static readonly TimeSpan AncientBuild = TimeSpan.FromDays(180);
|
||
private static readonly TimeSpan PrehistoricBuild = TimeSpan.FromDays(365);
|
||
|
||
private static readonly char[] PrioritySeparator = {' '};
|
||
private static readonly string[] EmojiPriority = { "😱", "💢", "‼", "❗", "❌", "⁉", "⚠", "❔", "✅", "ℹ" };
|
||
private const string EnabledMark = "[x]";
|
||
private const string DisabledMark = "[ ]";
|
||
|
||
public static async Task<DiscordEmbedBuilder> AsEmbedAsync(this LogParseState state, DiscordClient client, DiscordMessage message, ISource source)
|
||
{
|
||
DiscordEmbedBuilder builder;
|
||
var collection = state.CompleteCollection ?? state.WipCollection;
|
||
if (collection?.Count > 0)
|
||
{
|
||
if (collection["serial"] is string serial
|
||
&& KnownDiscOnPsnIds.TryGetValue(serial, out var psnSerial)
|
||
&& collection["ldr_game_serial"] is string ldrGameSerial
|
||
&& ldrGameSerial.StartsWith("NP", StringComparison.InvariantCultureIgnoreCase)
|
||
&& ldrGameSerial.Equals(psnSerial, StringComparison.InvariantCultureIgnoreCase))
|
||
{
|
||
collection["serial"] = psnSerial;
|
||
collection["game_category"] = "HG";
|
||
}
|
||
var gameInfo = await client.LookupGameInfoAsync(collection["serial"], collection["game_title"], true).ConfigureAwait(false);
|
||
builder = new DiscordEmbedBuilder(gameInfo) {ThumbnailUrl = null}; // or this will fuck up all formatting
|
||
if (state.Error == LogParseState.ErrorCode.PiracyDetected)
|
||
{
|
||
state.PiracyContext = state.PiracyContext.Sanitize();
|
||
var msg = "__You are being denied further support until you legally dump the game__.\n" +
|
||
"Please note that the RPCS3 community and its developers do not support piracy.\n" +
|
||
"Most of the issues with pirated dumps occur due to them having been tampered with in some way " +
|
||
"and therefore act unpredictably on RPCS3.\n" +
|
||
"If you need help obtaining legal dumps, please read [the quickstart guide](https://rpcs3.net/quickstart).";
|
||
builder.WithColor(Config.Colors.LogAlert)
|
||
.WithTitle("Pirated release detected")
|
||
.WithDescription(msg);
|
||
}
|
||
else
|
||
{
|
||
CleanupValues(collection);
|
||
BuildInfoSection(builder, collection);
|
||
var colA = BuildCpuSection(collection);
|
||
var colB = BuildGpuSection(collection);
|
||
BuildSettingsSections(builder, collection, colA, colB);
|
||
BuildLibsSection(builder, collection);
|
||
await BuildNotesSectionAsync(builder, state, collection, client).ConfigureAwait(false);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
builder = new DiscordEmbedBuilder
|
||
{
|
||
Description = "Log analysis failed, most likely cause is an empty log. Please try again.",
|
||
Color = Config.Colors.LogResultFailed,
|
||
};
|
||
}
|
||
builder.AddAuthor(client, message, source, state);
|
||
return builder;
|
||
}
|
||
|
||
private static void CleanupValues(NameValueCollection items)
|
||
{
|
||
if (items["strict_rendering_mode"] == "true")
|
||
items["resolution_scale"] = "Strict Mode";
|
||
if (items["spu_threads"] == "0")
|
||
items["spu_threads"] = "Auto";
|
||
if (items["spu_secondary_cores"] != null)
|
||
items["thread_scheduler"] = items["spu_secondary_cores"];
|
||
if (items["vulkan_initialized_device"] != null)
|
||
items["gpu_info"] = items["vulkan_initialized_device"];
|
||
else if (items["driver_manuf_new"] != null)
|
||
items["gpu_info"] = items["driver_manuf_new"];
|
||
else if (items["vulkan_gpu"] != "\"\"")
|
||
items["gpu_info"] = items["vulkan_gpu"];
|
||
else if (items["d3d_gpu"] != "\"\"")
|
||
items["gpu_info"] = items["d3d_gpu"];
|
||
else if (items["driver_manuf"] != null)
|
||
items["gpu_info"] = items["driver_manuf"];
|
||
if (!string.IsNullOrEmpty(items["gpu_info"]))
|
||
{
|
||
items["gpu_info"] = items["gpu_info"].StripMarks();
|
||
items["driver_version_info"] = GetOpenglDriverVersion(items["gpu_info"], items["driver_version_new"] ?? items["driver_version"]) ??
|
||
GetVulkanDriverVersion(items["vulkan_initialized_device"], items["vulkan_found_device"]) ??
|
||
GetVulkanDriverVersionRaw(items["gpu_info"], items["vulkan_driver_version_raw"]);
|
||
}
|
||
if (items["driver_version_info"] != null)
|
||
items["gpu_info"] += $" ({items["driver_version_info"]})";
|
||
|
||
if (items["vulkan_compatible_device_name"] is string vulkanDevices)
|
||
{
|
||
var devices = vulkanDevices.Split(Environment.NewLine)
|
||
.Distinct()
|
||
.Select(n => new {name = n.StripMarks(), driverVersion = GetVulkanDriverVersion(n, items["vulkan_found_device"])})
|
||
.Reverse()
|
||
.ToList();
|
||
if (string.IsNullOrEmpty(items["gpu_info"]) && devices.Count > 0)
|
||
{
|
||
var discreteGpu = devices.FirstOrDefault(d => IsNvidia(d.name))
|
||
?? devices.FirstOrDefault(d => IsAmd(d.name))
|
||
?? devices.First();
|
||
items["discrete_gpu_info"] = $"{discreteGpu.name} ({discreteGpu.driverVersion})";
|
||
items["driver_version_info"] = discreteGpu.driverVersion;
|
||
}
|
||
items["gpu_available_info"] = string.Join(Environment.NewLine, devices.Select(d => $"{d.name} ({d.driverVersion})"));
|
||
}
|
||
|
||
if (items["af_override"] is string af)
|
||
{
|
||
if (af == "0")
|
||
items["af_override"] = "Auto";
|
||
else if (af == "1")
|
||
items["af_override"] = "Disabled";
|
||
}
|
||
if (items["lib_loader"] is string libLoader)
|
||
{
|
||
var auto = libLoader.Contains("auto", StringComparison.InvariantCultureIgnoreCase);
|
||
var manual = libLoader.Contains("manual", StringComparison.InvariantCultureIgnoreCase);
|
||
if (auto && manual)
|
||
items["lib_loader"] = "Auto & manual select";
|
||
else if (auto)
|
||
items["lib_loader"] = "Auto";
|
||
else if (manual)
|
||
items["lib_loader"] = "Manual selection";
|
||
}
|
||
if (items["win_path"] != null)
|
||
items["os_path"] = "Windows";
|
||
else if (items["lin_path"] != null)
|
||
items["os_path"] = "Linux";
|
||
if (items["os_path"] == "Windows" && GetWindowsVersion((items["driver_version_new"] ?? items["driver_version"])) is string winVersion)
|
||
items["os_windows_version"] = winVersion;
|
||
if (items["library_list"] is string libs)
|
||
{
|
||
var libList = libs.Split('\n').Select(l => l.Trim(' ', '\t', '-', '\r', '[', ']')).Where(s => !string.IsNullOrEmpty(s)).ToList();
|
||
items["library_list"] = libList.Count > 0 ? string.Join(", ", libList) : "None";
|
||
}
|
||
else
|
||
items["library_list"] = "None";
|
||
|
||
foreach (var key in items.AllKeys)
|
||
{
|
||
var value = items[key];
|
||
if ("true".Equals(value, StringComparison.CurrentCultureIgnoreCase))
|
||
value = EnabledMark;
|
||
else if ("false".Equals(value, StringComparison.CurrentCultureIgnoreCase))
|
||
value = DisabledMark;
|
||
items[key] = value.Sanitize(false);
|
||
}
|
||
}
|
||
|
||
private static void PageSection(DiscordEmbedBuilder builder, string notesContent, string sectionName)
|
||
{
|
||
if (!string.IsNullOrEmpty(notesContent))
|
||
{
|
||
var fields = new EmbedPager().BreakInFieldContent(notesContent.Split(Environment.NewLine), 100).ToList();
|
||
if (fields.Count > 1)
|
||
for (var idx = 0; idx < fields.Count; idx++)
|
||
builder.AddField($"{sectionName} #{idx + 1} of {fields.Count}", fields[idx].content);
|
||
else
|
||
builder.AddField(sectionName, fields[0].content);
|
||
}
|
||
}
|
||
|
||
private static async Task<UpdateInfo> CheckForUpdateAsync(NameValueCollection items)
|
||
{
|
||
if (!(items["build_and_specs"] is string buildAndSpecs))
|
||
return null;
|
||
|
||
var buildInfo = BuildInfoInLog.Match(buildAndSpecs.ToLowerInvariant());
|
||
if (!buildInfo.Success)
|
||
return null;
|
||
|
||
var currentBuildCommit = items["build_commit"];
|
||
if (string.IsNullOrEmpty(currentBuildCommit))
|
||
currentBuildCommit = null;
|
||
var updateInfo = await compatClient.GetUpdateAsync(Config.Cts.Token, currentBuildCommit).ConfigureAwait(false);
|
||
if (updateInfo?.ReturnCode != 1 && currentBuildCommit != null)
|
||
updateInfo = await compatClient.GetUpdateAsync(Config.Cts.Token).ConfigureAwait(false);
|
||
var link = updateInfo?.LatestBuild?.Windows?.Download ?? updateInfo?.LatestBuild?.Linux?.Download;
|
||
if (string.IsNullOrEmpty(link))
|
||
return null;
|
||
|
||
var latestBuildInfo = BuildInfoInUpdate.Match(link.ToLowerInvariant());
|
||
if (latestBuildInfo.Success && VersionIsTooOld(buildInfo, latestBuildInfo, updateInfo))
|
||
return updateInfo;
|
||
|
||
return null;
|
||
|
||
}
|
||
|
||
private static bool VersionIsTooOld(Match log, Match update, UpdateInfo updateInfo)
|
||
{
|
||
if ((updateInfo.GetUpdateDelta() is TimeSpan updateTimeDelta) && (updateTimeDelta < Config.BuildTimeDifferenceForOutdatedBuilds))
|
||
return false;
|
||
|
||
if (Version.TryParse(log.Groups["version"].Value, out var logVersion) && Version.TryParse(update.Groups["version"].Value, out var updateVersion))
|
||
{
|
||
if (logVersion < updateVersion)
|
||
return true;
|
||
|
||
if (int.TryParse(log.Groups["build"].Value, out var logBuild) && int.TryParse(update.Groups["build"].Value, out var updateBuild))
|
||
{
|
||
if (logBuild + Config.BuildNumberDifferenceForOutdatedBuilds < updateBuild)
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
return !SameCommits(log.Groups["commit"].Value, update.Groups["commit"].Value);
|
||
}
|
||
|
||
private static bool SameCommits(string commitA, string commitB)
|
||
{
|
||
if (string.IsNullOrEmpty(commitA) && string.IsNullOrEmpty(commitB))
|
||
return true;
|
||
|
||
if (string.IsNullOrEmpty(commitA) || string.IsNullOrEmpty(commitB))
|
||
return false;
|
||
|
||
var len = Math.Min(commitA.Length, commitB.Length);
|
||
return commitA.Substring(0, len) == commitB.Substring(0, len);
|
||
}
|
||
|
||
private static string GetOpenglDriverVersion(string gpuInfo, string version)
|
||
{
|
||
if (string.IsNullOrEmpty(version))
|
||
return null;
|
||
|
||
if (gpuInfo.Contains("Radeon", StringComparison.InvariantCultureIgnoreCase) ||
|
||
gpuInfo.Contains("AMD", StringComparison.InvariantCultureIgnoreCase) ||
|
||
gpuInfo.Contains("ATI ", StringComparison.InvariantCultureIgnoreCase))
|
||
return AmdDriverVersionProvider.GetFromOpenglAsync(version).ConfigureAwait(false).GetAwaiter().GetResult();
|
||
|
||
return version;
|
||
}
|
||
|
||
private static string GetVulkanDriverVersion(string gpu, string foundDevices)
|
||
{
|
||
if (string.IsNullOrEmpty(gpu) || string.IsNullOrEmpty(foundDevices))
|
||
return null;
|
||
|
||
var info = (from line in foundDevices.Split(Environment.NewLine)
|
||
let m = VulkanDeviceInfo.Match(line)
|
||
where m.Success
|
||
select m
|
||
).FirstOrDefault(m => m.Groups["device_name"].Value == gpu);
|
||
var result = info?.Groups["version"].Value;
|
||
if (string.IsNullOrEmpty(result))
|
||
return null;
|
||
|
||
if (gpu.Contains("Radeon", StringComparison.InvariantCultureIgnoreCase) ||
|
||
gpu.Contains("AMD", StringComparison.InvariantCultureIgnoreCase) ||
|
||
gpu.Contains("ATI ", StringComparison.InvariantCultureIgnoreCase))
|
||
{
|
||
if (gpu.Contains("RADV", StringComparison.InvariantCultureIgnoreCase))
|
||
return result;
|
||
|
||
return AmdDriverVersionProvider.GetFromVulkanAsync(result).ConfigureAwait(false).GetAwaiter().GetResult();
|
||
}
|
||
|
||
if (result.EndsWith(".0.0"))
|
||
result = result.Substring(0, result.Length - 4);
|
||
if (result.Length > 3 && result[result.Length - 2] == '.')
|
||
result = result.Substring(0, result.Length - 1) + "0" + result[result.Length - 1];
|
||
return result;
|
||
}
|
||
|
||
private static string GetVulkanDriverVersionRaw(string gpuInfo, string version)
|
||
{
|
||
if (string.IsNullOrEmpty(version))
|
||
return null;
|
||
|
||
var ver = int.Parse(version);
|
||
if (IsAmd(gpuInfo))
|
||
{
|
||
var major = (ver >> 22) & 0x3ff;
|
||
var minor = (ver >> 12) & 0x3ff;
|
||
var patch = ver & 0xfff;
|
||
var result = $"{major}.{minor}.{patch}";
|
||
if (gpuInfo.Contains("RADV", StringComparison.InvariantCultureIgnoreCase))
|
||
return result;
|
||
|
||
return AmdDriverVersionProvider.GetFromVulkanAsync(result).ConfigureAwait(false).GetAwaiter().GetResult();
|
||
}
|
||
else
|
||
{
|
||
var major = (ver >> 22) & 0x3ff;
|
||
var minor = (ver >> 14) & 0xff;
|
||
var patch = ver & 0x3fff;
|
||
if (major == 0 && gpuInfo.Contains("Intel", StringComparison.InvariantCultureIgnoreCase))
|
||
return $"{minor}.{patch}";
|
||
|
||
if (IsNvidia(gpuInfo))
|
||
{
|
||
if (patch == 0)
|
||
return $"{major}.{minor}";
|
||
return $"{major}.{minor:00}.{(patch >> 6) & 0xff}.{patch & 0x3f}";
|
||
}
|
||
|
||
return $"{major}.{minor}.{patch}";
|
||
}
|
||
}
|
||
|
||
private static string GetWindowsVersion(string driverVersionString)
|
||
{
|
||
// see https://docs.microsoft.com/en-us/windows-hardware/drivers/display/wddm-2-1-features#driver-versioning
|
||
if (string.IsNullOrEmpty(driverVersionString) || !Version.TryParse(driverVersionString, out var driverVer))
|
||
return null;
|
||
|
||
switch (driverVer.Major)
|
||
{
|
||
case 6: //XDDM
|
||
return "XP";
|
||
case 7:
|
||
return "Vista";
|
||
case 8:
|
||
return "7";
|
||
case 9:
|
||
return "8";
|
||
case 10:
|
||
return "8.1";
|
||
case int v when v >= 20 && v < 30:
|
||
var wddmMinor = v % 10;
|
||
switch (wddmMinor)
|
||
{
|
||
// see https://en.wikipedia.org/wiki/Windows_Display_Driver_Model#WDDM_2.0
|
||
case 0:
|
||
return "10";
|
||
case 1:
|
||
return "10 1607";
|
||
case 2:
|
||
return "10 1703";
|
||
case 3:
|
||
return "10 1709";
|
||
case 4:
|
||
return "10 1803";
|
||
case 5:
|
||
return "10 1809";
|
||
case 6:
|
||
return "10 1903";
|
||
default:
|
||
Config.Log.Warn($"Invalid WDDM version 2.{wddmMinor} in driver version {driverVersionString}");
|
||
return null;
|
||
}
|
||
default:
|
||
Config.Log.Warn("Invalid video driver version " + driverVersionString);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
private static bool IsAmd(string gpuInfo)
|
||
{
|
||
return gpuInfo.Contains("Radeon", StringComparison.InvariantCultureIgnoreCase) ||
|
||
gpuInfo.Contains("AMD", StringComparison.InvariantCultureIgnoreCase) ||
|
||
gpuInfo.Contains("ATI ", StringComparison.InvariantCultureIgnoreCase);
|
||
}
|
||
|
||
private static bool IsNvidia(string gpuInfo)
|
||
{
|
||
return gpuInfo.Contains("GeForce", StringComparison.InvariantCultureIgnoreCase) ||
|
||
gpuInfo.Contains("nVidia", StringComparison.InvariantCultureIgnoreCase) ||
|
||
gpuInfo.Contains("Quadro", StringComparison.InvariantCultureIgnoreCase);
|
||
}
|
||
|
||
private static string GetTimeFormat(long microseconds)
|
||
{
|
||
if (microseconds < 1000)
|
||
return $"{microseconds} µs";
|
||
if (microseconds < 1_000_000)
|
||
return $"{microseconds / 1000.0:0.##} ms";
|
||
return $"{microseconds / 1_000_000.0:0.##} s";
|
||
}
|
||
|
||
private static List<string> SortLines(List<string> notes, DiscordEmoji piracyEmoji = null)
|
||
{
|
||
if (notes == null || notes.Count < 2)
|
||
return notes;
|
||
|
||
var priorityList = new List<string>(EmojiPriority);
|
||
if (piracyEmoji != null)
|
||
priorityList.Insert(0, piracyEmoji.ToString());
|
||
return notes
|
||
.Select(s =>
|
||
{
|
||
var prioritySymbol = s.Split(PrioritySeparator, 2)[0];
|
||
var priority = priorityList.IndexOf(prioritySymbol);
|
||
return new
|
||
{
|
||
priority = priority == -1 ? 69 : priority,
|
||
line = s
|
||
};
|
||
})
|
||
.OrderBy(i => i.priority)
|
||
.Select(i => i.line)
|
||
.ToList();
|
||
}
|
||
|
||
private static Dictionary<string, int> GetPatches(string hashList, string patchesList)
|
||
{
|
||
if (string.IsNullOrEmpty(hashList) || string.IsNullOrEmpty(patchesList))
|
||
return new Dictionary<string, int>(0);
|
||
|
||
var hashes = hashList.Split(Environment.NewLine);
|
||
var patches = patchesList.Split(Environment.NewLine);
|
||
if (hashes.Length != patches.Length)
|
||
{
|
||
Config.Log.Warn($"Hashes count: {hashes.Length}, Patches count: {patches.Length}");
|
||
return new Dictionary<string, int>(0);
|
||
}
|
||
|
||
var result = new Dictionary<string, int>();
|
||
for (var i = 0; i < hashes.Length; i++)
|
||
{
|
||
int.TryParse(patches[i], out var pCount);
|
||
result[hashes[i]] = pCount;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
internal static DiscordEmbedBuilder AddAuthor(this DiscordEmbedBuilder builder, DiscordClient client, DiscordMessage message, ISource source, LogParseState state = null)
|
||
{
|
||
if (state?.Error == LogParseState.ErrorCode.PiracyDetected)
|
||
return builder;
|
||
|
||
if (message != null)
|
||
{
|
||
var author = message.Author;
|
||
var member = client.GetMember(message.Channel?.Guild, author);
|
||
string msg;
|
||
if (member == null)
|
||
msg = $"Log from {author.Username.Sanitize()} | {author.Id}\n";
|
||
else
|
||
msg = $"Log from {member.DisplayName.Sanitize()} | {member.Id}\n";
|
||
msg += " | " + (source?.SourceType ?? "Unknown source");
|
||
if (state?.ReadBytes > 0 && source?.LogFileSize > 0 && source.LogFileSize < 2L*1024*1024*1024 && state.ReadBytes <= source.LogFileSize)
|
||
msg += $" | Parsed {state.ReadBytes * 100.0 / source.LogFileSize:0.##}%";
|
||
else if (source?.SourceFilePosition > 0 && source.SourceFileSize > 0 && source.SourceFilePosition <= source.SourceFileSize)
|
||
msg += $" | Read {source.SourceFilePosition * 100.0 / source.SourceFileSize:0.##}%";
|
||
else if (state?.ReadBytes > 0)
|
||
msg += $" | Parsed {state.ReadBytes} byte{(state.ReadBytes == 1 ? "" : "s")}";
|
||
else if (source?.LogFileSize > 0)
|
||
msg += $" | {source.LogFileSize} byte{(source.LogFileSize == 1 ? "" : "s")}";
|
||
#if DEBUG
|
||
if (state?.ParsingTime.TotalMilliseconds > 0)
|
||
msg += $" | {state.ParsingTime.TotalSeconds:0.###}s";
|
||
msg += " | Test Bot Instance";
|
||
#endif
|
||
builder.WithFooter(msg);
|
||
}
|
||
return builder;
|
||
}
|
||
}
|
||
}
|