Container whitelisting tool

So I recently went through the arduous task of organising my powder storage(!) using 60 small cardboard boxes, only to discover that the “+” sign many of them had meant something else was whitelisted to go inside them. Although it didn’t prevent me from [i]nserting what I wanted to store this kind of annoyed me; it’s not perfect until it’s perfect. But I’ll be damned if I’m going to go through and change each one manually, that would be a mind-numbingly tedious job. So I started poking around the save files and managed to come up with this bit of Python:

with open('/path/to/cataclysmdda-0.H/save/Apalachin/maps/12.7.0/385.251.0.map', 'r') as file:
  data = json.load(file)

item_type = "box_small"

for i in data:
  if "items" in i:
    for items in i["items"]:
      if isinstance(items, list):
        for item in items:
          if isinstance(item, list):
            item = item[0]
          if item["typeid"] == item_type:
            pocket = item["contents"]["contents"][0]
            contents = pocket["contents"][0]["typeid"]
            whitelist = pocket["favorite_settings"]["item_whitelist"]
            if len(whitelist) > 0:
              whitelist = whitelist[0]
              if whitelist != contents:
                print(f"box with {contents} doesn't match whitelist {whitelist}")
              else:
                print(f"box with {contents} matches whitelist {whitelist}")
            else:
              print(f"box with {contents} has no whitelist")

For now it just prints out whether the contents matches the whitelist or not, but I imagine this could be made to modify the whitelist and saving the edited data without too much trouble. Interesting to anyone?

A few caveats: you need to find which map file your containers are in first; if it’s your base and it’s similarly full of stuff to mine it will likely be the largest file by a good margin (mine’s almost 4 Mb, while all the others are less than a couple hundred kb each). The code assumes the container only has a single pocket (pocket = item["contents"]["contents"][0]) and that only one type of item is stored within (pocket["contents"][0]). Sample output from my base:

$ python parse.py 
box with yeast has no whitelist
box with sugar doesn't match whitelist cornmeal
box with seasoning_salt has no whitelist
box with protein_powder has no whitelist
box with milk_powder has no whitelist
box with powder_eggs has no whitelist
box with garlic_powder doesn't match whitelist bag_plastic
box with curry_powder doesn't match whitelist sugar
box with coffee_raw doesn't match whitelist macaroni_raw
box with cinnamon doesn't match whitelist toastem
box with chilly-p doesn't match whitelist toastem
box with pepper doesn't match whitelist sugar
box with salt doesn't match whitelist chem_washing_soda
box with seasoning_italian doesn't match whitelist detergent
box with chem_baking_soda has no whitelist
box with bag_plastic matches whitelist bag_plastic
box with detergent matches whitelist detergent
box with chem_washing_soda doesn't match whitelist detergent
box with chem_baking_soda matches whitelist chem_baking_soda
box with chem_agar has no whitelist
box with chem_carbide doesn't match whitelist charcoal
box with chem_zinc_powder doesn't match whitelist detergent
box with chem_potassium_chloride doesn't match whitelist chem_washing_soda
box with chem_baking_soda doesn't match whitelist charcoal
box with chem_washing_soda doesn't match whitelist detergent
box with chem_washing_soda matches whitelist chem_washing_soda
box with chem_washing_soda matches whitelist chem_washing_soda
box with chem_washing_soda doesn't match whitelist detergent
box with chem_washing_soda doesn't match whitelist detergent
box with chem_washing_soda doesn't match whitelist detergent
box with detergent matches whitelist detergent
box with detergent matches whitelist detergent
box with salt has no whitelist
box with pepper doesn't match whitelist cornmeal
box with pepper doesn't match whitelist cornmeal
box with chilly-p doesn't match whitelist sugar
box with cinnamon doesn't match whitelist sugar
box with seasoning_italian has no whitelist
box with seasoning_salt has no whitelist
box with sugar has no whitelist
box with salt has no whitelist
box with salt has no whitelist
box with salt has no whitelist
box with milk_powder has no whitelist
box with pepper doesn't match whitelist detergent
box with seasoning_italian has no whitelist
box with curry_powder has no whitelist
box with cinnamon doesn't match whitelist macaroni_raw
box with chilly-p doesn't match whitelist sugar
box with sugar has no whitelist
box with salt doesn't match whitelist detergent
box with salt has no whitelist
box with salt doesn't match whitelist detergent
box with salt doesn't match whitelist detergent
box with salt doesn't match whitelist detergent
box with salt doesn't match whitelist detergent
box with salt doesn't match whitelist detergent
box with salt doesn't match whitelist chem_washing_soda
box with salt doesn't match whitelist chem_washing_soda
box with salt doesn't match whitelist chem_washing_soda

The idea is that the script could change the whitelist to match the content, as if you had found the boxes unopened with their content already in them. I like the idea of having just one box of each powder to hand, and storing the other, completely full, boxes in my warehouse. Run out of salt? Go fetch a new box. If the number of full unopened boxes of some important ingredient is running low on the shelf, I’ll remember to gather some more of that resource on my next excursion. It helps that a small cardboard box has a volume/weight capacity that is easily filled, yet holds enough for a fair amount of crafting.

Having made sure I had a backup of the map file in question, I ran the following Python script to update the JSON and whitelist all small cardboard boxes for what’s actually in them:


#!/usr/bin/env python3

import json

filename = "/path/to/cataclysmdda-0.H/save/Apalachin/maps/12.7.0/385.251.0.map"
item_type = "box_small"

with open(filename, "r") as file:
  data = json.load(file)

for i in data:
  if "items" in i:
    for items in i["items"]:
      if isinstance(items, list):
        for item in items:
          if isinstance(item, list):
            item = item[0]
          if item["typeid"] == item_type:
            pocket = item["contents"]["contents"][0]
            contents = pocket["contents"][0]["typeid"]
            whitelist = pocket["favorite_settings"]["item_whitelist"]
            if len(whitelist) > 0:
              whitelist = whitelist[0]
              if whitelist != contents:
                print(f"box with {contents} doesn't match whitelist {whitelist}")
              else:
                print(f"box with {contents} matches whitelist {whitelist}")
            else:
              print(f"box with {contents} has no whitelist")
            # set the first pocket's whitelist to its contents: 
            pocket["favorite_settings"]["item_whitelist"] = [contents]

# write the JSON back to the map file: 
json.dump(data, open(filename, "w"))

Honestly, I fully expected to end up with a broken save, but was pleasantly surprised to find it worked perfectly, and all my small cardboard boxes are now whitelisted for their content:

Edit: It seems something prevents this from working properly if you have any of the containers in your inventory - make sure to drop all of them and save before running the script.

Updated script with a few extra checks:

#!/usr/bin/env python3

import json

filename = "/path/to/cataclysmdda-0.H/save/Apalachin/maps/12.7.0/385.251.0.map"
item_type = "jar_glass_sealed"
counters = {}
containers = 0

with open(filename, "r") as file:
  data = json.load(file)

for i in data:
  if "items" in i:
    for items in i["items"]:
      if isinstance(items, list):
        for item in items:
          if isinstance(item, list):
            item = item[0]
          if item["typeid"] == item_type:
            containers += 1
            pocket = item["contents"]["contents"][0]
            if pocket["contents"]:
              contents = pocket["contents"][0]["typeid"]
              whitelist = pocket["favorite_settings"]["item_whitelist"]
              if contents in counters:
                counters[contents] += 1
              else:
                counters[contents] = 1
              if len(whitelist) > 0:
                whitelist = whitelist[0]
                if whitelist != contents:
                  print(f"{item_type} with {contents} doesn't match whitelist {whitelist}")
                  pocket["favorite_settings"]["item_whitelist"] = [contents]
                else:
                  print(f"{item_type} with {contents} matches whitelist {whitelist}")
              else:
                print(f"{item_type} with {contents} has no whitelist")
                pocket["favorite_settings"]["item_whitelist"] = [contents]

json.dump(data, open(filename, "w"))
print(containers)
print(counters)