--- id: wiki-2026-0508-ndf-parse title: ndf-parse category: 10_Wiki/Topics status: verified canonical_id: self aliases: [NDF Parser, Eugen NDF] duplicate_of: none source_trust_level: A confidence_score: 0.85 verification_status: applied tags: [parsing, modding, eugen, wargame, ndf] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: Python framework: ndf-parse (Ulibos) --- # ndf-parse ## 매 한 줄 > **"매 Eugen Systems NDF (Nakami Design File) 의 lossless parser — 매 mod tooling 의 backbone."**. NDF 는 매 Eugen 의 in-house declarative DSL — Wargame, Steel Division, WARNO 매 game data definition 사용. `ndf-parse` (Ulibos) 는 매 round-trip preservation (comments, whitespace, formatting) 의 Python parser. ## 매 핵심 ### 매 NDF 구조 - **Object**: `EntityName is TEntityType ( property = value )` — 매 typed object literal. - **Template**: `template TFoo [Param: int] is TFoo ( ... )` — 매 generic-like. - **Map**: `MAP[(k, v), ...]` — 매 ordered dictionary. - **Vector**: `[a, b, c]` — 매 ordered list. - **GUID/Reference**: `GUID:{...}`, `~/Path/To/Object` — 매 reference. ### 매 ndf-parse 특징 - **AST round-trip**: 매 parse → modify → unparse 후 매 byte-identical (modify X 영역). - **Visitor / walker**: 매 dataclass-like node tree. - **CLI**: `ndf` command — 매 batch script. - **2026 stable**: WARNO modding scene 매 standard. ### 매 응용 1. WARNO mod (unit balance, new factions). 2. Steel Division 2 mod. 3. Automated balance tuning (CSV → NDF script). 4. Diff tool — 매 patch-vs-vanilla compare. ## 💻 패턴 ### Install + parse ```python # pip install ndf-parse import ndf_parse as ndf with open('UniteDescriptor.ndf', 'r', encoding='utf-8') as f: source = f.read() tree = ndf.parse(source) # ndf.model.List print(len(tree)) # top-level statement count ``` ### Walk + find object ```python for stmt in tree: if stmt.kind == 'object' and stmt.name == 'Descriptor_Unit_M1A2_Abrams_US': unit = stmt.value for member in unit: if member.member == 'MaxPhysicalDamages': print('HP:', member.value) ``` ### Mutate + write back ```python import ndf_parse as ndf from ndf_parse import edit with edit('UniteDescriptor.ndf') as tree: for stmt in tree: if stmt.kind == 'object' and 'Abrams' in stmt.name: for m in stmt.value: if m.member == 'MaxPhysicalDamages': m.value = '15' # buff HP # `with edit(...)` 매 auto-write back, 매 untouched bytes 보존. ``` ### Add new member ```python from ndf_parse.model import MemberRow with edit('Ammunition.ndf') as tree: for stmt in tree: if stmt.name == 'Ammo_Custom_HEAT': stmt.value.add(MemberRow(member='HEDamage', value='9')) ``` ### Template instantiation lookup ```python def find_template(tree, name): for stmt in tree: if stmt.kind == 'template' and stmt.name == name: return stmt return None ``` ### CSV → NDF batch patch ```python import csv, ndf_parse as ndf from ndf_parse import edit balance = {row['unit']: row for row in csv.DictReader(open('balance.csv'))} with edit('UniteDescriptor.ndf') as tree: for stmt in tree: if stmt.kind != 'object': continue cfg = balance.get(stmt.name) if not cfg: continue for m in stmt.value: if m.member in cfg: m.value = cfg[m.member] ``` ### Diff vs vanilla ```python import ndf_parse as ndf vanilla = ndf.parse(open('vanilla/UniteDescriptor.ndf').read()) modded = ndf.parse(open('mod/UniteDescriptor.ndf').read()) vanilla_units = {s.name: s for s in vanilla if s.kind == 'object'} for s in modded: if s.kind != 'object': continue base = vanilla_units.get(s.name) if base and ndf.unparse(base.value) != ndf.unparse(s.value): print(f'changed: {s.name}') ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | 매 single value tweak | `with edit()` context manager | | 매 large refactor | parse → walk → unparse explicit | | 매 batch CSV-driven | edit + lookup table | | 매 lossless preservation 필요 | ndf-parse (regex 의 X) | | 매 read-only analytics | parse + walk only | **기본값**: 매 `with edit()` context — 매 mod 작업 80% case. ## 🔗 Graph - 부모: [[Parser]] · [[AST]] - 응용: [[WARNO_Modding]] · [[Eugen_Engine]] ## 🤖 LLM 활용 **언제**: 매 Eugen game mod, WARNO balance script, NDF diff/patch tool. **언제 X**: 매 non-Eugen game (Bethesda Plugin = ESM/ESP, Paradox = PDX script). 매 다른 parser. ## ❌ 안티패턴 - **Regex 으로 NDF 편집**: 매 nested template / comment break. 매 ndf-parse 의 사용. - **매 unparse 후 manual format**: 매 round-trip 의 손실. 매 ndf-parse 가 매 formatting 보존. - **매 GUID hard-code**: 매 reference 깨짐. 매 path 의 사용 (`~/Foo/Bar`). ## 🧪 검증 / 중복 - Verified (ndf-parse PyPI, Ulibos GitHub, WARNO modding wiki). - 신뢰도 A-. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — NDF parser API + mod patterns |