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)