LibQuickHealth-2.0

From WowAce Wiki
Jump to: navigation, search
Summary
Lib: QuickHealth-2.0
TOC 2.4 (20400)
Category Libraries
Authors Tifi, Cncfanatics
Details
Links
Betas Ace SVN Zip
Changelog FishEye

LibQuickHealth-2.0 is a library that provides more up to date health data than the default Blizz events and functions.

In addition to the standard UNIT_HEALTH event, the library listens to combat log events (COMBAT_LOG_EVENT_UNFILTERED, or CLEU) to update health values. CLEU fires more often than UNIT_HEALTH, and it allows the library to get around the ~300ms throttling of UNIT_HEALTH updates. Throttling means that two UNIT_HEALTH events are at least 300ms apart. It doesn't mean that UNIT_HEALTH fires every 300ms, or that the maximum gain by using the library is 300ms.

The interesting CLEU events are those containing health differences (damage and heals). Normally, when UNIT_HEALTH fires, those differences add up to the value reported by Blizz's UnitHealth. But sometimes, when a unit takes damage according to the CLEU, that damage is processed *after* the next UNIT_HEALTH event. This is called "pending damage". One of the features of LibQuickHealth-2.0 (and an improvement over 1.0) is to detect pending damage, and incorporate it into the health values that are presented to players.

It is not clear why pending damage occurs, but it appears to be due to Blizz's server code. Damage seems to have some sort of extra lag built in. A temporal difference of 600-800ms between a CLEU and the corresponding UNIT_HEALTH event is not uncommon when it comes to damage.

Usage

The library supports two events, UnitHealthUpdated and HealthUpdated. The difference is that HealthUpdated fires for GUIDs, and UnitHealthUpdated fires for unitIDs. Those events not only replace UNIT_HEALTH, but also UNIT_MAXHEALTH. That means even if only the max health changes (but not the health), UnitHealthUpdated and HealthUpdated would fire. QuickHealth.UnitHealth replaces Blizz's UnitHealth. See example 2 below.

To start listening to the event, do QuickHealth.RegisterCallback(YourAddonTableHere, "eventName", HandlerMethodHere). The "HealthUpdated" callback triggers with 5 arguments: self, event, guid, health, healthMax (first two passed by the callbackhandler). The "UnitHealthUpdated" callback triggers with 5 arguments: self, event, unitID, health, healthMax. Additionaly, QuickHealth.UnitHealth(unitID) can be called to get what QuickHealth thinks is the current health.

Example 1: Using UnitHealthUpdated

	local QuickHealth = LibStub("LibQuickHealth-2.0")
	local MyAddon = {}
	function MyAddon:Initialize()
		-- Note: It's QuickHealth.RegisterCallback(), not QuickHealth:RegisterCallback().
		QuickHealth.RegisterCallback(MyAddon, "UnitHealthUpdated", "UnitHealthUpdated")
	end
	function MyAddon:UnitHealthUpdated(event, unitID, health, healthMax)
		assert(event == "UnitHealthUpdated")
		ChatFrame1:AddMessage(format("%s HealthUpdated %i/%i", unitID, health, healthMax))
		assert(health==QuickHealth.UnitHealth(unitID))
	end


Example 2: Making LibQuickHealth an optional dependency

	local QuickHealth = LibStub and LibStub("LibQuickHealth-2.0", true) -- don't error if not found
	local UnitHealth = QuickHealth and QuickHealth.UnitHealth or UnitHealth
	MyAddon = ...
	function MyAddon:Initialize()
		if QuickHealth then
			-- Add QuickHealth support. Register for the event and add a simple adapter method.
			QuickHealth.RegisterCallback(MyAddon, "UnitHealthUpdated", "UnitHealthUpdated")
			function MyAddon:UnitHealthUpdated(event, unitID)
				self:UpdateStuff(unitID)
			end
		else
			-- Assuming it's an Ace addon.
			MyAddon:RegisterEvent("UNIT_HEALTH", "UpdateStuff")
			MyAddon:RegisterEvent("UNIT_MAXHEALTH", "UpdateStuff")
		end
	end
	function MyAddon:UpdateStuff(unitID)
		local hp, max = UnitHealth(unitID), UnitHealthMax(unitID)
		-- do something with hp and max
	end


Example 3: Using HealthUpdated

	local QuickHealth = LibStub("LibQuickHealth-2.0")
	local MyAddon = {}
	function MyAddon:Initialize()
		QuickHealth.RegisterCallback(MyAddon, "HealthUpdated", "HealthUpdated")
	end
	function MyAddon:HealthUpdated(event, guid, health, healthMax)
		assert(event == "HealthUpdated")
		ChatFrame1:AddMessage(format("%s HealthUpdated %i/%i", guid, health, healthMax))
	end

Limitations

  • Sometimes there are combat log entries like this: -6000 (damage), +5000 (heal). But what really happened on the server was that the heal occured first. If at least part of this heal was overheal, the prediction (-6000+5000 = -1000) is way off, because what happened is for example +50 heal first(4950 overheal), and then 6000 damage, for a total of +50-6000 = -5950. No AddOn could possibly prevent or predict this, but luckily these cases are very rare.
However, if you see something like this happening (tank at ~100%, then takes damage instantly followed by a heal), you should know that this heal might have been overheal. So don't cancel your heal. ;)
  • If the maximum health changes, pending damage is completely ignored. Example: The tank is at 11001/18000, takes 9001 damage and uses Last Stand at the same time. Your client might tell you now that the tank health is 16401/23400 (+30% health and max health), because that 9k hit was not yet processed (pending damage). What the library does is: Show the tank at 11001/18000, then at 11001-9001 = 2000/18000, then at 16401/23400, because pending damage is ignored. But on the server, the tank has only 16401-9001 = 7400/23400 health!
This looks very similar to the case before: The tank takes damage, but shortly afterwards that damage is (magically) undone. Again, if you see this, don't cancel your heal!
  • Bloodrush and Life Tap. There's no combat log entry for the health lost.
  • Exceptionally large HP5 values. There are no combat log entries for HP5 ticks, which occur every 2 seconds. The library assumes that the health regen in combat is between 0 and 50 HP5, i.e. HP5 ticks between 0 and 20. Common HP5 values: Demon skin/armor <=18 (24 talented?), Elixir of Major Fortitude 10, Enchant Boots - Vitality 4. Less common: Dreaming Glory 30 (buff from herbalism), and a few level 60 items.
So the library might get confused by two things: Small amounts of pending damage (20 or less), and Warlocks with herbalism...

Differences to LibQuickHealth-1.0

  1. AddOns using LibQuickHealth-2.0 are advised not to listen to UNIT_HEALTH or UNIT_MAXHEALTH anymore. The library will always fire when a health change occurs. UnitHealthUpdated will also fire for units that don't have fast updates, like target while targeting a mob.
  2. HealthUpdated fires for GUIDs. But if unitIDs are more convenient, AddOns can now listen to UnitHealthUpdated. UnitHealthUpdated means that the library needs to keep track of the GUID->unitIDs map, which is extra work. Not much, but if HealthUpdated is enough for you (for example if your AddOn only needs updates for player), you should use it.
  3. Note that QuickHealth.UnitHealth changed from method notation QuickHealth:UnitHealth('unitID') to function notation QuickHealth.UnitHealth('unitID').