use poe2_agent::pob::PobHeadless;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let pob_rel = std::path::Path::new("vendor/PathOfBuilding-PoE2");
let pob_path = pob_rel
.canonicalize()
.expect("vendor/PathOfBuilding-PoE2 not found. Run from poe2-agent/ root.");
let pob_path_str = pob_path.to_str().unwrap();
println!("Initializing PobHeadless...");
let mut pob = PobHeadless::new()?;
pob.init(pob_path_str)?;
println!("PoB initialized.");
println!("\n=== Test 1: Ranger_with_gear.xml ===");
let ranger_xml = std::fs::read_to_string(pob_path.join("src/Builds/Ranger_with_gear.xml"))?;
pob.load_build_xml(&ranger_xml)?;
let ranger_stats = pob.calculate()?;
println!("Ranger stats: {:?}", ranger_stats);
println!(
" DPS: {:.1}, Life: {:.0}, Fire: {}, Cold: {}, Lightning: {}",
ranger_stats.total_dps,
ranger_stats.life,
ranger_stats.fire_res,
ranger_stats.cold_res,
ranger_stats.lightning_res
);
println!("\n=== Test 2: Witch dummy build ===");
pob.load_build_xml(WITCH_BUILD_XML)?;
let witch_stats = pob.calculate()?;
println!("Witch stats: {:?}", witch_stats);
println!(
" DPS: {:.1}, Life: {:.0}, Fire: {}, Cold: {}, Lightning: {}",
witch_stats.total_dps,
witch_stats.life,
witch_stats.fire_res,
witch_stats.cold_res,
witch_stats.lightning_res
);
println!("\n=== Test 3: Extended queries ===");
let build_stats = pob.query_build_stats()?;
println!(
"Build stats JSON:\n{}",
serde_json::to_string_pretty(&build_stats)?
);
let skill_list = pob.query_skill_list()?;
println!(
"\nSkill list JSON:\n{}",
serde_json::to_string_pretty(&skill_list)?
);
let output_path = pob_path.join("src/Builds/Witch_dummy.xml");
std::fs::write(&output_path, WITCH_BUILD_XML)?;
println!("\nWitch build written to {:?}", output_path);
Ok(())
}
const WITCH_BUILD_XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<PathOfBuilding2>
<Build level="70" ascendClassName="None" characterLevelAutoMode="false" className="Witch" mainSocketGroup="1" viewMode="TREE" targetVersion="0_1">
<Buffs curseList="" combatList="" buffList=""/>
<TimelessData socketFilterDistance="0" searchListFallback="" searchList="" devotionVariant2="1" devotionVariant1="1"/>
</Build>
<Config activeConfigSet="1">
<ConfigSet title="Default" id="1">
<Placeholder name="enemyLevel" number="82"/>
<Placeholder name="enemyFireResist" number="50"/>
<Placeholder name="enemyColdResist" number="50"/>
<Placeholder name="enemyLightningResist" number="50"/>
<Placeholder name="enemyChaosResist" number="0"/>
<Placeholder name="enemyArmour" number="8063"/>
<Placeholder name="enemyEvasion" number="1175"/>
<Placeholder name="enemyDistance" number="20"/>
<Placeholder name="enemyCritChance" number="5"/>
<Placeholder name="enemyCritDamage" number="30"/>
<Placeholder name="enemyDamageRollRange" number="70"/>
<Placeholder name="enemySpeed" number="700"/>
<Placeholder name="enemyPhysicalDamage" number="965"/>
<Placeholder name="enemyFireDamage" number="965"/>
<Placeholder name="enemyColdDamage" number="965"/>
<Placeholder name="enemyLightningDamage" number="965"/>
<Placeholder name="enemyChaosDamage" number="386"/>
<Placeholder name="enemyFirePen" number="3"/>
<Placeholder name="enemyColdPen" number="3"/>
<Placeholder name="enemyLightningPen" number="3"/>
</ConfigSet>
</Config>
<Calcs>
<Input name="misc_buffMode" string="EFFECTIVE"/>
<Input name="skill_number" number="1"/>
</Calcs>
<Notes>
Dummy Witch build for testing the headless PoB integration.
Ice Nova + Concentrated Effect with basic caster gear.
</Notes>
<Tree activeSpec="1">
<Spec nodes="54447" masteryEffects="" classInternalId="5" classId="0" secondaryAscendClassId="nil" ascendancyInternalId="" ascendClassId="0" treeVersion="0_4">
<URL></URL>
<Sockets/>
<Overrides/>
</Spec>
</Tree>
<Import exportParty="false"/>
<Skills sortGemsByDPS="true" sortGemsByDPSField="CombinedDPS" defaultGemLevel="normalMaximum" showSupportGemTypes="ALL" activeSkillSet="1" defaultGemQuality="0">
<SkillSet id="1">
<Skill includeInFullDPS="true" enabled="true" mainActiveSkill="1" mainActiveSkillCalcs="1" label="">
<Gem quality="0" gemId="Metadata/Items/Gems/SkillGemIceNova" nameSpec="Ice Nova" skillId="IceNovaPlayer" variantId="IceNova" statSetIndexCalcs="nil" enabled="true" enableGlobal2="true" statSetIndex="nil" count="1" level="20" enableGlobal1="true"/>
<Gem quality="0" gemId="Metadata/Items/Gems/SkillGemConcentratedEffectSupport" nameSpec="Concentrated Effect" skillId="SupportConcentratedEffect" variantId="ConcentratedEffect" statSetIndexCalcs="nil" enabled="true" enableGlobal2="true" statSetIndex="nil" count="1" level="20" enableGlobal1="true"/>
</Skill>
</SkillSet>
</Skills>
<Party destination="All" ShowAdvanceTools="false" append="false"/>
<TreeView searchStr="" zoomY="0" zoomLevel="5" zoomX="0" showStatDifferences="true"/>
<Items useSecondWeaponSet="false" activeItemSet="1" showStatDifferences="true">
<Item id="1">
Rarity: RARE
Spell Wand
Bone Wand
Crafted: true
Prefix: {range:0.5}SpellDamage5
Prefix: {range:0.5}AddedFireDamageToSpells3
Prefix: {range:0.5}AddedColdDamageToSpells3
Suffix: {range:0.5}CastSpeed3
Suffix: None
Suffix: None
Quality: 20
LevelReq: 60
Implicits: 0
60% increased Spell Damage
Adds 15 to 25 Fire Damage to Spells
Adds 13 to 21 Cold Damage to Spells
12% increased Cast Speed
</Item>
<Item id="2">
Rarity: RARE
Resistance Ring
Prismatic Ring
Crafted: true
Prefix: None
Prefix: None
Prefix: None
Suffix: {range:0.5}FireResist5
Suffix: {range:0.5}ColdResist5
Suffix: {range:0.5}LightningResist5
LevelReq: 35
Implicits: 1
{tags:elemental,fire,cold,lightning,resistance}{range:0.5}+(7-10)% to all Elemental Resistances
+28% to Fire Resistance
+28% to Cold Resistance
+28% to Lightning Resistance
<ModRange range="0.5" id="1"/>
<ModRange range="0.5" id="2"/>
<ModRange range="0.5" id="3"/>
<ModRange range="0.5" id="4"/>
</Item>
<Item id="3">
Rarity: RARE
Resistance Ring 2
Prismatic Ring
Crafted: true
Prefix: None
Prefix: None
Prefix: None
Suffix: {range:0.5}FireResist5
Suffix: {range:0.5}ColdResist5
Suffix: {range:0.5}LightningResist5
LevelReq: 35
Implicits: 1
{tags:elemental,fire,cold,lightning,resistance}{range:0.5}+(7-10)% to all Elemental Resistances
+28% to Fire Resistance
+28% to Cold Resistance
+28% to Lightning Resistance
<ModRange range="0.5" id="1"/>
<ModRange range="0.5" id="2"/>
<ModRange range="0.5" id="3"/>
<ModRange range="0.5" id="4"/>
</Item>
<Item id="4">
Rarity: RARE
Life Belt
Heavy Belt
Charm Slots: 2
Crafted: true
Prefix: {range:0.5}IncreasedLife7
Prefix: None
Prefix: None
Suffix: {range:0.5}Strength7
Suffix: None
Suffix: None
LevelReq: 50
Implicits: 2
{range:0.5}(20-30)% increased Stun Threshold
{range:0.5}Has (1-3) Charm Slots
+92 to maximum Life
+29 to Strength
<ModRange range="0.5" id="1"/>
<ModRange range="0.5" id="2"/>
<ModRange range="0.5" id="3"/>
<ModRange range="0.5" id="4"/>
</Item>
<ItemSet useSecondWeaponSet="false" id="1">
<Slot name="Weapon 1" itemPbURL="" itemId="1"/>
<Slot name="Weapon 2" itemPbURL="" itemId="0"/>
<Slot name="Helmet" itemPbURL="" itemId="0"/>
<Slot name="Body Armour" itemPbURL="" itemId="0"/>
<Slot name="Gloves" itemPbURL="" itemId="0"/>
<Slot name="Boots" itemPbURL="" itemId="0"/>
<Slot name="Amulet" itemPbURL="" itemId="0"/>
<Slot name="Ring 1" itemPbURL="" itemId="2"/>
<Slot name="Ring 2" itemPbURL="" itemId="3"/>
<Slot name="Ring 3" itemPbURL="" itemId="0"/>
<Slot name="Belt" itemPbURL="" itemId="4"/>
<Slot name="Flask 1" itemPbURL="" itemId="0"/>
<Slot name="Flask 2" itemPbURL="" itemId="0"/>
<Slot name="Weapon 1 Swap" itemPbURL="" itemId="0"/>
<Slot name="Weapon 2 Swap" itemPbURL="" itemId="0"/>
<Slot name="Arm 1" itemPbURL="" itemId="0"/>
<Slot name="Arm 2" itemPbURL="" itemId="0"/>
<Slot name="Leg 1" itemPbURL="" itemId="0"/>
<Slot name="Leg 2" itemPbURL="" itemId="0"/>
<Slot name="Charm 1" itemPbURL="" itemId="0"/>
<Slot name="Charm 2" itemPbURL="" itemId="0"/>
<Slot name="Charm 3" itemPbURL="" itemId="0"/>
</ItemSet>
<TradeSearchWeights/>
</Items>
</PathOfBuilding2>"#;