{"id":23471025,"url":"https://github.com/crschnick/pdxu_achievements","last_synced_at":"2026-01-21T13:32:19.709Z","repository":{"id":111720876,"uuid":"303571246","full_name":"crschnick/pdxu_achievements","owner":"crschnick","description":"This repository contains the official achievements for the Pdx-Unlimiter and a reference for creating custom achievements.","archived":false,"fork":false,"pushed_at":"2022-02-08T23:53:43.000Z","size":88,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-13T01:48:37.649Z","etag":null,"topics":["eu4","europa-universalis-4","europa-universalis-iv","paradox","paradox-interactive","pdx-unlimiter","pdxu"],"latest_commit_sha":null,"homepage":"https://github.com/crschnick/pdx_unlimiter","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crschnick.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-10-13T02:55:03.000Z","updated_at":"2020-11-01T18:58:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"a6122cfc-db42-4f54-be8b-80259b8aa12a","html_url":"https://github.com/crschnick/pdxu_achievements","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/crschnick/pdxu_achievements","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crschnick%2Fpdxu_achievements","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crschnick%2Fpdxu_achievements/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crschnick%2Fpdxu_achievements/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crschnick%2Fpdxu_achievements/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crschnick","download_url":"https://codeload.github.com/crschnick/pdxu_achievements/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crschnick%2Fpdxu_achievements/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28633761,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T04:47:28.174Z","status":"ssl_error","status_checked_at":"2026-01-21T04:47:22.943Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eu4","europa-universalis-4","europa-universalis-iv","paradox","paradox-interactive","pdx-unlimiter","pdxu"],"created_at":"2024-12-24T16:19:31.950Z","updated_at":"2026-01-21T13:32:19.703Z","avatar_url":"https://github.com/crschnick.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pdx-Unlimiter Achievements\n\nThis repository contains the official achievements for the [Pdx-Unlimiter](https://github.com/crschnick/pdx_unlimiter)\nand a reference for creating custom achievements.\n\n## Creating Achievements\n\nPdx-Unlimiter achievements are specified in the [JSON format](https://en.wikipedia.org/wiki/JSON) and make heavy use\nof [Json-Paths](https://github.com/json-path/JsonPath).\nIt is therefore useful to have a good understanding of both.\n\nCustom achievements can be created in the `\u003cpdxu_install_directory\u003e/user_achievements/\u003cgame\u003e/` directory.\nTo test your own Json-Path expressions, you can use the [Jayway JsonPath Evaluator](http://jsonpath.herokuapp.com/)\nwith the option `Always return result list` enabled.\n\nThe code that parses these achievement files can be found\n[here](https://github.com/crschnick/pdx_unlimiter/blob/master/app/src/main/java/com/crschnick/pdx_unlimiter/app/achievement/)\nIf you believe that the Pdx-Unlimiter has an achievement related bug,\nplease report it on the [Pdx-Unlimiter repository](https://github.com/crschnick/pdx_unlimiter)\nFor anything else you can use the [issues page](https://github.com/crschnick/pdxu_achievements/issues) of this repository.\n\n## Building\n\nYou can build the project with `gradle clean build`.\nTo create a release distribution, use `gradle createDist`.\n\n## Pdxu Achievement Reference\n\nAn achievement file has to contain the following definition:\n\n    {\n      \"achievement\": {\n        \u003cproperties\u003e\n      }\n    }\n\nThe first two properties of an achievement are self-explanatory.\nThey specify information that every user can see like the name and description of the achievement:\n\n    \"name\": \"Lucky Lucca\",\n    \"description\": \"As Lucca, own Lucknow!\",\n\nThe next property is the uuid of the achievement:\n\n    \"uuid\": \"db341422-144a-11eb-adc1-0242ac120002\",\n\nThis property is used to identify the achievement even if the name and description changes.\nTo generate this ID you can use an [online generator](https://uuid-generator.com/).\n\n### Nodes\n\nA node, in the context of pdxu achievements, are the contents of game data files or savegame files\non which Json-Path expressions can be applied on. (They don't have to be in the json format)\n\nThe savegame nodes are the contents of Pdx-Unlimiter save game data files, which are saved as `data.zip`.\nTo get an overview over the node structure of savegames, it is encouraged to browse the Pdx-Unlimiter save game data files.\nYou can also take a look at all [official achievements](https://github.com/crschnick/pdxu_achievements/tree/master/eu4/)\nto get a better understanding of the pdxu achievement structure.\n\nThe game data nodes are the contents of selected game data files:\n- `eu4.area`, the contents of `\u003cEU4 install dir\u003e/map/area.txt`\n- `eu4.region`, the contents of `\u003cEU4 install dir\u003e/map/region.txt`\n- `eu4.superregion`, the contents of `\u003cEU4 install dir\u003e/map/superregion.txt`\n- `eu4.continent`, the contents of `\u003cEU4 install dir\u003e/map/continent.txt`\n- `eu4.cultures`, the contents of `\u003cEU4 install dir\u003e/common/cultures/00_cultures.txt`\n\n### Variables\n\nVariables are defined with the following property:\n\n    \"variables\": {\n      \u003cvariableName\u003e: \u003cvariable\u003e\n      ...\n      \u003cvariableName\u003e: \u003cvariable\u003e\n    },\n\nThere are three types of variables.\nThe first type are value variables, which store a fixed value that can be used later on:\n\n      {\n        \"type\": \"value\",\n        \"value\": \u003cvalue\u003e,\n      }\n      \nThe second type are path value variables, which store the result of a Json-Path evaluation.\n      \n      {\n        \"type\": \"pathValue\",\n        \"node\": \u003cnode\u003e,\n        \"path\": \u003cJson-Path\u003e,\n        \"list\": (true|false)\n      }\n       \nIf the list property is set to true, the variable will always store a list.\nIf the list property is set to false, the variable will try to unpack the list and return a value, which means that\nif the variable evaluates to a list with the size of either zero or more than one, an exception is thrown.\n\nThe third type are path count variables, which store the size of a Json-Path evaluation:\n\n      {\n        \"type\": \"pathCount\",\n        \"node\": \u003cnode\u003e,\n        \"path\": \u003cJson-Path\u003e,\n      }\n\nThe return value of a variable evaluation can be referenced in other achievement definitions by using `%{variableName}` in the text.\nThere are also several predefined variables and the full list can be found\n[here](https://github.com/crschnick/pdx_unlimiter/blob/master/app/src/main/java/com/crschnick/pdx_unlimiter/app/achievement/AchievementContent.java).\nFor example, the variable property could look like this:\n\n    \"variables\": {\n      \"startDate\": {\n        \"type\": \"pathValue\",\n        \"node\": \"gamestate\",\n        \"path\": \"$.start_date\",\n        \"list\": false\n      },\n      \"provinceOwnedCount\": {\n        \"type\": \"pathCount\",\n        \"node\": \"provinces\",\n        \"path\": \"$[?(@.owner == ${player})]\"\n      },\n      \"requiredProvinceCount\": {\n        \"type\": \"value\",\n        \"value\": 100\n      }\n    },\n\n### Icon\n\nThe icon property is optional and specifies which image should be displayed:\n\n    \"icon\": \"%{eu4.achievementImageDir}/achievement_lucky_lucca.dds\",\n\nTo reference image files that lie in a specific directory you can use the following predefined variables:\n- `%{eu4.achievementImageDir}`, which points to the achievement image directory of your EU4 installation\n- `%{eu4.installDir}`, which points to the installation directory of the Pdx-Unlimiter.\n\n\n### Conditions\n\nConditions make use of JsonPath filter expressions to evaluate to either true or false.\nA condition node consists out of a description, an optional node entry and a JsonPath filter.\n\n      {\n        \"description\": \u003cdescription\u003e,\n        \"node\": \u003cnode\u003e (optional),\n        \"filter\": \u003cJsonPath filter\u003e\n      }\n\nThe node entry is only used if the JsonPath filter references it.\nIf a filter only uses variables that are already evaluated there is no need to specify a node entry:\n\n      {\n        \"description\": \"Is Lucca\",\n        \"filter\": \"[?(%{player} == 'LUC')]\"\n      }\n\nSince the player variable was previously evaluated, the actual filter in use evaluates to `[?('HUN' == 'LUC')]` if the player is playing as Hungary.\nHowever for more complex conditions, that cannot be completely replaced by variables, the node property is usually required:\n\n      {\n        \"description\": \"Started as Lucca\",\n        \"node\": \"countries_history\",\n        \"filter\": \"[?($[%{player}]['tag_history'].length() == 0 || $[%{player}]['tag_history'][0] == 'LUC')]\"\n      }\n\n\nThere also exists several predefined conditions, which can be referenced with a text value.\nThe full list of predefined conditions can be found [here](https://github.com/crschnick/pdx_unlimiter/blob/master/app/src/main/java/com/crschnick/pdx_unlimiter/app/achievement/AchievementContent.java).\n\n\n\n#### Achievement types\n\nAchievement types define the different settings of an achievement, that make it impossible to compare the scores of two different players.\nThey consist out of a name and a list of conditions:\n\n    \"types\": [\n      {\n        \"name\": \u003cname\u003e,\n        \"conditions\": [\n          \u003ccondition\u003e\n          ...\n          \u003ccondition\u003e\n        ]\n      },\n      ...\n      {\n        \"name\": \u003cname\u003e,\n        \"conditions\": [\n          \u003ccondition\u003e\n          ...\n          \u003ccondition\u003e\n        ]\n      }\n    ],\n\n\nCommon achievement types are the difficulty level as shown in the following example, which only supports the normal, hard and very hard difficulty:\n\n    \"types\": [\n      {\n        \"name\": \"Normal\",\n        \"conditions\": [\n          \"normal_difficulty\"\n        ]\n      },\n      {\n        \"name\": \"Hard\",\n        \"conditions\": [\n          \"hard_difficulty\"\n        ]\n      },\n      {\n        \"name\": \"Very hard\",\n        \"conditions\": [\n          \"very_hard_difficulty\"\n        ]\n      }\n    ]\n\nIf no set of conditions for any type is fulfilled, then the player is not eligible for the achievement.\nFor example if the player was playing on easy difficulty, no type conditions of the example above would be fulfilled.\n\n### Eligibility conditions\n\nThe eligibility conditions specify whether a save game is currently eligible for the achievement.\nThe eligibility conditions are defined by a list of conditions:\n\n    \"eligibilityConditions\": [\n        \u003ccondition\u003e,\n        ...\n        \u003ccondition\u003e\n    ]\n\n\nCommon eligibility conditions are usually the starting nation, the start date, the ironman setting and more.\nFor example the eligibility conditions could look like this:\n\n    \"eligibilityConditions\": [\n      \"ironman\",\n      \"normal_province_values\",\n      \"historical_lucky_nations\",\n      \"normal_start_date\",\n      \"limited_country_forming\",\n      \"no_custom_nation\",\n      {\n        \"description\": \"Started as Lucca\",\n        \"node\": \"countries_history\",\n        \"condition\": \"$[%{player}]['tag_history'].length() == 0 || $[%{player}]['tag_history'][0] == 'LUC'\"\n      }\n    ]\n\nNote that this example makes heavy use of the predefined conditions.\n\n### Achievement conditions\n\nAchievement conditions work exactly like eligibility conditions.\nThey specify the requirements to achieve the given achievement:\n\n    \"achievementConditions\": [\n        \u003ccondition\u003e,\n        ...\n        \u003ccondition\u003e\n    ]\n\nFor example the achievement conditions could look like this:\n\n    \"achievementConditions\": [\n      \"not_released_vassal\",\n      {\n        \"description\": \"Is Lucca\",\n        \"condition\": \"%{player} == 'LUC'\"\n      },\n      {\n        \"description\": \"Owns Lucknow\",\n        \"condition\": \"%{lucknowOwner} == 'LUC'\"\n      },\n      {\n        \"description\": \"Has core on Lucknow\",\n        \"condition\": \"'LUC' in %{lucknowCores}\"\n      }\n    ],\n\n### Score\n\nThe score property defines how to calculate a score for the achievement:\n\n    \"score\": \u003cscorer\u003e\n\nA scorer can have a name and be one of five types.\nThe first type is a simple value scorer:\n\n      {\n        \"name\": \u003cname\u003e (optional),\n        \"value\": \u003cvalue\u003e\n      },\n\nThe second type is the condition scorer, which returns a value if all conditions are fulfilled:\n\n      {\n        \"name\": \u003cname\u003e (optional),\n        \"value\": \u003cvalue\u003e,\n        \"conditions\": [\n          \u003ccondition\u003e\n          ...\n          \u003ccondition\u003e\n        ]\n      },\n\nThe third type is a path value scorer, which returns the value of a Json-Path evaluation.\nThis scorer throws an exception, if the result of the Json-Path evaluation can not be converted into a number.\n\n      {\n        \"type\": \"pathValue\"\n        \"name\": \u003cname\u003e (optional),\n        \"path\": \u003cJson-Path\u003e\n      },\n\nThe fourth type is a path count scorer, which returns the size of the result of a Json-Path evaluation.\n\n      {\n        \"type\": \"pathCount\"\n        \"name\": \u003cname\u003e (optional),\n        \"path\": \u003cJson-Path\u003e\n      },\n\nThe last type is a chain scorer, which is used to chain different scorers together.\nThe operator property specifies what operator will be used to chain the score values together.\n\n      {\n        \"type\": \"chain\"\n        \"operator\": (\"add\" | \"subtract\" | \"multiply\" | \"divide\")\n        \"name\": \u003cname\u003e (optional),\n        \"scorers\": [\n            \u003cscorer\u003e\n            ...\n            \u003cscorer\u003e\n        ]\n      },\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrschnick%2Fpdxu_achievements","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrschnick%2Fpdxu_achievements","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrschnick%2Fpdxu_achievements/lists"}