"매 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.
importndf_parseimportndf_parse.modelasndf_model# Parse a WARNO NDF filewithopen("UniteDescriptor.ndf")asf:source=f.read()tree=ndf_parse.parse(source)# Find Abrams unit and tweak HPforobjintree:ifobj.namespace=="TUniteDescriptor_M1Abrams":damage_mod=obj.value.by_member("ModulesDescriptors").value[0]damage_mod.value.by_member("MaxPhysicalDamages").value="12"# Write backwithopen("UniteDescriptor.modified.ndf","w")asf:f.write(ndf_parse.print_tree(tree))
매 batch 의 unit stat 의 audit
importndf_parsefrompathlibimportPathdefaudit_unit_hp(ndf_dir:Path)->dict[str,int]:"""Scan all unit descriptors and extract MaxPhysicalDamages."""results={}forndf_pathinndf_dir.glob("**/UniteDescriptor*.ndf"):tree=ndf_parse.parse(ndf_path.read_text(encoding="utf-8"))forobjintree:ifobj.value.type=="TUniteDescriptor":try:mods=obj.value.by_member("ModulesDescriptors").valueforminmods:ifm.value.type=="TBaseDamageModuleDescriptor":hp=int(m.value.by_member("MaxPhysicalDamages").value)results[obj.namespace]=hpexcept(AttributeError,KeyError):passreturnresultshp_table=audit_unit_hp(Path("./WARNO_GameData/Generated/Gameplay/Gfx"))# Find outliersforunit,hpinsorted(hp_table.items(),key=lambdax:-x[1])[:10]:print(f"{unit}: {hp}")
매 mod 의 inheritance (override only what changed)
// 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
# 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.
언제: 매 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).