fix #81
This commit is contained in:
@@ -22,7 +22,14 @@ tags:
|
|||||||
- Chat
|
- Chat
|
||||||
- Replacement
|
- Replacement
|
||||||
changelog: |-
|
changelog: |-
|
||||||
**Misc**
|
**Added**
|
||||||
- Implement 24-hour clock timestamp option [default false]
|
- Implement 24-hour clock timestamp option [default false]
|
||||||
- Fix hide activity channels not being saved across sessions
|
|
||||||
|
**Fixes**
|
||||||
|
- Bozja/Eureka tells should work again
|
||||||
|
- Invites in Bozja/Eureka should work again
|
||||||
|
- Added a notification that warns about fails duo missing player id
|
||||||
|
- Hide activity channels are now saved across sessions
|
||||||
|
|
||||||
|
**Misc**
|
||||||
- Loc updates
|
- Loc updates
|
||||||
|
|||||||
@@ -30,20 +30,23 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
private readonly delegate* unmanaged<RaptureLogModule*, ushort, Utf8String*, Utf8String*, ulong, ulong, ushort, byte, int, byte, void> PrintTellNative = null!;
|
private readonly delegate* unmanaged<RaptureLogModule*, ushort, Utf8String*, Utf8String*, ulong, ulong, ushort, byte, int, byte, void> PrintTellNative = null!;
|
||||||
|
|
||||||
[Signature("E8 ?? ?? ?? ?? 48 8D 4C 24 ?? E8 ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? ?? E8 ?? ?? ?? ?? B0 01")]
|
[Signature("E8 ?? ?? ?? ?? 48 8D 4C 24 ?? E8 ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? ?? E8 ?? ?? ?? ?? B0 01")]
|
||||||
private readonly delegate* unmanaged<NetworkModule*, ulong, ushort, Utf8String*, Utf8String*, ushort, ushort, bool> SendTellNative = null!;
|
private readonly delegate* unmanaged<NetworkModule*, ulong, ushort, Utf8String*, Utf8String*, ushort, ushort, byte> SendTellNative = null!;
|
||||||
|
|
||||||
// Client::UI::AddonChatLog.OnRefresh
|
// Client::UI::AddonChatLog.OnRefresh
|
||||||
[Signature("40 53 56 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 49 8B F0 8B FA", DetourName = nameof(ChatLogRefreshDetour))]
|
[Signature("40 53 56 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 49 8B F0 8B FA", DetourName = nameof(ChatLogRefreshDetour))]
|
||||||
private Hook<ChatLogRefreshDelegate>? ChatLogRefreshHook { get; init; }
|
private Hook<ChatLogRefreshDelegate>? ChatLogRefreshHook { get; init; }
|
||||||
private delegate byte ChatLogRefreshDelegate(nint log, ushort eventId, AtkValue* value);
|
private delegate byte ChatLogRefreshDelegate(nint log, ushort eventId, AtkValue* value);
|
||||||
|
|
||||||
|
// Replace with CS version later
|
||||||
|
[Signature("E8 ?? ?? ?? ?? EB 81 48 8B 1D", DetourName = nameof(ContextMenuTellInForayDetour))]
|
||||||
|
private Hook<ContextMenuTellInForayDelegate>? ContextMenuTellInForayHook { get; set; }
|
||||||
|
private delegate void ContextMenuTellInForayDelegate(RaptureShellModule* module, Utf8String* playerName, Utf8String* worldName, ushort worldId, ulong accountId, ulong contentId, ushort reason);
|
||||||
|
|
||||||
private Hook<AgentChatLog.Delegates.ChangeChannelName> ChangeChannelNameHook { get; init; }
|
private Hook<AgentChatLog.Delegates.ChangeChannelName> ChangeChannelNameHook { get; init; }
|
||||||
private Hook<RaptureShellModule.Delegates.ReplyInSelectedChatMode>? ReplyInSelectedChatModeHook { get; init; }
|
private Hook<RaptureShellModule.Delegates.ReplyInSelectedChatMode>? ReplyInSelectedChatModeHook { get; init; }
|
||||||
private Hook<RaptureShellModule.Delegates.SetContextTellTarget>? SetChatLogTellTargetHook { get; init; }
|
private Hook<RaptureShellModule.Delegates.SetContextTellTarget>? SetChatLogTellTargetHook { get; init; }
|
||||||
private Hook<RaptureShellModule.Delegates.SetContextTellTargetInForay>? EurekaContextMenuTellHook { get; init; }
|
|
||||||
|
|
||||||
// Pointers
|
// Pointers
|
||||||
|
|
||||||
[Signature("48 8D 35 ?? ?? ?? ?? 8B 05", ScanType = ScanType.StaticAddress)]
|
[Signature("48 8D 35 ?? ?? ?? ?? 8B 05", ScanType = ScanType.StaticAddress)]
|
||||||
private readonly char* CurrentCharacter = null!;
|
private readonly char* CurrentCharacter = null!;
|
||||||
|
|
||||||
@@ -75,6 +78,7 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
Plugin.GameInteropProvider.InitializeFromAttributes(this);
|
Plugin.GameInteropProvider.InitializeFromAttributes(this);
|
||||||
|
|
||||||
ChatLogRefreshHook?.Enable();
|
ChatLogRefreshHook?.Enable();
|
||||||
|
ContextMenuTellInForayHook?.Enable();
|
||||||
|
|
||||||
ChangeChannelNameHook = Plugin.GameInteropProvider.HookFromAddress<AgentChatLog.Delegates.ChangeChannelName>(AgentChatLog.MemberFunctionPointers.ChangeChannelName, ChangeChannelNameDetour);
|
ChangeChannelNameHook = Plugin.GameInteropProvider.HookFromAddress<AgentChatLog.Delegates.ChangeChannelName>(AgentChatLog.MemberFunctionPointers.ChangeChannelName, ChangeChannelNameDetour);
|
||||||
ChangeChannelNameHook.Enable();
|
ChangeChannelNameHook.Enable();
|
||||||
@@ -85,9 +89,6 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
SetChatLogTellTargetHook = Plugin.GameInteropProvider.HookFromAddress<RaptureShellModule.Delegates.SetContextTellTarget>(RaptureShellModule.MemberFunctionPointers.SetContextTellTarget, SetContextTellTarget);
|
SetChatLogTellTargetHook = Plugin.GameInteropProvider.HookFromAddress<RaptureShellModule.Delegates.SetContextTellTarget>(RaptureShellModule.MemberFunctionPointers.SetContextTellTarget, SetContextTellTarget);
|
||||||
SetChatLogTellTargetHook.Enable();
|
SetChatLogTellTargetHook.Enable();
|
||||||
|
|
||||||
// EurekaContextMenuTellHook = Plugin.GameInteropProvider.HookFromAddress<RaptureShellModule.Delegates.SetContextTellTargetInForay>(RaptureShellModule.MemberFunctionPointers.SetContextTellTargetInForay, SetContextTellTargetInForay);
|
|
||||||
// EurekaContextMenuTellHook.Enable();
|
|
||||||
|
|
||||||
Plugin.ClientState.Login += Login;
|
Plugin.ClientState.Login += Login;
|
||||||
Login();
|
Login();
|
||||||
}
|
}
|
||||||
@@ -100,7 +101,7 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
ReplyInSelectedChatModeHook?.Dispose();
|
ReplyInSelectedChatModeHook?.Dispose();
|
||||||
ChangeChannelNameHook?.Dispose();
|
ChangeChannelNameHook?.Dispose();
|
||||||
ChatLogRefreshHook?.Dispose();
|
ChatLogRefreshHook?.Dispose();
|
||||||
EurekaContextMenuTellHook?.Dispose();
|
ContextMenuTellInForayHook?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal string? GetLinkshellName(uint idx)
|
internal string? GetLinkshellName(uint idx)
|
||||||
@@ -213,6 +214,11 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// We already called this function once, so we skip the duplicated call
|
||||||
|
// Also return the original value here so that vanilla chat receives all information
|
||||||
|
if (Plugin.ChatLogWindow.TellSpecial)
|
||||||
|
return ChatLogRefreshHook!.Original(log, eventId, value);
|
||||||
|
|
||||||
Plugin.ChatLogWindow.Activated(new ChatActivatedArgs(new ChannelSwitchInfo(null)) { AddIfNotPresent = addIfNotPresent, });
|
Plugin.ChatLogWindow.Activated(new ChatActivatedArgs(new ChannelSwitchInfo(null)) { AddIfNotPresent = addIfNotPresent, });
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -294,35 +300,34 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
return SetChatLogTellTargetHook!.Original(a1, playerName, worldName, worldId, accountId, contentId, reason, setChatType);
|
return SetChatLogTellTargetHook!.Original(a1, playerName, worldName, worldId, accountId, contentId, reason, setChatType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void SetContextTellTargetInForay(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)
|
||||||
// {
|
{
|
||||||
// Plugin.Log.Information($"SetContextTellTargetInForay");
|
if (!UsesTellTempChannel)
|
||||||
// if (!UsesTellTempChannel)
|
{
|
||||||
// {
|
UsesTellTempChannel = true;
|
||||||
// UsesTellTempChannel = true;
|
PreviousChannel = Channel.Channel;
|
||||||
// PreviousChannel = Channel.Channel;
|
}
|
||||||
// }
|
|
||||||
//
|
if (playerName != null)
|
||||||
// if (playerName != null)
|
{
|
||||||
// {
|
try
|
||||||
// try
|
{
|
||||||
// {
|
var target = new TellTarget(playerName->ToString(), worldId, contentId, (TellReason) reason);
|
||||||
// Plugin.Log.Information($"Name {playerName->ToString()} World {worldName->ToString()} WorldId {worldId} accountId {accountId} ContentId {contentId} Reason {reason} rapture reason {a1->TellReason}");
|
Plugin.ChatLogWindow.Activated(new ChatActivatedArgs(new ChannelSwitchInfo(InputChannel.Tell))
|
||||||
// var target = new TellTarget(playerName->ToString(), worldId, contentId, (TellReason) reason);
|
{
|
||||||
// Activated?.Invoke(new ChatActivatedArgs(new ChannelSwitchInfo(InputChannel.Tell))
|
TellReason = (TellReason) reason,
|
||||||
// {
|
TellTarget = target,
|
||||||
// TellReason = (TellReason) reason,
|
TellSpecial = true,
|
||||||
// TellTarget = target,
|
});
|
||||||
// });
|
}
|
||||||
// }
|
catch (Exception ex)
|
||||||
// catch (Exception ex)
|
{
|
||||||
// {
|
Plugin.Log.Error(ex, "Error in chat Activated event");
|
||||||
// Plugin.Log.Error(ex, "Error in chat Activated event");
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
//
|
ContextMenuTellInForayHook!.Original(a1, playerName, worldName, worldId, accountId, contentId, reason);
|
||||||
// EurekaContextMenuTellHook!.Original(a1, playerName, worldName, worldId, accountId, contentId, reason);
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the channel is any non-linkshell channel, or if the
|
/// Returns true if the channel is any non-linkshell channel, or if the
|
||||||
@@ -457,6 +462,16 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
return new TellHistoryInfo(name, world, contentId);
|
return new TellHistoryInfo(name, world, contentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void SendTellUsingCommandInner(byte[] message)
|
||||||
|
{
|
||||||
|
var mes = new Utf8String(message);
|
||||||
|
|
||||||
|
RaptureShellModule.Instance()->ExecuteCommandInner(&mes, UIModule.Instance());
|
||||||
|
RaptureAtkModule.Instance()->ClearFocus(); // Clear the focus of vanilla chat that was still active
|
||||||
|
|
||||||
|
mes.Dtor(true);
|
||||||
|
}
|
||||||
|
|
||||||
internal void SendTell(TellReason reason, ulong contentId, string name, ushort homeWorld, byte[] message, string rawText)
|
internal void SendTell(TellReason reason, ulong contentId, string name, ushort homeWorld, byte[] message, string rawText)
|
||||||
{
|
{
|
||||||
var uName = Utf8String.FromString(name);
|
var uName = Utf8String.FromString(name);
|
||||||
@@ -470,15 +485,19 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
var logModule = RaptureLogModule.Instance();
|
var logModule = RaptureLogModule.Instance();
|
||||||
var networkModule = Framework.Instance()->GetNetworkModuleProxy()->NetworkModule;
|
var networkModule = Framework.Instance()->GetNetworkModuleProxy()->NetworkModule;
|
||||||
|
|
||||||
// TODO: Remap TellReasons
|
// // TODO: Remap TellReasons
|
||||||
if (reason == TellReason.Direct)
|
if (reason == TellReason.Direct)
|
||||||
reason = TellReason.Friend;
|
reason = TellReason.Friend;
|
||||||
|
|
||||||
var ok = SendTellNative(networkModule, contentId, homeWorld, uName, encoded, (ushort) reason, homeWorld);
|
var ok = SendTellNative(networkModule, contentId, homeWorld, uName, encoded, (ushort) reason, homeWorld);
|
||||||
if (ok)
|
if (ok == 1)
|
||||||
|
{
|
||||||
PrintTellNative(logModule, 33, uName, &decodedUtf8String, 0, contentId, homeWorld, 255, 0, 0);
|
PrintTellNative(logModule, 33, uName, &decodedUtf8String, 0, contentId, homeWorld, 255, 0, 0);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Plugin.ChatGui.PrintError(Language.Chat_SendTell_Error);
|
Plugin.ChatGui.PrintError(Language.Chat_SendTell_Error);
|
||||||
|
}
|
||||||
|
|
||||||
encoded->Dtor(true);
|
encoded->Dtor(true);
|
||||||
uName->Dtor(true);
|
uName->Dtor(true);
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
|
using ChatTwo.Resources;
|
||||||
using ChatTwo.Util;
|
using ChatTwo.Util;
|
||||||
|
using Dalamud.Interface.ImGuiNotification;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Info;
|
using FFXIVClientStructs.FFXIV.Client.UI.Info;
|
||||||
|
|
||||||
namespace ChatTwo.GameFunctions;
|
namespace ChatTwo.GameFunctions;
|
||||||
|
|
||||||
internal sealed unsafe class Party
|
internal static unsafe class Party
|
||||||
{
|
{
|
||||||
internal static void InviteSameWorld(string name, ushort world, ulong contentId)
|
internal static void InviteSameWorld(string name, ushort world, ulong contentId)
|
||||||
{
|
{
|
||||||
@@ -20,13 +22,23 @@ internal sealed unsafe class Party
|
|||||||
// if they're not on that world, it will fail
|
// if they're not on that world, it will fail
|
||||||
// pass 0 and it will work on any world EXCEPT for the world the
|
// pass 0 and it will work on any world EXCEPT for the world the
|
||||||
// current player is on
|
// current player is on
|
||||||
if (contentId != 0)
|
if (contentId == 0)
|
||||||
|
{
|
||||||
|
WrapperUtil.AddNotification(Language.PartyInvite_NoId, NotificationType.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
InfoProxyPartyInvite.Instance()->InviteToPartyContentId(contentId, 0);
|
InfoProxyPartyInvite.Instance()->InviteToPartyContentId(contentId, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void InviteInInstance(ulong contentId)
|
internal static void InviteInInstance(ulong contentId)
|
||||||
{
|
{
|
||||||
if (contentId != 0)
|
if (contentId == 0)
|
||||||
|
{
|
||||||
|
WrapperUtil.AddNotification(Language.PartyInvite_NoId, NotificationType.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
InfoProxyPartyInvite.Instance()->InviteToPartyInInstance(contentId);
|
InfoProxyPartyInvite.Instance()->InviteToPartyInInstance(contentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ internal sealed class ChatActivatedArgs
|
|||||||
internal ChannelSwitchInfo ChannelSwitchInfo { get; }
|
internal ChannelSwitchInfo ChannelSwitchInfo { get; }
|
||||||
internal TellReason? TellReason { get; init; }
|
internal TellReason? TellReason { get; init; }
|
||||||
internal TellTarget? TellTarget { get; init; }
|
internal TellTarget? TellTarget { get; init; }
|
||||||
|
internal bool TellSpecial { get; init; } // specific to Eureka/Bozja/Zadnor
|
||||||
|
|
||||||
internal ChatActivatedArgs(ChannelSwitchInfo channelSwitchInfo)
|
internal ChatActivatedArgs(ChannelSwitchInfo channelSwitchInfo)
|
||||||
{
|
{
|
||||||
|
|||||||
Generated
+9
@@ -3416,6 +3416,15 @@ namespace ChatTwo.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Unable to find ID for this message, please try another one..
|
||||||
|
/// </summary>
|
||||||
|
internal static string PartyInvite_NoId {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("PartyInvite_NoId", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Discard.
|
/// Looks up a localized string similar to Discard.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -964,6 +964,9 @@
|
|||||||
<data name="Context_CopySuccess">
|
<data name="Context_CopySuccess">
|
||||||
<value>Copied message to clipboard</value>
|
<value>Copied message to clipboard</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PartyInvite_NoId">
|
||||||
|
<value>Unable to find ID for this message, please try another one.</value>
|
||||||
|
</data>
|
||||||
<data name="Context_CopyLink" xml:space="preserve">
|
<data name="Context_CopyLink" xml:space="preserve">
|
||||||
<value>Copy link to clipboard</value>
|
<value>Copy link to clipboard</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
private int LastTab { get; set; }
|
private int LastTab { get; set; }
|
||||||
private InputChannel? TempChannel;
|
private InputChannel? TempChannel;
|
||||||
private TellTarget? TellTarget;
|
private TellTarget? TellTarget;
|
||||||
|
public bool TellSpecial;
|
||||||
private readonly Stopwatch LastResize = new();
|
private readonly Stopwatch LastResize = new();
|
||||||
private AutoCompleteInfo? AutoCompleteInfo;
|
private AutoCompleteInfo? AutoCompleteInfo;
|
||||||
private bool AutoCompleteOpen;
|
private bool AutoCompleteOpen;
|
||||||
@@ -145,6 +146,8 @@ public sealed class ChatLogWindow : Window
|
|||||||
|
|
||||||
internal void Activated(ChatActivatedArgs args)
|
internal void Activated(ChatActivatedArgs args)
|
||||||
{
|
{
|
||||||
|
TellSpecial = args.TellSpecial;
|
||||||
|
|
||||||
Activate = true;
|
Activate = true;
|
||||||
PlayedClosingSound = false;
|
PlayedClosingSound = false;
|
||||||
if (Plugin.Config.PlaySounds)
|
if (Plugin.Config.PlaySounds)
|
||||||
@@ -857,6 +860,21 @@ public sealed class ChatLogWindow : Window
|
|||||||
AddBacklog(trimmed);
|
AddBacklog(trimmed);
|
||||||
InputBacklogIdx = -1;
|
InputBacklogIdx = -1;
|
||||||
|
|
||||||
|
if (TellSpecial)
|
||||||
|
{
|
||||||
|
var tellBytes = Encoding.UTF8.GetBytes(trimmed);
|
||||||
|
AutoTranslate.ReplaceWithPayload(ref tellBytes);
|
||||||
|
|
||||||
|
Plugin.Functions.Chat.SendTellUsingCommandInner(tellBytes);
|
||||||
|
|
||||||
|
TellSpecial = false;
|
||||||
|
if (TempChannel is InputChannel.Tell)
|
||||||
|
TellTarget = null;
|
||||||
|
|
||||||
|
Chat = string.Empty;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!trimmed.StartsWith('/'))
|
if (!trimmed.StartsWith('/'))
|
||||||
{
|
{
|
||||||
if (TellTarget != null)
|
if (TellTarget != null)
|
||||||
|
|||||||
Reference in New Issue
Block a user