diff --git a/CustomizePlus.GameData/CustomizePlus.GameData.csproj b/CustomizePlus.GameData/CustomizePlus.GameData.csproj index ad75ed3..f10e52c 100644 --- a/CustomizePlus.GameData/CustomizePlus.GameData.csproj +++ b/CustomizePlus.GameData/CustomizePlus.GameData.csproj @@ -45,4 +45,12 @@ + + + + INCOGNIFY_STRINGS + + diff --git a/CustomizePlus/Core/ServiceManagerBuilder.cs b/CustomizePlus/Core/ServiceManagerBuilder.cs index b5d28f8..a3b87b6 100644 --- a/CustomizePlus/Core/ServiceManagerBuilder.cs +++ b/CustomizePlus/Core/ServiceManagerBuilder.cs @@ -137,7 +137,8 @@ private static ServiceManager AddCore(this ServiceManager services) .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton(); + .AddSingleton() + .AddSingleton(); return services; } diff --git a/CustomizePlus/Core/Services/SupportLogBuilderService.cs b/CustomizePlus/Core/Services/SupportLogBuilderService.cs new file mode 100644 index 0000000..5570422 --- /dev/null +++ b/CustomizePlus/Core/Services/SupportLogBuilderService.cs @@ -0,0 +1,134 @@ +using CustomizePlus.Armatures.Services; +using CustomizePlus.Configuration.Data; +using CustomizePlus.Core.Data; +using CustomizePlus.Core.Extensions; +using CustomizePlus.Profiles; +using CustomizePlus.Templates; +using Dalamud.Plugin; +using OtterGui.Services; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CustomizePlus.Core.Services; + +//Based on Penumbra's support log +public class SupportLogBuilderService +{ + private readonly PluginConfiguration _configuration; + private readonly TemplateManager _templateManager; + private readonly ProfileManager _profileManager; + private readonly ArmatureManager _armatureManager; + private readonly DalamudPluginInterface _dalamudPluginInterface; + + public SupportLogBuilderService( + PluginConfiguration configuration, + TemplateManager templateManager, + ProfileManager profileManager, + ArmatureManager armatureManager, + DalamudPluginInterface dalamudPluginInterface) + { + _configuration = configuration; + _templateManager = templateManager; + _profileManager = profileManager; + _armatureManager = armatureManager; + _dalamudPluginInterface = dalamudPluginInterface; + } + + public string BuildSupportLog() + { + var sb = new StringBuilder(10240); + sb.AppendLine("**Settings**"); + sb.Append($"> **`Plugin Version: `** {Plugin.Version}\n"); + sb.Append($"> **`Commit Hash: `** {ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha}\n"); + sb.Append($"> **`Root editing: `** {_configuration.EditorConfiguration.RootPositionEditingEnabled}\n"); + sb.AppendLine("**Settings -> Editor Settings**"); + sb.Append($"> **`Limit to my creatures (editor): `** {_configuration.EditorConfiguration.LimitLookupToOwnedObjects}\n"); + sb.Append($"> **`Preview character (editor): `** {_configuration.EditorConfiguration.PreviewCharacterName?.Incognify() ?? "Not set"}\n"); + sb.AppendLine("**Settings -> Profile application**"); + sb.Append($"> **`Character window: `** {_configuration.ProfileApplicationSettings.ApplyInCharacterWindow}\n"); + sb.Append($"> **`Try On: `** {_configuration.ProfileApplicationSettings.ApplyInTryOn}\n"); + sb.Append($"> **`Cards: `** {_configuration.ProfileApplicationSettings.ApplyInCards}\n"); + sb.Append($"> **`Inspect: `** {_configuration.ProfileApplicationSettings.ApplyInInspect}\n"); + sb.Append($"> **`Lobby: `** {_configuration.ProfileApplicationSettings.ApplyInLobby}\n"); + sb.AppendLine("**Relevant plugins**"); + GatherRelevantPlugins(sb); + sb.AppendLine("**Templates**"); + sb.Append($"> **`Count: `** {_templateManager.Templates.Count}\n"); + foreach (var template in _templateManager.Templates) + { + sb.Append($"> > **`{template.ToString(),-29}`**\n"); + } + sb.AppendLine("**Profiles**"); + sb.Append($"> **`Count: `** {_profileManager.Profiles.Count}\n"); + foreach (var profile in _profileManager.Profiles) + { + sb.Append($"> > =====\n"); + sb.Append($"> > **`{profile.ToString(),-29}`*\n"); + sb.Append($"> > **`Name: {profile.Name.Text.Incognify()}`**\n"); + sb.Append($"> > **`Type: {profile.ProfileType}`**\n"); + sb.Append($"> > **`Character name: {profile.CharacterName.Text.Incognify()}`**\n"); + sb.Append($"> > **`Limit to my creatures: {profile.LimitLookupToOwnedObjects}`**\n"); + sb.Append($"> > **`Templates:`**\n"); + sb.Append($"> > > **`Count: {profile.Templates.Count}`**\n"); + foreach (var template in profile.Templates) + { + sb.Append($"> > > **`{template.ToString()}`**\n"); + } + sb.Append($"> > **`Armatures:`**\n"); + sb.Append($"> > > **`Count: {profile.Armatures.Count}`**\n"); + foreach (var armature in profile.Armatures) + { + sb.Append($"> > > **`{armature.ToString()}`**\n"); + } + sb.Append($"> > =====\n"); + } + sb.AppendLine("**Armatures**"); + sb.Append($"> **`Count: `** {_armatureManager.Armatures.Count}\n"); + foreach (var kvPair in _armatureManager.Armatures) + { + var identifier = kvPair.Key; + var armature = kvPair.Value; + sb.Append($"> > =====\n"); + sb.Append($"> > **`{armature.ToString(),-29}`**\n"); + sb.Append($"> > **`Actor: {armature.ActorIdentifier.Incognito(null) ?? "None"}`**\n"); + sb.Append($"> > **`Built: {armature.IsBuilt}`**\n"); + sb.Append($"> > **`Visible: {armature.IsVisible}`**\n"); + sb.Append($"> > **`Pending rebind: {armature.IsPendingProfileRebind}`**\n"); + sb.Append($"> > **`Last seen: {armature.LastSeen}`**\n"); + sb.Append($"> > **`Profile: {armature.Profile?.ToString() ?? "None"}`**\n"); + sb.Append($"> > **`Main Root Bone/Total Bones/Partial Skeleton Count: {armature.MainRootBone}/{armature.TotalBoneCount}/{armature.PartialSkeletonCount}`**\n"); + sb.Append($"> > **`Bone template bindings:`**\n"); + foreach (var bindingKvPair in armature.BoneTemplateBinding) + { + sb.Append($"> > > **`{BoneData.GetBoneDisplayName(bindingKvPair.Key)} ({bindingKvPair.Key}) -> {bindingKvPair.Value.ToString()}`**\n"); + } + sb.Append($"> > =====\n"); + } + return sb.ToString(); + } + + + private void GatherRelevantPlugins(StringBuilder sb) + { + ReadOnlySpan relevantPlugins = + [ + "MareSynchronos", "Ktisis", "Brio", "DynamicBridge" + ]; + var plugins = _dalamudPluginInterface.InstalledPlugins + .GroupBy(p => p.InternalName) + .ToDictionary(g => g.Key, g => + { + var item = g.OrderByDescending(p => p.IsLoaded).ThenByDescending(p => p.Version).First(); + return (item.IsLoaded, item.Version, item.Name); + }); + foreach (var plugin in relevantPlugins) + { + if (plugins.TryGetValue(plugin, out var data)) + sb.Append($"> **`{data.Name + ':',-29}`** {data.Version}{(data.IsLoaded ? string.Empty : " (Disabled)")}\n"); + } + } +} diff --git a/CustomizePlus/CustomizePlus.csproj b/CustomizePlus/CustomizePlus.csproj index ef310d9..d6d9e28 100644 --- a/CustomizePlus/CustomizePlus.csproj +++ b/CustomizePlus/CustomizePlus.csproj @@ -38,6 +38,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all @@ -82,7 +86,7 @@ - diff --git a/CustomizePlus/Plugin.cs b/CustomizePlus/Plugin.cs index 4bc0456..1240593 100644 --- a/CustomizePlus/Plugin.cs +++ b/CustomizePlus/Plugin.cs @@ -9,13 +9,25 @@ using OtterGui.Services; using CustomizePlus.Api; using ECommons; +using ECommons.Commands; +using ECommons.Configuration; +using OtterGui; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Linq; +using CustomizePlus.Configuration.Data; +using CustomizePlus.Core.Extensions; +using CustomizePlus.Templates; +using CustomizePlus.Profiles; +using CustomizePlus.Armatures.Services; namespace CustomizePlus; public sealed class Plugin : IDalamudPlugin { #if DEBUG - public static readonly string Version = $"{Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty} [DEBUG]"; + public static readonly string Version = $"{ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha} [DEBUG]"; #else public static readonly string Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty; #endif @@ -40,7 +52,7 @@ public Plugin(DalamudPluginInterface pluginInterface) _services.GetService(); _services.GetService(); - Logger.Information($"Customize+ v{Version} [FantasiaPlus] started"); + Logger.Information($"Customize+ v{Version} ({ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha}) [FantasiaPlus] started"); } catch (Exception ex) { diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs index d4eb6d2..631156d 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs @@ -12,6 +12,7 @@ using CustomizePlus.Core.Extensions; using System.Numerics; using CustomizePlus.Game.Services; +using CustomizePlus.Core.Data; namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Debug; @@ -187,7 +188,7 @@ private void DrawSingleTemplate(string prefix, Template template) #if !INCOGNIFY_STRINGS ImGui.Text($"{kvPair.Key}: p: {kvPair.Value.Translation} | r: {kvPair.Value.Rotation} | s: {kvPair.Value.Scaling}"); #else - ImGui.Text($"{kvPair.Key}: p: {(kvPair.Value.Translation.IsApproximately(Vector3.Zero) ? "Approx. not changed" : "Changed")} | r: {(kvPair.Value.Rotation.IsApproximately(Vector3.Zero) ? "Approx. not changed" : "Changed")} | s: {(kvPair.Value.Scaling.IsApproximately(Vector3.One) ? "Not changed" : "Changed")}"); + ImGui.Text($"{BoneData.GetBoneDisplayName(kvPair.Key)} ({kvPair.Key}): p: {(kvPair.Value.Translation.IsApproximately(Vector3.Zero) ? "Approx. not changed" : "Changed")} | r: {(kvPair.Value.Rotation.IsApproximately(Vector3.Zero) ? "Approx. not changed" : "Changed")} | s: {(kvPair.Value.Scaling.IsApproximately(Vector3.One) ? "Not changed" : "Changed")}"); #endif } } @@ -215,7 +216,7 @@ private void DrawSingleArmature(string prefix, Armature armature) ImGui.Text($"Bone template bindings:"); foreach (var kvPair in armature.BoneTemplateBinding) { - ImGui.Text($"{kvPair.Key} -> {kvPair.Value.Name.Text.Incognify()} ({kvPair.Value.UniqueId})"); + ImGui.Text($"{BoneData.GetBoneDisplayName(kvPair.Key)} ({kvPair.Key}) -> {kvPair.Value.Name.Text.Incognify()} ({kvPair.Value.UniqueId})"); } } } diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/SettingsTab.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/SettingsTab.cs index 1ba8d42..f4581ee 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/SettingsTab.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/SettingsTab.cs @@ -28,6 +28,7 @@ public class SettingsTab private readonly TemplateEditorManager _templateEditorManager; private readonly CPlusChangeLog _changeLog; private readonly MessageService _messageService; + private readonly SupportLogBuilderService _supportLogBuilderService; public SettingsTab( PluginConfiguration configuration, @@ -35,7 +36,8 @@ public SettingsTab( HookingService hookingService, TemplateEditorManager templateEditorManager, CPlusChangeLog changeLog, - MessageService messageService) + MessageService messageService, + SupportLogBuilderService supportLogBuilderService) { _configuration = configuration; _armatureManager = armatureManager; @@ -43,6 +45,7 @@ public SettingsTab( _templateEditorManager = templateEditorManager; _changeLog = changeLog; _messageService = messageService; + _supportLogBuilderService = supportLogBuilderService; } public void Draw() @@ -53,6 +56,7 @@ public void Draw() DrawGeneralSettings(); + ImGui.NewLine(); ImGui.NewLine(); ImGui.NewLine(); @@ -299,7 +303,7 @@ private void DrawDebugModeCheckbox() #region Support Area private void DrawSupportButtons() { - var width = ImGui.CalcTextSize("Join Discord for Support").X + ImGui.GetStyle().FramePadding.X * 2; + var width = ImGui.CalcTextSize("Copy Support Info to Clipboard").X + ImGui.GetStyle().FramePadding.X * 2; var xPos = ImGui.GetWindowWidth() - width; // Respect the scroll bar width. if (ImGui.GetScrollMaxY() > 0) @@ -311,6 +315,14 @@ private void DrawSupportButtons() ImGui.SetCursorPos(new Vector2(xPos, 1 * ImGui.GetFrameHeightWithSpacing())); if (ImGui.Button("Show update history", new Vector2(width, 0))) _changeLog.Changelog.ForceOpen = true; + + ImGui.SetCursorPos(new Vector2(xPos, 2 * ImGui.GetFrameHeightWithSpacing())); + if (!ImGui.Button("Copy Support Info to Clipboard")) + return; + + var text = _supportLogBuilderService.BuildSupportLog(); + ImGui.SetClipboardText(text); + _messageService.NotificationMessage($"Copied Support Info to Clipboard.", NotificationType.Success, false); } /// Draw a button to open the official discord server.