From 82691f164545c2cc9ca259330e0c944f6976e86a Mon Sep 17 00:00:00 2001 From: Daylily-Zeleen Date: Tue, 23 May 2023 11:24:53 +0800 Subject: [PATCH] Expose low level properties of animation_tree --- doc/classes/AnimationTree.xml | 284 +++++++++++++++-------------- scene/animation/animation_tree.cpp | 176 ++++++++++++++++++ scene/animation/animation_tree.h | 51 ++++++ 3 files changed, 370 insertions(+), 141 deletions(-) diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml index ef3c1a3f9eeb..fa28c5ffb936 100644 --- a/doc/classes/AnimationTree.xml +++ b/doc/classes/AnimationTree.xml @@ -30,146 +30,6 @@ Manually advance the animations by the specified time (in seconds). - - - - Retrieve the motion delta of position with the [member root_motion_track] as a [Vector3] that can be used elsewhere. - If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_POSITION_3D], returns [code]Vector3(0, 0, 0)[/code]. - See also [member root_motion_track] and [RootMotionView]. - The most basic example is applying position to [CharacterBody3D]: - [codeblocks] - [gdscript] - var current_rotation: Quaternion - - func _process(delta): - if Input.is_action_just_pressed("animate"): - current_rotation = get_quaternion() - state_machine.travel("Animate") - var velocity: Vector3 = current_rotation * animation_tree.get_root_motion_position() / delta - set_velocity(velocity) - move_and_slide() - [/gdscript] - [/codeblocks] - By using this in combination with [method get_root_motion_position_accumulator], you can apply the root motion position more correctly to account for the rotation of the node. - [codeblocks] - [gdscript] - func _process(delta): - if Input.is_action_just_pressed("animate"): - state_machine.travel("Animate") - set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation()) - var velocity: Vector3 = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta - set_velocity(velocity) - move_and_slide() - [/gdscript] - [/codeblocks] - - - - - - Retrieve the blended value of the position tracks with the [member root_motion_track] as a [Vector3] that can be used elsewhere. - This is useful in cases where you want to respect the initial key values of the animation. - For example, if an animation with only one key [code]Vector3(0, 0, 0)[/code] is played in the previous frame and then an animation with only one key [code]Vector3(1, 0, 1)[/code] is played in the next frame, the difference can be calculated as follows: - [codeblocks] - [gdscript] - var prev_root_motion_position_accumulator: Vector3 - - func _process(delta): - if Input.is_action_just_pressed("animate"): - state_machine.travel("Animate") - var current_root_motion_position_accumulator: Vector3 = animation_tree.get_root_motion_position_accumulator() - var difference: Vector3 = current_root_motion_position_accumulator - prev_root_motion_position_accumulator - prev_root_motion_position_accumulator = current_root_motion_position_accumulator - transform.origin += difference - [/gdscript] - [/codeblocks] - However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. - - - - - - Retrieve the motion delta of rotation with the [member root_motion_track] as a [Quaternion] that can be used elsewhere. - If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_ROTATION_3D], returns [code]Quaternion(0, 0, 0, 1)[/code]. - See also [member root_motion_track] and [RootMotionView]. - The most basic example is applying rotation to [CharacterBody3D]: - [codeblocks] - [gdscript] - func _process(delta): - if Input.is_action_just_pressed("animate"): - state_machine.travel("Animate") - set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation()) - [/gdscript] - [/codeblocks] - - - - - - Retrieve the blended value of the rotation tracks with the [member root_motion_track] as a [Quaternion] that can be used elsewhere. - This is necessary to apply the root motion position correctly, taking rotation into account. See also [method get_root_motion_position]. - Also, this is useful in cases where you want to respect the initial key values of the animation. - For example, if an animation with only one key [code]Quaternion(0, 0, 0, 1)[/code] is played in the previous frame and then an animation with only one key [code]Quaternion(0, 0.707, 0, 0.707)[/code] is played in the next frame, the difference can be calculated as follows: - [codeblocks] - [gdscript] - var prev_root_motion_rotation_accumulator: Quaternion - - func _process(delta): - if Input.is_action_just_pressed("animate"): - state_machine.travel("Animate") - var current_root_motion_rotation_accumulator: Quaternion = animation_tree.get_root_motion_Quaternion_accumulator() - var difference: Quaternion = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator - prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator - transform.basis *= difference - [/gdscript] - [/codeblocks] - However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. - - - - - - Retrieve the motion delta of scale with the [member root_motion_track] as a [Vector3] that can be used elsewhere. - If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_SCALE_3D], returns [code]Vector3(0, 0, 0)[/code]. - See also [member root_motion_track] and [RootMotionView]. - The most basic example is applying scale to [CharacterBody3D]: - [codeblocks] - [gdscript] - var current_scale: Vector3 = Vector3(1, 1, 1) - var scale_accum: Vector3 = Vector3(1, 1, 1) - - func _process(delta): - if Input.is_action_just_pressed("animate"): - current_scale = get_scale() - scale_accum = Vector3(1, 1, 1) - state_machine.travel("Animate") - scale_accum += animation_tree.get_root_motion_scale() - set_scale(current_scale * scale_accum) - [/gdscript] - [/codeblocks] - - - - - - Retrieve the blended value of the scale tracks with the [member root_motion_track] as a [Vector3] that can be used elsewhere. - For example, if an animation with only one key [code]Vector3(1, 1, 1)[/code] is played in the previous frame and then an animation with only one key [code]Vector3(2, 2, 2)[/code] is played in the next frame, the difference can be calculated as follows: - [codeblocks] - [gdscript] - var prev_root_motion_scale_accumulator: Vector3 - - func _process(delta): - if Input.is_action_just_pressed("animate"): - state_machine.travel("Animate") - var current_root_motion_scale_accumulator: Vector3 = animation_tree.get_root_motion_scale_accumulator() - var difference: Vector3 = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator - prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator - transform.basis = transform.basis.scaled(difference) - [/gdscript] - [/codeblocks] - However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. - - @@ -185,12 +45,154 @@ The number of possible simultaneous sounds for each of the assigned AudioStreamPlayers. For example, if this value is [code]32[/code] and the animation has two audio tracks, the two [AudioStreamPlayer]s assigned can play simultaneously up to [code]32[/code] voices each. + + The process mode of this [AnimationTree]. See [enum AnimationProcessCallback] for available modes. + + + + The motion delta of position with the [member root_motion_track] as a [Vector3]. + If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_POSITION_3D], this property will not be updated internally. + See also [member root_motion_track] and [RootMotionView]. + The most basic example is applying position to [CharacterBody3D]: + [codeblocks] + [gdscript] + var current_rotation: Quaternion + + func _process(delta): + if Input.is_action_just_pressed("animate"): + current_rotation = get_quaternion() + state_machine.travel("Animate") + var velocity: Vector3 = current_rotation * animation_tree.root_motion_position / delta + set_velocity(velocity) + move_and_slide() + [/gdscript] + [/codeblocks] + By using this in combination with [member root_motion_position_accumulator], you can apply the root motion position more correctly to account for the rotation of the node. + [codeblocks] + [gdscript] + func _process(delta): + if Input.is_action_just_pressed("animate"): + state_machine.travel("Animate") + set_quaternion(get_quaternion() * animation_tree.root_motion_rotation) + var velocity: Vector3 = (animation_tree.root_motion_rotation_accumulator.inverse() * get_quaternion()) * animation_tree.root_motion_position / delta + set_velocity(velocity) + move_and_slide() + [/gdscript] + [/codeblocks] + + + The blended value of the position tracks with the [member root_motion_track] as a [Vector3]. + This is useful in cases where you want to respect the initial key values of the animation. + For example, if an animation with only one key [code]Vector3(0, 0, 0)[/code] is played in the previous frame and then an animation with only one key [code]Vector3(1, 0, 1)[/code] is played in the next frame, the difference can be calculated as follows: + [codeblocks] + [gdscript] + var prev_root_motion_position_accumulator: Vector3 + + func _process(delta): + if Input.is_action_just_pressed("animate"): + state_machine.travel("Animate") + var current_root_motion_position_accumulator: Vector3 = animation_tree.root_motion_position_accumulator + var difference: Vector3 = current_root_motion_position_accumulator - prev_root_motion_position_accumulator + prev_root_motion_position_accumulator = current_root_motion_position_accumulator + transform.origin += difference + [/gdscript] + [/codeblocks] + However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. + + + The motion delta of rotation with the [member root_motion_track] as a [Quaternion]. + If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_ROTATION_3D], this property will not be updated internally. + See also [member root_motion_track] and [RootMotionView]. + The most basic example is applying rotation to [CharacterBody3D]: + [codeblocks] + [gdscript] + func _process(delta): + if Input.is_action_just_pressed("animate"): + state_machine.travel("Animate") + set_quaternion(get_quaternion() * animation_tree.root_motion_rotation) + [/gdscript] + [/codeblocks] + + + The blended value of the rotation tracks with the [member root_motion_track] as a [Quaternion]. + This is necessary to apply the root motion position correctly, taking rotation into account. See also [member root_motion_position]. + Also, this is useful in cases where you want to respect the initial key values of the animation. + For example, if an animation with only one key [code]Quaternion(0, 0, 0, 1)[/code] is played in the previous frame and then an animation with only one key [code]Quaternion(0, 0.707, 0, 0.707)[/code] is played in the next frame, the difference can be calculated as follows: + [codeblocks] + [gdscript] + var prev_root_motion_rotation_accumulator: Quaternion + + func _process(delta): + if Input.is_action_just_pressed("animate"): + state_machine.travel("Animate") + var current_root_motion_rotation_accumulator: Quaternion = animation_tree.root_motion_Quaternion_accumulator + var difference: Quaternion = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator + prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator + transform.basis *= difference + [/gdscript] + [/codeblocks] + However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. + + + The motion delta of scale with the [member root_motion_track] as a [Vector3]. + If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_SCALE_3D], this property will not be updated internally. + See also [member root_motion_track] and [RootMotionView]. + The most basic example is applying scale to [CharacterBody3D]: + [codeblocks] + [gdscript] + var current_scale: Vector3 = Vector3(1, 1, 1) + var scale_accum: Vector3 = Vector3(1, 1, 1) + + func _process(delta): + if Input.is_action_just_pressed("animate"): + current_scale = get_scale() + scale_accum = Vector3(1, 1, 1) + state_machine.travel("Animate") + scale_accum += animation_tree.root_motion_scale + set_scale(current_scale * scale_accum) + [/gdscript] + [/codeblocks] + + + The blended value of the scale tracks with the [member root_motion_track] as a [Vector3]. + For example, if an animation with only one key [code]Vector3(1, 1, 1)[/code] is played in the previous frame and then an animation with only one key [code]Vector3(2, 2, 2)[/code] is played in the next frame, the difference can be calculated as follows: + [codeblocks] + [gdscript] + var prev_root_motion_scale_accumulator: Vector3 + + func _process(delta): + if Input.is_action_just_pressed("animate"): + state_machine.travel("Animate") + var current_root_motion_scale_accumulator: Vector3 = animation_tree.root_motion_scale_accumulator + var difference: Vector3 = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator + prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator + transform.basis = transform.basis.scaled(difference) + [/gdscript] + [/codeblocks] + However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. + The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code]. - If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be canceled visually, and the animation will appear to stay in place. See also [method get_root_motion_position], [method get_root_motion_rotation], [method get_root_motion_scale] and [RootMotionView]. + If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be canceled visually, and the animation will appear to stay in place. See also [member root_motion_position], [member root_motion_rotation], [member root_motion_scale] and [RootMotionView]. + + + + + + + + + + + + + + + + The root animation node of this [AnimationTree]. See [AnimationNode]. diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 5d4d58f283b2..437e3ee7b446 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -1882,6 +1882,7 @@ void AnimationTree::_notification(int p_what) { Object *player = ObjectDB::get_instance(last_animation_player); if (player) { player->connect("caches_cleared", callable_mp(this, &AnimationTree::_clear_caches)); + last_animation_player = player->get_instance_id(); } } } break; @@ -1981,6 +1982,121 @@ String AnimationTree::get_invalid_state_reason() const { return state.invalid_reasons; } +// =============================== +Dictionary AnimationTree::get_state_track_map_bind() const { + Dictionary ret; + for (auto &&E : state.track_map) { + ret[E.key] = E.value; + } + return ret; +} + +void AnimationTree::set_state_track_map_bind(const Dictionary &p_track_map) { + state.track_map.clear(); + auto k = p_track_map.next(); + while (k) { + ERR_FAIL_COND(k->get_type() != Variant::NODE_PATH && k->get_type() != Variant::STRING_NAME && k->get_type() != Variant::STRING); + ERR_FAIL_COND(p_track_map[*k].get_type() != Variant::INT); + + state.track_map.insert(*k, p_track_map[*k]); + + k = p_track_map.next(k); + } +} + +TypedArray AnimationTree::get_state_animation_states_bind() const { + TypedArray ret; + for (auto &&E : state.animation_states) { + Dictionary anim_state; + anim_state[SNAME("animation")] = E.animation; + anim_state[SNAME("time")] = E.time; + anim_state[SNAME("delta")] = E.delta; +#ifdef REAL_T_IS_DOUBLE + PackedFloat64Array track_blends; +#else + PackedFloat32Array track_blends; +#endif + track_blends.resize(E.track_blends.size()); + for (auto i = 0; i < track_blends.size(); ++i) { + track_blends.set(i, E.track_blends[i]); + } + anim_state[SNAME("track_blends")] = track_blends; + anim_state[SNAME("blend")] = E.blend; + anim_state[SNAME("seeked")] = E.seeked; + anim_state[SNAME("is_external_seeking")] = E.is_external_seeking; + anim_state[SNAME("looped_flag")] = E.looped_flag; + } + return ret; +} + +void AnimationTree::set_state_animation_states_bind(const TypedArray &p_animation_states) { + state.animation_states.clear(); + for (auto i = 0; i < p_animation_states.size(); ++i) { + Dictionary anim_state = p_animation_states[i]; + ERR_FAIL_COND(!anim_state.has(SNAME("animation"))); + ERR_FAIL_COND(!anim_state.has(SNAME("time"))); + ERR_FAIL_COND(!anim_state.has(SNAME("delta"))); + ERR_FAIL_COND(!anim_state.has(SNAME("track_blends"))); + ERR_FAIL_COND(!anim_state.has(SNAME("blend"))); + ERR_FAIL_COND(!anim_state.has(SNAME("seeked"))); + ERR_FAIL_COND(!anim_state.has(SNAME("is_external_seeking"))); + ERR_FAIL_COND(!anim_state.has(SNAME("looped_flag"))); + + AnimationNode::AnimationState anim_state_to_add; + +#ifdef REAL_T_IS_DOUBLE + PackedFloat64Array track_blends = anim_state[SNAME("track_blends")]; +#else + PackedFloat32Array track_blends = anim_state[SNAME("track_blends")]; +#endif + anim_state_to_add.track_blends.resize(track_blends.size()); + for (auto track_idx = 0; track_idx < track_blends.size(); ++track_idx) { + anim_state_to_add.track_blends.set(track_idx, track_blends[track_idx]); + } + + anim_state_to_add.blend = anim_state[SNAME("blend")]; + anim_state_to_add.delta = anim_state[SNAME("delta")]; + anim_state_to_add.time = anim_state[SNAME("time")]; + anim_state_to_add.animation = anim_state[SNAME("animation")]; + anim_state_to_add.seeked = anim_state[SNAME("seeked")]; + anim_state_to_add.looped_flag = Animation::LoopedFlag(anim_state[SNAME("looped_flag")].operator int8_t()); + anim_state_to_add.is_external_seeking = anim_state[SNAME("is_external_seeking")]; + + state.animation_states.push_back(anim_state_to_add); + } +} + +Dictionary AnimationTree::get_property_map_bind() const { + Dictionary ret; + for (auto &&E : property_map) { + Array prop; + prop.resize(2); + prop[0] = E.value.first; + prop[1] = E.value.second; + ret[E.key] = prop; + } + return ret; +} + +void AnimationTree::set_property_map_bind(Dictionary p_property_map) { + property_map.clear(); + auto k = p_property_map.next(); + while (k) { + ERR_FAIL_COND(k->get_type() != Variant::STRING_NAME && k->get_type() != Variant::STRING && k->get_type() != Variant::NODE_PATH); + ERR_FAIL_COND(p_property_map[*k].get_type() != Variant::ARRAY); + + Array val = p_property_map[*k]; + ERR_FAIL_COND(val.size() != 2); + ERR_FAIL_COND(val[1].get_type() != Variant::BOOL); + + property_map.insert(*k, Pair(val[0], val[1])); + + k = p_property_map.next(k); + } +} + +// =============================== + uint64_t AnimationTree::get_last_process_pass() const { return process_pass; } @@ -2236,6 +2352,66 @@ void AnimationTree::_bind_methods() { ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance); + // + ClassDB::bind_method(D_METHOD("set_state_track_count", "track_count"), &AnimationTree::set_state_track_count); + ClassDB::bind_method(D_METHOD("get_state_track_count"), &AnimationTree::get_state_track_count); + + ClassDB::bind_method(D_METHOD("set_state_track_map", "track_map"), &AnimationTree::set_state_track_map_bind); + ClassDB::bind_method(D_METHOD("get_state_track_map"), &AnimationTree::get_state_track_map_bind); + + ClassDB::bind_method(D_METHOD("set_state_animation_states", "animation_states"), &AnimationTree::set_state_animation_states_bind); + ClassDB::bind_method(D_METHOD("get_state_animation_states"), &AnimationTree::get_state_animation_states_bind); + + ClassDB::bind_method(D_METHOD("set_state_invalid", "invalid"), &AnimationTree::set_state_invalid); + ClassDB::bind_method(D_METHOD("is_state_invalid"), &AnimationTree::is_state_invalid); + + ClassDB::bind_method(D_METHOD("set_state_invalid_reasons", "invalid_reasons"), &AnimationTree::set_invalid_state_reasons); + ClassDB::bind_method(D_METHOD("get_state_invalid_reasons"), &AnimationTree::get_invalid_state_reason); + + ClassDB::bind_method(D_METHOD("set_state_player", "player"), &AnimationTree::set_state_player); + ClassDB::bind_method(D_METHOD("get_state_player"), &AnimationTree::get_state_player); + + ClassDB::bind_method(D_METHOD("set_state_last_pass", "last_pass"), &AnimationTree::set_state_last_pass); + ClassDB::bind_method(D_METHOD("get_state_last_pass"), &AnimationTree::get_state_last_pass); + + ClassDB::bind_method(D_METHOD("set_started", "started"), &AnimationTree::set_started); + ClassDB::bind_method(D_METHOD("is_started"), &AnimationTree::is_started); + + ClassDB::bind_method(D_METHOD("set_root_motion_position", "root_motion_position"), &AnimationTree::set_root_motion_position); + ClassDB::bind_method(D_METHOD("set_root_motion_rotation", "root_motion_rotation"), &AnimationTree::set_root_motion_rotation); + ClassDB::bind_method(D_METHOD("set_root_motion_scale", "root_motion_scale"), &AnimationTree::set_root_motion_scale); + + ClassDB::bind_method(D_METHOD("set_root_motion_position_accumulator", "root_motion_position_accumulator"), &AnimationTree::set_root_motion_position_accumulator); + ClassDB::bind_method(D_METHOD("set_root_motion_rotation_accumulator", "root_motion_rotation_accumulator"), &AnimationTree::set_root_motion_rotation_accumulator); + ClassDB::bind_method(D_METHOD("set_root_motion_scale_accumulator", "root_motion_scale_accumulator"), &AnimationTree::set_root_motion_scale_accumulator); + + ClassDB::bind_method(D_METHOD("set_property_map", "property_map"), &AnimationTree::set_property_map_bind); + ClassDB::bind_method(D_METHOD("get_property_map"), &AnimationTree::get_property_map_bind); + + ClassDB::bind_method(D_METHOD("set_last_process_pass", "process_pass"), &AnimationTree::set_last_process_pass); + ClassDB::bind_method(D_METHOD("get_last_process_pass"), &AnimationTree::get_last_process_pass); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "state_track_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_state_track_count", "get_state_track_count"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "state_track_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_state_track_map", "get_state_track_map"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "state_animation_states", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_state_animation_states", "get_state_animation_states"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "state_invalid", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_state_invalid", "is_state_invalid"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "state_invalid_reasons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_state_invalid_reasons", "get_state_invalid_reasons"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "state_player", PROPERTY_HINT_NODE_TYPE, AnimationPlayer::get_class_static(), PROPERTY_USAGE_NO_EDITOR), "set_state_player", "get_state_player"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "state_last_pass", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_state_last_pass", "get_state_last_pass"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "started", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_started", "is_started"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "last_process_pass", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_last_process_pass", "get_last_process_pass"); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "property_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_property_map", "get_property_map"); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "root_motion_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_root_motion_position", "get_root_motion_position"); + ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "root_motion_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_root_motion_rotation", "get_root_motion_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "root_motion_scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_root_motion_scale", "get_root_motion_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "root_motion_position_accumulator", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_root_motion_position_accumulator", "get_root_motion_position_accumulator"); + ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "root_motion_rotation_accumulator", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_root_motion_rotation_accumulator", "get_root_motion_rotation_accumulator"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "root_motion_scale_accumulator", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_root_motion_scale_accumulator", "get_root_motion_scale_accumulator"); + // + GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object", "object_idx"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root"); diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 0346fc42a74b..ebc384a2b6cc 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -418,6 +418,57 @@ class AnimationTree : public Node { real_t get_connection_activity(const StringName &p_path, int p_connection) const; void advance(double p_time); + int get_state_track_count() const { return state.track_count; } + void set_state_track_count(int p_track_count) { state.track_count = p_track_count; } + + HashMap get_state_track_map() const { return state.track_map; } + void set_state_track_map(const HashMap &p_track_map) { state.track_map = p_track_map; } + Dictionary get_state_track_map_bind() const; + void set_state_track_map_bind(const Dictionary &p_track_map); + + List get_state_animation_states() const { return state.animation_states; } + void set_state_animation_states(const List &p_animation_states) { state.animation_states = p_animation_states; } + TypedArray get_state_animation_states_bind() const; // May be should used a new reference class instead of Dictionary. + void set_state_animation_states_bind(const TypedArray &p_animation_states); // + + void set_state_invalid(bool p_invalid) { state.valid = !p_invalid; } + + AnimationPlayer *get_state_player() const { return state.player; } + void set_state_player(AnimationPlayer *p_player) { state.player = p_player; } + + void set_invalid_state_reasons(const String &p_invalid_reasons) { state.invalid_reasons = p_invalid_reasons; } + + uint64_t get_state_last_pass() const { return state.last_pass; } + void set_state_last_pass(const uint64_t &p_last_pass) { state.last_pass = p_last_pass; } + + void set_last_process_pass(uint64_t p_process_pass) { process_pass = p_process_pass; } + + bool is_started() const { return started; } + void set_started(bool p_started) { started = p_started; } + + void set_root_motion_position(Vector3 p_root_motion_position) { root_motion_position = p_root_motion_position; } + void set_root_motion_rotation(Quaternion p_root_motion_rotation) { root_motion_rotation = p_root_motion_rotation; } + void set_root_motion_scale(Vector3 p_root_motion_scale) { root_motion_scale = p_root_motion_scale; } + + void set_root_motion_position_accumulator(Vector3 p_root_motion_position_accumulator) { root_motion_position_accumulator = p_root_motion_position_accumulator; } + void set_root_motion_rotation_accumulator(Quaternion p_root_motion_rotation_accumulator) { root_motion_rotation_accumulator = p_root_motion_rotation_accumulator; } + void set_root_motion_scale_accumulator(Vector3 p_root_motion_scale_accumulator) { root_motion_scale_accumulator = p_root_motion_scale_accumulator; } + + // It seem the bool value in Pair is not used. + HashMap> get_property_map() const { return property_map; }; + void set_property_map(HashMap> p_property_map) { property_map = p_property_map; }; + Dictionary get_property_map_bind() const; + void set_property_map_bind(Dictionary p_property_map); + + // "root_motion_cache", "track_cache" and "playing_caches" and "cache_valid" are no need to be saved as state. + // The feature of playing audio is not getting AudioStreamPlayer from "playing_audio_stream_players", expose this property is not make sense. + // "setup_pass" is used in caching tracks, not need to be saved as state, too. + // "properties", "property_parent_map", "property_reference_map" may not need to be exposed + // "input_activity_map" is updated when update properties, expose it is not make sense. + // It seem "input_activity_map_get" only used in edior. + // "properties_dirty", "last_animation_player" are changed automatically and not effect the work logic, expose them is not make sense. + // ================================ + uint64_t get_last_process_pass() const; AnimationTree(); ~AnimationTree();