1+ using Dalamud . Game . Text ;
12using SomethingNeedDoing . Core . Events ;
23using SomethingNeedDoing . Core . Interfaces ;
4+ using System . Text . RegularExpressions ;
35using System . Threading . Tasks ;
46
57namespace SomethingNeedDoing . Managers ;
@@ -13,7 +15,8 @@ namespace SomethingNeedDoing.Managers;
1315/// <param name="macro">The macro containing the function.</param>
1416/// <param name="functionName">The name of the function.</param>
1517/// <param name="eventType">The trigger event this function handles.</param>
16- public class TriggerFunction ( IMacro macro , string functionName , TriggerEvent eventType )
18+ /// <param name="chatMessageFilter">Optional chat message filter configuration.</param>
19+ public class TriggerFunction ( IMacro macro , string functionName , TriggerEvent eventType , ChatMessageFilterConfig ? chatMessageFilter = null )
1720{
1821 /// <summary>
1922 /// Gets the macro containing this function.
@@ -44,6 +47,11 @@ public class TriggerFunction(IMacro macro, string functionName, TriggerEvent eve
4447 ? functionName . Split ( '_' ) [ 2 ]
4548 : null ;
4649
50+ /// <summary>
51+ /// Gets the chat message filter configuration for OnChatMessage triggers.
52+ /// </summary>
53+ public ChatMessageFilterConfig ? ChatMessageFilter { get ; } = chatMessageFilter ;
54+
4755 /// <inheritdoc/>
4856 public override bool Equals ( object ? obj )
4957 => obj is TriggerFunction other && Macro . Id == other . Macro . Id && FunctionName == other . FunctionName ;
@@ -79,7 +87,11 @@ public void RegisterTrigger(IMacro macro, TriggerEvent eventType)
7987 if ( ! EventHandlers . ContainsKey ( eventType ) )
8088 EventHandlers [ eventType ] = [ ] ;
8189
82- var triggerFunction = new TriggerFunction ( macro , string . Empty , eventType ) ;
90+ ChatMessageFilterConfig ? chatFilter = null ;
91+ if ( eventType == TriggerEvent . OnChatMessage && macro . Metadata . ChatMessageFilter != null )
92+ chatFilter = macro . Metadata . ChatMessageFilter ;
93+
94+ var triggerFunction = new TriggerFunction ( macro , string . Empty , eventType , chatFilter ) ;
8395 if ( ! EventHandlers [ eventType ] . Contains ( triggerFunction ) )
8496 EventHandlers [ eventType ] . Add ( triggerFunction ) ;
8597 }
@@ -122,7 +134,11 @@ public void RegisterFunctionTrigger(IMacro macro, string functionName)
122134 if ( ! EventHandlers . ContainsKey ( eventType ) )
123135 EventHandlers [ eventType ] = [ ] ;
124136
125- var triggerFunction = new TriggerFunction ( macro , functionName , eventType ) ;
137+ ChatMessageFilterConfig ? chatFilter = null ;
138+ if ( eventType == TriggerEvent . OnChatMessage && macro . Metadata . FunctionChatFilters . TryGetValue ( functionName , out var filter ) )
139+ chatFilter = filter ;
140+
141+ var triggerFunction = new TriggerFunction ( macro , functionName , eventType , chatFilter ) ;
126142 if ( EventHandlers [ eventType ] . Contains ( triggerFunction ) )
127143 {
128144 FrameworkLogger . Debug ( $ "Function trigger already registered for macro { macro . Name } function { functionName } event { eventType } ") ;
@@ -222,6 +238,11 @@ public async Task RaiseTriggerEvent(TriggerEvent eventType, object? data = null)
222238 continue ;
223239 }
224240
241+ // For OnChatMessage, check if the message matches the filter
242+ if ( eventType == TriggerEvent . OnChatMessage && data is Dictionary < string , object > chatData )
243+ if ( ! MatchesChatMessageFilter ( chatData , triggerFunction . ChatMessageFilter ) )
244+ continue ;
245+
225246 if ( string . IsNullOrEmpty ( triggerFunction . FunctionName ) )
226247 {
227248 // Macro-level trigger: raise the event for the entire macro
@@ -248,6 +269,72 @@ public async Task RaiseTriggerEvent(TriggerEvent eventType, object? data = null)
248269 }
249270 }
250271
272+ /// <summary>
273+ /// Checks if a chat message matches the given filter configuration.
274+ /// </summary>
275+ /// <param name="chatData">The chat message data dictionary.</param>
276+ /// <param name="filter">The filter configuration to check against.</param>
277+ /// <returns>True if the message matches the filter (or if no filter is specified), false otherwise.</returns>
278+ private static bool MatchesChatMessageFilter ( Dictionary < string , object > chatData , ChatMessageFilterConfig ? filter )
279+ {
280+ if ( filter == null )
281+ return true ;
282+
283+ if ( filter . Channels != null && filter . Channels . Count > 0 )
284+ {
285+ if ( chatData . TryGetValue ( "type" , out var typeObj ) && typeObj is XivChatType chatType )
286+ {
287+ if ( ! filter . Channels . Contains ( chatType ) )
288+ return false ;
289+ }
290+ else
291+ return false ;
292+ }
293+
294+ if ( ! string . IsNullOrEmpty ( filter . MessageContains ) )
295+ {
296+ if ( chatData . TryGetValue ( "message" , out var messageObj ) && messageObj is string message )
297+ {
298+ if ( ! message . Contains ( filter . MessageContains , StringComparison . OrdinalIgnoreCase ) )
299+ return false ;
300+ }
301+ else
302+ return false ;
303+ }
304+
305+ if ( ! string . IsNullOrEmpty ( filter . SenderContains ) )
306+ {
307+ if ( chatData . TryGetValue ( "sender" , out var senderObj ) && senderObj is string sender )
308+ {
309+ if ( ! sender . Contains ( filter . SenderContains , StringComparison . OrdinalIgnoreCase ) )
310+ return false ;
311+ }
312+ else
313+ return false ;
314+ }
315+
316+ if ( ! string . IsNullOrEmpty ( filter . MessageRegex ) )
317+ {
318+ if ( chatData . TryGetValue ( "message" , out var messageObj ) && messageObj is string message )
319+ {
320+ try
321+ {
322+ if ( ! Regex . IsMatch ( message , filter . MessageRegex , RegexOptions . IgnoreCase ) )
323+ return false ;
324+ }
325+ catch ( ArgumentException )
326+ {
327+ FrameworkLogger . Warning ( $ "Invalid regex pattern in chat message filter: { filter . MessageRegex } ") ;
328+ return false ;
329+ }
330+ }
331+ else
332+ return false ;
333+ }
334+
335+ return true ;
336+ }
337+
251338 /// <summary>
252339 /// Disposes of the trigger event manager.
253340 /// </summary>
0 commit comments