Dragonflight Talent System

The main focus of this guide is the new player talent tree systemhttps://worldofwarcraft.com/en-us/news/23814291/dragonflight-pre-expansion-update-notes-now-live#item1. Professions and "Generic" trees are sometimes mentioned, but professions in particular have some differences that this guide won't dive into.
Currently, the only "Generic" tree, is the dragonriding talent tree. If the system turns out to be a success, we can expect more generic trees in the future.
==Overview==
C_Traits contains all the generic APIs and interacts with C_ClassTalents for talent tree specific APIs, and C_ProfSpecs for profession specific APIs.
The hierarchy in the new talent system is:
 [system] - config >< tree < node < nodeEntry - nodeDefinition - spell
In other words (with wow.tools links added when db2 files line up, however, there are usually multiple tables involved for each entity):
* TraitSystem - specifies Generic trees, e.g. dragonriding talents. This is not part of the hierarchy for player talent trees or professions
* TraitConfig - when you apply your talent choices, you apply it to the config. Switching talent loadouts basically boils down to switching TraitConfig. A config can contain multiple TraitTrees (this is the case for professions, for talent trees there is only 1 TraitTree).
* TraitTree - a tree is basically a list of TraitNodes, and currency cost information. For talent trees, while visually there's a separate class and spec tree, in the API it's all 1 tree. There's 1 TraitTree per class. Professions have a TraitTree for each profession specialization tab.
* TraitNode - a node is roughly equivalent to a button in the tree UI. Nodes can have multiple entries, in particular, choice nodes will have 2, whereas single option nodes have 1.
* TraitNodeEntry - an entry holds information about a specific talent choice itself, including how many ranks it has.
* TraitDefinition - is directly related to a TraitNodeEntry, and will contain the spellID and/or other relevant information, of what a talent will actually do for a player.
These entities can all be queried with the C_Traits API, which is listed below
==Commands==
Several script and slash commandshttps://worldofwarcraft.com/en-us/news/23874318/updated-nov-15-dragonflight-pre-expansion-phase-2-update-notes-now-live#item11 have been added for accessibility and general use in ClassTalentHelper.lua
* Activate loadout by name:
/run ClassTalentHelper.SwitchToLoadoutByName("loadoutName")
/loadoutname loadoutName
/lon loadoutName
* Activate loadout by dropdown list order, starting with 1:
/run ClassTalentHelper.SwitchToLoadoutByIndex(1)
/loadoutindex 2
/loi 3
* Activate specialization by name:
/run ClassTalentHelper.SwitchToSpecializationByName("specName")
/specname specName
/spn specName
* Activate specialization by order within the Specializations tab, starting with 1:
/run ClassTalentHelper.SwitchToSpecializationByIndex(1)
/specindex 2
/spi 3
==Examples==
* Extracts the list of SpellIDs for the player's current specialization
function GetSpellIDList()
 local list = {}
 local configID = C_ClassTalents.GetActiveConfigID()
 if configID == nil then return end
 local configInfo = C_Traits.GetConfigInfo(configID)
 if configInfo == nil then return end
 for _, treeID in ipairs(configInfo.treeIDs) do -- in the context of talent trees, there is only 1 treeID
 local nodes = C_Traits.GetTreeNodes(treeID)
 for i, nodeID in ipairs(nodes) do
 local nodeInfo = C_Traits.GetNodeInfo(configID, nodeID)
 for _, entryID in ipairs(nodeInfo.entryIDs) do -- each node can have multiple entries (e.g. choice nodes have 2)
 local entryInfo = C_Traits.GetEntryInfo(configID, entryID)
 if entryInfo and entryInfo.definitionID then
 local definitionInfo = C_Traits.GetDefinitionInfo(entryInfo.definitionID)
 if definitionInfo.spellID then
 table.insert(list, definitionInfo.spellID)
 end
 end
 end
 end
 end
 return list
end
* Change a selection node choice, and apply the changes.
function SwitchDragonridingTalentSelection()
 local DRAGONRIDING_TRAIT_SYSTEM_ID = 1
 local nodeID = 64062 -- vigor regen node
 local configID = C_Traits.GetConfigIDBySystemID(DRAGONRIDING_TRAIT_SYSTEM_ID)
 -- for class talents, this should be: configID = C_ClassTalents.GetActiveConfigID()
 if not configID then return end
 local nodeInfo = C_Traits.GetNodeInfo(configID, nodeID)
 if not nodeInfo or not nodeInfo.entryIDs or 2 ~= #nodeInfo.entryIDs then return end
 local currentEntryID = nodeInfo.entryIDsWithCommittedRanks[1] or nil
 local currentSelection
 for index, entryID in ipairs(nodeInfo.entryIDs) do
 if entryID == currentEntryID then currentSelection = index end
 end
 local success = C_Traits.SetSelection(configID, nodeID, nodeInfo.entryIDs[currentSelection == 2 and 1 or 2]) -- defaults to setting the second option, if not currently set
 if not success then return end
 local commitSuccess = C_Traits.CommitConfig(configID)
 -- for class talents, this should be: commitSuccess = C_ClassTalents.CommitConfig(selectedLoadoutID)
end
* Get the currently selected loadout configID. Currently, there is no authoritative API to tell you which loadout is currently selected, so you have to do a best-effort guess instead.
function GetSelectedLoadoutConfigID()
 local lastSelected = PlayerUtil.GetCurrentSpecID() and C_ClassTalents.GetLastSelectedSavedConfigID(PlayerUtil.GetCurrentSpecID())
 local selectionID = ClassTalentFrame and ClassTalentFrame.TalentsTab and ClassTalentFrame.TalentsTab.LoadoutDropDown and ClassTalentFrame.TalentsTab.LoadoutDropDown.GetSelectionID and ClassTalentFrame.TalentsTab.LoadoutDropDown:GetSelectionID()
 -- the priority in authoritativeness is [default UI's dropdown] > [API] > ['ActiveConfigID'] > nil
 return selectionID or lastSelected or C_ClassTalents.GetActiveConfigID() or nil -- nil happens when you don't have any spec selected, e.g. on a freshly created character
end
* Checks if a spellID is a learned talent, note that this is an example to explain the API, and that it's generally encouraged to use instead.
function IsSpellTalented(spellID) -- this could be made to be a lot more efficient, if you already know the relevant nodeID and entryID
 local configID = C_ClassTalents.GetActiveConfigID()
 if configID == nil then return end
 local configInfo = C_Traits.GetConfigInfo(configID)
 if configInfo == nil then return end
 for _, treeID in ipairs(configInfo.treeIDs) do -- in the context of talent trees, there is only 1 treeID
 local nodes = C_Traits.GetTreeNodes(treeID)
 for i, nodeID in ipairs(nodes) do
 local nodeInfo = C_Traits.GetNodeInfo(configID, nodeID)
 for _, entryID in ipairs(nodeInfo.entryIDsWithCommittedRanks) do -- there should be 1 or 0
 local entryInfo = C_Traits.GetEntryInfo(configID, entryID)
 if entryInfo and entryInfo.definitionID then
 local definitionInfo = C_Traits.GetDefinitionInfo(entryInfo.definitionID)
 if definitionInfo.spellID == spellID then
 return true
 end
 end
 end
 end
 end
 return false
end
==References==