OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / modifier_read_probe.gd

79 lines · gd ref:
extends Node3D
## Which read sees a SkeletonModifier3D's writes?
##
## ISOLATED ON PURPOSE. foot_slope_gate produced byte-identical tables with
## FootIK switched OFF, so its reads were the animation pose and every number it
## printed meant nothing. An earlier attempt to settle this asked the question
## through the whole player scene -- physics, autoloads, FootIK, a slope -- and
## hung without printing. This is a two-bone skeleton and a modifier that writes
## ONE known offset, so the answer is analytic: whichever read reports the offset
## is the one to use, and any read reporting the rest value is looking at the
## pre-modifier pose.
##
## Run:
##   "$HYPER_TPS_GODOT" --headless res://scenes/test/modifier_read_probe.tscn

const OFFSET := Vector3(0.0, 0.25, 0.0)


class Mod extends SkeletonModifier3D:
	var offset: Vector3
	var ran := false
	func _process_modification() -> void:
		var sk: Skeleton3D = get_skeleton()
		if sk == null or sk.get_bone_count() < 2:
			return
		ran = true
		sk.set_bone_pose_position(1, sk.get_bone_pose_position(1) + offset)


var _skel: Skeleton3D = null
var _mod: Mod = null
var _sig := Vector3(-999, -999, -999)
var _frames := 0


func _ready() -> void:
	process_priority = 100
	_skel = Skeleton3D.new()
	add_child(_skel)
	_skel.add_bone("root")
	_skel.add_bone("child")
	_skel.set_bone_parent(1, 0)
	_skel.set_bone_rest(0, Transform3D(Basis.IDENTITY, Vector3.ZERO))
	_skel.set_bone_rest(1, Transform3D(Basis.IDENTITY, Vector3(0.0, 1.0, 0.0)))
	_skel.reset_bone_poses()

	_mod = Mod.new()
	_mod.offset = OFFSET
	_skel.add_child(_mod)

	if _skel.has_signal("skeleton_updated"):
		_skel.skeleton_updated.connect(_on_updated)


func _on_updated() -> void:
	_sig = _skel.get_bone_global_pose(1).origin


func _process(_d: float) -> void:
	_frames += 1
	if _frames < 5:
		return
	var a: Vector3 = _skel.get_bone_global_pose(1).origin
	var c: Vector3 = _skel.get_bone_pose_position(1)
	var want: Vector3 = Vector3(0.0, 1.0, 0.0) + OFFSET
	print("")
	print("modifier ran          : %s" % str(_mod.ran))
	print("has skeleton_updated  : %s" % str(_skel.has_signal("skeleton_updated")))
	print("rest child position   : (0, 1, 0)   modifier adds %s   expect %s"
			% [str(OFFSET), str(want)])
	print("")
	print("A  get_bone_global_pose in _process : %s   sees write: %s"
			% [str(a), str(a.is_equal_approx(want))])
	print("B  same, in skeleton_updated        : %s   sees write: %s"
			% [str(_sig), str(_sig.is_equal_approx(want))])
	print("C  get_bone_pose_position (local)   : %s   sees write: %s"
			% [str(c), str(c.is_equal_approx(want))])
	get_tree().quit(0)