├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── docs └── code_structure.md ├── poetry.lock ├── pyproject.toml └── src └── scripts ├── convert_skill_data.py └── fetch_character.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.swp 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | pip-wheel-metadata/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to PathOfBuilding-Python 2 | 3 | ## Setting up a development installation 4 | 5 | * This project targets Python 3.10. You can install it from 6 | [here](https://www.python.org/downloads/release/python-3100/). 7 | * For dependency management, we use [poetry](https://python-poetry.org/). 8 | Install it like so (Powershell): 9 | ```shell 10 | (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -UseBasicParsing).Content | python - 11 | ``` 12 | * Run this command to clone the repository: 13 | ```shell 14 | git clone -b dev https://github.com/PathOfBuildingCommunity/PathOfBuilding.git 15 | ``` 16 | * Afterwards, run this command to install all dependencies: 17 | ```shell 18 | poetry install 19 | ``` 20 | 21 | ## Before submitting your PR 22 | 23 | ### Style guide 24 | 25 | * Code: [PEP 8](https://www.python.org/dev/peps/pep-0008/) 26 | * Docstrings: [PEP 257](https://www.python.org/dev/peps/pep-0257/) 27 | * Type hints: [PEP 484](https://www.python.org/dev/peps/pep-0484/) 28 | * Formatting: [black](https://github.com/psf/black) and 29 | [isort](https://github.com/PyCQA/isort) 30 | * Commit message: Follow the 31 | [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) guidelines 32 | * Branch: Pull requests must be created against the `dev` branch. It is strongly 33 | recommended creating a new branch off of `dev` to contain your proposed changes. 34 | 35 | Here's a primer on the specifics: 36 | * Class/type names: `CamelCase` 37 | * Variable/function/module/file names: `snake_case`. 38 | * Variables with values that do not change during program execution: `UPPER_SNAKE_CASE`. 39 | These could be literals or enum variants. 40 | * Mark module- or class-level implementation details by prepending a single underscore, 41 | like `_variable`, `_method`. 42 | * Do not shadow built-ins (even `id`, `help` and the like). 43 | Instead, append a single underscore, like `id_`, `help_. 44 | * Likewise for reserved keywords (`class_`, `import_`, etc. 45 | Please no `klass`, `clazz or similar!) 46 | 47 | In case of contradictions between individual guidelines, `black` is right. 48 | 49 | In the specific case of third-party libraries with divergent style conventions, 50 | follow theirs. This is in line with PEP 8. 51 | 52 | 53 | ## Getting in touch with the developers 54 | 55 | There is a [Discord](https://discordapp.com/) server, intended for active development on 56 | this project. If you are interested in joining, send a private message to 57 | Cinnabarit#1341. 58 | 59 | ## Keeping your fork up to date 60 | 61 | * Add a new remote repository and name it upstream. 62 | ```shell 63 | git remote add upstream https://github.com/PathOfBuildingCommunity/PathOfBuilding.git 64 | ``` 65 | * Verify that adding the remote worked. 66 | ```shell 67 | git remote -v 68 | ``` 69 | * Fetch all branches and their commits from upstream. 70 | ```shell 71 | git fetch upstream 72 | ``` 73 | * Check out your local dev branch if you haven't already. 74 | ```shell 75 | git checkout dev 76 | ``` 77 | * Merge all changes from upstream/dev into your local dev branch. 78 | ```shell 79 | git rebase upstream/dev 80 | ``` 81 | * Push your updated branch to GitHub. 82 | ```shell 83 | git push -f origin dev 84 | ``` 85 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 David Gowor 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python port of Path of Building 2 | The goal of this repository is to eventually be able to port all of 3 | [Path of Building](https://github.com/PathOfBuildingCommunity/PathOfBuilding) 4 | from Lua to Python. Currently, it is mostly intended for exploring ideas on how to 5 | accomplish this. 6 | 7 | ## Install 8 | This project targets Python 3.10. You need to have Python 3.10 installed 9 | to run this project. Start off by cloning the repository like so: 10 | ```commandline 11 | git clone -b dev https://github.com/PathOfBuildingCommunity/PathOfBuilding-Python.git 12 | ``` 13 | 14 | ## Usage 15 | This project is WIP and not generally useful yet, except for developers. 16 | 17 | ## Contributing 18 | Pull requests are welcome! This project is in its very early stages, so there 19 | are plenty of opportunities to contribute. 20 | 21 | ## Maintainers 22 | [@ppoelzl](https://github.com/ppoelzl) 23 | 24 | ## Licence 25 | [MIT](https://github.com/PathOfBuildingCommunity/PathOfBuilding-Python/blob/master/LICENSE.md) 26 | -------------------------------------------------------------------------------- /docs/code_structure.md: -------------------------------------------------------------------------------- 1 | # Python Object Enumeration Thoughts 2 | 3 | [dict] All GGPK Extracted Gems { act_str, act_dex, act_int, sup_str, sup_dex, sup_str } 4 | -- addressable by name 5 | 6 | [dict] All Uniques (sub-partitioned by item type) 7 | -- addressable by name 8 | -- can return applicable list based on item type 9 | 10 | [class] Environment 11 | [dict] Environment Configuration 12 | 13 | [class] Build 14 | [ref] Tree 15 | [ref] Player 16 | 17 | [class] Tree 18 | [str] version 19 | [dict] All Nodes (addressable by Node ID) 20 | [dict] Selected Nodes (addressable by Node ID) 21 | 22 | [class] Player 23 | [enum] Class Selection 24 | [enum] Ascendancy Selection 25 | [dict] Stats (e.g. Str/Dex/Int, Hit/Crit, Life/Mana, Block/Spell Block/Evade/Dodge, etc.) 26 | [dict] Item Slots 27 | [per slot ref] Item 28 | [optional list] Minions 29 | 30 | [class] Item 31 | [dict] Attribute requirements 32 | [list] Modifiers 33 | [optional ref] Skill class (for skills granted by items) 34 | 35 | [class] Skill 36 | [dict] Requirements (per level Str, Dex, Int) 37 | [list] Granted Effect reference 38 | [list] Supports 39 | 40 | [class] GrantedEffect 41 | [str] Name 42 | [dict] PerLevelEffects 43 | 44 | [class] Minion 45 | [ref] Player 46 | [dict] Stats 47 | [ref list] Items 48 | [ref list] Skills 49 | [int] Quantity 50 | 51 | [class] EnemyModel (e.g. Shaper, Maven) 52 | [dict] Stats (e.g. Str/Dex/Int, Hit/Crit, Life/Mana, Block/Spell Block/Evade/Dodge, etc.) 53 | 54 | [class] Simulator 55 | [ref] Environment(s) 56 | [ref list] Build(s) 57 | [ref] Enemy Model(s) 58 | 59 | [class] Analytics Module 60 | [func] Node Comparison 61 | [func] Item Comparison 62 | [func] Gem Comparison 63 | 64 | [list] Saved Builds 65 | 66 | [dict] UI API imports/exports 67 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "black" 3 | version = "21.9b0" 4 | description = "The uncompromising code formatter." 5 | category = "dev" 6 | optional = false 7 | python-versions = ">=3.6.2" 8 | 9 | [package.dependencies] 10 | click = ">=7.1.2" 11 | mypy-extensions = ">=0.4.3" 12 | pathspec = ">=0.9.0,<1" 13 | platformdirs = ">=2" 14 | regex = ">=2020.1.8" 15 | tomli = ">=0.2.6,<2.0.0" 16 | typing-extensions = [ 17 | {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, 18 | {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, 19 | ] 20 | 21 | [package.extras] 22 | colorama = ["colorama (>=0.4.3)"] 23 | d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] 24 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 25 | python2 = ["typed-ast (>=1.4.2)"] 26 | uvloop = ["uvloop (>=0.15.2)"] 27 | 28 | [[package]] 29 | name = "certifi" 30 | version = "2021.10.8" 31 | description = "Python package for providing Mozilla's CA Bundle." 32 | category = "main" 33 | optional = false 34 | python-versions = "*" 35 | 36 | [[package]] 37 | name = "charset-normalizer" 38 | version = "2.0.7" 39 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 40 | category = "main" 41 | optional = false 42 | python-versions = ">=3.5.0" 43 | 44 | [package.extras] 45 | unicode_backport = ["unicodedata2"] 46 | 47 | [[package]] 48 | name = "click" 49 | version = "8.0.3" 50 | description = "Composable command line interface toolkit" 51 | category = "dev" 52 | optional = false 53 | python-versions = ">=3.6" 54 | 55 | [package.dependencies] 56 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 57 | 58 | [[package]] 59 | name = "colorama" 60 | version = "0.4.4" 61 | description = "Cross-platform colored terminal text." 62 | category = "dev" 63 | optional = false 64 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 65 | 66 | [[package]] 67 | name = "idna" 68 | version = "3.3" 69 | description = "Internationalized Domain Names in Applications (IDNA)" 70 | category = "main" 71 | optional = false 72 | python-versions = ">=3.5" 73 | 74 | [[package]] 75 | name = "isort" 76 | version = "5.9.3" 77 | description = "A Python utility / library to sort Python imports." 78 | category = "dev" 79 | optional = false 80 | python-versions = ">=3.6.1,<4.0" 81 | 82 | [package.extras] 83 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"] 84 | requirements_deprecated_finder = ["pipreqs", "pip-api"] 85 | colors = ["colorama (>=0.4.3,<0.5.0)"] 86 | plugins = ["setuptools"] 87 | 88 | [[package]] 89 | name = "mypy-extensions" 90 | version = "0.4.3" 91 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 92 | category = "dev" 93 | optional = false 94 | python-versions = "*" 95 | 96 | [[package]] 97 | name = "pathspec" 98 | version = "0.9.0" 99 | description = "Utility library for gitignore style pattern matching of file paths." 100 | category = "dev" 101 | optional = false 102 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 103 | 104 | [[package]] 105 | name = "platformdirs" 106 | version = "2.4.0" 107 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 108 | category = "dev" 109 | optional = false 110 | python-versions = ">=3.6" 111 | 112 | [package.extras] 113 | docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] 114 | test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] 115 | 116 | [[package]] 117 | name = "regex" 118 | version = "2021.10.8" 119 | description = "Alternative regular expression module, to replace re." 120 | category = "dev" 121 | optional = false 122 | python-versions = "*" 123 | 124 | [[package]] 125 | name = "requests" 126 | version = "2.26.0" 127 | description = "Python HTTP for Humans." 128 | category = "main" 129 | optional = false 130 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 131 | 132 | [package.dependencies] 133 | certifi = ">=2017.4.17" 134 | charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} 135 | idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} 136 | urllib3 = ">=1.21.1,<1.27" 137 | 138 | [package.extras] 139 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 140 | use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] 141 | 142 | [[package]] 143 | name = "six" 144 | version = "1.16.0" 145 | description = "Python 2 and 3 compatibility utilities" 146 | category = "main" 147 | optional = false 148 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 149 | 150 | [[package]] 151 | name = "slpp" 152 | version = "1.2.3" 153 | description = "SLPP is a simple lua-python data structures parser" 154 | category = "main" 155 | optional = false 156 | python-versions = "*" 157 | 158 | [package.dependencies] 159 | six = "*" 160 | 161 | [[package]] 162 | name = "tomli" 163 | version = "1.2.1" 164 | description = "A lil' TOML parser" 165 | category = "dev" 166 | optional = false 167 | python-versions = ">=3.6" 168 | 169 | [[package]] 170 | name = "typing-extensions" 171 | version = "3.10.0.2" 172 | description = "Backported and Experimental Type Hints for Python 3.5+" 173 | category = "dev" 174 | optional = false 175 | python-versions = "*" 176 | 177 | [[package]] 178 | name = "urllib3" 179 | version = "1.26.7" 180 | description = "HTTP library with thread-safe connection pooling, file post, and more." 181 | category = "main" 182 | optional = false 183 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 184 | 185 | [package.extras] 186 | brotli = ["brotlipy (>=0.6.0)"] 187 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] 188 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 189 | 190 | [metadata] 191 | lock-version = "1.1" 192 | python-versions = "^3.9" 193 | content-hash = "4aab865f2c8d9be675ec48fa97a312ae79eaf002a3d8a6856dd006457be2b910" 194 | 195 | [metadata.files] 196 | black = [ 197 | {file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"}, 198 | {file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"}, 199 | ] 200 | certifi = [ 201 | {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, 202 | {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, 203 | ] 204 | charset-normalizer = [ 205 | {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, 206 | {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, 207 | ] 208 | click = [ 209 | {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, 210 | {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, 211 | ] 212 | colorama = [ 213 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 214 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 215 | ] 216 | idna = [ 217 | {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, 218 | {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, 219 | ] 220 | isort = [ 221 | {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, 222 | {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, 223 | ] 224 | mypy-extensions = [ 225 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 226 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 227 | ] 228 | pathspec = [ 229 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, 230 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, 231 | ] 232 | platformdirs = [ 233 | {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, 234 | {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, 235 | ] 236 | regex = [ 237 | {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:094a905e87a4171508c2a0e10217795f83c636ccc05ddf86e7272c26e14056ae"}, 238 | {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:981c786293a3115bc14c103086ae54e5ee50ca57f4c02ce7cf1b60318d1e8072"}, 239 | {file = "regex-2021.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b0f2f874c6a157c91708ac352470cb3bef8e8814f5325e3c5c7a0533064c6a24"}, 240 | {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51feefd58ac38eb91a21921b047da8644155e5678e9066af7bcb30ee0dca7361"}, 241 | {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8de658d7db5987b11097445f2b1f134400e2232cb40e614e5f7b6f5428710e"}, 242 | {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1ce02f420a7ec3b2480fe6746d756530f69769292eca363218c2291d0b116a01"}, 243 | {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39079ebf54156be6e6902f5c70c078f453350616cfe7bfd2dd15bdb3eac20ccc"}, 244 | {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ff24897f6b2001c38a805d53b6ae72267025878d35ea225aa24675fbff2dba7f"}, 245 | {file = "regex-2021.10.8-cp310-cp310-win32.whl", hash = "sha256:c6569ba7b948c3d61d27f04e2b08ebee24fec9ff8e9ea154d8d1e975b175bfa7"}, 246 | {file = "regex-2021.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:45cb0f7ff782ef51bc79e227a87e4e8f24bc68192f8de4f18aae60b1d60bc152"}, 247 | {file = "regex-2021.10.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fab3ab8aedfb443abb36729410403f0fe7f60ad860c19a979d47fb3eb98ef820"}, 248 | {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e55f8d66f1b41d44bc44c891bcf2c7fad252f8f323ee86fba99d71fd1ad5e3"}, 249 | {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d52c5e089edbdb6083391faffbe70329b804652a53c2fdca3533e99ab0580d9"}, 250 | {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1abbd95cbe9e2467cac65c77b6abd9223df717c7ae91a628502de67c73bf6838"}, 251 | {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9b5c215f3870aa9b011c00daeb7be7e1ae4ecd628e9beb6d7e6107e07d81287"}, 252 | {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f540f153c4f5617bc4ba6433534f8916d96366a08797cbbe4132c37b70403e92"}, 253 | {file = "regex-2021.10.8-cp36-cp36m-win32.whl", hash = "sha256:1f51926db492440e66c89cd2be042f2396cf91e5b05383acd7372b8cb7da373f"}, 254 | {file = "regex-2021.10.8-cp36-cp36m-win_amd64.whl", hash = "sha256:5f55c4804797ef7381518e683249310f7f9646da271b71cb6b3552416c7894ee"}, 255 | {file = "regex-2021.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb2baff66b7d2267e07ef71e17d01283b55b3cc51a81b54cc385e721ae172ba4"}, 256 | {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e527ab1c4c7cf2643d93406c04e1d289a9d12966529381ce8163c4d2abe4faf"}, 257 | {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c98b013273e9da5790ff6002ab326e3f81072b4616fd95f06c8fa733d2745f"}, 258 | {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:55ef044899706c10bc0aa052f2fc2e58551e2510694d6aae13f37c50f3f6ff61"}, 259 | {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0ab3530a279a3b7f50f852f1bab41bc304f098350b03e30a3876b7dd89840e"}, 260 | {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a37305eb3199d8f0d8125ec2fb143ba94ff6d6d92554c4b8d4a8435795a6eccd"}, 261 | {file = "regex-2021.10.8-cp37-cp37m-win32.whl", hash = "sha256:2efd47704bbb016136fe34dfb74c805b1ef5c7313aef3ce6dcb5ff844299f432"}, 262 | {file = "regex-2021.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:924079d5590979c0e961681507eb1773a142553564ccae18d36f1de7324e71ca"}, 263 | {file = "regex-2021.10.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19b8f6d23b2dc93e8e1e7e288d3010e58fafed323474cf7f27ab9451635136d9"}, 264 | {file = "regex-2021.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b09d3904bf312d11308d9a2867427479d277365b1617e48ad09696fa7dfcdf59"}, 265 | {file = "regex-2021.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:951be934dc25d8779d92b530e922de44dda3c82a509cdb5d619f3a0b1491fafa"}, 266 | {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f125fce0a0ae4fd5c3388d369d7a7d78f185f904c90dd235f7ecf8fe13fa741"}, 267 | {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f199419a81c1016e0560c39773c12f0bd924c37715bffc64b97140d2c314354"}, 268 | {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:09e1031e2059abd91177c302da392a7b6859ceda038be9e015b522a182c89e4f"}, 269 | {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c070d5895ac6aeb665bd3cd79f673775caf8d33a0b569e98ac434617ecea57d"}, 270 | {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:176796cb7f82a7098b0c436d6daac82f57b9101bb17b8e8119c36eecf06a60a3"}, 271 | {file = "regex-2021.10.8-cp38-cp38-win32.whl", hash = "sha256:5e5796d2f36d3c48875514c5cd9e4325a1ca172fc6c78b469faa8ddd3d770593"}, 272 | {file = "regex-2021.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:e4204708fa116dd03436a337e8e84261bc8051d058221ec63535c9403a1582a1"}, 273 | {file = "regex-2021.10.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6dcf53d35850ce938b4f044a43b33015ebde292840cef3af2c8eb4c860730fff"}, 274 | {file = "regex-2021.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b8b6ee6555b6fbae578f1468b3f685cdfe7940a65675611365a7ea1f8d724991"}, 275 | {file = "regex-2021.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e2ec1c106d3f754444abf63b31e5c4f9b5d272272a491fa4320475aba9e8157c"}, 276 | {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973499dac63625a5ef9dfa4c791aa33a502ddb7615d992bdc89cf2cc2285daa3"}, 277 | {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88dc3c1acd3f0ecfde5f95c32fcb9beda709dbdf5012acdcf66acbc4794468eb"}, 278 | {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4786dae85c1f0624ac77cb3813ed99267c9adb72e59fdc7297e1cf4d6036d493"}, 279 | {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe6ce4f3d3c48f9f402da1ceb571548133d3322003ce01b20d960a82251695d2"}, 280 | {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9e3e2cea8f1993f476a6833ef157f5d9e8c75a59a8d8b0395a9a6887a097243b"}, 281 | {file = "regex-2021.10.8-cp39-cp39-win32.whl", hash = "sha256:82cfb97a36b1a53de32b642482c6c46b6ce80803854445e19bc49993655ebf3b"}, 282 | {file = "regex-2021.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:b04e512eb628ea82ed86eb31c0f7fc6842b46bf2601b66b1356a7008327f7700"}, 283 | {file = "regex-2021.10.8.tar.gz", hash = "sha256:26895d7c9bbda5c52b3635ce5991caa90fbb1ddfac9c9ff1c7ce505e2282fb2a"}, 284 | ] 285 | requests = [ 286 | {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, 287 | {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, 288 | ] 289 | six = [ 290 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 291 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 292 | ] 293 | slpp = [ 294 | {file = "SLPP-1.2.3-py2.py3-none-any.whl", hash = "sha256:b2ff423e6afe8f49c56ed60209790a7e15a239c6d4a0a034337ab9d175389227"}, 295 | {file = "SLPP-1.2.3.tar.gz", hash = "sha256:21fdd9328348090c71a5d32773e8ee68aab8ad7ecc322f5e0cc010114cb549c8"}, 296 | ] 297 | tomli = [ 298 | {file = "tomli-1.2.1-py3-none-any.whl", hash = "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f"}, 299 | {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"}, 300 | ] 301 | typing-extensions = [ 302 | {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, 303 | {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, 304 | {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, 305 | ] 306 | urllib3 = [ 307 | {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, 308 | {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, 309 | ] 310 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "pathofbuilding-python" 3 | version = "0.1.0" 4 | description = "Python port of Path of Building" 5 | authors = ["ppoelzl <33464174+ppoelzl@users.noreply.github.com>"] 6 | license = "MIT" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.9" 10 | requests = "^2.26.0" 11 | SLPP = "^1.2.3" 12 | 13 | [tool.poetry.dev-dependencies] 14 | black = "^21.9b0" 15 | isort = "^5.9.3" 16 | 17 | [build-system] 18 | requires = ["poetry-core>=1.0.0"] 19 | build-backend = "poetry.core.masonry.api" 20 | 21 | [tool.isort] 22 | profile = "black" 23 | multi_line_output = 3 24 | -------------------------------------------------------------------------------- /src/scripts/convert_skill_data.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | import slpp 4 | 5 | line_count = 0 6 | data = io.StringIO() 7 | data.write("{") 8 | with open("act_dex.lua") as fd: 9 | lines = fd.readlines() 10 | for line in lines: 11 | line = line.strip() 12 | # Ignore comments or local Lua defines 13 | if line.startswith("--") or line.startswith("local"): 14 | continue 15 | data.write(line) 16 | line_count += 1 17 | data.write("}") 18 | data.seek(0) 19 | 20 | converted_data = slpp.slpp.decode(data.read()) 21 | print(f"processed {line_count} lines") 22 | # for key in converted_data: 23 | # print(key) 24 | print(converted_data["AnimateWeapon"]) 25 | -------------------------------------------------------------------------------- /src/scripts/fetch_character.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import re 3 | 4 | import requests 5 | 6 | HOST_NAME = "https://www.pathofexile.com/" 7 | PROFILE_PATH = "account/view-profile/" 8 | CHARACTER_PATH = "character-window/get-characters" 9 | PASSIVE_TREE_PATH = "character-window/get-passive-skills" 10 | ITEM_PATH = "character-window/get-items" 11 | 12 | realms = { 13 | "pc": { 14 | "realmCode": "pc", 15 | "hostName": "https://www.pathofexile.com/", 16 | "profileURL": "account/view-profile/", 17 | }, 18 | "xbox": { 19 | "realmCode": "xbox", 20 | "hostName": "https://www.pathofexile.com/", 21 | "profileURL": "account/xbox/view-profile/", 22 | }, 23 | "sony": { 24 | "realmCode": "sony", 25 | "hostName": "https://www.pathofexile.com/", 26 | "profileURL": "account/sony/view-profile/", 27 | }, 28 | "garena": { 29 | "realmCode": "pc", 30 | "hostName": "https://web.poe.garena.tw/", 31 | "profileURL": "account/view-profile/", 32 | }, 33 | "tencent": { 34 | "realmCode": "pc", 35 | "hostName": "https://poe.game.qq.com/", 36 | "profileURL": "account/view-profile/", 37 | }, 38 | } 39 | realm_code = "pc" 40 | headers = {"User-Agent": "Path of Building Community", "Accept": ""} 41 | 42 | 43 | def import_characters(account_name: str) -> tuple[str, dict] | None: 44 | url = f"{HOST_NAME}{CHARACTER_PATH}" 45 | params = {"accountName": account_name, "realm": realm_code} 46 | try: 47 | response = requests.get(url, params=params, headers=headers, timeout=6.0) 48 | except requests.RequestException as e: 49 | print(f"Error retrieving account: {e}.") 50 | return 51 | characters = response.json() 52 | url = f"{HOST_NAME}{PROFILE_PATH}{account_name}" 53 | try: 54 | response = requests.get(url, headers=headers, timeout=6.0) 55 | except requests.RequestException as e: 56 | print(f"Error retrieving character list: {e}.") 57 | return 58 | if m := re.search(r"/view-profile/(\w+)/characters", response.text): 59 | return m.group(1), characters 60 | 61 | 62 | def import_passive_tree(account_name: str, char_name: str) -> dict | None: 63 | url = f"{HOST_NAME}{PASSIVE_TREE_PATH}" 64 | params = {"accountName": account_name, "character": char_name, "realm": realm_code} 65 | try: 66 | response = requests.get(url, params=params, headers=headers, timeout=6.0) 67 | except requests.RequestException as e: 68 | print(f"Error retrieving passive skill tree: {e}.") 69 | return 70 | return response.json() 71 | 72 | 73 | def import_items(account_name: str, char_name: str) -> dict | None: 74 | url = f"{HOST_NAME}{ITEM_PATH}" 75 | params = {"accountName": account_name, "character": char_name, "realm": realm_code} 76 | try: 77 | response = requests.get(url, params=params, headers=headers, timeout=6.0) 78 | except requests.RequestException as e: 79 | print(f"Error retrieving items: {e}.") 80 | return 81 | return response.json() 82 | 83 | 84 | if __name__ == "__main__": 85 | parser = argparse.ArgumentParser(description="Parse Character/Account Info") 86 | parser.add_argument("account_name", help="account name", type=str) 87 | parser.add_argument("--realm", help="specify realm code (e.g., pc, xbox, sony)") 88 | args = parser.parse_args() 89 | print(args) 90 | if args.realm: 91 | try: 92 | realm_code = realms[args.realm.lower()]["realmCode"] 93 | HOST_NAME = realms[args.realm.lower()]["hostName"] 94 | PROFILE_PATH = realms[args.realm.lower()]["profileURL"] 95 | except KeyError: 96 | pass 97 | current_league = "Standard" 98 | name, characters = import_characters(args.account_name) 99 | if characters and "error" not in characters: 100 | current_league_characters = [ 101 | character["name"] 102 | for character in characters 103 | if character["league"] == current_league 104 | ] 105 | print(f"[{current_league.upper()}] Characters: {current_league_characters}") 106 | passive_tree = import_passive_tree(name, current_league_characters[0]) 107 | items = import_items(name, current_league_characters[0]) 108 | --------------------------------------------------------------------------------