Handle temp chat channel switching via hotkeys
This commit is contained in:
@@ -63,10 +63,36 @@ public unsafe sealed class GameChatHooks : IDisposable
|
|||||||
DetourName = nameof(ShouldDoNameLookupDetour)
|
DetourName = nameof(ShouldDoNameLookupDetour)
|
||||||
)]
|
)]
|
||||||
private Hook<ShouldDoNameLookupDelegate>? ShouldDoNameLookupHook { get; init; }
|
private Hook<ShouldDoNameLookupDelegate>? ShouldDoNameLookupHook { get; init; }
|
||||||
|
|
||||||
|
// Temporary chat channel change (via hotkey)
|
||||||
|
private delegate ulong TempChatChannelDelegate(RaptureShellModule* module, uint x, uint y, ulong z);
|
||||||
|
[Signature(
|
||||||
|
"48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 83 B9 ?? ?? ?? ?? ?? 49 8B F9 41 8B F0",
|
||||||
|
DetourName = nameof(TempChatChannelDetour)
|
||||||
|
)]
|
||||||
|
private Hook<TempChatChannelDelegate>? TempChatChannelHook { get; init; }
|
||||||
|
|
||||||
|
// Temporary tell target change (via hotkey)
|
||||||
|
// Client::UI::Shell::RaptureShellModule::SetContextTellTargetInForay
|
||||||
|
private delegate ulong TempTellTargetDelegate(RaptureShellModule* module, ulong a, ulong b, ulong c, ushort d, ulong e, ulong f, ushort g);
|
||||||
|
[Signature(
|
||||||
|
"48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 83 B9 ?? ?? ?? ?? ?? 41 0F B7 F9",
|
||||||
|
DetourName = nameof(TempTellTargetDetour)
|
||||||
|
)]
|
||||||
|
private Hook<TempTellTargetDelegate>? TempTellTargetHook { get; init; }
|
||||||
|
|
||||||
|
// Called every frame while the chat bar is not focused
|
||||||
|
private delegate void UnfocusTickDelegate(RaptureShellModule* module);
|
||||||
|
[Signature(
|
||||||
|
"40 53 48 83 EC ?? 83 B9 ?? ?? ?? ?? ?? 48 8B D9 0F 84 ?? ?? ?? ?? 48 8D 91",
|
||||||
|
DetourName = nameof(UnfocusTickDetour)
|
||||||
|
)]
|
||||||
|
private Hook<UnfocusTickDelegate>? UnfocusTickHook { get; init; }
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private ChatChannelOverride? _chatChannelOverride;
|
private ChatChannelOverride? _chatChannelOverride;
|
||||||
|
private ChatChannelOverride? _chatChannelOverrideTempBuffer;
|
||||||
private bool _shouldForceNameLookup = false;
|
private bool _shouldForceNameLookup = false;
|
||||||
|
|
||||||
private DateTime _nextMessageIsReply = DateTime.UnixEpoch;
|
private DateTime _nextMessageIsReply = DateTime.UnixEpoch;
|
||||||
@@ -76,7 +102,27 @@ public unsafe sealed class GameChatHooks : IDisposable
|
|||||||
get => _chatChannelOverride;
|
get => _chatChannelOverride;
|
||||||
set {
|
set {
|
||||||
_chatChannelOverride = value;
|
_chatChannelOverride = value;
|
||||||
this._shouldForceNameLookup = true;
|
_shouldForceNameLookup = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StashChatChannel()
|
||||||
|
{
|
||||||
|
if (_chatChannelOverride != null)
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Stashing chat channel");
|
||||||
|
_chatChannelOverrideTempBuffer = _chatChannelOverride;
|
||||||
|
ChatChannelOverride = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnstashChatChannel()
|
||||||
|
{
|
||||||
|
if (_chatChannelOverrideTempBuffer != null)
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Unstashing chat channel");
|
||||||
|
ChatChannelOverride = _chatChannelOverrideTempBuffer;
|
||||||
|
_chatChannelOverrideTempBuffer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,18 +133,24 @@ public unsafe sealed class GameChatHooks : IDisposable
|
|||||||
logger.LogInformation("Initializing GameChatHooks");
|
logger.LogInformation("Initializing GameChatHooks");
|
||||||
gameInteropProvider.InitializeFromAttributes(this);
|
gameInteropProvider.InitializeFromAttributes(this);
|
||||||
|
|
||||||
this.SendMessageHook?.Enable();
|
SendMessageHook?.Enable();
|
||||||
this.SetChatChannelHook?.Enable();
|
SetChatChannelHook?.Enable();
|
||||||
this.ChangeChannelNameHook?.Enable();
|
ChangeChannelNameHook?.Enable();
|
||||||
this.ShouldDoNameLookupHook?.Enable();
|
ShouldDoNameLookupHook?.Enable();
|
||||||
|
TempChatChannelHook?.Enable();
|
||||||
|
TempTellTargetHook?.Enable();
|
||||||
|
UnfocusTickHook?.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
this.SendMessageHook?.Dispose();
|
SendMessageHook?.Dispose();
|
||||||
this.SetChatChannelHook?.Dispose();
|
SetChatChannelHook?.Dispose();
|
||||||
this.ChangeChannelNameHook?.Dispose();
|
ChangeChannelNameHook?.Dispose();
|
||||||
this.ShouldDoNameLookupHook?.Dispose();
|
ShouldDoNameLookupHook?.Dispose();
|
||||||
|
TempChatChannelHook?.Dispose();
|
||||||
|
TempTellTargetHook?.Dispose();
|
||||||
|
UnfocusTickHook?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendMessageDetour(ShellCommandModule* thisPtr, Utf8String* message, UIModule* uiModule)
|
private void SendMessageDetour(ShellCommandModule* thisPtr, Utf8String* message, UIModule* uiModule)
|
||||||
@@ -145,7 +197,7 @@ public unsafe sealed class GameChatHooks : IDisposable
|
|||||||
_nextMessageIsReply = utcNow + TimeSpan.FromMilliseconds(100);
|
_nextMessageIsReply = utcNow + TimeSpan.FromMilliseconds(100);
|
||||||
|
|
||||||
// If not a command, or no override is set, then call the original chat handler
|
// If not a command, or no override is set, then call the original chat handler
|
||||||
if (isCommand || this._chatChannelOverride == null)
|
if (isCommand || _chatChannelOverride == null)
|
||||||
{
|
{
|
||||||
SendMessageHook!.OriginalDisposeSafe(thisPtr, message, uiModule);
|
SendMessageHook!.OriginalDisposeSafe(thisPtr, message, uiModule);
|
||||||
return;
|
return;
|
||||||
@@ -155,11 +207,11 @@ public unsafe sealed class GameChatHooks : IDisposable
|
|||||||
// The chat input string is rendered in to a payload for display first
|
// The chat input string is rendered in to a payload for display first
|
||||||
var pronounModule = UIModule.Instance()->GetPronounModule();
|
var pronounModule = UIModule.Instance()->GetPronounModule();
|
||||||
var chatString1 = pronounModule->ProcessString(message, true);
|
var chatString1 = pronounModule->ProcessString(message, true);
|
||||||
var chatString2 = this._processStringStep2(pronounModule, chatString1, 1);
|
var chatString2 = _processStringStep2(pronounModule, chatString1, 1);
|
||||||
var chatBytes = MemoryHelper.ReadRaw((nint)chatString2->StringPtr.Value, chatString2->Length);
|
var chatBytes = MemoryHelper.ReadRaw((nint)chatString2->StringPtr.Value, chatString2->Length);
|
||||||
|
|
||||||
if (chatBytes.Length > 0)
|
if (chatBytes.Length > 0)
|
||||||
this._chatChannelOverride.ChatMessageHandler?.Invoke(chatBytes);
|
_chatChannelOverride.ChatMessageHandler?.Invoke(chatBytes);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -171,10 +223,10 @@ public unsafe sealed class GameChatHooks : IDisposable
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (this._chatChannelOverride != null)
|
if (_chatChannelOverride != null)
|
||||||
{
|
{
|
||||||
this._chatChannelOverride = null;
|
_chatChannelOverride = null;
|
||||||
this._shouldForceNameLookup = true;
|
_shouldForceNameLookup = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -185,6 +237,32 @@ public unsafe sealed class GameChatHooks : IDisposable
|
|||||||
SetChatChannelHook!.OriginalDisposeSafe(module, channel);
|
SetChatChannelHook!.OriginalDisposeSafe(module, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ulong TempChatChannelDetour(RaptureShellModule* module, uint x, uint y, ulong z)
|
||||||
|
{
|
||||||
|
var result = TempChatChannelHook!.OriginalDisposeSafe(module, x, y, z);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
StashChatChannel();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ulong TempTellTargetDetour(RaptureShellModule* module, ulong a, ulong b, ulong c, ushort d, ulong e, ulong f, ushort g)
|
||||||
|
{
|
||||||
|
var result = TempTellTargetHook!.OriginalDisposeSafe(module, a, b, c, d, e, f, g);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
StashChatChannel();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnfocusTickDetour(RaptureShellModule* module)
|
||||||
|
{
|
||||||
|
UnfocusTickHook!.OriginalDisposeSafe(module);
|
||||||
|
UnstashChatChannel();
|
||||||
|
}
|
||||||
|
|
||||||
private byte* ChangeChannelNameDetour(AgentChatLog* agent)
|
private byte* ChangeChannelNameDetour(AgentChatLog* agent)
|
||||||
{
|
{
|
||||||
var originalResult = ChangeChannelNameHook!.OriginalDisposeSafe(agent);
|
var originalResult = ChangeChannelNameHook!.OriginalDisposeSafe(agent);
|
||||||
@@ -192,9 +270,9 @@ public unsafe sealed class GameChatHooks : IDisposable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Replace the chat channel name on the UI if active
|
// Replace the chat channel name on the UI if active
|
||||||
if (this._chatChannelOverride != null)
|
if (_chatChannelOverride != null)
|
||||||
{
|
{
|
||||||
agent->ChannelLabel.SetString(this._chatChannelOverride.ChannelName);
|
agent->ChannelLabel.SetString(_chatChannelOverride.ChannelName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -212,7 +290,7 @@ public unsafe sealed class GameChatHooks : IDisposable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Force the chat channel name to update when required
|
// Force the chat channel name to update when required
|
||||||
if (this._shouldForceNameLookup)
|
if (_shouldForceNameLookup)
|
||||||
{
|
{
|
||||||
_shouldForceNameLookup = false;
|
_shouldForceNameLookup = false;
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user