Technical Documentation: PathOfBuildingCommunity/PathOfBuilding
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (README.md)
Path of Building Community
Welcome to Path of Building, an offline build planner for Path of Exile!
Features
- Comprehensive offence + defence calculations:
- Calculate your skill DPS, damage over time, life/mana/ES totals and much more!
- Can factor in auras, buffs, charges, curses, monster resistances and more, to estimate your effective DPS
- Also calculates life/mana reservations
- Shows a summary of character stats in the side bar, as well as a detailed calculations breakdown tab which can show you how the stats were derived
- Supports all skills and support gems, and most passives and item modifiers
- Throughout the program, supported modifiers will show in blue and unsupported ones in red
- Full support for minions
- Support for party play and support builds
- Passive skill tree planner:
- Support for jewels including most radius/conversion and timeless jewels
- Features alternate path tracing (mouse over a sequence of nodes while holding shift, then click to allocate them all)
- Fully integrated with the offence/defence calculations; see exactly how each node will affect your character!
- Can import PathOfExile.com and PoEPlanner.com passive tree links; links shortened with PoEURL.com also work
- Skill planner:
- Add any number of main or supporting skills to your build
- Supporting skills (auras, curses, buffs) can be toggled on and off
- Automatically applies Socketed Gem modifiers from the item a skill is socketed into
- Automatically applies support gems granted by items
- Item planner:
- Add items from in game by copying and pasting them straight into the program!
- Automatically adds quality to non-corrupted items
- Search the trade site for the most impactful items
- Fully integrated with the offence/defence calculations; see exactly how much of an upgrade a given item is!
- Contains a searchable database of all uniques that are currently in game (and some that aren't yet!)
- You can choose the modifier rolls when you add a unique to your build
- Includes all league-specific items and legacy variants
- Features an item crafting system:
- You can select from any of the game's base item types
- You can select prefix/suffix modifiers from lists
- Custom modifiers can be added, with Master and Essence modifiers available
- Also contains a database of rare item templates:
- Allows you to create rare items for your build to approximate the gear you will be using
- Choose which modifiers appear on each item, and the rolls for each modifier, to suit your needs
- Has templates that should cover the majority of builds
- Other features:
- You can import passive tree, items, and skills from existing characters
- Share builds with other users by generating a share code
- Automatic updating; most updates will only take a couple of seconds to apply
Download
Head over to the Releases page to download the install wizard or portable zip.
Changelog
You can find the full version history here.
Contribute
You can find instructions on how to contribute code and bug reports here.
Licence
For 3rd-party licences, see LICENSE.
The licencing information is considered to be part of the documentation.
AddingMods (`docs/addingMods.md`)
In this tutorial, we'll step through the logic in ModParser.lua. This module takes care of parsing mods from any item, passive node, or pantheon in the game. This won't be comprehensive, since there are many patterns, and a lot of examples to work off of. If you'd like to follow along, the code starts here. Having a good understanding of Lua patterns will also be invaluable here (If you know regex, patterns will be similar, but less powerful and a different syntax).
Jewels
The first mods parsed are mods from jewels with a radius. Jewels with a radius care about the nodes around them. Since PoB doesn't know where these jewels will be placed when parsing the mod, a function is prepared for when the jewel has access to this information. Any variable data are passed along much like other mods via pattern capture (i.e. anywhere you see cap1, cap2, etc., corresponds to a captured number from the Lua pattern) See CalcSetup.buildModListForNode() for the code that handles actually calling the function to modify any nodes. There are several helper functions specific to each type of jewel, but they all boil down to this function (which can be used on its own, when necessary):
function(node, out, data)node: The node that is being affected within the radius. Can use things likenode.typeto determine notable or keystone, for exampleout: Instance ofModListClass, used for altering or replacing the mod originally on the nodedata: other data that might be relevant. Mostly just used for preserving the source withdata.modSource
There are 4 categories of jewels that have a helper function:
- Jewels that modify nodes in their radius (
jewelOtherFuncs). Uses customized functions for each jewel most of the time.getSimpleConv(srcList, dst, type, remove, factor)srcList: List of stats that will be affected in the radiusdst: Stat that those stats should apply to as well or insteadtype: The type of increase that should apply (usually "INC" or "BASE")remove: boolean that says whether or not to remove the original statsfactor: If the conversion shouldn't apply the full value, apply this factor instead
- Jewels that modify themselves based on stats allocated in their radius
getPerStat(dst, modType, flags, stat, factor)- The first three parameters correspond to name, modType, and flags in the mod syntax, where only
ModFlags are used stat: The stat we're multiplying thedststat byfactor: If the stats aren't 1:1, use this factor to change that
- The first three parameters correspond to name, modType, and flags in the mod syntax, where only
- Jewels that modify themselves based on stats unallocated in their radius. This uses the same
getPerStatfunction as above. - Threshold jewels, which give stats after 40 of that stat is reached in their radius
getThreshold(attrib, name, modType, value, ...)attrib: The attribute we need to reach a threshold for- The rest of the parameters are covered in the mod syntax
- Cluster jewels, which parse simply what mods to add to their nodes and which notables to add as well.
Scanning for matching text
The next steps all use the scan function to match text. It looks for the earliest and longest match from the given pattern list. If a match is found, it returns the value from the list, the remaining unmatched text, and any captures associated with the matched pattern. For example, passing in "15% increased fire damage", and a table containing the key "^(%d+)%% increased" would return the value corresponding to the key, "fire damage", and 15.
Special mods - `specialModList`
This is the largest list of ModParser and it's a catch-all for mods that don't fit a standard format (and aren't numerous enough to change the parsing logic to accommodate their format). If the mod has a component captured via Lua pattern, a function can be used to capture the number(s) or other captured text. E.g. ["lose ([%d%.]+) mana per second"] = function(num) return { mod("ManaDegen", "BASE", num) } end,
Otherwise everything in this list can be done using the standard mod syntax
Parts of a "standard mod"
The mod we'll demonstrate adding is "Attack skills deal 20% increased damage while holding a Shield" from the Solidity notable on the passive tree.
PreFlags - `preFlagList`
The first step in the process is scanning the text for text that matches one in the preFlag list. In this case, we find ["^attack skills [hd][ae][va][el] "] = { keywordFlags = KeywordFlag.Attack }, and save that flag for later, continuing on with "20% increased damage while holding a Shield".
Skill Tag - `preSkillNameList`
This looks for a skill name at the start of the line, usually used for enchantments. Our example is not based on a skill, so we continue with the rest of the line.
Mod form - `formList`
This is the meat of the mod parsing logic. Most mods will match one of these styles. In our case, we match ["^(%d+)%% increased"] = "INC",, store the 20% off to be eventually used as modValue, and continue with "damage while holding a shield".
Mod Tags - `modTagList`
This logic is run through twice, so we can have up to two tags after a mod to restrict it. In our case, we only have one tag, and it matches on ["while holding a shield"] = { tag = { type = "Condition", var = "UsingShield" } }, and we continue on with "damage" as the only thing left of our line.
Mod Name - `modNameList`
Finally we look through modNameList and match the remainder of our line on ["damage"] = "Damage",, leaving us with nothing remaining in our line.
Putting it all together
Our example is fairly simple, as some mod forms will slightly alter mod names and values to be compatible with with names used elsewhere in PoB. Regardless, once we have the mod name, type, value, and tags, we can combine them all into a mod as defined in the mod syntax.
Important notes and tips
ModParser.luais actually not where most mods really come from. When you refresh the dev mode version of PoB withCtrl+F5,ModParser.luaruns and regeneratesModCache.lua, which stores the actual parsed version of the mod.ModParser.luaonly gets used if the mod doesn't already exist somewhere when loading PoB (passive tree, unique list, or rare item list). If you hold left alt while hovering over a mod, you can see how it gets parsed:If you're missing something, you can also see what is unable to be parsed:
All mods get converted to lower case before getting parsed, so when adding a new one make sure it's also lowercase.
When adding a mod, see if you can add a new flag, or mod tag, before adding it to
specialModList. It makes the code much cleaner overall.When a mod changes, keep in mind backwards compatibility. Since mods in most builds contain just the raw mod text, and are not tied to the underlying mod from GGG's data, we need to keep old mod wordings intact so those keep working on older builds. This is especially true for mods that have gone legacy (i.e. can still exist in game)
Miscellaneous
There are a few flags you might see attached to mods that are defined in this section. These have to do with enemy or minion modifiers, or mods that don't directly affect the player.
AddingSkills (`docs/addingSkills.md`)
Skills in Path of Building are generated from what is called a template file. These template files are used when exporting data from the ggpk and can be found here. While this tutorial will focus on the combined data files know that any changes will be overwritten unless added to the template files. The script that combines these template files with the game data can be found here
Template files
A template file for a new skill can consist of the following directives, which tell the export script what to put in the final file. Other fields that end up in
#skill grantedEffectId [displayName]
This directive initializes all the data for the skill and emits the skill header. grantedEffectId matches up with the name defined in the ggpk, in the GrantedEffects table. displayName is optional, but can override the display name from the game data if needed
#flags
Sets the base flags for an active skill, like projectile, attack, or minion, for example. These flags are then used, along with the SkillTypes gotten from the ggpk, to add different KeywordFlags and ModFlags to the skill. The available flags include the following, and add a KeywordFlag or ModFlag of the same name unless otherwise stated:
- melee
- attack
- spell
- projectile
- area
- hit
- brand
- totem
- trap
- mine
- chaining
- warcry
- duration
- curse
- hex
#mods
This directive does nothing but ensure the mods that come with the skill are included after exporting. This will almost always be included
#baseMod
This directive is used when there are mods associated with the skill that don't come in the statMap (see the statMap section below)
#noGem
This directive is used when a new skill shouldn't have a gem associated with it. Some skills have a gem internally, but it's not one that can be socketed in gear, so this is used to disable it (e.g. Bone Armour)
Combined data
The most important tables constructed from the game data are the stats table, and the levels table. Taking a look at just one row in levels, there is a list of numbers, followed by named entries, such as levelRequirement, damageEffectiveness, etc. This list of numbers maps directly to each entry in the stats table. Notice that not all of the stats have a number in the first part of the levels row. These extra stats are usually for booleans/flags that are always true.
- For example, here are the two tables for Fireball:The value forlua
stats = { "spell_minimum_base_fire_damage", "spell_maximum_base_fire_damage", "base_chance_to_ignite_%", "fireball_base_radius_up_to_+_at_longer_ranges", "base_is_projectile", "quality_display_active_skill_ignite_damage_is_gem", }, levels = { [1] = { 0.80000001192093, 1.2000000476837, 25, 0, damageEffectiveness = 2.4, critChance = 6, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 6, }, }, [2] = { 0.80000001192093, 1.2000000476837, 25, 0, damageEffectiveness = 2.4, critChance = 6, levelRequirement = 2, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 6, }, }, [3] = { 0.80000001192093, 1.2000000476837, 25, 1, damageEffectiveness = 2.4, critChance = 6, levelRequirement = 4, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 7, }, },spell_minimum_base_fire_damagewould be 0.80000001192093, the value forbase_chance_to_ignite_%would be 25, and sincebase_is_projectiledoesn't have a number, it's just a flag on the skill to properly factor in projectile mods.
Each of these stats are mapped to a mod in Path of Building either via SkillStatMap.lua, or if the stat is specific to this particular skill (e.g. spectral_helix_rotations_% would only apply to Spectral Helix) in statMap in this same table. If a mapping exists in both places, the one local to this skill will take precedence. The corresponding mod will have nil in place of its normal value, and that value instead comes from this row in the levels table.
Notice how these stat numbers don't really align with damage numbers in any meaningful way for active skills. The stat numbers are interpolated by the numbers in the corresponding position in the statInterpolation table in the same row.
- 1 means take the number as-is. This is the most common interpolation
- 2 means apply a linear interpolation:
statValue = round(prevStat + (nextStat - prevStat) * (actorLevel - prevReq) / (nextReq - prevReq)) - 3 means apply an effectiveness interpolation. Take this formula for current effectiveness and multiply by the first two values in the gem level's row:
(3.885209 + 0.360246 * (actorLevel - 1)) * (grantedEffect.baseEffectiveness or 1) * (1 + (grantedEffect.incrementalEffectiveness or 0)) ^ (actorLevel - 1)- For example, a level 20 Fireball (as of this writing) deals 1095 to 1643 damage. To get those numbers we'd apply the formula like so:
(3.885209 + 0.360246 * (70 - 1)) * (2.9384000301361 or 1) * (1 + (0.041200000792742 or 0)) ^ (70 - 1)ends up being 1369.26, and multiplied by the lower value for the level 20 row (0.80000001192093) you get 1095 minimum damage. Do the same thing for the higher value in that same row (1.2000000476837) and you get 1643 maximum damage.
- For example, a level 20 Fireball (as of this writing) deals 1095 to 1643 damage. To get those numbers we'd apply the formula like so:
The code for this can be found in CalcTools.lua starting here
Skill Parts
Many times a skill will have different components that each do different types of damage, or the skill can be used in more than one way that changes the damage output. To support these different modes or parts of a skill, add a table called parts to the skill that contains multiple entries of the form: { name = , }. Making mods based on the skill part the user chooses simply requires the SkillPart tag to be added to a mod: { type = "SkillPart", skillPart = 2 }
Pre Functions (preFuncs)
Some skills rely on knowing something more about the character before they can calculate damage or some other property. One example is Righteous Fire, as it has to know the player (or totem's) life and ES totals before running the calculation. To do this, a calculator will call a function, giving it activeSkill and output as parameters. This function will live alongside the skill and is completely custom. There are 4 preFuncs that can currently be used:
- initialFunc - This is called before anything else is done in CalcOffence, allowing for special mods to be added to the player
- preSkillTypeFunc - This is called before the flag-specific logic is called in CalcOffence. For example, if you needed to calculate ChainCount differently, you could add the mod here
- preDamageFunc - This is called before the final damage passes are done. This is the most used of all the preFuncs, so there are plenty of examples to search for.
- preDotFunc - This is run before damage over time is calculated. The only current example is Burning Arrow, for its 5 stack multiplier.
Adding skills
- Add
#skill grantedEffectIdto the appropriate template file for the skill - Add
#modsbelow that - Export the skills to combine it with the game data
- If there are stats in the
statstable that aren't recognized already inSkillStatMap.lua, add astatMaptable to the template file to map them properly to a mod. - Add other directives/options if needed
Adding minions
- The minion itself has to be added to
Minion.txt. This file uses different directives to construct the data, but the most important ones are#monster monsterVariety monsterName,#limit modName, and#emit.monsterVarietyuses the Id fromMonsterVarieties, whilemonsterNamewill be referenced in the skill gem.#limitsets a limit on summoned monsters based on a multiplier calculated elsewhere on the character, and#emitworks similarly to the#modsdirective on skills. - The only extra thing that needs to be added to the base skill is a table called
minionListthat contains the names of all the minions that skill can summon (monsterNamefrom the previous step). - Some minions have skills of their own. These skills can be added like any other skill to
minion.txt.
CalcOffence (`docs/calcOffence.md`)
This document is intended to help contributors understand what's going on in the offensive calculation process. More specifically, it aims to ensure that you understand what an output is, and where they are set.
At the most basic level, an output is a collection of values that belong to an actor. The very first lines of the calcs.perform function shows this.
In CalcOffence a number of passes are made. For attacks, it's a pass for main hand and one for off hand if it exists. For non-attacks, it's just the one pass. For attacks this means that the output is set to the output of the weapon, so output.MainHand rather than output. The consequence of this is that any value added to output inside of a damage pass may not be added onto the main or global output.
The places passes are iterated through are:
As a concrete example, let's say the active skill is an attack. You want to add the variable VeryCoolVar to the main output, and you want to do it inside of one of the damage pass. As you can see on the first few lines of each of the for loops iterating over the passes, the first thing that happens is that globalOutput is defined to be output, and a local output is set to pass.output. In other words:
Inside the for loops for the passes, when using an attack, output.VeryCoolVar is actually actor.output.MainHand.VeryCoolVar or actor.output.OffHand.VeryCoolVar. Outside the for loops, output.VeryCoolVar is actor.output.VeryCoolVar.
In order to add a variable to actor.output while inside the passes, you have two options.
- Add it to
globalOutput, which points toactor.output. This is great when it's a stat not connected to a hand, so there's no point calculating it for both hands. - Combine the stats. The function
combineStattakes the specified stat from bothactor.output.MainHand.statandactor.output.OffHand.statand combines them intoactor.output.stat. This is already done for other stats after every loop that iterates over the passes. To reiterate, while inside the passes as an attack, the local variableoutputis already set toactor.output.MainHandor OffHand. All you need to do is addoutput.VeryCoolVarinside the pass, and thencombineStat("VeryCoolVar", type)after the passes are done.
If you're trying to add something to an output and it's not showing up, it's likely you're adding it to the wrong output. Double check where you are in the code and what output is behind the currently local output variable.
ModSyntax (`docs/modSyntax.md`)
This syntax is used all over the codebase, but there are two locations that hold the majority of them: ModParser and Skill Stats.
In ModParser, the standard format of a mod looks like this: mod(ModName, ModType, Value, source, modFlags, keywordFlags, extraTags) See the function declaration here
For Skills, the format is simplified slightly to remove the source parameter, as that is added in automatically based on the gem it came from.
ModName
Used as a key, so you can reference this mod elsewhere in PoB. Can really be anything, but look around the codebase to find ones you need (e.g. "Damage", "Life", "PhysicalDamageGainAsLightning", etc)
ModType
- "BASE": used for flat values that add to other base values (e.g. Flat added damage, flat life, flat evasion)
- "INC": used for increased and reduced mods that stack additively. Use a negative value to represent "reduced".
- "MORE": used for more and less mods that stack multiplicatively. Use a negative value to represent "less".
- "OVERRIDE": used when you want to ignore any calculations done on this mod and just use the value (e.g. "your resistances are 78%" from Loreweave)
- "FLAG": used for conditions. Value will be true/false when this type is used.
- When you need the "FLAG" ModType, consider using the function
flag(name, source, modFlags, keywordFlags, extraTags)instead. This method shortens the code and clarifies the intent. For example,flag("ZealotsOath", { type = "Condition", var = "UsingFlask" })is the same asmod("ZealotsOath", "FLAG", true, { type = "Condition", var = "UsingFlask" })
- When you need the "FLAG" ModType, consider using the function
- "MAX" and "MIN": used for values where only the highest or lowest value should take effect respectively. Examples are
"ImprovedMinionDamageAppliesToPlayer"for "Increases and Reductions to Minion Damage apply ... at X% of their value" or"PoisonStackLimit"for "Cannot Poison Enemies with at least X Poisons on them"
Value
This represents the raw value of the mod. When it's used in the skills to map from the skill data, this will be nil, as it pulls the number from the gem based on the level.
Source
This is where the mod comes from. Often it will be automatically filled in, coming from a tree node, gem, or item. If you do need to specify it for some reason, it's a string, and you can use "Tree:[nodeId]" as a special value to show a tree inset on hover.
Mod Flags
These are bitwise flags that say what the mod can apply to. See a full list here under ModFlag. If you want to use several flags at once, make use of bit.bor and bor (ModParser.lua uses this alias) to combine them. When combined, all of the flags have to match. If you only need one to match, use the "ModFlagOr" tag instead.
Keyword Flags
These function similarly to the mod flags, and use the KeywordFlag group in Global.lua. These are usually based off of the flags on the gem itself. If you want to use several flags at once, make use of bit.bor and bor (ModParser.lua uses this alias) to combine them. When combined, only one of the flags has to match. If you need them all to match, use the "KeywordFlagAnd" tag instead.
Extra Tags
Often a mod will only apply under certain conditions, apply multiple times based on other stats, etc. The syntax for that depends heavily on the first parameter, "type". There can be an infinite number of these tags at the end of a mod, so multiple can apply at one time. Some parameters, like actor or neg can be used on all of the types. Below are different types and the other parameters they need to function.
- Condition: Used for conditions on the player that need to be in place before the mod applies (e.g. CritRecently, Shocked, etc.)
- var: Contains the name of the condition
- neg: (defaults to false) Boolean that negates the condition
- In order to set a condition, use "Condition:[name]" as a FLAG mod
- ActorCondition: Used for conditions on an enemy or a minion.
- var: Contains the name of the condition
- neg: (defaults to false) Boolean that negates the condition
- actor: Can be "enemy" or "parent". "parent" is used when giving a mod to a minion that is based on a condition on the player (its controller). e.g.
mod("MinionModifier", "LIST", { mod = mod("Damage", "INC", num, { type = "ActorCondition", actor = "parent", var = "HavePhysicalGolem" }) }, { type = "SkillType", skillType = SkillType.Golem }),
- Multiplier: Multiplies the mod by this variable
- var: mod to multiply by
- limit: The maximum number the mod can go up to
- limitTotal: boolean that changes the behavior of limit to apply after multiplication. Defaults to false.
- globalLimit: The maximum global number the mod can go up to, even with multiple sources. Useful for mods that say "up to a maximum of ..."
- globalLimitKey: string identifier for the global limit. Mods with identical keys cannot go over the globalLimit.
- MultiplierThreshold: Similar to a condition that only applies when the variable is above a specified threshold
- var: name of the mod
- threshold: number to reach before the mod applies
- PerStat: Similar to Multiplier, but is used for character stats instead of arbitrary multiplier like number of sockets
- stat: The stat to multiply by
- div: Defaults to 1. Divide by this number after calculation, rounding down. Useful for mods that say "per 5 strength", for example
- StatThreshold: Similar to MultiplierThreshold
- stat: The name of the stat
- threshold: number to reach before the mod applies
- PercentStat: Used for mods based on percentages of other stats (e.g. Agnostic)
- stat: The name of the stat
- percent: value of the percent
- SkillType: This type is for mods that affect all skills of a certain type
- skillType: An enum value in Global.lua
- SkillName: Similar to SkillType, but specifies the name of the skill, usually for enchantments
- skillName: The English name of the skill (e.g. "Decoy Totem")
- GlobalEffect: This is used largely for buffs and curses that affect actors even when it's not the main skill
- effectType: Can be "Guard", "Buff", "Debuff", "Aura", "AuraDebuff", "Curse". These apply to you, you, enemies, you + minions, enemies, and enemies, respectively
- effectName: String to specify where the global effect comes from
- effectEnemyCond: Specify a condition so this mod applies to the enemy when that condition is fulfilled
- effectStackVar: Multiplies the mod by this variable (usually another mod)
- modCond: Apply the mod when the actor has this condition
- unscalable: boolean that determines whether this buff can be scaled by buff effect
- DistanceRamp: A rare type that is used on skills and effects that do different things at different distances from the character
- ramp: Numbers to multiply the mod by at different distances. e.g.
ramp = {{35,0},{70,1}}means the mod does nothing at 35 units, but has its full value at 70 units.
- ramp: Numbers to multiply the mod by at different distances. e.g.
- ModFlagOr: Used when you only need one ModFlag to match, e.g.
["with axes or swords"] = { flags = ModFlag.Hit, tag = { type = "ModFlagOr", modFlags = bor(ModFlag.Axe, ModFlag.Sword) } },needsHit, but can use either of the other two flags- modFlags: Use
boras if you were adding ModFlags normally
- modFlags: Use
- KeywordFlagAnd: Used when you need all of the KeywordFlags to match
- keywordFlags: Use
boras if you were adding KeywordFlags normally
- keywordFlags: Use
Rundown (`docs/rundown.md`)
Path of Building Community Fork Codebase Rundown
Layout
Assets
- game_ui_small.png
Overlay on top of range_guide.png. - range_guide.png
Area of effect scale in Calcs view. - ring.png
Ring overlay on hovering over jewel sockets in Tree view. - ShadedInnerRing.png
Ring overlay for radius jewels. - ShadedInnerRingFlipped.png
Ring overlay for Thread of Hope. - ShadedOuterRing.png
Ring overlay for radius jewels. - ShadedOuterRingFlipped.png
Ring overlay for Thread of Hope. - small_ring.png
Highlighting of matching nodes in Tree view search results.
- game_ui_small.png
Classes
- BuildControlList.lua
- ButtonControl.lua
- CalcBreakdownControl.lua
- CalcSectionControl.lua
- CalcsTab.lua
- CheckBoxControl.lua
- ConfigTab.lua
- Control.lua
- ControlHost.lua
- DropDownControl.lua
- EditControl.lua
- FolderListControl.lua
- GemSelectControl.lua
- ImportTab.lua
- Item.lua
- ItemDBControl.lua
- ItemListControl.lua
- ItemSetListControl.lua
- ItemSlotControl.lua
- ItemsTab.lua
- LabelControl.lua
- ListControl.lua
- MinionListControl.lua
- ModDB.lua
- ModList.lua
- ModStore.lua
- NotableDBControl.lua
- NotesTab.lua
- PassiveSpec.lua
- PassiveSpecListControl.lua
- PassiveTree.lua
- PassiveTreeView.lua
- PathControl.lua
- PopupDialog.lua
- PowerReportListControl.lua
- ScrollBarControl.lua
- SearchHost.lua
- SectionControl.lua
- SharedItemListControl.lua
- SharedItemSetListControl.lua
- SkillListControl.lua
- SkillsTab.lua
- SliderControl.lua
- TextListControl.lua
- Tooltip.lua
- TooltipHost.lua
- TreeTab.lua
- UndoHandler.lua
Data
- Global.lua
Contains mappings of colour codes, mod flags and keywords. Also contains an enumeration of skill types used in theActiveSkills.datandGrantedEffects.datgame files to hardcode specific interactions. This has to be reverse engineered from the GGPK and not all flags are fully understood yet. - New.lua
Newly announced uniques live here until their mod ranges are known.
- Global.lua
Export
The export system warrants its own in-depth document.Modules
- Build.lua
Contains controls for everything on the build screen:
top: "back", "save", "save as", skill points, level, class, ascendancy
left: the buttons for the different tabs, bandits, pantheon, main skill, stat overview.
Loads build, initialises all tab components, loads corresponding sections from the build file, builds calculation tab output.
Contains functions to load/save build and input handling, popups for build version migration, saving, spectre library.
Contains functions to add totem/minion stats to the sidebar, refreshing and building the statlist.
Contains functions for attribute requirements in tooltips and comparison of tooltips.
Contains additional file loading/saving logic. - BuildList.lua
Contains the build selection screen that only has basic UI elements not exclusive to this screen. Filesystem manipulation, searching for XML build files in the build path and sorting the resulting list can be found here. - CalcActiveSkill.lua
- CalcBreakdown.lua
- CalcDefence.lua
- CalcOffence.lua
- CalcPerform.lua
- Calcs.lua
Loads other calcs modules.
Contains printer for console debugging output, calculators for changes to nodes, items, gems, etc and builds stats for sidebar and calcs tab (one function). - CalcSections.lua
- CalcSetup.lua
Most of the code here revolves around the mod databases of player and enemy actors. Adds all mods that the two share with each other, as well as all modifiers that are specific to one actor type. Stuff like the base stats of characters, bandits and pantheons get applied here. Builds the list of nodes on the skill tree as well as the mod list for each node, including all mods added, removed or changed by radius jewels, and adds it to the calculation environment. Tracks attribute requirements, finds skills granted by items, checks jewel sockets, radius jewel and abyss jewels, adds flasks. Has special handling for Necromantic Aegis and Dancing Dervish. Counts number of corrupted/Shaper/Elder/etc. items. Processes extra skills granted by items and removes socket groups that no longer have matching items. Gets weapon data, adds granted passives and merges mods of allocated passives. Sets main skill group, builds list of active skills including support gems. Sets the main skill to the default attack if none is selected. - CalcTools.lua
Calculates mod values and tally up increased/more modifiers, validates gems and skill types, checks if support gems can apply to active gems, determines gem type and attribute requirements, builds stat table for skill. - Common.lua
Contains various utilities such as a class library, character encoding converters, MurmurHash non-cryptographic hash function used in the GGPK file, type casts used for working with the GGPK file, JSON-to-Lua converter, utilities for manipulating and printing tables, functions for comparison, rounding, formatting and file manipulation - ConfigOptions.lua
Contains specifications of the various configuration options for buffs, conditions, map mods and more. - Data.lua
Contains skill types, item types. Duplicates some mod creation/processing logic.
Holds common mappings such as jewel radius, monster exp multiplier, weapon and base info.
Loads uniques and all bases, skills, stat descriptions, item mods, enchantments, essences, pantheons, skills, gems, minions and builds list of item bases, loads rare items template. There are extra checks to load either the 3.0 or the 2.6 versions, if applicable. - ItemTools.lua
Calculate the range of mods on items, replace non-ascii characters in item text and colour mod lines. - Main.lua
Loads game version, common, data, mod/item/calc/pantheon..tools.
There are two modes of the program: the build list and the build itself.
Sets build paths, loads mod caches, trees, rare and unique items.
Rebuilds mod caches if in dev mode.
Draws non-mode-dependent UI controls. - ModParser.lua
Parses all mods on items, skills, pantheon to generate theModCache.
Warrants its own in-depth document. - ModTools.lua
Functions to create mods, and format values, flags, tags.
Also loads theModCachegenerated by theModParsers. - PantheonTools.lua
Parser for pantheon mods used duringCalcSetup. - StatDescriber.lua
- Build.lua
TreeData
- .gitattributes
See https://www.git-scm.com/docs/gitattributes. - .gitignore
See https://www.git-scm.com/docs/gitignore. - CHANGELOG.md
Patch notes written in Markdown. - changelog.txt
Patch notes written in plain text. - CONTRIBUTING.md
Contribution guides. - GameVersions.lua
Contains global variables to identify and convert outdated builds. Also contains global table of passive skill tree versions used to upgrade to newer skill tree versions. - HeadlessWrapper.lua
Provides stubs for PoB's graphics host and its environment. Can be used to run PoB from the command line. You would still need to implement at leastDeflate()andInflate()to import/export builds. Useful for automated testing. - Launch.lua
Updates on first start, discerns whether PoB is running in dev mode, initialises renderer, loadsMainmodule, has callbacks for exiting the program, advancing frames, registering key presses, launching non-blocking subscripts, updating, notification and error prompts. - LaunchInstall.lua
Downloads and installs the auto-updater on finishing program installation. - LICENSE.md
MIT licence - manifest.xml
Contains file name : SHA-1 hash pairings used to determine which files to update. - README.md
Project overview - runtime-win32.zip
Contains PoB executable, update executable, compiled librarieslibcurl(HTTPS requests),lcurl(libcurl bindings for Lua),lua51(LuaJIT 5.1),lzip(DEFLATE),SimpleGraphic(custom 2D graphics host), Lua libraries for Base64, JSON, SHA-1, XML, and fonts. - tree-2_6.zip
- tree-3_6.zip
- tree-3_7.zip
- tree-3_8.zip
- tree-3_9.zip
- tree-3_10.zip
- tree-3_11.zip
- tree-3_12.zip
- update_manifest.py
Generates SHA-1 hashes for files inmanifest.xml.
New files have to be manually added tomanifest.xmlto be processed. - UpdateApply.lua
Consumes and applies table of update instructions. Updating the runtime itself is done from a separate host environment. - UpdateCheck.lua
Compares local and remote manifests to determine which files need to be updated, downloads these files andchangelog.txt, rebuildsmanifest.xmland builds table of update instructions.
--- METRICS ---
- Files Extracted: 6
- Estimated Token Budget: ~9917 tokens
- Canonical Reference: https://codewiki.google/github.com/PathOfBuildingCommunity/PathOfBuilding