- Migrate DB to v2 (Channel)

- Add channel selection to DBViewer
This commit is contained in:
Infi
2024-05-22 19:25:36 +02:00
parent 6e0dd15ac0
commit 88fbb24ff0
8 changed files with 176 additions and 32 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ namespace ChatTwo.Code;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1028:Enum Storage should be Int32")]
[Flags]
internal enum ChatSource : ushort
public enum ChatSource : ushort
{
Self = 2,
PartyMember = 4,
+17 -14
View File
@@ -12,45 +12,48 @@ using Lumina.Excel.GeneratedSheets;
namespace ChatTwo;
internal class SortCode {
internal class SortCode
{
internal ChatType Type { get; }
internal ChatSource Source { get; }
[BsonCtor] // Used by LegacyMessageImporter
public SortCode(ChatType type, ChatSource source) {
public SortCode(ChatType type, ChatSource source)
{
Type = type;
Source = source;
}
internal SortCode(uint raw) {
internal SortCode(uint raw)
{
Type = (ChatType)(raw >> 16);
Source = (ChatSource)(raw & 0xFFFF);
}
internal uint Encode() {
internal uint Encode()
{
return ((uint) Type << 16) | (uint) Source;
}
private bool Equals(SortCode other) {
private bool Equals(SortCode other)
{
return Type == other.Type && Source == other.Source;
}
public override bool Equals(object? obj) {
if (ReferenceEquals(null, obj)) {
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj))
return false;
}
if (ReferenceEquals(this, obj)) {
if (ReferenceEquals(this, obj))
return true;
}
return obj.GetType() == GetType() && Equals((SortCode) obj);
}
public override int GetHashCode() {
unchecked {
return ((int) Type * 397) ^ (int) Source;
}
public override int GetHashCode()
{
unchecked { return ((int) Type * 397) ^ (int) Source; }
}
}
+25 -9
View File
@@ -167,12 +167,17 @@ internal class MessageStore : IDisposable
var userVersion = Convert.ToInt32(cmd.ExecuteScalar());
var migrationsToDo = new List<Action>();
if (userVersion <= 0)
switch (userVersion)
{
migrationsToDo.Add(Migrate0);
// Migration support was only added in version 1. Migrate0 is
// idempotent.
migrationsToDo.Add(Migrate1);
case <= 0:
migrationsToDo.Add(Migrate0);
// Migration support was only added in version 1. Migrate0 is
// idempotent.
migrationsToDo.Add(Migrate1);
break;
case 1:
migrationsToDo.Add(Migrate2);
break;
}
foreach (var migration in migrationsToDo)
@@ -213,6 +218,17 @@ internal class MessageStore : IDisposable
SetMigrationVersion(1);
}
private void Migrate2()
{
Connection.Execute(@"
-- Migration 2: Add Channel generated column
ALTER TABLE messages ADD COLUMN Channel INTEGER GENERATED ALWAYS AS (Code & 0x7f) VIRTUAL;
CREATE INDEX IF NOT EXISTS idx_messages_channel ON messages (Channel);
");
SetMigrationVersion(2);
}
private void SetMigrationVersion(int version)
{
var cmd = Connection.CreateCommand();
@@ -373,14 +389,14 @@ internal class MessageStore : IDisposable
cmd.ExecuteNonQuery();
}
internal long CountDateRange(DateTime after, DateTime before, ulong? receiver = null)
internal long CountDateRange(DateTime after, DateTime before, uint[] channels, ulong? receiver = null)
{
List<string> whereClauses = ["deleted = false"];
if (receiver != null)
whereClauses.Add("Receiver = $Receiver");
whereClauses.Add("Date BETWEEN $After AND $Before");
whereClauses.Add("Code != 72");
whereClauses.Add($"Channel IN ({string.Join(", ", channels)})");
var whereClause = "WHERE " + string.Join(" AND ", whereClauses);
@@ -402,14 +418,14 @@ internal class MessageStore : IDisposable
return (long) cmd.ExecuteScalar()!;
}
internal MessageEnumerator GetDateRange(DateTime after, DateTime before, ulong? receiver = null, int page = 0)
internal MessageEnumerator GetDateRange(DateTime after, DateTime before, uint[] channels, ulong? receiver = null, int page = 0)
{
List<string> whereClauses = ["deleted = false"];
if (receiver != null)
whereClauses.Add("Receiver = $Receiver");
whereClauses.Add("Date BETWEEN $After AND $Before");
whereClauses.Add("Code != 72");
whereClauses.Add($"Channel IN ({string.Join(", ", channels)})");
var whereClause = "WHERE " + string.Join(" AND ", whereClauses);
+9
View File
@@ -1634,6 +1634,15 @@ namespace ChatTwo.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Chat Type.
/// </summary>
internal static string DbViewer_TableField_Type {
get {
return ResourceManager.GetString("DbViewer_TableField_Type", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Chinese (full).
/// </summary>
+3
View File
@@ -1168,6 +1168,9 @@
<data name="DbViewer_TableField_Date" xml:space="preserve">
<value>Date</value>
</data>
<data name="DbViewer_TableField_Type" xml:space="preserve">
<value>Chat Type</value>
</data>
<data name="DbViewer_TableField_Sender" xml:space="preserve">
<value>Sender</value>
</data>
+65 -8
View File
@@ -1,6 +1,7 @@
using System.Collections.Concurrent;
using System.Globalization;
using System.Numerics;
using ChatTwo.Code;
using ChatTwo.Resources;
using ChatTwo.Util;
using Dalamud.Interface;
@@ -24,10 +25,11 @@ public class DbViewer : Window
private int CurrentPage = 1;
private string SimpleSearchTerm = "";
private bool OnlyCurrentCharacter = true;
private readonly Dictionary<ChatType, ChatSource> ChatCodes;
private bool IsProcessing;
private long ProcessingStart = Environment.TickCount64;
private (DateTime Min, DateTime Max, int Page, bool Local) LastProcessed;
private (DateTime Min, DateTime Max, int Page, bool Local, int ChannelCount) LastProcessed;
private string MinDateString = "";
private string MaxDateString = "";
@@ -42,11 +44,12 @@ public class DbViewer : Window
public DbViewer(Plugin plugin) : base("DBViewer###chat2-dbviewer")
{
Plugin = plugin;
ChatCodes = TabsUtil.MostlyPlayer;
DateFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
DateTimeFormat = CultureInfo.CurrentCulture.DateTimeFormat.FullDateTimePattern;
LastProcessed = (AfterDate, BeforeDate, CurrentPage, OnlyCurrentCharacter);
LastProcessed = (AfterDate, BeforeDate, CurrentPage, OnlyCurrentCharacter, ChatCodes.Count);
DateReset();
SizeConstraints = new WindowSizeConstraints
@@ -88,6 +91,8 @@ public class DbViewer : Window
if (ImGuiUtil.IconButton(FontAwesomeIcon.Recycle))
DateReset();
ImGuiUtil.DrawArrows(ref CurrentPage, 1, totalPages, spacing);
ImGui.SameLine(0, spacing);
ChannelSelection();
var skipText = Language.DbViewer_CharacterOption;
var textLength = ImGui.GetTextLineHeight() + ImGui.CalcTextSize(skipText).X + ImGui.GetStyle().ItemInnerSpacing.X + ImGui.GetStyle().FramePadding.X * 2;
@@ -107,7 +112,7 @@ public class DbViewer : Window
if (DateWidget.Validate(MinimalDate, ref AfterDate, ref BeforeDate))
DateRefresh();
if (!IsProcessing && LastProcessed != (AfterDate, BeforeDate, CurrentPage, OnlyCurrentCharacter))
if (!IsProcessing && LastProcessed != (AfterDate, BeforeDate, CurrentPage, OnlyCurrentCharacter, ChatCodes.Count))
{
// Page hasn't changed, so we reset it back to 1
if (LastProcessed.Page == CurrentPage)
@@ -116,17 +121,18 @@ public class DbViewer : Window
AdjustDates();
IsProcessing = true;
ProcessingStart = Environment.TickCount64 + 1_000; // + 1 second
LastProcessed = (AfterDate, BeforeDate, CurrentPage, OnlyCurrentCharacter);
LastProcessed = (AfterDate, BeforeDate, CurrentPage, OnlyCurrentCharacter, ChatCodes.Count);
Task.Run(() =>
{
try
{
ulong? character = OnlyCurrentCharacter ? Plugin.ClientState.LocalContentId : null;
var channels = ChatCodes.Select(c => (uint) c.Key).ToArray();
// We only want to fetch count if this is the first page
if (CurrentPage == 1)
Count = Plugin.MessageManager.Store.CountDateRange(AfterDate, BeforeDate, character);
Messages = Plugin.MessageManager.Store.GetDateRange(AfterDate, BeforeDate, character, CurrentPage - 1).ToArray();
Count = Plugin.MessageManager.Store.CountDateRange(AfterDate, BeforeDate, channels, character);
Messages = Plugin.MessageManager.Store.GetDateRange(AfterDate, BeforeDate, channels, character, CurrentPage - 1).ToArray();
Filter();
}
@@ -153,11 +159,13 @@ public class DbViewer : Window
if (!child.Success)
return;
using var table = ImRaii.Table("##messageHistory", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg | ImGuiTableFlags.Resizable);
using var table = ImRaii.Table("##messageHistory", 4, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg | ImGuiTableFlags.Resizable);
if (!table.Success)
return;
ImGui.TableSetupColumn(Language.DbViewer_TableField_Date, ImGuiTableColumnFlags.WidthFixed);
var columnWidth = ImGui.CalcTextSize(Language.DbViewer_TableField_Type);
ImGui.TableSetupColumn(Language.DbViewer_TableField_Date, ImGuiTableColumnFlags.WidthFixed | ImGuiTableColumnFlags.NoResize);
ImGui.TableSetupColumn(Language.DbViewer_TableField_Type, ImGuiTableColumnFlags.WidthFixed | ImGuiTableColumnFlags.NoResize, columnWidth.X);
ImGui.TableSetupColumn(Language.DbViewer_TableField_Sender);
ImGui.TableSetupColumn(Language.DbViewer_TableField_Content);
@@ -167,6 +175,14 @@ public class DbViewer : Window
ImGui.TableNextColumn();
ImGui.TextUnformatted(message.Date.ToLocalTime().ToString(DateTimeFormat));
ImGui.TableNextColumn();
var pos = ImGui.GetCursorPos();
ImGuiUtil.CenterText($"{message.Code.Raw}");
ImGui.SetCursorPos(pos);
ImGui.Dummy(columnWidth);
if (ImGui.IsItemHovered())
ImGui.SetTooltip(message.Code.Type.Name());
ImGui.TableNextColumn();
Plugin.ChatLogWindow.DrawChunks(message.Sender);
@@ -175,6 +191,47 @@ public class DbViewer : Window
}
}
private void ChannelSelection()
{
const string addTabPopup = "add-channel-popup";
if (ImGui.Button("Channels"))
ImGui.OpenPopup(addTabPopup);
using var popup = ImRaii.Popup(addTabPopup);
if (!popup.Success)
return;
using var channelNode = ImRaii.TreeNode(Language.Options_Tabs_Channels);
if (!channelNode.Success)
return;
foreach (var (header, types) in ChatTypeExt.SortOrder)
{
using var headerNode = ImRaii.TreeNode(header);
if (!headerNode.Success)
continue;
foreach (var type in types)
{
if (type.IsGm())
continue;
var enabled = ChatCodes.ContainsKey(type);
if (ImGui.Checkbox($"##{type.Name()}", ref enabled))
{
if (enabled)
ChatCodes[type] = ChatSourceExt.All;
else
ChatCodes.Remove(type);
}
ImGui.SameLine();
ImGui.TextUnformatted(type.Name());
}
}
}
private void Filter()
{
if (SimpleSearchTerm == "")
+7
View File
@@ -317,6 +317,13 @@ internal static class ImGuiUtil
}
}
public static void CenterText(string text, float indent = 0.0f)
{
indent *= ImGuiHelpers.GlobalScale;
ImGui.SameLine(((ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize(text).X) * 0.5f) + indent);
ImGui.TextUnformatted(text);
}
internal static bool TryToImGui(this VirtualKey key, out ImGuiKey result)
{
result = key switch {
+49
View File
@@ -73,4 +73,53 @@ internal static class TabsUtil {
[ChatType.NpcDialogue] = ChatSourceExt.All,
},
};
internal static Dictionary<ChatType, ChatSource> MostlyPlayer => new()
{
// Special
[ChatType.Debug] = ChatSourceExt.All,
[ChatType.Urgent] = ChatSourceExt.All,
[ChatType.Notice] = ChatSourceExt.All,
// Chat
[ChatType.Say] = ChatSourceExt.All,
[ChatType.Yell] = ChatSourceExt.All,
[ChatType.Shout] = ChatSourceExt.All,
[ChatType.TellIncoming] = ChatSourceExt.All,
[ChatType.TellOutgoing] = ChatSourceExt.All,
[ChatType.Party] = ChatSourceExt.All,
[ChatType.CrossParty] = ChatSourceExt.All,
[ChatType.Alliance] = ChatSourceExt.All,
[ChatType.FreeCompany] = ChatSourceExt.All,
[ChatType.PvpTeam] = ChatSourceExt.All,
[ChatType.CrossLinkshell1] = ChatSourceExt.All,
[ChatType.CrossLinkshell2] = ChatSourceExt.All,
[ChatType.CrossLinkshell3] = ChatSourceExt.All,
[ChatType.CrossLinkshell4] = ChatSourceExt.All,
[ChatType.CrossLinkshell5] = ChatSourceExt.All,
[ChatType.CrossLinkshell6] = ChatSourceExt.All,
[ChatType.CrossLinkshell7] = ChatSourceExt.All,
[ChatType.CrossLinkshell8] = ChatSourceExt.All,
[ChatType.Linkshell1] = ChatSourceExt.All,
[ChatType.Linkshell2] = ChatSourceExt.All,
[ChatType.Linkshell3] = ChatSourceExt.All,
[ChatType.Linkshell4] = ChatSourceExt.All,
[ChatType.Linkshell5] = ChatSourceExt.All,
[ChatType.Linkshell6] = ChatSourceExt.All,
[ChatType.Linkshell7] = ChatSourceExt.All,
[ChatType.Linkshell8] = ChatSourceExt.All,
[ChatType.NoviceNetwork] = ChatSourceExt.All,
[ChatType.StandardEmote] = ChatSourceExt.All,
[ChatType.CustomEmote] = ChatSourceExt.All,
// Announcements
[ChatType.System] = ChatSourceExt.All,
[ChatType.Error] = ChatSourceExt.All,
[ChatType.Echo] = ChatSourceExt.All,
[ChatType.NoviceNetworkSystem] = ChatSourceExt.All,
[ChatType.FreeCompanyAnnouncement] = ChatSourceExt.All,
[ChatType.PvpTeamAnnouncement] = ChatSourceExt.All,
[ChatType.FreeCompanyLoginLogout] = ChatSourceExt.All,
[ChatType.PvpTeamLoginLogout] = ChatSourceExt.All,
[ChatType.RandomNumber] = ChatSourceExt.All,
[ChatType.MessageBook] = ChatSourceExt.All,
};
}