Implement dynamic channel list

This commit is contained in:
Infi
2024-08-25 01:03:02 +02:00
parent 29e3c6acee
commit 19f10b09c8
8 changed files with 118 additions and 50 deletions
@@ -7,6 +7,11 @@ public struct SwitchChannel(string name)
[JsonProperty("channel")] public string Name = name;
}
public struct ChannelList(Dictionary<string, uint> channels)
{
[JsonProperty("channels")] public Dictionary<string, uint> Channels = channels;
}
public struct Messages(MessageResponse[] set)
{
[JsonProperty("messages")] public MessageResponse[] Set = set;
@@ -5,6 +5,8 @@ namespace ChatTwo.Http.MessageProtocol;
public class CloseEvent() : BaseEvent("close");
public class ChannelListEvent(ChannelList channelList) : BaseEvent("channel-list", JsonConvert.SerializeObject(channelList));
public class SwitchChannelEvent(SwitchChannel switchChannel) : BaseEvent("switch-channel", JsonConvert.SerializeObject(switchChannel));
public class NewMessageEvent(Messages messages) : BaseEvent("new-message", JsonConvert.SerializeObject(messages));
+2
View File
@@ -165,9 +165,11 @@ public class RouteController
// TODO Check if reconnect or new connection
var messages = await WebserverUtil.FrameworkWrapper(Core.Processing.ReadMessageList);
var channels = await Plugin.Framework.RunOnTick(Plugin.ChatLogWindow.GetAvailableChannels);
var channelName = await Plugin.Framework.RunOnTick(() => Core.Processing.ReadChannelName(Plugin.ChatLogWindow.PreviousChannel));
sse.OutboundQueue.Enqueue(new NewMessageEvent(new Messages(messages)));
sse.OutboundQueue.Enqueue(new SwitchChannelEvent(new SwitchChannel(channelName)));
sse.OutboundQueue.Enqueue(new ChannelListEvent(new ChannelList(channels.ToDictionary(pair => pair.Key, pair => (uint)pair.Value))));
await sse.HandleEventLoop(ctx);
+20 -1
View File
@@ -1,4 +1,5 @@
using ChatTwo.Http.MessageProtocol;
using ChatTwo.Code;
using ChatTwo.Http.MessageProtocol;
using WatsonWebserver.Core;
using WatsonWebserver.Lite;
using ExceptionEventArgs = WatsonWebserver.Core.ExceptionEventArgs;
@@ -72,6 +73,24 @@ public class ServerCore : IAsyncDisposable
Plugin.Log.Error(ex, "Sending channel switch over SSE failed.");
}
}
internal void SendChannelList()
{
try
{
Plugin.Framework.RunOnTick(() =>
{
var channels = Plugin.ChatLogWindow.GetAvailableChannels();
var bundledResponse = new ChannelListEvent(new ChannelList(channels.ToDictionary(pair => pair.Key, pair => (uint)pair.Value)));
foreach (var eventServer in EventConnections)
eventServer.OutboundQueue.Enqueue(bundledResponse);
});
}
catch (Exception ex)
{
Plugin.Log.Error(ex, "Sending channel switch over SSE failed.");
}
}
#endregion
#region GeneralHandlers
+23 -4
View File
@@ -13,12 +13,15 @@ class SSEConnection {
});
this.socket.addEventListener('new-message', (event) => {
let eventData = JSON.parse(event.data);
for (let message of eventData.messages)
for (let message of JSON.parse(event.data).messages)
{
addMessage(message);
}
});
this.socket.addEventListener('channel-list', (event) => {
updateChannelOptions(JSON.parse(event.data).channels)
});
}
send(message) {
@@ -31,14 +34,30 @@ const sse = new SSEConnection();
// channel switcher
function updateChannelHint(label) {
document.getElementById('channel-hint').innerText = label;
document.getElementById('channel-hint').innerHTML = label;
}
document.getElementById('channel-select').addEventListener('change', (event) => {
updateChannelHint(event.target.value);
// TODO: send new channel to "backend"
// ws.send(...);
});
function updateChannelOptions(channels) {
let select = document.getElementById('channel-select');
// clear existing channels
select.innerHTML = '';
for (let [ name, channel ] of Object.entries(channels))
{
let option = document.createElement('option');
option.text = name;
option.value = channel;
select.appendChild(option)
}
}
// functions for handling the message list
function scrollMessagesToBottom() {
Binary file not shown.
+20
View File
@@ -0,0 +1,20 @@
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
namespace ChatTwo;
public static class Sheets
{
public static readonly ExcelSheet<Item> ItemSheet;
public static readonly ExcelSheet<World> WorldSheet;
public static readonly ExcelSheet<LogFilter> LogFilterSheet;
public static readonly ExcelSheet<TextCommand> TextCommandSheet;
static Sheets()
{
ItemSheet = Plugin.DataManager.GetExcelSheet<Item>()!;
WorldSheet = Plugin.DataManager.GetExcelSheet<World>()!;
LogFilterSheet = Plugin.DataManager.GetExcelSheet<LogFilter>()!;
TextCommandSheet = Plugin.DataManager.GetExcelSheet<TextCommand>()!;
}
}
+46 -45
View File
@@ -20,7 +20,6 @@ using Dalamud.Interface.Windowing;
using Dalamud.Memory;
using FFXIVClientStructs.FFXIV.Client.UI;
using ImGuiNET;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
namespace ChatTwo.Ui;
@@ -91,10 +90,6 @@ public sealed class ChatLogWindow : Window
private long FrameTime; // set every frame
internal long LastActivityTime = Environment.TickCount64;
private readonly ExcelSheet<World> WorldSheet;
private readonly ExcelSheet<LogFilter> LogFilterSheet;
private readonly ExcelSheet<TextCommand> TextCommandSheet;
internal ChatLogWindow(Plugin plugin) : base($"{Plugin.PluginName}###chat2")
{
Plugin = plugin;
@@ -118,10 +113,6 @@ public sealed class ChatLogWindow : Window
Plugin.Commands.Register("/clearlog2", "Clear the Chat 2 chat log").Execute += ClearLog;
Plugin.Commands.Register("/chat2").Execute += ToggleChat;
WorldSheet = Plugin.DataManager.GetExcelSheet<World>()!;
LogFilterSheet = Plugin.DataManager.GetExcelSheet<LogFilter>()!;
TextCommandSheet = Plugin.DataManager.GetExcelSheet<TextCommand>()!;
Plugin.ClientState.Login += Login;
Plugin.ClientState.Logout += Logout;
@@ -302,7 +293,7 @@ public sealed class ChatLogWindow : Window
AddTextCommandChannel(command, type);
}
var echo = Plugin.DataManager.GetExcelSheet<TextCommand>()?.GetRow(116);
var echo = Sheets.TextCommandSheet.GetRow(116);
if (echo != null)
AddTextCommandChannel(echo, ChatType.Echo);
}
@@ -573,41 +564,12 @@ public sealed class ChatLogWindow : Window
{
if (popup)
{
foreach (var channel in Enum.GetValues<InputChannel>())
{
var name = LogFilterSheet.FirstOrDefault(row => row.LogKind == (byte) channel.ToChatType())?.Name?.RawString ?? channel.ToChatType().Name();
if (channel.IsLinkshell())
{
var lsName = Plugin.Functions.Chat.GetLinkshellName(channel.LinkshellIndex());
if (string.IsNullOrWhiteSpace(lsName))
continue;
name += $": {lsName}";
}
if (channel.IsCrossLinkshell())
{
var lsName = Plugin.Functions.Chat.GetCrossLinkshellName(channel.LinkshellIndex());
if (string.IsNullOrWhiteSpace(lsName))
continue;
name += $": {lsName}";
}
// Check if the linkshell with this index is registered in
// the ExtraChat plugin by seeing if the command is
// registered. The command gets registered only if a
// linkshell is assigned (and even gets unassigned if the
// index changes!).
if (channel.IsExtraChatLinkshell())
if (!Plugin.CommandManager.Commands.ContainsKey(channel.Prefix()))
continue;
var channels = GetAvailableChannels();
foreach (var (name, channel) in channels)
if (ImGui.Selectable(name))
SetChannel(channel);
}
}
}
ImGui.SameLine();
var afterIcon = ImGui.GetCursorPos();
@@ -753,6 +715,45 @@ public sealed class ChatLogWindow : Window
GameFunctions.GameFunctions.ClickNoviceNetworkButton();
}
internal Dictionary<string, InputChannel> GetAvailableChannels()
{
var channels = new Dictionary<string, InputChannel>();
foreach (var channel in Enum.GetValues<InputChannel>())
{
var name = Sheets.LogFilterSheet.FirstOrDefault(row => row.LogKind == (byte) channel.ToChatType())?.Name?.RawString ?? channel.ToChatType().Name();
if (channel.IsLinkshell())
{
var lsName = Plugin.Functions.Chat.GetLinkshellName(channel.LinkshellIndex());
if (string.IsNullOrWhiteSpace(lsName))
continue;
name += $": {lsName}";
}
if (channel.IsCrossLinkshell())
{
var lsName = Plugin.Functions.Chat.GetCrossLinkshellName(channel.LinkshellIndex());
if (string.IsNullOrWhiteSpace(lsName))
continue;
name += $": {lsName}";
}
// Check if the linkshell with this index is registered in
// the ExtraChat plugin by seeing if the command is
// registered. The command gets registered only if a
// linkshell is assigned (and even gets unassigned if the
// index changes!).
if (channel.IsExtraChatLinkshell())
if (!Plugin.CommandManager.Commands.ContainsKey(channel.Prefix()))
continue;
channels.Add(name, channel);
}
return channels;
}
private void DrawChannelName(Tab? activeTab)
{
var currentChannel = ReadChannelName(activeTab);
@@ -776,7 +777,7 @@ public sealed class ChatLogWindow : Window
// Note: don't use HidePlayerInString here because
// abbreviation settings do not affect this.
playerName = HashPlayer(TellTarget.Name, TellTarget.World);
var world = WorldSheet.GetRow(TellTarget.World)?.Name?.RawString ?? "???";
var world = Sheets.WorldSheet.GetRow(TellTarget.World)?.Name?.RawString ?? "???";
channelNameChunks =
[
@@ -829,7 +830,7 @@ public sealed class ChatLogWindow : Window
// Note: don't use HidePlayerInString here because
// abbreviation settings do not affect this.
var playerName = HashPlayer(tellPlayerName, tellWorldId);
var world = WorldSheet.GetRow(tellWorldId)?.Name?.RawString ?? "???";
var world = Sheets.WorldSheet.GetRow(tellWorldId)?.Name?.RawString ?? "???";
channelNameChunks =
[
@@ -909,7 +910,7 @@ public sealed class ChatLogWindow : Window
{
var target = TellTarget;
var reason = target.Reason;
var world = WorldSheet.GetRow(target.World);
var world = Sheets.WorldSheet.GetRow(target.World);
if (world is { IsPublic: true })
{
if (reason == TellReason.Reply && GameFunctions.GameFunctions.GetFriends().Any(friend => friend.ContentId == target.ContentId))
@@ -1571,7 +1572,7 @@ public sealed class ChatLogWindow : Window
if (text.StartsWith('/'))
{
var command = text.Split(' ')[0];
var cmd = TextCommandSheet.FirstOrDefault(cmd =>
var cmd = Sheets.TextCommandSheet.FirstOrDefault(cmd =>
cmd.Command.RawString == command || cmd.Alias.RawString == command ||
cmd.ShortCommand.RawString == command || cmd.ShortAlias.RawString == command);