# Detect CPU animation dropping winding (including accidentally loading an old dylib). extends SceneTree var failures := 0 func _initialize() -> void: call_deferred("run") func indices(model: Node) -> Array: var meshes := model.find_children("*", "MeshInstance3D", true, false) var out := [] for mi in meshes: for s in mi.mesh.get_surface_count(): out.append(mi.mesh.surface_get_arrays(s)[Mesh.ARRAY_INDEX]) return out func check_reversed(a: Array, b: Array, stage: String) -> void: if a.is_empty() or a.size() != b.size(): failures += 1 printerr("FAIL: missing surfaces at ", stage) return for s in a.size(): if a[s].size() != b[s].size(): failures += 1 continue for t in range(0, a[s].size(), 3): if a[s][t] != b[s][t] or a[s][t + 1] != b[s][t + 2] or a[s][t + 2] != b[s][t + 1]: failures += 1 printerr("FAIL: winding lost at ", stage, " surface ", s) break func run() -> void: var base := AssetRoot.path().path_join("PC/ymir work/pc/warrior") var models := [] var animations := [] for flip in [false, true]: var model: Node = ClassDB.instantiate("Metin2Model") model.set("gr2_path", base.path_join("warrior_novice.gr2")) model.set("hair_gr2", base.path_join("hair/hair_1_1.gr2")) model.set("flip_winding", flip) model.set("lod_enabled", false) root.add_child(model) models.append(model) check_reversed(indices(models[0]), indices(models[1]), "bind") for model in models: var anim: Node = ClassDB.instantiate("Metin2AnimPlayer") anim.set("model_path", model.get_path()) anim.set("anim_path", base.path_join("general/wait.msa")) anim.set("playing", false) root.add_child(anim) animations.append(anim) for time in [0.0, 0.5, 1.0]: for anim in animations: anim.set("time", time) check_reversed(indices(models[0]), indices(models[1]), "animated %s" % time) if indices(models[0]).size() != 4: failures += 1 printerr("FAIL: body and hair surfaces must both be exercised") print("character_winding_test: failures=", failures) for node in animations + models: node.queue_free() await process_frame quit(1 if failures else 0)