Clean actor runtime baseline after motion fix
This commit is contained in:
@@ -165,17 +165,15 @@ It also now includes an actor/content validator:
|
|||||||
|
|
||||||
- `scripts/validate_actor_scenarios.py`
|
- `scripts/validate_actor_scenarios.py`
|
||||||
|
|
||||||
On the current real client runtime, the full actor validator reports five data
|
The current actor validator now resolves real `MotionFileName` targets from
|
||||||
issues that look like pre-existing content inconsistencies rather than `.m2p`
|
`.msa` files instead of assuming every motion uses a same-name local `.gr2`.
|
||||||
loader regressions:
|
That removed the old false positives from redirected actor motions, and the
|
||||||
|
remaining `orc_lord` mismatch was fixed in the runtime assets by correcting
|
||||||
|
`30_1.msa` to point to `30_1.GR2`.
|
||||||
|
|
||||||
- `Monster/misterious_diseased_host` missing `25.gr2`
|
On the current real client runtime, the actor validator now passes cleanly.
|
||||||
- `Monster/skeleton_king` missing `24.gr2`
|
|
||||||
- `Monster/thief2` missing `03_1.gr2`
|
|
||||||
- `NPC/christmas_tree` missing `wait.gr2`
|
|
||||||
- `NPC/guild_war_flag` missing `wait.gr2`
|
|
||||||
|
|
||||||
The expanded validator did not find additional breakage in:
|
It still verifies:
|
||||||
|
|
||||||
- `.msm` base model references
|
- `.msm` base model references
|
||||||
- `.msm` effect script references
|
- `.msm` effect script references
|
||||||
@@ -205,11 +203,11 @@ previous cross-pack and wrong-path sound references were cleaned up in the
|
|||||||
runtime assets, and the last remaining `combo7.wav` issue was resolved by
|
runtime assets, and the last remaining `combo7.wav` issue was resolved by
|
||||||
aligning `combo_07.mss` with the byte-identical `combo_08` motion variant.
|
aligning `combo_07.mss` with the byte-identical `combo_08` motion variant.
|
||||||
|
|
||||||
Those current actor and effect findings are also recorded in:
|
The current effect findings are recorded in:
|
||||||
|
|
||||||
- `known_issues/runtime_known_issues.json`
|
- `known_issues/runtime_known_issues.json`
|
||||||
|
|
||||||
The current audio findings are recorded there as well.
|
Actor and audio are currently clean in that baseline.
|
||||||
|
|
||||||
That file is now the shared runtime baseline used by the validators and the
|
That file is now the shared runtime baseline used by the validators and the
|
||||||
aggregated release gate.
|
aggregated release gate.
|
||||||
|
|||||||
@@ -208,7 +208,8 @@ python3 scripts/validate_actor_scenarios.py \
|
|||||||
This validator checks local actor integrity for `Monster`, `NPC`, and `PC`:
|
This validator checks local actor integrity for `Monster`, `NPC`, and `PC`:
|
||||||
|
|
||||||
- `motlist.txt` motion files exist
|
- `motlist.txt` motion files exist
|
||||||
- each motion has a paired `.gr2` in the same actor directory
|
- each motion resolves to a valid `.gr2`, including redirected `MotionFileName`
|
||||||
|
targets in `.msa`
|
||||||
- `.msm` base model targets resolve against the runtime asset set
|
- `.msm` base model targets resolve against the runtime asset set
|
||||||
- `.msm` effect script targets resolve against the runtime asset set
|
- `.msm` effect script targets resolve against the runtime asset set
|
||||||
- `.msm` default hit effect targets resolve against the runtime asset set
|
- `.msm` default hit effect targets resolve against the runtime asset set
|
||||||
@@ -275,7 +276,7 @@ Strict behavior:
|
|||||||
Current baseline on the real runtime:
|
Current baseline on the real runtime:
|
||||||
|
|
||||||
- `world`: `0`
|
- `world`: `0`
|
||||||
- `actor`: `5`
|
- `actor`: `0`
|
||||||
- `effect`: `12`
|
- `effect`: `12`
|
||||||
- `audio`: `0`
|
- `audio`: `0`
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
{
|
{
|
||||||
"world": [],
|
"world": [],
|
||||||
"actor": [
|
"actor": [],
|
||||||
"actor:paired_model:ymir work/monster/misterious_diseased_host:25.gr2",
|
|
||||||
"actor:paired_model:ymir work/monster/skeleton_king:24.gr2",
|
|
||||||
"actor:paired_model:ymir work/monster/thief2:03_1.gr2",
|
|
||||||
"actor:paired_model:ymir work/npc/christmas_tree:wait.gr2",
|
|
||||||
"actor:paired_model:ymir work/npc/guild_war_flag:wait.gr2"
|
|
||||||
],
|
|
||||||
"effect": [
|
"effect": [
|
||||||
"effect:reference:ymir work/effect/background/moonlight_eff_bat.mse:ymir work/effect/pet/halloween_2022_coffin_bat_01.dds",
|
"effect:reference:ymir work/effect/background/moonlight_eff_bat.mse:ymir work/effect/pet/halloween_2022_coffin_bat_01.dds",
|
||||||
"effect:reference:ymir work/effect/background/moonlight_eff_bat.mse:ymir work/effect/pet/halloween_2022_coffin_bat_02.dds",
|
"effect:reference:ymir work/effect/background/moonlight_eff_bat.mse:ymir work/effect/pet/halloween_2022_coffin_bat_02.dds",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ BASE_MODEL_RE = re.compile(r'^BaseModelFileName\s+"([^"]+)"', re.IGNORECASE)
|
|||||||
EFFECT_SCRIPT_RE = re.compile(r'^EffectScriptName\s+"([^"]+)"', re.IGNORECASE)
|
EFFECT_SCRIPT_RE = re.compile(r'^EffectScriptName\s+"([^"]+)"', re.IGNORECASE)
|
||||||
DEFAULT_HIT_EFFECT_RE = re.compile(r'^DefaultHitEffectFileName\s+"([^"]*)"', re.IGNORECASE)
|
DEFAULT_HIT_EFFECT_RE = re.compile(r'^DefaultHitEffectFileName\s+"([^"]*)"', re.IGNORECASE)
|
||||||
DEFAULT_HIT_SOUND_RE = re.compile(r'^DefaultHitSoundFileName\s+"([^"]*)"', re.IGNORECASE)
|
DEFAULT_HIT_SOUND_RE = re.compile(r'^DefaultHitSoundFileName\s+"([^"]*)"', re.IGNORECASE)
|
||||||
|
MOTION_FILE_RE = re.compile(r'^MotionFileName\s+"([^"]+)"', re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -110,6 +111,15 @@ def parse_motlist(path: Path) -> list[str]:
|
|||||||
return motions
|
return motions
|
||||||
|
|
||||||
|
|
||||||
|
def parse_msa_motion_file(path: Path) -> str | None:
|
||||||
|
for raw_line in path.read_text(encoding="utf-8", errors="ignore").splitlines():
|
||||||
|
line = raw_line.strip()
|
||||||
|
match = MOTION_FILE_RE.match(line)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def parse_msm_references(path: Path) -> tuple[str | None, list[str], list[str], list[str]]:
|
def parse_msm_references(path: Path) -> tuple[str | None, list[str], list[str], list[str]]:
|
||||||
base_model: str | None = None
|
base_model: str | None = None
|
||||||
effect_scripts: list[str] = []
|
effect_scripts: list[str] = []
|
||||||
@@ -146,6 +156,13 @@ def validate_actor_dir(pack: str, pack_dir: Path, actor_dir: Path, asset_index:
|
|||||||
if not msa_path.is_file():
|
if not msa_path.is_file():
|
||||||
missing_msa.append(motion)
|
missing_msa.append(motion)
|
||||||
continue
|
continue
|
||||||
|
motion_file = parse_msa_motion_file(msa_path)
|
||||||
|
if motion_file:
|
||||||
|
resolved_motion = normalize_virtual_path(motion_file)
|
||||||
|
if resolved_motion not in asset_index:
|
||||||
|
missing_gr2_for_motions.append(resolved_motion)
|
||||||
|
continue
|
||||||
|
|
||||||
gr2_name = Path(motion).with_suffix(".gr2").name
|
gr2_name = Path(motion).with_suffix(".gr2").name
|
||||||
if not (actor_dir / gr2_name).is_file():
|
if not (actor_dir / gr2_name).is_file():
|
||||||
missing_gr2_for_motions.append(gr2_name)
|
missing_gr2_for_motions.append(gr2_name)
|
||||||
@@ -234,7 +251,8 @@ def main() -> int:
|
|||||||
failures.append(message)
|
failures.append(message)
|
||||||
issue_map[issue_id] = message
|
issue_map[issue_id] = message
|
||||||
for gr2_name in check.missing_gr2_for_motions:
|
for gr2_name in check.missing_gr2_for_motions:
|
||||||
issue_id = f"actor:paired_model:{check.actor_dir}:{gr2_name.lower()}"
|
normalized_gr2 = normalize_virtual_path(gr2_name)
|
||||||
|
issue_id = f"actor:paired_model:{check.actor_dir}:{normalized_gr2}"
|
||||||
message = f"{check.actor_dir}: missing paired model {gr2_name}"
|
message = f"{check.actor_dir}: missing paired model {gr2_name}"
|
||||||
failures.append(message)
|
failures.append(message)
|
||||||
issue_map[issue_id] = message
|
issue_map[issue_id] = message
|
||||||
|
|||||||
Reference in New Issue
Block a user