241 lines
8.7 KiB
C#
241 lines
8.7 KiB
C#
![]() |
using Dalamud.Game.Text;
|
||
|
using Dalamud.Game.Text.SeStringHandling;
|
||
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||
|
using Dalamud.Plugin.Services;
|
||
|
using MareSynchronos.API.Data;
|
||
|
using MareSynchronos.Interop;
|
||
|
using MareSynchronos.MareConfiguration;
|
||
|
using MareSynchronos.MareConfiguration.Models;
|
||
|
using MareSynchronos.PlayerData.Pairs;
|
||
|
using MareSynchronos.Services.Mediator;
|
||
|
using MareSynchronos.Services.ServerConfiguration;
|
||
|
using MareSynchronos.Utils;
|
||
|
using MareSynchronos.WebAPI;
|
||
|
using Microsoft.Extensions.Logging;
|
||
|
|
||
|
namespace MareSynchronos.Services;
|
||
|
|
||
|
public class ChatService : DisposableMediatorSubscriberBase
|
||
|
{
|
||
|
public const int DefaultColor = 710;
|
||
|
public const int CommandMaxNumber = 50;
|
||
|
|
||
|
private readonly ILogger<ChatService> _logger;
|
||
|
private readonly IChatGui _chatGui;
|
||
|
private readonly DalamudUtilService _dalamudUtil;
|
||
|
private readonly MareConfigService _mareConfig;
|
||
|
private readonly ApiController _apiController;
|
||
|
private readonly PairManager _pairManager;
|
||
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||
|
|
||
|
private readonly Lazy<GameChatHooks> _gameChatHooks;
|
||
|
|
||
|
public ChatService(ILogger<ChatService> logger, DalamudUtilService dalamudUtil, MareMediator mediator, ApiController apiController,
|
||
|
PairManager pairManager, ILoggerFactory loggerFactory, IGameInteropProvider gameInteropProvider, IChatGui chatGui,
|
||
|
MareConfigService mareConfig, ServerConfigurationManager serverConfigurationManager) : base(logger, mediator)
|
||
|
{
|
||
|
_logger = logger;
|
||
|
_dalamudUtil = dalamudUtil;
|
||
|
_chatGui = chatGui;
|
||
|
_mareConfig = mareConfig;
|
||
|
_apiController = apiController;
|
||
|
_pairManager = pairManager;
|
||
|
_serverConfigurationManager = serverConfigurationManager;
|
||
|
|
||
|
Mediator.Subscribe<UserChatMsgMessage>(this, HandleUserChat);
|
||
|
Mediator.Subscribe<GroupChatMsgMessage>(this, HandleGroupChat);
|
||
|
|
||
|
_gameChatHooks = new(() => new GameChatHooks(loggerFactory.CreateLogger<GameChatHooks>(), gameInteropProvider, SendChatShell));
|
||
|
|
||
|
// Initialize chat hooks in advance
|
||
|
_ = Task.Run(() =>
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
_ = _gameChatHooks.Value;
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
_logger.LogError(ex, "Failed to initialize chat hooks");
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
protected override void Dispose(bool disposing)
|
||
|
{
|
||
|
base.Dispose(disposing);
|
||
|
if (_gameChatHooks.IsValueCreated)
|
||
|
_gameChatHooks.Value!.Dispose();
|
||
|
}
|
||
|
|
||
|
private void HandleUserChat(UserChatMsgMessage message)
|
||
|
{
|
||
|
var chatMsg = message.ChatMsg;
|
||
|
var prefix = new SeStringBuilder();
|
||
|
prefix.AddText("[BnnuyChat] ");
|
||
|
_chatGui.Print(new XivChatEntry{
|
||
|
MessageBytes = [..prefix.Build().Encode(), ..message.ChatMsg.PayloadContent],
|
||
|
Name = chatMsg.SenderName,
|
||
|
Type = XivChatType.TellIncoming
|
||
|
});
|
||
|
}
|
||
|
|
||
|
private ushort ResolveShellColor(int shellColor)
|
||
|
{
|
||
|
if (shellColor != 0)
|
||
|
return (ushort)shellColor;
|
||
|
var globalColor = _mareConfig.Current.ChatColor;
|
||
|
if (globalColor != 0)
|
||
|
return (ushort)globalColor;
|
||
|
return (ushort)DefaultColor;
|
||
|
}
|
||
|
|
||
|
private XivChatType ResolveShellLogKind(int shellLogKind)
|
||
|
{
|
||
|
if (shellLogKind != 0)
|
||
|
return (XivChatType)shellLogKind;
|
||
|
return (XivChatType)_mareConfig.Current.ChatLogKind;
|
||
|
}
|
||
|
|
||
|
private void HandleGroupChat(GroupChatMsgMessage message)
|
||
|
{
|
||
|
if (_mareConfig.Current.DisableSyncshellChat)
|
||
|
return;
|
||
|
|
||
|
var chatMsg = message.ChatMsg;
|
||
|
var shellConfig = _serverConfigurationManager.GetShellConfigForGid(message.GroupInfo.GID);
|
||
|
var shellNumber = shellConfig.ShellNumber;
|
||
|
|
||
|
if (!shellConfig.Enabled)
|
||
|
return;
|
||
|
|
||
|
ushort color = ResolveShellColor(shellConfig.Color);
|
||
|
var extraChatTags = _mareConfig.Current.ExtraChatTags;
|
||
|
var logKind = ResolveShellLogKind(shellConfig.LogKind);
|
||
|
|
||
|
var msg = new SeStringBuilder();
|
||
|
if (extraChatTags)
|
||
|
{
|
||
|
msg.Add(ChatUtils.CreateExtraChatTagPayload(message.GroupInfo.GID));
|
||
|
msg.Add(RawPayload.LinkTerminator);
|
||
|
}
|
||
|
if (color != 0)
|
||
|
msg.AddUiForeground((ushort)color);
|
||
|
msg.AddText($"[SS{shellNumber}]<");
|
||
|
if (message.ChatMsg.Sender.UID.Equals(_apiController.UID, StringComparison.Ordinal))
|
||
|
{
|
||
|
// Don't link to your own character
|
||
|
msg.AddText(chatMsg.SenderName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
msg.Add(new PlayerPayload(chatMsg.SenderName, chatMsg.SenderHomeWorldId));
|
||
|
}
|
||
|
msg.AddText("> ");
|
||
|
msg.Append(SeString.Parse(message.ChatMsg.PayloadContent));
|
||
|
if (color != 0)
|
||
|
msg.AddUiForegroundOff();
|
||
|
|
||
|
_chatGui.Print(new XivChatEntry{
|
||
|
Message = msg.Build(),
|
||
|
Name = chatMsg.SenderName,
|
||
|
Type = logKind
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Print an example message to the configured global chat channel
|
||
|
public void PrintChannelExample(string message, string gid = "")
|
||
|
{
|
||
|
int chatType = _mareConfig.Current.ChatLogKind;
|
||
|
|
||
|
foreach (var group in _pairManager.Groups)
|
||
|
{
|
||
|
if (group.Key.GID.Equals(gid, StringComparison.Ordinal))
|
||
|
{
|
||
|
int shellChatType = _serverConfigurationManager.GetShellConfigForGid(gid).LogKind;
|
||
|
if (shellChatType != 0)
|
||
|
chatType = shellChatType;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_chatGui.Print(new XivChatEntry{
|
||
|
Message = message,
|
||
|
Name = "",
|
||
|
Type = (XivChatType)chatType
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Called to update the active chat shell name if its renamed
|
||
|
public void MaybeUpdateShellName(int shellNumber)
|
||
|
{
|
||
|
if (_mareConfig.Current.DisableSyncshellChat)
|
||
|
return;
|
||
|
|
||
|
foreach (var group in _pairManager.Groups)
|
||
|
{
|
||
|
var shellConfig = _serverConfigurationManager.GetShellConfigForGid(group.Key.GID);
|
||
|
if (shellConfig.Enabled && shellConfig.ShellNumber == shellNumber)
|
||
|
{
|
||
|
if (_gameChatHooks.IsValueCreated && _gameChatHooks.Value.ChatChannelOverride != null)
|
||
|
{
|
||
|
// Very dumb and won't handle re-numbering -- need to identify the active chat channel more reliably later
|
||
|
if (_gameChatHooks.Value.ChatChannelOverride.ChannelName.StartsWith($"SS [{shellNumber}]", StringComparison.Ordinal))
|
||
|
SwitchChatShell(shellNumber);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void SwitchChatShell(int shellNumber)
|
||
|
{
|
||
|
if (_mareConfig.Current.DisableSyncshellChat)
|
||
|
return;
|
||
|
|
||
|
foreach (var group in _pairManager.Groups)
|
||
|
{
|
||
|
var shellConfig = _serverConfigurationManager.GetShellConfigForGid(group.Key.GID);
|
||
|
if (shellConfig.Enabled && shellConfig.ShellNumber == shellNumber)
|
||
|
{
|
||
|
var name = _serverConfigurationManager.GetNoteForGid(group.Key.GID) ?? group.Key.AliasOrGID;
|
||
|
// BUG: This doesn't always update the chat window e.g. when renaming a group
|
||
|
_gameChatHooks.Value.ChatChannelOverride = new()
|
||
|
{
|
||
|
ChannelName = $"SS [{shellNumber}]: {name}",
|
||
|
ChatMessageHandler = chatBytes => SendChatShell(shellNumber, chatBytes)
|
||
|
};
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_chatGui.PrintError($"[ElezenSync] Syncshell number #{shellNumber} not found");
|
||
|
}
|
||
|
|
||
|
public void SendChatShell(int shellNumber, byte[] chatBytes)
|
||
|
{
|
||
|
if (_mareConfig.Current.DisableSyncshellChat)
|
||
|
return;
|
||
|
|
||
|
foreach (var group in _pairManager.Groups)
|
||
|
{
|
||
|
var shellConfig = _serverConfigurationManager.GetShellConfigForGid(group.Key.GID);
|
||
|
if (shellConfig.Enabled && shellConfig.ShellNumber == shellNumber)
|
||
|
{
|
||
|
_ = Task.Run(async () => {
|
||
|
// Should cache the name and home world instead of fetching it every time
|
||
|
var chatMsg = await _dalamudUtil.RunOnFrameworkThread(() => {
|
||
|
return new ChatMessage()
|
||
|
{
|
||
|
SenderName = _dalamudUtil.GetPlayerName(),
|
||
|
SenderHomeWorldId = _dalamudUtil.GetHomeWorldId(),
|
||
|
PayloadContent = chatBytes
|
||
|
};
|
||
|
}).ConfigureAwait(false);
|
||
|
await _apiController.GroupChatSendMsg(new(group.Key), chatMsg).ConfigureAwait(false);
|
||
|
}).ConfigureAwait(false);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_chatGui.PrintError($"[ElezenSync] Syncshell number #{shellNumber} not found");
|
||
|
}
|
||
|
}
|