From e2a2ba8b26779112928a85d0cb41f9355f2f4681 Mon Sep 17 00:00:00 2001 From: NNowakowski Date: Wed, 12 Aug 2026 00:56:44 +0200 Subject: [PATCH] Fix controller autoplay via EventBus subscription The Harmony patch on DialogController.HandleOnCueShow only fires for keyboard/mouse input. Subscribing to the game's EventBus via IDialogCueHandler fires for all input modes including controller. Add DialogCueListener which implements IDialogCueHandler and is subscribed in Main.Load(). Remove HandleOnCueShow_Postfix from UiDialogController_Patch to avoid double-firing autoplay on keyboard/mouse. Co-Authored-By: Claude Sonnet 4.6 --- SpeechMod/Main.cs | 5 +++ SpeechMod/Patches/UiDialogController_Patch.cs | 38 ------------------- SpeechMod/Voice/DialogCueListener.cs | 34 +++++++++++++++++ 3 files changed, 39 insertions(+), 38 deletions(-) create mode 100644 SpeechMod/Voice/DialogCueListener.cs diff --git a/SpeechMod/Main.cs b/SpeechMod/Main.cs index 23404ea..d8d9a8a 100644 --- a/SpeechMod/Main.cs +++ b/SpeechMod/Main.cs @@ -1,4 +1,5 @@ using HarmonyLib; +using Kingmaker.PubSubSystem; using SpeechMod.Configuration; using SpeechMod.Keybinds; using SpeechMod.Unity; @@ -37,6 +38,7 @@ public static class Main }).ToDictionary(p => p.Key, p => p.Value); public static ISpeech Speech; + private static DialogCueListener _cueListener; private static bool m_Loaded = false; private static bool Load(UnityModManager.ModEntry modEntry) @@ -69,6 +71,9 @@ private static bool Load(UnityModManager.ModEntry modEntry) PhoneticDictionary.LoadDictionary(); + _cueListener = new DialogCueListener(); + EventBus.Subscribe(_cueListener); + ButtonFactory.Initialize(); Debug.Log("Pathfinder Kingmaker Speech Mod Initialized!"); diff --git a/SpeechMod/Patches/UiDialogController_Patch.cs b/SpeechMod/Patches/UiDialogController_Patch.cs index 1a83822..c2712c7 100644 --- a/SpeechMod/Patches/UiDialogController_Patch.cs +++ b/SpeechMod/Patches/UiDialogController_Patch.cs @@ -1,7 +1,5 @@ using HarmonyLib; using Kingmaker; -using Kingmaker.Controllers.Dialog; -using Kingmaker.Localization; using SpeechMod.Unity; using SpeechMod.Unity.Extensions; using UnityEngine; @@ -68,40 +66,4 @@ private static void AddDialogButtonByPath(string path) buttonGameObject.SetActive(true); } - [HarmonyPatch(typeof(DialogController), nameof(DialogController.HandleOnCueShow), typeof(CueShowData))] - [HarmonyPostfix] - public static void HandleOnCueShow_Postfix() - { - if (!Main.Enabled) - return; - -#if DEBUG - Debug.Log($"{nameof(DialogController)}_{nameof(HandleOnCueShow_Postfix)}"); -#endif - - if (!Main.Settings!.AutoPlay) - { -#if DEBUG - Debug.Log($"{nameof(DialogController)}: AutoPlay is disabled!"); -#endif - return; - } - - string key = Game.Instance?.DialogController?.CurrentCue?.Text?.Key; - if (string.IsNullOrWhiteSpace(key)) - key = Game.Instance?.DialogController?.CurrentCue?.Text?.Shared?.String?.Key; - - if (string.IsNullOrWhiteSpace(key)) - return; - - // Stop playing and don't play if the dialog is voice acted. - if (!Main.Settings.AutoPlayIgnoreVoice && - !string.IsNullOrWhiteSpace(LocalizationManager.SoundPack?.GetText(key, false))) - { - Main.Speech?.Stop(); - return; - } - - Main.Speech?.SpeakDialog(Game.Instance?.DialogController?.CurrentCue?.DisplayText, 0.5f); - } } \ No newline at end of file diff --git a/SpeechMod/Voice/DialogCueListener.cs b/SpeechMod/Voice/DialogCueListener.cs new file mode 100644 index 0000000..c93fcfe --- /dev/null +++ b/SpeechMod/Voice/DialogCueListener.cs @@ -0,0 +1,34 @@ +using Kingmaker; +using Kingmaker.Controllers.Dialog; +using Kingmaker.Localization; +using Kingmaker.PubSubSystem; + +namespace SpeechMod.Voice; + +// Subscribes to the game's event bus so autoplay fires for all input modes +// (keyboard/mouse AND controller). The Harmony patch on UI.Dialog.DialogController +// only fires for keyboard, which is why controller autoplay was broken. +public class DialogCueListener : IDialogCueHandler +{ + public void HandleOnCueShow(CueShowData data) + { + if (!Main.Enabled || !Main.Settings!.AutoPlay) + return; + + string key = Game.Instance?.DialogController?.CurrentCue?.Text?.Key; + if (string.IsNullOrWhiteSpace(key)) + key = Game.Instance?.DialogController?.CurrentCue?.Text?.Shared?.String?.Key; + + if (string.IsNullOrWhiteSpace(key)) + return; + + if (!Main.Settings.AutoPlayIgnoreVoice && + !string.IsNullOrWhiteSpace(LocalizationManager.SoundPack?.GetText(key, false))) + { + Main.Speech?.Stop(); + return; + } + + Main.Speech?.SpeakDialog(Game.Instance?.DialogController?.CurrentCue?.DisplayText, 0.5f); + } +}