원클릭으로
dnf-physics-extraction
从 DNF 客户端 PVF 提取战斗物理真值(重力/跳跃/launch/knockback/...),按三级置信度铁律落档
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
从 DNF 客户端 PVF 提取战斗物理真值(重力/跳跃/launch/knockback/...),按三级置信度铁律落档
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
引导添加新的 FrameDataAction,确保 provenance、hitbox、reaction、cancel policy 完整
生成符合项目约定的 static test 文件 — 无框架、node:assert/strict、standalone Node 执行
一键运行三道验证门:typecheck → static:test → build,对应 CI 完整流程
| name | dnf-physics-extraction |
| description | 从 DNF 客户端 PVF 提取战斗物理真值(重力/跳跃/launch/knockback/...),按三级置信度铁律落档 |
系统性从 Script.pvf + ImagePacks2 提取 DNF 战斗物理真值(跳跃、重力、launch velocity、knockback、状态参数等),按 CLAUDE.md 三级置信度铁律 输出可落档的研究文档 + 项目数据层。
需要还原 DNF 任意战斗机制的真值参数时调用。涵盖:
tools/dnf-extract.exe 编译可用(commit ≥ 99432ae,含 .nut/binary dispatch + bounds 保护)Script.pvf 路径已知(典型:D:/BaiduNetdiskDownload/DNF客户端(2018年2月更新)/地下城与勇士/Script.pvf)D:\carbon-shade-web)mkdir -p .tmp/dnf-research
tools/dnf-extract.exe --pvf "$PVF" --list --filter "sqr/" 2>/dev/null \
> .tmp/dnf-research/sqr-index.json
按子目录分组:用 Python collections.Counter + 路径 split 看哪些职业 / 哪些子系统的 .nut 多。
经验:旧职业(swordman / fighter)通常没有自定义 .nut,物理走引擎默认;新职业(atmage / creatormage / priest)有大量 .nut 自定义。关键 API 调用样本在新职业的 .nut 里。
四类必提:
sqr/common.nut、sqr/init_character.nut、sqr/loadstate.nut、sqr/dnf_enum_header.nut(最核心,含所有物理常数)sqr/character/common/common_header.nut、sqr/character/common_load_state.nut、sqr/character/*_load_state.nutsqr/character/<job>/<job>_header.nut、<job>_common.nutjumpattack|pushout|launch|elementalrain|magiccannon|multishot|fastmoveecho "quit" | cat targets.txt - | tools/dnf-extract.exe --pvf "$PVF" --pipe \
2>/dev/null > .tmp/dnf-research/nut-dump.jsonl
用 Python 把 JSONL split 成单文件方便 grep:
for chunk in content.split('\n---\n'):
d = json.loads(chunk.strip())
if d['type'] == 'text':
open(f".tmp/dnf-research/nut/{d['path'].replace('/','_')}", 'w', encoding='utf-8').write(d['content'])
cd .tmp/dnf-research/nut
# 列出所有 sq_*Velocity / sq_*Speed / sq_*Force / sq_*Power API
grep -ohE "sq_[A-Z][A-Za-z]*(Velocity|Speed|Force|Power|Push|Jump|Z[A-Z]|Gravity)[A-Za-z]*" *.nut | sort -u
# 关键 API 调用上下文(带 -B 2 -A 1 看参数语义)
grep -B 2 -A 1 "sq_SetZVelocity\b" *.nut
grep -B 1 -A 1 "sq_SetCurrentAttacknUpForce\|sq_SetCurrentAttacknBackForce" *.nut
grep -B 2 -A 1 "sq_JumpUpStartFrame\|sq_JumpDownStartFrame\|sq_JumpLandStartFrame" *.nut
核心 API 表(记住这几个,遇到对应字段就直接用):
| API | 第一参数语义 | 第二参数语义 | 单位 |
|---|---|---|---|
sq_SetZVelocity(obj, v0, accel) | initial Z velocity | Z acceleration | (px/s, px/s²) |
sq_SetVelocity(obj, axis, value) | axis 0=X, 1=Y(depth), 2=Z(height) | velocity | px/s |
sq_SetCurrentAttacknUpForce(atk, F) | launch upward velocity | - | px/s |
sq_SetCurrentAttacknBackForce(atk, F) | knockback X velocity | - | px/s |
sq_SetAttackInfoForceHitStunTime(atk, T) | hitstun duration | - | frames (60 Hz) |
sq_JumpUpStartFrame(N) | 上升起始动画帧 | - | frame index |
sq_JumpDownStartFrame(N) | 下降起始动画帧 | - | frame index |
sq_JumpLandStartFrame(N) | 落地起始动画帧 | - | frame index |
提 sqr/dnf_enum_header.nut 找以下宏(韩文注释直接给出单位语义):
| 宏 | 必查的注释关键词 |
|---|---|
DEFAULT_GRAVITY_ACCEL | "중력 가속도"(重力加速度) |
X_NORMALMOVE_VELOCITY / Y_NORMALMOVE_VELOCITY | "1초동안 이동 픽셀 수"(1 秒像素数)→ 铁证单位是 px/s |
FORCE_TO_VELOCITY_CONST | "속도 = 상수 * 힘 / 무게" → 速度公式 |
SPEED_VALUE_DEFAULT | "1000 = 100%" |
LIGHT/MIDDLE_OBJECT_MAX_WEIGHT | "효과음" → 仅音效用 |
tools/dnf-extract.exe --pvf "$PVF" --batch \
"character/swordman/swordman.chr" \
"character/swordman/demonicswordman.chr" \
"character/gunner/gunner.chr" "character/gunner/atgunner.chr" \
"character/priest/priest.chr" \
"character/fighter/fighter.chr" "character/fighter/atfighter.chr" \
"character/mage/mage.chr" "character/mage/atmage.chr" "character/mage/creatormage.chr" \
"character/thief/thief.chr" \
2>/dev/null > .tmp/dnf-research/all-chr.jsonl
11 个职业。.chr 里 IEEE 754 float 是整数表示:
import struct
def f32(s):
i = int(s)
return struct.unpack('<f', struct.pack('<I', i))[0]
# e.g. "1138163712" → 430.0 (jump_power)
关键字段:jump power / jump speed / move speed / attack speed / weight / mp regen speed / hit recovery。
.atk 文件里 [lift up] 字段是 launch velocity(传给 sq_SetCurrentAttacknUpForce),单位 px/s。
tools/dnf-extract.exe --pvf "$PVF" --batch \
"character/<job>/attackinfo/attack1.atk" \
"character/<job>/attackinfo/attack2.atk" \
"character/<job>/attackinfo/attack3.atk" \
"character/<job>/attackinfo/jumpattack.atk" \
"character/<job>/attackinfo/hitback.atk" \
"character/<job>/attackinfo/hardattack.atk" \
...
字段 lift up 值范围观察:普攻 75-90 px/s,强击 / 第 3 段 300 px/s,重击 220 px/s。
写两个产出:
docs/research/YYYY-MM-DD-dnf-<topic>-extraction.md
src/data/official/,每个数值标 sourceProvenance.source: "pvf:<full-path>" + confidence: "high"|"medium"|"low"。Tier 3 待定值必须 requiresManualVerification: true。cd .tmp/... 后下一次相对路径会失败 — 用绝对路径或末尾 cd /d/carbon-shade-web 复位npm run analyze 重建 .tmp/test-js/ 可能清相邻产物 — 提取产物归档到 docs/research/ 表格,别只放 .tmp/struct.unpack('<f', struct.pack('<I', N))[0] 解码(IEEE 754 little-endian)중력=重力, 힘=force, 무게=weight, 속도=speed, 점프=jump, 픽셀=pixel, 초=secondconfidence: "high"confidence: "medium"confidence: "low" + requiresManualVerification: true禁止反向覆盖:低优先级证据不能否决高优先级。Tier 3 的 hypothesis 必须明示是工作假设而非真值。
详见 docs/research/2026-05-21-dnf-air-physics-phase1.md。
关键发现速查:
DEFAULT_GRAVITY_ACCEL = -1500 px/s² ✓ Tier 1y vs z 命名跟 DNF 原生反了(DNF z=height, y=depth)dnf-extract.exe 工作dnf_enum_header.nut 全文已看,所有物理宏单位 closuresq_SetZVelocity 调用样本反推过 peak heightlift up 等字段)sourceProvenance 标注准则在文档里明确