76a4de1192
ipc.md guides third-party plugin authors who want to bind to our context-menu IPC and our typing-state IPC. After the v1.0.0 channel rename (ChatTwo.* → HellionChat.*) the example code in this file no longer matched the channels the plugin actually exposes — third-party authors who copy-pasted from the doc would see silent no-op subscriptions. Updated: - All 6 channel string literals in code samples (Register, Unregister, Invoke, Available, GetChatInputState, ChatInputStateChanged) - Code-path references in the Typing State IPC explanation block (HellionChat.Code.ChatType, HellionChat/Configuration.cs etc.) - Class/variable name in the example (ChatTwoIpc → HellionChatIpc) - Prose references to the plugin name Added a short migration note at the top so existing integrators see the rename in one paragraph instead of having to diff the file.
6.2 KiB
Executable File
6.2 KiB
Executable File
Context Menu IPC Integration
If you want to display custom menu items in the chat context menu, you can use Hellion Chat's IPC.
Migrating from Chat 2: the channel-name prefix changed from
ChatTwo.*toHellionChat.*in v1.0.0. If you previously bound toChatTwo.Registeretc., rename toHellionChat.Registeretc. Tuple shapes and call semantics are unchanged.
Here's an example.
public class ContextMenuIntegration {
// This is used to register your plugin with the IPC. It will return an ID
// that you should save for later.
private ICallGateSubscriber<string> Register { get; }
// This is used to unregister your plugin from the IPC. You should call this
// when your plugin is unloaded.
private ICallGateSubscriber<string, object?> Unregister { get; }
// You should subscribe to this event in order to receive a notification
// when Hellion Chat is loaded or updated, so you can re-register.
private ICallGateSubscriber<object?> Available { get; }
// Subscribe to this to draw your custom context menu items.
private ICallGateSubscriber<string, PlayerPayload?, ulong, Payload?, SeString?, SeString?, object?> Invoke { get; }
// The registration ID.
private string? _id;
public HellionChatIpc(DalamudPluginInterface @interface) {
this.Register = @interface.GetIpcSubscriber<string>("HellionChat.Register");
this.Unregister = @interface.GetIpcSubscriber<string, object?>("HellionChat.Unregister");
this.Invoke = @interface.GetIpcSubscriber<string, PlayerPayload?, ulong, Payload?, SeString?, SeString?, object?>("HellionChat.Invoke");
this.Available = @interface.GetIpcSubscriber<object?>("HellionChat.Available");
}
public void Enable() {
// When Hellion Chat becomes available (if it loads after this plugin) or
// when Hellion Chat is updated, register automatically.
this.Available.Subscribe(() => this.Register());
// Register if Hellion Chat is already loaded.
this.Register();
// Listen for context menu events.
this.Invoke.Subscribe(this.Integration);
}
private void Register() {
// Register and save the registration ID.
this._id = this.Register.InvokeFunc();
}
public void Disable() {
if (this._id != null) {
this.Unregister.InvokeAction(this._id);
this._id = null;
}
this.Invoke.Unsubscribe(this.Integration);
}
private void Integration(string id, PlayerPayload? sender, ulong contentId, Payload? payload, SeString? senderString, SeString? content) {
// Make sure the ID is the same as the saved registration ID.
if (id != this._id) {
return;
}
// Draw your custom menu items here.
// sender is the first PlayerPayload contained in the sender SeString
// contentId is the content ID of the message sender or 0 if not known
// payload is the payload that was right-clicked, if any (excluding text)
// senderString is the message sender SeString
// content is the message content SeString
if (ImGui.Selectable("Test plugin")) {
PluginLog.Log($"hi!\nsender: {sender}\ncontent id: {contentId:X}\npayload: {payload}\nsender string: {senderString}\ncontent string: {content}");
}
}
}
Typing State IPC
If you need to know whether the player is currently interacting with Hellion Chat's input box, subscribe to the typing IPC.
HellionChat.GetChatInputState: call this function to retrieve the current state.HellionChat.ChatInputStateChanged: subscribe to this event to receive updates whenever the state changes (and once immediately after subscribing). Both IPC endpoints use the same tuple payload:
(bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType)
InputVisible:truewhen Hellion Chat is not hidden by user/cutscene/battle settings.InputFocused:truewhile the Hellion Chat input box currently has keyboard focus.HasText:truewhen the input buffer contains more than whitespace.IsTyping: convenience flag (InputFocused && HasText).TextLength: length of the raw input buffer.ChannelType: theHellionChat.Code.ChatTyperepresenting the channel/mode that will be used if the buffer is submitted. This value comes from the current tab'sUsedChannel(HellionChat/Configuration.cs) which the plugin keeps in sync by hooking the in-game shell (HellionChat/GameFunctions/Chat.cs) and by resolving temporary overrides inside the chat UI (HellionChat/Ui/ChatLogWindow.cs:597).InputChannelvalues are converted into the exportedChatTypeviaHellionChat/Code/InputChannelExt.ToChatType. Example usage:
public sealed class TypingIntegration {
private ICallGateSubscriber<(bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType)> GetChatInputState { get; }
private ICallGateSubscriber<(bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType)> ChatInputStateChanged { get; }
public TypingIntegration(DalamudPluginInterface @interface) {
this.GetChatInputState = @interface.GetIpcSubscriber<(bool, bool, bool, bool, int, ChatType)>("HellionChat.GetChatInputState");
this.ChatInputStateChanged = @interface.GetIpcSubscriber<(bool, bool, bool, bool, int, ChatType)>("HellionChat.ChatInputStateChanged");
}
public void Enable() {
this.ChatInputStateChanged.Subscribe(OnChatInputStateChanged);
// Optionally poll the current state on enable.
var state = this.GetChatInputState.InvokeFunc();
PluginLog.Information($"Initial typing state: {state}");
}
public void Disable() {
this.ChatInputStateChanged.Unsubscribe(OnChatInputStateChanged);
}
private void OnChatInputStateChanged((bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType) state) {
if (state.IsTyping) {
// Show typing indicator.
} else {
// Hide typing indicator.
}
}
}
All integrations are called inside of an ImGui BeginMenu.