# motion_event_payload_test —— native .msa event dictionary parity. # 40250 RaceMotionDataEvent payloads must survive the native parser all the # way to motion_event_detailed/get_events before any visual routing is added. extends SceneTree const AssetRoot = preload("res://asset_root.gd") var failures := 0 func check(ok: bool, label: String) -> void: if not ok: failures += 1 printerr("FAIL: " + label) func _init() -> void: call_deferred("run") func run() -> void: if not ClassDB.class_exists("Metin2AnimPlayer"): print("motion_event_payload_test: skipped (native extension unavailable)") quit(0) return var assets := AssetRoot.path() await _test_asset(assets.path_join("PC/ymir work/pc/warrior/skill/daejin_2.msa"), 2, 2.0) await _test_asset(assets.path_join("PC/ymir work/pc/warrior/skill/gihyeol.msa"), 4, 2.0) await _test_asset(assets.path_join("PC/ymir work/pc/warrior/skill/geompung.msa"), 6, 1.4) await _test_asset(assets.path_join("PC/ymir work/pc/assassin/skill/gungsin_3.msa"), 7, 1.5) if failures == 0: print("PASS: motion_event_payload_test") else: printerr("motion_event_payload_test: %d failure(s)" % failures) quit(1 if failures else 0) func _test_asset(path: String, expected_type: int, expected_duration: float) -> void: if not FileAccess.file_exists(path): check(false, "reference asset exists: %s" % path) return var anim: Node = ClassDB.instantiate("Metin2AnimPlayer") get_root().add_child(anim) anim.set("anim_path", path) await process_frame var events: Array = anim.call("get_events") var motion_data: Dictionary = anim.call("get_motion_data") check(is_equal_approx(float(motion_data.get("duration", 0.0)), expected_duration), "%s uses MSA MotionDuration %.3f as motion timing" % [path.get_file(), expected_duration]) var found: Dictionary = {} for event in events: if event is Dictionary: found[int(event.get("type", -1))] = event check(found.has(expected_type), "%s exposes type %d" % [path.get_file(), expected_type]) if found.has(2): var wave: Dictionary = found[2] check(wave.has("duration_time") and wave.has("power") and wave.has("affecting_range"), "SCREEN_WAVING keeps DuringTime/Power/AffectingRange") if found.has(4): var attack: Dictionary = found[4] check(attack.has("enable_hit_process") and attack.has("collision_spheres") and attack.collision_spheres.size() > 0, "SPECIAL_ATTACKING keeps collision spheres") if found.has(6): var fly: Dictionary = found[6] check(String(fly.get("fly_file", "")).to_lower().ends_with(".msf") and fly.has("fly_pos") and fly.has("fly_bone"), "FLY keeps FlyFileName/FlyPosition/bone") if found.has(7): check(found[7].has("duration_time") and found[7].has("collision_spheres"), "no-payload event types retain a stable detailed dictionary") anim.free()