Patch 2.4.0/Consolidated API changes/Guide to the New Combat Log

Introduction
This information is a copy of Slouken's post on the US WoW forums describing the new combat logging system (source, archived)

Hello Fellow UI Modders,

With the release of patch 2.4.0, we’ve made some enormous changes to the existing combat log. While this will result in some hard work now, it should be easier to maintain your AddOns in the future.

The feature we’re most proud of is the ability to filter your combat log. The combat log stores the last five minutes worth of raw combat events. Filters can be setup on multiple criteria, affiliation, ownership, etc. Any events that match the current filter are passed through the client via the COMBAT_LOG_EVENT message. The combat log filter is global. However, AddOns which want to parse all events the moment they happen can register for the COMBAT_LOG_EVENT_UNFILTERED message. This should allow all existing AddOns to still respond to combat events without a complicated middle-manager AddOn. While the default combat log will only be setting 1-2 filters at a time, the WoW client supports many simultaneous filters. It’s possible to setup multiple filters to filter very specific source-target-event combinations. If a combat log event passes any of the filters, the COMBAT_LOG_EVENT event fires. This allows AddOns to define extremely specific settings we chose not expose in the base UI.

The new combat log will be coming with two text formats. One is the familiar, grammatically correct sentences with substitutions. The other is a terse format, containing the source, target, spell, action and result. There will be a number of ways to manipulate the formatting, from unit name coloring to coloring the damage numbers by their magic school. The settings used for these formats are stored in the Blizzard_CombatLog_Filters variable.

The result of the new terse format is that it’s very easy to write AddOns to modify or extend the format which ships with 2.4.0. In the formatting section, you can read up on a quick demonstration of how to convert the combat log to a “Nurfed” style combat log. While you can do a lot by just adjusting the settings within WoW, it’s also possible to provide an AddOn that changes the strings used to generate the Combat Log messages. This allows for more extensive formatting changes without re-writing the entire parsing engine. See the Formatting Section for an example.

The whole combat log also supports a new coloring model, based on context. While by default, entire lines are a single color, highlighting the most important details. The combat log also supports coloring just unit names, spells, actions and damage numbers. Spells and damage can also be colored by school. However, there are several features not exposed in the base UI that AddOns can use right away. These are event-specific coloring, unit coloring with greater granularity and the ability to customize the list of highlighted events.

There are several other formatting related features. You can enable timestamps which show the time that spell or attack happened. You can show or hide square braces, change formatting without refreshing the combat log and disable the display of raid icons. These features were too niche to go into the base UI, but can be easily exposed for power users. By now you’ve already thought of some features of your own and are ready to get to coding. So let’s jump straight to some examples.

Formatting & Coloring
One of the major combat log formats we considered while redoing the combat log was the Nurfed Combat Log format. This combat log format was very concise, made heavy use of color-coding and was one of the final candidates for the combat log. We eventually axed it on the basis of being too overwhelming for new users. However, we left in all of the options to convert the current combat log into the Nurfed combat log.

Here’s how: Combat Log Settings -> Colors

Unit Colors: Me 	-> Green My Pet -> Dark Green Friends -> Blue Enemies -> Red Neutral -> Yellow

Colorize: Unit Names	 	-> Checked Spell Names 		-> Checked Spell Color-by-School 	-> Checked Damage Number	 	-> Checked Damage Color-by-School -> Checked Damage School 		-> Checked Entire Line 		-> Unchecked All Highlighting Options-> Unchecked

Formatting: Verbose 		-> Unchecked Braces 			-> Checked Timestamps 		-> Checked

However, some people may want it even more terse than that. For this, we present:

Hyper Condensed Mode

To get rid of the word “Fire” and “Frost” type:

/script TEXT_MODE_A_STRING_VALUE_SCHOOL = "";

That will remove the Fire from “55 Fire”. However, let’s go even farther:

(Critical) (Crushing) (Blocked) (Resisted)

All of these are really long. Let’s compress them:

TEXT_MODE_A_STRING_RESULT_RESISTED = "R";

TEXT_MODE_A_STRING_RESULT_BLOCKED = "B";

TEXT_MODE_A_STRING_RESULT_ABSORBED = "A";

TEXT_MODE_A_STRING_RESULT_CRITICAL = "C";

TEXT_MODE_A_STRING_RESULT_GLANCING = "G";

TEXT_MODE_A_STRING_RESULT_CRUSHING = "Cr";

Now we get

[You] [Fireball] Hit [Spider] 64. (C) (5 R)

Filters
Filters consistent of 3 parts: * Source * Target * Events Source & Target can be one of two types: * String * Number If it is a string, then that string is assumed to be the GUID of the unit in question. If it’s a number, it is assumed to be a bitfield assembled from the following criteria:

Constants
-- Affiliation

COMBATLOG_OBJECT_AFFILIATION_MINE		= 0x00000001;

COMBATLOG_OBJECT_AFFILIATION_PARTY		= 0x00000002;

COMBATLOG_OBJECT_AFFILIATION_RAID		= 0x00000004;

COMBATLOG_OBJECT_AFFILIATION_OUTSIDER		= 0x00000008;

COMBATLOG_OBJECT_AFFILIATION_MASK		= 0x0000000F;

-- Reaction

COMBATLOG_OBJECT_REACTION_FRIENDLY		= 0x00000010;

COMBATLOG_OBJECT_REACTION_NEUTRAL		= 0x00000020;

COMBATLOG_OBJECT_REACTION_HOSTILE		= 0x00000040;

COMBATLOG_OBJECT_REACTION_MASK			= 0x000000F0;

-- Ownership

COMBATLOG_OBJECT_CONTROL_PLAYER			= 0x00000100;

COMBATLOG_OBJECT_CONTROL_NPC			= 0x00000200;

COMBATLOG_OBJECT_CONTROL_MASK			= 0x00000300;

-- Unit type

COMBATLOG_OBJECT_TYPE_PLAYER			= 0x00000400;

COMBATLOG_OBJECT_TYPE_NPC			= 0x00000800;

COMBATLOG_OBJECT_TYPE_PET			= 0x00001000;

COMBATLOG_OBJECT_TYPE_GUARDIAN			= 0x00002000;

COMBATLOG_OBJECT_TYPE_OBJECT			= 0x00004000;

COMBATLOG_OBJECT_TYPE_MASK			= 0x0000FC00;

-- Special cases (non-exclusive)

COMBATLOG_OBJECT_TARGET				= 0x00010000;

COMBATLOG_OBJECT_FOCUS				= 0x00020000;

COMBATLOG_OBJECT_MAINTANK			= 0x00040000;

COMBATLOG_OBJECT_MAINASSIST			= 0x00080000;

COMBATLOG_OBJECT_RAIDTARGET1			= 0x00100000;

COMBATLOG_OBJECT_RAIDTARGET2			= 0x00200000;

COMBATLOG_OBJECT_RAIDTARGET3			= 0x00400000;

COMBATLOG_OBJECT_RAIDTARGET4			= 0x00800000;

COMBATLOG_OBJECT_RAIDTARGET5			= 0x01000000;

COMBATLOG_OBJECT_RAIDTARGET6			= 0x02000000;

COMBATLOG_OBJECT_RAIDTARGET7			= 0x04000000;

COMBATLOG_OBJECT_RAIDTARGET8			= 0x08000000;

COMBATLOG_OBJECT_NONE				= 0x80000000;

COMBATLOG_OBJECT_SPECIAL_MASK			= 0xFFFF0000;

A unit can only be one of the following four categories: 1. Affiliation 2. Reaction 3. Ownership 4. Type

Here’s a quick explanation of how these flags are broken down:

Affiliation:
A unit’s affiliation is the unit’s relationship relative to YOU. Either it is owned by you, your party, your raid or someone else.

[[[Mine]Party]Raid] Outsiders

Reaction:
This is the unit’s faction reaction, relative to you. Anything that hates you is Hostile, anything that is friendly with you is Friendly, everything else is Neutral.

Ownership:
This is who owns this object. It can only be controlled by a player or the server.

Unit Type:
This is the way the unit is currently being controlled. Units directly controlled by their owner are players. Units controlled by the server are NPCs. Pets are controlled by another player or unit. Guardians are automatons that are not controlled, but automatically defend their master. Objects are everything else, such as Traps.

The result is that these bits can tell you what kind of unit that combat log object was.

Example: A player who is dueling you is 0x0548. (A hostile outsider who is both owned by a player and controlled as a player) A player who was mind controlled that attacks you is 0x1148. (A hostile outsiders who is owned by a player, but controlled as a pet)

Default Filters
The default filters are constructed by summing certain bit combinations together:

COMBATLOG_FILTER_MINE	= bit.bor (

COMBATLOG_OBJECT_AFFILIATION_MINE,

COMBATLOG_OBJECT_REACTION_FRIENDLY,

COMBATLOG_OBJECT_CONTROL_PLAYER,

COMBATLOG_OBJECT_TYPE_PLAYER,

COMBATLOG_OBJECT_TYPE_OBJECT

);

This means that everything colored mine by default must be affiliated with me, friendly, controlled by a player and be a player.

Any unit that matches at least one bit in each of the four exclusive categories will pass the filter test. Filters can have more than one bit set in a category.

COMBATLOG_FILTER_FRIENDLY_UNITS = bit.bor(

COMBATLOG_OBJECT_AFFILIATION_PARTY,

COMBATLOG_OBJECT_AFFILIATION_RAID,

COMBATLOG_OBJECT_AFFILIATION_OUTSIDER,

COMBATLOG_OBJECT_REACTION_FRIENDLY,

COMBATLOG_OBJECT_CONTROL_PLAYER,

COMBATLOG_OBJECT_CONTROL_NPC,

COMBATLOG_OBJECT_TYPE_PLAYER,

COMBATLOG_OBJECT_TYPE_NPC,

COMBATLOG_OBJECT_TYPE_PET,

COMBATLOG_OBJECT_TYPE_GUARDIAN,

COMBATLOG_OBJECT_TYPE_OBJECT

);

This will allow messages relating to any unit who has a friendly reaction with you, the player. (Another way to do this is to use the “_MASK” suffixed globals, rather than specifying all bits, but I did it this way to make the point clear).

Setting up Filters
Each time you call the CombatLogAddFilter function, you add a new filter. Any unit that passes that filter fires the COMBAT_LOG_EVENT event. For example, if you wanted to see anything that you did and anything hostile enemies did to you, you would call the following CombatLogAddFilter(nil, COMBATLOG_FILTER_MINE, nil)

CombatLogAddFilter(nil, COMBATLOG_FILTER_HOSTILE_UNITS, COMBATLOG_FILTER_MINE nil)

Retrieving Combat Messages
Once you setup your filter, all of the entries which match that filter are organized into a linked list. By calling CombatLogSetCurrentEntry(1), you set the current pointer to the beginning of that list. If no message exists, CombatLogSetCurrentEntry(1) will fail. If you pass a negative number into CombatLogSetCurrentEntry, it will select the Nth entry from the end of the list.

To move the pointer forward, call CombatLogAdvanceEntry(1) to move to the next entry in the list.

The CombatLogGetCurrentEntry and COMBAT_LOG_EVENT events will return all of the arguments for that event. The exact argument order depends on the event, but here are the arguments that do not change:

timestamp, event, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags = CombatLogGetCurrentEntry

Events
There are honestly too many events to go into detail on all of them here, but here’s the basic organization.

Base Events:

 * SWING – These events relate to melee swings, commonly called “White Damage”.
 * RANGE – These events relate to hunters shooting their bow or a warlock shooting their wand.
 * SPELL – These events relate to spells and abilities.
 * SPELL_CAST – These events relate to spells starting and failing.
 * SPELL_AURA – These events relate to buffs and debuffs.
 * SPELL_PERIODIC – These events relate to HoT, DoTs and similar effects.
 * DAMAGE_SHIELD – These events relate to damage shields, such as Thorns
 * ENCHANT – These events relate to temporary and permanent item buffs.
 * ENVIRONMENTAL – This is any damage done by the world. Fires, Lava, Falling, etc.

Suffixes:

 * _DAMAGE – If the event resulted in damage, here it is.
 * _MISSED - If the event resulted in failure, such as missing, resisting or being blocked.
 * _HEAL – If the event resulted in a heal.
 * _ENERGIZE – If the event resulted in a power restoration.
 * _LEECH – If the event transferred health or power.
 * _DRAIN – If the event reduces power, but did not transfer it.

Special Events:

 * PARTY_KILL – Fired when you or a party member kills something.
 * UNIT_DIED – Fired when any nearby unit dies.

Q & A:
Q: The combat log only stores 5 minutes of events. Why 5? Why not 10? A: We feel that 5 minutes is a good base number for most players. You can change this length, however with the CombatLogSetRetentionTime(seconds) function.

Q: Will the combat log be saved when I logout to my character list? A: No. However, if you only reload the UI, the messages stay in the client.

Q: Why did you do it this way? Why didn’t you do it X way? A: We tried to expose as much information as we could, without compromising gameplay and giving us the feature set we needed.

Q: Why didn’t you include information about who owns ? A: This was one we considered for a while, but decided to leave out for the sake of simplicity. We’re going to be watching how the new combat log plays out before adding new features or making additional changes.

Q: Why did the CombatLog.txt file change? A: Changing the CombatLog.txt format freed us to implement the combat log in this new event-driven way. We also felt that providing the combat log as raw data made parsing easier for sites such as WoW Web Stats, avoiding localization issues.

Q: Will the combat log format change again? A: We’re always dedicated to improving our game, so we will very likely be making changes again in the future. However, we do realize the frustration that comes with AddOns breaking between patches. Hopefully, this new system will actually reduce how often you need to recode your AddOns, by decoupling AddOn authors from localization changes.

Q: Can we provide feedback on the new combat log? A: Absolutely! We’ll be reading the Test Forums during the 2.4.0 PTR and gathering feedback. The more constructive, clear and concise the feedback is, the more responsive we can be.