MosswartOverlord/inventory-service/extract_all_enums.py
2025-06-10 19:21:21 +00:00

294 lines
No EOL
9.8 KiB
Python

#!/usr/bin/env python3
"""
Comprehensive enum extraction from Mag-Plugins/Shared/Constants directory.
This script extracts ALL enum definitions from the Mag-Plugins source code
and creates structured JSON mappings for the inventory service.
"""
import re
import json
import os
from pathlib import Path
from typing import Dict, List, Any, Tuple, Optional
def extract_enum_from_file(file_path: Path) -> Tuple[str, Dict[str, Any]]:
"""Extract enum definition from a C# file."""
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# Find enum declaration
enum_match = re.search(r'public enum (\w+)(?:\s*:\s*(\w+))?\s*{', content)
if not enum_match:
return None, {}
enum_name = enum_match.group(1)
enum_type = enum_match.group(2) or 'int'
print(f"Extracting {enum_name} from {file_path.name}")
# Extract enum entries
entries = {}
comments = {}
attributes = {}
# Pattern to match enum entries with various formats
# Supports: Name = Value, Name, Name = 0x12345, etc.
pattern = r'^\s*(?:\[([^\]]+)\])?\s*(?:/// <summary>\s*([^<]*?)\s*/// </summary>\s*)?(?:\[([^\]]+)\])?\s*(\w+)(?:\s*=\s*([^,]+?))?\s*,?\s*(?://\s*(.*))?$'
lines = content.split('\n')
in_enum = False
current_value = 0
for line in lines:
# Check if we're entering the enum
if f'enum {enum_name}' in line:
in_enum = True
continue
# Check if we're exiting the enum
if in_enum and '}' in line and not line.strip().startswith('//'):
break
if in_enum:
match = re.match(pattern, line)
if match:
attr1, summary, attr2, name, value, comment = match.groups()
# Parse value
if value:
value = value.strip()
if value.startswith('0x') and ' ' not in value:
# Simple hex value
parsed_value = int(value, 16)
elif value.isdigit():
# Simple integer
parsed_value = int(value)
elif '|' in value or '<<' in value or '+' in value:
# Complex expression - store as string for now
parsed_value = f"EXPR:{value}"
else:
# Try simple conversion
try:
parsed_value = int(value)
except ValueError:
parsed_value = f"VALUE:{value}"
else:
parsed_value = current_value
entries[parsed_value] = name
# Update current_value for auto-increment
if isinstance(parsed_value, int):
current_value = parsed_value + 1
else:
# For non-numeric values, increment anyway for next entry
current_value += 1
# Store metadata
if summary:
comments[name] = summary.strip()
if comment:
comments[name] = comment.strip()
if attr1 or attr2:
attributes[name] = (attr1 or '') + ' ' + (attr2 or '')
return enum_name, {
'type': enum_type,
'values': entries,
'comments': comments,
'attributes': attributes,
'source_file': file_path.name
}
def extract_skill_names():
"""Extract skill names with their indices from Skill.cs"""
skill_file = Path('/home/erik/MosswartOverlord/Mag-Plugins/Shared/Constants/Skill.cs')
with open(skill_file, 'r') as f:
content = f.read()
skills = {}
lines = content.split('\n')
in_enum = False
index = 0
for line in lines:
if 'enum Skill' in line:
in_enum = True
continue
if in_enum and '}' in line:
break
if in_enum:
# Match skill entries like "None," or "Axe, /* Retired */"
match = re.match(r'^\s*(\w+),?\s*(?:/\*\s*([^*]*)\s*\*/)?', line)
if match:
skill_name = match.group(1)
status = match.group(2) or "Active"
skills[index] = {
'name': skill_name,
'status': status.strip()
}
index += 1
return skills
def categorize_enums():
"""Create logical categories for different enum types."""
return {
'item_properties': {
'description': 'Item property value keys for different data types',
'enums': ['IntValueKey', 'DoubleValueKey', 'StringValueKey', 'BoolValueKey', 'QuadValueKey']
},
'item_classification': {
'description': 'Item type and material classification',
'enums': ['ItemType', 'MaterialType', 'WeenieType']
},
'game_mechanics': {
'description': 'Skills, spells, and game system enums',
'enums': ['Skill', 'SpellCategory', 'WieldRequirement']
},
'technical': {
'description': 'Technical flags and masks for game engine',
'enums': ['CoverageMask', 'EquipMask']
}
}
def create_translation_mappings():
"""Create user-friendly translations for important enum values."""
# Map IntValueKey values to more descriptive names
int_value_translations = {
5: 'Encumbrance',
19: 'Value (Pyreals)',
25: 'Level',
28: 'Armor Level',
44: 'Base Damage',
45: 'Damage Type',
48: 'Weapon Skill',
158: 'Wield Requirements',
160: 'Wield Difficulty',
218103842: 'Maximum Damage',
218103849: 'Icon Overlay',
218103850: 'Icon Underlay'
}
# Material type friendly names
material_translations = {
0: 'Unknown',
1: 'Ceramic',
20: 'Diamond',
21: 'Emerald',
31: 'Ruby',
32: 'Sapphire'
}
return {
'int_values': int_value_translations,
'materials': material_translations
}
def main():
"""Main extraction process."""
constants_dir = Path('/home/erik/MosswartOverlord/Mag-Plugins/Shared/Constants')
output_dir = Path('/home/erik/MosswartOverlord/inventory-service')
# Ensure output directory exists
output_dir.mkdir(exist_ok=True)
print("Starting comprehensive enum extraction from Mag-Plugins/Shared/Constants...")
# Extract all enum files
all_enums = {}
enum_files = list(constants_dir.glob('*.cs'))
for enum_file in enum_files:
if enum_file.name == 'Dictionaries.cs': # Skip non-enum files
continue
enum_name, enum_data = extract_enum_from_file(enum_file)
if enum_name and enum_data:
all_enums[enum_name] = enum_data
# Special handling for Skills (has complex structure)
skill_data = extract_skill_names()
all_enums['Skill'] = {
'type': 'indexed',
'values': skill_data,
'source_file': 'Skill.cs'
}
# Create categorized structure
categories = categorize_enums()
translations = create_translation_mappings()
# Save complete enum database
complete_data = {
'metadata': {
'extracted_at': '2025-06-10',
'source': 'Mag-Plugins/Shared/Constants',
'total_enums': len(all_enums),
'version': '1.0.0'
},
'categories': categories,
'translations': translations,
'enums': all_enums
}
# Save main database
main_output = output_dir / 'complete_enum_database.json'
with open(main_output, 'w') as f:
json.dump(complete_data, f, indent=2)
print(f"Saved complete enum database to {main_output}")
# Save individual enum files for backward compatibility
individual_dir = output_dir / 'enums'
individual_dir.mkdir(exist_ok=True)
for enum_name, enum_data in all_enums.items():
enum_file = individual_dir / f'{enum_name}.json'
with open(enum_file, 'w') as f:
json.dump({enum_name: enum_data}, f, indent=2)
# Update existing files for backward compatibility
if 'IntValueKey' in all_enums:
legacy_int_file = output_dir / 'int_value_enums.json'
with open(legacy_int_file, 'w') as f:
json.dump(all_enums['IntValueKey']['values'], f, indent=2)
print(f"Updated legacy file: {legacy_int_file}")
# Create comprehensive summary
print("\n" + "="*60)
print("EXTRACTION SUMMARY")
print("="*60)
for enum_name, enum_data in all_enums.items():
value_count = len(enum_data.get('values', {}))
enum_type = enum_data.get('type', 'unknown')
print(f"{enum_name:20} | {value_count:4} values | Type: {enum_type}")
print(f"\nTotal enums extracted: {len(all_enums)}")
print(f"Files created:")
print(f" - {main_output}")
print(f" - {len(all_enums)} individual enum files in {individual_dir}/")
# Show sample translations
print("\nSample enum translations:")
for enum_name in ['IntValueKey', 'MaterialType', 'ItemType', 'Skill']:
if enum_name in all_enums:
values = all_enums[enum_name]['values']
if isinstance(values, dict):
sample_keys = list(values.keys())[:3]
for key in sample_keys:
if isinstance(values[key], dict):
print(f" {enum_name}[{key}] = {values[key].get('name', values[key])}")
else:
print(f" {enum_name}[{key}] = {values[key]}")
if __name__ == '__main__':
main()