diff --git a/ChatTwo/GameFunctions/Chat.cs b/ChatTwo/GameFunctions/Chat.cs index 7cd3705..a1f7a32 100755 --- a/ChatTwo/GameFunctions/Chat.cs +++ b/ChatTwo/GameFunctions/Chat.cs @@ -104,9 +104,13 @@ internal sealed unsafe class Chat : IDisposable { #pragma warning restore 0649 + // Pointers + [Signature("48 8D 15 ?? ?? ?? ?? 0F B6 C8 48 8D 05", ScanType = ScanType.StaticAddress)] + private readonly char* _currentCharacter = null!; + // Events - internal delegate void ChatActivatedEventDelegate(string? input, ChannelSwitchInfo info, TellReason? reason, TellTarget? target); + internal delegate void ChatActivatedEventDelegate(ChatActivatedArgs args); internal event ChatActivatedEventDelegate? Activated; @@ -349,7 +353,9 @@ internal sealed unsafe class Chat : IDisposable { } try { - this.Activated?.Invoke(null, info, TellReason.Reply, null); + this.Activated?.Invoke(new ChatActivatedArgs(info) { + TellReason = TellReason.Reply, + }); } catch (Exception ex) { PluginLog.LogError(ex, "Error in chat Activated event"); } @@ -374,18 +380,35 @@ internal sealed unsafe class Chat : IDisposable { return this.ChatLogRefreshHook!.Original(log, eventId, value); } - string? eventInput = null; + string? input = null; + var option = Framework.Instance()->GetUiModule()->GetConfigModule()->GetValueById(572); + if (option != null) { + var directChat = option->Int > 0; + if (directChat && this._currentCharacter != null) { + // FIXME: this whole system sucks + var c = *this._currentCharacter; + if (c != '\0' && !char.IsControl(c)) { + input = c.ToString(); + } + } + } + + string? addIfNotPresent = null; var str = value + 2; if (str != null && ((int) str->Type & 0xF) == (int) ValueType.String && str->String != null) { - var input = MemoryHelper.ReadStringNullTerminated((IntPtr) str->String); - if (input.Length > 0) { - eventInput = input; + var add = MemoryHelper.ReadStringNullTerminated((IntPtr) str->String); + if (add.Length > 0) { + addIfNotPresent = add; } } try { - this.Activated?.Invoke(eventInput, new ChannelSwitchInfo(null), null, null); + var args = new ChatActivatedArgs(new ChannelSwitchInfo(null)) { + AddIfNotPresent = addIfNotPresent, + Input = input, + }; + this.Activated?.Invoke(args); } catch (Exception ex) { PluginLog.LogError(ex, "Error in chat Activated event"); } @@ -465,7 +488,10 @@ internal sealed unsafe class Chat : IDisposable { if (name != null) { try { var target = new TellTarget(name->ToString(), world, contentId, (TellReason) reason); - this.Activated?.Invoke(null, new ChannelSwitchInfo(InputChannel.Tell), (TellReason) reason, target); + this.Activated?.Invoke(new ChatActivatedArgs(new ChannelSwitchInfo(InputChannel.Tell)) { + TellReason = (TellReason) reason, + TellTarget = target, + }); } catch (Exception ex) { PluginLog.LogError(ex, "Error in chat Activated event"); } diff --git a/ChatTwo/GameFunctions/Types/ChatActivatedArgs.cs b/ChatTwo/GameFunctions/Types/ChatActivatedArgs.cs new file mode 100755 index 0000000..dfb6cdb --- /dev/null +++ b/ChatTwo/GameFunctions/Types/ChatActivatedArgs.cs @@ -0,0 +1,13 @@ +namespace ChatTwo.GameFunctions.Types; + +internal sealed class ChatActivatedArgs { + internal string? AddIfNotPresent { get; init; } + internal string? Input { get; init; } + internal ChannelSwitchInfo ChannelSwitchInfo { get; } + internal TellReason? TellReason { get; init; } + internal TellTarget? TellTarget { get; init; } + + internal ChatActivatedArgs(ChannelSwitchInfo channelSwitchInfo) { + this.ChannelSwitchInfo = channelSwitchInfo; + } +} diff --git a/ChatTwo/Ui/ChatLog.cs b/ChatTwo/Ui/ChatLog.cs index 4b4c793..61d24f4 100755 --- a/ChatTwo/Ui/ChatLog.cs +++ b/ChatTwo/Ui/ChatLog.cs @@ -56,12 +56,18 @@ internal sealed class ChatLog : IUiComponent { this.Ui.Plugin.CommandManager.RemoveHandler("/clearlog2"); } - private void Activated(string? input, ChannelSwitchInfo info, TellReason? reason, TellTarget? target) { + private void Activated(ChatActivatedArgs args) { this.Activate = true; - if (input != null && !this.Chat.Contains(input)) { - this.Chat += input; + if (args.AddIfNotPresent != null && !this.Chat.Contains(args.AddIfNotPresent)) { + this.Chat += args.AddIfNotPresent; } + if (args.Input != null) { + this.Chat += args.Input; + } + + var (info, reason, target) = (args.ChannelSwitchInfo, args.TellReason, args.TellTarget); + if (info.Channel != null) { var prevTemp = this._tempChannel; @@ -231,7 +237,9 @@ internal sealed class ChatLog : IUiComponent { try { TellReason? reason = info.Channel == InputChannel.Tell ? TellReason.Reply : null; - this.Activated(null, info, reason, null); + this.Activated(new ChatActivatedArgs(info) { + TellReason = reason, + }); } catch (Exception ex) { PluginLog.LogError(ex, "Error in chat Activated event"); } @@ -267,7 +275,7 @@ internal sealed class ChatLog : IUiComponent { if (this.Ui.Plugin.Config.HideDuringCutscenes && this._hideState == HideState.None && (this.CutsceneActive || this.GposeActive)) { this._hideState = HideState.Cutscene; } - + // if the chat is hidden because of a cutscene and no longer in a cutscene, set the hide state to none if (this._hideState is HideState.Cutscene or HideState.CutsceneOverride && !this.CutsceneActive && !this.GposeActive) { this._hideState = HideState.None;