294 lines
No EOL
9.8 KiB
Python
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() |