feat: updated engine

This commit is contained in:
Sara Gerretsen 2026-07-10 17:04:34 +02:00
parent cbe99774ff
commit f4cf6b3999
6607 changed files with 910135 additions and 430025 deletions

View file

@ -30,6 +30,10 @@
#include "animation_node_state_machine.h"
#include "core/config/engine.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
/////////////////////////////////////////////////
void AnimationNodeStateMachineTransition::set_switch_mode(SwitchMode p_mode) {
@ -163,7 +167,7 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_advance_expression"), &AnimationNodeStateMachineTransition::get_advance_expression);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_xfade_curve", "get_xfade_curve");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "break_loop_at_end"), "set_break_loop_at_end", "is_loop_broken_at_end");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset");
@ -192,7 +196,7 @@ AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() {
////////////////////////////////////////////////////////
void AnimationNodeStateMachinePlayback::_set_current(AnimationNodeStateMachine *p_state_machine, const StringName &p_state) {
void AnimationNodeStateMachinePlayback::_set_current(AnimationNode::ProcessState &p_process_state, AnimationNodeStateMachine *p_state_machine, const StringName &p_state) {
current = p_state;
if (current == StringName()) {
group_start_transition = Ref<AnimationNodeStateMachineTransition>();
@ -200,7 +204,7 @@ void AnimationNodeStateMachinePlayback::_set_current(AnimationNodeStateMachine *
return;
}
AnimationTree *tree = p_state_machine->process_state ? p_state_machine->process_state->tree : nullptr;
AnimationTree *tree = p_process_state.tree;
Ref<AnimationNodeStateMachine> anodesm = p_state_machine->find_node_by_path(current);
if (anodesm.is_null()) {
group_start_transition = Ref<AnimationNodeStateMachineTransition>();
@ -354,9 +358,9 @@ bool _is_grouped_state_machine(const Ref<AnimationNodeStateMachine> p_node) {
return p_node.is_valid() && p_node->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED;
}
void AnimationNodeStateMachinePlayback::_clear_fading(AnimationNodeStateMachine *p_state_machine, const StringName &p_state) {
void AnimationNodeStateMachinePlayback::_clear_fading(AnimationNode::ProcessState &p_process_state, AnimationNodeStateMachine *p_state_machine, const StringName &p_state) {
if (!p_state.is_empty() && !_is_grouped_state_machine(p_state_machine->get_node(p_state))) {
_signal_state_change(p_state_machine->get_animation_tree(), p_state, false);
_signal_state_change(p_process_state.tree, p_state, false);
}
fading_from = StringName();
fadeing_from_nti = AnimationNode::NodeTimeInfo();
@ -373,8 +377,8 @@ void AnimationNodeStateMachinePlayback::_signal_state_change(AnimationTree *p_an
emit_signal(p_started ? SceneStringName(state_started) : SceneStringName(state_finished), p_state);
}
void AnimationNodeStateMachinePlayback::_clear_path_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only) {
List<AnimationNode::ChildNode> child_nodes;
void AnimationNodeStateMachinePlayback::_clear_path_children(AnimationNode::ProcessState &p_process_state, AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only) {
LocalVector<AnimationNode::ChildNode> child_nodes;
p_state_machine->get_child_nodes(&child_nodes);
for (const AnimationNode::ChildNode &child_node : child_nodes) {
Ref<AnimationNodeStateMachine> anodesm = child_node.node;
@ -386,9 +390,9 @@ void AnimationNodeStateMachinePlayback::_clear_path_children(AnimationTree *p_tr
playback = playback->duplicate();
}
playback->path.clear();
playback->_clear_path_children(p_tree, anodesm.ptr(), p_test_only);
playback->_clear_path_children(p_process_state, p_tree, anodesm.ptr(), p_test_only);
if (current != child_node.name) {
playback->_start(anodesm.ptr()); // Can restart.
playback->_start(p_process_state, anodesm.ptr()); // Can restart.
}
}
}
@ -421,7 +425,7 @@ void AnimationNodeStateMachinePlayback::_start_children(AnimationTree *p_tree, A
}
}
bool AnimationNodeStateMachinePlayback::_travel_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const String &p_path, bool p_is_allow_transition_to_self, bool p_is_parent_same_state, bool p_test_only) {
bool AnimationNodeStateMachinePlayback::_travel_children(AnimationNode::ProcessState &p_process_state, AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const String &p_path, bool p_is_allow_transition_to_self, bool p_is_parent_same_state, bool p_test_only) {
if (p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
return false; // This function must be fired only by the top state machine, do nothing in child state machine.
}
@ -448,7 +452,7 @@ bool AnimationNodeStateMachinePlayback::_travel_children(AnimationTree *p_tree,
playback = playback->duplicate();
}
if (!playback->is_playing()) {
playback->_start(anodesm.ptr());
playback->_start(p_process_state, anodesm.ptr());
}
ChildStateMachineInfo child_info;
child_info.playback = playback;
@ -471,18 +475,18 @@ bool AnimationNodeStateMachinePlayback::_travel_children(AnimationTree *p_tree,
child_playback = child_playback->duplicate();
}
child_playback->_travel_main(SceneStringName(End));
child_found_route &= child_playback->_travel(p_tree, child_anodesm.ptr(), false, p_test_only);
child_found_route &= child_playback->_travel(p_process_state, p_tree, child_anodesm.ptr(), false, p_test_only);
child_path += "/" + child_playback->get_current_node();
}
// Force restart target state machine.
playback->_start(anodesm.ptr());
playback->_start(p_process_state, anodesm.ptr());
}
is_parent_same_state = is_current_same_state;
bool is_deepest_state = i == temp_path.size() - 1;
child_info.is_reset = is_deepest_state ? reset_request_on_teleport : false;
playback->_travel_main(temp_path[i], child_info.is_reset);
if (playback->_make_travel_path(p_tree, anodesm.ptr(), is_deepest_state ? p_is_allow_transition_to_self : false, child_info.path, p_test_only)) {
if (playback->_make_travel_path(p_process_state, p_tree, anodesm.ptr(), is_deepest_state ? p_is_allow_transition_to_self : false, child_info.path, p_test_only)) {
found_route &= child_found_route;
} else {
child_info.path.push_back(temp_path[i]);
@ -511,16 +515,16 @@ bool AnimationNodeStateMachinePlayback::_travel_children(AnimationTree *p_tree,
return found_route;
}
void AnimationNodeStateMachinePlayback::_start(AnimationNodeStateMachine *p_state_machine) {
void AnimationNodeStateMachinePlayback::_start(AnimationNode::ProcessState &p_process_state, AnimationNodeStateMachine *p_state_machine) {
playing = true;
_set_current(p_state_machine, start_request != StringName() ? start_request : SceneStringName(Start));
_set_current(p_process_state, p_state_machine, start_request != StringName() ? start_request : SceneStringName(Start));
teleport_request = true;
stop_request = false;
start_request = StringName();
}
bool AnimationNodeStateMachinePlayback::_travel(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_is_allow_transition_to_self, bool p_test_only) {
return _make_travel_path(p_tree, p_state_machine, p_is_allow_transition_to_self, path, p_test_only);
bool AnimationNodeStateMachinePlayback::_travel(AnimationNode::ProcessState &p_process_state, AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_is_allow_transition_to_self, bool p_test_only) {
return _make_travel_path(p_process_state, p_tree, p_state_machine, p_is_allow_transition_to_self, path, p_test_only);
}
String AnimationNodeStateMachinePlayback::_validate_path(AnimationNodeStateMachine *p_state_machine, const String &p_path) {
@ -541,12 +545,12 @@ String AnimationNodeStateMachinePlayback::_validate_path(AnimationNodeStateMachi
return target;
}
bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_is_allow_transition_to_self, Vector<StringName> &r_path, bool p_test_only) {
bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationNode::ProcessState &p_process_state, AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_is_allow_transition_to_self, Vector<StringName> &r_path, bool p_test_only) {
StringName travel = travel_request;
travel_request = StringName();
if (!playing) {
_start(p_state_machine);
_start(p_process_state, p_state_machine);
}
ERR_FAIL_COND_V(!p_state_machine->states.has(travel), false);
@ -678,13 +682,13 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree,
playback = playback->duplicate();
}
if (i > 0) {
playback->_start(anodesm.ptr());
playback->_start(p_process_state, anodesm.ptr());
}
if (i >= new_path.size()) {
break; // Tracing has been finished, needs to break.
}
playback->_travel_main(SceneStringName(End));
if (!playback->_travel(p_tree, anodesm.ptr(), false, p_test_only)) {
if (!playback->_travel(p_process_state, p_tree, anodesm.ptr(), false, p_test_only)) {
found_route = false;
break;
}
@ -705,8 +709,8 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree,
}
}
AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
AnimationNode::NodeTimeInfo nti = _process(p_state_machine, p_playback_info, p_test_only);
AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::process(AnimationNode::ProcessState &p_process_state, AnimationNodeInstance &p_instance, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
AnimationNode::NodeTimeInfo nti = _process(p_process_state, p_instance, p_state_machine, p_playback_info, p_test_only);
start_request = StringName();
next_request = false;
stop_request = false;
@ -714,8 +718,8 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::process(Animation
return nti;
}
AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
AnimationTree *tree = p_state_machine->process_state->tree;
AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(AnimationNode::ProcessState &p_process_state, AnimationNodeInstance &p_instance, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
AnimationTree *tree = p_process_state.tree;
double p_time = p_playback_info.time;
double p_delta = p_playback_info.delta;
@ -728,9 +732,9 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(Animatio
// Restart state machine.
if (p_state_machine->get_state_machine_type() != AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
path.clear();
_clear_path_children(tree, p_state_machine, p_test_only);
_clear_path_children(p_process_state, tree, p_state_machine, p_test_only);
}
_start(p_state_machine);
_start(p_process_state, p_state_machine);
reset_request = true;
} else {
// Reset current state.
@ -754,7 +758,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(Animatio
// Process start/travel request.
if (start_request != StringName() || travel_request != StringName()) {
if (p_state_machine->get_state_machine_type() != AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
_clear_path_children(tree, p_state_machine, p_test_only);
_clear_path_children(p_process_state, tree, p_state_machine, p_test_only);
}
}
@ -768,7 +772,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(Animatio
}
// Teleport to start.
if (p_state_machine->states.has(start_request)) {
_start(p_state_machine);
_start(p_process_state, p_state_machine);
} else {
StringName node = start_request;
ERR_FAIL_V_MSG(AnimationNode::NodeTimeInfo(), "No such node: '" + node + "'");
@ -783,10 +787,10 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(Animatio
StringName temp_travel_request = travel_request; // For the case that can't travel.
// Process children.
Vector<StringName> new_path;
bool can_travel = _make_travel_path(tree, p_state_machine, travel_path.size() <= 1 ? p_state_machine->is_allow_transition_to_self() : false, new_path, p_test_only);
bool can_travel = _make_travel_path(p_process_state, tree, p_state_machine, travel_path.size() <= 1 ? p_state_machine->is_allow_transition_to_self() : false, new_path, p_test_only);
if (travel_path.size()) {
if (can_travel) {
can_travel = _travel_children(tree, p_state_machine, travel_target, p_state_machine->is_allow_transition_to_self(), travel_path[0] == current, p_test_only);
can_travel = _travel_children(p_process_state, tree, p_state_machine, travel_target, p_state_machine->is_allow_transition_to_self(), travel_path[0] == current, p_test_only);
} else {
_start_children(tree, p_state_machine, travel_target, p_test_only);
}
@ -800,7 +804,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(Animatio
if (p_state_machine->states.has(temp_travel_request)) {
path.clear();
if (current != temp_travel_request || reset_request_on_teleport) {
_set_current(p_state_machine, temp_travel_request);
_set_current(p_process_state, p_state_machine, temp_travel_request);
reset_request = reset_request_on_teleport;
teleport_request = true;
}
@ -823,15 +827,16 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(Animatio
pi.seeked = true;
pi.is_external_seeking = false;
pi.weight = 0;
current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true);
AnimationNodeInstance *other_instance = p_instance.get_child_instance_by_path_or_null(current);
current_nti = p_state_machine->blend_node(p_process_state, p_instance, other_instance, pi, AnimationNode::FILTER_IGNORE, true, true);
// Don't process first node if not necessary, instead process next node.
_transition_to_next_recursive(tree, p_state_machine, p_delta, p_test_only);
_transition_to_next_recursive(p_process_state, p_instance, tree, p_state_machine, p_delta, p_test_only);
}
// Check current node existence.
if (!p_state_machine->states.has(current)) {
playing = false; // Current does not exist.
_set_current(p_state_machine, StringName());
_set_current(p_process_state, p_state_machine, StringName());
return AnimationNode::NodeTimeInfo();
}
@ -873,7 +878,8 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(Animatio
pi.time = 0;
pi.seeked = true;
}
current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
AnimationNodeInstance *other_instance = p_instance.get_child_instance_by_path_or_null(current);
current_nti = p_state_machine->blend_node(p_process_state, p_instance, other_instance, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
// Cross-fade process.
if (fading_from != StringName()) {
@ -892,16 +898,17 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(Animatio
pi.time = 0;
pi.seeked = true;
}
fadeing_from_nti = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
AnimationNodeInstance *fading_from_instance = p_instance.get_child_instance_by_path_or_null(fading_from);
fadeing_from_nti = p_state_machine->blend_node(p_process_state, p_instance, fading_from_instance, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
if (Animation::is_greater_or_equal_approx(fading_pos, fading_time)) {
// Finish fading.
_clear_fading(p_state_machine, fading_from);
_clear_fading(p_process_state, p_state_machine, fading_from);
}
}
// Find next and see when to transition.
bool will_end = _transition_to_next_recursive(tree, p_state_machine, p_delta, p_test_only) || current == SceneStringName(End);
bool will_end = _transition_to_next_recursive(p_process_state, p_instance, tree, p_state_machine, p_delta, p_test_only) || current == SceneStringName(End);
// Predict remaining time.
if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) {
@ -919,7 +926,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(Animatio
return current_nti;
}
bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, double p_delta, bool p_test_only) {
bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationNode::ProcessState &p_process_state, AnimationNodeInstance &p_instance, AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, double p_delta, bool p_test_only) {
_reset_request_for_fading_from = false;
AnimationMixer::PlaybackInfo pi;
@ -928,9 +935,9 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT
Vector<StringName> transition_path;
transition_path.push_back(current);
while (true) {
next = _find_next(p_tree, p_state_machine);
next = _find_next(p_process_state, p_instance, p_tree, p_state_machine);
if (!_can_transition_to_next(p_tree, p_state_machine, next, p_test_only)) {
if (!_can_transition_to_next(p_process_state, p_tree, p_state_machine, next, p_test_only)) {
break; // Finish transition.
}
@ -954,9 +961,10 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT
pi.seeked = true;
pi.is_external_seeking = false;
pi.weight = 0;
p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only);
AnimationNodeInstance *other_instance = p_instance.get_child_instance_by_path_or_null(current);
p_state_machine->blend_node(p_process_state, p_instance, other_instance, pi, AnimationNode::FILTER_IGNORE, true, p_test_only);
}
_clear_fading(p_state_machine, current);
_clear_fading(p_process_state, p_state_machine, current);
fading_time = 0;
fading_pos = 0;
}
@ -967,7 +975,7 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT
}
// Update current status.
_set_current(p_state_machine, next.node);
_set_current(p_process_state, p_state_machine, next.node);
current_curve = next.curve;
if (current == SceneStringName(End)) {
@ -979,12 +987,13 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT
fadeing_from_nti = current_nti;
AnimationNodeInstance *other_instance = p_instance.get_child_instance_by_path_or_null(current);
if (next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
pi.time = current_nti.position;
pi.seeked = true;
pi.is_external_seeking = false;
pi.weight = 0;
p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only);
p_state_machine->blend_node(p_process_state, p_instance, other_instance, pi, AnimationNode::FILTER_IGNORE, true, p_test_only);
}
// Just get length to find next recursive.
@ -992,7 +1001,7 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT
pi.is_external_seeking = false;
pi.weight = 0;
pi.seeked = next.is_reset;
current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Just retrieve remain length, don't process.
current_nti = p_state_machine->blend_node(p_process_state, p_instance, other_instance, pi, AnimationNode::FILTER_IGNORE, true, true); // Just retrieve remain length, don't process.
// Fading must be processed.
if (fading_time) {
@ -1003,7 +1012,7 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT
return next.node == SceneStringName(End);
}
bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, NextInfo p_next, bool p_test_only) {
bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationNode::ProcessState &p_process_state, AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, NextInfo p_next, bool p_test_only) {
if (p_next.node == StringName()) {
return false;
}
@ -1022,7 +1031,7 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p
}
playback->_next_main();
// Then, fading should end.
_clear_fading(p_state_machine, fading_from);
_clear_fading(p_process_state, p_state_machine, fading_from);
fading_pos = 0;
} else {
return true;
@ -1063,7 +1072,7 @@ Ref<AnimationNodeStateMachineTransition> AnimationNodeStateMachinePlayback::_che
return p_transition.transition;
}
AnimationNodeStateMachinePlayback::NextInfo AnimationNodeStateMachinePlayback::_find_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine) const {
AnimationNodeStateMachinePlayback::NextInfo AnimationNodeStateMachinePlayback::_find_next(AnimationNode::ProcessState &p_process_state, AnimationNodeInstance &p_instance, AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine) const {
NextInfo next;
if (path.size()) {
for (int i = 0; i < p_state_machine->transitions.size(); i++) {
@ -1092,7 +1101,7 @@ AnimationNodeStateMachinePlayback::NextInfo AnimationNodeStateMachinePlayback::_
if (ref_transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) {
continue;
}
if (p_state_machine->transitions[i].from == current && (_check_advance_condition(anodesm, ref_transition) || bypass)) {
if (p_state_machine->transitions[i].from == current && (_check_advance_condition(p_process_state, p_instance, anodesm, ref_transition) || bypass)) {
if (ref_transition->get_priority() <= priority_best) {
priority_best = ref_transition->get_priority();
auto_advance_to = i;
@ -1116,19 +1125,21 @@ AnimationNodeStateMachinePlayback::NextInfo AnimationNodeStateMachinePlayback::_
return next;
}
bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<AnimationNodeStateMachine> state_machine, const Ref<AnimationNodeStateMachineTransition> transition) const {
bool AnimationNodeStateMachinePlayback::_check_advance_condition(AnimationNode::ProcessState &p_process_state, AnimationNodeInstance &p_instance, const Ref<AnimationNodeStateMachine> state_machine, const Ref<AnimationNodeStateMachineTransition> transition) const {
if (transition->get_advance_mode() != AnimationNodeStateMachineTransition::ADVANCE_MODE_AUTO) {
return false;
}
StringName advance_condition_name = transition->get_advance_condition_name();
if (advance_condition_name != StringName() && !bool(state_machine->get_parameter(advance_condition_name))) {
ERR_FAIL_COND_V(p_instance.resource != state_machine, false);
if (advance_condition_name != StringName() && !bool(p_instance.get_parameter(advance_condition_name))) {
return false;
}
if (transition->expression.is_valid()) {
AnimationTree *tree_base = state_machine->get_animation_tree();
AnimationTree *tree_base = p_process_state.tree;
ERR_FAIL_NULL_V(tree_base, false);
NodePath advance_expression_base_node_path = tree_base->get_advance_expression_base_node();
@ -1236,9 +1247,19 @@ AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() {
///////////////////////////////////////////////////////
void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) const {
void AnimationNodeStateMachine::validate_node(const AnimationTree *p_tree, const StringName &p_path) const {
AnimationRootNode::validate_node(p_tree, p_path);
const String playback_path = String(p_path) + String(playback);
Ref<AnimationNodeStateMachinePlayback> pb = p_tree->get(playback_path);
if (pb.is_null()) {
add_validation_error(p_tree, p_path, vformat(RTR("No playback resource set at path: %s."), playback_path));
}
}
void AnimationNodeStateMachine::get_parameter_list(LocalVector<PropertyInfo> *r_list) const {
AnimationNode::get_parameter_list(r_list);
r_list->push_back(PropertyInfo(Variant::OBJECT, playback, PROPERTY_HINT_RESOURCE_TYPE, "AnimationNodeStateMachinePlayback", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ALWAYS_DUPLICATE)); // Don't store this object in .tres, it always needs to be made as unique object.
r_list->push_back(PropertyInfo(Variant::OBJECT, playback, PROPERTY_HINT_RESOURCE_TYPE, AnimationNodeStateMachinePlayback::get_class_static(), PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ALWAYS_DUPLICATE)); // Don't store this object in .tres, it always needs to be made as unique object.
List<StringName> advance_conditions;
for (int i = 0; i < transitions.size(); i++) {
StringName ac = transitions[i].transition->get_advance_condition_name();
@ -1290,12 +1311,9 @@ void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<Animation
states[p_name] = state_new;
_add_node(p_node);
emit_changed();
emit_signal(SNAME("tree_changed"));
p_node->connect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed), CONNECT_REFERENCE_COUNTED);
p_node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_renamed), CONNECT_REFERENCE_COUNTED);
p_node->connect("animation_node_removed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_removed), CONNECT_REFERENCE_COUNTED);
_tree_changed();
}
void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<AnimationNode> p_node) {
@ -1306,26 +1324,21 @@ void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<Anima
{
Ref<AnimationNode> node = states[p_name].node;
if (node.is_valid()) {
node->disconnect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed));
node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_renamed));
node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_removed));
_remove_node(node);
}
}
states[p_name].node = p_node;
_add_node(p_node);
emit_changed();
emit_signal(SNAME("tree_changed"));
p_node->connect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed), CONNECT_REFERENCE_COUNTED);
p_node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_renamed), CONNECT_REFERENCE_COUNTED);
p_node->connect("animation_node_removed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_removed), CONNECT_REFERENCE_COUNTED);
_tree_changed();
}
void AnimationNodeStateMachine::set_state_machine_type(StateMachineType p_state_machine_type) {
state_machine_type = p_state_machine_type;
emit_changed();
emit_signal(SNAME("tree_changed"));
_tree_changed();
notify_property_list_changed();
}
@ -1374,7 +1387,7 @@ StringName AnimationNodeStateMachine::get_node_name(const Ref<AnimationNode> &p_
ERR_FAIL_V(StringName());
}
void AnimationNodeStateMachine::get_child_nodes(List<ChildNode> *r_child_nodes) {
void AnimationNodeStateMachine::get_child_nodes(LocalVector<ChildNode> *r_child_nodes) {
Vector<StringName> nodes;
for (const KeyValue<StringName, State> &E : states) {
@ -1412,9 +1425,7 @@ void AnimationNodeStateMachine::remove_node(const StringName &p_name) {
{
Ref<AnimationNode> node = states[p_name].node;
ERR_FAIL_COND(node.is_null());
node->disconnect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed));
node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_renamed));
node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_removed));
_remove_node(node);
}
states.erase(p_name);
@ -1635,16 +1646,17 @@ Vector2 AnimationNodeStateMachine::get_graph_offset() const {
return graph_offset;
}
AnimationNode::NodeTimeInfo AnimationNodeStateMachine::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
Ref<AnimationNodeStateMachinePlayback> playback_new = get_parameter(playback);
AnimationNode::NodeTimeInfo AnimationNodeStateMachine::_process(ProcessState &p_process_state, AnimationNodeInstance &p_instance, const AnimationMixer::PlaybackInfo &p_playback_info, bool p_test_only) {
Ref<AnimationNodeStateMachinePlayback> playback_new = p_instance.get_parameter(playback);
ERR_FAIL_COND_V(playback_new.is_null(), AnimationNode::NodeTimeInfo());
playback_new->_set_base_path(node_state.get_base_path());
playback_new->_set_base_path(p_instance.path);
playback_new->_set_grouped(state_machine_type == STATE_MACHINE_TYPE_GROUPED);
if (p_test_only) {
playback_new = playback_new->duplicate(); // Don't process original when testing.
}
return playback_new->process(this, p_playback_info, p_test_only);
return playback_new->process(p_process_state, p_instance, this, p_playback_info, p_test_only);
}
String AnimationNodeStateMachine::get_caption() const {
@ -1740,7 +1752,7 @@ void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) c
names.sort_custom<StringName::AlphCompare>();
for (const StringName &prop_name : names) {
p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NO_EDITOR));
p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, AnimationNode::get_class_static(), PROPERTY_USAGE_NO_EDITOR));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "states/" + prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
}
@ -1777,7 +1789,7 @@ void AnimationNodeStateMachine::reset_state() {
states[SceneStringName(End)] = end;
emit_changed();
emit_signal(SNAME("tree_changed"));
_tree_changed();
}
void AnimationNodeStateMachine::set_node_position(const StringName &p_name, const Vector2 &p_position) {