Files
test/Documentation/CONVERTER_GFX_TO_SFX.md
2026-04-10 16:35:07 +07:00

4.9 KiB

Converter: GFX paths → SFX paths in skill stubs

This document describes how skill .cs files get m_szFlySfxPath / m_szHitGrndSfxPath / m_szHitSfxPath from the same client .gfx assets that supply m_sz*GfxPath, and how to extend or re-run the pipeline.

Goal

For each non-empty GFX path emitted from .sgc (m_szFlyGfxPath, m_szHitGrndGfxPath, m_szHitGfxPath), find the matching .gfx file on disk under the GFX root (--gfx, e.g. C:\Users\BrewPC\Downloads\gfx) and read the classic file-based sound path from the Sound element inside that .gfx. Emit the corresponding m_sz*SfxPath field on SkillStub.

Example (skill 1):

  • m_szHitGfxPath = "策划联入/人物技能/击中/虎击击中.gfx"
  • On disk: …\gfx\策划联入\人物技能\击中\虎击击中.gfx
  • Inside .gfx: Sound element (GFXELEMENTID: 170) → Path: / PathNum: + Path: lines (see C++ GFXSOUNDIMP::Load)
  • Result: m_szHitSfxPath = "Skill\\01Fighter\\虎击_C" (exact string depends on asset data)

Reference: client behavior

See C++_SkillGfx_Sfx_Play_Flow.md: the client plays Sfx\ + filename from the Sound element in the GFX resource.

Unity data model

In skill.cs, SkillStub defines:

Field Source
m_szFlyGfxPath .sgc line 1 Path
m_szHitGrndGfxPath .sgc line 2 Path
m_szHitGfxPath .sgc 3rd Path (after version/scales per format)
m_szFlySfxPath First classic SFX path parsed from fly .gfx
m_szHitGrndSfxPath Same for hit-ground .gfx
m_szHitSfxPath Same for hit .gfx

If a GFX path is empty, or the .gfx file is missing, or there is no parseable Sound element, the matching SFX field is string.Empty.

Tool: convert_skills_fixed.py

Inputs

  • --cppCElementSkill (skill *.h)
  • --cs — Unity Scripts/Skills (or subfolder layout you use)
  • --gfxGFX root (folder that contains sgc\ and the same tree as in-game paths, e.g. 策划联入\...)

Resolution rule (GFX file on disk)

Game path uses /. On Windows, join under gfx_root:

gfx_root + path.replace("/", os.sep)

Example: 策划联入/人物技能/击中/虎击击中.gfxgfx_root\策划联入\人物技能\击中\虎击击中.gfx

Text .gfx detection

Text format starts with a line matching Version: <int> (Angelica A3DGFXEx::Load). If the file does not match (likely binary .gfx), SFX extraction is skipped (empty string).

Parsing Sound element (classic mode)

  1. Split file into blocks after each line GFXELEMENTID: <id>.
  2. For blocks with id = 170 (ID_ELE_TYPE_SOUND in client headers):
    • Take the substring before the first SoundVer: line (start of GfxSoundParamInfo).
    • If PathNum: N: read the next N lines Path: …; use the first path as the stub value (runtime may randomize among N).
    • Else: use the last Path: … line in that prefix (legacy single path).
  3. Normalize:
    • "\\""/" for logical path (same separator style as m_sz*GfxPath)
    • Strip trailing .wav / .ogg / .mp3 if present
  4. Escape for C# with the same helper used for other strings in the generator.

Limitations (v1)

Topic Behavior
Binary .gfx No SFX extracted
GFXSOUNDIMP22 audio-event Path: after SoundVer: Not used as classic SFX in v1
Multiple GFXELEMENTID: 170 First non-empty classic path wins
No --gfx / missing file All three m_sz*SfxPath = string.Empty
Skills without .sgc data No gfx_path_code block; stub defaults apply

Regenerating stubs

From repo root (adjust paths):

python convert_skills_fixed.py --stubs "E:\Projects\perfect-world-source\perfect-world-source\CElement\CElementSkill\stubs1.cpp" --gfx "C:\Users\BrewPC\Downloads\gfx"

Or --ids 1 for a single skill smoke test.

Future work (checklist)

  • Binary .gfx: port minimal binary reader for GFXELEMENTID + Sound chunk, or shell out to a small C++/CLI tool.
  • Audio-event mode: map GFXSOUNDIMP22 Path: (after SoundVer:) to a separate field or naming convention if Unity uses FMOD/Wwise events.
  • Multiple sounds: emit multiple candidates or document “first only” vs random.
  • Runtime: wire m_sz*SfxPath into actual playback (load under Sfx\ or Addressables) where m_sz*GfxPath is consumed today.

Files touched by this feature

File Role
convert_skills_fixed.py _resolve_gfx_path_on_disk, text .gfx parse, m_sz*SfxPath emission
skill.cs SkillStub fields m_szFlySfxPath, m_szHitGrndSfxPath, m_szHitSfxPath
Generated skillN.cs Constructor assignments next to GFX paths