🚨 Shai-Hulud Strikes Again:834 Packages Compromised.Technical Analysis →
Socket
Book a DemoInstallSign in
Socket

pyoe2-craftpath

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pyoe2-craftpath

A tool for Path of Exile 2 to find the best craftpaths based on the categories: *most likely, most efficient and cheapest*, between a starting item and a target item.

pipPyPI
Version
0.3.1
Maintainers
1

GitHub Actions Workflow Status GitHub Repo PyPI - Version Crates.io Version GitHub License

PyoE 2 - CraftPath

A tool for Path of Exile 2 to find the best craftpaths based on the categories: most likely, most efficient and cheapest, between a starting item and a target item.

Available as Python package pyoe2-craftpath or as "bro just gimme something that goes brrr"-executable command-line utility for Windows under Releases. Bindings for Python are generated with PyO3, to let you build your own data analysis pipeline upon the calculated items and craftpaths. Made possible by the power of 🦀 Rust.

Built and tested for Path of Exile 2 on version 0.3.1. Supported Python versions and platforms are determined by the automated pipeline, here (should support all widely used platforms and versions >=3.10).

The primary goal is to provide a framework for calculating craft paths and to enable its integration into native applications (over FFI), including overlays or mobile apps ... or just run easily as a Windows executable or Python library.

About

To keep it short, I was introduced to Path of Exile 2 and enjoyed it quite a bit. After reaching higher levels and starting to get the hang of things, I became interested in crafting. As big noob, I was completly overwhelmed with the information available.

Me need simple. Me want good item. How get good item?

CraftPath. The purpose of this tool is give it information about your current item and the affixes you want it to have, then let it efficiently calculate possible craftpaths; Without the need to manually look up mod weights, mod groups, or spend hours crunching probabilities on a Casio calculator, as all true PoE gamers do1. It simulates all sensible currency sequences that can be applied on a starting item, and collects the best routes that lead to the given target item, based on the specified statistic (more in Development Strategy and Caveats).

đźš§ Notice for Versions Below 1.0.0

Keep in mind that this project is in its early stages, and can contain bugs and lack features. Therefore, the section Features should give an overview over all planned/completed/unplanned currencies and known bugs. If your topic is not documented there, it is yet unknown and not reviewed. Feel free to create an Issue with more information!

My plan is of course to reach version 1.0.0 ... which depends on the traction this project gains, which in turn affects how much free time I'm motivated to dedicate to it, which in turn leads to a more robust and well-rounded project. Until then, this notice lingers... possibly forever. 🧙‍♂️

Features

CurrencyOptionsStatusNote
Orb of TransmutationNormal, Greater (55), Perfect (70)Completed
Orb of AugmentationNormal, Greater (55), Perfect (70)Completed
Regal OrbNormal, Greater (35), Perfect (50), Homogenising CoronationCompleted
Orb of AlchemyNot PlannedToo random to craft deterministically.
Chaos OrbNormal, Greater (35), Perfect (50), Dex/Sin Erasure, *WhittlingCompletedWhittling removes the affix based on minimal item level, not tier.
Exalted OrbNormal, Greater (35), Perfect (50), Dex/Sin Exaltation, Homogenising ExaltationCompleted
Orb of AnnulmentDex/Sin AnnulmentCompleted
Divine OrbNot PlannedDifferent use-case.
Artificers OrbCompletedClick item. Socket. Much wow. Such awesome.
Fracturing OrbPartially Completed, PlannedAlgorithm respects fractured affixes if present on the start item; does not create fractured affixes automatically yet.
Vaal OrbOmen of CorruptionPartially Completed, Partially PlannedEffect 1/3. Creates new socket and corrupts item. Effect 2/3. Does not create implicits yet, but is MAYBE planned (low prio). Effect 3/3. Reroll up to three modifiers is NOT planned.
Lesser to Greater EssenceCompleted
Perfect EssenceDex/Sin CrystallisationCompletedAlgorithm tries to create a temporary affix to swap with, if otherwise unreachable.
DesecrationAbyssal Echoes, Blackhooded, Liege, Sovereign, Sin/Dex NecromancyPartially Completed, Not Planned"Blackhooded, Liege, Sovereign" are forced. Loose propagation of affixes is not planned. ATTENTION Desecration weights are unknown and are treated equally by the algorithm; all desecration weights = 1.
OthersOn requestIf not explicitly listed in this table, other crafting methods have not been reviewed yet or are not planned. Open an issue if I forgot something that you would find nice to have.

All affix weights are fetched from craftofexile.com; refer to the given link for infos about how the weights are collected.

How To Run

This tool is primarily intended to be used as a framework for native applications, such as overlays or mobile apps (via FFI). If you need help creating an FFI from this tool to your programming language, feel free to create an Issue with your target.

Another way to easily run the tool is as a Python library, which also demonstrates one way to use FFI. Check out the extended Python example as a Jupyter Notebook or browse the python_examples directory for commented usage examples in Python.

The following section shows a guide for the quick-n-dirty approach to run the Windows executable via the console, since I wanted to offer a simple(r) solution for those who just want to have a basic overview and are not planning to create further analytical pipelines.

First things first. Download the program from Releases.

To make the CLI more approachable, I've uploaded a video demonstrating the workflow, from configuring the executable to supplying items for calculation. You can watch it on YouTube by clicking the thumbnail, or here: Watch the video

pyoe2-craftpath.exe [options]

Available optional, options:

--start_item_path <Path to JSON File>

Default: pyoe2-craftpath/startitem.json
Provides the file location of the saved item to treat as the starting item of the craft.
Use CraftOfExile → Emulator → Export and paste the output into pyoe2-craftpath/startitem.json.

--target_item_path <Path to JSON File>

Default: pyoe2-craftpath/targetitem.json
Provides the file location of the saved item to treat as the end item of the craft.
Use CraftOfExile → Emulator → Export and paste the output into pyoe2-craftpath/targetitem.json.

--cache_path <Path to Temp Folder>

Default: pyoe2-craftpath
Used for caching CraftOfExile's and
PoE.Ninja's datasets.
The folder must already exist.
Mostly to express consent for the program to cache things and edit that folder’s contents.

--poe2_league <League>

Default: Rise of the Abyssal
Fetches PoE.Ninja's economy data for the specified league.

--amount_routes <Number>

Default: 5
Number of craft paths collected and printed per stats category.
(Current categories: highest chance, most efficient, cheapest → 3 × amount_routes shown.)

--no_updates

Default: checks GitHub for updates
If set, CraftPath will not query GitHub or check for newer versions.

--no_groups

Default: collects all possible paths
If set, CraftPath will not collect all possible path groups.
This greatly reduces RAM usage but results in less complete output.

--max-ram <<Number>[GB|KB|MB]>

Default: 1GB
Sets the maximum amount of RAM the program may use during path collection.

Development Strategy and Caveats

The following section explains the inner workings of my algorithm, if you are interested in contributing or just want to have an idea of how this tool works. If you're only here for the crafting you can skip this.

The architecture to return the best paths based on custom statistics consists of two important parts. Firstly, the MatrixPropagator and secondly the StatisticAnalyzer(s).

  • A matrix propagator's job is to collect all sensible items with all sensible possible next items, specified currencies and their chances. The definition of all sensible is to be defined by the actual algorithm implementing the trait MatrixBuilder. This structure is efficiently constructed as a tree. For an actual implementation refer to HappyPathMatrixBuilderImpl.
  • A statistical analyzer now uses the constructed matrix to traverse all possible paths and calculates weights for each unique route. The weights are dependent on the algorithm and can be e. g. the chance, the cost, etc. Each analyzer can specify if lower is better. Currently two predefined general traits exist, firstly the StatisticAnalyzerPaths, which returns the best unique routes, and secondly StatisticAnalyzerCurrencyGroups, which returns the best currency sequences. Actual implementations are contained here.

Matrix Builder Implementation

To constraint propagation and massivly reduce complexity, my algorithm tries to stay on the Happy Path as much as possible. That means, that affixes that can be rolled, but are not included in the desired affix state, will not be considered for additive currencies like Exalted Orb. Subtractive currencies like Orb of Annulment will only result in affix states, that lose unwanted affixes. (= Definition of all sensible) Simply put, if my algorithm was a player, it would immediatly stop crafting an item, that does not gain an affix from the desired affixes (or lose an unwanted affix).

While this approach enables more efficient path construction, it may miss routes that can only be reached by temporarily applying an undesired affix. Such an edge case can be found by trying to apply Perfect Essence.

Let's assume we have an item with three desirable prefixes that we want to keep, and we plan to apply a Perfect Essence to add a suffix. Naivly applying it results in an item with two prefixes and the new suffix from the Perfect Essence. This action is not done by HappyPathMatrixBuilderImpl, since it would remove a wanted affix. Thus, propagation stops and completes without finding a craft path that leads to the target item at all.

To fix this specific edge case, PerfectEssencePropagator introduces an additional temporary step, forcing propagation outside of the Happy Path: expanding on the mentioned example, it first applies a suffix from the unwanted affix pool. This ensures that the three desired prefixes remain untouched, while the temporary suffix can be replaced with the Perfect Essence and the Dextral Crystallisation omen.

I'm sure many more such edge cases exist, and those need to be specifically implemented. If you can think of any, please tell me :3

Analysis Implementation

I haven't implemented anything crazy for this one, so I'll keep it short. The most interesting detail is probably the need to filter out theoretical cyclic propagations. I'm not aware of this happening in my algorithm, but it is an edge-case that must be handled to avoid infinite loops. A theoretical possibility would be f. e. Exalted Orb, Orb of Annulment, Exalted Orb, Orb of Annulment ... resulting in the same affix state. Therefore calculate_crafting_paths only continues paths, that do not contain the same affix state twice2. What would be nice as well, is an improved filtration of senseless routes ... but the definition for senseless routes is actually the hard task here. Cauz the above example only filters out the same affixes. It would still calculate the same currency sequence for different affixes, which is senseless, but I do not know how to filter it out efficiently yet. Hence, the current version only filters out cycles, and lets the StatisticalAnalyzers handle the sorting. Since the senseless routes will have a much worse weight than the best ones, they will be filtered out naturally; on the expense of checking senseless routes, which really is a problem on deep paths (6 affixes+), resulting in millions of senseless checks.

Contribution / Dev Usage

I've published the project on crates.io (and PyPI). You can either use the API to build your own extension as own Rust crate depending on pyoe2-craftpath. If you're planning to offer FFI for your language, free to open an Issue to ask about technical stuff.

If you want, you can also create a pull request to have it directly included here. The only requirement is the usage of the Conventional Commits format for your commit messages and preferably a new test for your code.

I recommend looking at the central types StatisticAnalyzerCurrencyGroupPreset, StatisticAnalyzerPathPreset and MatrixBuilderPreset which are most likely the things that an extension wants to offer. The mentioned enums provide specific, usuable implementations for both Rust and Python and integrate seamlessly into the rest of CraftPath's "ecosystem". E. g. a DynMatrixBuilder could be passed over arguments in Section 5 of the Jupyter Notebook example. This is possible for statistic analyzers as well (refer to Section 6).

Acknowledgments

  • Of course, Grinding Gear Games for providing Path of Exile 2, that got me hooked to the extent of actually coding this.

  • CraftOfExile that permitted me to use their item data. CraftPath would not be possible without it. CoE offers an extensive, crunched mapping for weights, items, affixes, etc. Moreover I integrated CoE's Emulator Export outputs to parse the starting/target item, offering an external, easy capture of item information over a GUI. Since I as noob needed something hands-on, easy to use, CraftOfExile was essential for this project.

  • poe.ninja for providing a public API to fetch up-to-date currency exchange prices. Used by CraftPath to calculate the cost of a crafting path, and subsequently corresponding cost-based analysis. Cudos for hosting and keeping a free, public API alive for such a long time!

Disclaimer

CraftPath is not affiliated with or endorsed by Grinding Gear Games

License

MIT License

Footnotes

  • Source: trust me, bro ↩

  • Actually item state (ItemSnapshot), but in the given example w/e. The item state contains more information like rarity, base item id, level, etc. ↩

Keywords

path-of-exile-2

FAQs

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts