Thread Tools Display Modes
10-16-11, 03:03 PM   #1
Animor
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Mar 2011
Posts: 136
LUA error - my addon collides with WIM

Hello ppl,

I'm working on a chat addon, in which I use ChatFrame_AddMessageEventFilter for officer chat. The filter breaks the message into several lines by adding "\n".
The addon works fine with this filter. However, when I run it with WIM addon loaded, I get this LUA error:

Code:
Message: memory allocation error: block too big
Time: 10/16/11 22:45:19
Count: 4
Stack: [C]: ?
[C]: in function `insert'
Interface\AddOns\hebChat\hebChat.lua:512: in function `filterFunc'
Interface\AddOns\WIM\WIM.lua:314: in function `honorChatFrameEventFilter'
Interface\AddOns\WIM\Modules\ChatEngine.lua:409: in function `handler'
...s\WIM\Libs\LibChatHandler-1.0\LibChatHandler-1.0.lua:267: in function <...s\WIM\Libs\LibChatHandler-1.0\LibChatHandler-1.0.lua:252>
...s\WIM\Libs\LibChatHandler-1.0\LibChatHandler-1.0.lua:308: in function <...s\WIM\Libs\LibChatHandler-1.0\LibChatHandler-1.0.lua:296>

Locals:
Line 512 in my code is simply the place where I insert \n on several locations in the message:
Code:
table.insert(newStringTable, lineStringBkp.."\n")
I looked in WIM code and found this honorChatFrameEventFilter:
Code:
function WIM.honorChatFrameEventFilter(event, ...)
        local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15 = ...;
        local chatFilters = _G.ChatFrame_GetMessageEventFilters(event);
	local filter = false;
        if chatFilters then
            local narg1, narg2, narg3, narg4, narg5, narg6, narg7, narg8, narg9, narg10, narg11, narg12, narg13, narg14, narg15;
            for _, filterFunc in next, chatFilters do
		filter, narg1, narg2, narg3, narg4, narg5, narg6, narg7, narg8, narg9, narg10, narg11, narg12, narg13, narg14, narg15 = filterFunc(workerFrame, event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
                if filter then 
                    return true, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15; 
                elseif(narg1) then
                    arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 = narg1, narg2, narg3, narg4, narg5, narg6, narg7, narg8, narg9, narg10, narg11, narg12, narg13, narg14, narg15;
                end
            end 
        end 
        return filter, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15;
end
I have no idea what could be the problem. Any help is appreciated!
  Reply With Quote
10-16-11, 04:46 PM   #2
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
I don't think that's relevant to WIM.

Does 'newStringTable' keep growing indefinitely?

If yes that's your problem.
  Reply With Quote
10-16-11, 05:01 PM   #3
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
This is a relevant discussion from a couple years back.
  Reply With Quote
10-17-11, 02:24 AM   #4
Animor
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Mar 2011
Posts: 136
Thank you

Then I should understand what is wrong with my filterfunc.
I have the following declared in this func:
Code:
local newStringTable			= {}
This is the table I insert the lines to. But as you can see I reset it every time the func begins. In addition, it wouldn't work if it will just grow indefinitely because I display its content on the screen as the new/modified text.

I also have this:
Code:
local tempFrame	= CreateFrame("Frame", nil, UIParent)
tempFrame:Hide()
tempFrame.text = tempFrame:CreateFontString()
tempFrame.text:SetAllPoints(tempFrame)	
tempFrame.text:SetFont(hebChat.fonts[hebChatDB.currentFont][2], hebChatDB.currentFontSize)
This is a fontstring I use it to measure a string width, in order to know where to break the lines.

In addition, I have 2 while loops, one nested inside the other. Perhaps it's too much?
These loops run on each char of the message string.

The thing is I get the error on the first thing I write in Officer chat, even if it's only one single letter. So it's not that these local variables can grow indefinitely until then.
  Reply With Quote
10-17-11, 02:26 AM   #5
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
You should probably post your full code.
  Reply With Quote
10-17-11, 02:46 AM   #6
Animor
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Mar 2011
Posts: 136
filterfunc calling:
Code:
ChatFrame_AddMessageEventFilter("CHAT_MSG_OFFICER", hebChat.hebChatFixWrap)
filterfunc code:
Code:
function hebChat.hebChatFixWrap(chatFrame, event, msg, author, ...)
  local remainingString			= msg
  local newStringTable	         	= {}
  local newString			= ""
  local lineString			= ""
  local lineStringBkp			= ""
  local remainingStringBkp		= ""
  local chatFrameWidth			= chatFrame:GetWidth()
  local effectiveChatFrameWidth	   = 0
  local header1				= ""
  local headerWidth1			= 0
  local headerWidth2			= 0

  -- In case of hebrew char	
  if (msg:find("[א-ת]")) then

	-- Create temporary frame to calculate string width
	local tempFrame			= CreateFrame("Frame", nil, UIParent)
	tempFrame:Hide()
	tempFrame.text = tempFrame:CreateFontString()
	tempFrame.text:SetAllPoints(tempFrame)	
	tempFrame.text:SetFont(hebChat.fonts[hebChatDB.currentFont][2], ebChatDB.currentFontSize)

	-- Calculate header widths
	if (event == "CHAT_MSG_WHISPER" or event == CHAT_MSG_BN_WHISPER") then
		header = "["..author.."] whispers: "
	elseif (event == "CHAT_MSG_WHISPER_INFORM" or event == CHAT_MSG_BN_WHISPER_INFORM") then
		header = "To ["..author.."]: "
	elseif (event == "CHAT_MSG_GUILD") then
		header = "[Guild] ["..author.."]: "
	elseif (event == "CHAT_MSG_OFFICER") then
		header = "[Officer] ["..author.."]: "
	elseif (event == "CHAT_MSG_RAID") then
		header = "[Raid] ["..author.."]: "
	elseif (event == "CHAT_MSG_PARTY") then
		header = "[Party] ["..author.."]: "
	elseif (event == "CHAT_MSG_BN_CONVERSATION") then
		header = "11. [Conversation] ["..author.."]: "
	else
		header = ""
	end
	
	tempFrame.text:SetText(header)
	headerWidth1 = tempFrame.text:GetStringWidth()
	tempFrame.text:SetText("[2")
	headerWidth2 = tempFrame.text:GetStringWidth()	
	-- first line effective width
	effectiveChatFrameWidth = chatFrameWidth - headerWidth1 - 10
			
	-- Prepare for outer while loop
	tempFrame.text:SetText(remainingString)
		
	while (tempFrame.text:GetStringWidth() > effectiveChatFrameWidth)	do			
		-- Prepare for inner while loop		
		tempFrame.text:SetText(lineString)	
		while (tempFrame.text:GetStringWidth() <= effectiveChatFrameWidth) do			
			-- Extract last char
			lineString		= utf8sub(remainingString, strlenutf8(remainingString), 1)..lineString
			remainingString	= utf8sub(remainingString, 1, strlenutf8(remainingString) - 1)						
			-- Store current lineString between words and move last space to end of line
			if (lineString:find("^%s")) then
				lineStringBkp		= utf8sub(lineString, 2, strlenutf8(lineString) - 1)..utf8sub(lineString, 1, 1)				
				remainingStringBkp	= remainingString				
			end			
			-- Prepare for next while loop check 
			tempFrame.text:SetText(lineString)
		end -- Inner while loop
		-- out of inner while loop: lineString is wider than frame width
		
		if (#lineStringBkp ~= 0) then			
			remainingString = remainingStringBkp
		else
			-- Single word longer than width - just add the word
			lineStringBkp			= lineString			
		end
			
		-- Break lines and insert to table.
		table.insert(newStringTable, lineStringBkp.."\n")
		
		-- Prepare for outer while loop 
		tempFrame.text:SetText(remainingString)
		-- non-first line effective width
		effectiveChatFrameWidth = chatFrameWidth - headerWidth2 - 10
		-- reset strings
		lineStringBkp	= ""
		lineString		= ""		
	end -- Outer while loop	
	table.insert (newStringTable, remainingString)
	newString = table.concat(newStringTable)	
	return false, newString, author, ...
	--return false
  else
	return false
  end
	
end
  Reply With Quote
10-17-11, 04:21 AM   #7
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
Try this for starters.

filterfunc code:
Code:
local newStringTable = {}
local tempFrame = CreateFrame("Frame", nil, UIParent)
tempFrame.text = tempFrame:CreateFontString()
tempFrame.text:SetAllPoints(tempFrame)
tempFrame:Hide()

function hebChat.hebChatFixWrap(chatFrame, event, msg, author, ...)
  local remainingString			= msg
  wipe(newStringTable)
  local newString			= ""
  local lineString			= ""
  local lineStringBkp			= ""
  local remainingStringBkp		= ""
  local chatFrameWidth			= chatFrame:GetWidth()
  local effectiveChatFrameWidth	   = 0
  local header1				= ""
  local headerWidth1			= 0
  local headerWidth2			= 0

  -- In case of hebrew char	
  if (msg:find("[א-ת]")) then

	tempFrame.text:SetFont(hebChat.fonts[hebChatDB.currentFont][2], ebChatDB.currentFontSize)

	-- Calculate header widths
	if (event == "CHAT_MSG_WHISPER" or event == CHAT_MSG_BN_WHISPER") then
		header = "["..author.."] whispers: "
	elseif (event == "CHAT_MSG_WHISPER_INFORM" or event == CHAT_MSG_BN_WHISPER_INFORM") then
		header = "To ["..author.."]: "
	elseif (event == "CHAT_MSG_GUILD") then
		header = "[Guild] ["..author.."]: "
	elseif (event == "CHAT_MSG_OFFICER") then
		header = "[Officer] ["..author.."]: "
	elseif (event == "CHAT_MSG_RAID") then
		header = "[Raid] ["..author.."]: "
	elseif (event == "CHAT_MSG_PARTY") then
		header = "[Party] ["..author.."]: "
	elseif (event == "CHAT_MSG_BN_CONVERSATION") then
		header = "11. [Conversation] ["..author.."]: "
	else
		header = ""
	end
	
	tempFrame.text:SetText(header)
	headerWidth1 = tempFrame.text:GetStringWidth()
	tempFrame.text:SetText("[2")
	headerWidth2 = tempFrame.text:GetStringWidth()	
	-- first line effective width
	effectiveChatFrameWidth = chatFrameWidth - headerWidth1 - 10
			
	-- Prepare for outer while loop
	tempFrame.text:SetText(remainingString)
		
	while (tempFrame.text:GetStringWidth() > effectiveChatFrameWidth)	do			
		-- Prepare for inner while loop		
		tempFrame.text:SetText(lineString)	
		while (tempFrame.text:GetStringWidth() <= effectiveChatFrameWidth) do			
			-- Extract last char
			lineString		= utf8sub(remainingString, strlenutf8(remainingString), 1)..lineString
			remainingString	= utf8sub(remainingString, 1, strlenutf8(remainingString) - 1)						
			-- Store current lineString between words and move last space to end of line
			if (lineString:find("^%s")) then
				lineStringBkp		= utf8sub(lineString, 2, strlenutf8(lineString) - 1)..utf8sub(lineString, 1, 1)				
				remainingStringBkp	= remainingString				
			end			
			-- Prepare for next while loop check 
			tempFrame.text:SetText(lineString)
		end -- Inner while loop
		-- out of inner while loop: lineString is wider than frame width
		
		if (#lineStringBkp ~= 0) then			
			remainingString = remainingStringBkp
		else
			-- Single word longer than width - just add the word
			lineStringBkp			= lineString			
		end
			
		-- Break lines and insert to table.
		table.insert(newStringTable, lineStringBkp.."\n")
		
		-- Prepare for outer while loop 
		tempFrame.text:SetText(remainingString)
		-- non-first line effective width
		effectiveChatFrameWidth = chatFrameWidth - headerWidth2 - 10
		-- reset strings
		lineStringBkp	= ""
		lineString		= ""		
	end -- Outer while loop	
	table.insert (newStringTable, remainingString)
	newString = table.concat(newStringTable)	
	return false, newString, author, ...
	--return false
  else
	return false
  end
	
end
  Reply With Quote
10-17-11, 05:11 AM   #8
Animor
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Mar 2011
Posts: 136
Thank you for your answer.

I have found the reason for the error. I've removed line after line from my code, until I had only the outer while loop with almost no content in it. Then the game stuck, without even giving lua error.
So I made some var prints and I realized WIM is running my filterfunc as well.
WIM got into infinite loop since
Code:
local chatFrameWidth			= chatFrame:GetWidth()
returned 0 for him. Hence, the while condition was always true, for ever.

What is the reason for that? How can I make WIM get the correct width when running my filterfunc?
Perhaps it is related to the "workerFrame" WIM is passing to the filterfunc?

Last edited by Animor : 10-17-11 at 05:13 AM.
  Reply With Quote
10-17-11, 05:18 AM   #9
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
Nice, but you should still avoid creating a new table and new frame every time your filter function runs.
  Reply With Quote
10-17-11, 05:21 AM   #10
Animor
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Mar 2011
Posts: 136
Originally Posted by Dridzt View Post
Nice, but you should still avoid creating a new table and new frame every time your filter function runs.
Yea, I will fix that. I thought that making it local inside the function is memory-friendly. But I will do as you suggested and wipe the table.

Do you have an idea how to fix the chatframe width and WIM?
  Reply With Quote
10-17-11, 09:08 AM   #11
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
I can't run the code in-game atm so this is just guessing,
but it looks like you're "eating" the chatframe in your function

Your filterfunc is passed chatframe, event, msg, author, ...

ie 4 named parameters and the ellipsis (...) with any more params passed
but later you return from msg onward - newstring, author, ...
  Reply With Quote
10-17-11, 09:20 AM   #12
Animor
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Mar 2011
Posts: 136
Originally Posted by Dridzt View Post
I can't run the code in-game atm so this is just guessing,
but it looks like you're "eating" the chatframe in your function

Your filterfunc is passed chatframe, event, msg, author, ...

ie 4 named parameters and the ellipsis (...) with any more params passed
but later you return from msg onward - newstring, author, ...
I did it according to the explanation here:
http://www.wowpedia.org/API_ChatFram...ageEventFilter

and specific line:
Code:
filter, arg1, arg2, arg3, ..., arg11 = myFilterFunc(chatFrame, event, arg1, arg2, arg3, ..., arg11);
Anyway, the new msg is working, so I guess it's in the right place.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » LUA error - my addon collides with WIM


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off