CleverRaven / Cataclysm-DDA

Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world.
http://cataclysmdda.org
Other
10.53k stars 4.16k forks source link

Obsolete legacy JSON #36110

Open ymber opened 4 years ago

ymber commented 4 years ago

Is your feature request related to a problem? Please describe. We've got a load of legacy JSON making game data inconsistent and it's harder to make tooling for our data when it isn't well standardized.

Describe the solution you'd like All game data should use current conventions and support for loading legacy JSON objects should be dropped. Most of the updates should be relatively easy to automate.

snipercup commented 4 years ago

Any direction as to what the 'current convention' is? For example the name i'm assuming the 'str: name, str_pl: names' is the current convention. However I'm seeing some 'name: name, name_plural: names' in some entries. The tooling I made is taking both forms into account but you're right, having one standard to live up to would make things easier.

anothersimulacrum commented 4 years ago

"name": { "str": "foo", "str_pl": "faz" } is preferred.

ymber commented 4 years ago

Item groups should be as described in ITEM_SPAWN.md. Volume, weight, and time should use quantity strings. And guns defining burst should define modes instead.

Davi-DeGanne commented 4 years ago

When (if ever) should we obsolete the corresponding C++ that reads said legacy JSON?

ymber commented 4 years ago

Saves need to be compatible from one stable to the next but longer is optional. For anything that doesn't affect save compatibility we can cut support as soon as everything in mainline is updated.

jayhide commented 4 years ago

What kind of quantity string to use for time values like in bionics.json that are very small and in moves?

anothersimulacrum commented 4 years ago

Another suggestion: Legacy damage loading, such as this https://github.com/CleverRaven/Cataclysm-DDA/blob/745411a13e2802c08529d0c81338ff89937ae090/src/item_factory.cpp#L1330

The damage and pierce ints should be replaced with "damage": { "damage_type": "stab", "amount": old_damage, "armor_penetration": old_pierce }

ymber commented 4 years ago

Time strings are deserialized into time_duration objects which can't store values less than a turn. It gets complicated that small because there isn't a fixed relationship between turns and moves so we're keeping moves as ints for now.

hexagonrecursion commented 4 years ago

@ymber

hexagonrecursion commented 4 years ago
$ shopt -s globstar
$ jq '.[] | select(.volume? | type == "number") | {file:input_filename, id, volume}' data/json/items/**/*.json | jq --slurp 'reduce  .[] as $it ({}; .[$it.file] |= [.[]?, $it | {id, volume}])'
{
  "data/json/items/armor/jewelry.json": [
    {
      "id": "diamond_dental_grill",
      "volume": 0
    },
    {
      "id": "garnet_dental_grill",
      "volume": 0
    },
    {
      "id": "diamond_ring",
      "volume": 0
    },
    {
      "id": "cufflinks",
      "volume": 0
    },
    {
      "id": "cufflinks_intricate",
      "volume": 0
    },
    {
      "id": "garnet_gold_cufflinks",
      "volume": 0
    },
    {
      "id": "garnet_silver_cufflinks",
      "volume": 0
    },
    {
      "id": "garnet_platinum_cufflinks",
      "volume": 0
    },
    {
      "id": "garnet_gold_earring",
      "volume": 0
    },
    {
      "id": "garnet_silver_earring",
      "volume": 0
    },
    {
      "id": "garnet_platinum_earring",
      "volume": 0
    },
    {
      "id": "garnet_gold_ring",
      "volume": 0
    },
    {
      "id": "garnet_silver_ring",
      "volume": 0
    },
    {
      "id": "garnet_platinum_ring",
      "volume": 0
    },
    {
      "id": "garnet_gold_bracelet",
      "volume": 0
    },
    {
      "id": "garnet_silver_bracelet",
      "volume": 0
    },
    {
      "id": "garnet_platinum_bracelet",
      "volume": 0
    },
    {
      "id": "garnet_gold_pendant_necklace",
      "volume": 0
    },
    {
      "id": "garnet_silver_pendant_necklace",
      "volume": 0
    },
    {
      "id": "garnet_platinum_pendant_necklace",
      "volume": 0
    }
  ],
  "data/json/items/generic.json": [
    {
      "id": "delay_fuze",
      "volume": 0
    },
    {
      "id": "impact_fuze",
      "volume": 0
    }
  ],
  "data/json/items/melee/misc.json": [
    {
      "id": "bullwhip_razor",
      "volume": 9
    }
  ],
  "data/json/items/melee/swords_and_blades.json": [
    {
      "id": "machete_gimmick",
      "volume": 1
    }
  ],
  "data/json/items/tool/misc.json": [
    {
      "id": "tindalos_whistle",
      "volume": 0
    }
  ]
}

$ shopt -s globstar
$ jq '.[] | select(.weight? | type == "number") | {file:input_filename, id, weight}' data/json/items/**/*.json | jq --slurp 'reduce  .[] as $it ({}; .[$it.file] |= [.[]?, $it | {id, weight}])'
{
  "data/json/items/melee/swords_and_blades.json": [
    {
      "id": "bone_knife",
      "weight": 169
    },
    {
      "id": "machete_gimmick",
      "weight": 522
    }
  ]
}

hexagonrecursion commented 4 years ago

In bcb44892841232004069bc623dc14e86c41d9b28 the following narrow query for items with numbers in the top level keys "volume" and "weight" returns no results.

shopt -s globstar
jq '.[] | select(.volume, .weight| type == "number") | .id' data/json/items/**/*.json

The following query yields more suspect keys: EDIT: see my next comment for a more informative version

obsolete ``` shopt -s globstar MAP='.. | objects | to_entries | .[] | select(.key | (contains("weight")) or contains("volume")) | [.key, (.value | type)]' REDUCE='reduce .[] as [$k, $v] ({}; .[$k] |= ([.[]?, $v] | unique)) | to_entries | .[] | select(.value != ["string"])' jq "$MAP" data/json/**/*.json | jq --slurp "$REDUCE" ``` Especially suspicious are keys that have both numbers and strings as values. ``` { "key": "volume", "value": [ "number", "string" ] } { "key": "weight", "value": [ "number", "string" ] } { "key": "reload_noise_volume", "value": [ "number" ] } { "key": "integral_volume", "value": [ "number", "string" ] } { "key": "integral_weight", "value": [ "number", "string" ] } { "key": "weight_multiplier", "value": [ "number" ] } { "key": "sound_volume", "value": [ "number" ] } { "key": "max_weight", "value": [ "number" ] } { "key": "weighting", "value": [ "number" ] } { "key": "targeting_volume", "value": [ "number" ] } { "key": "weight_capacity_modifier", "value": [ "number" ] } { "key": "trigger_weight", "value": [ "number" ] } { "key": "folded_volume", "value": [ "number", "string" ] } ```
hexagonrecursion commented 4 years ago

The following should prove more informative than my previous attempt Edit: updated listing for 00fb404a589fc095ed179b186f253b2109b80148 Edit: fixed heuristic in the query Edit: better context info for use_action

Top Level Entries
["string",["material","burn_data","[]","volume_per_turn"]]
["string",["vehicle_part","folded_volume"]]
["string",["GUNMOD","integral_volume"]]
["string",["GUNMOD","integral_weight"]]
["string",["furniture","max_volume"]]
["string",["terrain","max_volume"]]
["string",["ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["ARMOR","pocket_data","[]","min_item_volume"]]
["string",["COMESTIBLE","pocket_data","[]","max_contains_volume"]]
["string",["COMESTIBLE","pocket_data","[]","max_contains_weight"]]
["string",["GENERIC","pocket_data","[]","max_contains_volume"]]
["string",["GENERIC","pocket_data","[]","max_contains_weight"]]
["string",["GENERIC","pocket_data","[]","max_item_volume"]]
["string",["GUN","pocket_data","[]","max_contains_volume"]]
["string",["GUN","pocket_data","[]","max_contains_weight"]]
["string",["GUNMOD","pocket_data","[]","max_contains_volume"]]
["string",["GUNMOD","pocket_data","[]","max_contains_weight"]]
["string",["PET_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["PET_ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["TOOL","pocket_data","[]","max_contains_volume"]]
["string",["TOOL","pocket_data","[]","max_contains_weight"]]
["string",["TOOL_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["TOOL_ARMOR","pocket_data","[]","max_contains_weight"]]
["number",["trap","trigger_weight"]]
["string",["AMMO","volume"]]
["string",["ARMOR","volume"]]
["string",["BATTERY","volume"]]
["string",["BIONIC_ITEM","volume"]]
["string",["BOOK","volume"]]
["string",["COMESTIBLE","volume"]]
["string",["ENGINE","volume"]]
["string",["GENERIC","volume"]]
["string",["GUN","volume"]]
["string",["GUNMOD","volume"]]
["string",["MAGAZINE","volume"]]
["string",["MONSTER","volume"]]
["string",["PET_ARMOR","volume"]]
["string",["TOOL","volume"]]
["string",["TOOLMOD","volume"]]
["string",["TOOL_ARMOR","volume"]]
["string",["WHEEL","volume"]]
["string",["AMMO","weight"]]
["string",["ARMOR","weight"]]
["string",["BATTERY","weight"]]
["string",["BIONIC_ITEM","weight"]]
["string",["BOOK","weight"]]
["string",["COMESTIBLE","weight"]]
["string",["ENGINE","weight"]]
["string",["GENERIC","weight"]]
["string",["GUN","weight"]]
["string",["GUNMOD","weight"]]
["string",["MAGAZINE","weight"]]
["string",["MONSTER","weight"]]
["string",["PET_ARMOR","weight"]]
["string",["TOOL","weight"]]
["string",["TOOLMOD","weight"]]
["string",["TOOL_ARMOR","weight"]]
["string",["WHEEL","weight"]]
["string",["bionic","weight_capacity_bonus"]]
["string",["furniture","workbench","volume"]]
["string",["vehicle_part","workbench","volume"]]
["number",["skill","companion_skill_practice","[]","weight"]]
["number",["overmap_terrain","mapgen","[]","weight"]]
["number",["AMMO","proportional","volume"]]
["number",["AMMO","proportional","weight"]]
["number",["ARMOR","proportional","volume"]]
["number",["ARMOR","proportional","weight"]]
["number",["COMESTIBLE","proportional","volume"]]
["number",["COMESTIBLE","proportional","weight"]]
["number",["GENERIC","proportional","volume"]]
["number",["GENERIC","proportional","weight"]]
["number",["GUN","proportional","volume"]]
["number",["GUN","proportional","weight"]]
["number",["TOOL","proportional","volume"]]
["number",["TOOL","proportional","weight"]]
["number",["BOOK","relative","weight"]]
["number",["GENERIC","relative","weight"]]
["number",["GUN","relative","volume"]]
["string",["GUN","relative","volume"]]
["number",["GUN","relative","weight"]]
["string",["TOOL","relative","volume"]]
["string",["TOOL","relative","weight"]]
["number",["WHEEL","relative","weight"]]
["number",["GUN","reload_noise_volume"]]
["number",["vehicle_spawn","spawn_types","[]","weight"]]
["number",["MONSTER","special_attacks","[]","targeting_volume"]]
["number",["trap","vehicle_data","sound_volume"]]
["number",["speech","volume"]]
["number",["mapgen","weight"]]
["number",["mutation","weight_capacity_modifier"]]
["number",["GUNMOD","weight_multiplier"]]
["number",["technique","weighting"]]
Use Actions
["string",["unpack","filthy_volume_threshold"]]
["number",["weigh_self","max_weight"]]
["number",["musical_instrument","volume"]]
["number",["explosion","sound_volume"]]

query:

#!/usr/bin/env bash
shopt -s globstar

# TODO
# magazine_well
# barrel_length
# max_pet_vol
# min_pet_vol

MAP='
.[] | {(.type): .}  # Example: {"BOOK": {"type": "BOOK", "id": "modern_tanner", ...}}

# Example: [["BOOK", "type"], "string"], [["BOOK", "id"], "string"]
# Indexing an array is represented as "[]"
| tostream | select(length == 2) | .[1] |= type | .[0] |= map(if type == "number" then "[]" else . end)

# Example: [["AMMO", "weight"], "string"], [["BOOK", "relative", "weight"], "number"]
| select(.[0][-1] | type == "string" and (contains("weight") or contains("volume")))
'

REDUCE='
# ( [1,2] | intersects([2,3]) ) == true
# ( [1,2] | intersects([3,4]) ) == false 
def intersects($other): any(.[] as $x | $other | .[] | . == $x; .);

unique
| map(reverse)  # Emphasize the type by putting it first

# Use a heuristic to sort the output to put the entries that are likely
# supposed to numbers after entries that are likely supposed to be strings
| ["proportional", "relative", "companion_skill_practice","mapgen",
   "spawn_types", "weight_capacity_modifier", "weight_multiplier", "weighting",
   "reload_noise_volume", "sound_volume", "speech", "targeting_volume"]
   as $heuristic
| sort_by([.[1] | intersects($heuristic), .[1]])

| .[]

# use_action is handled in a separate followup query
| select(.[1] | intersects(["use_action"]) | not)
'

echo "Top Level Entries"
jq "$MAP" data/json/**/*.json | jq --slurp --compact-output "$REDUCE"

MAP2='
.. | .use_action? | objects | {(.type): .}

# Indexing an array is represented as "[]"
| tostream | select(length == 2) | .[1] |= type | .[0] |= map(if type == "number" then "[]" else . end)

| select(.[0][-1] | type == "string" and (contains("weight") or contains("volume")))
'

echo "Use Actions"
jq "$MAP2" data/json/**/*.json | jq --slurp --compact-output "$REDUCE"
hexagonrecursion commented 4 years ago

How to interpret time ints? 100 = 1 second? Are there exceptions to this rule?

ymber commented 4 years ago

Time ints are interpreted differently in different objects. You'll have to check the loading code for what you're dealing with.

hexagonrecursion commented 4 years ago

I'm observing an odd effect. The trigger weight of a bear trap is 200. I am trying to figure out what this means in grams. I expected that just like everywhere else 200 = 200 grams, but I experimentally determined that in this case 200 = 500 grams: a canvas bag with 165 papers does not trigger the bear trap, but a canvas bag with 166 papers does. The odd thing is: I can't figure out why this is happening.

https://github.com/CleverRaven/Cataclysm-DDA/blob/adb3d75d64fb22e3af7d234274f8cb4b2ecb22da/data/json/traps.json#L141-L142

https://github.com/CleverRaven/Cataclysm-DDA/blob/438774d386c5dcde03ebabcb098a3a0cb57ff245/src/trap.cpp#L127

https://github.com/CleverRaven/Cataclysm-DDA/blob/438774d386c5dcde03ebabcb098a3a0cb57ff245/src/assign.h#L297

https://github.com/CleverRaven/Cataclysm-DDA/blob/438774d386c5dcde03ebabcb098a3a0cb57ff245/src/trap.cpp#L250-L253

hexagonrecursion commented 4 years ago

Figured it out https://github.com/CleverRaven/Cataclysm-DDA/blob/43eebbdfb5420c9e5838ec0351ab105ce773928d/src/ballistics.cpp#L133-L143

https://github.com/CleverRaven/Cataclysm-DDA/blob/c2b5b38ca7bd4acd658862bde2d5d508365b550b/src/ranged.cpp#L1015-L1017

hexagonrecursion commented 4 years ago

I updated my query again and ran it against 55df0e422b6d87b1f25d60185907ebe382e0a104 There are still some items remaining. Note that ["number",["use_action","weigh_self","max_weight"]] is already fixed by #41555

["string",["[]","AMMO","volume"]]
["string",["[]","AMMO","weight"]]
["string",["[]","ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","ARMOR","pocket_data","[]","min_item_volume"]]
["string",["[]","ARMOR","volume"]]
["string",["[]","ARMOR","weight"]]
["string",["[]","BATTERY","volume"]]
["string",["[]","BATTERY","weight"]]
["string",["[]","BIONIC_ITEM","volume"]]
["string",["[]","BIONIC_ITEM","weight"]]
["number",["[]","BOOK","relative","weight"]]
["string",["[]","BOOK","volume"]]
["string",["[]","BOOK","weight"]]
["string",["[]","COMESTIBLE","pocket_data","[]","max_contains_volume"]]
["string",["[]","COMESTIBLE","pocket_data","[]","max_contains_weight"]]
["string",["[]","COMESTIBLE","volume"]]
["string",["[]","COMESTIBLE","weight"]]
["string",["[]","ENGINE","volume"]]
["string",["[]","ENGINE","weight"]]
["string",["[]","GENERIC","pocket_data","[]","magazine_well"]]
["string",["[]","GENERIC","pocket_data","[]","max_contains_volume"]]
["string",["[]","GENERIC","pocket_data","[]","max_contains_weight"]]
["string",["[]","GENERIC","pocket_data","[]","max_item_volume"]]
["number",["[]","GENERIC","relative","weight"]]
["string",["[]","GENERIC","volume"]]
["string",["[]","GENERIC","weight"]]
["string",["[]","GUN","barrel_length"]]
["string",["[]","GUN","pocket_data","[]","max_contains_volume"]]
["string",["[]","GUN","pocket_data","[]","max_contains_weight"]]
["number",["[]","GUN","relative","barrel_length"]]
["number",["[]","GUN","relative","volume"]]
["string",["[]","GUN","relative","volume"]]
["number",["[]","GUN","relative","weight"]]
["string",["[]","GUN","volume"]]
["string",["[]","GUN","weight"]]
["string",["[]","GUNMOD","integral_volume"]]
["string",["[]","GUNMOD","integral_weight"]]
["string",["[]","GUNMOD","pocket_data","[]","max_contains_volume"]]
["string",["[]","GUNMOD","pocket_data","[]","max_contains_weight"]]
["string",["[]","GUNMOD","volume"]]
["string",["[]","GUNMOD","weight"]]
["string",["[]","MAGAZINE","volume"]]
["string",["[]","MAGAZINE","weight"]]
["string",["[]","MONSTER","volume"]]
["string",["[]","MONSTER","weight"]]
["string",["[]","PET_ARMOR","max_pet_vol"]]
["string",["[]","PET_ARMOR","min_pet_vol"]]
["string",["[]","PET_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","PET_ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","PET_ARMOR","volume"]]
["string",["[]","PET_ARMOR","weight"]]
["string",["[]","TOOL","pocket_data","[]","max_contains_volume"]]
["string",["[]","TOOL","pocket_data","[]","max_contains_weight"]]
["string",["[]","TOOL","relative","volume"]]
["string",["[]","TOOL","relative","weight"]]
["string",["[]","TOOL","volume"]]
["string",["[]","TOOL","weight"]]
["string",["[]","TOOLMOD","volume"]]
["string",["[]","TOOLMOD","weight"]]
["string",["[]","TOOL_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","TOOL_ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","TOOL_ARMOR","volume"]]
["string",["[]","TOOL_ARMOR","weight"]]
["number",["[]","WHEEL","relative","weight"]]
["string",["[]","WHEEL","volume"]]
["string",["[]","WHEEL","weight"]]
["string",["[]","bionic","weight_capacity_bonus"]]
["string",["[]","furniture","max_volume"]]
["string",["[]","furniture","workbench","volume"]]
["string",["[]","material","burn_data","[]","volume_per_turn"]]
["string",["[]","terrain","max_volume"]]
["number",["[]","trap","trigger_weight"]]
["number",["[]","vehicle_part","folded_volume"]]
["string",["[]","vehicle_part","folded_volume"]]
["string",["[]","vehicle_part","workbench","volume"]]
["string",["use_action","unpack","filthy_volume_threshold"]]
["number",["use_action","weigh_self","max_weight"]]
["number",["[]","AMMO","proportional","volume"]]
["number",["[]","AMMO","proportional","weight"]]
["number",["[]","ARMOR","proportional","volume"]]
["number",["[]","ARMOR","proportional","weight"]]
["number",["[]","COMESTIBLE","proportional","volume"]]
["number",["[]","COMESTIBLE","proportional","weight"]]
["number",["[]","GENERIC","proportional","volume"]]
["number",["[]","GENERIC","proportional","weight"]]
["number",["[]","GUN","proportional","volume"]]
["number",["[]","GUN","proportional","weight"]]
["number",["[]","GUN","reload_noise_volume"]]
["number",["[]","GUNMOD","weight_multiplier"]]
["number",["[]","MONSTER","special_attacks","[]","targeting_volume"]]
["number",["[]","TOOL","proportional","volume"]]
["number",["[]","TOOL","proportional","weight"]]
["number",["[]","mapgen","weight"]]
["number",["[]","mutation","weight_capacity_modifier"]]
["number",["[]","overmap_terrain","mapgen","[]","weight"]]
["number",["[]","skill","companion_skill_practice","[]","weight"]]
["number",["[]","speech","volume"]]
["number",["[]","technique","weighting"]]
["number",["[]","trap","vehicle_data","sound_volume"]]
["number",["[]","vehicle_spawn","spawn_types","[]","weight"]]
["number",["use_action","explosion","sound_volume"]]
["number",["use_action","musical_instrument","volume"]]

query:

#!/usr/bin/env bash
shopt -s globstar

JQ='
# ( [1,2] | intersects([2,3]) ) == true
# ( [1,2] | intersects([3,4]) ) == false 
def intersects($other): any(.[] as $x | $other | .[] | . == $x; .);

[
    # For each top level entry
    ., inputs | .[]

    # Examples
    # {"[]":{"id":"achievement_kill_zombie","type":"achievement",...}}
    # {"use_action":{"type":"holster",...}}
    | {"[]": .}, (.. | .use_action? | objects | {use_action: .}) 

    # Examples
    # {"[]":{"achievement":{"id":"achievement_kill_zombie","type":"achievement",...}}}
    # {"use_action":{"holster":{"type":"holster","holster_prompt":"Stash ammo",...}}}
    | map_values({(.type): .})

    # Examples
    # [["[]","achievement","id"],"achievement_kill_zombie"]
    # [["use_action","holster","holster_prompt"],"Stash ammo"]
    | tostream | select(length == 2)

    # Examples
    # ["string",["[]","achievement","id"]]
    # ["string",["use_action","holster","holster_prompt"]]
    | [(.[1] | type), (.[0] | map(if type == "number" then "[]" else . end))]

    # Examples
    # ["string",["[]","furniture","max_volume"]]
    # ["string",["use_action","unpack","filthy_volume_threshold"]]
    | ["weight", "volume", "_pet_vol", "barrel_length", "magazine_well"] as $needle
    | select(.[1] | any(($needle | .[]) as $n | contains([$n]); .))
]

| unique

# Use a heuristic to sort the output to put the entries that are likely
# supposed to numbers after entries that are likely supposed to be strings
| ["proportional", "companion_skill_practice","mapgen", "spawn_types",
   "weight_capacity_modifier", "weight_multiplier", "weighting",
   "reload_noise_volume", "sound_volume", "speech", "targeting_volume",
   "musical_instrument"] as $heuristic
| sort_by([.[1] | intersects($heuristic), .])

| .[]

# Exclude use_action entries since they are handled separately
| select(.[1][1:] | intersects(["use_action"]) | not)
'

jq --compact-output "$JQ" data/json/**/*.json
anothersimulacrum commented 4 years ago

Thanks for working on this, @hexagonrecursion !

hexagonrecursion commented 4 years ago

Which style is preferred?

"name": { "str": "backpack" }

or

"name": { "str": "backpack", "str_pl": "backpacks" },

If I'm reading the below code right, the above styles produce identical results. https://github.com/CleverRaven/Cataclysm-DDA/blob/000ecc66aad982cb492123fd21ffcfcd15408cef/src/translations.cpp#L500-L504

anothersimulacrum commented 4 years ago

The first one.

hexagonrecursion commented 4 years ago

data/json wins the 2020 code obfuscation prize in the "the most confusing directory name" category for successfully tricking me into assuming that all json game data is in that directory.

hexagonrecursion commented 4 years ago

Every time I think I'm done I start looking for more places where numeric weights and volumes could be lurking and find more. Now the script searches the entire data directory instead of just data/json.

["number",["[]","AMMO","volume"]]
["string",["[]","AMMO","volume"]]
["number",["[]","AMMO","weight"]]
["string",["[]","AMMO","weight"]]
["string",["[]","ARMOR","pocket_data","[]","magazine_well"]]
["string",["[]","ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","ARMOR","pocket_data","[]","max_item_volume"]]
["string",["[]","ARMOR","pocket_data","[]","min_item_volume"]]
["number",["[]","ARMOR","volume"]]
["string",["[]","ARMOR","volume"]]
["number",["[]","ARMOR","weight"]]
["string",["[]","ARMOR","weight"]]
["string",["[]","BATTERY","volume"]]
["string",["[]","BATTERY","weight"]]
["string",["[]","BIONIC_ITEM","volume"]]
["string",["[]","BIONIC_ITEM","weight"]]
["string",["[]","BOOK","relative","weight"]]
["string",["[]","BOOK","volume"]]
["string",["[]","BOOK","weight"]]
["string",["[]","COMESTIBLE","pocket_data","[]","max_contains_volume"]]
["string",["[]","COMESTIBLE","pocket_data","[]","max_contains_weight"]]
["number",["[]","COMESTIBLE","volume"]]
["string",["[]","COMESTIBLE","volume"]]
["number",["[]","COMESTIBLE","weight"]]
["string",["[]","COMESTIBLE","weight"]]
["number",["[]","CONTAINER","volume"]]
["number",["[]","CONTAINER","weight"]]
["string",["[]","ENGINE","volume"]]
["string",["[]","ENGINE","weight"]]
["string",["[]","GENERIC","pocket_data","[]","magazine_well"]]
["string",["[]","GENERIC","pocket_data","[]","max_contains_volume"]]
["string",["[]","GENERIC","pocket_data","[]","max_contains_weight"]]
["string",["[]","GENERIC","pocket_data","[]","max_item_volume"]]
["string",["[]","GENERIC","relative","weight"]]
["number",["[]","GENERIC","volume"]]
["string",["[]","GENERIC","volume"]]
["number",["[]","GENERIC","weight"]]
["string",["[]","GENERIC","weight"]]
["number",["[]","GUN","barrel_length"]]
["string",["[]","GUN","barrel_length"]]
["string",["[]","GUN","pocket_data","[]","magazine_well"]]
["string",["[]","GUN","pocket_data","[]","max_contains_volume"]]
["string",["[]","GUN","pocket_data","[]","max_contains_weight"]]
["string",["[]","GUN","relative","barrel_length"]]
["string",["[]","GUN","relative","volume"]]
["string",["[]","GUN","relative","weight"]]
["number",["[]","GUN","volume"]]
["string",["[]","GUN","volume"]]
["number",["[]","GUN","weight"]]
["string",["[]","GUN","weight"]]
["number",["[]","GUNMOD","integral_volume"]]
["string",["[]","GUNMOD","integral_volume"]]
["string",["[]","GUNMOD","integral_weight"]]
["string",["[]","GUNMOD","pocket_data","[]","max_contains_volume"]]
["string",["[]","GUNMOD","pocket_data","[]","max_contains_weight"]]
["number",["[]","GUNMOD","volume"]]
["string",["[]","GUNMOD","volume"]]
["number",["[]","GUNMOD","weight"]]
["string",["[]","GUNMOD","weight"]]
["number",["[]","MAGAZINE","volume"]]
["string",["[]","MAGAZINE","volume"]]
["string",["[]","MAGAZINE","weight"]]
["string",["[]","MONSTER","volume"]]
["number",["[]","MONSTER","weight"]]
["string",["[]","MONSTER","weight"]]
["string",["[]","PET_ARMOR","max_pet_vol"]]
["string",["[]","PET_ARMOR","min_pet_vol"]]
["string",["[]","PET_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","PET_ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","PET_ARMOR","volume"]]
["string",["[]","PET_ARMOR","weight"]]
["string",["[]","TOOL","pocket_data","[]","magazine_well"]]
["string",["[]","TOOL","pocket_data","[]","max_contains_volume"]]
["string",["[]","TOOL","pocket_data","[]","max_contains_weight"]]
["string",["[]","TOOL","relative","volume"]]
["string",["[]","TOOL","relative","weight"]]
["number",["[]","TOOL","volume"]]
["string",["[]","TOOL","volume"]]
["number",["[]","TOOL","weight"]]
["string",["[]","TOOL","weight"]]
["string",["[]","TOOLMOD","volume"]]
["string",["[]","TOOLMOD","weight"]]
["string",["[]","TOOL_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","TOOL_ARMOR","pocket_data","[]","max_contains_weight"]]
["number",["[]","TOOL_ARMOR","volume"]]
["string",["[]","TOOL_ARMOR","volume"]]
["string",["[]","TOOL_ARMOR","weight"]]
["string",["[]","TOOL_ARMOR","weight_capacity_bonus"]]
["string",["[]","WHEEL","relative","weight"]]
["string",["[]","WHEEL","volume"]]
["string",["[]","WHEEL","weight"]]
["string",["[]","bionic","weight_capacity_bonus"]]
["string",["[]","furniture","max_volume"]]
["string",["[]","furniture","workbench","volume"]]
["string",["[]","material","burn_data","[]","volume_per_turn"]]
["string",["[]","terrain","max_volume"]]
["string",["[]","trap","trigger_weight"]]
["string",["[]","vehicle_part","folded_volume"]]
["string",["[]","vehicle_part","workbench","volume"]]
["string",["use_action","unpack","filthy_volume_threshold"]]
["string",["use_action","weigh_self","max_weight"]]
["number",["[]","AMMO","proportional","volume"]]
["number",["[]","AMMO","proportional","weight"]]
["number",["[]","ARMOR","pocket_data","[]","weight_multiplier"]]
["number",["[]","ARMOR","proportional","volume"]]
["number",["[]","ARMOR","proportional","weight"]]
["number",["[]","COMESTIBLE","proportional","volume"]]
["number",["[]","COMESTIBLE","proportional","weight"]]
["number",["[]","GENERIC","pocket_data","[]","volume_multiplier"]]
["number",["[]","GENERIC","pocket_data","[]","weight_multiplier"]]
["number",["[]","GENERIC","proportional","volume"]]
["number",["[]","GENERIC","proportional","weight"]]
["number",["[]","GUN","proportional","volume"]]
["number",["[]","GUN","proportional","weight"]]
["number",["[]","GUN","reload_noise_volume"]]
["number",["[]","GUNMOD","weight_multiplier"]]
["number",["[]","MONSTER","special_attacks","[]","targeting_volume"]]
["number",["[]","TOOL","proportional","volume"]]
["number",["[]","TOOL","proportional","weight"]]
["number",["[]","TOOL_ARMOR","pocket_data","[]","volume_multiplier"]]
["number",["[]","TOOL_ARMOR","pocket_data","[]","weight_multiplier"]]
["number",["[]","mapgen","weight"]]
["number",["[]","mutation","weight_capacity_modifier"]]
["number",["[]","overmap_terrain","mapgen","[]","weight"]]
["number",["[]","skill","companion_skill_practice","[]","weight"]]
["number",["[]","sound_effect","volume"]]
["number",["[]","speech","volume"]]
["number",["[]","technique","weighting"]]
["number",["[]","trap","vehicle_data","sound_volume"]]
["number",["[]","vehicle_spawn","spawn_types","[]","weight"]]
["number",["use_action","explosion","sound_volume"]]
["number",["use_action","musical_instrument","volume"]]

The query:

#!/usr/bin/env bash

mapfile -t < <(
    find utilities data \
        -name '*.json' \
        -not -path 'data/raw/color_templates/no_bright_background.json' \
        -not -path 'data/names/*' \
        -not -path 'data/mods/replacements.json' \
        -not -path 'data/fontdata.json' \
)

JQ='
# ( [1,2] | intersects([2,3]) ) == true
# ( [1,2] | intersects([3,4]) ) == false 
def intersects($other): any(.[] as $x | $other | .[] | . == $x; .);

[
    # For each top level entry
    ., inputs | .[]

    # Examples
    # {"[]":{"id":"achievement_kill_zombie","type":"achievement",...}}
    # {"use_action":{"type":"holster",...}}
    | {"[]": .}, (.. | .use_action? | objects | {use_action: .}) 

    # Examples
    # {"[]":{"achievement":{"id":"achievement_kill_zombie","type":"achievement",...}}}
    # {"use_action":{"holster":{"type":"holster","holster_prompt":"Stash ammo",...}}}
    | map_values({(.type): .})

    # Examples
    # [["[]","achievement","id"],"achievement_kill_zombie"]
    # [["use_action","holster","holster_prompt"],"Stash ammo"]
    | tostream | select(length == 2)

    # Examples
    # ["string",["[]","achievement","id"]]
    # ["string",["use_action","holster","holster_prompt"]]
    | [(.[1] | type), (.[0] | map(if type == "number" then "[]" else . end))]

    # Examples
    # ["string",["[]","furniture","max_volume"]]
    # ["string",["use_action","unpack","filthy_volume_threshold"]]
    | ["weight", "volume", "_pet_vol", "barrel_length", "magazine_well"] as $needle
    | select(.[1] | any(($needle | .[]) as $n | contains([$n]); .))
]

| unique

# Use a heuristic to sort the output to put the entries that are likely
# supposed to numbers after entries that are likely supposed to be strings
| ["proportional", "companion_skill_practice","mapgen", "spawn_types",
   "weight_capacity_modifier", "weight_multiplier", "volume_multiplier",
   "weighting", "sound_effect", "reload_noise_volume", "sound_volume",
   "speech", "targeting_volume", "musical_instrument"] as $heuristic
| sort_by([.[1] | intersects($heuristic), .])

| .[]

# Exclude use_action entries since they are handled separately
| select(.[1][1:] | intersects(["use_action"]) | not)
'

jq --compact-output "$JQ" "${MAPFILE[@]}"
hexagonrecursion commented 4 years ago

Updating for 75af9416f9d1eb6ac4874763cc86ff0e074de43b

["string",["[]","AMMO","volume"]]
["string",["[]","AMMO","weight"]]
["string",["[]","ARMOR","pocket_data","[]","magazine_well"]]
["string",["[]","ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","ARMOR","pocket_data","[]","max_item_volume"]]
["string",["[]","ARMOR","pocket_data","[]","min_item_volume"]]
["string",["[]","ARMOR","volume"]]
["string",["[]","ARMOR","weight"]]
["string",["[]","BATTERY","volume"]]
["string",["[]","BATTERY","weight"]]
["string",["[]","BIONIC_ITEM","volume"]]
["string",["[]","BIONIC_ITEM","weight"]]
["string",["[]","BOOK","relative","weight"]]
["string",["[]","BOOK","volume"]]
["string",["[]","BOOK","weight"]]
["string",["[]","COMESTIBLE","pocket_data","[]","max_contains_volume"]]
["string",["[]","COMESTIBLE","pocket_data","[]","max_contains_weight"]]
["string",["[]","COMESTIBLE","volume"]]
["string",["[]","COMESTIBLE","weight"]]
["string",["[]","CONTAINER","volume"]]
["string",["[]","CONTAINER","weight"]]
["string",["[]","ENGINE","volume"]]
["string",["[]","ENGINE","weight"]]
["string",["[]","GENERIC","pocket_data","[]","magazine_well"]]
["string",["[]","GENERIC","pocket_data","[]","max_contains_volume"]]
["string",["[]","GENERIC","pocket_data","[]","max_contains_weight"]]
["string",["[]","GENERIC","pocket_data","[]","max_item_volume"]]
["string",["[]","GENERIC","relative","weight"]]
["string",["[]","GENERIC","volume"]]
["string",["[]","GENERIC","weight"]]
["number",["[]","GUN","barrel_length"]]
["string",["[]","GUN","barrel_length"]]
["string",["[]","GUN","pocket_data","[]","magazine_well"]]
["string",["[]","GUN","pocket_data","[]","max_contains_volume"]]
["string",["[]","GUN","pocket_data","[]","max_contains_weight"]]
["string",["[]","GUN","relative","barrel_length"]]
["string",["[]","GUN","relative","volume"]]
["string",["[]","GUN","relative","weight"]]
["string",["[]","GUN","volume"]]
["string",["[]","GUN","weight"]]
["number",["[]","GUNMOD","integral_volume"]]
["string",["[]","GUNMOD","integral_volume"]]
["string",["[]","GUNMOD","integral_weight"]]
["string",["[]","GUNMOD","pocket_data","[]","max_contains_volume"]]
["string",["[]","GUNMOD","pocket_data","[]","max_contains_weight"]]
["string",["[]","GUNMOD","volume"]]
["string",["[]","GUNMOD","weight"]]
["string",["[]","MAGAZINE","volume"]]
["string",["[]","MAGAZINE","weight"]]
["string",["[]","MONSTER","volume"]]
["string",["[]","MONSTER","weight"]]
["string",["[]","PET_ARMOR","max_pet_vol"]]
["string",["[]","PET_ARMOR","min_pet_vol"]]
["string",["[]","PET_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","PET_ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","PET_ARMOR","volume"]]
["string",["[]","PET_ARMOR","weight"]]
["string",["[]","TOOL","pocket_data","[]","magazine_well"]]
["string",["[]","TOOL","pocket_data","[]","max_contains_volume"]]
["string",["[]","TOOL","pocket_data","[]","max_contains_weight"]]
["string",["[]","TOOL","relative","volume"]]
["string",["[]","TOOL","relative","weight"]]
["string",["[]","TOOL","volume"]]
["string",["[]","TOOL","weight"]]
["string",["[]","TOOLMOD","volume"]]
["string",["[]","TOOLMOD","weight"]]
["string",["[]","TOOL_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","TOOL_ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","TOOL_ARMOR","volume"]]
["string",["[]","TOOL_ARMOR","weight"]]
["string",["[]","TOOL_ARMOR","weight_capacity_bonus"]]
["string",["[]","WHEEL","relative","weight"]]
["string",["[]","WHEEL","volume"]]
["string",["[]","WHEEL","weight"]]
["string",["[]","bionic","weight_capacity_bonus"]]
["string",["[]","furniture","max_volume"]]
["string",["[]","furniture","workbench","volume"]]
["string",["[]","material","burn_data","[]","volume_per_turn"]]
["string",["[]","terrain","max_volume"]]
["string",["[]","trap","trigger_weight"]]
["string",["[]","vehicle_part","folded_volume"]]
["string",["[]","vehicle_part","workbench","volume"]]
["string",["use_action","unpack","filthy_volume_threshold"]]
["string",["use_action","weigh_self","max_weight"]]
["number",["[]","AMMO","proportional","volume"]]
["number",["[]","AMMO","proportional","weight"]]
["number",["[]","ARMOR","pocket_data","[]","weight_multiplier"]]
["number",["[]","ARMOR","proportional","volume"]]
["number",["[]","ARMOR","proportional","weight"]]
["number",["[]","COMESTIBLE","proportional","volume"]]
["number",["[]","COMESTIBLE","proportional","weight"]]
["number",["[]","GENERIC","pocket_data","[]","volume_multiplier"]]
["number",["[]","GENERIC","pocket_data","[]","weight_multiplier"]]
["number",["[]","GENERIC","proportional","volume"]]
["number",["[]","GENERIC","proportional","weight"]]
["number",["[]","GUN","proportional","volume"]]
["number",["[]","GUN","proportional","weight"]]
["number",["[]","GUN","reload_noise_volume"]]
["number",["[]","GUNMOD","weight_multiplier"]]
["number",["[]","MONSTER","special_attacks","[]","targeting_volume"]]
["number",["[]","TOOL","proportional","volume"]]
["number",["[]","TOOL","proportional","weight"]]
["number",["[]","TOOL_ARMOR","pocket_data","[]","volume_multiplier"]]
["number",["[]","TOOL_ARMOR","pocket_data","[]","weight_multiplier"]]
["number",["[]","mapgen","weight"]]
["number",["[]","mutation","weight_capacity_modifier"]]
["number",["[]","overmap_terrain","mapgen","[]","weight"]]
["number",["[]","skill","companion_skill_practice","[]","weight"]]
["number",["[]","sound_effect","volume"]]
["number",["[]","speech","volume"]]
["number",["[]","technique","weighting"]]
["number",["[]","trap","vehicle_data","sound_volume"]]
["number",["[]","vehicle_spawn","spawn_types","[]","weight"]]
["number",["use_action","explosion","sound_volume"]]
["number",["use_action","musical_instrument","volume"]]
hexagonrecursion commented 4 years ago

Update for 6e2952812428448c6cb119656fb9cc686c4a5fdb

["string",["[]","AMMO","volume"]]
["string",["[]","AMMO","weight"]]
["string",["[]","ARMOR","pocket_data","[]","magazine_well"]]
["string",["[]","ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","ARMOR","pocket_data","[]","max_item_volume"]]
["string",["[]","ARMOR","pocket_data","[]","min_item_volume"]]
["string",["[]","ARMOR","volume"]]
["string",["[]","ARMOR","weight"]]
["string",["[]","BATTERY","volume"]]
["string",["[]","BATTERY","weight"]]
["string",["[]","BIONIC_ITEM","volume"]]
["string",["[]","BIONIC_ITEM","weight"]]
["string",["[]","BOOK","relative","weight"]]
["string",["[]","BOOK","volume"]]
["string",["[]","BOOK","weight"]]
["string",["[]","COMESTIBLE","pocket_data","[]","max_contains_volume"]]
["string",["[]","COMESTIBLE","pocket_data","[]","max_contains_weight"]]
["string",["[]","COMESTIBLE","volume"]]
["string",["[]","COMESTIBLE","weight"]]
["string",["[]","CONTAINER","volume"]]
["string",["[]","CONTAINER","weight"]]
["string",["[]","ENGINE","volume"]]
["string",["[]","ENGINE","weight"]]
["string",["[]","GENERIC","pocket_data","[]","magazine_well"]]
["string",["[]","GENERIC","pocket_data","[]","max_contains_volume"]]
["string",["[]","GENERIC","pocket_data","[]","max_contains_weight"]]
["string",["[]","GENERIC","pocket_data","[]","max_item_volume"]]
["string",["[]","GENERIC","relative","weight"]]
["string",["[]","GENERIC","volume"]]
["string",["[]","GENERIC","weight"]]
["string",["[]","GUN","barrel_volume"]]
["string",["[]","GUN","pocket_data","[]","magazine_well"]]
["string",["[]","GUN","pocket_data","[]","max_contains_volume"]]
["string",["[]","GUN","pocket_data","[]","max_contains_weight"]]
["string",["[]","GUN","relative","barrel_volume"]]
["string",["[]","GUN","relative","volume"]]
["string",["[]","GUN","relative","weight"]]
["string",["[]","GUN","volume"]]
["string",["[]","GUN","weight"]]
["string",["[]","GUNMOD","integral_volume"]]
["string",["[]","GUNMOD","integral_weight"]]
["string",["[]","GUNMOD","pocket_data","[]","max_contains_volume"]]
["string",["[]","GUNMOD","pocket_data","[]","max_contains_weight"]]
["string",["[]","GUNMOD","volume"]]
["string",["[]","GUNMOD","weight"]]
["string",["[]","MAGAZINE","volume"]]
["string",["[]","MAGAZINE","weight"]]
["string",["[]","MONSTER","volume"]]
["string",["[]","MONSTER","weight"]]
["string",["[]","PET_ARMOR","max_pet_vol"]]
["string",["[]","PET_ARMOR","min_pet_vol"]]
["string",["[]","PET_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","PET_ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","PET_ARMOR","volume"]]
["string",["[]","PET_ARMOR","weight"]]
["string",["[]","TOOL","pocket_data","[]","magazine_well"]]
["string",["[]","TOOL","pocket_data","[]","max_contains_volume"]]
["string",["[]","TOOL","pocket_data","[]","max_contains_weight"]]
["string",["[]","TOOL","relative","volume"]]
["string",["[]","TOOL","relative","weight"]]
["string",["[]","TOOL","volume"]]
["string",["[]","TOOL","weight"]]
["string",["[]","TOOLMOD","pocket_mods","[]","max_contains_volume"]]
["string",["[]","TOOLMOD","pocket_mods","[]","max_contains_weight"]]
["string",["[]","TOOLMOD","volume"]]
["string",["[]","TOOLMOD","weight"]]
["string",["[]","TOOL_ARMOR","pocket_data","[]","max_contains_volume"]]
["string",["[]","TOOL_ARMOR","pocket_data","[]","max_contains_weight"]]
["string",["[]","TOOL_ARMOR","volume"]]
["string",["[]","TOOL_ARMOR","weight"]]
["string",["[]","TOOL_ARMOR","weight_capacity_bonus"]]
["string",["[]","WHEEL","relative","weight"]]
["string",["[]","WHEEL","volume"]]
["string",["[]","WHEEL","weight"]]
["string",["[]","bionic","weight_capacity_bonus"]]
["string",["[]","furniture","max_volume"]]
["string",["[]","furniture","workbench","volume"]]
["string",["[]","material","burn_data","[]","volume_per_turn"]]
["number",["[]","relic_procgen_data","items","[]","weight"]]
["number",["[]","relic_procgen_data","passive_add_procgen_values","[]","weight"]]
["string",["[]","relic_procgen_data","type_weights","[]","value"]]
["number",["[]","relic_procgen_data","type_weights","[]","weight"]]
["string",["[]","terrain","max_volume"]]
["string",["[]","trap","trigger_weight"]]
["number",["[]","vehicle_part","folded_volume"]]
["string",["[]","vehicle_part","folded_volume"]]
["string",["[]","vehicle_part","workbench","volume"]]
["string",["use_action","unpack","filthy_volume_threshold"]]
["string",["use_action","weigh_self","max_weight"]]
["number",["[]","AMMO","proportional","volume"]]
["number",["[]","AMMO","proportional","weight"]]
["number",["[]","ARMOR","pocket_data","[]","weight_multiplier"]]
["number",["[]","ARMOR","proportional","volume"]]
["number",["[]","ARMOR","proportional","weight"]]
["number",["[]","COMESTIBLE","proportional","volume"]]
["number",["[]","COMESTIBLE","proportional","weight"]]
["number",["[]","GENERIC","pocket_data","[]","volume_multiplier"]]
["number",["[]","GENERIC","pocket_data","[]","weight_multiplier"]]
["number",["[]","GENERIC","proportional","volume"]]
["number",["[]","GENERIC","proportional","weight"]]
["number",["[]","GUN","proportional","volume"]]
["number",["[]","GUN","proportional","weight"]]
["number",["[]","GUN","reload_noise_volume"]]
["number",["[]","GUNMOD","weight_multiplier"]]
["number",["[]","MONSTER","special_attacks","[]","targeting_volume"]]
["number",["[]","TOOL","proportional","volume"]]
["number",["[]","TOOL","proportional","weight"]]
["number",["[]","TOOL_ARMOR","pocket_data","[]","volume_multiplier"]]
["number",["[]","TOOL_ARMOR","pocket_data","[]","weight_multiplier"]]
["number",["[]","mapgen","weight"]]
["number",["[]","mutation","weight_capacity_modifier"]]
["number",["[]","overmap_terrain","mapgen","[]","weight"]]
["number",["[]","skill","companion_skill_practice","[]","weight"]]
["number",["[]","sound_effect","volume"]]
["number",["[]","speech","volume"]]
["number",["[]","technique","weighting"]]
["number",["[]","trap","vehicle_data","sound_volume"]]
["number",["[]","vehicle_spawn","spawn_types","[]","weight"]]
["number",["use_action","explosion","sound_volume"]]
["number",["use_action","musical_instrument","volume"]]

At the very least vehicle_part.folded_volume should definitely be a string. Have not looked into relic_procgen_data yet.

UmbralReaper commented 3 years ago

@hexagonrecursion could you run your script(s) on Goats Mod Compilation? I would love to finally remove obsolete json but I use windows and don't have enough experience using either cygwin or jq to make it work for me.

Maleclypse commented 3 years ago

@hexagonrecursion It looks like your PR mean we can mark completed volume and weight up at the top. Is that correct?

Maleclypse commented 3 years ago

I've marked name and burst as complete. Please let me know if that's premature.

Maleclypse commented 2 years ago

I've marked volume and weight as complete because when I looked through I couldn't find any integer uses in items.