wynnbuilder-forked-for-changes/py_script/v3_process_items.py
hppeng f3b4429b2e Add missing fields to ingreds
missing ids and consumableIDs tags in some ingreds
2023-12-29 18:55:31 -08:00

236 lines
7.6 KiB
Python

"""
Used to process the raw item data pulled from the API.
Usage:
- python process_items.py [infile] [outfile]
OR
- python process_items.py [infile and outfile]
NOTE: id_map.json is due for change. Should be updated manually when Wynn2.0/corresponding WB version drops.
"""
import json
import sys
import os
import base64
import argparse
from items_common import translate_mappings
parser = argparse.ArgumentParser(description="Process raw pulled item data.")
parser.add_argument('infile', help='input file to read data from', default=None, nargs='?')
#parser.add_argument('outfile', help='output file to dump clean data into')
args = parser.parse_args()
if args.infile is None:
print("Grabbing json data from wynn api")
from item_wrapper import Items
api_data = Items().get_all_items()
json.dump(api_data, open('dump.json', 'w'))
else:
with open(args.infile, "r") as in_file:
api_data = json.load(in_file)
def translate_single_item(key, entry, name, directives, accumulate):
ret = entry
try:
if 'min' in entry and 'max' in entry:
if 'raw' in entry:
ret = entry['raw']
else:
ret = [entry['min'], entry['max']]
except:
pass
i = 0
while i < len(directives):
directive = directives[i]
if directive == 'DELETE':
ret = None
elif directive == 'CAPS':
ret = ret[0].upper() + ret[1:]
elif directive == 'ALLCAPS':
ret = ret.upper()
elif directive == 'STR_RANGE':
if 'min' in entry and 'max' in entry:
ret = f"{entry['min']}-{entry['max']}"
elif directive == 'UNWRAP':
recursive_translate(entry, accumulate, name, translate_single_item)
ret = None
i += 1
return ret
def translate_single_ing(key, entry, name, directives, accumulate):
ret = entry
try:
if 'min' in entry and 'max' in entry:
ret = {
'minimum': entry['min'],
'maximum': entry['max']
}
except:
pass
i = 0
while i < len(directives):
directive = directives[i]
if directive == 'DELETE':
ret = None
elif directive == 'UNWRAP':
recursive_translate(entry, accumulate, name, translate_single_ing)
ret = None
elif directive[:8] == 'RECURSE_':
ret = recursive_translate(entry, {}, directive[8:], translate_single_ing)
i += 1
return ret
def recursive_translate(entry, result, path, translate_single):
mapping = translate_mappings[path]
for k, v in entry.items():
# Translate the item.
if k in mapping:
tmp = mapping[k].split(';')
directives, translated_name = tmp[:-1], tmp[-1]
res = translate_single(k, v, translated_name, directives, result)
if res is not None:
result[translated_name] = res
continue
# pass it through unchanged.
result[k] = v
return result
armor_types = ['helmet', 'chestplate', 'leggings', 'boots']
def translate_entry(entry):
"""
Convert an api entry into an appropriate parsed item.
Returns a pair: (converted, type)
where `type` is "item", "ingredient", "tome", "material", "charm", or None
and converted might be None if the conversion failed.
"""
# sketchily infer what kind of item we're dealing with, and translate it appropriately.
if "type" in entry:
# only items have this field.
res = recursive_translate(entry, {}, "item", translate_single_item)
if res['type'] in armor_types:
res['category'] = 'armor'
else:
res['category'] = 'weapon'
for element in 'netwfa':
damage_key = element + 'Dam'
if damage_key not in res:
res[damage_key] = '0-0'
return res, 'item'
if "accessoryType" in entry:
# only accessories have this field.
return recursive_translate(entry, {'category': 'accessory'}, "item", translate_single_item), "item"
if "itemOnlyIDs" in entry:
# only ingredients have this field.
res = recursive_translate(entry, {}, "ingredient", translate_single_ing)
return res, "ingredient"
#return recursive_translate(entry, {}, "ing"), "ingredient"
if "tomeType" in entry:
# only tomes have this field.
return None, "tome"
if "craftable" in entry:
return None, "material"
# I think the only things left are charms, we just don't classify them.
return None, None
with open("id_map.json", "r") as id_map_file:
id_map = json.load(id_map_file)
used_ids = set([v for k, v in id_map.items()])
max_id = 0
with open("ing_map.json","r") as ing_map_file:
ing_map = json.load(ing_map_file)
items = []
ingreds = []
for name, entry in api_data.items():
entry['name'] = name
res, entry_type = translate_entry(entry)
print(f"Parsed {name}, type {entry_type}")
if res is None:
continue
# TODO: make this a map or smth less ugly code
if entry_type == 'item':
items.append(res)
elif entry_type == 'ingredient':
ingreds.append(res)
with open("../clean.json", "r") as oldfile:
old_data = json.load(oldfile)
old_items = old_data['items']
with open("../ingreds_clean.json", "r") as ingfile:
old_ingreds = json.load(ingfile)
known_item_names = set()
known_ingred_names = set()
for item in items:
known_item_names.add(item["name"])
for ingred in ingreds:
known_ingred_names.add(ingred["name"])
for item in old_items:
if item["name"] not in known_item_names:
print(f'Unknown old item: {item["name"]}!!!')
for ingred in old_ingreds:
if ingred["name"] not in known_ingred_names:
print(f'Unknown old ingred: {ingred["name"]}!!!')
# TODO hack pull the major id file
major_ids_filename = "../js/builder/major_ids_clean.json"
with open(major_ids_filename, 'r') as major_ids_file:
major_ids_map = json.load(major_ids_file)
major_ids_reverse_map = { v['displayName'] : k for k, v in major_ids_map.items() }
for item in items:
# HACKY ITEM FIXES!
if 'majorIds' in item:
item['majorIds'] = [ major_ids_reverse_map[item['majorIds']['name']] ]
if not (item["name"] in id_map):
while max_id in used_ids:
max_id += 1
used_ids.add(max_id)
id_map[item["name"]] = max_id
print(f'New item: {item["name"]} (id: {max_id})')
item["id"] = id_map[item["name"]]
for ingred in ingreds:
# HACKY ING FIXES!
ingred['itemIDs']['dura'] = int(ingred['itemIDs']['dura'] / 1000)
ingred['skills'] = [x.upper() for x in ingred['skills']]
if 'ids' not in ingred:
ingred['ids'] = dict()
print(f"ing missing 'ids': {ingred['name']}")
if 'consumableIDs' not in ingred:
ingred['consumableIDs'] = {'dura': 0, 'charges': 0}
print(f"ing missing 'consumableIDs': {ingred['name']}")
if not (ingred["name"] in ing_map):
new_id = len(ing_map)
ing_map[ingred["name"]] = new_id
print(f'New item: {item["name"]} (id: {new_id})')
ingred["id"] = ing_map[ingred["name"]]
#write items back into data
old_data["items"] = items
#save id map
with open("id_map.json","w") as id_map_file:
json.dump(id_map, id_map_file, indent=2)
with open("ing_map.json","w") as ing_map_file:
json.dump(ing_map, ing_map_file, indent=2)
#write the data back to the outfile
with open('item_out.json', "w+") as out_file:
json.dump(old_data, out_file, ensure_ascii=False, separators=(',', ':'))
with open('ing_out.json', "w+") as out_file:
json.dump(ingreds, out_file, ensure_ascii=False, separators=(',', ':'))