--- id: wiki-2026-0508-ndf-neutral-data-format title: NDF (Neutral Data Format) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Neutral Data Format, Eugen NDF, WARNO NDF] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [modding, data-format, eugen-systems, warno, configuration] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: NDF framework: Eugen-Iriszoom --- # NDF (Neutral Data Format) ## 매 한 줄 > **"매 declarative game-data DSL — Eugen Systems Iriszoom engine 의 data layer"**. 매 Wargame/Steel Division/WARNO 시리즈 의 unit/weapon/visual 의 모든 stat 의 NDF 파일 정의. 매 modding 의 entry point — 매 binary patch 가 X, plain text 의 git-diffable. ## 매 핵심 ### 매 Syntax 의 핵심 - **Object literal**: `Identifier is TYPE(...)` — 매 모든 entity 의 declaration. - **Module 의 nesting**: 매 outer module 안의 inner objects 의 reference. - **Reference**: `~/Module/Path/Identifier` — 매 absolute paths. - **Map / List**: `MAP[(key, value), ...]`, `[item1, item2]`. - **Comment**: `//` (line) — 매 `/* */` 의 X. ### 매 typical structure - **GameData**: 매 unit definitions / weapon stats / texture references / sound mappings. - **Module**: 매 named container — 매 `ZModule_TWeaponManagerModuleDescriptor` 의 sort 의 component. - **Inheritance**: 매 `is BaseType(...)` 의 prototype 의 from inheritance — override fields only. ### 매 응용 1. **Unit balance modding** (HP / armor / damage tweaks). 2. **New unit creation** (copy/paste/rename + export to deck). 3. **Visual mod** (camo swap, model substitution via NDF reference change). ## 💻 패턴 ### 매 NDF 의 unit definition (WARNO style) ```ndf // Unit declaration with module composition TUniteDescriptor_M1Abrams is TUniteDescriptor ( ClassNameForDebug = "M1A1 Abrams" AcknowUnitType = ~/AcknowUnitType_Tank ModulesDescriptors = [ TBaseDamageModuleDescriptor ( MaxPhysicalDamages = 9 ArmorDescriptorFront = ~/Armor_Tank_Heavy_Front ArmorDescriptorSides = ~/Armor_Tank_Heavy_Side ), TWeaponManagerModuleDescriptor ( Salves = [1, 1, 1] TurretDescriptorList = [TTurretInfanterieDescriptor()] ), ] ) ``` ### 매 NDF parser (Python — ndf-parse 패키지) ```python import ndf_parse import ndf_parse.model as ndf_model # Parse a WARNO NDF file with open("UniteDescriptor.ndf") as f: source = f.read() tree = ndf_parse.parse(source) # Find Abrams unit and tweak HP for obj in tree: if obj.namespace == "TUniteDescriptor_M1Abrams": damage_mod = obj.value.by_member("ModulesDescriptors").value[0] damage_mod.value.by_member("MaxPhysicalDamages").value = "12" # Write back with open("UniteDescriptor.modified.ndf", "w") as f: f.write(ndf_parse.print_tree(tree)) ``` ### 매 batch 의 unit stat 의 audit ```python import ndf_parse from pathlib import Path def audit_unit_hp(ndf_dir: Path) -> dict[str, int]: """Scan all unit descriptors and extract MaxPhysicalDamages.""" results = {} for ndf_path in ndf_dir.glob("**/UniteDescriptor*.ndf"): tree = ndf_parse.parse(ndf_path.read_text(encoding="utf-8")) for obj in tree: if obj.value.type == "TUniteDescriptor": try: mods = obj.value.by_member("ModulesDescriptors").value for m in mods: if m.value.type == "TBaseDamageModuleDescriptor": hp = int(m.value.by_member("MaxPhysicalDamages").value) results[obj.namespace] = hp except (AttributeError, KeyError): pass return results hp_table = audit_unit_hp(Path("./WARNO_GameData/Generated/Gameplay/Gfx")) # Find outliers for unit, hp in sorted(hp_table.items(), key=lambda x: -x[1])[:10]: print(f"{unit}: {hp}") ``` ### 매 mod 의 inheritance (override only what changed) ```ndf // Mod file — overrides base unit export TUniteDescriptor_M1Abrams_Modded is TUniteDescriptor_M1Abrams ( // Only override the fields you change Modifications = [ ("MaxPhysicalDamages", 15), // buff HP ("MaxSpeedInKmph", 75), // faster ] ) ``` ### 매 NDF 의 git-friendly diff ```bash # Mod versioning workflow git init mods/abrams_buff cd mods/abrams_buff cp ../../WARNO_GameData/Generated/Gameplay/Gfx/UniteDescriptor.ndf base.ndf # ... edit ... git diff base.ndf modified.ndf > abrams_buff.patch # Reapply on update git apply abrams_buff.patch # works as long as upstream context stable ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | 매 single value tweak | Direct edit + diff | | 매 systematic balance pass | ndf-parse Python script | | 매 new unit | Inherit from existing TUniteDescriptor + override | | 매 cross-version mod | `Modifications = [...]` override list (resilient to base changes) | | 매 visual-only mod | Texture path swap in TextureBank NDF | **기본값**: 매 inheritance + Modifications list — 매 maintainability 의 best. ## 🔗 Graph - 부모: [[Eugen Systems 모딩 매뉴얼]] · [[Iriszoom 엔진]] - 변형: [[ndf-parse 패키지]] · [[WARNO Modding]] ## 🤖 LLM 활용 **언제**: 매 large balance pass (parse → batch edit → write) / 매 new unit boilerplate generation / 매 cross-mod conflict detection. **언제 X**: 매 tiny single-value edit — 매 manual edit 의 faster. ## ❌ 안티패턴 - **매 binary patch**: 매 game patches 의 break — NDF 의 source-level 의 stay. - **매 full file 의 copy**: 매 base game patch 의 conflict — Modifications override list 의 use. - **매 string concat 의 NDF generation**: 매 syntax error 의 risk — proper parser library 의 use. - **매 무 backup**: 매 NDF 의 game crash 시 root cause — git-track everything. ## 🧪 검증 / 중복 - Verified (Eugen Systems WARNO modding documentation; ndf-parse Python package on PyPI; community Discord patterns). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — NDF syntax + ndf-parse patterns + modding workflow |