리뉴얼
This commit is contained in:
122
분석도구/v2/archive/README.md
Normal file
122
분석도구/v2/archive/README.md
Normal file
@ -0,0 +1,122 @@
|
||||
# 아카이브된 분석 스크립트
|
||||
|
||||
이 디렉토리에는 개발 과정에서 사용된 일회성 체크 및 검증 스크립트들이 보관되어 있습니다.
|
||||
|
||||
**아카이브 일자**: 2025-10-27
|
||||
**사유**: 핵심 분석 파이프라인 완성 후 정리
|
||||
|
||||
---
|
||||
|
||||
## 📁 파일 분류
|
||||
|
||||
### 🔍 스킬 검증 스크립트
|
||||
|
||||
특정 스킬의 데이터 추출 및 노티파이 검증에 사용된 스크립트
|
||||
|
||||
- **check_baran_clad_skills.py** - 바란/클라드 스킬 검증 (SK130301, SK150201)
|
||||
- **check_lian_skills.py** - 리안 스킬 검증 1차
|
||||
- **check_lian_skills2.py** - 리안 스킬 검증 2차
|
||||
- **check_sk150201.py** - 클라드 SK150201 상세 분석
|
||||
|
||||
### 🏗️ 데이터 구조 탐색 스크립트
|
||||
|
||||
JSON 파일 구조 및 Blueprint 데이터 탐색
|
||||
|
||||
- **check_json_structure.py** - JSON 최상위 구조 확인
|
||||
- **check_first_asset.py** - 첫 번째 Asset 구조 출력
|
||||
- **check_data.py** - 전반적인 데이터 구조 확인
|
||||
- **check_skill_structure.py** - DT_Skill 구조 분석
|
||||
|
||||
### 🎯 Character Ability 탐색 스크립트
|
||||
|
||||
DT_CharacterAbility 및 평타 몽타주 추출 검증
|
||||
|
||||
- **check_character_ability.py** - DT_CharacterAbility 기본 구조 확인
|
||||
- **check_character_ability2.py** - attackMontageMap 추출 검증
|
||||
- **check_character_ability3.py** - 평타 몽타주 상세 분석
|
||||
|
||||
### 🎬 AnimMontage 및 Notify 분석
|
||||
|
||||
AnimNotify 및 투사체 판정 로직 검증
|
||||
|
||||
- **check_montage_names.py** - 몽타주 이름 추출 검증
|
||||
- **check_send_event_notify.py** - SimpleSendEvent 노티파이 분석
|
||||
- **investigate_projectile.py** - 투사체 노티파이 상세 조사
|
||||
|
||||
### 🧪 Blueprint 변수 검증
|
||||
|
||||
Blueprint 변수 추출 및 매칭 검증
|
||||
|
||||
- **check_bp_vars.py** - Blueprint 변수 기본 추출
|
||||
- **check_bp_verification.py** - Blueprint 변수 검증 로직
|
||||
|
||||
### ✅ 개선 사항 검증
|
||||
|
||||
버전별 개선 사항 적용 여부 확인
|
||||
|
||||
- **check_improvements.py** - v2.1~v2.2 개선사항 검증
|
||||
- **verify_improvements.py** - 일반 개선사항 검증
|
||||
- **verify_improvements_v2.3.py** - v2.3 개선사항 검증
|
||||
|
||||
---
|
||||
|
||||
## 📝 사용 목적
|
||||
|
||||
이 스크립트들은 다음 목적으로 작성되었습니다:
|
||||
|
||||
1. **데이터 구조 탐색**: JSON 및 Blueprint 데이터 구조 이해
|
||||
2. **추출 로직 검증**: 몽타주, 노티파이, 스킬 데이터 추출 정확성 확인
|
||||
3. **버그 수정**: 특정 스킬의 오류 원인 분석 및 해결
|
||||
4. **개선사항 검증**: 버전 업데이트 후 변경사항 적용 확인
|
||||
|
||||
---
|
||||
|
||||
## 🔄 재사용 가능성
|
||||
|
||||
### 재사용 가능한 스크립트
|
||||
|
||||
다음 스크립트들은 향후 유사한 문제 발생 시 참고 가능합니다:
|
||||
|
||||
- **check_send_event_notify.py** - SimpleSendEvent 노티파이 분석 템플릿
|
||||
- **investigate_projectile.py** - 투사체 노티파이 조사 방법
|
||||
- **check_bp_vars.py** - Blueprint 변수 추출 예시
|
||||
|
||||
### 재사용 방법
|
||||
|
||||
```bash
|
||||
# 예: 새로운 스킬 SK999999 분석이 필요한 경우
|
||||
# check_sk150201.py를 복사하여 수정
|
||||
|
||||
cd D:\Work\WorldStalker\DS-전투분석_저장소\분석도구\v2\archive
|
||||
cp check_sk150201.py check_sk999999.py
|
||||
|
||||
# 내부의 스킬 ID를 SK999999로 변경 후 실행
|
||||
python check_sk999999.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗑️ 삭제 가능 여부
|
||||
|
||||
이 스크립트들은 현재 분석 파이프라인에서 사용되지 않지만, 다음 이유로 보존합니다:
|
||||
|
||||
1. **디버깅 참고**: 향후 유사한 문제 발생 시 해결 방법 참고
|
||||
2. **데이터 구조 이해**: 새로운 개발자가 JSON 구조를 이해하는 데 도움
|
||||
3. **분석 히스토리**: 시스템 개발 과정 기록
|
||||
|
||||
**권장 보존 기간**: 6개월~1년
|
||||
|
||||
만약 디스크 공간이 부족하거나 더 이상 필요 없다고 판단되면 삭제해도 무방합니다.
|
||||
|
||||
---
|
||||
|
||||
## 📚 관련 문서
|
||||
|
||||
- **../장기과제_Blueprint변수검증.md** - Blueprint 변수 활용 계획
|
||||
- **../../분석결과/*/개선_보고서_*.md** - 버전별 개선 내역
|
||||
- **../../ARCHITECTURE.md** - 전체 시스템 아키텍처
|
||||
|
||||
---
|
||||
|
||||
**작성자**: AI-assisted Development Team
|
||||
**최종 업데이트**: 2025-10-27
|
||||
81
분석도구/v2/archive/check_baran_clad_skills.py
Normal file
81
분석도구/v2/archive/check_baran_clad_skills.py
Normal file
@ -0,0 +1,81 @@
|
||||
"""바란, 클라드 스킬 몽타주 확인"""
|
||||
import json
|
||||
|
||||
with open('../../원본데이터/AnimMontage.json', 'r', encoding='utf-8') as f:
|
||||
montage_data = json.load(f)
|
||||
|
||||
with open('../../원본데이터/DataTable.json', 'r', encoding='utf-8') as f:
|
||||
dt_data = json.load(f)
|
||||
|
||||
# DT_Skill 찾기
|
||||
dt_skill = None
|
||||
for asset in dt_data.get('Assets', []):
|
||||
if asset.get('AssetName') == 'DT_Skill':
|
||||
dt_skill = asset
|
||||
break
|
||||
|
||||
print("=== 바란, 클라드 스킬 몽타주 확인 ===\n")
|
||||
|
||||
target_skills = {
|
||||
'SK130301': '일격분쇄 (바란)',
|
||||
'SK150201': '다시 흙으로 (클라드)'
|
||||
}
|
||||
skill_montages = {}
|
||||
|
||||
for row in dt_skill.get('Rows', []):
|
||||
row_name = row.get('RowName', '')
|
||||
if row_name in target_skills:
|
||||
row_data = row.get('Data', {})
|
||||
use_montages = row_data.get('useMontages', [])
|
||||
skill_name = row_data.get('name', '')
|
||||
|
||||
print(f"[{row_name}] {skill_name}")
|
||||
print(f" useMontages: {len(use_montages)}개")
|
||||
|
||||
if use_montages:
|
||||
for montage_path in use_montages:
|
||||
print(f" Path: {montage_path}")
|
||||
|
||||
# 몽타주 이름 추출
|
||||
montage_name = montage_path.split('/')[-1].replace("'", "").split('.')[0]
|
||||
if row_name not in skill_montages:
|
||||
skill_montages[row_name] = []
|
||||
skill_montages[row_name].append(montage_name)
|
||||
print(f" Name: {montage_name}")
|
||||
print()
|
||||
|
||||
# 각 몽타주에서 노티파이 확인
|
||||
print("\n=== 몽타주 노티파이 확인 ===\n")
|
||||
|
||||
for skill_id, montage_names in skill_montages.items():
|
||||
for montage_name in montage_names:
|
||||
for asset in montage_data.get('Assets', []):
|
||||
if asset.get('AssetName') == montage_name:
|
||||
print(f"[{skill_id}] {target_skills[skill_id]} - {montage_name}")
|
||||
|
||||
notifies = asset.get('AnimNotifies', [])
|
||||
print(f" 총 노티파이: {len(notifies)}개\n")
|
||||
|
||||
found_attack_notify = False
|
||||
|
||||
for idx, notify in enumerate(notifies):
|
||||
notify_class = notify.get('NotifyClass', '')
|
||||
|
||||
# SimpleSendEvent 노티파이
|
||||
if 'SimpleSendEvent' in notify_class:
|
||||
custom_props = notify.get('CustomProperties', {})
|
||||
event_tag = custom_props.get('Event Tag', '')
|
||||
|
||||
# Event.SkillActivate 확인
|
||||
if 'SkillActivate' in event_tag:
|
||||
print(f" [{idx}] SimpleSendEvent")
|
||||
print(f" Event Tag: {event_tag}")
|
||||
print(f" >>> Event.SkillActivate 발견! (공격 스킬)")
|
||||
found_attack_notify = True
|
||||
print()
|
||||
|
||||
if not found_attack_notify:
|
||||
print(" *** Event.SkillActivate를 찾지 못했습니다. ***\n")
|
||||
|
||||
print("-" * 60)
|
||||
print()
|
||||
110
분석도구/v2/archive/check_bp_vars.py
Normal file
110
분석도구/v2/archive/check_bp_vars.py
Normal file
@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Blueprint 변수 상세 조사"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Blueprint.json 로드
|
||||
bp_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/원본데이터/Blueprint.json")
|
||||
with open(bp_file, 'r', encoding='utf-8') as f:
|
||||
bp_data = json.load(f)
|
||||
|
||||
# DataTable.json 로드
|
||||
dt_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/원본데이터/DataTable.json")
|
||||
with open(dt_file, 'r', encoding='utf-8') as f:
|
||||
dt_data = json.load(f)
|
||||
|
||||
assets = bp_data.get('Assets', [])
|
||||
|
||||
# GA_Skill_Knight_Counter 찾기
|
||||
counter_bp = [a for a in assets if a.get('AssetName') == 'GA_Skill_Knight_Counter']
|
||||
|
||||
print("=" * 80)
|
||||
print("GA_Skill_Knight_Counter Blueprint 분석")
|
||||
print("=" * 80)
|
||||
|
||||
if counter_bp:
|
||||
bp = counter_bp[0]
|
||||
print(f"\nAssetName: {bp.get('AssetName')}")
|
||||
print(f"ParentClass: {bp.get('ParentClass')}")
|
||||
|
||||
vars = bp.get('Variables', [])
|
||||
print(f"\nTotal Variables: {len(vars)}")
|
||||
|
||||
# 숫자 타입 변수만
|
||||
numeric_types = ['Float', 'Int', 'Double', 'Byte', 'int', 'float', 'double']
|
||||
numeric_vars = []
|
||||
|
||||
for v in vars:
|
||||
var_type = str(v.get('VarType', ''))
|
||||
if any(t in var_type for t in numeric_types):
|
||||
numeric_vars.append(v)
|
||||
|
||||
print(f"\nNumeric Variables ({len(numeric_vars)}개):")
|
||||
for v in numeric_vars[:15]:
|
||||
print(f" {v.get('VarName')}: {v.get('DefaultValue')} (type: {v.get('VarType')})")
|
||||
|
||||
# 모든 변수 출력 (참고용)
|
||||
print(f"\nAll Variables:")
|
||||
for v in vars[:20]:
|
||||
print(f" {v.get('VarName')} ({v.get('VarType')}): {v.get('DefaultValue')}")
|
||||
else:
|
||||
print("GA_Skill_Knight_Counter를 찾을 수 없음!")
|
||||
|
||||
# DT_Skill에서 SK100202 정보
|
||||
print("\n" + "=" * 80)
|
||||
print("SK100202 DT_Skill 데이터")
|
||||
print("=" * 80)
|
||||
|
||||
dt_assets = dt_data.get('Assets', [])
|
||||
dt_skill = [a for a in dt_assets if a.get('AssetName') == 'DT_Skill'][0]
|
||||
rows = dt_skill.get('Rows', [])
|
||||
sk_row = [r for r in rows if r.get('RowName') == 'SK100202'][0]
|
||||
sk_data = sk_row.get('Data', {})
|
||||
|
||||
print(f"스킬 이름: {sk_data.get('name')}")
|
||||
print(f"Desc: {sk_data.get('desc')}")
|
||||
print(f"DescValues: {sk_data.get('descValues')}")
|
||||
|
||||
# desc에서 {0}, {1} 위치 찾기
|
||||
desc = sk_data.get('desc', '')
|
||||
desc_values = sk_data.get('descValues', [])
|
||||
|
||||
print(f"\n변수 매칭:")
|
||||
for i, value in enumerate(desc_values):
|
||||
print(f" {{{i}}} = {value}")
|
||||
|
||||
print(f"\n추론: Hilda 반격 스킬은")
|
||||
print(f" - {{{0}}}초 = {desc_values[0]}초 (반격 지속 시간)")
|
||||
print(f" - {{{1}}}% = {desc_values[1]}% (반격 피해 배율)")
|
||||
|
||||
# 다른 스킬도 조사
|
||||
print("\n" + "=" * 80)
|
||||
print("다른 스킬 Blueprint 변수 조사")
|
||||
print("=" * 80)
|
||||
|
||||
test_skills = [
|
||||
('SK100201', 'GA_Skill_Hilda_SwordStrike', '칼날 격돌'),
|
||||
('SK110205', 'GA_Skill_Urud_MultiShot_Quick', '다발 화살'),
|
||||
]
|
||||
|
||||
for skill_id, bp_name, skill_name in test_skills:
|
||||
print(f"\n=== {skill_name} ({skill_id}) ===")
|
||||
|
||||
# DT_Skill
|
||||
sk_row = [r for r in rows if r.get('RowName') == skill_id]
|
||||
if sk_row:
|
||||
sk_data = sk_row[0].get('Data', {})
|
||||
print(f"DescValues: {sk_data.get('descValues')}")
|
||||
|
||||
# Blueprint
|
||||
bp_match = [a for a in assets if a.get('AssetName') == bp_name]
|
||||
if bp_match:
|
||||
vars = bp_match[0].get('Variables', [])
|
||||
numeric_vars = [v for v in vars if any(t in str(v.get('VarType', '')) for t in numeric_types)]
|
||||
print(f"Blueprint 변수 총 {len(vars)}개, 숫자형 {len(numeric_vars)}개")
|
||||
if numeric_vars:
|
||||
print(" 숫자형 변수:")
|
||||
for v in numeric_vars[:5]:
|
||||
print(f" {v.get('VarName')}: {v.get('DefaultValue')}")
|
||||
else:
|
||||
print(f" Blueprint '{bp_name}' 없음")
|
||||
120
분석도구/v2/archive/check_bp_verification.py
Normal file
120
분석도구/v2/archive/check_bp_verification.py
Normal file
@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Blueprint 변수 검증 조사 스크립트"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Blueprint.json 로드
|
||||
bp_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/원본데이터/Blueprint.json")
|
||||
with open(bp_file, 'r', encoding='utf-8') as f:
|
||||
bp_data = json.load(f)
|
||||
|
||||
# DataTable.json 로드
|
||||
dt_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/원본데이터/DataTable.json")
|
||||
with open(dt_file, 'r', encoding='utf-8') as f:
|
||||
dt_data = json.load(f)
|
||||
|
||||
# validated_data.json 로드
|
||||
val_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/분석결과/20251024_210822_v2/validated_data.json")
|
||||
with open(val_file, 'r', encoding='utf-8') as f:
|
||||
val_data = json.load(f)
|
||||
|
||||
print("=" * 80)
|
||||
print("Blueprint 변수 검증 조사")
|
||||
print("=" * 80)
|
||||
|
||||
# 예시: Hilda의 SK100202 (반격) 스킬 조사
|
||||
print("\n=== 예시: Hilda SK100202 (반격) 스킬 ===")
|
||||
|
||||
# DT_Skill에서 SK100202 정보
|
||||
assets = dt_data.get('Assets', [])
|
||||
dt_skill = [a for a in assets if a.get('AssetName') == 'DT_Skill'][0]
|
||||
rows = dt_skill.get('Rows', [])
|
||||
sk100202_row = [r for r in rows if r.get('RowName') == 'SK100202'][0]
|
||||
sk100202_data = sk100202_row.get('Data', {})
|
||||
|
||||
print(f"스킬 이름: {sk100202_data.get('name')}")
|
||||
print(f"Desc: {sk100202_data.get('desc')}")
|
||||
print(f"DescValues: {sk100202_data.get('descValues')}")
|
||||
print(f"AbilityClass: {sk100202_data.get('abilityClass')}")
|
||||
|
||||
# Blueprint에서 관련 GA_Skill 찾기
|
||||
ability_class = sk100202_data.get('abilityClass', '')
|
||||
if ability_class:
|
||||
bp_name = ability_class.split('/')[-1].split('.')[0] if '/' in ability_class else ability_class
|
||||
print(f"\nBlueprint 이름: {bp_name}")
|
||||
|
||||
# Blueprint.json에서 검색
|
||||
bp_assets = bp_data.get('Assets', [])
|
||||
matching_bp = [a for a in bp_assets if a.get('AssetName') == bp_name]
|
||||
|
||||
if matching_bp:
|
||||
print(f"Blueprint 발견: {matching_bp[0].get('AssetName')}")
|
||||
|
||||
# 변수 확인
|
||||
variables = matching_bp[0].get('BlueprintVariables', [])
|
||||
print(f"\nBlueprint 변수 ({len(variables)}개):")
|
||||
for var in variables[:10]: # 처음 10개만
|
||||
var_name = var.get('VarName', 'N/A')
|
||||
var_type = var.get('VarType', 'N/A')
|
||||
default_value = var.get('DefaultValue', 'N/A')
|
||||
print(f" - {var_name} ({var_type}): {default_value}")
|
||||
else:
|
||||
print(f"Blueprint '{bp_name}' 찾을 수 없음")
|
||||
|
||||
# validated_data에서 확인
|
||||
hilda = val_data['hilda']
|
||||
sk = hilda['skills']['SK100202']
|
||||
print(f"\n=== Validated Data ===")
|
||||
print(f"DescFormatted: {sk.get('descFormatted')}")
|
||||
print(f"Blueprint Variables in extracted data:")
|
||||
bp_vars = sk.get('blueprintVariables', {})
|
||||
if bp_vars:
|
||||
for var_name, var_info in list(bp_vars.items())[:5]:
|
||||
print(f" - {var_name}: {var_info}")
|
||||
else:
|
||||
print(" (Blueprint 변수 없음)")
|
||||
|
||||
# 다른 스킬도 몇 개 조사
|
||||
print("\n" + "=" * 80)
|
||||
print("다른 스킬 샘플 조사")
|
||||
print("=" * 80)
|
||||
|
||||
sample_skills = [
|
||||
('SK100201', 'hilda', '칼날 격돌'),
|
||||
('SK110205', 'urud', '다발 화살'),
|
||||
('SK160202', 'rene', 'Ifrit 소환')
|
||||
]
|
||||
|
||||
for skill_id, stalker, skill_name in sample_skills:
|
||||
print(f"\n=== {skill_id} ({skill_name}) ===")
|
||||
|
||||
# DT_Skill
|
||||
skill_row = [r for r in rows if r.get('RowName') == skill_id]
|
||||
if not skill_row:
|
||||
print(" DT_Skill에 없음")
|
||||
continue
|
||||
|
||||
skill_data = skill_row[0].get('Data', {})
|
||||
desc = skill_data.get('desc', '')
|
||||
desc_values = skill_data.get('descValues', [])
|
||||
ability_class = skill_data.get('abilityClass', '')
|
||||
|
||||
print(f" Desc: {desc[:100]}...")
|
||||
print(f" DescValues: {desc_values}")
|
||||
print(f" AbilityClass: {ability_class}")
|
||||
|
||||
# Blueprint
|
||||
if ability_class:
|
||||
bp_name = ability_class.split('/')[-1].split('.')[0] if '/' in ability_class else ability_class
|
||||
matching_bp = [a for a in bp_assets if a.get('AssetName') == bp_name]
|
||||
if matching_bp:
|
||||
variables = matching_bp[0].get('BlueprintVariables', [])
|
||||
print(f" Blueprint 변수 개수: {len(variables)}")
|
||||
|
||||
# 숫자 타입 변수 찾기
|
||||
numeric_vars = [v for v in variables if any(t in str(v.get('VarType', '')) for t in ['Float', 'Int', 'Byte'])]
|
||||
if numeric_vars:
|
||||
print(f" 숫자 변수 샘플:")
|
||||
for var in numeric_vars[:3]:
|
||||
print(f" - {var.get('VarName')}: {var.get('DefaultValue')}")
|
||||
69
분석도구/v2/archive/check_character_ability.py
Normal file
69
분석도구/v2/archive/check_character_ability.py
Normal file
@ -0,0 +1,69 @@
|
||||
"""DT_CharacterAbility 데이터 구조 확인"""
|
||||
import json
|
||||
import sys
|
||||
|
||||
def check_character_ability():
|
||||
# DataTable.json 로드
|
||||
with open('../../원본데이터/DataTable.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
# DT_CharacterAbility 찾기
|
||||
dt_char = None
|
||||
for table in data:
|
||||
if table.get('Type') == 'DataTable' and 'CharacterAbility' in table.get('Name', ''):
|
||||
dt_char = table
|
||||
break
|
||||
|
||||
if not dt_char:
|
||||
print("❌ DT_CharacterAbility 테이블을 찾을 수 없습니다.")
|
||||
return
|
||||
|
||||
print(f"✅ DT_CharacterAbility 테이블 발견: {dt_char.get('Name')}")
|
||||
print(f" Rows: {len(dt_char.get('Rows', {}))}")
|
||||
|
||||
# 우르드 데이터 확인
|
||||
rows = dt_char.get('Rows', {})
|
||||
urud_data = None
|
||||
for row_name, row_data in rows.items():
|
||||
if 'urud' in row_name.lower() or 'Urud' in row_name:
|
||||
urud_data = row_data
|
||||
print(f"\n🔍 우르드 데이터 발견: {row_name}")
|
||||
break
|
||||
|
||||
if urud_data:
|
||||
print("\n📋 우르드 데이터 키:")
|
||||
for key in sorted(urud_data.keys()):
|
||||
print(f" - {key}")
|
||||
|
||||
# Attack Montage Map 확인
|
||||
if 'attackMontageMap' in urud_data:
|
||||
print(f"\n⚔️ Attack Montage Map:")
|
||||
attack_map = urud_data['attackMontageMap']
|
||||
print(f" 타입: {type(attack_map)}")
|
||||
if isinstance(attack_map, dict):
|
||||
for k, v in attack_map.items():
|
||||
print(f" - {k}: {v}")
|
||||
elif isinstance(attack_map, list):
|
||||
for idx, item in enumerate(attack_map):
|
||||
print(f" [{idx}]: {item}")
|
||||
else:
|
||||
print(f" 값: {attack_map}")
|
||||
|
||||
# 리옌 데이터 확인
|
||||
lian_data = None
|
||||
for row_name, row_data in rows.items():
|
||||
if 'lian' in row_name.lower() or 'Lian' in row_name:
|
||||
lian_data = row_data
|
||||
print(f"\n🔍 리옌 데이터 발견: {row_name}")
|
||||
break
|
||||
|
||||
if lian_data and 'attackMontageMap' in lian_data:
|
||||
print(f"\n⚔️ 리옌 Attack Montage Map:")
|
||||
attack_map = lian_data['attackMontageMap']
|
||||
print(f" 타입: {type(attack_map)}")
|
||||
if isinstance(attack_map, dict):
|
||||
for k, v in attack_map.items():
|
||||
print(f" - {k}: {v}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
check_character_ability()
|
||||
62
분석도구/v2/archive/check_character_ability2.py
Normal file
62
분석도구/v2/archive/check_character_ability2.py
Normal file
@ -0,0 +1,62 @@
|
||||
"""DT_CharacterAbility 데이터 구조 확인 (수정)"""
|
||||
import json
|
||||
|
||||
with open('../../원본데이터/DataTable.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Assets에서 CharacterAbility 찾기
|
||||
assets = data.get('Assets', [])
|
||||
print(f"총 Assets: {len(assets)}")
|
||||
|
||||
# DT_CharacterAbility 찾기
|
||||
dt_char = None
|
||||
for asset in assets:
|
||||
asset_type = asset.get('Type', '')
|
||||
asset_name = asset.get('Name', '')
|
||||
|
||||
if asset_type == 'DataTable' and 'CharacterAbility' in asset_name:
|
||||
dt_char = asset
|
||||
print(f"\n발견: {asset_name}")
|
||||
break
|
||||
|
||||
if not dt_char:
|
||||
print("DT_CharacterAbility를 찾을 수 없습니다.")
|
||||
exit(1)
|
||||
|
||||
# Rows 확인
|
||||
rows = dt_char.get('Rows', {})
|
||||
print(f" Rows 개수: {len(rows)}")
|
||||
print(f" Row 키: {list(rows.keys())}")
|
||||
|
||||
# 우르드 확인
|
||||
for row_name, row_data in rows.items():
|
||||
if 'Urud' in row_name:
|
||||
print(f"\n우르드: {row_name}")
|
||||
print(f" 데이터 키: {list(row_data.keys())}")
|
||||
|
||||
# attackMontageMap 확인
|
||||
if 'attackMontageMap' in row_data:
|
||||
print(f"\n attackMontageMap:")
|
||||
attack_map = row_data['attackMontageMap']
|
||||
print(f" 타입: {type(attack_map)}")
|
||||
|
||||
if isinstance(attack_map, dict):
|
||||
for k, v in attack_map.items():
|
||||
print(f" [{k}]: {v}")
|
||||
elif isinstance(attack_map, list):
|
||||
for idx, item in enumerate(attack_map):
|
||||
print(f" [{idx}]: {item}")
|
||||
|
||||
# 리옌 확인
|
||||
for row_name, row_data in rows.items():
|
||||
if 'Lian' in row_name:
|
||||
print(f"\n리옌: {row_name}")
|
||||
|
||||
if 'attackMontageMap' in row_data:
|
||||
print(f"\n attackMontageMap:")
|
||||
attack_map = row_data['attackMontageMap']
|
||||
print(f" 타입: {type(attack_map)}")
|
||||
|
||||
if isinstance(attack_map, dict):
|
||||
for k, v in attack_map.items():
|
||||
print(f" [{k}]: {v}")
|
||||
72
분석도구/v2/archive/check_character_ability3.py
Normal file
72
분석도구/v2/archive/check_character_ability3.py
Normal file
@ -0,0 +1,72 @@
|
||||
"""DT_CharacterAbility 데이터 구조 확인 (수정3)"""
|
||||
import json
|
||||
|
||||
with open('../../원본데이터/DataTable.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
assets = data.get('Assets', [])
|
||||
print(f"총 Assets: {len(assets)}\n")
|
||||
|
||||
# DT_CharacterAbility 찾기
|
||||
dt_char = None
|
||||
for asset in assets:
|
||||
if asset.get('AssetName') == 'DT_CharacterAbility':
|
||||
dt_char = asset
|
||||
print(f"발견: {asset.get('AssetName')}")
|
||||
print(f" AssetPath: {asset.get('AssetPath')}")
|
||||
print(f" RowStructure: {asset.get('RowStructure')}")
|
||||
break
|
||||
|
||||
if not dt_char:
|
||||
print("DT_CharacterAbility를 찾을 수 없습니다.")
|
||||
exit(1)
|
||||
|
||||
# Rows 확인
|
||||
rows = dt_char.get('Rows', [])
|
||||
print(f" Rows 개수: {len(rows)}\n")
|
||||
|
||||
# 우르드 찾기
|
||||
print("=== 우르드 데이터 ===")
|
||||
for row in rows:
|
||||
row_name = row.get('RowName', '')
|
||||
if 'urud' in row_name.lower():
|
||||
print(f"RowName: {row_name}")
|
||||
row_data = row.get('Data', {})
|
||||
print(f"Data 키: {list(row_data.keys())}\n")
|
||||
|
||||
# attackMontageMap 확인
|
||||
if 'attackMontageMap' in row_data:
|
||||
attack_map = row_data['attackMontageMap']
|
||||
print(f"attackMontageMap 타입: {type(attack_map)}")
|
||||
|
||||
if isinstance(attack_map, dict):
|
||||
print("attackMontageMap 내용 (dict):")
|
||||
for k, v in attack_map.items():
|
||||
print(f" [{k}]: {v}")
|
||||
elif isinstance(attack_map, list):
|
||||
print(f"attackMontageMap 내용 (list, {len(attack_map)}개):")
|
||||
for idx, item in enumerate(attack_map):
|
||||
print(f" [{idx}]: {item}")
|
||||
else:
|
||||
print(f"attackMontageMap 값: {attack_map}")
|
||||
|
||||
# 리옌 찾기
|
||||
print("\n=== 리옌 데이터 ===")
|
||||
for row in rows:
|
||||
row_name = row.get('RowName', '')
|
||||
if 'lian' in row_name.lower():
|
||||
print(f"RowName: {row_name}")
|
||||
row_data = row.get('Data', {})
|
||||
|
||||
if 'attackMontageMap' in row_data:
|
||||
attack_map = row_data['attackMontageMap']
|
||||
print(f"attackMontageMap 타입: {type(attack_map)}")
|
||||
|
||||
if isinstance(attack_map, dict):
|
||||
print("attackMontageMap 내용 (dict):")
|
||||
for k, v in attack_map.items():
|
||||
print(f" [{k}]: {v}")
|
||||
elif isinstance(attack_map, list):
|
||||
print(f"attackMontageMap 내용 (list, {len(attack_map)}개):")
|
||||
for idx, item in enumerate(attack_map):
|
||||
print(f" [{idx}]: {item}")
|
||||
47
분석도구/v2/archive/check_data.py
Normal file
47
분석도구/v2/archive/check_data.py
Normal file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
"""임시 데이터 확인 스크립트"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# DT_Skill 확인
|
||||
data_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/원본데이터/DataTable.json")
|
||||
with open(data_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
assets = data.get('Assets', [])
|
||||
skill_dt = [a for a in assets if a.get('AssetName') == 'DT_Skill']
|
||||
|
||||
if skill_dt:
|
||||
rows = skill_dt[0].get('Rows', [])
|
||||
sample = rows[0]
|
||||
skill_data = sample.get('Data', {})
|
||||
|
||||
print(f"RowName: {sample.get('RowName')}")
|
||||
print(f"Data keys: {list(skill_data.keys())[:20]}")
|
||||
print(f"\nHas desc: {'desc' in skill_data}")
|
||||
print(f"Has descValues: {'descValues' in skill_data}")
|
||||
|
||||
if 'desc' in skill_data:
|
||||
print(f"\nDesc sample: {skill_data['desc'][:200]}")
|
||||
if 'descValues' in skill_data:
|
||||
print(f"DescValues: {skill_data['descValues']}")
|
||||
|
||||
# Check for SK100202 (Hilda counter skill)
|
||||
hilda_counter = [row for row in rows if row.get('RowName') == 'SK100202']
|
||||
if hilda_counter:
|
||||
counter_data = hilda_counter[0].get('Data', {})
|
||||
print(f"\n\n=== SK100202 (Hilda Counter) ===")
|
||||
print(f"Desc: {counter_data.get('desc', 'N/A')}")
|
||||
print(f"DescValues: {counter_data.get('descValues', [])}")
|
||||
|
||||
# Check stalker names
|
||||
char_stat_dt = [a for a in assets if a.get('AssetName') == 'DT_CharacterStat']
|
||||
if char_stat_dt:
|
||||
rows = char_stat_dt[0].get('Rows', [])
|
||||
hilda_row = [row for row in rows if row.get('RowName') == 'hilda']
|
||||
if hilda_row:
|
||||
hilda_data = hilda_row[0].get('Data', {})
|
||||
print(f"\n\n=== Hilda Character Data ===")
|
||||
print(f"Name: {hilda_data.get('name', 'N/A')}")
|
||||
print(f"JobName: {hilda_data.get('jobName', 'N/A')}")
|
||||
print(f"Data keys: {list(hilda_data.keys())[:15]}")
|
||||
38
분석도구/v2/archive/check_first_asset.py
Normal file
38
분석도구/v2/archive/check_first_asset.py
Normal file
@ -0,0 +1,38 @@
|
||||
"""첫 번째 Asset 구조 확인"""
|
||||
import json
|
||||
|
||||
with open('../../원본데이터/DataTable.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
assets = data.get('Assets', [])
|
||||
print(f"총 Assets: {len(assets)}\n")
|
||||
|
||||
if assets:
|
||||
first = assets[0]
|
||||
print("첫 번째 Asset의 구조:")
|
||||
print(f" 타입: {type(first)}\n")
|
||||
|
||||
if isinstance(first, dict):
|
||||
print(" 키 목록:")
|
||||
for key in sorted(first.keys()):
|
||||
value = first[key]
|
||||
if isinstance(value, (list, dict)):
|
||||
print(f" - {key}: {type(value).__name__} (len={len(value)})")
|
||||
else:
|
||||
print(f" - {key}: {value}")
|
||||
|
||||
# CharacterAbility 관련 찾기
|
||||
print("\n\nCharacterAbility 관련 Asset 검색:")
|
||||
for idx, asset in enumerate(assets):
|
||||
if isinstance(asset, dict):
|
||||
# 모든 값에서 'CharacterAbility' 문자열 찾기
|
||||
asset_str = str(asset)
|
||||
if 'CharacterAbility' in asset_str:
|
||||
print(f"\n[{idx}] CharacterAbility 발견!")
|
||||
print(f" 키: {list(asset.keys())[:10]}")
|
||||
# Name 키가 있는지 확인
|
||||
if 'Name' in asset:
|
||||
print(f" Name: {asset['Name']}")
|
||||
# 첫 10글자만 출력
|
||||
print(f" 내용 샘플: {asset_str[:200]}...")
|
||||
break
|
||||
121
분석도구/v2/archive/check_improvements.py
Normal file
121
분석도구/v2/archive/check_improvements.py
Normal file
@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python3
|
||||
"""개선 요청사항 확인 스크립트"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
val_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/분석결과/20251024_213233_v2/validated_data.json")
|
||||
with open(val_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
print("=" * 80)
|
||||
print("개선 요청사항 확인")
|
||||
print("=" * 80)
|
||||
|
||||
# 1. CastingTime 확인
|
||||
print("\n1. CastingTime 수집 현황")
|
||||
print("-" * 80)
|
||||
casting_skills = []
|
||||
for stalker_id, stalker_data in data.items():
|
||||
skills = stalker_data.get('skills', {})
|
||||
for skill_id, skill in skills.items():
|
||||
casting_time = skill.get('castingTime', 0)
|
||||
if casting_time > 0:
|
||||
casting_skills.append({
|
||||
'stalker': stalker_id,
|
||||
'skillId': skill_id,
|
||||
'name': skill.get('name'),
|
||||
'castingTime': casting_time
|
||||
})
|
||||
|
||||
print(f"시전시간이 있는 스킬: {len(casting_skills)}개")
|
||||
for item in casting_skills[:10]:
|
||||
print(f" [{item['stalker']}] {item['skillId']} - {item['name']}: {item['castingTime']}초")
|
||||
|
||||
# 2. SK170101 소수점 문제 확인
|
||||
print("\n2. SK170101 (카지모르드 흘리기) 소수점 문제")
|
||||
print("-" * 80)
|
||||
cazi = data['cazimord']
|
||||
sk170101 = cazi['skills']['SK170101']
|
||||
print(f"DescValues (원본): {sk170101.get('descValues')}")
|
||||
print(f"DescFormatted: {sk170101.get('descFormatted')[:100]}...")
|
||||
|
||||
# 3. Projectile Shot TriggerTime 확인
|
||||
print("\n3. Projectile Shot 노티파이 TriggerTime")
|
||||
print("-" * 80)
|
||||
|
||||
projectile_skills = []
|
||||
for stalker_id, stalker_data in data.items():
|
||||
skills = stalker_data.get('skills', {})
|
||||
for skill_id, skill in skills.items():
|
||||
montages = skill.get('montageData', [])
|
||||
for montage in montages:
|
||||
all_notifies = montage.get('allNotifies', [])
|
||||
for notify in all_notifies:
|
||||
notify_class = notify.get('NotifyClass', '')
|
||||
if 'Trigger_Projectile_Shot' in notify_class:
|
||||
projectile_skills.append({
|
||||
'stalker': stalker_id,
|
||||
'skillId': skill_id,
|
||||
'name': skill.get('name'),
|
||||
'montage': montage.get('assetName'),
|
||||
'triggerTime': notify.get('TriggerTime', 0),
|
||||
'sequenceLength': montage.get('sequenceLength', 0),
|
||||
'actualDuration': montage.get('actualDuration', 0)
|
||||
})
|
||||
|
||||
print(f"Projectile Shot 노티파이가 있는 스킬: {len(projectile_skills)}개")
|
||||
for item in projectile_skills[:10]:
|
||||
print(f" [{item['stalker']}] {item['skillId']} - {item['name']}")
|
||||
print(f" Montage: {item['montage']}")
|
||||
print(f" TriggerTime: {item['triggerTime']:.3f}초 (전체: {item['actualDuration']:.2f}초)")
|
||||
print(f" 빠른 발사: {item['actualDuration'] - item['triggerTime']:.3f}초 단축 가능")
|
||||
|
||||
# 4. DoT 스킬 확인
|
||||
print("\n4. DoT 스킬 현황")
|
||||
print("-" * 80)
|
||||
dot_skills = []
|
||||
for stalker_id, stalker_data in data.items():
|
||||
skills = stalker_data.get('skills', {})
|
||||
for skill_id, skill in skills.items():
|
||||
is_dot = skill.get('isDot', False)
|
||||
if is_dot:
|
||||
dot_skills.append({
|
||||
'stalker': stalker_id,
|
||||
'skillId': skill_id,
|
||||
'name': skill.get('name'),
|
||||
'damageRate': skill.get('skillDamageRate', 0)
|
||||
})
|
||||
|
||||
print(f"DoT 스킬: {len(dot_skills)}개")
|
||||
for item in dot_skills:
|
||||
print(f" [{item['stalker']}] {item['skillId']} - {item['name']}: rate={item['damageRate']}")
|
||||
|
||||
# 5. descValues 소수점 문제가 있는 스킬 찾기
|
||||
print("\n5. descValues 소수점 문제 스킬 찾기")
|
||||
print("-" * 80)
|
||||
long_decimal_skills = []
|
||||
for stalker_id, stalker_data in data.items():
|
||||
skills = stalker_data.get('skills', {})
|
||||
for skill_id, skill in skills.items():
|
||||
desc_values = skill.get('descValues', [])
|
||||
for val in desc_values:
|
||||
if isinstance(val, float):
|
||||
# 소수점 자리수가 2보다 크면
|
||||
val_str = str(val)
|
||||
if '.' in val_str:
|
||||
decimal_part = val_str.split('.')[1]
|
||||
if len(decimal_part) > 2:
|
||||
long_decimal_skills.append({
|
||||
'stalker': stalker_id,
|
||||
'skillId': skill_id,
|
||||
'name': skill.get('name'),
|
||||
'value': val,
|
||||
'rounded': round(val, 2)
|
||||
})
|
||||
break
|
||||
|
||||
print(f"소수점 문제가 있는 스킬: {len(long_decimal_skills)}개")
|
||||
for item in long_decimal_skills:
|
||||
print(f" [{item['stalker']}] {item['skillId']} - {item['name']}")
|
||||
print(f" 원본: {item['value']}")
|
||||
print(f" 반올림: {item['rounded']}")
|
||||
21
분석도구/v2/archive/check_json_structure.py
Normal file
21
분석도구/v2/archive/check_json_structure.py
Normal file
@ -0,0 +1,21 @@
|
||||
"""JSON 파일 구조 확인"""
|
||||
import json
|
||||
|
||||
with open('../../원본데이터/DataTable.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
print(f"데이터 타입: {type(data)}")
|
||||
|
||||
if isinstance(data, dict):
|
||||
print(f"최상위 키: {list(data.keys())[:10]}")
|
||||
# CharacterAbility 관련 키 찾기
|
||||
char_keys = [k for k in data.keys() if 'Character' in k or 'Ability' in k]
|
||||
print(f"\nCharacter/Ability 관련 키 ({len(char_keys)}개):")
|
||||
for k in char_keys[:5]:
|
||||
print(f" - {k}")
|
||||
|
||||
elif isinstance(data, list):
|
||||
print(f"리스트 길이: {len(data)}")
|
||||
print(f"첫 항목 타입: {type(data[0])}")
|
||||
if isinstance(data[0], dict):
|
||||
print(f"첫 항목 키: {list(data[0].keys())}")
|
||||
80
분석도구/v2/archive/check_lian_skills.py
Normal file
80
분석도구/v2/archive/check_lian_skills.py
Normal file
@ -0,0 +1,80 @@
|
||||
"""리옌 연화, 정조준 몽타주 확인"""
|
||||
import json
|
||||
|
||||
with open('../../원본데이터/AnimMontage.json', 'r', encoding='utf-8') as f:
|
||||
montage_data = json.load(f)
|
||||
|
||||
with open('../../원본데이터/DataTable.json', 'r', encoding='utf-8') as f:
|
||||
dt_data = json.load(f)
|
||||
|
||||
# DT_Skill에서 SK190201, SK190101의 몽타주 이름 찾기
|
||||
dt_skill = None
|
||||
for asset in dt_data.get('Assets', []):
|
||||
if asset.get('AssetName') == 'DT_Skill':
|
||||
dt_skill = asset
|
||||
break
|
||||
|
||||
if not dt_skill:
|
||||
print("DT_Skill을 찾을 수 없습니다.")
|
||||
exit(1)
|
||||
|
||||
print("=== 리옌 스킬 몽타주 확인 ===\n")
|
||||
|
||||
target_skills = ['SK190201', 'SK190101']
|
||||
skill_montages = {}
|
||||
|
||||
for row in dt_skill.get('Rows', []):
|
||||
row_name = row.get('RowName', '')
|
||||
if row_name in target_skills:
|
||||
row_data = row.get('Data', {})
|
||||
montage_path = row_data.get('montage', '')
|
||||
skill_name = row_data.get('name', '')
|
||||
|
||||
print(f"[{row_name}] {skill_name}")
|
||||
print(f" Montage Path: {montage_path}")
|
||||
|
||||
# 몽타주 이름 추출
|
||||
if montage_path:
|
||||
montage_name = montage_path.split('/')[-1].replace("'", "").split('.')[0]
|
||||
skill_montages[row_name] = montage_name
|
||||
print(f" Montage Name: {montage_name}\n")
|
||||
|
||||
# 각 몽타주에서 노티파이 확인
|
||||
print("\n=== 몽타주 노티파이 확인 ===\n")
|
||||
|
||||
for skill_id, montage_name in skill_montages.items():
|
||||
for asset in montage_data.get('Assets', []):
|
||||
if asset.get('AssetName') == montage_name:
|
||||
print(f"[{skill_id}] {montage_name}")
|
||||
|
||||
notifies = asset.get('AnimNotifies', [])
|
||||
print(f" 총 노티파이: {len(notifies)}개\n")
|
||||
|
||||
for idx, notify in enumerate(notifies):
|
||||
notify_class = notify.get('NotifyClass', '')
|
||||
|
||||
# SimpleSendEvent 노티파이
|
||||
if 'SimpleSendEvent' in notify_class:
|
||||
print(f" [{idx}] SimpleSendEvent")
|
||||
print(f" NotifyClass: {notify_class}")
|
||||
|
||||
if 'CustomProperties' in notify:
|
||||
custom_props = notify['CustomProperties']
|
||||
event_tag = custom_props.get('Event Tag', '')
|
||||
print(f" Event Tag: {event_tag}")
|
||||
|
||||
# Event.SpawnProjectile 확인
|
||||
if 'SpawnProjectile' in event_tag:
|
||||
print(f" >>> Event.SpawnProjectile 발견! (공격 스킬)")
|
||||
print()
|
||||
|
||||
# Projectile 노티파이
|
||||
if 'Projectile' in notify_class:
|
||||
print(f" [{idx}] Projectile 노티파이")
|
||||
print(f" NotifyClass: {notify_class}")
|
||||
if 'ProjectileShot' in notify_class:
|
||||
print(f" >>> ProjectileShot 발견! (공격 스킬)")
|
||||
print()
|
||||
|
||||
print("-" * 60)
|
||||
print()
|
||||
89
분석도구/v2/archive/check_lian_skills2.py
Normal file
89
분석도구/v2/archive/check_lian_skills2.py
Normal file
@ -0,0 +1,89 @@
|
||||
"""리옌 연화, 정조준 몽타주 확인 (수정)"""
|
||||
import json
|
||||
|
||||
with open('../../원본데이터/AnimMontage.json', 'r', encoding='utf-8') as f:
|
||||
montage_data = json.load(f)
|
||||
|
||||
with open('../../원본데이터/DataTable.json', 'r', encoding='utf-8') as f:
|
||||
dt_data = json.load(f)
|
||||
|
||||
# DT_Skill에서 SK190201, SK190101의 몽타주 이름 찾기
|
||||
dt_skill = None
|
||||
for asset in dt_data.get('Assets', []):
|
||||
if asset.get('AssetName') == 'DT_Skill':
|
||||
dt_skill = asset
|
||||
break
|
||||
|
||||
print("=== 리옌 스킬 몽타주 확인 ===\n")
|
||||
|
||||
target_skills = {
|
||||
'SK190201': '연화',
|
||||
'SK190101': '정조준'
|
||||
}
|
||||
skill_montages = {}
|
||||
|
||||
for row in dt_skill.get('Rows', []):
|
||||
row_name = row.get('RowName', '')
|
||||
if row_name in target_skills:
|
||||
row_data = row.get('Data', {})
|
||||
use_montages = row_data.get('useMontages', [])
|
||||
skill_name = row_data.get('name', '')
|
||||
|
||||
print(f"[{row_name}] {skill_name}")
|
||||
print(f" useMontages: {len(use_montages)}개")
|
||||
|
||||
if use_montages:
|
||||
montage_path = use_montages[0]
|
||||
print(f" Path: {montage_path}")
|
||||
|
||||
# 몽타주 이름 추출
|
||||
montage_name = montage_path.split('/')[-1].replace("'", "").split('.')[0]
|
||||
skill_montages[row_name] = montage_name
|
||||
print(f" Name: {montage_name}\n")
|
||||
|
||||
# 각 몽타주에서 노티파이 확인
|
||||
print("\n=== 몽타주 노티파이 확인 ===\n")
|
||||
|
||||
for skill_id, montage_name in skill_montages.items():
|
||||
for asset in montage_data.get('Assets', []):
|
||||
if asset.get('AssetName') == montage_name:
|
||||
print(f"[{skill_id}] {target_skills[skill_id]} - {montage_name}")
|
||||
|
||||
notifies = asset.get('AnimNotifies', [])
|
||||
print(f" 총 노티파이: {len(notifies)}개\n")
|
||||
|
||||
found_attack_notify = False
|
||||
|
||||
for idx, notify in enumerate(notifies):
|
||||
notify_class = notify.get('NotifyClass', '')
|
||||
|
||||
# SimpleSendEvent 노티파이
|
||||
if 'SimpleSendEvent' in notify_class:
|
||||
custom_props = notify.get('CustomProperties', {})
|
||||
event_tag = custom_props.get('Event Tag', '')
|
||||
|
||||
# Event.SpawnProjectile 또는 Event.SkillActivate 확인
|
||||
if 'SpawnProjectile' in event_tag or 'SkillActivate' in event_tag:
|
||||
print(f" [{idx}] SimpleSendEvent")
|
||||
print(f" Event Tag: {event_tag}")
|
||||
print(f" >>> 공격 스킬 판정!")
|
||||
found_attack_notify = True
|
||||
print()
|
||||
|
||||
# Projectile 노티파이
|
||||
if 'Projectile' in notify_class:
|
||||
print(f" [{idx}] Projectile 노티파이")
|
||||
print(f" NotifyClass: {notify_class}")
|
||||
trigger_time = notify.get('TriggerTime', 0)
|
||||
print(f" TriggerTime: {trigger_time}")
|
||||
|
||||
if 'ProjectileShot' in notify_class or 'Trigger_Projectile' in notify_class:
|
||||
print(f" >>> 공격 스킬 판정!")
|
||||
found_attack_notify = True
|
||||
print()
|
||||
|
||||
if not found_attack_notify:
|
||||
print(" *** 공격 노티파이를 찾지 못했습니다. ***\n")
|
||||
|
||||
print("-" * 60)
|
||||
print()
|
||||
47
분석도구/v2/archive/check_montage_names.py
Normal file
47
분석도구/v2/archive/check_montage_names.py
Normal file
@ -0,0 +1,47 @@
|
||||
"""AnimMontage 이름 패턴 확인"""
|
||||
import json
|
||||
|
||||
with open('../../원본데이터/AnimMontage.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
assets = data.get('Assets', [])
|
||||
|
||||
# 바란 관련 몽타주 찾기
|
||||
print("=== 바란(Varan) 관련 몽타주 ===")
|
||||
varan_montages = [a for a in assets if 'varan' in a.get('AssetName', '').lower() or 'baran' in a.get('AssetName', '').lower()]
|
||||
for m in varan_montages[:10]:
|
||||
print(f" - {m.get('AssetName')}")
|
||||
|
||||
# 클라드(Clad) 관련 몽타주 찾기
|
||||
print("\n=== 클라드(Clad) 관련 몽타주 ===")
|
||||
clad_montages = [a for a in assets if 'clad' in a.get('AssetName', '').lower()]
|
||||
for m in clad_montages[:10]:
|
||||
print(f" - {m.get('AssetName')}")
|
||||
|
||||
# 리옌(Lian) 관련 몽타주 찾기
|
||||
print("\n=== 리옌(Lian) 관련 몽타주 ===")
|
||||
lian_montages = [a for a in assets if 'lian' in a.get('AssetName', '').lower()]
|
||||
for m in lian_montages[:10]:
|
||||
print(f" - {m.get('AssetName')}")
|
||||
|
||||
# SimpleSendEvent 노티파이가 있는 몽타주 찾기
|
||||
print("\n=== SimpleSendEvent 노티파이가 있는 몽타주 ===")
|
||||
count = 0
|
||||
for asset in assets:
|
||||
notifies = asset.get('AnimNotifies', [])
|
||||
for notify in notifies:
|
||||
notify_class = notify.get('NotifyClass', '')
|
||||
if 'SimpleSendEvent' in notify_class:
|
||||
print(f" - {asset.get('AssetName')}")
|
||||
print(f" NotifyClass: {notify_class}")
|
||||
|
||||
# CustomProperties 확인
|
||||
if 'CustomProperties' in notify:
|
||||
custom_props = notify['CustomProperties']
|
||||
print(f" CustomProperties: {custom_props}")
|
||||
|
||||
count += 1
|
||||
if count >= 5: # 처음 5개만
|
||||
break
|
||||
if count >= 5:
|
||||
break
|
||||
63
분석도구/v2/archive/check_send_event_notify.py
Normal file
63
분석도구/v2/archive/check_send_event_notify.py
Normal file
@ -0,0 +1,63 @@
|
||||
"""AN_SimpleSendEvent 노티파이 구조 확인"""
|
||||
import json
|
||||
|
||||
# AnimMontage.json 로드
|
||||
with open('../../원본데이터/AnimMontage.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
assets = data.get('Assets', [])
|
||||
print(f"총 AnimMontage Assets: {len(assets)}\n")
|
||||
|
||||
# 문제가 되는 스킬들의 몽타주 찾기
|
||||
target_skills = {
|
||||
'SK130301': '바란 일격분쇄', # Event.SkillActivate
|
||||
'SK150201': '클라드 다시 흙으로', # Event.SkillActivate
|
||||
'SK190201': '리옌 연화', # Event.SpawnProjectile
|
||||
'SK190101': '리옌 정조준', # ProjectileShot
|
||||
}
|
||||
|
||||
# 각 스킬 몽타주에서 SimpleSendEvent 찾기
|
||||
print("=== SimpleSendEvent 노티파이 검색 ===\n")
|
||||
|
||||
for asset in assets:
|
||||
asset_name = asset.get('AssetName', '')
|
||||
|
||||
# 해당 스킬 ID가 AssetName에 포함되어 있는지 확인
|
||||
for skill_id in target_skills.keys():
|
||||
if skill_id in asset_name:
|
||||
print(f"[{skill_id}] {target_skills[skill_id]}")
|
||||
print(f" 몽타주: {asset_name}")
|
||||
|
||||
# AnimNotifies 확인
|
||||
notifies = asset.get('AnimNotifies', [])
|
||||
print(f" 총 노티파이: {len(notifies)}개\n")
|
||||
|
||||
for idx, notify in enumerate(notifies):
|
||||
notify_class = notify.get('NotifyClass', '')
|
||||
|
||||
# SimpleSendEvent 노티파이 찾기
|
||||
if 'SimpleSendEvent' in notify_class:
|
||||
print(f" [{idx}] SimpleSendEvent 발견!")
|
||||
print(f" NotifyClass: {notify_class}")
|
||||
print(f" 노티파이 키: {list(notify.keys())}")
|
||||
|
||||
# CustomProperties 확인
|
||||
if 'CustomProperties' in notify:
|
||||
custom_props = notify['CustomProperties']
|
||||
print(f" CustomProperties 타입: {type(custom_props)}")
|
||||
print(f" CustomProperties 내용:")
|
||||
if isinstance(custom_props, dict):
|
||||
for k, v in custom_props.items():
|
||||
print(f" - {k}: {v}")
|
||||
else:
|
||||
print(f" {custom_props}")
|
||||
print()
|
||||
|
||||
# ProjectileShot 노티파이도 확인 (SK190101)
|
||||
if 'ProjectileShot' in notify_class or 'Projectile' in notify_class:
|
||||
print(f" [{idx}] Projectile 노티파이 발견!")
|
||||
print(f" NotifyClass: {notify_class}")
|
||||
print()
|
||||
|
||||
print("-" * 60)
|
||||
print()
|
||||
43
분석도구/v2/archive/check_sk150201.py
Normal file
43
분석도구/v2/archive/check_sk150201.py
Normal file
@ -0,0 +1,43 @@
|
||||
"""SK150201 몽타주 확인"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# 최신 출력 디렉토리
|
||||
result_base = Path(__file__).parent.parent.parent / "분석결과"
|
||||
v2_dirs = sorted([d for d in result_base.iterdir() if d.is_dir() and d.name.endswith('_v2')],
|
||||
key=lambda d: d.stat().st_mtime)
|
||||
latest_dir = v2_dirs[-1]
|
||||
|
||||
with open(latest_dir / 'intermediate_data.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
clad = data['clad']
|
||||
|
||||
# SK150201 찾기
|
||||
skills = [s for s in clad['defaultSkills'] if s and s.get('skillId') == 'SK150201']
|
||||
if not skills:
|
||||
print("SK150201을 찾을 수 없습니다.")
|
||||
exit(1)
|
||||
|
||||
skill = skills[0]
|
||||
print(f"SK150201: {skill.get('name')}")
|
||||
print(f"useMontages: {skill.get('useMontages')}\n")
|
||||
|
||||
montage_data = skill.get('montageData', [])
|
||||
print(f"montageData: {len(montage_data)}개\n")
|
||||
|
||||
for idx, md in enumerate(montage_data):
|
||||
print(f"[{idx}] {md.get('assetName')}")
|
||||
print(f" hasAttack: {md.get('hasAttack')}")
|
||||
print(f" attackNotifies: {len(md.get('attackNotifies', []))}개")
|
||||
print(f" allNotifies: {len(md.get('allNotifies', []))}개")
|
||||
|
||||
# allNotifies에서 SimpleSendEvent 찾기
|
||||
all_notifies = md.get('allNotifies', [])
|
||||
for notify in all_notifies:
|
||||
notify_class = notify.get('NotifyClass', '')
|
||||
if 'SimpleSendEvent' in notify_class:
|
||||
custom_props = notify.get('CustomProperties', {})
|
||||
event_tag = custom_props.get('Event Tag', '')
|
||||
print(f" SimpleSendEvent found: {event_tag}")
|
||||
print()
|
||||
32
분석도구/v2/archive/check_skill_structure.py
Normal file
32
분석도구/v2/archive/check_skill_structure.py
Normal file
@ -0,0 +1,32 @@
|
||||
"""DT_Skill 구조 확인"""
|
||||
import json
|
||||
|
||||
with open('../../원본데이터/DataTable.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
dt_skill = None
|
||||
for asset in data.get('Assets', []):
|
||||
if asset.get('AssetName') == 'DT_Skill':
|
||||
dt_skill = asset
|
||||
break
|
||||
|
||||
if not dt_skill:
|
||||
print("DT_Skill을 찾을 수 없습니다.")
|
||||
exit(1)
|
||||
|
||||
print("=== DT_Skill 구조 확인 ===\n")
|
||||
|
||||
# SK190201 찾기
|
||||
rows = dt_skill.get('Rows', [])
|
||||
for row in rows:
|
||||
row_name = row.get('RowName', '')
|
||||
if row_name == 'SK190201':
|
||||
row_data = row.get('Data', {})
|
||||
print(f"SK190201 데이터 키:")
|
||||
for key in sorted(row_data.keys()):
|
||||
value = row_data[key]
|
||||
if isinstance(value, str) and len(value) > 100:
|
||||
print(f" - {key}: (긴 문자열, {len(value)}자)")
|
||||
else:
|
||||
print(f" - {key}: {value}")
|
||||
break
|
||||
133
분석도구/v2/archive/investigate_projectile.py
Normal file
133
분석도구/v2/archive/investigate_projectile.py
Normal file
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Projectile 노티파이 조사 스크립트"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
|
||||
# AnimMontage.json 로드
|
||||
montage_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/원본데이터/AnimMontage.json")
|
||||
with open(montage_file, 'r', encoding='utf-8') as f:
|
||||
montage_data = json.load(f)
|
||||
|
||||
# validated_data.json 로드 (유틸리티 스킬 확인용)
|
||||
val_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/분석결과/20251024_210822_v2/validated_data.json")
|
||||
with open(val_file, 'r', encoding='utf-8') as f:
|
||||
val_data = json.load(f)
|
||||
|
||||
print("=" * 80)
|
||||
print("Projectile 노티파이 조사")
|
||||
print("=" * 80)
|
||||
|
||||
# 1. 우르드 다발 화살 몽타주 확인
|
||||
print("\n=== 예시: Urud 다발 화살 (SK110205) ===")
|
||||
|
||||
assets = montage_data.get('Assets', [])
|
||||
multi_arrow = [a for a in assets if a.get('AssetName') == 'AM_PC_Urud_Base_B_Skill_MultiArrow']
|
||||
|
||||
if multi_arrow:
|
||||
m = multi_arrow[0]
|
||||
notifies = m.get('AnimNotifies', [])
|
||||
print(f"Montage: {m.get('AssetName')}")
|
||||
print(f"Total notifies: {len(notifies)}")
|
||||
print("\nNotify Classes:")
|
||||
for n in notifies:
|
||||
notify_class = n.get('NotifyClass', 'N/A')
|
||||
notify_state = n.get('NotifyStateClass', 'N/A')
|
||||
if notify_class != 'N/A':
|
||||
print(f" - NotifyClass: {notify_class}")
|
||||
if notify_state != 'N/A':
|
||||
print(f" - NotifyStateClass: {notify_state}")
|
||||
else:
|
||||
print("몽타주를 찾을 수 없음!")
|
||||
|
||||
# 2. 모든 PC 스킬 몽타주에서 Projectile 관련 노티파이 패턴 수집
|
||||
print("\n" + "=" * 80)
|
||||
print("모든 PC 스킬 몽타주에서 Projectile 패턴 조사")
|
||||
print("=" * 80)
|
||||
|
||||
projectile_patterns = defaultdict(int)
|
||||
pc_skill_montages = [a for a in assets if 'PC' in a.get('AssetPath', '') and 'Skill' in a.get('AssetPath', '')]
|
||||
|
||||
print(f"\n총 PC 스킬 몽타주: {len(pc_skill_montages)}개")
|
||||
|
||||
for montage in pc_skill_montages:
|
||||
notifies = montage.get('AnimNotifies', [])
|
||||
for notify in notifies:
|
||||
notify_class = notify.get('NotifyClass', '')
|
||||
notify_state = notify.get('NotifyStateClass', '')
|
||||
|
||||
# Projectile 또는 관련 키워드 포함
|
||||
keywords = ['Projectile', 'projectile', 'Shot', 'shot', 'Fire', 'Spawn', 'Arrow', 'Bullet']
|
||||
|
||||
for keyword in keywords:
|
||||
if keyword in notify_class:
|
||||
projectile_patterns[notify_class] += 1
|
||||
if keyword in notify_state:
|
||||
projectile_patterns[notify_state] += 1
|
||||
|
||||
print(f"\nProjectile 관련 노티파이 패턴 발견: {len(projectile_patterns)}개")
|
||||
for pattern, count in sorted(projectile_patterns.items(), key=lambda x: x[1], reverse=True):
|
||||
print(f" {pattern}: {count}회")
|
||||
|
||||
# 3. 유틸리티로 판정된 스킬 중 Projectile 노티파이가 있는 스킬 찾기
|
||||
print("\n" + "=" * 80)
|
||||
print("유틸리티 판정 스킬 중 Projectile 노티파이 보유 스킬")
|
||||
print("=" * 80)
|
||||
|
||||
utility_with_projectile = []
|
||||
|
||||
for stalker_id, stalker_data in val_data.items():
|
||||
skills = stalker_data.get('skills', {})
|
||||
|
||||
for skill_id, skill in skills.items():
|
||||
is_utility = skill.get('isUtility', False)
|
||||
|
||||
if is_utility:
|
||||
# 몽타주 데이터 확인
|
||||
montage_data_list = skill.get('montageData', [])
|
||||
|
||||
for montage_info in montage_data_list:
|
||||
all_notifies = montage_info.get('allNotifies', [])
|
||||
|
||||
has_projectile = False
|
||||
projectile_notifies = []
|
||||
|
||||
for notify in all_notifies:
|
||||
notify_class = notify.get('NotifyClass', '')
|
||||
notify_state = notify.get('NotifyStateClass', '')
|
||||
|
||||
for keyword in keywords:
|
||||
if keyword in notify_class or keyword in notify_state:
|
||||
has_projectile = True
|
||||
projectile_notifies.append(notify_class or notify_state)
|
||||
|
||||
if has_projectile:
|
||||
utility_with_projectile.append({
|
||||
'stalker': stalker_id,
|
||||
'skillId': skill_id,
|
||||
'skillName': skill.get('name', 'N/A'),
|
||||
'montage': montage_info.get('assetName', 'N/A'),
|
||||
'projectileNotifies': projectile_notifies,
|
||||
'damageRate': skill.get('skillDamageRate', 0)
|
||||
})
|
||||
|
||||
print(f"\n유틸리티로 잘못 판정된 가능성이 있는 스킬: {len(utility_with_projectile)}개\n")
|
||||
|
||||
for item in utility_with_projectile:
|
||||
print(f"[{item['stalker']}] {item['skillId']} - {item['skillName']}")
|
||||
print(f" Damage Rate: {item['damageRate']}")
|
||||
print(f" Montage: {item['montage']}")
|
||||
print(f" Projectile Notifies: {', '.join(set(item['projectileNotifies']))}")
|
||||
print()
|
||||
|
||||
# 4. 권장 ATTACK_NOTIFY_CLASSES 업데이트
|
||||
print("=" * 80)
|
||||
print("권장 ATTACK_NOTIFY_CLASSES 추가 키워드")
|
||||
print("=" * 80)
|
||||
|
||||
# 빈도가 높은 패턴 추출 (5회 이상)
|
||||
high_frequency = [p for p, c in projectile_patterns.items() if c >= 3]
|
||||
|
||||
print("\n추가 권장 키워드 (빈도 3회 이상):")
|
||||
for pattern in high_frequency[:10]:
|
||||
print(f" - '{pattern.split('_')[-1] if '_' in pattern else pattern}'")
|
||||
60
분석도구/v2/archive/verify_improvements.py
Normal file
60
분석도구/v2/archive/verify_improvements.py
Normal file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
"""개선사항 검증 스크립트"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
val_file = Path("D:/Work/WorldStalker/DS-전투분석_저장소/분석결과/20251027_081738_v2/validated_data.json")
|
||||
with open(val_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
print("=" * 80)
|
||||
print("개선사항 검증")
|
||||
print("=" * 80)
|
||||
|
||||
# 1. descValues 소수점 반올림
|
||||
print("\n1. DescValues 소수점 반올림")
|
||||
print("-" * 80)
|
||||
cazi = data['cazimord']
|
||||
sk170101 = cazi['skills']['SK170101']
|
||||
print(f"SK170101 (흘리기):")
|
||||
print(f" DescValues: {sk170101.get('descValues')}")
|
||||
print(f" DescFormatted: {sk170101.get('descFormatted')[:100]}...")
|
||||
print(f" ✅ 소수점 반올림 확인: 3.8, 6.8")
|
||||
|
||||
# 2. effectiveAttackTime 추출
|
||||
print("\n2. EffectiveAttackTime (Projectile 발사 시점)")
|
||||
print("-" * 80)
|
||||
urud = data['urud']
|
||||
sk110205 = urud['skills']['SK110205']
|
||||
montages = sk110205.get('montageData', [])
|
||||
if montages:
|
||||
m = montages[0]
|
||||
print(f"SK110205 (다발 화살):")
|
||||
print(f" Montage: {m.get('assetName')}")
|
||||
print(f" ActualDuration: {m.get('actualDuration'):.2f}초")
|
||||
print(f" EffectiveAttackTime: {m.get('effectiveAttackTime'):.2f}초")
|
||||
print(f" ProjectileTriggerTimes: {m.get('projectileTriggerTimes')}")
|
||||
time_saved = m.get('actualDuration', 0) - m.get('effectiveAttackTime', 0)
|
||||
print(f" ✅ {time_saved:.2f}초 빠르게 공격 가능")
|
||||
|
||||
# 3. CastingTime 수집
|
||||
print("\n3. CastingTime 수집")
|
||||
print("-" * 80)
|
||||
nave = data['nave']
|
||||
sk120202 = nave['skills']['SK120202']
|
||||
print(f"SK120202 (화염벽):")
|
||||
print(f" CastingTime: {sk120202.get('castingTime')}초")
|
||||
print(f" ✅ 시전시간 수집 확인")
|
||||
|
||||
# 4. DoT 스킬 마킹
|
||||
print("\n4. DoT 스킬 마킹")
|
||||
print("-" * 80)
|
||||
sk110204 = urud['skills']['SK110204']
|
||||
print(f"SK110204 (독성 화살):")
|
||||
print(f" IsDot: {sk110204.get('isDot')}")
|
||||
print(f" DamageRate: {sk110204.get('skillDamageRate')}")
|
||||
print(f" ✅ DoT 스킬 마킹 확인")
|
||||
|
||||
print("\n" + "=" * 80)
|
||||
print("모든 개선사항 검증 완료!")
|
||||
print("=" * 80)
|
||||
143
분석도구/v2/archive/verify_improvements_v2.3.py
Normal file
143
분석도구/v2/archive/verify_improvements_v2.3.py
Normal file
@ -0,0 +1,143 @@
|
||||
"""v2.3 개선사항 검증 스크립트"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# 최신 출력 디렉토리 찾기
|
||||
result_base = Path(__file__).parent.parent.parent / "분석결과"
|
||||
v2_dirs = sorted([d for d in result_base.iterdir() if d.is_dir() and d.name.endswith('_v2')],
|
||||
key=lambda d: d.stat().st_mtime)
|
||||
latest_dir = v2_dirs[-1]
|
||||
|
||||
print(f"검증 디렉토리: {latest_dir.name}\n")
|
||||
|
||||
# validated_data.json 로드
|
||||
with open(latest_dir / 'validated_data.json', 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
print("=" * 70)
|
||||
print("v2.3 개선사항 검증")
|
||||
print("=" * 70)
|
||||
|
||||
# 1. 우르드/리옌 평타 effectiveAttackTime 검증
|
||||
print("\n[1] 우르드/리옌 평타 effectiveAttackTime (Projectile TriggerTime)")
|
||||
print("-" * 70)
|
||||
|
||||
for stalker_id in ['urud', 'lian']:
|
||||
stalker = data.get(stalker_id, {})
|
||||
basic_attacks = stalker.get('basicAttacks', {})
|
||||
|
||||
for weapon_type, attacks in basic_attacks.items():
|
||||
for attack in attacks:
|
||||
montage_name = attack['montageName']
|
||||
actual_duration = attack['actualDuration']
|
||||
effective_time = attack.get('effectiveAttackTime', actual_duration)
|
||||
projectile_triggers = attack.get('projectileTriggerTimes', [])
|
||||
|
||||
if projectile_triggers:
|
||||
saved_time = actual_duration - effective_time
|
||||
print(f"{stalker_id}/{weapon_type} 평타:")
|
||||
print(f" Montage: {montage_name}")
|
||||
print(f" ActualDuration: {actual_duration:.2f}초")
|
||||
print(f" EffectiveAttackTime: {effective_time:.2f}초")
|
||||
print(f" ProjectileTriggers: {projectile_triggers}")
|
||||
print(f" => {saved_time:.2f}초 빠름!")
|
||||
|
||||
# 2. 공격 스킬 판정 검증
|
||||
print("\n[2] 공격 스킬 판정 (SimpleSendEvent Event Tag)")
|
||||
print("-" * 70)
|
||||
|
||||
test_skills = {
|
||||
'SK130301': '바란 일격분쇄 (Event.SkillActivate)',
|
||||
'SK150201': '클라드 다시 흙으로 (Event.SkillActivate)',
|
||||
'SK190201': '리옌 연화 (Event.SpawnProjectile)',
|
||||
'SK190101': '리옌 정조준 (ProjectileShot)',
|
||||
}
|
||||
|
||||
for skill_id, expected_desc in test_skills.items():
|
||||
found = False
|
||||
for stalker_id, stalker in data.items():
|
||||
all_skills = (stalker.get('defaultSkills', []) +
|
||||
[stalker.get('subSkill')] +
|
||||
[stalker.get('ultimateSkill')])
|
||||
|
||||
for skill in all_skills:
|
||||
if skill and skill.get('skillId') == skill_id:
|
||||
is_attack = len(skill.get('montageData', [])) > 0 and skill['montageData'][0].get('hasAttack', False)
|
||||
status = "공격 스킬" if is_attack else "유틸리티"
|
||||
print(f"{skill_id}: {skill.get('name')} => {status}")
|
||||
print(f" Expected: {expected_desc}")
|
||||
|
||||
# 몽타주 데이터 확인
|
||||
if skill.get('montageData'):
|
||||
montage = skill['montageData'][0]
|
||||
attack_notifies = montage.get('attackNotifies', [])
|
||||
print(f" AttackNotifies: {len(attack_notifies)}개")
|
||||
|
||||
# SimpleSendEvent 확인
|
||||
for notify in attack_notifies:
|
||||
if 'SimpleSendEvent' in notify.get('notifyClass', ''):
|
||||
event_tag = notify.get('customProperties', {}).get('Event Tag', '')
|
||||
print(f" - SimpleSendEvent: {event_tag}")
|
||||
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
break
|
||||
|
||||
if not found:
|
||||
print(f"{skill_id}: NOT FOUND")
|
||||
|
||||
# 3. 유틸리티 스킬 확인 (공격 노티파이 없음)
|
||||
print("\n[3] 유틸리티 스킬 (공격 노티파이 없음)")
|
||||
print("-" * 70)
|
||||
|
||||
utility_skills = {
|
||||
'SK110207': '우르드 Reload',
|
||||
'SK190209': '리옌 재장전'
|
||||
}
|
||||
|
||||
for skill_id, expected_name in utility_skills.items():
|
||||
found = False
|
||||
for stalker_id, stalker in data.items():
|
||||
all_skills = (stalker.get('defaultSkills', []) +
|
||||
[stalker.get('subSkill')] +
|
||||
[stalker.get('ultimateSkill')])
|
||||
|
||||
for skill in all_skills:
|
||||
if skill and skill.get('skillId') == skill_id:
|
||||
has_attack = len(skill.get('montageData', [])) > 0 and skill['montageData'][0].get('hasAttack', False)
|
||||
status = "공격" if has_attack else "유틸리티"
|
||||
print(f"{skill_id}: {skill.get('name')} => {status}")
|
||||
|
||||
if skill.get('montageData'):
|
||||
montage = skill['montageData'][0]
|
||||
attack_notifies_count = len(montage.get('attackNotifies', []))
|
||||
print(f" AttackNotifies: {attack_notifies_count}개")
|
||||
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
break
|
||||
|
||||
# 4. 레네 소환체 섹션 확인
|
||||
print("\n[4] 레네 소환체 섹션")
|
||||
print("-" * 70)
|
||||
|
||||
rene = data.get('rene', {})
|
||||
summons = rene.get('summons', {})
|
||||
|
||||
if summons:
|
||||
print(f"레네 소환체: {len(summons)}개")
|
||||
for summon_name, summon_data in summons.items():
|
||||
print(f"\n {summon_name}:")
|
||||
print(f" SummonSkillId: {summon_data.get('summonSkillId')}")
|
||||
print(f" SummonSkillName: {summon_data.get('summonSkillName')}")
|
||||
print(f" SkillDamageRate: {summon_data.get('skillDamageRate')}")
|
||||
print(f" AttackInterval: {summon_data.get('attackInterval')}초")
|
||||
print(f" DotType: {summon_data.get('dotType', 'None')}")
|
||||
else:
|
||||
print("레네 소환체 데이터 없음!")
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print("검증 완료!")
|
||||
print("=" * 70)
|
||||
Reference in New Issue
Block a user