Thread Tools Display Modes
08-05-05, 01:19 PM   #1
Cladhaire
Salad!
 
Cladhaire's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Jul 2005
Posts: 1,935
Table.sort and other issues for HealTracker

I'm in the process of polishing up a healer-side heal tracker, so you can track your efficiency and your overhealing percentage. I do this by grabbing the events for periodic and regular heals, and checking the health of the target of the heal. Right now its kinda clunky but its working. Essentially it gives you a short listing of your top 5 or 10 heal targets (by total amount) and gives you an efficiency rating on that user. You can then mouseover the user to get detailed information about each spell you've cast.

I've got two problem I'm trying to work out to keep the code as efficient as possible. Table structure looks like:

table["Player"].total
table["Player"].actual
table["Player"]["Spell"].total
table["Player"]["Spell"].actual
table["Player"]["Spell"].casts
table["Player"]["Spell"].crits

I give detailed stats about each individual spell, so you can gauge your efficiency on each type of heal.

Since the table is keyed, I wasn't able to get it sorted based upon the interior elements, so to cut down on the sort time and memory, I'm building an external table of the keys, and sorting that based upon the info we have. For example:

{"Sagart", "Dewin", "Satrina"}

function (a,b) return healStats.a.total > healStats.b.total end)

And that seems to sort the table well, without too many lookups, but I'm wondering if I'm missing something that could make this easier.

The second issue I'm concerned about is the clunky method to lookup the health of the current target.

Code:
function HealTracker_GetActual(unitName, amount)
	local unitID = nil
	
	if unitName == "you" then unitID = "player" end
	
	for i, trialUnit in { "party1", "party2", "party3", "party4" } do
		if ( unitName == UnitName(trialUnit) ) then
			unitID = trialUnit
        end
    end
    for i=1,40,1 do
        local trialUnit = "raid"..i;
        if ( unitName == UnitName(trialUnit) ) then
			unitID = trialUnit
        end
    end

	if not unitID then return nil end
	
	local missinghp = UnitHealthMax(unitID) - UnitHealth(unitID);
	local healState = amount - missinghp;
	if healState > 0 then return missinghp else return amount end

end
What I plan for here is building a table once of name to unit for lookup, and updating that on party_change events which looks like it will work fine and improve the code, but I'm wondering if anyone has a better idea.

Thanks!
  Reply With Quote
08-05-05, 03:33 PM   #2
Littlejohn
A Warpwood Thunder Caller
AddOn Author - Click to view addons
Join Date: Jun 2005
Posts: 90
The code you have is really not bad. (Yeah, I know, glowing praise. Seriously though, unless the code is in a tight loop or OnUpdate it probably won't make much performance difference.)

The sort problem can be solved without making a table of keys -- just make another table from the contents of the keyed table. When you assign a table to a variable, Lua doesn't copy the table; it just shares the original table. If you know what a pointer is, what you want to do is create two tables that contain pointers to the same player info. One table is indexed by player name. The other table is sorted by index. Maybe this example will help:

Code:
local player = { }
player["foo"] = { name = "foo", total = 10, actual = 17 }
player["bar"] = { name = "bar", total = 7, actual = 47 }
player["goo"] = { name = "goo", total = 12, actual = 5 }

local sorted_player = { }
for k, v in player do
    table.insert(sorted_player, v)
end

table.sort(sorted_player, function(x, y)
			      return x.total > y.total
			  end)

for i=1,3 do
    print(sorted_player[i].name, sorted_player[i].total)
end
The HealTracker_GetActual can get you in a bit more trouble because you've got a couple loops that you will always run through even if you find the player name on the first pass. Lua lets you break out of loops with the "break" statement. If you add a cache and break out of the loops, I think this function works fine. (I would move the player name lookup into its own function of course. You'll probably want to use this code in other parts of your add-on.)

One thing you might think is ugly is my replacing your "partyN" loop with a numeric loop. Surprisingly the "party"..i does not generate garbage, but the { "party1", ... } does. Lua has shared (or interned) strings. This means that every time it builds a string, it looks up the string in a master dictionary to see if the string already exists. If it does, then the new string is thrown away and the old string is re-used. Lua doesn't do this for tables though. In your original code, the party table is re-created (and thrown away) every time.

Here's my implementation of HealTracker_GetActual:

Code:
local unit_name_to_id = { }

function HealTracker_GetActual(unit_name, amount)
    local unit_id = unit_name_to_id[unit_name]

    if not unit_id then
	if unit_name == "you" then
	    unit_id = "player"
	else
	    for i=1, 4 do
		local trialUnit = "party"..i
		if unit_name == UnitName(trialUnit) then
		    unit_id = trialUnit
		    break
		end
	    end

	    if not unit_id then
		for i=1, 40 do
		    local trialUnit = "raid"..i
		    if unit_name == UnitName(trialUnit) then
			unit_id = trialUnit
			break
		    end
		end
	    end
	end

	unit_name_to_id[unit_name] = unit_id
    end

    if not unit_id then
	return nil
    end

    local missinghp = UnitHealthMax(unit_id) - UnitHealth(unit_id)
    local healState = amount - missinghp

    if healState > 0 then
	return missinghp
    else
	return amount
    end
end
By the way, are you the Cladhaire that Vika has blessed with taking over WatchDog? I've got some patches for WatchDog if you are. I'm also curious about Vika and his disappearance. Can you fill us in with details? Think he's going to be back soon?
  Reply With Quote
08-09-05, 07:39 AM   #3
Cladhaire
Salad!
 
Cladhaire's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Jul 2005
Posts: 1,935
Thanks for the response LJ... Yes I am the same Cladhaire that is taking over development of WatchDog.. and if your'e the one who posted a while ago in the WoW forums about efficiency of the parsing algorithm, then I've been looking for you :P

Vika has been called away by the miliary and at this point his account is cancelled and has no plans to return. He's passed full control of the mod over to me (which is a scary thing) but asked me to keep in the main spirit of what he was trying to accomplish. I'm working on some siginifigant rewrite right now, particularly in the loading/saving of the savedvariables, which may no longer be an issue with per-add-on files.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Table.sort and other issues for HealTracker

Thread Tools
Display Modes

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