# -*- coding: utf-8 -*- """ DS 전투 데이터 수집 메인 스크립트 실행 방법: python collect_combat_data.py """ import json import logging import os from datetime import datetime from typing import Dict, List from data_extractors import ( TARGET_STALKERS, extract_character_stat, extract_attack_montages, extract_skill_data, extract_montage_info ) from markdown_formatter import generate_stalker_markdown from validators import validate_collection_result, log_collection_summary # 로깅 설정 logging.basicConfig( level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) logger = logging.getLogger(__name__) # 경로 설정 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SOURCE_DATA_DIR = os.path.join(os.path.dirname(BASE_DIR), '원본데이터') OUTPUT_DIR = os.path.join(BASE_DIR, '수집결과') MARKDOWN_DIR = os.path.join(OUTPUT_DIR, 'markdown') DATATABLE_JSON = os.path.join(SOURCE_DATA_DIR, 'DataTable.json') ANIMMONTAGE_JSON = os.path.join(SOURCE_DATA_DIR, 'AnimMontage.json') OUTPUT_JSON = os.path.join(OUTPUT_DIR, 'all_stalkers_combat_data.json') LOG_FILE = os.path.join(OUTPUT_DIR, 'collection_log.txt') def load_json_file(file_path: str) -> dict: """JSON 파일 로드""" logger.info(f"JSON 파일 로드 중: {file_path}") with open(file_path, 'r', encoding='utf-8') as f: data = json.load(f) logger.info(f" - 로드 완료") return data def collect_stalker_data( stalker_name: str, datatable_assets: List[Dict], animmontage_assets: List[Dict] ) -> Dict: """ 단일 스토커의 전투 데이터 수집 Args: stalker_name: 스토커 이름 (소문자) datatable_assets: DataTable.json의 Assets 배열 animmontage_assets: AnimMontage.json의 Assets 배열 Returns: 스토커 전투 데이터 """ logger.info(f" [{stalker_name}] 데이터 수집 시작") # 1. 기본 스탯 추출 stats = extract_character_stat(datatable_assets, stalker_name) if not stats: logger.error(f" [{stalker_name}] 스탯 정보 추출 실패") return {} # 2. 기본 정보 분리 basic_info = { 'name': stats.pop('name', ''), 'jobName': stats.pop('jobName', '') } # 3. 스킬 정보 분리 skills = { 'default': stats.pop('defaultSkills', []), 'sub': stats.pop('subSkill', ''), 'ultimate': stats.pop('ultimateSkill', ''), 'ultimatePoint': stats.pop('ultimatePoint', 0) } # 4. 스킬 상세 정보 및 몽타주 수집 skill_details = {} all_skill_ids = skills['default'] + [skills['sub'], skills['ultimate']] for skill_id in all_skill_ids: if not skill_id: continue skill_data = extract_skill_data(datatable_assets, skill_id) if not skill_data: logger.warning(f" [{stalker_name}] 스킬 {skill_id} 데이터 추출 실패") continue # 스킬 몽타주 정보 수집 montage_paths = skill_data.get('useMontages', []) montages = [] for montage_path in montage_paths: montage_info = extract_montage_info(animmontage_assets, montage_path) if montage_info: montages.append(montage_info) skill_data['montages'] = montages skill_details[skill_id] = skill_data # 5. 기본 공격 몽타주 수집 attack_montages_map = extract_attack_montages(datatable_assets, stalker_name) basic_attacks = {} for weapon_type, montage_paths in attack_montages_map.items(): montages = [] for montage_path in montage_paths: montage_info = extract_montage_info(animmontage_assets, montage_path) if montage_info: montages.append(montage_info) if montages: basic_attacks[weapon_type] = montages # 6. 최종 데이터 구성 stalker_data = { 'basic_info': basic_info, 'stats': stats, 'skills': skills, 'skill_details': skill_details, 'basic_attacks': basic_attacks } logger.info(f" [{stalker_name}] 데이터 수집 완료") logger.info(f" - 스킬 {len(skill_details)}개") logger.info(f" - 무기 타입 {len(basic_attacks)}개") return stalker_data def main(): """메인 실행 함수""" logger.info("=" * 80) logger.info("DS 전투 데이터 수집 시작") logger.info("=" * 80) # 1. 원본 데이터 로드 logger.info("1. 원본 데이터 로드 중...") datatable_data = load_json_file(DATATABLE_JSON) animmontage_data = load_json_file(ANIMMONTAGE_JSON) datatable_assets = datatable_data.get('Assets', []) animmontage_assets = animmontage_data.get('Assets', []) logger.info(f" - DataTable 에셋 수: {len(datatable_assets)}") logger.info(f" - AnimMontage 에셋 수: {len(animmontage_assets)}") logger.info("") # 2. 스토커별 데이터 수집 logger.info(f"2. 스토커 데이터 수집 중 (총 {len(TARGET_STALKERS)}명)...") stalkers_data = {} for stalker_name in TARGET_STALKERS: stalker_data = collect_stalker_data( stalker_name, datatable_assets, animmontage_assets ) if stalker_data: stalkers_data[stalker_name] = stalker_data logger.info("") # 3. 통합 JSON 생성 logger.info("3. 통합 JSON 생성 중...") collection_data = { 'collection_metadata': { 'collected_at': datetime.now().isoformat(), 'source_files': [ 'DataTable.json', 'AnimMontage.json' ], 'total_stalkers': len(stalkers_data) }, 'stalkers': stalkers_data } with open(OUTPUT_JSON, 'w', encoding='utf-8') as f: json.dump(collection_data, f, ensure_ascii=False, indent=2) logger.info(f" - 통합 JSON 생성 완료: {OUTPUT_JSON}") logger.info("") # 4. 스토커별 마크다운 생성 logger.info(f"4. 스토커별 마크다운 생성 중 ({len(stalkers_data)}명)...") for stalker_name, stalker_data in stalkers_data.items(): markdown_content = generate_stalker_markdown(stalker_name, stalker_data) markdown_path = os.path.join(MARKDOWN_DIR, f'{stalker_name}.md') with open(markdown_path, 'w', encoding='utf-8') as f: f.write(markdown_content) logger.info(f" - {stalker_name}.md 생성 완료") logger.info("") # 5. 데이터 검증 logger.info("5. 데이터 검증 중...") is_valid = validate_collection_result(collection_data) if is_valid: logger.info(" ✓ 모든 데이터 검증 통과") else: logger.warning(" ⚠ 일부 데이터 검증 실패 (상세 내용은 로그 참조)") logger.info("") # 6. 수집 요약 로그 생성 logger.info("6. 수집 요약 로그 생성 중...") log_collection_summary(collection_data, LOG_FILE) logger.info("") # 7. 완료 logger.info("=" * 80) logger.info("DS 전투 데이터 수집 완료!") logger.info("=" * 80) logger.info(f"결과 파일:") logger.info(f" - 통합 JSON: {OUTPUT_JSON}") logger.info(f" - 마크다운: {MARKDOWN_DIR}") logger.info(f" - 수집 로그: {LOG_FILE}") logger.info("") if __name__ == '__main__': try: main() except Exception as e: logger.exception("수집 중 예외 발생:") raise