Files
mtgodot-poc/project/skill_motion_loop_test.gd
T
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00

114 lines
4.0 KiB
GDScript

# skill_motion_loop_test —— 40250 SetMotionLoopCount / MSA LoopData parity。
# godot --headless --path project --script skill_motion_loop_test.gd
extends SceneTree
const AssetRoot = preload("res://asset_root.gd")
const PlayerView = preload("res://ui/player_view.gd")
class FakeAnim extends Node:
signal playback_finished
var anim_path := ""
var loop := true
var time_scale := 1.0
var playing := true
var motion_loop_count := -1
func set_motion_loop_count(count: int) -> void:
motion_loop_count = count
func get_motion_data() -> Dictionary:
return {}
var _fail := 0
func _ck(ok: bool, message: String) -> void:
if not ok:
_fail += 1
printerr("FAIL: " + message)
func _touch(path: String) -> void:
DirAccess.make_dir_recursive_absolute(path.get_base_dir())
var f := FileAccess.open(path, FileAccess.WRITE)
f.store_string("")
f.close()
func _init() -> void:
call_deferred("_run")
func _run() -> void:
await _test_player_view_payload()
await _test_native_msa_segment_loop()
if _fail == 0:
print("PASS: skill_motion_loop_test")
quit(0)
else:
printerr("%d check(s) failed" % _fail)
quit(1)
func _test_player_view_payload() -> void:
var root := ProjectSettings.globalize_path("user://skill_motion_loop_test")
var skill_dir := root.path_join("PC/ymir work/pc/warrior/skill")
_touch(skill_dir.path_join("loop_skill.msa"))
var pv: Node = PlayerView.new()
get_root().add_child(pv)
var anim := FakeAnim.new()
pv.add_child(anim)
pv.anim = anim
pv._assets_root = root
pv._race = 0
pv.motion_dir = root.path_join("PC/ymir work/pc/warrior/general")
var played: bool = pv.play_skill_motion("loop_skill", 0, 3, true)
_ck(played, "PlayerView accepts a skill motion from the resource directory")
_ck(anim.motion_loop_count == 3, "PlayerView forwards uMotLoopCount to the animation player")
_ck(pv.skill_motion_state() == {"loop_count": 3, "moving": true},
"PlayerView keeps loop count and moving-skill bit together")
pv.free()
await process_frame
func _test_native_msa_segment_loop() -> void:
if not ClassDB.class_exists("Metin2AnimPlayer"):
print(" (skip native MSA loop test: animation extension unavailable)")
return
var assets := AssetRoot.path()
var msa := assets.path_join("PC/ymir work/pc/assassin/skill/yeonsa.msa")
if not FileAccess.file_exists(msa):
print(" (skip native MSA loop test: yeonsa.msa unavailable)")
return
var anim: Node = ClassDB.instantiate("Metin2AnimPlayer")
get_root().add_child(anim)
if not anim.has_method("set_motion_loop_count") or not anim.has_method("get_motion_loop_count"):
_ck(false, "Metin2AnimPlayer exposes SetMotionLoopCount")
anim.free()
await process_frame
return
anim.set("loop", false)
anim.set("anim_path", msa)
await process_frame
var loop_data: Dictionary = anim.call("get_loop_data")
_ck(bool(loop_data.get("present", false)), "MSA LoopData is exposed")
_ck(int(loop_data.get("count", 0)) == 7, "yeonsa resource loop count is 7")
anim.call("set_motion_loop_count", 2)
_ck(int(anim.call("get_motion_loop_count")) == 2,
"SetMotionLoopCount overrides the resource count")
var previous: float = float(anim.call("get_time"))
var wraps := 0
var count_after_wrap := -1
var finished := [false]
anim.playback_finished.connect(func(): finished[0] = true)
var frames := 0
while frames < 500 and not finished[0]:
await process_frame
var current: float = float(anim.call("get_time"))
if current + 0.05 < previous:
wraps += 1
count_after_wrap = int(anim.call("get_motion_loop_count"))
previous = current
frames += 1
_ck(wraps == 1, "loop count 2 performs one LoopData segment rewind")
_ck(count_after_wrap == 1, "segment rewind decrements the remaining count")
_ck(finished[0], "finite MSA loop returns to playback_finished after the tail")
anim.set("anim_path", assets.path_join("PC/ymir work/pc/warrior/general/wait.msa"))
await process_frame
_ck(int(anim.call("get_motion_loop_count")) == 0,
"normal motion does not inherit the previous skill loop override")
anim.free()
await process_frame