7d5496e959
81 namespace declarations and 100 using directives converted via sed, plus two FQN-aliases (ChatTwoPartyFinderPayload in PayloadHandler.cs and ModifierFlag in KeybindManager.cs) updated. Critical: Language.Designer.cs and HellionStrings.Designer.cs ResourceManager string arguments updated synchronously — these are runtime reflection lookups not caught by the C# compiler. Two intentional ChatTwo references remain: the legacy migration path 'ChatTwo.json' in Plugin.cs (still points to upstream Chat 2's config file by design) and the InternalsVisibleTo declaration in AssemblyInfo.cs (handled in the upcoming repo-folder rename task). The local alias names 'ChatTwoPartyFinderPayload' and 'ChatTwoConflictDetector' are preserved as local symbols; only their target namespaces and references changed.
260 lines
10 KiB
C#
Executable File
260 lines
10 KiB
C#
Executable File
using System.Diagnostics;
|
|
using HellionChat.Code;
|
|
using HellionChat.Resources;
|
|
using HellionChat.Util;
|
|
using Dalamud.Game.Text.SeStringHandling;
|
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
|
using Dalamud.Interface.ImGuiNotification;
|
|
using Dalamud.Interface.Utility.Raii;
|
|
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Game.Text;
|
|
|
|
namespace HellionChat.Ui.SettingsTabs;
|
|
|
|
internal sealed class Database : ISettingsTab
|
|
{
|
|
private Plugin Plugin { get; }
|
|
private Configuration Mutable { get; }
|
|
|
|
public string Name => HellionStrings.Settings_Tab_Database + "###tabs-database";
|
|
|
|
internal Database(Plugin plugin, Configuration mutable)
|
|
{
|
|
Plugin = plugin;
|
|
Mutable = mutable;
|
|
}
|
|
|
|
private bool ShowAdvanced;
|
|
|
|
private long DatabaseLastRefreshTicks;
|
|
private long DatabaseSize;
|
|
private long DatabaseLogSize;
|
|
private int DatabaseMessageCount;
|
|
|
|
public void Draw(bool changed)
|
|
{
|
|
// Shift-on-open keeps the Advanced tools available without a permanent
|
|
// toggle in the UI, mirroring upstream Chat 2 behaviour.
|
|
if (changed)
|
|
ShowAdvanced = ImGui.GetIO().KeyShift;
|
|
|
|
DrawStorageSection();
|
|
ImGui.Spacing();
|
|
DrawViewerSection();
|
|
ImGui.Spacing();
|
|
DrawStatsSection();
|
|
}
|
|
|
|
private void DrawStorageSection()
|
|
{
|
|
using var tree = ImRaii.TreeNode(HellionStrings.Settings_Database_Storage_Heading);
|
|
if (!tree.Success)
|
|
return;
|
|
|
|
using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false))
|
|
{
|
|
ImGui.Checkbox(Language.Options_DatabaseBattleMessages_Name, ref Mutable.DatabaseBattleMessages);
|
|
ImGuiUtil.HelpMarker(Language.Options_DatabaseBattleMessages_Description);
|
|
|
|
if (ImGui.Checkbox(Language.Options_LoadPreviousSession_Name, ref Mutable.LoadPreviousSession))
|
|
if (Mutable.LoadPreviousSession)
|
|
Mutable.FilterIncludePreviousSessions = true;
|
|
ImGuiUtil.HelpMarker(Language.Options_LoadPreviousSession_Description);
|
|
|
|
if (ImGui.Checkbox(Language.Options_FilterIncludePreviousSessions_Name, ref Mutable.FilterIncludePreviousSessions))
|
|
if (!Mutable.FilterIncludePreviousSessions)
|
|
Mutable.LoadPreviousSession = false;
|
|
ImGuiUtil.HelpMarker(Language.Options_FilterIncludePreviousSessions_Description);
|
|
|
|
var old = new FileInfo(Path.Join(Plugin.Interface.ConfigDirectory.FullName, "chat.db"));
|
|
var migratedOld = new FileInfo(Path.Join(Plugin.Interface.ConfigDirectory.FullName, "chat-litedb.db"));
|
|
if (old.Exists || migratedOld.Exists)
|
|
{
|
|
ImGui.Spacing();
|
|
ImGui.Separator();
|
|
ImGui.Spacing();
|
|
|
|
ImGui.TextUnformatted(Language.Options_Database_Old_Heading);
|
|
ImGui.Spacing();
|
|
|
|
if (ImGuiUtil.CtrlShiftButton(Language.Options_Database_Old_Delete, Language.Options_Database_Old_Delete_Tooltip))
|
|
{
|
|
try
|
|
{
|
|
if (old.Exists)
|
|
old.Delete();
|
|
else
|
|
migratedOld.Delete();
|
|
WrapperUtil.AddNotification(Language.Options_Database_Old_Delete_Success, NotificationType.Success);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Plugin.Log.Error(e, "Unable to delete old database");
|
|
WrapperUtil.AddNotification(Language.Options_Database_Old_Delete_Error, NotificationType.Error);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawViewerSection()
|
|
{
|
|
using var tree = ImRaii.TreeNode(HellionStrings.Settings_Database_Viewer_Heading);
|
|
if (!tree.Success)
|
|
return;
|
|
|
|
using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false))
|
|
{
|
|
// Refresh the database size and message count every 5 seconds to avoid
|
|
// constant stat calls and spamming the database.
|
|
if (DatabaseLastRefreshTicks + 5 * 1000 < Environment.TickCount64)
|
|
{
|
|
DatabaseSize = Plugin.MessageManager.Store.DatabaseSize();
|
|
DatabaseLogSize = Plugin.MessageManager.Store.DatabaseLogSize();
|
|
DatabaseMessageCount = Plugin.MessageManager.Store.MessageCount();
|
|
DatabaseLastRefreshTicks = Environment.TickCount64;
|
|
}
|
|
|
|
// Copy the directory path instead of the file path so people can
|
|
// paste it into their file explorer.
|
|
ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Path, MessageManager.DatabasePath()));
|
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
|
{
|
|
var path = Path.GetDirectoryName(MessageManager.DatabasePath());
|
|
ImGui.SetClipboardText(path);
|
|
WrapperUtil.AddNotification(Language.Options_Database_Metadata_CopyConfigPathNotification, NotificationType.Info);
|
|
}
|
|
|
|
if (ImGui.IsItemHovered())
|
|
{
|
|
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
|
|
ImGuiUtil.Tooltip(Language.Options_Database_Metadata_CopyConfigPath);
|
|
}
|
|
|
|
ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Size, StringUtil.BytesToString(DatabaseSize)));
|
|
if (ImGui.IsItemHovered())
|
|
ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseSize));
|
|
|
|
ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_LogSize, StringUtil.BytesToString(DatabaseLogSize)));
|
|
if (ImGui.IsItemHovered())
|
|
ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseLogSize));
|
|
|
|
ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_MessageCount, DatabaseMessageCount));
|
|
|
|
if (ImGuiUtil.CtrlShiftButton(Language.Options_ClearDatabase_Button, Language.Options_ClearDatabase_Tooltip))
|
|
{
|
|
Plugin.Log.Warning("Clearing messages from database");
|
|
Plugin.MessageManager.Store.ClearMessages();
|
|
Plugin.MessageManager.ClearAllTabs();
|
|
|
|
// Refresh on next draw
|
|
DatabaseLastRefreshTicks = 0;
|
|
WrapperUtil.AddNotification(Language.Options_ClearDatabase_Success, NotificationType.Info);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawStatsSection()
|
|
{
|
|
if (!ShowAdvanced)
|
|
return;
|
|
|
|
using var tree = ImRaii.TreeNode(HellionStrings.Settings_Database_Stats_Heading);
|
|
if (!tree.Success)
|
|
return;
|
|
|
|
using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false))
|
|
{
|
|
using var wrap = ImRaii.TextWrapPos(0.0f);
|
|
|
|
ImGuiUtil.WarningText(Language.Options_Database_Advanced_Warning);
|
|
if (ImGuiUtil.CtrlShiftButton("Perform maintenance", "Ctrl+Shift: MessageManager.Store.PerformMaintenance()"))
|
|
Plugin.MessageManager.Store.PerformMaintenance();
|
|
|
|
if (ImGuiUtil.CtrlShiftButton("Reload messages from database", "Ctrl+Shift: MessageManager.FilterAllTabs()"))
|
|
{
|
|
Plugin.MessageManager.ClearAllTabs();
|
|
Plugin.MessageManager.FilterAllTabsAsync();
|
|
}
|
|
|
|
if (ImGuiUtil.CtrlShiftButton("Inject 10,000 messages", "Ctrl+Shift: creates 10,000 unique messages (async)"))
|
|
new Thread(() => InsertMessages(10_000)).Start();
|
|
}
|
|
}
|
|
|
|
private void InsertMessages(int count)
|
|
{
|
|
Plugin.Log.Info($"Inserting {count} messages due to user request");
|
|
|
|
// Generate
|
|
var stopwatch = Stopwatch.StartNew();
|
|
var playerName = Plugin.PlayerState.CharacterName;
|
|
var worldId = Plugin.PlayerState.HomeWorld.ValueNullable?.RowId ?? 0;
|
|
var senderSource = new SeStringBuilder()
|
|
.AddText("<")
|
|
.Add(new PlayerPayload(playerName, worldId))
|
|
.AddText("Random Message")
|
|
.Add(RawPayload.LinkTerminator)
|
|
.AddText(">: ")
|
|
.Build();
|
|
var senderChunks = ChunkUtil.ToChunks(senderSource, ChunkSource.Sender, ChatType.Debug).ToList();
|
|
var messages = new List<Message>(count);
|
|
for (var i = 0; i < count; i++)
|
|
{
|
|
var contentSource = new SeStringBuilder()
|
|
.AddText("Random message payload - ")
|
|
.AddItalics(Guid.NewGuid().ToString())
|
|
.Build();
|
|
var contentChunks = ChunkUtil.ToChunks(contentSource, ChunkSource.Content, ChatType.Debug).ToList();
|
|
|
|
var chatCode = new ChatCode(XivChatType.Say, 0, 0);
|
|
messages.Add(new Message(
|
|
Guid.NewGuid(),
|
|
Plugin.MessageManager.CurrentContentId,
|
|
Plugin.MessageManager.CurrentContentId,
|
|
DateTimeOffset.UtcNow,
|
|
chatCode,
|
|
senderChunks,
|
|
contentChunks,
|
|
senderSource,
|
|
contentSource,
|
|
Guid.Empty
|
|
));
|
|
}
|
|
|
|
var elapsedTicks = stopwatch.ElapsedTicks;
|
|
stopwatch.Stop();
|
|
Plugin.Log.Info($"Crafted {count} messages in {elapsedTicks} ticks ({elapsedTicks / TimeSpan.TicksPerMillisecond}ms)");
|
|
|
|
// Insert
|
|
stopwatch = Stopwatch.StartNew();
|
|
foreach (var message in messages)
|
|
Plugin.MessageManager.Store.UpsertMessage(message);
|
|
|
|
elapsedTicks = stopwatch.ElapsedTicks;
|
|
stopwatch.Stop();
|
|
Plugin.Log.Info($"Upserted {count} messages in {elapsedTicks} ticks ({elapsedTicks / TimeSpan.TicksPerMillisecond}ms)");
|
|
|
|
// Clear tabs during framework frame
|
|
Plugin.Framework.Run(() =>
|
|
{
|
|
stopwatch = Stopwatch.StartNew();
|
|
Plugin.MessageManager.ClearAllTabs();
|
|
elapsedTicks = stopwatch.ElapsedTicks;
|
|
stopwatch.Stop();
|
|
Plugin.Log.Info($"Cleared {Plugin.Config.Tabs.Count} tabs in {elapsedTicks} ticks ({elapsedTicks / TimeSpan.TicksPerMillisecond}ms)");
|
|
}).Wait();
|
|
|
|
// Fetch and filter during framework frame
|
|
Plugin.Framework.Run(() =>
|
|
{
|
|
stopwatch = Stopwatch.StartNew();
|
|
// Intentionally synchronous
|
|
Plugin.MessageManager.FilterAllTabs();
|
|
elapsedTicks = stopwatch.ElapsedTicks;
|
|
stopwatch.Stop();
|
|
Plugin.Log.Info($"Fetched and filtered all tabs in {elapsedTicks} ticks ({elapsedTicks / TimeSpan.TicksPerMillisecond}ms)");
|
|
}).Wait();
|
|
}
|
|
}
|