Updated generation pages.

This commit is contained in:
Aodhan Collins
2026-03-15 17:45:17 +00:00
parent 79bbf669e2
commit d756ea1d0e
30 changed files with 2033 additions and 189 deletions

164
migrate_field_groups.py Normal file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env python3
"""Migrate character, outfit, and action JSON files to new field groupings.
New groups combine identity + wardrobe fields by body region:
base - base_specs / full_body → all detailers
head - hair+eyes / headwear → face detailer
upper_body - arms+torso / top
lower_body - pelvis+legs / bottom+legwear
hands - hands / hands+gloves → hand detailer
feet - feet / footwear → foot detailer
additional - extra / accessories
"""
import json
import glob
import os
DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
def merge(*values):
"""Concatenate non-empty strings with ', '."""
parts = [v.strip().rstrip(',').strip() for v in values if v and v.strip()]
return ', '.join(parts)
def migrate_identity(identity):
"""Convert old identity dict to new grouped format."""
return {
'base': identity.get('base_specs', ''),
'head': merge(identity.get('hair', ''), identity.get('eyes', '')),
'upper_body': merge(identity.get('arms', ''), identity.get('torso', '')),
'lower_body': merge(identity.get('pelvis', ''), identity.get('legs', '')),
'hands': identity.get('hands', ''),
'feet': identity.get('feet', ''),
'additional': identity.get('extra', ''),
}
def migrate_wardrobe_outfit(outfit):
"""Convert old wardrobe outfit dict to new grouped format."""
return {
'base': outfit.get('full_body', ''),
'head': outfit.get('headwear', ''),
'upper_body': outfit.get('top', ''),
'lower_body': merge(outfit.get('bottom', ''), outfit.get('legwear', '')),
'hands': merge(outfit.get('hands', ''), outfit.get('gloves', '')),
'feet': outfit.get('footwear', ''),
'additional': outfit.get('accessories', ''),
}
def migrate_action(action):
"""Convert old action dict to new grouped format."""
return {
'base': action.get('full_body', ''),
'head': merge(action.get('head', ''), action.get('eyes', '')),
'upper_body': merge(action.get('arms', ''), action.get('torso', '')),
'lower_body': merge(action.get('pelvis', ''), action.get('legs', '')),
'hands': action.get('hands', ''),
'feet': action.get('feet', ''),
'additional': action.get('additional', ''),
}
def process_file(path, transform_fn, section_key):
"""Load JSON, apply transform to a section, write back."""
with open(path, 'r') as f:
data = json.load(f)
section = data.get(section_key)
if section is None:
print(f" SKIP {path} — no '{section_key}' section")
return False
# Check if already migrated (new keys present, no old keys)
if 'upper_body' in section and 'base' in section and 'full_body' not in section and 'base_specs' not in section:
print(f" SKIP {path} — already migrated")
return False
data[section_key] = transform_fn(section)
with open(path, 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
f.write('\n')
return True
def process_character(path):
"""Migrate a character JSON file (identity + all wardrobe outfits)."""
with open(path, 'r') as f:
data = json.load(f)
changed = False
# Migrate identity
identity = data.get('identity', {})
if identity and 'base_specs' in identity:
data['identity'] = migrate_identity(identity)
changed = True
# Migrate wardrobe (nested format with named outfits)
wardrobe = data.get('wardrobe', {})
if wardrobe:
new_wardrobe = {}
for outfit_name, outfit_data in wardrobe.items():
if isinstance(outfit_data, dict):
if 'full_body' in outfit_data or 'headwear' in outfit_data or 'top' in outfit_data:
new_wardrobe[outfit_name] = migrate_wardrobe_outfit(outfit_data)
changed = True
else:
new_wardrobe[outfit_name] = outfit_data # already migrated or unknown format
else:
new_wardrobe[outfit_name] = outfit_data
data['wardrobe'] = new_wardrobe
if changed:
with open(path, 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
f.write('\n')
return changed
def main():
stats = {'characters': 0, 'outfits': 0, 'actions': 0, 'skipped': 0}
# Characters
print("=== Characters ===")
for path in sorted(glob.glob(os.path.join(DATA_DIR, 'characters', '*.json'))):
name = os.path.basename(path)
if process_character(path):
print(f" OK {name}")
stats['characters'] += 1
else:
print(f" SKIP {name}")
stats['skipped'] += 1
# Outfits (clothing)
print("\n=== Outfits ===")
for path in sorted(glob.glob(os.path.join(DATA_DIR, 'clothing', '*.json'))):
name = os.path.basename(path)
if process_file(path, migrate_wardrobe_outfit, 'wardrobe'):
print(f" OK {name}")
stats['outfits'] += 1
else:
print(f" SKIP {name}")
stats['skipped'] += 1
# Actions
print("\n=== Actions ===")
for path in sorted(glob.glob(os.path.join(DATA_DIR, 'actions', '*.json'))):
name = os.path.basename(path)
if process_file(path, migrate_action, 'action'):
print(f" OK {name}")
stats['actions'] += 1
else:
print(f" SKIP {name}")
stats['skipped'] += 1
print(f"\nDone! Characters: {stats['characters']}, Outfits: {stats['outfits']}, "
f"Actions: {stats['actions']}, Skipped: {stats['skipped']}")
if __name__ == '__main__':
main()