بنقرة واحدة
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 标注准则在文档里明确