Browse Source

Merge pull request #62623 from TokageItLab/refactor-sync-animtree

Add `sync` to `NodeTransition` and `BlendSpace1D/2D` and refactor `sync` in `AnimationTree`
Rémi Verschelde 3 years ago
parent
commit
c39223e0db

+ 2 - 2
doc/classes/AnimationNode.xml

@@ -88,7 +88,7 @@
 			<argument index="3" name="seek_root" type="bool" />
 			<argument index="3" name="seek_root" type="bool" />
 			<argument index="4" name="blend" type="float" />
 			<argument index="4" name="blend" type="float" />
 			<argument index="5" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
 			<argument index="5" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
-			<argument index="6" name="optimize" type="bool" default="true" />
+			<argument index="6" name="sync" type="bool" default="true" />
 			<description>
 			<description>
 				Blend an input. This is only useful for nodes created for an [AnimationNodeBlendTree]. The [code]time[/code] parameter is a relative delta, unless [code]seek[/code] is [code]true[/code], in which case it is absolute. A filter mode may be optionally passed (see [enum FilterAction] for options).
 				Blend an input. This is only useful for nodes created for an [AnimationNodeBlendTree]. The [code]time[/code] parameter is a relative delta, unless [code]seek[/code] is [code]true[/code], in which case it is absolute. A filter mode may be optionally passed (see [enum FilterAction] for options).
 			</description>
 			</description>
@@ -102,7 +102,7 @@
 			<argument index="4" name="seek_root" type="bool" />
 			<argument index="4" name="seek_root" type="bool" />
 			<argument index="5" name="blend" type="float" />
 			<argument index="5" name="blend" type="float" />
 			<argument index="6" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
 			<argument index="6" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
-			<argument index="7" name="optimize" type="bool" default="true" />
+			<argument index="7" name="sync" type="bool" default="true" />
 			<description>
 			<description>
 				Blend another animation node (in case this node contains children animation nodes). This function is only useful if you inherit from [AnimationRootNode] instead, else editors will not display your node for addition.
 				Blend another animation node (in case this node contains children animation nodes). This function is only useful if you inherit from [AnimationRootNode] instead, else editors will not display your node for addition.
 			</description>
 			</description>

+ 1 - 6
doc/classes/AnimationNodeAdd2.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeAdd2" inherits="AnimationNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeAdd2" inherits="AnimationNodeSync" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
 	<brief_description>
 	<brief_description>
 		Blends two animations additively inside of an [AnimationNodeBlendTree].
 		Blends two animations additively inside of an [AnimationNodeBlendTree].
 	</brief_description>
 	</brief_description>
@@ -9,9 +9,4 @@
 	<tutorials>
 	<tutorials>
 		<link title="AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
 		<link title="AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
 	</tutorials>
 	</tutorials>
-	<members>
-		<member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync" default="false">
-			If [code]true[/code], sets the [code]optimization[/code] to [code]false[/code] when calling [method AnimationNode.blend_input], forcing the blended animations to update every frame.
-		</member>
-	</members>
 </class>
 </class>

+ 1 - 6
doc/classes/AnimationNodeAdd3.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeAdd3" inherits="AnimationNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeAdd3" inherits="AnimationNodeSync" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
 	<brief_description>
 	<brief_description>
 		Blends two of three animations additively inside of an [AnimationNodeBlendTree].
 		Blends two of three animations additively inside of an [AnimationNodeBlendTree].
 	</brief_description>
 	</brief_description>
@@ -14,9 +14,4 @@
 		<link title="AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
 		<link title="AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
 		<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
 		<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
 	</tutorials>
 	</tutorials>
-	<members>
-		<member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync" default="false">
-			If [code]true[/code], sets the [code]optimization[/code] to [code]false[/code] when calling [method AnimationNode.blend_input], forcing the blended animations to update every frame.
-		</member>
-	</members>
 </class>
 </class>

+ 1 - 6
doc/classes/AnimationNodeBlend2.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeBlend2" inherits="AnimationNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeBlend2" inherits="AnimationNodeSync" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
 	<brief_description>
 	<brief_description>
 		Blends two animations linearly inside of an [AnimationNodeBlendTree].
 		Blends two animations linearly inside of an [AnimationNodeBlendTree].
 	</brief_description>
 	</brief_description>
@@ -11,9 +11,4 @@
 		<link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link>
 		<link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link>
 		<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
 		<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
 	</tutorials>
 	</tutorials>
-	<members>
-		<member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync" default="false">
-			If [code]true[/code], sets the [code]optimization[/code] to [code]false[/code] when calling [method AnimationNode.blend_input], forcing the blended animations to update every frame.
-		</member>
-	</members>
 </class>
 </class>

+ 1 - 6
doc/classes/AnimationNodeBlend3.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeBlend3" inherits="AnimationNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeBlend3" inherits="AnimationNodeSync" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
 	<brief_description>
 	<brief_description>
 		Blends two of three animations linearly inside of an [AnimationNodeBlendTree].
 		Blends two of three animations linearly inside of an [AnimationNodeBlendTree].
 	</brief_description>
 	</brief_description>
@@ -13,9 +13,4 @@
 	<tutorials>
 	<tutorials>
 		<link title="AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
 		<link title="AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
 	</tutorials>
 	</tutorials>
-	<members>
-		<member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync" default="false">
-			If [code]true[/code], sets the [code]optimization[/code] to [code]false[/code] when calling [method AnimationNode.blend_input], forcing the blended animations to update every frame.
-		</member>
-	</members>
 </class>
 </class>

+ 4 - 0
doc/classes/AnimationNodeBlendSpace1D.xml

@@ -76,6 +76,10 @@
 		<member name="snap" type="float" setter="set_snap" getter="get_snap" default="0.1">
 		<member name="snap" type="float" setter="set_snap" getter="get_snap" default="0.1">
 			Position increment to snap to when moving a point on the axis.
 			Position increment to snap to when moving a point on the axis.
 		</member>
 		</member>
+		<member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync" default="false">
+			If [code]false[/code], the blended animations' frame are stopped when the blend value is [code]0[/code].
+			If [code]true[/code], forcing the blended animations to advance frame.
+		</member>
 		<member name="value_label" type="String" setter="set_value_label" getter="get_value_label" default="&quot;value&quot;">
 		<member name="value_label" type="String" setter="set_value_label" getter="get_value_label" default="&quot;value&quot;">
 			Label of the virtual axis of the blend space.
 			Label of the virtual axis of the blend space.
 		</member>
 		</member>

+ 4 - 0
doc/classes/AnimationNodeBlendSpace2D.xml

@@ -113,6 +113,10 @@
 		<member name="snap" type="Vector2" setter="set_snap" getter="get_snap" default="Vector2(0.1, 0.1)">
 		<member name="snap" type="Vector2" setter="set_snap" getter="get_snap" default="Vector2(0.1, 0.1)">
 			Position increment to snap to when moving a point.
 			Position increment to snap to when moving a point.
 		</member>
 		</member>
+		<member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync" default="false">
+			If [code]false[/code], the blended animations' frame are stopped when the blend value is [code]0[/code].
+			If [code]true[/code], forcing the blended animations to advance frame.
+		</member>
 		<member name="x_label" type="String" setter="set_x_label" getter="get_x_label" default="&quot;x&quot;">
 		<member name="x_label" type="String" setter="set_x_label" getter="get_x_label" default="&quot;x&quot;">
 			Name of the blend space's X axis.
 			Name of the blend space's X axis.
 		</member>
 		</member>

+ 1 - 3
doc/classes/AnimationNodeOneShot.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeOneShot" inherits="AnimationNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeOneShot" inherits="AnimationNodeSync" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
 	<brief_description>
 	<brief_description>
 		Plays an animation once in [AnimationNodeBlendTree].
 		Plays an animation once in [AnimationNodeBlendTree].
 	</brief_description>
 	</brief_description>
@@ -26,8 +26,6 @@
 		</member>
 		</member>
 		<member name="mix_mode" type="int" setter="set_mix_mode" getter="get_mix_mode" enum="AnimationNodeOneShot.MixMode" default="0">
 		<member name="mix_mode" type="int" setter="set_mix_mode" getter="get_mix_mode" enum="AnimationNodeOneShot.MixMode" default="0">
 		</member>
 		</member>
-		<member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync" default="false">
-		</member>
 	</members>
 	</members>
 	<constants>
 	<constants>
 		<constant name="MIX_MODE_BLEND" value="0" enum="MixMode">
 		<constant name="MIX_MODE_BLEND" value="0" enum="MixMode">

+ 15 - 0
doc/classes/AnimationNodeSync.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AnimationNodeSync" inherits="AnimationNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+	<brief_description>
+	</brief_description>
+	<description>
+	</description>
+	<tutorials>
+	</tutorials>
+	<members>
+		<member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync" default="false">
+			If [code]false[/code], the blended animations' frame are stopped when the blend value is [code]0[/code].
+			If [code]true[/code], forcing the blended animations to advance frame.
+		</member>
+	</members>
+</class>

+ 4 - 1
doc/classes/AnimationNodeTransition.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationNodeTransition" inherits="AnimationNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="AnimationNodeTransition" inherits="AnimationNodeSync" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
 	<brief_description>
 	<brief_description>
 		A generic animation transition node for [AnimationTree].
 		A generic animation transition node for [AnimationTree].
 	</brief_description>
 	</brief_description>
@@ -40,6 +40,9 @@
 		</method>
 		</method>
 	</methods>
 	</methods>
 	<members>
 	<members>
+		<member name="from_start" type="bool" setter="set_from_start" getter="is_from_start" default="true">
+			If [code]true[/code], the destination animation is played back from the beginning when switched.
+		</member>
 		<member name="input_count" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0">
 		<member name="input_count" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0">
 			The number of available input ports for this node.
 			The number of available input ports for this node.
 		</member>
 		</member>

+ 11 - 1
editor/plugins/animation_blend_space_1d_editor.cpp

@@ -314,6 +314,8 @@ void AnimationNodeBlendSpace1DEditor::_update_space() {
 	max_value->set_value(blend_space->get_max_space());
 	max_value->set_value(blend_space->get_max_space());
 	min_value->set_value(blend_space->get_min_space());
 	min_value->set_value(blend_space->get_min_space());
 
 
+	sync->set_pressed(blend_space->is_using_sync());
+
 	label_value->set_text(blend_space->get_value_label());
 	label_value->set_text(blend_space->get_value_label());
 
 
 	snap_value->set_value(blend_space->get_snap());
 	snap_value->set_value(blend_space->get_snap());
@@ -329,13 +331,15 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) {
 	}
 	}
 
 
 	updating = true;
 	updating = true;
-	undo_redo->create_action(TTR("Change BlendSpace1D Limits"));
+	undo_redo->create_action(TTR("Change BlendSpace1D Config"));
 	undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value());
 	undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
 	undo_redo->add_do_method(blend_space.ptr(), "set_min_space", min_value->get_value());
 	undo_redo->add_do_method(blend_space.ptr(), "set_min_space", min_value->get_value());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space());
 	undo_redo->add_do_method(blend_space.ptr(), "set_snap", snap_value->get_value());
 	undo_redo->add_do_method(blend_space.ptr(), "set_snap", snap_value->get_value());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
+	undo_redo->add_do_method(blend_space.ptr(), "set_use_sync", sync->is_pressed());
+	undo_redo->add_undo_method(blend_space.ptr(), "set_use_sync", blend_space->is_using_sync());
 	undo_redo->add_do_method(this, "_update_space");
 	undo_redo->add_do_method(this, "_update_space");
 	undo_redo->add_undo_method(this, "_update_space");
 	undo_redo->add_undo_method(this, "_update_space");
 	undo_redo->commit_action();
 	undo_redo->commit_action();
@@ -650,6 +654,12 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
 	snap_value->set_step(0.01);
 	snap_value->set_step(0.01);
 	snap_value->set_max(1000);
 	snap_value->set_max(1000);
 
 
+	top_hb->add_child(memnew(VSeparator));
+	top_hb->add_child(memnew(Label(TTR("Sync:"))));
+	sync = memnew(CheckBox);
+	top_hb->add_child(sync);
+	sync->connect("toggled", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
+
 	edit_hb = memnew(HBoxContainer);
 	edit_hb = memnew(HBoxContainer);
 	top_hb->add_child(edit_hb);
 	top_hb->add_child(edit_hb);
 	edit_hb->add_child(memnew(VSeparator));
 	edit_hb->add_child(memnew(VSeparator));

+ 2 - 0
editor/plugins/animation_blend_space_1d_editor.h

@@ -61,6 +61,8 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
 	SpinBox *max_value = nullptr;
 	SpinBox *max_value = nullptr;
 	SpinBox *min_value = nullptr;
 	SpinBox *min_value = nullptr;
 
 
+	CheckBox *sync = nullptr;
+
 	HBoxContainer *edit_hb = nullptr;
 	HBoxContainer *edit_hb = nullptr;
 	SpinBox *edit_value = nullptr;
 	SpinBox *edit_value = nullptr;
 	Button *open_editor = nullptr;
 	Button *open_editor = nullptr;

+ 11 - 1
editor/plugins/animation_blend_space_2d_editor.cpp

@@ -595,6 +595,7 @@ void AnimationNodeBlendSpace2DEditor::_update_space() {
 
 
 	auto_triangles->set_pressed(blend_space->get_auto_triangles());
 	auto_triangles->set_pressed(blend_space->get_auto_triangles());
 
 
+	sync->set_pressed(blend_space->is_using_sync());
 	interpolation->select(blend_space->get_blend_mode());
 	interpolation->select(blend_space->get_blend_mode());
 
 
 	max_x_value->set_value(blend_space->get_max_space().x);
 	max_x_value->set_value(blend_space->get_max_space().x);
@@ -620,13 +621,15 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) {
 	}
 	}
 
 
 	updating = true;
 	updating = true;
-	undo_redo->create_action(TTR("Change BlendSpace2D Limits"));
+	undo_redo->create_action(TTR("Change BlendSpace2D Config"));
 	undo_redo->add_do_method(blend_space.ptr(), "set_max_space", Vector2(max_x_value->get_value(), max_y_value->get_value()));
 	undo_redo->add_do_method(blend_space.ptr(), "set_max_space", Vector2(max_x_value->get_value(), max_y_value->get_value()));
 	undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
 	undo_redo->add_do_method(blend_space.ptr(), "set_min_space", Vector2(min_x_value->get_value(), min_y_value->get_value()));
 	undo_redo->add_do_method(blend_space.ptr(), "set_min_space", Vector2(min_x_value->get_value(), min_y_value->get_value()));
 	undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space());
 	undo_redo->add_do_method(blend_space.ptr(), "set_snap", Vector2(snap_x->get_value(), snap_y->get_value()));
 	undo_redo->add_do_method(blend_space.ptr(), "set_snap", Vector2(snap_x->get_value(), snap_y->get_value()));
 	undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
+	undo_redo->add_do_method(blend_space.ptr(), "set_use_sync", sync->is_pressed());
+	undo_redo->add_undo_method(blend_space.ptr(), "set_use_sync", blend_space->is_using_sync());
 	undo_redo->add_do_method(blend_space.ptr(), "set_blend_mode", interpolation->get_selected());
 	undo_redo->add_do_method(blend_space.ptr(), "set_blend_mode", interpolation->get_selected());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_blend_mode", blend_space->get_blend_mode());
 	undo_redo->add_undo_method(blend_space.ptr(), "set_blend_mode", blend_space->get_blend_mode());
 	undo_redo->add_do_method(this, "_update_space");
 	undo_redo->add_do_method(this, "_update_space");
@@ -899,6 +902,13 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
 
 
 	top_hb->add_child(memnew(VSeparator));
 	top_hb->add_child(memnew(VSeparator));
 
 
+	top_hb->add_child(memnew(Label(TTR("Sync:"))));
+	sync = memnew(CheckBox);
+	top_hb->add_child(sync);
+	sync->connect("toggled", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed));
+
+	top_hb->add_child(memnew(VSeparator));
+
 	top_hb->add_child(memnew(Label(TTR("Blend:"))));
 	top_hb->add_child(memnew(Label(TTR("Blend:"))));
 	interpolation = memnew(OptionButton);
 	interpolation = memnew(OptionButton);
 	top_hb->add_child(interpolation);
 	top_hb->add_child(interpolation);

+ 1 - 0
editor/plugins/animation_blend_space_2d_editor.h

@@ -55,6 +55,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
 	Button *snap = nullptr;
 	Button *snap = nullptr;
 	SpinBox *snap_x = nullptr;
 	SpinBox *snap_x = nullptr;
 	SpinBox *snap_y = nullptr;
 	SpinBox *snap_y = nullptr;
+	CheckBox *sync = nullptr;
 	OptionButton *interpolation = nullptr;
 	OptionButton *interpolation = nullptr;
 
 
 	Button *auto_triangles = nullptr;
 	Button *auto_triangles = nullptr;

+ 19 - 4
scene/animation/animation_blend_space_1d.cpp

@@ -78,6 +78,9 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
 	ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
 	ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
 	ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
 
 
+	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace1D::set_use_sync);
+	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace1D::is_using_sync);
+
 	ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace1D::_add_blend_point);
 	ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace1D::_add_blend_point);
 
 
 	for (int i = 0; i < MAX_BLEND_POINTS; i++) {
 	for (int i = 0; i < MAX_BLEND_POINTS; i++) {
@@ -89,6 +92,7 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_space", "get_max_space");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_space", "get_max_space");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_value_label", "get_value_label");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_value_label", "get_value_label");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
 }
 }
 
 
 void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
 void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
@@ -211,6 +215,14 @@ String AnimationNodeBlendSpace1D::get_value_label() const {
 	return value_label;
 	return value_label;
 }
 }
 
 
+void AnimationNodeBlendSpace1D::set_use_sync(bool p_sync) {
+	sync = p_sync;
+}
+
+bool AnimationNodeBlendSpace1D::is_using_sync() const {
+	return sync;
+}
+
 void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) {
 void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) {
 	if (p_index == blend_points_used) {
 	if (p_index == blend_points_used) {
 		add_blend_point(p_node, 0);
 		add_blend_point(p_node, 0);
@@ -226,7 +238,7 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_see
 
 
 	if (blend_points_used == 1) {
 	if (blend_points_used == 1) {
 		// only one point available, just play that animation
 		// only one point available, just play that animation
-		return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, false);
+		return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
 	}
 	}
 
 
 	double blend_pos = get_parameter(blend_position);
 	double blend_pos = get_parameter(blend_position);
@@ -295,9 +307,12 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_see
 	double max_time_remaining = 0.0;
 	double max_time_remaining = 0.0;
 
 
 	for (int i = 0; i < blend_points_used; i++) {
 	for (int i = 0; i < blend_points_used; i++) {
-		double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, weights[i], FILTER_IGNORE, false);
-
-		max_time_remaining = MAX(max_time_remaining, remaining);
+		if (i == point_lower || i == point_higher) {
+			double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, weights[i], FILTER_IGNORE, true);
+			max_time_remaining = MAX(max_time_remaining, remaining);
+		} else {
+			blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+		}
 	}
 	}
 
 
 	return max_time_remaining;
 	return max_time_remaining;

+ 5 - 0
scene/animation/animation_blend_space_1d.h

@@ -63,6 +63,8 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
 	StringName blend_position = "blend_position";
 	StringName blend_position = "blend_position";
 
 
 protected:
 protected:
+	bool sync = false;
+
 	virtual void _validate_property(PropertyInfo &property) const override;
 	virtual void _validate_property(PropertyInfo &property) const override;
 	static void _bind_methods();
 	static void _bind_methods();
 
 
@@ -93,6 +95,9 @@ public:
 	void set_value_label(const String &p_label);
 	void set_value_label(const String &p_label);
 	String get_value_label() const;
 	String get_value_label() const;
 
 
+	void set_use_sync(bool p_sync);
+	bool is_using_sync() const;
+
 	double process(double p_time, bool p_seek, bool p_seek_root) override;
 	double process(double p_time, bool p_seek, bool p_seek_root) override;
 	String get_caption() const override;
 	String get_caption() const override;
 
 

+ 23 - 6
scene/animation/animation_blend_space_2d.cpp

@@ -502,7 +502,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
 			for (int j = 0; j < 3; j++) {
 			for (int j = 0; j < 3; j++) {
 				if (i == triangle_points[j]) {
 				if (i == triangle_points[j]) {
 					//blend with the given weight
 					//blend with the given weight
-					double t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, blend_weights[j], FILTER_IGNORE, false);
+					double t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, blend_weights[j], FILTER_IGNORE, true);
 					if (first || t < mind) {
 					if (first || t < mind) {
 						mind = t;
 						mind = t;
 						first = false;
 						first = false;
@@ -513,8 +513,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
 			}
 			}
 
 
 			if (!found) {
 			if (!found) {
-				//ignore
-				blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, false);
+				blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
 			}
 			}
 		}
 		}
 	} else {
 	} else {
@@ -539,16 +538,22 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
 					na_n->set_backward(na_c->is_backward());
 					na_n->set_backward(na_c->is_backward());
 				}
 				}
 				//see how much animation remains
 				//see how much animation remains
-				from = length_internal - blend_node(blend_points[closest].name, blend_points[closest].node, p_time, false, p_seek_root, 0.0, FILTER_IGNORE, false);
+				from = length_internal - blend_node(blend_points[closest].name, blend_points[closest].node, p_time, false, p_seek_root, 0.0, FILTER_IGNORE, true);
 			}
 			}
 
 
-			mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_seek_root, 1.0, FILTER_IGNORE, false);
+			mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_seek_root, 1.0, FILTER_IGNORE, true);
 			length_internal = from + mind;
 			length_internal = from + mind;
 
 
 			closest = new_closest;
 			closest = new_closest;
 
 
 		} else {
 		} else {
-			mind = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, false);
+			mind = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
+		}
+
+		for (int i = 0; i < blend_points_used; i++) {
+			if (i != closest) {
+				blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+			}
 		}
 		}
 	}
 	}
 
 
@@ -604,6 +609,14 @@ AnimationNodeBlendSpace2D::BlendMode AnimationNodeBlendSpace2D::get_blend_mode()
 	return blend_mode;
 	return blend_mode;
 }
 }
 
 
+void AnimationNodeBlendSpace2D::set_use_sync(bool p_sync) {
+	sync = p_sync;
+}
+
+bool AnimationNodeBlendSpace2D::is_using_sync() const {
+	return sync;
+}
+
 void AnimationNodeBlendSpace2D::_bind_methods() {
 void AnimationNodeBlendSpace2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1));
 	ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1));
 	ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace2D::set_blend_point_position);
 	ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace2D::set_blend_point_position);
@@ -644,6 +657,9 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace2D::set_blend_mode);
 	ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace2D::set_blend_mode);
 	ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace2D::get_blend_mode);
 	ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace2D::get_blend_mode);
 
 
+	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace2D::set_use_sync);
+	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace2D::is_using_sync);
+
 	ClassDB::bind_method(D_METHOD("_update_triangles"), &AnimationNodeBlendSpace2D::_update_triangles);
 	ClassDB::bind_method(D_METHOD("_update_triangles"), &AnimationNodeBlendSpace2D::_update_triangles);
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_auto_triangles", "get_auto_triangles");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_auto_triangles", "get_auto_triangles");
@@ -661,6 +677,7 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_x_label", "get_x_label");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_x_label", "get_x_label");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_y_label", "get_y_label");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_y_label", "get_y_label");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NO_EDITOR), "set_blend_mode", "get_blend_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NO_EDITOR), "set_blend_mode", "get_blend_mode");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
 
 
 	ADD_SIGNAL(MethodInfo("triangles_updated"));
 	ADD_SIGNAL(MethodInfo("triangles_updated"));
 	BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);
 	BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);

+ 5 - 0
scene/animation/animation_blend_space_2d.h

@@ -88,6 +88,8 @@ protected:
 	void _tree_changed();
 	void _tree_changed();
 
 
 protected:
 protected:
+	bool sync = false;
+
 	virtual void _validate_property(PropertyInfo &property) const override;
 	virtual void _validate_property(PropertyInfo &property) const override;
 	static void _bind_methods();
 	static void _bind_methods();
 
 
@@ -137,6 +139,9 @@ public:
 	void set_blend_mode(BlendMode p_blend_mode);
 	void set_blend_mode(BlendMode p_blend_mode);
 	BlendMode get_blend_mode() const;
 	BlendMode get_blend_mode() const;
 
 
+	void set_use_sync(bool p_sync);
+	bool is_using_sync() const;
+
 	virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) override;
 	virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) override;
 
 
 	AnimationNodeBlendSpace2D();
 	AnimationNodeBlendSpace2D();

+ 66 - 91
scene/animation/animation_blend_tree.cpp

@@ -179,6 +179,26 @@ AnimationNodeAnimation::AnimationNodeAnimation() {
 
 
 ////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////
 
 
+void AnimationNodeSync::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeSync::set_use_sync);
+	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeSync::is_using_sync);
+
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
+}
+
+void AnimationNodeSync::set_use_sync(bool p_sync) {
+	sync = p_sync;
+}
+
+bool AnimationNodeSync::is_using_sync() const {
+	return sync;
+}
+
+AnimationNodeSync::AnimationNodeSync() {
+}
+
+////////////////////////////////////////////////////////
+
 void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
 void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
 	r_list->push_back(PropertyInfo(Variant::BOOL, active));
 	r_list->push_back(PropertyInfo(Variant::BOOL, active));
 	r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
 	r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
@@ -276,7 +296,7 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo
 		}
 		}
 
 
 		if (!active) {
 		if (!active) {
-			return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, !sync);
+			return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
 		}
 		}
 	}
 	}
 
 
@@ -313,12 +333,12 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo
 
 
 	double main_rem;
 	double main_rem;
 	if (mix == MIX_MODE_ADD) {
 	if (mix == MIX_MODE_ADD) {
-		main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, !sync);
+		main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
 	} else {
 	} else {
-		main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_BLEND, !sync);
+		main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_BLEND, sync);
 	}
 	}
 
 
-	double os_rem = blend_input(1, os_seek ? time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, false);
+	double os_rem = blend_input(1, os_seek ? time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, true);
 
 
 	if (do_start) {
 	if (do_start) {
 		remaining = os_rem;
 		remaining = os_rem;
@@ -343,14 +363,6 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo
 	return MAX(main_rem, remaining);
 	return MAX(main_rem, remaining);
 }
 }
 
 
-void AnimationNodeOneShot::set_use_sync(bool p_sync) {
-	sync = p_sync;
-}
-
-bool AnimationNodeOneShot::is_using_sync() const {
-	return sync;
-}
-
 void AnimationNodeOneShot::_bind_methods() {
 void AnimationNodeOneShot::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_fadein_time", "time"), &AnimationNodeOneShot::set_fadein_time);
 	ClassDB::bind_method(D_METHOD("set_fadein_time", "time"), &AnimationNodeOneShot::set_fadein_time);
 	ClassDB::bind_method(D_METHOD("get_fadein_time"), &AnimationNodeOneShot::get_fadein_time);
 	ClassDB::bind_method(D_METHOD("get_fadein_time"), &AnimationNodeOneShot::get_fadein_time);
@@ -370,9 +382,6 @@ void AnimationNodeOneShot::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode);
 	ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode);
 	ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode);
 	ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode);
 
 
-	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync);
-	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync);
-
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_mode", PROPERTY_HINT_ENUM, "Blend,Add"), "set_mix_mode", "get_mix_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_mode", PROPERTY_HINT_ENUM, "Blend,Add"), "set_mix_mode", "get_mix_mode");
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadein_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_fadein_time", "get_fadein_time");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadein_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_fadein_time", "get_fadein_time");
@@ -384,9 +393,6 @@ void AnimationNodeOneShot::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay");
 
 
-	ADD_GROUP("", "");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
-
 	BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
 	BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
 	BIND_ENUM_CONSTANT(MIX_MODE_ADD);
 	BIND_ENUM_CONSTANT(MIX_MODE_ADD);
 }
 }
@@ -410,31 +416,19 @@ String AnimationNodeAdd2::get_caption() const {
 	return "Add2";
 	return "Add2";
 }
 }
 
 
-void AnimationNodeAdd2::set_use_sync(bool p_sync) {
-	sync = p_sync;
-}
-
-bool AnimationNodeAdd2::is_using_sync() const {
-	return sync;
-}
-
 bool AnimationNodeAdd2::has_filter() const {
 bool AnimationNodeAdd2::has_filter() const {
 	return true;
 	return true;
 }
 }
 
 
 double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_seek_root) {
 double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_seek_root) {
 	double amount = get_parameter(add_amount);
 	double amount = get_parameter(add_amount);
-	double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, !sync);
-	blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, !sync);
+	double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
+	blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync);
 
 
 	return rem0;
 	return rem0;
 }
 }
 
 
 void AnimationNodeAdd2::_bind_methods() {
 void AnimationNodeAdd2::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd2::set_use_sync);
-	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd2::is_using_sync);
-
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
 }
 }
 
 
 AnimationNodeAdd2::AnimationNodeAdd2() {
 AnimationNodeAdd2::AnimationNodeAdd2() {
@@ -456,32 +450,20 @@ String AnimationNodeAdd3::get_caption() const {
 	return "Add3";
 	return "Add3";
 }
 }
 
 
-void AnimationNodeAdd3::set_use_sync(bool p_sync) {
-	sync = p_sync;
-}
-
-bool AnimationNodeAdd3::is_using_sync() const {
-	return sync;
-}
-
 bool AnimationNodeAdd3::has_filter() const {
 bool AnimationNodeAdd3::has_filter() const {
 	return true;
 	return true;
 }
 }
 
 
 double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_seek_root) {
 double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_seek_root) {
 	double amount = get_parameter(add_amount);
 	double amount = get_parameter(add_amount);
-	blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_PASS, !sync);
-	double rem0 = blend_input(1, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, !sync);
-	blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_PASS, !sync);
+	blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_PASS, sync);
+	double rem0 = blend_input(1, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
+	blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_PASS, sync);
 
 
 	return rem0;
 	return rem0;
 }
 }
 
 
 void AnimationNodeAdd3::_bind_methods() {
 void AnimationNodeAdd3::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd3::set_use_sync);
-	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd3::is_using_sync);
-
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
 }
 }
 
 
 AnimationNodeAdd3::AnimationNodeAdd3() {
 AnimationNodeAdd3::AnimationNodeAdd3() {
@@ -507,29 +489,17 @@ String AnimationNodeBlend2::get_caption() const {
 double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_seek_root) {
 double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_seek_root) {
 	double amount = get_parameter(blend_amount);
 	double amount = get_parameter(blend_amount);
 
 
-	double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - amount, FILTER_BLEND, !sync);
-	double rem1 = blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, !sync);
+	double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - amount, FILTER_BLEND, sync);
+	double rem1 = blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync);
 
 
 	return amount > 0.5 ? rem1 : rem0; //hacky but good enough
 	return amount > 0.5 ? rem1 : rem0; //hacky but good enough
 }
 }
 
 
-void AnimationNodeBlend2::set_use_sync(bool p_sync) {
-	sync = p_sync;
-}
-
-bool AnimationNodeBlend2::is_using_sync() const {
-	return sync;
-}
-
 bool AnimationNodeBlend2::has_filter() const {
 bool AnimationNodeBlend2::has_filter() const {
 	return true;
 	return true;
 }
 }
 
 
 void AnimationNodeBlend2::_bind_methods() {
 void AnimationNodeBlend2::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend2::set_use_sync);
-	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend2::is_using_sync);
-
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
 }
 }
 
 
 AnimationNodeBlend2::AnimationNodeBlend2() {
 AnimationNodeBlend2::AnimationNodeBlend2() {
@@ -551,35 +521,22 @@ String AnimationNodeBlend3::get_caption() const {
 	return "Blend3";
 	return "Blend3";
 }
 }
 
 
-void AnimationNodeBlend3::set_use_sync(bool p_sync) {
-	sync = p_sync;
-}
-
-bool AnimationNodeBlend3::is_using_sync() const {
-	return sync;
-}
-
 double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_seek_root) {
 double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_seek_root) {
 	double amount = get_parameter(blend_amount);
 	double amount = get_parameter(blend_amount);
-	double rem0 = blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_IGNORE, !sync);
-	double rem1 = blend_input(1, p_time, p_seek, p_seek_root, 1.0 - ABS(amount), FILTER_IGNORE, !sync);
-	double rem2 = blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_IGNORE, !sync);
+	double rem0 = blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_IGNORE, sync);
+	double rem1 = blend_input(1, p_time, p_seek, p_seek_root, 1.0 - ABS(amount), FILTER_IGNORE, sync);
+	double rem2 = blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_IGNORE, sync);
 
 
 	return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough
 	return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough
 }
 }
 
 
 void AnimationNodeBlend3::_bind_methods() {
 void AnimationNodeBlend3::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend3::set_use_sync);
-	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend3::is_using_sync);
-
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
 }
 }
 
 
 AnimationNodeBlend3::AnimationNodeBlend3() {
 AnimationNodeBlend3::AnimationNodeBlend3() {
 	add_input("-blend");
 	add_input("-blend");
 	add_input("in");
 	add_input("in");
 	add_input("+blend");
 	add_input("+blend");
-	sync = false;
 }
 }
 
 
 /////////////////////////////////
 /////////////////////////////////
@@ -599,9 +556,9 @@ String AnimationNodeTimeScale::get_caption() const {
 double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_seek_root) {
 double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_seek_root) {
 	double scale = get_parameter(this->scale);
 	double scale = get_parameter(this->scale);
 	if (p_seek) {
 	if (p_seek) {
-		return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, false);
+		return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
 	} else {
 	} else {
-		return blend_input(0, p_time * scale, false, p_seek_root, 1.0, FILTER_IGNORE, false);
+		return blend_input(0, p_time * scale, false, p_seek_root, 1.0, FILTER_IGNORE, true);
 	}
 	}
 }
 }
 
 
@@ -629,13 +586,13 @@ String AnimationNodeTimeSeek::get_caption() const {
 double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_seek_root) {
 double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_seek_root) {
 	double seek_pos = get_parameter(this->seek_pos);
 	double seek_pos = get_parameter(this->seek_pos);
 	if (p_seek) {
 	if (p_seek) {
-		return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, false);
+		return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
 	} else if (seek_pos >= 0) {
 	} else if (seek_pos >= 0) {
-		double ret = blend_input(0, seek_pos, true, true, 1.0, FILTER_IGNORE, false);
+		double ret = blend_input(0, seek_pos, true, true, 1.0, FILTER_IGNORE, true);
 		set_parameter(this->seek_pos, -1.0); //reset
 		set_parameter(this->seek_pos, -1.0); //reset
 		return ret;
 		return ret;
 	} else {
 	} else {
-		return blend_input(0, p_time, false, p_seek_root, 1.0, FILTER_IGNORE, false);
+		return blend_input(0, p_time, false, p_seek_root, 1.0, FILTER_IGNORE, true);
 	}
 	}
 }
 }
 
 
@@ -727,6 +684,14 @@ float AnimationNodeTransition::get_cross_fade_time() const {
 	return xfade;
 	return xfade;
 }
 }
 
 
+void AnimationNodeTransition::set_from_start(bool p_from_start) {
+	from_start = p_from_start;
+}
+
+bool AnimationNodeTransition::is_from_start() const {
+	return from_start;
+}
+
 double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_root) {
 double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_root) {
 	int current = get_parameter(this->current);
 	int current = get_parameter(this->current);
 	int prev = get_parameter(this->prev);
 	int prev = get_parameter(this->prev);
@@ -753,9 +718,15 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
 
 
 	double rem = 0.0;
 	double rem = 0.0;
 
 
+	for (int i = 0; i < enabled_inputs; i++) {
+		if (i != current && i != prev) {
+			blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+		}
+	}
+
 	if (prev < 0) { // process current animation, check for transition
 	if (prev < 0) { // process current animation, check for transition
 
 
-		rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, false);
+		rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
 
 
 		if (p_seek) {
 		if (p_seek) {
 			time = p_time;
 			time = p_time;
@@ -771,18 +742,18 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
 
 
 		float blend = xfade == 0 ? 0 : (prev_xfading / xfade);
 		float blend = xfade == 0 ? 0 : (prev_xfading / xfade);
 
 
-		if (!p_seek && switched) { //just switched, seek to start of current
+		if (from_start && !p_seek && switched) { //just switched, seek to start of current
 
 
-			rem = blend_input(current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, false);
+			rem = blend_input(current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
 		} else {
 		} else {
-			rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, false);
+			rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
 		}
 		}
 
 
-		if (p_seek) { // don't seek prev animation
-			blend_input(prev, 0, false, p_seek_root, blend, FILTER_IGNORE, false);
+		if (p_seek) {
+			blend_input(prev, p_time, true, p_seek_root, blend, FILTER_IGNORE, true);
 			time = p_time;
 			time = p_time;
 		} else {
 		} else {
-			blend_input(prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, false);
+			blend_input(prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, true);
 			time += p_time;
 			time += p_time;
 			prev_xfading -= p_time;
 			prev_xfading -= p_time;
 			if (prev_xfading < 0) {
 			if (prev_xfading < 0) {
@@ -824,8 +795,12 @@ void AnimationNodeTransition::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
 	ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
 	ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
 	ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
 
 
+	ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start);
+	ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start);
+
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_cross_fade_time", "get_cross_fade_time");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_cross_fade_time", "get_cross_fade_time");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start");
 
 
 	for (int i = 0; i < MAX_INPUTS; i++) {
 	for (int i = 0; i < MAX_INPUTS; i++) {
 		ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i);
 		ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i);
@@ -846,7 +821,7 @@ String AnimationNodeOutput::get_caption() const {
 }
 }
 
 
 double AnimationNodeOutput::process(double p_time, bool p_seek, bool p_seek_root) {
 double AnimationNodeOutput::process(double p_time, bool p_seek, bool p_seek_root) {
-	return blend_input(0, p_time, p_seek, p_seek_root, 1.0);
+	return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
 }
 }
 
 
 AnimationNodeOutput::AnimationNodeOutput() {
 AnimationNodeOutput::AnimationNodeOutput() {
@@ -1060,7 +1035,7 @@ String AnimationNodeBlendTree::get_caption() const {
 
 
 double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_seek_root) {
 double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_seek_root) {
 	Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
 	Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
-	return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_seek_root, 1.0);
+	return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
 }
 }
 
 
 void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
 void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {

+ 31 - 33
scene/animation/animation_blend_tree.h

@@ -77,8 +77,23 @@ private:
 
 
 VARIANT_ENUM_CAST(AnimationNodeAnimation::PlayMode)
 VARIANT_ENUM_CAST(AnimationNodeAnimation::PlayMode)
 
 
-class AnimationNodeOneShot : public AnimationNode {
-	GDCLASS(AnimationNodeOneShot, AnimationNode);
+class AnimationNodeSync : public AnimationNode {
+	GDCLASS(AnimationNodeSync, AnimationNode);
+
+protected:
+	bool sync = false;
+
+	static void _bind_methods();
+
+public:
+	void set_use_sync(bool p_sync);
+	bool is_using_sync() const;
+
+	AnimationNodeSync();
+};
+
+class AnimationNodeOneShot : public AnimationNodeSync {
+	GDCLASS(AnimationNodeOneShot, AnimationNodeSync);
 
 
 public:
 public:
 	enum MixMode {
 	enum MixMode {
@@ -95,8 +110,6 @@ private:
 	float autorestart_random_delay = 0.0;
 	float autorestart_random_delay = 0.0;
 	MixMode mix = MIX_MODE_BLEND;
 	MixMode mix = MIX_MODE_BLEND;
 
 
-	bool sync = false;
-
 	/*	bool active;
 	/*	bool active;
 	bool do_start;
 	bool do_start;
 	float time;
 	float time;
@@ -134,9 +147,6 @@ public:
 	void set_mix_mode(MixMode p_mix);
 	void set_mix_mode(MixMode p_mix);
 	MixMode get_mix_mode() const;
 	MixMode get_mix_mode() const;
 
 
-	void set_use_sync(bool p_sync);
-	bool is_using_sync() const;
-
 	virtual bool has_filter() const override;
 	virtual bool has_filter() const override;
 	virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
 	virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
 
 
@@ -145,11 +155,10 @@ public:
 
 
 VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
 VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
 
 
-class AnimationNodeAdd2 : public AnimationNode {
-	GDCLASS(AnimationNodeAdd2, AnimationNode);
+class AnimationNodeAdd2 : public AnimationNodeSync {
+	GDCLASS(AnimationNodeAdd2, AnimationNodeSync);
 
 
 	StringName add_amount = PNAME("add_amount");
 	StringName add_amount = PNAME("add_amount");
-	bool sync = false;
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
@@ -160,20 +169,16 @@ public:
 
 
 	virtual String get_caption() const override;
 	virtual String get_caption() const override;
 
 
-	void set_use_sync(bool p_sync);
-	bool is_using_sync() const;
-
 	virtual bool has_filter() const override;
 	virtual bool has_filter() const override;
 	virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
 	virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
 
 
 	AnimationNodeAdd2();
 	AnimationNodeAdd2();
 };
 };
 
 
-class AnimationNodeAdd3 : public AnimationNode {
-	GDCLASS(AnimationNodeAdd3, AnimationNode);
+class AnimationNodeAdd3 : public AnimationNodeSync {
+	GDCLASS(AnimationNodeAdd3, AnimationNodeSync);
 
 
 	StringName add_amount = PNAME("add_amount");
 	StringName add_amount = PNAME("add_amount");
-	bool sync = false;
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
@@ -184,20 +189,16 @@ public:
 
 
 	virtual String get_caption() const override;
 	virtual String get_caption() const override;
 
 
-	void set_use_sync(bool p_sync);
-	bool is_using_sync() const;
-
 	virtual bool has_filter() const override;
 	virtual bool has_filter() const override;
 	virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
 	virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
 
 
 	AnimationNodeAdd3();
 	AnimationNodeAdd3();
 };
 };
 
 
-class AnimationNodeBlend2 : public AnimationNode {
-	GDCLASS(AnimationNodeBlend2, AnimationNode);
+class AnimationNodeBlend2 : public AnimationNodeSync {
+	GDCLASS(AnimationNodeBlend2, AnimationNodeSync);
 
 
 	StringName blend_amount = PNAME("blend_amount");
 	StringName blend_amount = PNAME("blend_amount");
-	bool sync = false;
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
@@ -209,18 +210,14 @@ public:
 	virtual String get_caption() const override;
 	virtual String get_caption() const override;
 	virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
 	virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
 
 
-	void set_use_sync(bool p_sync);
-	bool is_using_sync() const;
-
 	virtual bool has_filter() const override;
 	virtual bool has_filter() const override;
 	AnimationNodeBlend2();
 	AnimationNodeBlend2();
 };
 };
 
 
-class AnimationNodeBlend3 : public AnimationNode {
-	GDCLASS(AnimationNodeBlend3, AnimationNode);
+class AnimationNodeBlend3 : public AnimationNodeSync {
+	GDCLASS(AnimationNodeBlend3, AnimationNodeSync);
 
 
 	StringName blend_amount = PNAME("blend_amount");
 	StringName blend_amount = PNAME("blend_amount");
-	bool sync;
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
@@ -231,9 +228,6 @@ public:
 
 
 	virtual String get_caption() const override;
 	virtual String get_caption() const override;
 
 
-	void set_use_sync(bool p_sync);
-	bool is_using_sync() const;
-
 	double process(double p_time, bool p_seek, bool p_seek_root) override;
 	double process(double p_time, bool p_seek, bool p_seek_root) override;
 	AnimationNodeBlend3();
 	AnimationNodeBlend3();
 };
 };
@@ -276,8 +270,8 @@ public:
 	AnimationNodeTimeSeek();
 	AnimationNodeTimeSeek();
 };
 };
 
 
-class AnimationNodeTransition : public AnimationNode {
-	GDCLASS(AnimationNodeTransition, AnimationNode);
+class AnimationNodeTransition : public AnimationNodeSync {
+	GDCLASS(AnimationNodeTransition, AnimationNodeSync);
 
 
 	enum {
 	enum {
 		MAX_INPUTS = 32
 		MAX_INPUTS = 32
@@ -304,6 +298,7 @@ class AnimationNodeTransition : public AnimationNode {
 	StringName prev_current = "prev_current";
 	StringName prev_current = "prev_current";
 
 
 	float xfade = 0.0;
 	float xfade = 0.0;
+	bool from_start = true;
 
 
 	void _update_inputs();
 	void _update_inputs();
 
 
@@ -329,6 +324,9 @@ public:
 	void set_cross_fade_time(float p_fade);
 	void set_cross_fade_time(float p_fade);
 	float get_cross_fade_time() const;
 	float get_cross_fade_time() const;
 
 
+	void set_from_start(bool p_from_start);
+	bool is_from_start() const;
+
 	double process(double p_time, bool p_seek, bool p_seek_root) override;
 	double process(double p_time, bool p_seek, bool p_seek_root) override;
 
 
 	AnimationNodeTransition();
 	AnimationNodeTransition();

+ 6 - 6
scene/animation/animation_node_state_machine.cpp

@@ -395,7 +395,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
 			current = p_state_machine->start_node;
 			current = p_state_machine->start_node;
 		}
 		}
 
 
-		len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 1.0, AnimationNode::FILTER_IGNORE, false);
+		len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 1.0, AnimationNode::FILTER_IGNORE, true);
 		pos_current = 0;
 		pos_current = 0;
 	}
 	}
 
 
@@ -420,10 +420,10 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
 		}
 		}
 	}
 	}
 
 
-	float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, false);
+	float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, true);
 
 
 	if (fading_from != StringName()) {
 	if (fading_from != StringName()) {
-		p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_seek_root, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, false);
+		p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_seek_root, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, true);
 	}
 	}
 
 
 	//guess playback position
 	//guess playback position
@@ -577,12 +577,12 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
 			}
 			}
 			current = next;
 			current = next;
 			if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
 			if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
-				len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, false);
+				len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
 				pos_current = MIN(pos_current, len_current);
 				pos_current = MIN(pos_current, len_current);
-				p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, false);
+				p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
 
 
 			} else {
 			} else {
-				len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, false);
+				len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
 				pos_current = 0;
 				pos_current = 0;
 			}
 			}
 
 

+ 11 - 9
scene/animation/animation_tree.cpp

@@ -150,7 +150,7 @@ void AnimationNode::make_invalid(const String &p_reason) {
 	state->invalid_reasons += String::utf8("•  ") + p_reason;
 	state->invalid_reasons += String::utf8("•  ") + p_reason;
 }
 }
 
 
-double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_optimize) {
+double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_sync) {
 	ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
 	ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
 	ERR_FAIL_COND_V(!state, 0);
 	ERR_FAIL_COND_V(!state, 0);
 
 
@@ -169,7 +169,7 @@ double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool
 
 
 	//inputs.write[p_input].last_pass = state->last_pass;
 	//inputs.write[p_input].last_pass = state->last_pass;
 	real_t activity = 0.0;
 	real_t activity = 0.0;
-	double ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_seek_root, p_blend, p_filter, p_optimize, &activity);
+	double ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_seek_root, p_blend, p_filter, p_sync, &activity);
 
 
 	Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path);
 	Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path);
 
 
@@ -180,11 +180,11 @@ double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool
 	return ret;
 	return ret;
 }
 }
 
 
-double AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_optimize) {
-	return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_seek_root, p_blend, p_filter, p_optimize);
+double AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_sync) {
+	return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_seek_root, p_blend, p_filter, p_sync);
 }
 }
 
 
-double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_optimize, real_t *r_max) {
+double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_sync, real_t *r_max) {
 	ERR_FAIL_COND_V(!p_node.is_valid(), 0);
 	ERR_FAIL_COND_V(!p_node.is_valid(), 0);
 	ERR_FAIL_COND_V(!state, 0);
 	ERR_FAIL_COND_V(!state, 0);
 
 
@@ -292,9 +292,11 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
 	}
 	}
 
 
 	// If tracks for blending don't exist for one of the animations, Rest or RESET animation is blended as init animation instead.
 	// If tracks for blending don't exist for one of the animations, Rest or RESET animation is blended as init animation instead.
-	// Then, blend weight is 0 means that the init animation blend weight is 1.
+	// Then blend weight is 0 means that the init animation blend weight is 1.
+	// In that case, processing only the animation with the lacking track will not process the lacking track, and will not properly apply the Reset value.
+	// This means that all tracks which the animations in the branch that may be blended have must be processed.
 	// Therefore, the blending process must be executed even if the blend weight is 0.
 	// Therefore, the blending process must be executed even if the blend weight is 0.
-	if (!p_seek && p_optimize && !any_valid) {
+	if (!p_seek && !p_sync && !any_valid) {
 		return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_seek_root, p_connections);
 		return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_seek_root, p_connections);
 	}
 	}
 	return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_seek_root, p_connections);
 	return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_seek_root, p_connections);
@@ -428,8 +430,8 @@ void AnimationNode::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
 	ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
 
 
 	ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "seek_root", "blend", "pingponged"), &AnimationNode::blend_animation, DEFVAL(0));
 	ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "seek_root", "blend", "pingponged"), &AnimationNode::blend_animation, DEFVAL(0));
-	ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "seek_root", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
-	ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "seek_root", "blend", "filter", "optimize"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
+	ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "seek_root", "blend", "filter", "sync"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
+	ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "seek_root", "blend", "filter", "sync"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
 
 
 	ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter);
 	ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter);
 	ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);
 	ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);

+ 3 - 3
scene/animation/animation_tree.h

@@ -99,12 +99,12 @@ public:
 	Array _get_filters() const;
 	Array _get_filters() const;
 	void _set_filters(const Array &p_filters);
 	void _set_filters(const Array &p_filters);
 	friend class AnimationNodeBlendTree;
 	friend class AnimationNodeBlendTree;
-	double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, real_t *r_max = nullptr);
+	double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, real_t *r_max = nullptr);
 
 
 protected:
 protected:
 	void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_seek_root, real_t p_blend, int p_pingponged = 0);
 	void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_seek_root, real_t p_blend, int p_pingponged = 0);
-	double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
-	double blend_input(int p_input, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
+	double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);
+	double blend_input(int p_input, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);
 
 
 	void make_invalid(const String &p_reason);
 	void make_invalid(const String &p_reason);
 	AnimationTree *get_animation_tree() const;
 	AnimationTree *get_animation_tree() const;

+ 1 - 0
scene/register_scene_types.cpp

@@ -439,6 +439,7 @@ void register_scene_types() {
 	GDREGISTER_CLASS(AnimationNodeStateMachine);
 	GDREGISTER_CLASS(AnimationNodeStateMachine);
 	GDREGISTER_CLASS(AnimationNodeStateMachinePlayback);
 	GDREGISTER_CLASS(AnimationNodeStateMachinePlayback);
 
 
+	GDREGISTER_CLASS(AnimationNodeSync);
 	GDREGISTER_CLASS(AnimationNodeStateMachineTransition);
 	GDREGISTER_CLASS(AnimationNodeStateMachineTransition);
 	GDREGISTER_CLASS(AnimationNodeOutput);
 	GDREGISTER_CLASS(AnimationNodeOutput);
 	GDREGISTER_CLASS(AnimationNodeOneShot);
 	GDREGISTER_CLASS(AnimationNodeOneShot);