Final API11 updates and new channel switcher
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>1.29.5</Version>
|
<Version>1.29.6</Version>
|
||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
@@ -54,7 +54,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DalamudPackager" Version="11.0.0" />
|
<PackageReference Include="DalamudPackager" Version="11.0.0" />
|
||||||
<PackageReference Include="EmbedIO" Version="3.5.2" />
|
|
||||||
<PackageReference Include="MessagePack" Version="3.0.238-rc.1" />
|
<PackageReference Include="MessagePack" Version="3.0.238-rc.1" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.0" />
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.0" />
|
||||||
<PackageReference Include="Pidgin" Version="3.3.0" />
|
<PackageReference Include="Pidgin" Version="3.3.0" />
|
||||||
|
|||||||
@@ -40,4 +40,6 @@ internal enum InputChannel : uint
|
|||||||
ExtraChatLinkshell6 = 1006,
|
ExtraChatLinkshell6 = 1006,
|
||||||
ExtraChatLinkshell7 = 1007,
|
ExtraChatLinkshell7 = 1007,
|
||||||
ExtraChatLinkshell8 = 1008,
|
ExtraChatLinkshell8 = 1008,
|
||||||
|
|
||||||
|
Invalid = 9999,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ internal static class InputChannelExt
|
|||||||
InputChannel.ExtraChatLinkshell6 => ChatType.ExtraChatLinkshell6,
|
InputChannel.ExtraChatLinkshell6 => ChatType.ExtraChatLinkshell6,
|
||||||
InputChannel.ExtraChatLinkshell7 => ChatType.ExtraChatLinkshell7,
|
InputChannel.ExtraChatLinkshell7 => ChatType.ExtraChatLinkshell7,
|
||||||
InputChannel.ExtraChatLinkshell8 => ChatType.ExtraChatLinkshell8,
|
InputChannel.ExtraChatLinkshell8 => ChatType.ExtraChatLinkshell8,
|
||||||
|
InputChannel.Invalid => ChatType.Echo,
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(input), input, null),
|
_ => throw new ArgumentOutOfRangeException(nameof(input), input, null),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -107,6 +108,7 @@ internal static class InputChannelExt
|
|||||||
InputChannel.ExtraChatLinkshell6 => "/ecl6",
|
InputChannel.ExtraChatLinkshell6 => "/ecl6",
|
||||||
InputChannel.ExtraChatLinkshell7 => "/ecl7",
|
InputChannel.ExtraChatLinkshell7 => "/ecl7",
|
||||||
InputChannel.ExtraChatLinkshell8 => "/ecl8",
|
InputChannel.ExtraChatLinkshell8 => "/ecl8",
|
||||||
|
InputChannel.Invalid => "/e",
|
||||||
_ => "",
|
_ => "",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -187,4 +189,10 @@ internal static class InputChannelExt
|
|||||||
InputChannel.ExtraChatLinkshell8 => true,
|
InputChannel.ExtraChatLinkshell8 => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
internal static bool IsValid(this InputChannel channel) => channel switch
|
||||||
|
{
|
||||||
|
InputChannel.Invalid => false,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,8 +241,7 @@ internal class Tab
|
|||||||
[NonSerialized] public long LastActivity;
|
[NonSerialized] public long LastActivity;
|
||||||
[NonSerialized] public MessageList Messages = new();
|
[NonSerialized] public MessageList Messages = new();
|
||||||
|
|
||||||
[NonSerialized] public TellTarget? TellTarget;
|
[NonSerialized] public UsedChannel CurrentChannel = new();
|
||||||
[NonSerialized] public InputChannel? PreviousChannel;
|
|
||||||
|
|
||||||
[NonSerialized] public Guid Identifier = Guid.NewGuid();
|
[NonSerialized] public Guid Identifier = Guid.NewGuid();
|
||||||
|
|
||||||
@@ -271,6 +270,8 @@ internal class Tab
|
|||||||
ExtraChatChannels = ExtraChatChannels.ToHashSet(),
|
ExtraChatChannels = ExtraChatChannels.ToHashSet(),
|
||||||
UnreadMode = UnreadMode,
|
UnreadMode = UnreadMode,
|
||||||
UnhideOnActivity = UnhideOnActivity,
|
UnhideOnActivity = UnhideOnActivity,
|
||||||
|
Unread = Unread,
|
||||||
|
LastActivity = LastActivity,
|
||||||
DisplayTimestamp = DisplayTimestamp,
|
DisplayTimestamp = DisplayTimestamp,
|
||||||
Channel = Channel,
|
Channel = Channel,
|
||||||
PopOut = PopOut,
|
PopOut = PopOut,
|
||||||
@@ -278,6 +279,7 @@ internal class Tab
|
|||||||
Opacity = Opacity,
|
Opacity = Opacity,
|
||||||
Identifier = Identifier,
|
Identifier = Identifier,
|
||||||
InputDisabled = InputDisabled,
|
InputDisabled = InputDisabled,
|
||||||
|
CurrentChannel = CurrentChannel,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,6 +424,16 @@ internal class Tab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class UsedChannel
|
||||||
|
{
|
||||||
|
internal InputChannel Channel = InputChannel.Invalid;
|
||||||
|
internal List<Chunk> Name = [];
|
||||||
|
internal TellTarget? TellTarget;
|
||||||
|
|
||||||
|
internal bool UseTempChannel;
|
||||||
|
internal InputChannel TempChannel = InputChannel.Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal enum PreviewPosition
|
internal enum PreviewPosition
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,15 +52,6 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
|
|
||||||
private Plugin Plugin { get; }
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Holds the current game channel details.
|
|
||||||
/// `TellPlayerName` and `TellWorldId` are only set when the channel is `InputChannel.Tell`.
|
|
||||||
/// </summary>
|
|
||||||
internal (InputChannel Channel, List<Chunk> Name, string? TellPlayerName, ushort TellWorldId) Channel { get; private set; }
|
|
||||||
|
|
||||||
internal bool UsesTellTempChannel { get; set; }
|
|
||||||
internal InputChannel? PreviousChannel { get; private set; }
|
|
||||||
|
|
||||||
private enum PlayerNameDisplayType : uint
|
private enum PlayerNameDisplayType : uint
|
||||||
{
|
{
|
||||||
FullName = 0,
|
FullName = 0,
|
||||||
@@ -171,7 +162,7 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
|
|
||||||
private byte ChatLogRefreshDetour(nint log, ushort eventId, AtkValue* value)
|
private byte ChatLogRefreshDetour(nint log, ushort eventId, AtkValue* value)
|
||||||
{
|
{
|
||||||
if (Plugin is { ChatLogWindow.CurrentTab.InputDisabled: true })
|
if (Plugin.CurrentTab.InputDisabled)
|
||||||
return ChatLogRefreshHook!.Original(log, eventId, value);
|
return ChatLogRefreshHook!.Original(log, eventId, value);
|
||||||
|
|
||||||
if (eventId != 0x31 || value == null || value->UInt is not (0x05 or 0x0C))
|
if (eventId != 0x31 || value == null || value->UInt is not (0x05 or 0x0C))
|
||||||
@@ -263,7 +254,12 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
Plugin.Log.Debug($"Detected tell target '{playerName}'@{worldId}");
|
Plugin.Log.Debug($"Detected tell target '{playerName}'@{worldId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel = ((InputChannel) channel, nameChunks, playerName, worldId);
|
Plugin.CurrentTab.CurrentChannel = new UsedChannel
|
||||||
|
{
|
||||||
|
Channel = (InputChannel) channel,
|
||||||
|
Name = nameChunks,
|
||||||
|
TellTarget = playerName != null ? new TellTarget(playerName, worldId, 0, 0) : null,
|
||||||
|
};
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -305,11 +301,8 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
|
|
||||||
private void ContextMenuTellInForayDetour(RaptureShellModule* a1, Utf8String* playerName, Utf8String* worldName, ushort worldId, ulong accountId, ulong contentId, ushort reason)
|
private void ContextMenuTellInForayDetour(RaptureShellModule* a1, Utf8String* playerName, Utf8String* worldName, ushort worldId, ulong accountId, ulong contentId, ushort reason)
|
||||||
{
|
{
|
||||||
if (!UsesTellTempChannel)
|
if (!Plugin.CurrentTab.CurrentChannel.UseTempChannel)
|
||||||
{
|
Plugin.CurrentTab.CurrentChannel.UseTempChannel = true;
|
||||||
UsesTellTempChannel = true;
|
|
||||||
PreviousChannel = Channel.Channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerName != null)
|
if (playerName != null)
|
||||||
{
|
{
|
||||||
@@ -411,7 +404,7 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void SetChannel(InputChannel channel, string? tellTarget = null)
|
internal void SetChannel(InputChannel channel, TellTarget? tellTarget = null)
|
||||||
{
|
{
|
||||||
// ExtraChat linkshells aren't supported in game so we never want to
|
// ExtraChat linkshells aren't supported in game so we never want to
|
||||||
// call the ChangeChatChannel function with them.
|
// call the ChangeChatChannel function with them.
|
||||||
@@ -421,14 +414,15 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
if (channel.IsExtraChatLinkshell())
|
if (channel.IsExtraChatLinkshell())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var target = Utf8String.FromString(tellTarget ?? "");
|
var target = Utf8String.FromString(tellTarget?.ToTargetString() ?? "");
|
||||||
var idx = channel.LinkshellIndex();
|
var idx = channel.LinkshellIndex();
|
||||||
if (idx == uint.MaxValue)
|
if (idx == uint.MaxValue)
|
||||||
idx = 0;
|
idx = 0;
|
||||||
|
|
||||||
if (!ValidAnyLinkshell(channel))
|
if (!ValidAnyLinkshell(channel))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RaptureShellModule.Instance()->ChangeChatChannel((int) channel, idx, target, true);
|
RaptureShellModule.Instance()->ChangeChatChannel(tellTarget != null ? 17 : (int)channel, idx, target, true);
|
||||||
target->Dtor(true);
|
target->Dtor(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,11 +431,8 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
// param6 is 0 for contentId and 1 for objectId
|
// param6 is 0 for contentId and 1 for objectId
|
||||||
// param7 is always 0 ?
|
// param7 is always 0 ?
|
||||||
|
|
||||||
if (!UsesTellTempChannel)
|
if (!Plugin.CurrentTab.CurrentChannel.UseTempChannel)
|
||||||
{
|
Plugin.CurrentTab.CurrentChannel.UseTempChannel = true;
|
||||||
UsesTellTempChannel = true;
|
|
||||||
PreviousChannel = Channel.Channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
var utfName = Utf8String.FromString(name);
|
var utfName = Utf8String.FromString(name);
|
||||||
var utfWorld = Utf8String.FromString(worldName);
|
var utfWorld = Utf8String.FromString(worldName);
|
||||||
@@ -492,6 +483,16 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
if (reason == TellReason.Direct)
|
if (reason == TellReason.Direct)
|
||||||
reason = TellReason.Friend;
|
reason = TellReason.Friend;
|
||||||
|
|
||||||
|
if (contentId == 0)
|
||||||
|
{
|
||||||
|
encoded->Dtor(true);
|
||||||
|
uName->Dtor(true);
|
||||||
|
uMessage->Dtor(true);
|
||||||
|
|
||||||
|
Plugin.Log.Warning("Tried to send a tell with content id being 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var ok = SendTellNative(networkModule, contentId, homeWorld, uName, encoded, (ushort) reason, homeWorld);
|
var ok = SendTellNative(networkModule, contentId, homeWorld, uName, encoded, (ushort) reason, homeWorld);
|
||||||
if (ok == 1)
|
if (ok == 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ internal static unsafe class Party
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void InviteOtherWorld(ulong contentId)
|
internal static void InviteOtherWorld(ulong contentId, ushort worldId = 0)
|
||||||
{
|
{
|
||||||
// third param is world, but it requires a specific world
|
// third param is world, but it requires a specific world
|
||||||
// if they're not on that world, it will fail
|
// if they're not on that world, it will fail
|
||||||
@@ -28,7 +28,7 @@ internal static unsafe class Party
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoProxyPartyInvite.Instance()->InviteToPartyContentId(contentId, 0);
|
InfoProxyPartyInvite.Instance()->InviteToPartyContentId(contentId, worldId);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void InviteInInstance(ulong contentId)
|
internal static void InviteInInstance(ulong contentId)
|
||||||
|
|||||||
@@ -14,4 +14,9 @@ internal sealed class TellTarget
|
|||||||
ContentId = contentId;
|
ContentId = contentId;
|
||||||
Reason = reason;
|
Reason = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsSet() => Name.Length > 0 && World > 0;
|
||||||
|
|
||||||
|
public string ToWorldString() => Sheets.WorldSheet.TryGetRow(World, out var worldRow) ? worldRow.Name.ExtractText() : string.Empty;
|
||||||
|
public string ToTargetString() => $"{Name}@{ToWorldString()}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ public class Processing
|
|||||||
|
|
||||||
internal (MessageTemplate[] ChannelName, bool Locked) ReadChannelName(Chunk[] channelName)
|
internal (MessageTemplate[] ChannelName, bool Locked) ReadChannelName(Chunk[] channelName)
|
||||||
{
|
{
|
||||||
var locked = Plugin.ChatLogWindow.CurrentTab is not { Channel: null };
|
var locked = Plugin.CurrentTab is not { Channel: null };
|
||||||
return (channelName.Select(ProcessChunk).ToArray(), locked);
|
return (channelName.Select(ProcessChunk).ToArray(), locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<MessageResponse[]> ReadMessageList()
|
internal async Task<MessageResponse[]> ReadMessageList()
|
||||||
{
|
{
|
||||||
var tabMessages = await Plugin.ChatLogWindow.CurrentTab!.Messages.GetCopy();
|
var tabMessages = await Plugin.CurrentTab!.Messages.GetCopy();
|
||||||
return tabMessages.TakeLast(Plugin.Config.WebinterfaceMaxLinesToSend).Select(ReadMessageContent).ToArray();
|
return tabMessages.TakeLast(Plugin.Config.WebinterfaceMaxLinesToSend).Select(ReadMessageContent).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -154,12 +154,6 @@ public class RouteController
|
|||||||
#region PostAuthRoutes
|
#region PostAuthRoutes
|
||||||
private async Task ChatBoxRoute(HttpContextBase ctx)
|
private async Task ChatBoxRoute(HttpContextBase ctx)
|
||||||
{
|
{
|
||||||
if (Plugin.ChatLogWindow.CurrentTab == null)
|
|
||||||
{
|
|
||||||
await ctx.Response.Send("No valid chat tab!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await ctx.Response.Send(ChatBoxTemplate);
|
await ctx.Response.Send(ChatBoxTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +177,7 @@ public class RouteController
|
|||||||
await Plugin.Framework.RunOnFrameworkThread(() =>
|
await Plugin.Framework.RunOnFrameworkThread(() =>
|
||||||
{
|
{
|
||||||
Plugin.ChatLogWindow.Chat = content.Message;
|
Plugin.ChatLogWindow.Chat = content.Message;
|
||||||
Plugin.ChatLogWindow.SendChatBox(Plugin.ChatLogWindow.CurrentTab);
|
Plugin.ChatLogWindow.SendChatBox(Plugin.CurrentTab);
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.Response.StatusCode = 201;
|
ctx.Response.StatusCode = 201;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using ChatTwo.Http.MessageProtocol;
|
using ChatTwo.Http.MessageProtocol;
|
||||||
|
|
||||||
namespace ChatTwo.Http;
|
namespace ChatTwo.Http;
|
||||||
|
|
||||||
public class ServerCore : IAsyncDisposable
|
public class ServerCore : IAsyncDisposable
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ internal class MessageManager : IAsyncDisposable
|
|||||||
if (Plugin.Config.DatabaseBattleMessages || !message.Code.IsBattle())
|
if (Plugin.Config.DatabaseBattleMessages || !message.Code.IsBattle())
|
||||||
Store.UpsertMessage(message);
|
Store.UpsertMessage(message);
|
||||||
|
|
||||||
var currentTabId = Plugin.ChatLogWindow.CurrentTab?.Identifier ?? Guid.Empty;
|
var currentTabId = Plugin.CurrentTab.Identifier;
|
||||||
var currentMatches = Plugin.ChatLogWindow.CurrentTab?.Matches(message) ?? false;
|
var currentMatches = Plugin.CurrentTab.Matches(message);
|
||||||
foreach (var tab in Plugin.Config.Tabs)
|
foreach (var tab in Plugin.Config.Tabs)
|
||||||
{
|
{
|
||||||
var unread = !(tab.UnreadMode == UnreadMode.Unseen && Plugin.ChatLogWindow.CurrentTab != tab && currentMatches);
|
var unread = !(tab.UnreadMode == UnreadMode.Unseen && Plugin.CurrentTab != tab && currentMatches);
|
||||||
|
|
||||||
if (tab.Matches(message))
|
if (tab.Matches(message))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -585,7 +585,7 @@ public sealed class PayloadHandler {
|
|||||||
GameFunctions.Party.InviteSameWorld(player.PlayerName, (ushort) world.RowId, chunk.Message?.ContentId ?? 0);
|
GameFunctions.Party.InviteSameWorld(player.PlayerName, (ushort) world.RowId, chunk.Message?.ContentId ?? 0);
|
||||||
|
|
||||||
if (validContentId && ImGui.Selectable(Language.Context_InviteToParty_DifferentWorld))
|
if (validContentId && ImGui.Selectable(Language.Context_InviteToParty_DifferentWorld))
|
||||||
GameFunctions.Party.InviteOtherWorld(chunk.Message!.ContentId);
|
GameFunctions.Party.InviteOtherWorld(chunk.Message!.ContentId, (ushort) world.RowId);
|
||||||
|
|
||||||
ImGui.EndMenu();
|
ImGui.EndMenu();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,18 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
|
|
||||||
internal DateTime GameStarted { get; }
|
internal DateTime GameStarted { get; }
|
||||||
|
|
||||||
|
// Tab managed needs to happen outside the chatlog window class for access reasons
|
||||||
|
internal int LastTab { get; set; }
|
||||||
|
internal int? WantedTab { get; set; }
|
||||||
|
internal Tab CurrentTab
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var i = LastTab;
|
||||||
|
return i > -1 && i < Config.Tabs.Count ? Config.Tabs[i] : new Tab();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Plugin()
|
public Plugin()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
+116
-125
@@ -20,7 +20,6 @@ using Dalamud.Interface.Windowing;
|
|||||||
using Dalamud.Memory;
|
using Dalamud.Memory;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Info;
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Lumina.Excel.Sheets;
|
using Lumina.Excel.Sheets;
|
||||||
|
|
||||||
@@ -41,24 +40,12 @@ public sealed class ChatLogWindow : Window
|
|||||||
|
|
||||||
internal Vector4 DefaultText { get; set; }
|
internal Vector4 DefaultText { get; set; }
|
||||||
|
|
||||||
internal int? WantedTab { get; set; }
|
|
||||||
internal Tab? CurrentTab
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var i = LastTab;
|
|
||||||
return i > -1 && i < Plugin.Config.Tabs.Count ? Plugin.Config.Tabs[i] : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool FocusedPreview;
|
internal bool FocusedPreview;
|
||||||
internal bool Activate;
|
internal bool Activate;
|
||||||
private int ActivatePos = -1;
|
private int ActivatePos = -1;
|
||||||
internal string Chat = string.Empty;
|
internal string Chat = string.Empty;
|
||||||
private readonly List<string> InputBacklog = [];
|
private readonly List<string> InputBacklog = [];
|
||||||
private int InputBacklogIdx = -1;
|
private int InputBacklogIdx = -1;
|
||||||
private int LastTab { get; set; }
|
|
||||||
private InputChannel? TempChannel;
|
|
||||||
public bool TellSpecial;
|
public bool TellSpecial;
|
||||||
private readonly Stopwatch LastResize = new();
|
private readonly Stopwatch LastResize = new();
|
||||||
private AutoCompleteInfo? AutoCompleteInfo;
|
private AutoCompleteInfo? AutoCompleteInfo;
|
||||||
@@ -141,10 +128,6 @@ public sealed class ChatLogWindow : Window
|
|||||||
|
|
||||||
internal unsafe void Activated(ChatActivatedArgs args)
|
internal unsafe void Activated(ChatActivatedArgs args)
|
||||||
{
|
{
|
||||||
// Return if we don't have a tab selected
|
|
||||||
if (CurrentTab == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TellSpecial = args.TellSpecial;
|
TellSpecial = args.TellSpecial;
|
||||||
|
|
||||||
Activate = true;
|
Activate = true;
|
||||||
@@ -153,7 +136,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
UIModule.PlaySound(ChatOpenSfx);
|
UIModule.PlaySound(ChatOpenSfx);
|
||||||
|
|
||||||
// Don't set the channel or text content when activating a disabled tab.
|
// Don't set the channel or text content when activating a disabled tab.
|
||||||
if (CurrentTab?.InputDisabled == true)
|
if (Plugin.CurrentTab.InputDisabled)
|
||||||
{
|
{
|
||||||
// The closing sound would've been immediately played in this case.
|
// The closing sound would've been immediately played in this case.
|
||||||
PlayedClosingSound = true;
|
PlayedClosingSound = true;
|
||||||
@@ -175,24 +158,26 @@ public sealed class ChatLogWindow : Window
|
|||||||
{
|
{
|
||||||
if (info.Rotate != RotateMode.None)
|
if (info.Rotate != RotateMode.None)
|
||||||
{
|
{
|
||||||
var idx = TempChannel != InputChannel.Tell
|
var idx = Plugin.CurrentTab.CurrentChannel.TempChannel != InputChannel.Tell
|
||||||
? 0 : info.Rotate == RotateMode.Reverse
|
? 0 : info.Rotate == RotateMode.Reverse
|
||||||
? -1 : 1;
|
? -1 : 1;
|
||||||
|
|
||||||
var tellInfo = Plugin.Functions.Chat.GetTellHistoryInfo(idx);
|
var tellInfo = Plugin.Functions.Chat.GetTellHistoryInfo(idx);
|
||||||
if (tellInfo != null && reason != null)
|
if (tellInfo != null && reason != null)
|
||||||
CurrentTab!.TellTarget = new TellTarget(tellInfo.Name, (ushort) tellInfo.World, tellInfo.ContentId, reason.Value);
|
{
|
||||||
|
Plugin.CurrentTab.CurrentChannel.TellTarget = new TellTarget(tellInfo.Name, (ushort) tellInfo.World, tellInfo.ContentId, reason.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CurrentTab!.TellTarget = null;
|
Plugin.CurrentTab.CurrentChannel.TellTarget = null;
|
||||||
if (target != null)
|
if (target != null)
|
||||||
CurrentTab!.TellTarget = target;
|
Plugin.CurrentTab.CurrentChannel.TellTarget = target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CurrentTab!.TellTarget = null;
|
Plugin.CurrentTab.CurrentChannel.TellTarget = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.Channel is InputChannel.Linkshell1 or InputChannel.CrossLinkshell1 && info.Rotate != RotateMode.None)
|
if (info.Channel is InputChannel.Linkshell1 or InputChannel.CrossLinkshell1 && info.Rotate != RotateMode.None)
|
||||||
@@ -215,7 +200,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
targetChannel = GameFunctions.Chat.ResolveTempInputChannel(TempChannel, info.Channel.Value, info.Rotate);
|
targetChannel = GameFunctions.Chat.ResolveTempInputChannel(Plugin.CurrentTab.CurrentChannel.TempChannel, info.Channel.Value, info.Rotate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,9 +211,11 @@ public sealed class ChatLogWindow : Window
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (info.Permanent)
|
if (info.Permanent)
|
||||||
|
{
|
||||||
SetChannel(targetChannel);
|
SetChannel(targetChannel);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
TempChannel = targetChannel;
|
Plugin.CurrentTab.CurrentChannel.TempChannel = targetChannel.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.Text != null && Chat.Length == 0)
|
if (info.Text != null && Chat.Length == 0)
|
||||||
@@ -253,8 +240,8 @@ public sealed class ChatLogWindow : Window
|
|||||||
Plugin.ChatGui.Print("- /clearlog2 help: shows this help");
|
Plugin.ChatGui.Print("- /clearlog2 help: shows this help");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (LastTab > -1 && LastTab < Plugin.Config.Tabs.Count)
|
if (Plugin.LastTab > -1 && Plugin.LastTab < Plugin.Config.Tabs.Count)
|
||||||
Plugin.Config.Tabs[LastTab].Clear();
|
Plugin.Config.Tabs[Plugin.LastTab].Clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,31 +341,27 @@ public sealed class ChatLogWindow : Window
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void ChangeTab(int index) {
|
internal void ChangeTab(int index) {
|
||||||
WantedTab = index;
|
Plugin.WantedTab = index;
|
||||||
LastActivityTime = FrameTime;
|
LastActivityTime = FrameTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ChangeTabDelta(int offset)
|
internal void ChangeTabDelta(int offset)
|
||||||
{
|
{
|
||||||
var newIndex = (LastTab + offset) % Plugin.Config.Tabs.Count;
|
var newIndex = (Plugin.LastTab + offset) % Plugin.Config.Tabs.Count;
|
||||||
while (newIndex < 0)
|
while (newIndex < 0)
|
||||||
newIndex += Plugin.Config.Tabs.Count;
|
newIndex += Plugin.Config.Tabs.Count;
|
||||||
ChangeTab(newIndex);
|
ChangeTab(newIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TabChannelSwitch(Tab tab)
|
private void TabChannelSwitch(Tab newTab, Tab previousTab)
|
||||||
{
|
{
|
||||||
// Save the previous channel to restore it later
|
// Use the fixed channel if set by the user, or set it to the current tabs channel if this tab wasn't accessed before
|
||||||
var current = CurrentTab;
|
if (newTab.Channel is not null)
|
||||||
if (current is { Channel: null })
|
newTab.CurrentChannel.Channel = newTab.Channel.Value;
|
||||||
current.PreviousChannel = Plugin.Functions.Chat.Channel.Channel;
|
else if (newTab.CurrentChannel.Channel is InputChannel.Invalid)
|
||||||
|
newTab.CurrentChannel = previousTab.CurrentChannel;
|
||||||
|
|
||||||
// Channel will be null if PreviousChannel is used
|
SetChannel(newTab.CurrentChannel.Channel);
|
||||||
var channel = tab.Channel ?? tab.PreviousChannel;
|
|
||||||
|
|
||||||
// If channel is null it doesn't have a default, and we never selected this channel before
|
|
||||||
if (channel != null)
|
|
||||||
SetChannel(tab.Channel ?? tab.PreviousChannel);
|
|
||||||
|
|
||||||
// Inform the webinterface about tab switch
|
// Inform the webinterface about tab switch
|
||||||
// TODO implement tabs in the webinterface
|
// TODO implement tabs in the webinterface
|
||||||
@@ -475,7 +458,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentTab = CurrentTab; // local to avoid calling the getter repeatedly
|
var currentTab = Plugin.CurrentTab; // local to avoid calling the getter repeatedly
|
||||||
var lastActivityTime = Plugin.Config.Tabs
|
var lastActivityTime = Plugin.Config.Tabs
|
||||||
.Where(tab => !tab.PopOut && (tab.UnhideOnActivity || tab == currentTab))
|
.Where(tab => !tab.PopOut && (tab.UnhideOnActivity || tab == currentTab))
|
||||||
.Select(tab => tab.LastActivity)
|
.Select(tab => tab.LastActivity)
|
||||||
@@ -499,7 +482,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
// the text input in a tab with input disabled. The usual way that
|
// the text input in a tab with input disabled. The usual way that
|
||||||
// Activate gets disabled is via the text input callback, but that
|
// Activate gets disabled is via the text input callback, but that
|
||||||
// doesn't get called if the input is disabled.
|
// doesn't get called if the input is disabled.
|
||||||
if (CurrentTab?.InputDisabled == true)
|
if (Plugin.CurrentTab.InputDisabled == true)
|
||||||
Activate = false;
|
Activate = false;
|
||||||
if (Plugin.Config is { OverrideStyle: true, ChosenStyle: not null })
|
if (Plugin.Config is { OverrideStyle: true, ChosenStyle: not null })
|
||||||
StyleModel.GetConfiguredStyles()?.FirstOrDefault(style => style.Name == Plugin.Config.ChosenStyle)?.Pop();
|
StyleModel.GetConfiguredStyles()?.FirstOrDefault(style => style.Name == Plugin.Config.ChosenStyle)?.Pop();
|
||||||
@@ -548,12 +531,12 @@ public sealed class ChatLogWindow : Window
|
|||||||
if (IsChatMode && Plugin.InputPreview.IsDrawable)
|
if (IsChatMode && Plugin.InputPreview.IsDrawable)
|
||||||
Plugin.InputPreview.CalculatePreview();
|
Plugin.InputPreview.CalculatePreview();
|
||||||
|
|
||||||
var currentTab = Plugin.Config.SidebarTabView ? DrawTabSidebar() : DrawTabBar();
|
if (Plugin.Config.SidebarTabView)
|
||||||
|
DrawTabSidebar();
|
||||||
Tab? activeTab = null;
|
else
|
||||||
if (currentTab > -1 && currentTab < Plugin.Config.Tabs.Count)
|
DrawTabBar();
|
||||||
activeTab = Plugin.Config.Tabs[currentTab];
|
|
||||||
|
|
||||||
|
var activeTab = Plugin.CurrentTab;
|
||||||
if (Plugin.Config.PreviewPosition is PreviewPosition.Inside && Plugin.InputPreview.IsDrawable)
|
if (Plugin.Config.PreviewPosition is PreviewPosition.Inside && Plugin.InputPreview.IsDrawable)
|
||||||
Plugin.InputPreview.DrawPreview();
|
Plugin.InputPreview.DrawPreview();
|
||||||
|
|
||||||
@@ -563,10 +546,10 @@ public sealed class ChatLogWindow : Window
|
|||||||
}
|
}
|
||||||
|
|
||||||
var beforeIcon = ImGui.GetCursorPos();
|
var beforeIcon = ImGui.GetCursorPos();
|
||||||
if (ImGuiUtil.IconButton(FontAwesomeIcon.Comment) && activeTab is not { Channel: not null })
|
if (ImGuiUtil.IconButton(FontAwesomeIcon.Comment) && activeTab.Channel is null)
|
||||||
ImGui.OpenPopup(ChatChannelPicker);
|
ImGui.OpenPopup(ChatChannelPicker);
|
||||||
|
|
||||||
if (activeTab is { Channel: not null } && ImGui.IsItemHovered())
|
if (activeTab.Channel is not null && ImGui.IsItemHovered())
|
||||||
ImGui.SetTooltip(Language.ChatLog_SwitcherDisabled);
|
ImGui.SetTooltip(Language.ChatLog_SwitcherDisabled);
|
||||||
|
|
||||||
using (var popup = ImRaii.Popup(ChatChannelPicker))
|
using (var popup = ImRaii.Popup(ChatChannelPicker))
|
||||||
@@ -588,7 +571,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
var buttonsRight = (showNovice ? 1 : 0) + (Plugin.Config.ShowHideButton ? 1 : 0);
|
var buttonsRight = (showNovice ? 1 : 0) + (Plugin.Config.ShowHideButton ? 1 : 0);
|
||||||
var inputWidth = ImGui.GetContentRegionAvail().X - buttonWidth * (1 + buttonsRight);
|
var inputWidth = ImGui.GetContentRegionAvail().X - buttonWidth * (1 + buttonsRight);
|
||||||
|
|
||||||
var inputType = TempChannel?.ToChatType() ?? activeTab?.Channel?.ToChatType() ?? Plugin.Functions.Chat.Channel.Channel.ToChatType();
|
var inputType = activeTab.CurrentChannel.UseTempChannel ? activeTab.CurrentChannel.TempChannel.ToChatType() : activeTab.CurrentChannel.Channel.ToChatType();
|
||||||
var isCommand = Chat.Trim().StartsWith('/');
|
var isCommand = Chat.Trim().StartsWith('/');
|
||||||
if (isCommand)
|
if (isCommand)
|
||||||
{
|
{
|
||||||
@@ -642,10 +625,10 @@ public sealed class ChatLogWindow : Window
|
|||||||
{
|
{
|
||||||
Chat = chatCopy;
|
Chat = chatCopy;
|
||||||
|
|
||||||
if (Plugin.Functions.Chat.UsesTellTempChannel)
|
if (activeTab.CurrentChannel.UseTempChannel)
|
||||||
{
|
{
|
||||||
Plugin.Functions.Chat.UsesTellTempChannel = false;
|
activeTab.CurrentChannel.UseTempChannel = false;
|
||||||
SetChannel(Plugin.Functions.Chat.PreviousChannel);
|
SetChannel(activeTab.CurrentChannel.Channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -654,10 +637,10 @@ public sealed class ChatLogWindow : Window
|
|||||||
Plugin.CommandHelpWindow.IsOpen = false;
|
Plugin.CommandHelpWindow.IsOpen = false;
|
||||||
SendChatBox(activeTab);
|
SendChatBox(activeTab);
|
||||||
|
|
||||||
if (Plugin.Functions.Chat.UsesTellTempChannel)
|
if (activeTab.CurrentChannel.UseTempChannel)
|
||||||
{
|
{
|
||||||
Plugin.Functions.Chat.UsesTellTempChannel = false;
|
activeTab.CurrentChannel.UseTempChannel = false;
|
||||||
SetChannel(Plugin.Functions.Chat.PreviousChannel);
|
SetChannel(activeTab.CurrentChannel.Channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -678,14 +661,10 @@ public sealed class ChatLogWindow : Window
|
|||||||
UIModule.PlaySound(ChatCloseSfx);
|
UIModule.PlaySound(ChatCloseSfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TempChannel is InputChannel.Tell && CurrentTab != null)
|
if (Plugin.CurrentTab.CurrentChannel.UseTempChannel)
|
||||||
CurrentTab.TellTarget = null;
|
|
||||||
|
|
||||||
TempChannel = null;
|
|
||||||
if (Plugin.Functions.Chat.UsesTellTempChannel)
|
|
||||||
{
|
{
|
||||||
Plugin.Functions.Chat.UsesTellTempChannel = false;
|
Plugin.CurrentTab.CurrentChannel.UseTempChannel = false;
|
||||||
SetChannel(Plugin.Functions.Chat.PreviousChannel);
|
SetChannel(Plugin.CurrentTab.CurrentChannel.Channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -729,6 +708,9 @@ public sealed class ChatLogWindow : Window
|
|||||||
var channels = new Dictionary<string, InputChannel>();
|
var channels = new Dictionary<string, InputChannel>();
|
||||||
foreach (var channel in Enum.GetValues<InputChannel>())
|
foreach (var channel in Enum.GetValues<InputChannel>())
|
||||||
{
|
{
|
||||||
|
if (!channel.IsValid())
|
||||||
|
continue;
|
||||||
|
|
||||||
var name = Sheets.LogFilterSheet.FirstOrNull(row => row.LogKind == (byte) channel.ToChatType())?.Name.ExtractText() ?? channel.ToChatType().Name();
|
var name = Sheets.LogFilterSheet.FirstOrNull(row => row.LogKind == (byte) channel.ToChatType())?.Name.ExtractText() ?? channel.ToChatType().Name();
|
||||||
if (channel.IsLinkshell())
|
if (channel.IsLinkshell())
|
||||||
{
|
{
|
||||||
@@ -763,32 +745,31 @@ public sealed class ChatLogWindow : Window
|
|||||||
return channels;
|
return channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawChannelName(Tab? activeTab)
|
private void DrawChannelName(Tab activeTab)
|
||||||
{
|
{
|
||||||
var currentChannel = ReadChannelName(activeTab);
|
var currentChannel = ReadChannelName(activeTab);
|
||||||
|
|
||||||
if (!currentChannel.SequenceEqual(PreviousChannel))
|
if (!currentChannel.SequenceEqual(PreviousChannel))
|
||||||
{
|
{
|
||||||
PreviousChannel = currentChannel;
|
PreviousChannel = currentChannel;
|
||||||
Plugin.ServerCore?.SendChannelSwitch(currentChannel);
|
Plugin.ServerCore?.SendChannelSwitch(currentChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawChunks(ReadChannelName(activeTab));
|
DrawChunks(currentChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Chunk[] ReadChannelName(Tab? activeTab)
|
internal Chunk[] ReadChannelName(Tab activeTab)
|
||||||
{
|
{
|
||||||
Chunk[] channelNameChunks;
|
Chunk[] channelNameChunks;
|
||||||
if (activeTab?.TellTarget != null)
|
if (activeTab.CurrentChannel.TellTarget != null && activeTab.CurrentChannel.TellTarget.IsSet())
|
||||||
{
|
{
|
||||||
var playerName = activeTab.TellTarget.Name;
|
var playerName = activeTab.CurrentChannel.TellTarget.Name;
|
||||||
if (ScreenshotMode)
|
if (ScreenshotMode)
|
||||||
// Note: don't use HidePlayerInString here because
|
// Note: don't use HidePlayerInString here because
|
||||||
// abbreviation settings do not affect this.
|
// abbreviation settings do not affect this.
|
||||||
playerName = HashPlayer(activeTab.TellTarget.Name, activeTab.TellTarget.World);
|
playerName = HashPlayer(activeTab.CurrentChannel.TellTarget.Name, activeTab.CurrentChannel.TellTarget.World);
|
||||||
|
|
||||||
var world = Sheets.WorldSheet.HasRow(activeTab.TellTarget.World)
|
var world = Sheets.WorldSheet.TryGetRow(activeTab.CurrentChannel.TellTarget.World, out var worldRow)
|
||||||
? Sheets.WorldSheet.GetRow(activeTab.TellTarget.World).Name.ExtractText()
|
? worldRow.Name.ExtractText()
|
||||||
: "???";
|
: "???";
|
||||||
|
|
||||||
channelNameChunks =
|
channelNameChunks =
|
||||||
@@ -799,24 +780,24 @@ public sealed class ChatLogWindow : Window
|
|||||||
new TextChunk(ChunkSource.None, null, world)
|
new TextChunk(ChunkSource.None, null, world)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
else if (TempChannel != null)
|
else if (activeTab.CurrentChannel.UseTempChannel)
|
||||||
{
|
{
|
||||||
string name;
|
string name;
|
||||||
if (TempChannel.Value.IsLinkshell())
|
if (activeTab.CurrentChannel.TempChannel.IsLinkshell())
|
||||||
{
|
{
|
||||||
var idx = (uint) TempChannel.Value - (uint) InputChannel.Linkshell1;
|
var idx = (uint) activeTab.CurrentChannel.TempChannel - (uint) InputChannel.Linkshell1;
|
||||||
var lsName = Plugin.Functions.Chat.GetLinkshellName(idx);
|
var lsName = Plugin.Functions.Chat.GetLinkshellName(idx);
|
||||||
name = $"LS #{idx + 1}: {lsName}";
|
name = $"LS #{idx + 1}: {lsName}";
|
||||||
}
|
}
|
||||||
else if (TempChannel.Value.IsCrossLinkshell())
|
else if (activeTab.CurrentChannel.TempChannel.IsCrossLinkshell())
|
||||||
{
|
{
|
||||||
var idx = (uint) TempChannel.Value - (uint) InputChannel.CrossLinkshell1;
|
var idx = (uint) activeTab.CurrentChannel.TempChannel - (uint) InputChannel.CrossLinkshell1;
|
||||||
var cwlsName = Plugin.Functions.Chat.GetCrossLinkshellName(idx);
|
var cwlsName = Plugin.Functions.Chat.GetCrossLinkshellName(idx);
|
||||||
name = $"CWLS [{idx + 1}]: {cwlsName}";
|
name = $"CWLS [{idx + 1}]: {cwlsName}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
name = TempChannel.Value.ToChatType().Name();
|
name = activeTab.CurrentChannel.TempChannel.ToChatType().Name();
|
||||||
}
|
}
|
||||||
|
|
||||||
channelNameChunks = [new TextChunk(ChunkSource.None, null, name)];
|
channelNameChunks = [new TextChunk(ChunkSource.None, null, name)];
|
||||||
@@ -835,15 +816,15 @@ public sealed class ChatLogWindow : Window
|
|||||||
{
|
{
|
||||||
channelNameChunks = [new TextChunk(ChunkSource.None, null, overrideName)];
|
channelNameChunks = [new TextChunk(ChunkSource.None, null, overrideName)];
|
||||||
}
|
}
|
||||||
else if (ScreenshotMode && Plugin.Functions.Chat.Channel is (InputChannel.Tell, _, var tellPlayerName, var tellWorldId))
|
else if (ScreenshotMode && activeTab.CurrentChannel.Channel is InputChannel.Tell && activeTab.CurrentChannel.TellTarget != null)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(tellPlayerName) && tellWorldId != 0)
|
if (!string.IsNullOrWhiteSpace(activeTab.CurrentChannel.TellTarget.Name) && activeTab.CurrentChannel.TellTarget.World != 0)
|
||||||
{
|
{
|
||||||
// Note: don't use HidePlayerInString here because
|
// Note: don't use HidePlayerInString here because
|
||||||
// abbreviation settings do not affect this.
|
// abbreviation settings do not affect this.
|
||||||
var playerName = HashPlayer(tellPlayerName, tellWorldId);
|
var playerName = HashPlayer(activeTab.CurrentChannel.TellTarget.Name, activeTab.CurrentChannel.TellTarget.World);
|
||||||
var world = Sheets.WorldSheet.HasRow(tellWorldId)
|
var world = Sheets.WorldSheet.TryGetRow(activeTab.CurrentChannel.TellTarget.World, out var worldRow)
|
||||||
? Sheets.WorldSheet.GetRow(tellWorldId).Name.ExtractText()
|
? worldRow.Name.ExtractText()
|
||||||
: "???";
|
: "???";
|
||||||
|
|
||||||
channelNameChunks =
|
channelNameChunks =
|
||||||
@@ -863,7 +844,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
channelNameChunks = Plugin.Functions.Chat.Channel.Name.ToArray();
|
channelNameChunks = activeTab.CurrentChannel.Name.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
return channelNameChunks;
|
return channelNameChunks;
|
||||||
@@ -872,8 +853,9 @@ public sealed class ChatLogWindow : Window
|
|||||||
internal void SetChannel(InputChannel? channel)
|
internal void SetChannel(InputChannel? channel)
|
||||||
{
|
{
|
||||||
channel ??= InputChannel.Say;
|
channel ??= InputChannel.Say;
|
||||||
if (CurrentTab != null)
|
|
||||||
CurrentTab.TellTarget = null;
|
if (channel != InputChannel.Tell)
|
||||||
|
Plugin.CurrentTab.CurrentChannel.TellTarget = null;
|
||||||
|
|
||||||
// Instead of calling SetChannel(), we ask the ExtraChat plugin to set a
|
// Instead of calling SetChannel(), we ask the ExtraChat plugin to set a
|
||||||
// channel override by just calling the command directly.
|
// channel override by just calling the command directly.
|
||||||
@@ -893,10 +875,10 @@ public sealed class ChatLogWindow : Window
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameFunctions.Chat.SetChannel(channel.Value);
|
Plugin.Functions.Chat.SetChannel(channel.Value, Plugin.CurrentTab.CurrentChannel.TellTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SendChatBox(Tab? activeTab)
|
internal void SendChatBox(Tab activeTab)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(Chat))
|
if (!string.IsNullOrWhiteSpace(Chat))
|
||||||
{
|
{
|
||||||
@@ -912,8 +894,9 @@ public sealed class ChatLogWindow : Window
|
|||||||
Plugin.Functions.Chat.SendTellUsingCommandInner(tellBytes);
|
Plugin.Functions.Chat.SendTellUsingCommandInner(tellBytes);
|
||||||
|
|
||||||
TellSpecial = false;
|
TellSpecial = false;
|
||||||
if (TempChannel is InputChannel.Tell && CurrentTab != null)
|
activeTab.CurrentChannel.UseTempChannel = false;
|
||||||
CurrentTab.TellTarget = null;
|
if (activeTab.CurrentChannel.TempChannel is InputChannel.Tell)
|
||||||
|
activeTab.CurrentChannel.TellTarget = null;
|
||||||
|
|
||||||
Chat = string.Empty;
|
Chat = string.Empty;
|
||||||
return;
|
return;
|
||||||
@@ -921,9 +904,22 @@ public sealed class ChatLogWindow : Window
|
|||||||
|
|
||||||
if (!trimmed.StartsWith('/'))
|
if (!trimmed.StartsWith('/'))
|
||||||
{
|
{
|
||||||
if (CurrentTab?.TellTarget != null)
|
var target = activeTab.CurrentChannel.TellTarget;
|
||||||
|
if (target != null)
|
||||||
{
|
{
|
||||||
var target = CurrentTab.TellTarget;
|
// ContentId 0 is a case where we can't directly send messages, so we send a /tell formatted message and let the game handle it
|
||||||
|
if (target.ContentId == 0)
|
||||||
|
{
|
||||||
|
trimmed = $"/tell {target.ToTargetString()} {trimmed}";
|
||||||
|
var tellBytes = Encoding.UTF8.GetBytes(trimmed);
|
||||||
|
AutoTranslate.ReplaceWithPayload(ref tellBytes);
|
||||||
|
|
||||||
|
Plugin.Common.SendMessageUnsafe(tellBytes);
|
||||||
|
|
||||||
|
Chat = string.Empty;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var reason = target.Reason;
|
var reason = target.Reason;
|
||||||
var world = Sheets.WorldSheet.GetRow(target.World);
|
var world = Sheets.WorldSheet.GetRow(target.World);
|
||||||
if (world is { IsPublic: true })
|
if (world is { IsPublic: true })
|
||||||
@@ -937,18 +933,17 @@ public sealed class ChatLogWindow : Window
|
|||||||
Plugin.Functions.Chat.SendTell(reason, target.ContentId, target.Name, (ushort) world.RowId, tellBytes, trimmed);
|
Plugin.Functions.Chat.SendTell(reason, target.ContentId, target.Name, (ushort) world.RowId, tellBytes, trimmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TempChannel is InputChannel.Tell)
|
if (activeTab.CurrentChannel.TempChannel is InputChannel.Tell)
|
||||||
CurrentTab.TellTarget = null;
|
activeTab.CurrentChannel.TellTarget = null;
|
||||||
|
|
||||||
Chat = string.Empty;
|
Chat = string.Empty;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (activeTab.CurrentChannel.UseTempChannel)
|
||||||
if (TempChannel != null)
|
trimmed = $"{activeTab.CurrentChannel.TempChannel.Prefix()} {trimmed}";
|
||||||
trimmed = $"{TempChannel.Value.Prefix()} {trimmed}";
|
else // (activeTab is { Channel: { } channel }) TODO Check this channel selection
|
||||||
else if (activeTab is { Channel: { } channel })
|
trimmed = $"{activeTab.CurrentChannel.Channel.Prefix()} {trimmed}";
|
||||||
trimmed = $"{channel.Prefix()} {trimmed}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytes = Encoding.UTF8.GetBytes(trimmed);
|
var bytes = Encoding.UTF8.GetBytes(trimmed);
|
||||||
@@ -1196,23 +1191,22 @@ public sealed class ChatLogWindow : Window
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int DrawTabBar()
|
private void DrawTabBar()
|
||||||
{
|
{
|
||||||
var currentTab = -1;
|
|
||||||
|
|
||||||
using var tabBar = ImRaii.TabBar("##chat2-tabs");
|
using var tabBar = ImRaii.TabBar("##chat2-tabs");
|
||||||
if (!tabBar.Success)
|
if (!tabBar.Success)
|
||||||
return currentTab;
|
return;
|
||||||
|
|
||||||
|
var previousTab = Plugin.CurrentTab;
|
||||||
for (var tabI = 0; tabI < Plugin.Config.Tabs.Count; tabI++)
|
for (var tabI = 0; tabI < Plugin.Config.Tabs.Count; tabI++)
|
||||||
{
|
{
|
||||||
var tab = Plugin.Config.Tabs[tabI];
|
var tab = Plugin.Config.Tabs[tabI];
|
||||||
if (tab.PopOut)
|
if (tab.PopOut)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var unread = tabI == LastTab || tab.UnreadMode == UnreadMode.None || tab.Unread == 0 ? "" : $" ({tab.Unread})";
|
var unread = tabI == Plugin.LastTab || tab.UnreadMode == UnreadMode.None || tab.Unread == 0 ? "" : $" ({tab.Unread})";
|
||||||
var flags = ImGuiTabItemFlags.None;
|
var flags = ImGuiTabItemFlags.None;
|
||||||
if (WantedTab == tabI)
|
if (Plugin.WantedTab == tabI)
|
||||||
flags |= ImGuiTabItemFlags.SetSelected;
|
flags |= ImGuiTabItemFlags.SetSelected;
|
||||||
using var tabItem = ImRaii.TabItem($"{tab.Name}{unread}###log-tab-{tabI}", flags);
|
using var tabItem = ImRaii.TabItem($"{tab.Name}{unread}###log-tab-{tabI}", flags);
|
||||||
DrawTabContextMenu(tab, tabI);
|
DrawTabContextMenu(tab, tabI);
|
||||||
@@ -1220,28 +1214,25 @@ public sealed class ChatLogWindow : Window
|
|||||||
if (!tabItem.Success)
|
if (!tabItem.Success)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
currentTab = tabI;
|
var switchedTab = Plugin.LastTab != tabI;
|
||||||
var switchedTab = LastTab != tabI;
|
|
||||||
|
Plugin.LastTab = tabI;
|
||||||
if (switchedTab)
|
if (switchedTab)
|
||||||
TabChannelSwitch(tab);
|
TabChannelSwitch(tab, previousTab);
|
||||||
|
|
||||||
LastTab = tabI;
|
|
||||||
tab.Unread = 0;
|
tab.Unread = 0;
|
||||||
|
|
||||||
DrawMessageLog(tab, PayloadHandler, GetRemainingHeightForMessageLog(), switchedTab);
|
DrawMessageLog(tab, PayloadHandler, GetRemainingHeightForMessageLog(), switchedTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
WantedTab = null;
|
Plugin.WantedTab = null;
|
||||||
return currentTab;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int DrawTabSidebar()
|
private void DrawTabSidebar()
|
||||||
{
|
{
|
||||||
var currentTab = -1;
|
var currentTab = -1;
|
||||||
|
|
||||||
using var tabTable = ImRaii.Table("tabs-table", 2, ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.Resizable);
|
using var tabTable = ImRaii.Table("tabs-table", 2, ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.Resizable);
|
||||||
if (!tabTable.Success)
|
if (!tabTable.Success)
|
||||||
return currentTab;
|
return;
|
||||||
|
|
||||||
ImGui.TableSetupColumn("tabs", ImGuiTableColumnFlags.None, 1);
|
ImGui.TableSetupColumn("tabs", ImGuiTableColumnFlags.None, 1);
|
||||||
ImGui.TableSetupColumn("chat", ImGuiTableColumnFlags.None, 4);
|
ImGui.TableSetupColumn("chat", ImGuiTableColumnFlags.None, 4);
|
||||||
@@ -1254,41 +1245,41 @@ public sealed class ChatLogWindow : Window
|
|||||||
{
|
{
|
||||||
if (child)
|
if (child)
|
||||||
{
|
{
|
||||||
|
var previousTab = Plugin.CurrentTab;
|
||||||
for (var tabI = 0; tabI < Plugin.Config.Tabs.Count; tabI++)
|
for (var tabI = 0; tabI < Plugin.Config.Tabs.Count; tabI++)
|
||||||
{
|
{
|
||||||
var tab = Plugin.Config.Tabs[tabI];
|
var tab = Plugin.Config.Tabs[tabI];
|
||||||
if (tab.PopOut)
|
if (tab.PopOut)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var unread = tabI == LastTab || tab.UnreadMode == UnreadMode.None || tab.Unread == 0 ? "" : $" ({tab.Unread})";
|
var unread = tabI == Plugin.LastTab || tab.UnreadMode == UnreadMode.None || tab.Unread == 0 ? "" : $" ({tab.Unread})";
|
||||||
var clicked = ImGui.Selectable($"{tab.Name}{unread}###log-tab-{tabI}", LastTab == tabI || WantedTab == tabI);
|
var clicked = ImGui.Selectable($"{tab.Name}{unread}###log-tab-{tabI}", Plugin.LastTab == tabI || Plugin.WantedTab == tabI);
|
||||||
DrawTabContextMenu(tab, tabI);
|
DrawTabContextMenu(tab, tabI);
|
||||||
|
|
||||||
if (!clicked && WantedTab != tabI)
|
if (!clicked && Plugin.WantedTab != tabI)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
currentTab = tabI;
|
currentTab = tabI;
|
||||||
switchedTab = LastTab != tabI;
|
switchedTab = Plugin.LastTab != tabI;
|
||||||
|
Plugin.LastTab = tabI;
|
||||||
if (switchedTab)
|
if (switchedTab)
|
||||||
TabChannelSwitch(tab);
|
TabChannelSwitch(tab, previousTab);
|
||||||
LastTab = tabI;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
if (currentTab == -1 && LastTab < Plugin.Config.Tabs.Count)
|
if (currentTab == -1 && Plugin.LastTab < Plugin.Config.Tabs.Count)
|
||||||
{
|
{
|
||||||
currentTab = LastTab;
|
currentTab = Plugin.LastTab;
|
||||||
Plugin.Config.Tabs[currentTab].Unread = 0;
|
Plugin.Config.Tabs[currentTab].Unread = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTab > -1)
|
if (currentTab > -1)
|
||||||
DrawMessageLog(Plugin.Config.Tabs[currentTab], PayloadHandler, childHeight, switchedTab);
|
DrawMessageLog(Plugin.Config.Tabs[currentTab], PayloadHandler, childHeight, switchedTab);
|
||||||
|
|
||||||
WantedTab = null;
|
Plugin.WantedTab = null;
|
||||||
return currentTab;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawTabContextMenu(Tab tab, int i)
|
private void DrawTabContextMenu(Tab tab, int i)
|
||||||
|
|||||||
@@ -8,15 +8,6 @@
|
|||||||
"resolved": "11.0.0",
|
"resolved": "11.0.0",
|
||||||
"contentHash": "bjT7XUlhIJSmsE/O76b7weUX+evvGQctbQB8aKXt94o+oPWxHpCepxAGMs7Thow3AzCyqWs7cOpp9/2wcgRRQA=="
|
"contentHash": "bjT7XUlhIJSmsE/O76b7weUX+evvGQctbQB8aKXt94o+oPWxHpCepxAGMs7Thow3AzCyqWs7cOpp9/2wcgRRQA=="
|
||||||
},
|
},
|
||||||
"EmbedIO": {
|
|
||||||
"type": "Direct",
|
|
||||||
"requested": "[3.5.2, )",
|
|
||||||
"resolved": "3.5.2",
|
|
||||||
"contentHash": "YU4j+3XvuO8/VPkNf7KWOF1TpMhnyVhXnPsG1mvnDhTJ9D5BZOFXVDvCpE/SkQ1AJ0Aa+dXOVSW3ntgmLL7aJg==",
|
|
||||||
"dependencies": {
|
|
||||||
"Unosquare.Swan.Lite": "3.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MessagePack": {
|
"MessagePack": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[3.0.238-rc.1, )",
|
"requested": "[3.0.238-rc.1, )",
|
||||||
@@ -139,24 +130,11 @@
|
|||||||
"resolved": "8.0.5",
|
"resolved": "8.0.5",
|
||||||
"contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg=="
|
"contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg=="
|
||||||
},
|
},
|
||||||
"System.ValueTuple": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.5.0",
|
|
||||||
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
|
||||||
},
|
|
||||||
"Timestamps": {
|
"Timestamps": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.9",
|
"resolved": "1.0.9",
|
||||||
"contentHash": "xdCVp+T4VFXOT+Ube2Cz527fnFXFUxQK24uPMGcCmICIpIcGCXPtI7vKLnWsJ6Nfc1B92tNBK9e/I8NDq2ee6g=="
|
"contentHash": "xdCVp+T4VFXOT+Ube2Cz527fnFXFUxQK24uPMGcCmICIpIcGCXPtI7vKLnWsJ6Nfc1B92tNBK9e/I8NDq2ee6g=="
|
||||||
},
|
},
|
||||||
"Unosquare.Swan.Lite": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "3.1.0",
|
|
||||||
"contentHash": "X3s5QE/KMj3WAPFqFve7St+Ds10BB50u8kW8PmKIn7FVkn7yEXe9Yxr2htt1WV85DRqfFR0MN/BUNHkGHtL4OQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.ValueTuple": "4.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"UrlMatcher": {
|
"UrlMatcher": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "3.0.0",
|
"resolved": "3.0.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user