# motion_event_timing_test —— 40250 ActorInstanceMotionEvent 帧游标回归。 # 覆盖:frame 0 事件、普通动作不重复,以及一个大 delta 跨越多个循环时 # 每个 LoopData/整段循环边界都能触发事件。 extends SceneTree const AssetRoot = preload("res://asset_root.gd") var _fail := 0 func _ck(ok: bool, msg: String) -> void: if not ok: _fail += 1 printerr("FAIL: " + msg) func _init() -> void: call_deferred("_run") func _run() -> void: if not ClassDB.class_exists("Metin2AnimPlayer"): print("motion_event_timing_test: skipped (native extension unavailable)") quit(0) return var msa := AssetRoot.path().path_join("PC/ymir work/pc/shaman/fishing/fishing_catch.msa") if not FileAccess.file_exists(msa): print("motion_event_timing_test: skipped (fishing_catch.msa unavailable)") quit(0) return var once: Node = ClassDB.instantiate("Metin2AnimPlayer") get_root().add_child(once) var once_events: Array = [] once.motion_event_detailed.connect(func(event: Dictionary): once_events.append(event)) once.set("loop", false) once.set("anim_path", msa) for _i in range(3): await process_frame _ck(once_events.size() == 1 and int(once_events[0].get("type", -1)) == 10, "StartingTime=0 在首个动作帧触发一次(实际 %d)" % once_events.size()) once.free() await process_frame var looping: Node = ClassDB.instantiate("Metin2AnimPlayer") get_root().add_child(looping) var loop_events: Array = [] looping.motion_event_detailed.connect(func(event: Dictionary): loop_events.append(event)) looping.set("loop", true) looping.set("time_scale", 1000.0) looping.set("anim_path", msa) for _i in range(3): await process_frame var duration := float(looping.call("get_duration")) var elapsed := float(looping.call("get_time")) var expected_min := maxi(1, int(floor(elapsed / duration)) + 1) _ck(loop_events.size() >= expected_min, "大时间步跨多次循环不漏 MotionEvent(实际 %d,至少 %d,t=%.3f/d=%.3f)" % [loop_events.size(), expected_min, elapsed, duration]) looping.free() await process_frame if _fail == 0: print("PASS: motion_event_timing_test") else: printerr("motion_event_timing_test: %d failure(s)" % _fail) quit(1 if _fail else 0)