Skip to content

Commit ab2f101

Browse files
committed
Add set_name() and get_name() methods to Tween for debugging purposes
Use optional tween names in tweener errors Make messages more consistent
1 parent 08e6cd1 commit ab2f101

File tree

3 files changed

+101
-14
lines changed

3 files changed

+101
-14
lines changed

doc/classes/Tween.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,13 @@
137137
Returns the number of remaining loops for this [Tween] (see [method set_loops]). A return value of [code]-1[/code] indicates an infinitely looping [Tween], and a return value of [code]0[/code] indicates that the [Tween] has already finished.
138138
</description>
139139
</method>
140+
<method name="get_name" qualifiers="const">
141+
<return type="StringName" />
142+
<description>
143+
Returns the name set using [method set_name] for this [Tween], or an empty StringName if none was set.
144+
[b]Warning:[/b] Note that a [Tween]'s name is not guaranteed to uniquely identify it.
145+
</description>
146+
</method>
140147
<method name="get_total_elapsed_time" qualifiers="const">
141148
<return type="float" />
142149
<description>
@@ -244,6 +251,26 @@
244251
[b]Warning:[/b] Make sure to always add some duration/delay when using infinite loops. To prevent the game freezing, 0-duration looped animations (e.g. a single [CallbackTweener] with no delay) are stopped after a small number of loops, which may produce unexpected results. If a [Tween]'s lifetime depends on some node, always use [method bind_node].
245252
</description>
246253
</method>
254+
<method name="set_name">
255+
<return type="void" />
256+
<param index="0" name="name" type="StringName" />
257+
<description>
258+
Sets a name for this [Tween] to use in error statements and when displayed as a string. This is useful for determining exactly which [Tween] is raising errors when many [Tween]s are being used at the same time.
259+
[codeblock]
260+
var unnamed_tween = create_tween()
261+
unnamed_tween.tween_callback(func(): print("This tween is looping forever"))
262+
unnamed_tween.set_loops(-1)
263+
# ERROR: Infinite loop detected. Check set_loops() description for more info.
264+
265+
var named_tween = create_tween()
266+
named_tween.set_name("SlideDown")
267+
named_tween.tween_callback(func(): print("This tween is looping forever"))
268+
named_tween.set_loops(-1)
269+
# ERROR: Infinite loop detected in Tween "SlideDown". Check set_loops() description for more info.
270+
[/codeblock]
271+
See also [method get_name].
272+
</description>
273+
</method>
247274
<method name="set_parallel">
248275
<return type="Tween" />
249276
<param index="0" name="parallel" type="bool" default="true" />

scene/animation/tween.cpp

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,14 @@
3434
#include "scene/main/node.h"
3535
#include "scene/resources/animation.h"
3636

37-
#define CHECK_VALID() \
38-
ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); \
39-
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
37+
#define CHECK_VALID() \
38+
if (name.length() > 0) { \
39+
ERR_FAIL_COND_V_MSG(!valid, nullptr, vformat("Tween \"%s\" invalid. Either finished or created outside scene tree.", name)); \
40+
ERR_FAIL_COND_V_MSG(started, nullptr, vformat("Can't append to a Tween \"%s\" that has started. Use stop() first.", name)); \
41+
} else { \
42+
ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); \
43+
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); \
44+
}
4045

4146
Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
4247
{ &Linear::in, &Linear::in, &Linear::in, &Linear::in }, // Linear is the same for each easing.
@@ -78,7 +83,11 @@ void Tweener::_bind_methods() {
7883
void Tween::_start_tweeners() {
7984
if (tweeners.is_empty()) {
8085
dead = true;
81-
ERR_FAIL_MSG("Tween without commands, aborting.");
86+
if (name.length() > 0) {
87+
ERR_FAIL_MSG(vformat("Tween \"%s\" has no commands, aborting.", name));
88+
} else {
89+
ERR_FAIL_MSG("Tween has no commands, aborting.");
90+
}
8291
}
8392

8493
for (Ref<Tweener> &tweener : tweeners[current_step]) {
@@ -192,8 +201,14 @@ void Tween::pause() {
192201
}
193202

194203
void Tween::play() {
195-
ERR_FAIL_COND_MSG(!valid, "Tween invalid. Either finished or created outside scene tree.");
196-
ERR_FAIL_COND_MSG(dead, "Can't play finished Tween, use stop() first to reset its state.");
204+
if (name.length() > 0) {
205+
ERR_FAIL_COND_MSG(!valid, vformat("Tween \"%s\" invalid. Either finished or created outside scene tree.", name));
206+
ERR_FAIL_COND_MSG(dead, vformat("Can't play finished Tween \"%s\", use stop() first to reset its state.", name));
207+
} else {
208+
ERR_FAIL_COND_MSG(!valid, "Tween invalid. Either finished or created outside scene tree.");
209+
ERR_FAIL_COND_MSG(dead, "Can't play finished Tween, use stop() first to reset its state.");
210+
}
211+
197212
running = true;
198213
}
199214

@@ -309,7 +324,11 @@ RequiredResult<Tween> Tween::chain() {
309324
}
310325

311326
bool Tween::custom_step(double p_delta) {
312-
ERR_FAIL_COND_V_MSG(in_step, true, "Can't call custom_step() during another Tween step.");
327+
if (name.length() > 0) {
328+
ERR_FAIL_COND_V_MSG(in_step, true, vformat("Can't call custom_step() during another Tween step for Tween named \"%s\".", name));
329+
} else {
330+
ERR_FAIL_COND_V_MSG(in_step, true, "Can't call custom_step() during another Tween step.");
331+
}
313332

314333
bool r = running;
315334
running = true;
@@ -341,10 +360,10 @@ bool Tween::step(double p_delta) {
341360

342361
if (!started) {
343362
if (tweeners.is_empty()) {
344-
String tween_id;
363+
String tween_id = name.length() > 0 ? vformat("Tween \"%s\"", name) : "Tween";
345364
Node *node = get_bound_node();
346365
if (node) {
347-
tween_id = vformat("Tween (bound to %s)", node->is_inside_tree() ? (String)node->get_path() : (String)node->get_name());
366+
tween_id = vformat("%s (bound to %s)", tween_id, node->is_inside_tree() ? (String)node->get_path() : (String)node->get_name());
348367
} else {
349368
tween_id = to_string();
350369
}
@@ -403,7 +422,11 @@ bool Tween::step(double p_delta) {
403422
} else {
404423
// Looped twice without using any time, this is 100% certain infinite loop.
405424
in_step = false;
406-
ERR_FAIL_V_MSG(false, "Infinite loop detected. Check set_loops() description for more info.");
425+
if (name.length() > 0) {
426+
ERR_FAIL_V_MSG(false, vformat("Infinite loop detected in Tween \"%s\". Check set_loops() description for more info.", name));
427+
} else {
428+
ERR_FAIL_V_MSG(false, "Infinite loop detected. Check set_loops() description for more info.");
429+
}
407430
}
408431
}
409432
#endif
@@ -462,12 +485,23 @@ Variant Tween::interpolate_variant(const Variant &p_initial_val, const Variant &
462485
String Tween::_to_string() {
463486
String ret = Object::_to_string();
464487
Node *node = get_bound_node();
488+
if (name.length() > 0) {
489+
ret += vformat(" \"%s\"", name);
490+
}
465491
if (node) {
466492
ret += vformat(" (bound to %s)", node->get_name());
467493
}
468494
return ret;
469495
}
470496

497+
void Tween::set_name(const StringName &p_name) {
498+
name = p_name;
499+
}
500+
501+
StringName Tween::get_name() const {
502+
return name;
503+
}
504+
471505
void Tween::_bind_methods() {
472506
ClassDB::bind_method(D_METHOD("tween_property", "object", "property", "final_val", "duration"), &Tween::tween_property);
473507
ClassDB::bind_method(D_METHOD("tween_interval", "time"), &Tween::tween_interval);
@@ -499,6 +533,9 @@ void Tween::_bind_methods() {
499533
ClassDB::bind_method(D_METHOD("parallel"), &Tween::parallel);
500534
ClassDB::bind_method(D_METHOD("chain"), &Tween::chain);
501535

536+
ClassDB::bind_method(D_METHOD("set_name", "name"), &Tween::set_name);
537+
ClassDB::bind_method(D_METHOD("get_name"), &Tween::get_name);
538+
502539
ClassDB::bind_static_method("Tween", D_METHOD("interpolate_value", "initial_value", "delta_value", "elapsed_time", "duration", "trans_type", "ease_type"), &Tween::interpolate_variant);
503540

504541
ADD_SIGNAL(MethodInfo("step_finished", PropertyInfo(Variant::INT, "idx")));
@@ -546,10 +583,19 @@ double PropertyTweener::_get_custom_interpolated_value(const Variant &p_value) {
546583
Variant result;
547584
Callable::CallError ce;
548585
custom_method.callp(&argptr, 1, result, ce);
586+
Ref<Tween> tween = _get_tween();
549587
if (ce.error != Callable::CallError::CALL_OK) {
550-
ERR_FAIL_V_MSG(false, "Error calling custom method from PropertyTweener: " + Variant::get_callable_error_text(custom_method, &argptr, 1, ce) + ".");
588+
if (tween->get_name().length() > 0) {
589+
ERR_FAIL_V_MSG(false, vformat("Error calling custom method from PropertyTweener in Tween \"%s\": %s.", tween->get_name(), Variant::get_callable_error_text(custom_method, &argptr, 1, ce)));
590+
} else {
591+
ERR_FAIL_V_MSG(false, vformat("Error calling custom method from PropertyTweener: %s.", Variant::get_callable_error_text(custom_method, &argptr, 1, ce)));
592+
}
551593
} else if (result.get_type() != Variant::FLOAT) {
552-
ERR_FAIL_V_MSG(false, vformat("Wrong return type in PropertyTweener custom method. Expected float, got %s.", Variant::get_type_name(result.get_type())));
594+
if (tween->get_name().length() > 0) {
595+
ERR_FAIL_V_MSG(false, vformat("Wrong return type in PropertyTweener custom method in Tween \"%s\". Expected float, got %s.", tween->get_name(), Variant::get_type_name(result.get_type())));
596+
} else {
597+
ERR_FAIL_V_MSG(false, vformat("Wrong return type in PropertyTweener custom method. Expected float, got %s.", Variant::get_type_name(result.get_type())));
598+
}
553599
}
554600
return result;
555601
}
@@ -752,7 +798,12 @@ bool CallbackTweener::step(double &r_delta) {
752798
Callable::CallError ce;
753799
callback.callp(nullptr, 0, result, ce);
754800
if (ce.error != Callable::CallError::CALL_OK) {
755-
ERR_FAIL_V_MSG(false, "Error calling method from CallbackTweener: " + Variant::get_callable_error_text(callback, nullptr, 0, ce) + ".");
801+
Ref<Tween> tween = _get_tween();
802+
if (tween->get_name().length() > 0) {
803+
ERR_FAIL_V_MSG(false, vformat("Error calling method from CallbackTweener in Tween \"%s\": %s.", tween->get_name(), Variant::get_callable_error_text(callback, nullptr, 0, ce)));
804+
} else {
805+
ERR_FAIL_V_MSG(false, vformat("Error calling method from CallbackTweener: %s.", Variant::get_callable_error_text(callback, nullptr, 0, ce)));
806+
}
756807
}
757808

758809
r_delta = elapsed_time - delay;
@@ -829,7 +880,11 @@ bool MethodTweener::step(double &r_delta) {
829880
Callable::CallError ce;
830881
callback.callp(argptr, 1, result, ce);
831882
if (ce.error != Callable::CallError::CALL_OK) {
832-
ERR_FAIL_V_MSG(false, "Error calling method from MethodTweener: " + Variant::get_callable_error_text(callback, argptr, 1, ce) + ".");
883+
if (tween->get_name().length() > 0) {
884+
ERR_FAIL_V_MSG(false, vformat("Error calling method from MethodTweener in Tween \"%s\": %s.", tween->get_name(), Variant::get_callable_error_text(callback, argptr, 1, ce)));
885+
} else {
886+
ERR_FAIL_V_MSG(false, vformat("Error calling method from MethodTweener: %s.", Variant::get_callable_error_text(callback, argptr, 1, ce)));
887+
}
833888
}
834889

835890
if (time < duration) {

scene/animation/tween.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ class Tween : public RefCounted {
128128
bool valid = false;
129129
bool default_parallel = false;
130130
bool parallel_enabled = false;
131+
132+
StringName name;
131133
#ifdef DEBUG_ENABLED
132134
bool is_infinite = false;
133135
#endif
@@ -188,6 +190,9 @@ class Tween : public RefCounted {
188190
Node *get_bound_node() const;
189191
double get_total_time() const;
190192

193+
void set_name(const StringName &p_name);
194+
StringName get_name() const;
195+
191196
Tween();
192197
Tween(SceneTree *p_parent_tree);
193198
};

0 commit comments

Comments
 (0)