WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   pattern matching (https://www.wowinterface.com/forums/showthread.php?t=48291)

Caellian 10-02-13 01:03 AM

pattern matching
 
Hey, anyone good at this could help me match this message so i can filter it ?

Playername-Realm is now roleicon Tank. (Changed by Playerame.)

roleicon is, well, the icon :) and Realm may contain spaces

Phanx 10-02-13 02:06 AM

First, you need to figure out which global string gets used. When filtering system messages, you should always use the relevant global string, so it works in all languages and automatically works if/when Blizzard changes the string. In this case, it's ROLE_CHANGED_INFORM_WITH_SOURCE, which in its raw state looks like "%s is now %s. (Changed by %s.)" in English, "%s ist nun %s. (Von %s geändert.)" in German, etc.

Second, you need to use some gsub magic to turn that string into a pattern you can use with string.find. Here's the function I use that will turn any Blizzard global string into a search pattern:

Code:

local function topattern(str)
        str = gsub(str, "%%%d?$?c", ".+")
        str = gsub(str, "%%%d?$?s", ".+")
        str = gsub(str, "%%%d?$?d", "%%d+")
        str = gsub(str, "([%(%)])", "%%%1")
        return str
end

Notes:

(a) If you're only working with a few strings, you may be tempted to just gsub them directly, but then if Blizzard changes them (for example, changes %s tokens to %1$s tokens, or adds a token) you have to update. The above function will automatically handle any such changes, unless Blizzard adds some new type of tokens.

(b) The above function doesn't add captures, so it's mainly for use with string.find -- is this a "X defated Y in a duel" message? -- and not with string.match -- what are the values of X and Y in this message?.

Back on topic -- to hide the messages:

Code:

local pattern = topattern(ROLE_CHANGED_INFORM_WITH_SOURCE)

ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", function(frame, event, message, ...)
  return strfind(message, pattern)
end)

If you have a lot of messages to block (for example, if you wanted to block all the messages about how drunk other people are) I'd suggest putting them in an indexed table (faster than a hash table because you don't need a function call to iterate over it) and looping over it like so:

Code:

local patterns = {
  topattern(DRUNK_MESSAGE_ITEM_OTHER1),
  topattern(DRUNK_MESSAGE_ITEM_OTHER2),
  topattern(DRUNK_MESSAGE_ITEM_OTHER3),
  topattern(DRUNK_MESSAGE_ITEM_OTHER4),
  topattern(DRUNK_MESSAGE_OTHER1),
  topattern(DRUNK_MESSAGE_OTHER2),
  topattern(DRUNK_MESSAGE_OTHER3),
  topattern(DRUNK_MESSAGE_OTHER4),
}

ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", function(frame, event, message, ...)
  for i = 1, #patterns do
      if strfind(message, patterns[i]) then
        return true
      end
  end
end)


Caellian 10-02-13 03:39 AM

This is absolutely perfect, and will simplify my filters file ten fold.

There's one system message i can't seem to find in the GlobalStrings though "Playername is not online."

Any idea how it's possible that it isn't there ? Could it be an addon sending a message through that channel or ?

Phanx 10-02-13 03:49 AM

Well, you could search your Addons folder for the phrase "not online". Some messages are sent pre-formed from the server, though, and don't have global strings, so you'll have to use hardcoded translations for them, unfortunately. :/

Caellian 10-02-13 04:06 AM

Did that, but:

Search "is not online." (0 hits in 0 files)

Ah well, that's no big deal, thanks a lot anyway !

Caellian 10-02-13 07:40 AM

So it should look like this but somehow, the role thingy isn't filtered

Code:

local patternize = function(text)
        text = gsub(text, "%%%d?$?c", ".+")
        text = gsub(text, "%%%d?$?s", ".+")
        text = gsub(text, "%%%d?$?d", "%%d+")
        text = gsub(text, "([%(%)])", "%%%1")

        return text
end

local patterns = {
        patternize(CLEARED_AFK),
        patternize(MARKED_AFK),
        patternize(CLEARED_DND),
        patternize(MARKED_DND),

        patternize(NEW_TITLE_EARNED),
        patternize(ERR_FRIEND_ONLINE_SS),
        patternize(BN_INLINE_TOAST_FRIEND_ONLINE),
        patternize(ERR_FRIEND_OFFLINE_S),
        patternize(BN_INLINE_TOAST_FRIEND_OFFLINE),
        patternize(ERR_LEARN_SPELL_S),
        patternize(ERR_LEARN_ABILITY_S),
        patternize(ERR_LEARN_PASSIVE_S),
        patternize(ERR_SPELL_UNLEARNED_S),
        patternize(ERR_PET_SPELL_UNLEARNED_S),
        patternize(ERR_GUILD_INTERNAL),
        patternize(ROLE_CHANGED_INFORM_WITH_SOURCE),
        patternize(ERR_INSTANCE_GROUP_ADDED_S),
        patternize(ERR_INSTANCE_GROUP_REMOVED_S)
}

ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", function(frame, event, message, ...)
  for i = 1, #patterns do
      if strfind(message, patterns[i]) then
        return true
      end
  end
end)


Phanx 10-02-13 02:41 PM

Code:

ROLE_CHANGED_INFORM = "%s is now %s.";
ROLE_CHANGED_INFORM_WITH_SOURCE = "%s is now %s. (Changed by %s.)";

You've got #2 on your list, but you're missing #1.

Caellian 10-10-13 11:45 AM

Quote:

Originally Posted by Phanx (Post 285427)
Code:

ROLE_CHANGED_INFORM = "%s is now %s.";
ROLE_CHANGED_INFORM_WITH_SOURCE = "%s is now %s. (Changed by %s.)";

You've got #2 on your list, but you're missing #1.

Phanx, i think that you're pattern function doesn't catch this one at all :(

Phanx 10-11-13 02:14 AM

What? I meant that your code is missing a string, and that's why you're still seeing messages about roles being changed. There are two separate global strings for this:

Code:

ROLE_CHANGED_INFORM_WITH_SOURCE = "%s is now %s. (Changed by %s.)";
^ This string is used when one player changes another player's role, eg. the raid leader right-clicks on someone's unit frame, and sets them as a tank.

Code:

ROLE_CHANGED_INFORM = "%s is now %s.";
^ This string is used when a player sets their own role, or when their role is set automatically, eg. by the LFR system.

Your code only looks for the first string (changed by another player) and not the second one.

Caellian 10-11-13 03:56 AM

Oh i know, i do have both, but those just aren't filtered:

Code:

local topattern = function(text)
        text = gsub(text, "%%%d?$?c", ".+")
        text = gsub(text, "%%%d?$?s", ".+")
        text = gsub(text, "%%%d?$?d", "%%d+")
        text = gsub(text, "([%(%)])", "%%%1")

        return text
end

local patterns = {
        topattern(CLEARED_AFK),
        topattern(MARKED_AFK),
        topattern(CLEARED_DND),
        topattern(MARKED_DND),

        topattern(NEW_TITLE_EARNED),
        topattern(ERR_FRIEND_ONLINE_SS),
        topattern(BN_INLINE_TOAST_FRIEND_ONLINE),
        topattern(ERR_FRIEND_OFFLINE_S),
        topattern(BN_INLINE_TOAST_FRIEND_OFFLINE),
        topattern(ERR_LEARN_SPELL_S),
        topattern(ERR_LEARN_ABILITY_S),
        topattern(ERR_LEARN_PASSIVE_S),
        topattern(ERR_SPELL_UNLEARNED_S),
        topattern(ERR_PET_SPELL_UNLEARNED_S),
        topattern(ERR_GUILD_INTERNAL),
        topattern(ERR_INSTANCE_GROUP_ADDED_S),
        topattern(ERR_INSTANCE_GROUP_REMOVED_S),
        topattern(ERR_BG_PLAYER_LEFT_S),
        topattern(ERR_BG_PLAYER_JOINED_SS),
        topattern(ROLE_CHANGED_INFORM),
        topattern(ROLE_CHANGED_INFORM_WITH_SOURCE),
}


Phanx 10-11-13 08:09 PM

Use debug prints to figure out what the problem is.

Code:

local topattern = function(text)
        text = gsub(text, "%%%d?$?c", ".+")
        text = gsub(text, "%%%d?$?s", ".+")
        text = gsub(text, "%%%d?$?d", "%%d+")
        text = gsub(text, "([%(%)])", "%%%1")
        return text
end

local a = topattern(ROLE_CHANGED_INFORM)
local b = topattern(ROLE_CHANGED_INFORM_WITH_SOURCE)

ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", function(frame, event, message)
        if strfind(message, " is now ") then
                -- Display the raw message text without transforming escapes:
                print("MESSAGE:", gsub(message, "\124", "\124\124"))
                -- Display the raw patterns + whether they matched:
                print(strfind(message, a) and "MATCH:" or "NO MATCH:", a)
                print(strfind(message, b) and "MATCH:" or "NO MATCH:", b)
        end
end)


Caellian 10-12-13 12:12 AM

Thing is, with this, absolutely nothing gets printed. How can that be ?

Lombra 10-12-13 02:32 AM

The first print is missing a closing parenthesis. You'll want to enable Lua errors to catch these kind of errors easily.

Caellian 10-12-13 02:33 AM

Quote:

Originally Posted by Lombra (Post 285774)
The first print is missing a closing parenthesis. You'll want to enable Lua errors to catch these kind of errors easily.


Well, no, obviously i fixed that before even trying :)

Lombra 10-12-13 02:37 AM

Then "if strfind(message, " is now ") then" must be failing. Print the message too, I guess, just to be sure.

Caellian 10-12-13 03:02 AM

Quote:

Originally Posted by Lombra (Post 285776)
Then "if strfind(message, " is now ") then" must be failing. Print the message too, I guess, just to be sure.

I changed it to "now" for testing purposes, here's the result:

Code:

NO MATCH: .+ is now .+.
NO MATCH: .+ is now .+. %(Changed by .+.%)


Lombra 10-12-13 03:34 AM

And what's the chat message?

Caellian 10-12-13 03:43 AM

Quote:

Originally Posted by Lombra (Post 285779)
And what's the chat message?

That's the part i don't get, since it has nothing to do with it.

Code:

MESSAGE: You are now queued in the Raid Finder. 0
Also, well i'm not sure yet, but it looks like it only doesn't work in battlegrounds, nothing gets printed at all.

Hard to tell for now. Doesn't make much sense tbh.

Rilgamon 10-12-13 04:11 AM

So a chat msg fits your "if" but the whole message is not in your patterns. Whats wrong ?

Caellian 10-12-13 04:15 AM

Quote:

Originally Posted by Rilgamon (Post 285781)
So a chat msg fits your "if" but the whole message is not in your patterns. Whats wrong ?

Well, i assumed those patterns where able to match just about every globalstrings.

Rilgamon 10-12-13 06:02 AM

They do, when you add the global string of the message ("You are now queued in the Raid Finder.") to your pattern list.

from GlobalStrings.lua
Lua Code:
  1. ERR_LFG_JOINED_RF_QUEUE = "You are now queued in the Raid Finder.";

Caellian 10-12-13 06:19 AM

Quote:

Originally Posted by Rilgamon (Post 285784)
They do, when you add the global string of the message ("You are now queued in the Raid Finder.") to your pattern list.

from GlobalStrings.lua
Lua Code:
  1. ERR_LFG_JOINED_RF_QUEUE = "You are now queued in the Raid Finder.";

You're missunderstanding, that's not at all what i'm trying to filter, i'm guessing that one was taken because it has "now" in it, since my catch wasn't specific enough.

This is what i want to filter, but those just aren't:

Code:

ROLE_CHANGED_INFORM = "%s is now %s.";
ROLE_CHANGED_INFORM_WITH_SOURCE = "%s is now %s. (Changed by %s.)";


Lombra 10-12-13 06:41 AM

Quote:

Originally Posted by Caellian (Post 285780)
That's the part i don't get, since it has nothing to do with it.

Code:

MESSAGE: You are now queued in the Raid Finder. 0
Also, well i'm not sure yet, but it looks like it only doesn't work in battlegrounds, nothing gets printed at all.

Hard to tell for now. Doesn't make much sense tbh.

Is that what your addon prints when in your chat frame you see "[Player] is now [role]." or what are you saying?

Move the print(message) to outside of the if-block and see what it says when someone sets their role.



EDIT: Ok ok, it's not even a chat event, hah. :P
Code:

ROLE_CHANGED_INFORM(changed, from, oldRole, newRole)
You can probably just do this to remove these messages:
Code:

RoleChangedFrame:UnregisterEvent("ROLE_CHANGED_INFORM")
Now that I think of it, I seem to recall this from some other thread...

Rilgamon 10-12-13 07:07 AM

Ups, did not expect that ... for the records:

http://wowprogramming.com/utils/xmlb...L/RolePoll.xml
Code:

    <Frame name="RoleChangedFrame" parent="UIParent">
        <Scripts>
            <OnLoad function="RoleChangedFrame_OnLoad"/>
            <OnEvent function="RoleChangedFrame_OnEvent"/>
        </Scripts>
    </Frame>

http://wowprogramming.com/utils/xmlb...L/RolePoll.lua

Lua Code:
  1. function RoleChangedFrame_OnLoad(self)
  2.     self:RegisterEvent("ROLE_CHANGED_INFORM");
  3. end
  4.  
  5. function RoleChangedFrame_OnEvent(self, event, ...)
  6.     if ( event == "ROLE_CHANGED_INFORM" ) then
  7.         local changed, from, oldRole, newRole = ...;
  8.          
  9.         if ( newRole == "NONE" ) then
  10.             if ( changed == from ) then
  11.                 ChatFrame_DisplaySystemMessageInPrimary(format(ROLE_REMOVED_INFORM, changed));
  12.             else
  13.                 ChatFrame_DisplaySystemMessageInPrimary(format(ROLE_REMOVED_INFORM_WITH_SOURCE, changed, from));
  14.             end
  15.         else
  16.             local displayedRole = _G["INLINE_"..newRole.."_ICON"].." ".._G[newRole];    --Uses INLINE_TANK_ICON, etc.
  17.             if ( changed == from ) then
  18.                 ChatFrame_DisplaySystemMessageInPrimary(format(ROLE_CHANGED_INFORM, changed, displayedRole));
  19.             else
  20.                 ChatFrame_DisplaySystemMessageInPrimary(format(ROLE_CHANGED_INFORM_WITH_SOURCE, changed, displayedRole, from));
  21.             end
  22.         end
  23.     end
  24. end

Caellian 10-12-13 07:41 AM

Sure these are events, but as you can see, there's something sent to chat "ChatFrame_DisplaySystemMessageInPrimary"

There's no need to unregister the event, there has to be a way to just filter the message, right ?

And the question is, why aren't the patterns catching them ?

Lombra 10-12-13 07:52 AM

Quote:

Originally Posted by Caellian (Post 285790)
Sure these are events, but as you can see, there's something sent to chat "ChatFrame_DisplaySystemMessageInPrimary"

There's no need to unregister the event, there has to be a way to just filter the message, right ?

Sure, you can override ChatFrame1.AddMessage and filter it out that way. Wouldn't recommend it, though. If your only mission is to suppress these messages, then unregister that event. The only purpose of RoleChangedFrame is to print out those messages, as far as I can tell. There's no reason to look for another way.

Quote:

Originally Posted by Caellian (Post 285790)
And the question is, why aren't the patterns catching them ?

Because they aren't chat events. The chat filtering system doesn't work on any event, only CHAT_MSG_* events. Edit: To answer the exact question; because those messages never reach that pattern test. The pattern is fine.

Caellian 10-12-13 09:17 AM

Code:

RoleChangedFrame:UnregisterAllEvents()
Works, obviously.

But it bothers me. Why the filtering way wouldn't work. I mean, those messages are sent to CHAT_MSG_SYSTEM right ?

So, if they are why can't i filter them there like just about anything else being sent to the chat ?

Lombra 10-12-13 10:17 AM

Quote:

Originally Posted by Caellian (Post 285790)
But it bothers me. Why the filtering way wouldn't work. I mean, those messages are sent to CHAT_MSG_SYSTEM right ?

They are not. CHAT_MSG_SYSTEM is a real event. Nothing is "sent to" being a chat event. When I say chat event I just mean the events that are handled by the chat frame. In this case the event is ROLE_CHANGED_INFORM, nothing else.

Caellian 10-12-13 10:20 AM

Quote:

Originally Posted by Lombra (Post 285796)
They are not.

ChatFrame_DisplaySystemMessageInPrimary ?

Or not, i don't know :)

Phanx 10-13-13 02:39 AM

Quote:

Originally Posted by Caellian (Post 285764)
Thing is, with this, absolutely nothing gets printed. How can that be ?

It should only print something when a role changed message appears. If you're not playing in an English client, you'll need to change the " is now " search string to the appropriate text to match in your language.

Also, you may want to change the last line in topattern to escape all the "magic characters", not just parentheses. For my purposes it didn't matter, but if you're using it on other global strings, it might matter.

Code:

text = gsub(text, "([%(%)%.%%%+%-%*%?%[%^%$])", "%%%1")

Caellian 10-13-13 03:32 AM

Quote:

Originally Posted by Phanx (Post 285811)
It should only print something when a role changed message appears. If you're not playing in an English client, you'll need to change the " is now " search string to the appropriate text to match in your language.

That's the thing, i am on an enGB client, playing on a frFR realm but that doesn't make any difference and the " is now " didn't catch anything.

Quote:

Originally Posted by Phanx (Post 285811)
Also, you may want to change the last line in topattern to escape all the "magic characters", not just parentheses. For my purposes it didn't matter, but if you're using it on other global strings, it might matter.

Code:

text = gsub(text, "([%(%)%.%%%+%-%*%?%[%^%$])", "%%%1")

Done, i'll try again like this though i didn't notice any other special characters other than the (Changed by...)

Caellian 10-16-13 08:53 AM

Quote:

Originally Posted by Phanx (Post 285811)
Code:

text = gsub(text, "([%(%)%.%%%+%-%*%?%[%^%$])", "%%%1")

Phanx, this new line doesn't work when for example, switching between 2 specs on a hunter, "Your pet has unlearned..."


All times are GMT -6. The time now is 12:31 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI