The purpose of this project is to define rules to assess the quality and potential of each artifact allowing for a simpler exclusion of bad artifacts.
Your inventory is always full and you don't have the patience to choose which artifacts to discard.
You want to use wider filters to generate your build, and it's taking hours.
+------------------+ +------+ +---------------+ +-----+ +-------------------------+
| Inventory Kamera | -> | GOOD | -> | g2c-validator | -> | g2c | -> | Artifact List (or GOOD) |
+------------------+ +------+ +---------------+ +-----+ +-------------------------+
/\ ||
|| \/
+---------------+
| JSON editor |
+---------------+
Scans
Format
Optimizers
- Genshin Optimizer (Character Optimizer)
- gcsim Team Optimizer (Team Optimizer)
The builds contain two main components: 1) the filters; and 2) the weights of each sub stats.
Filters are used to limit the artifacts that will be evaluated. Then each artifact receives a score according to the sub stats present.
Undeclared sub stats will be considered as zero.
The weights are normalized when evaluating the artifact score ensuring that every artifact can get points from 0 to 1.
For simplicity's sake, we've abstracted the configuration by creating builds with the relevant artifacts for each character. This ensures that any artifact relevant to a character is preserved.
Each artifact can contain 0 to N scores according to how many builds adhere to it. Additionally, the best score is highlighted in the artifact attributes (in G2C format).
- G2C (Genshin Garbage Collector): used to compute build and scores
- GOOD (Genshin Open Object Description): de facto standard in Genshin community
- Count: amount artifacts returned
This attribute indicates the artifacts that must be kept.
keep
: display only artifacts that must be kept (locked)discard
: display only artifacts that must be discarded (unlocked)all
: display all artifacts (locked and unlocked)
Filters are an additional layer for excluding artifacts, allowing you to evaluate artifacts by their best score.
Filters contain two main components: 1) the selectors; and 2) the actions.
Selectors are a comma-separated list of key and value. Below is a list of supported keys and values:
set_key
: GOOD-like valuesslot_key
: GOOD-like valuesmain_stat_key
: GOOD-like valuesrarity
:1-5
level
:0-20
rank
:0-5
(rank isfloor(level/4)
, i.e. the number of additional rolls an artifact got by leveling)
*Only artifacts matched by the selector will be filtered.
*Any artifact that don't match the selector will be preserved.
It is possible to use a wildcard character to select all artifacts for filtering, i.e. *:*
.
It is possible to use a semicolon-separated list to specify more than one value for the selector.
The actions will effectively filter the list of artifacts and can be as follows:
- threshold (
t
): minimum score threshold to keep artifacts (float
). - best score (
b
): select the N best artifacts (int
).
As an alternative to filters, you can use groupings to limit the amount of artifacts kept in each group.
The same filter selector keys apply here (except the wildcard character).
After all filters are applied it is possible to sort the list of artifacts.
Sort contain two main components: 1) the key; and 2) the order.
Below is a list of supported keys:
set_key
slot_key
main_stat_key
rarity
level
rank
best_score
refer_id
And as for the order, the possible parameters are:
asc
desc
If not specified an order, asc is assumed.
Special order keys
By default, sorting use alphabetical character order, but for some keys Genshin's internal order used. The purpose of this is to facilitate the mapping between the artifacts exported by G2C and the game.
Below is a list of keys don't use alphabetical order:
set_key
slot_key
Genshin order
This section explains the game order if you want to order the output of artifacts exported by this program in the same way.
rarity:desc
level:desc
set_key:asc
(specific Genshin order; non-alphabetic order)slot_key:asc
(specific Genshin order; non-alphabetic order)- Original artifact sub stats amount (it would be necessary to calculate the number of sub stat rolls based on the known values of each sub stat)
- Artifact acquisition date (we cannot obtain this information)
For the last two ordering criteria we suggest using the best_score
.
Alternatively, the Inventory Kamera adds an identifier (refer_id
) to the artifact based on the order of collection which can be used to achieve the exact same ordering as in the game. However, when importing into Genshin Optimizer this identifier is removed.
source venv/bin/activate
pip install -r requirements.txt
python3 validator.py -i ~/good-full.json -vvv
python3 main.py -i '~/good-full.json' -o good > ~/good-filtered.json
> pip --version
Traceback (most recent call last):
File "/home/rodrigo/Git/personal/genshin-garbage-collector/venv/bin/pip", line 5, in <module>
from pip._internal.cli.main import main
ModuleNotFoundError: No module named 'pip'
> python3 -m ensurepip
> pip install --upgrade pip
Specify input file in GOOD format.
-i/--input-file input_file
Example:
-i './good.json'
Specify output format (default: g2c).
-o/--output-format [g2c|count|good]
Specify which artifacts to show (default: keep).
-k/--keep
-d/--discard
-a/--all
Display artifacts that are not at the maximum rarity allowed by the set.
-w/--weak
Filter artifacts according to defined rules.
-f/--filter selector_list=action
selector_list = selector_key:selector_value[,selector_key:selector_value]
action = action_type:action_value
Example 1: keep artifacts above score 0.3
-f '*:*=t:0.3'
Example 2: use different score based on artifact rank
-f 'rank:0=t:0.15' -f 'rank:1=t:0.20' -f 'rank:2=t:0.25' -f 'rank:3=t:0.30' -f 'rank:4=t:0.35' -f 'rank:5=t:0.40'
-f 'rank:0=t:0.20' -f 'rank:1=t:0.30' -f 'rank:2=t:0.40' -f 'rank:3=t:0.45' -f 'rank:4=t:0.50' -f 'rank:5=t:0.55'
Example 3: keep artifacts above score 0.4
among Gladiators Finale
and Wanderers Troupe
whose rank is between 0
and 2
-f 'set_key:[GladiatorsFinale,WanderersTroupe],rank:[0,1,2]=t:0.4'
Example 4: keep the 700
best artifacts
-f '*:*=b:700'
Example 5: keep the 5
best plume
from the Pale Flame
artifact
-f 'set_key:PaleFlame,slot_key:plume=b:5'
Example 6: keep the 20
best artifacts among Crimson Witch Of Flames
and Shimenawas Reminiscence
whose rank is between 0
and 3
-f 'set_key:[CrimsonWitchOfFlames,ShimenawasReminiscence],rank:[0,1,2,3]=b:20'
Keeps only N artifacts in each group.
-g/--group group_key_list=amount
group_key_list = set_key,slot_key,main_stat_key,rarity,level,rank
amount = integer
Examples:
-g 'set_key=25' # keep the 25 best artifacts each set
-g 'set_key,slot_key=5' # keep the 5 best artifacts each set and slot
-g 'set_key,slot_key,rank=1' # keep the best artifact each set, slot and rank
-s/--sort sort_key:sort_order[,sort_key:sort_order]
Examples:
-s 'best_score' # sort artifacts from highest to lowest based on best_score attribute
-s 'best_score:desc' # sort artifacts from highest to lowest based on best_score attribute
-s 'best_score:asc' # sort artifacts from lowest to highest based on best_score attribute
-s 'level:asc,best_score:desc' # sort artifacts ascending by level and descending by best_score attribute
-s 'rarity:desc,level:desc,set_key,slot_key,best_score:desc' # genshin inventory order (almost)
-s 'refer_id' # genshin inventory order (when using data exported from Inventory Kamera)
- Check for null on the first three sub stats
- Check for null on forth sub stat for upgraded artifact
- Check max rarity for artifact sets
- Check invalid artifact sets
source venv/bin/activate
pip install -r requirements.txt
python3 main.py -i '~/good.json'
jq . builds/**/*.json > /dev/null 2>&1; echo $?
- GOOD (Genshin Open Object Description)
- G2C (Genshin Garbage Collector)
- List:
[artifact]
- Set/Slot format:
{ set_key: { slot_key: [artifact] } }
- ID format:
{ id: artifact }
# Follow in order listed on Genshin to see which artifacts can be deleted
python3 main.py -i 'good/data.json' -o g2c -aw | jq '[.[] | {rarity,level,rank,main_stat_key,set_key,slot_key,best_score,best_build,refer_id,location,lock,sub_stats}] | sort_by(.refer_id)' > output/all.json
# How many artifacts to remove (only the ones that don't match any build)
cat output/all.json | jq '[.[] | select(.lock == false)] | length'
# To reduce a specific set (e.g. WanderersTroupe or GladiatorsFinale), sort by quantity...
cat output/all.json | jq 'group_by(.set_key) | map({set_key: .[0].set_key, count: . | length}) | sort_by(.count)'
# ...evaluate total amount for specific set...
cat output/all.json | jq '[.[] | select(.set_key == "WanderersTroupe")] | length'
# ...and then create threshold for each rank until you find a satisfactory amount to remove...
cat output/all.json | jq '[.[] | select(.set_key == "WanderersTroupe") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.25) or (.rank == 1 and .best_score < 0.30) or (.rank == 2 and .best_score < 0.35) or (.rank == 3 and .best_score < 0.40) or (.rank == 4 and .best_score < 0.45) or (.rank == 5 and .best_score < 0.50))] | length'
# ...finally get a list of artifacts with the same filter used in the previous command
cat output/all.json | jq '[.[] | select(.set_key == "WanderersTroupe") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.25) or (.rank == 1 and .best_score < 0.30) or (.rank == 2 and .best_score < 0.35) or (.rank == 3 and .best_score < 0.40) or (.rank == 4 and .best_score < 0.45) or (.rank == 5 and .best_score < 0.50))]' > output/wanderers.json
# To reduce a specific slot (e.g. flower or plume), sort by quantity...
cat output/all.json | jq 'group_by(.slot_key) | map({slot_key: .[0].slot_key, count: . | length}) | sort_by(.count)'
# ...evaluate total amount...
cat output/all.json | jq '[.[] | select(.slot_key == "flower")] | length'
# ...and then create threshold for each rank until you find a satisfactory amount to remove to remove...
cat output/all.json | jq '[.[] | select(.slot_key == "flower") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.20) or (.rank == 1 and .best_score < 0.25) or (.rank == 2 and .best_score < 0.30) or (.rank == 3 and .best_score < 0.35) or (.rank == 4 and .best_score < 0.40) or (.rank == 5 and .best_score < 0.45))] | length'
# ...finally get a list of artifacts with the same filter used in the previous command
cat output/all.json | jq '[.[] | select(.slot_key == "flower") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.20) or (.rank == 1 and .best_score < 0.25) or (.rank == 2 and .best_score < 0.30) or (.rank == 3 and .best_score < 0.35) or (.rank == 4 and .best_score < 0.40) or (.rank == 5 and .best_score < 0.45))]' > output/flower.json
# To reduce artifact-based builds (e.g. "Goblet - Elemental DMG", "Circlet - Rare Stats", "Sands - Elemental Mastery")...
cat output/all.json | jq 'group_by(.best_build) | map({best_build: .[0].best_build, count: . | length}) | sort_by(.count)'
# ...first, create file with all artifacts and build_score attributes
python3 main.py -i 'good/data.json' -o g2c -aw | jq '[.[] | del(.artifact_data)] | sort_by(.refer_id)' > output/all-with-build-score.json
# ...then evaluate total amount...
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Goblet - Elemental DMG")] | length'
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Circlet - Rare Stats")] | length'
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Sands - Elemental Mastery")] | length'
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Artifact - Deepwood Memories")] | length'
# ...and then create threshold for each rank until you find a satisfactory amount to remove...
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Goblet - Elemental DMG") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.30) or (.rank == 1 and .best_score < 0.35) or (.rank == 2 and .best_score < 0.40) or (.rank == 3 and .best_score < 0.45) or (.rank == 4 and .best_score < 0.50) or (.rank == 5 and .best_score < 0.55))] | length'
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Circlet - Rare Stats") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.30) or (.rank == 1 and .best_score < 0.35) or (.rank == 2 and .best_score < 0.40) or (.rank == 3 and .best_score < 0.45) or (.rank == 4 and .best_score < 0.50) or (.rank == 5 and .best_score < 0.55))] | length'
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Sands - Elemental Mastery") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.28) or (.rank == 1 and .best_score < 0.33) or (.rank == 2 and .best_score < 0.38) or (.rank == 3 and .best_score < 0.43) or (.rank == 4 and .best_score < 0.48) or (.rank == 5 and .best_score < 0.53))] | length'
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Artifact - Deepwood Memories") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.28) or (.rank == 1 and .best_score < 0.33) or (.rank == 2 and .best_score < 0.38) or (.rank == 3 and .best_score < 0.43) or (.rank == 4 and .best_score < 0.48) or (.rank == 5 and .best_score < 0.53))] | length'
# ...finally get a list of artifacts with the same filter used in the previous command
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Goblet - Elemental DMG") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.30) or (.rank == 1 and .best_score < 0.35) or (.rank == 2 and .best_score < 0.40) or (.rank == 3 and .best_score < 0.45) or (.rank == 4 and .best_score < 0.50) or (.rank == 5 and .best_score < 0.55))]' > output/art-goblet.json
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Circlet - Rare Stats") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.30) or (.rank == 1 and .best_score < 0.35) or (.rank == 2 and .best_score < 0.40) or (.rank == 3 and .best_score < 0.45) or (.rank == 4 and .best_score < 0.50) or (.rank == 5 and .best_score < 0.55))]' > output/art-circlet.json
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Sands - Elemental Mastery") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.28) or (.rank == 1 and .best_score < 0.33) or (.rank == 2 and .best_score < 0.38) or (.rank == 3 and .best_score < 0.43) or (.rank == 4 and .best_score < 0.48) or (.rank == 5 and .best_score < 0.53))]' > output/art-sands.json
cat output/all-with-build-score.json | jq '[.[] | select(.best_build == "Artifact - Deepwood Memories") | select((.best_score == 0) or (.rank == 0 and .best_score < 0.28) or (.rank == 1 and .best_score < 0.33) or (.rank == 2 and .best_score < 0.38) or (.rank == 3 and .best_score < 0.43) or (.rank == 4 and .best_score < 0.48) or (.rank == 5 and .best_score < 0.53))]' > output/art-deepwood.json
# >>>> Verify whether these artifacts not match with other build thresholds <<<<
# To group all artifacts to be removed in a single file, use the command below
jq -s 'reduce .[] as $item ([]; . + $item) | unique_by(.refer_id) | .[].lock = false' output/{flower,plume,sands,goblet,circlet,gladiators,wanderers,art-sands,art-goblet,art-circlet,art-deepwood}.json > output/remove.json
# To merge artifacts to be removed in the general list, use the command below (the order of the remove.json and all.json files is important)
jq -s '.[0] + .[1] | unique_by(.refer_id)' output/{remove,all}.json > output/all-with-remove.json
# How many artifacts to remove
cat output/all-with-remove.json | jq '[.[] | select(.lock == false)] | length'
# ---
python3 main.py -i 'good/data.json' -o g2c -aw | jq '[.[] | del(.artifact_data)] | sort_by(.refer_id)' > output/all-with-build-score.json
python3 build-counter.py -i 'output/all-with-build-score.json'
# ---
# Disable builds like artifact-*.json
for file in builds/artifact-*.json; do mv ${file} ${file}.disabled; done
python3 main.py -i 'good/data.json' -o g2c -aw | jq '[.[] | {rarity,level,rank,main_stat_key,set_key,slot_key,best_score,best_build,refer_id,location,lock,sub_stats}] | sort_by(.refer_id)' > output/all-without-artifact-builds.json
for file in builds/artifact-*.json.disabled; do mv ${file} ${file//.disabled/}; done
# Find better artifacts to upgrade (disable build artifact-*.json)
cat output/all-without-artifact-builds.json | jq '[.[] | select(.rank != 5)] | sort_by(.best_score) | reverse' > output/upgrade.json
# To remove some arbitrary artifacts chain removal rules with select
cat output/upgrade.json | jq '[.[] | select(.slot_key != "flower") | select(.slot_key != "plume") | select(.set_key != "WanderersTroupe") | select(.set_key != "GladiatorsFinale") | select(.level < 16)]' > output/upgrade-reduced-set.json
# To upgrade artifacts from a specific set (disable build artifact-*.json)
cat output/all-without-artifact-builds.json | jq '[.[] | select(.rank != 5) | select(.set_key == "TenacityOfTheMillelith")] | sort_by(.best_score) | reverse' > output/millelith.json
cat output/all-without-artifact-builds.json | jq '[.[] | select(.rank != 5) | select(.set_key == "PaleFlame")] | sort_by(.best_score) | reverse' > output/pale.json
cat output/all-without-artifact-builds.json | jq '[.[] | select(.rank != 5) | select(.set_key == "EmblemOfSeveredFate")] | sort_by(.best_score) | reverse' > output/emblem.json
cat output/all-without-artifact-builds.json | jq '[.[] | select(.rank != 5) | select(.set_key == "HuskOfOpulentDreams")] | sort_by(.best_score) | reverse' > output/husk.json
cat output/all-without-artifact-builds.json | jq '[.[] | select(.rank != 5) | select(.set_key == "OceanHuedClam")] | sort_by(.best_score) | reverse' > output/ocean.json
cat output/all-without-artifact-builds.json | jq '[.[] | select(.rank != 5) | select(.set_key == "VermillionHereafter")] | sort_by(.best_score) | reverse' > output/vermillion.json
cat output/all-without-artifact-builds.json | jq '[.[] | select(.rank != 5) | select(.set_key == "CrimsonWitchOfFlames")] | sort_by(.best_score) | reverse' > output/crimson.json
# To upgrade artifacts from a specific build (disable build artifact-*.json)
cat output/all-without-artifact-builds.json | jq '[.[] | select(.rank != 5) | select(.best_build == "Eula - DPS")] | sort_by(.best_score) | reverse' > output/eula-dps.json
Copiar arquivos
- all-with-remove.json
- upgrade-reduced-set.json
- all-with-build-score.json