Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a6e72a9

Browse files
committedOct 28, 2021
Add AnimationTree Advance Expressions
* Allows specifying an expression as a condition for state machine transitions. * For this to work safely (user not call queue_free or something in the expression), a const call mode was added to Object and Variant (and optionally Script). * This mode ensures only const functions can be called, making it safe to use from the editor. * Bonus: Fixed an animation import bug in Collada. This gives much greater flexibility for creating complex state machines. By directly interfacing with the script code, it is possible to create complex animation advance condition for switching between states.
1 parent d3547be commit a6e72a9

29 files changed

+297
-52
lines changed
 

‎core/core_constants.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ void register_global_constants() {
539539
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR);
540540
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE);
541541
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MULTILINE_TEXT);
542+
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXPRESSION);
542543
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT);
543544
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
544545
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY);

‎core/extension/gdnative_interface.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ typedef enum {
152152
GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */
153153
GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */
154154
GDNATIVE_CALL_ERROR_INSTANCE_IS_NULL,
155-
155+
GDNATIVE_CALL_ERROR_METHOD_NOT_CONST, /* used for const call */
156156
} GDNativeCallErrorType;
157157

158158
typedef struct {

‎core/math/expression.cpp

+21-17
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,7 @@ bool Expression::_compile_expression() {
11571157
return false;
11581158
}
11591159

1160-
bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str) {
1160+
bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, bool p_const_calls_only, String &r_error_str) {
11611161
switch (p_node->type) {
11621162
case Expression::ENode::TYPE_INPUT: {
11631163
const Expression::InputNode *in = static_cast<const Expression::InputNode *>(p_node);
@@ -1183,15 +1183,15 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
11831183
const Expression::OperatorNode *op = static_cast<const Expression::OperatorNode *>(p_node);
11841184

11851185
Variant a;
1186-
bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, r_error_str);
1186+
bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, p_const_calls_only, r_error_str);
11871187
if (ret) {
11881188
return true;
11891189
}
11901190

11911191
Variant b;
11921192

11931193
if (op->nodes[1]) {
1194-
ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str);
1194+
ret = _execute(p_inputs, p_instance, op->nodes[1], b, p_const_calls_only, r_error_str);
11951195
if (ret) {
11961196
return true;
11971197
}
@@ -1209,14 +1209,14 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
12091209
const Expression::IndexNode *index = static_cast<const Expression::IndexNode *>(p_node);
12101210

12111211
Variant base;
1212-
bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str);
1212+
bool ret = _execute(p_inputs, p_instance, index->base, base, p_const_calls_only, r_error_str);
12131213
if (ret) {
12141214
return true;
12151215
}
12161216

12171217
Variant idx;
12181218

1219-
ret = _execute(p_inputs, p_instance, index->index, idx, r_error_str);
1219+
ret = _execute(p_inputs, p_instance, index->index, idx, p_const_calls_only, r_error_str);
12201220
if (ret) {
12211221
return true;
12221222
}
@@ -1233,7 +1233,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
12331233
const Expression::NamedIndexNode *index = static_cast<const Expression::NamedIndexNode *>(p_node);
12341234

12351235
Variant base;
1236-
bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str);
1236+
bool ret = _execute(p_inputs, p_instance, index->base, base, p_const_calls_only, r_error_str);
12371237
if (ret) {
12381238
return true;
12391239
}
@@ -1253,7 +1253,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
12531253
arr.resize(array->array.size());
12541254
for (int i = 0; i < array->array.size(); i++) {
12551255
Variant value;
1256-
bool ret = _execute(p_inputs, p_instance, array->array[i], value, r_error_str);
1256+
bool ret = _execute(p_inputs, p_instance, array->array[i], value, p_const_calls_only, r_error_str);
12571257

12581258
if (ret) {
12591259
return true;
@@ -1270,14 +1270,14 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
12701270
Dictionary d;
12711271
for (int i = 0; i < dictionary->dict.size(); i += 2) {
12721272
Variant key;
1273-
bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, r_error_str);
1273+
bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, p_const_calls_only, r_error_str);
12741274

12751275
if (ret) {
12761276
return true;
12771277
}
12781278

12791279
Variant value;
1280-
ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, r_error_str);
1280+
ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, p_const_calls_only, r_error_str);
12811281
if (ret) {
12821282
return true;
12831283
}
@@ -1297,7 +1297,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
12971297

12981298
for (int i = 0; i < constructor->arguments.size(); i++) {
12991299
Variant value;
1300-
bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, r_error_str);
1300+
bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, p_const_calls_only, r_error_str);
13011301

13021302
if (ret) {
13031303
return true;
@@ -1325,7 +1325,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
13251325

13261326
for (int i = 0; i < bifunc->arguments.size(); i++) {
13271327
Variant value;
1328-
bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, r_error_str);
1328+
bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, p_const_calls_only, r_error_str);
13291329
if (ret) {
13301330
return true;
13311331
}
@@ -1346,7 +1346,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
13461346
const Expression::CallNode *call = static_cast<const Expression::CallNode *>(p_node);
13471347

13481348
Variant base;
1349-
bool ret = _execute(p_inputs, p_instance, call->base, base, r_error_str);
1349+
bool ret = _execute(p_inputs, p_instance, call->base, base, p_const_calls_only, r_error_str);
13501350

13511351
if (ret) {
13521352
return true;
@@ -1359,7 +1359,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
13591359

13601360
for (int i = 0; i < call->arguments.size(); i++) {
13611361
Variant value;
1362-
ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str);
1362+
ret = _execute(p_inputs, p_instance, call->arguments[i], value, p_const_calls_only, r_error_str);
13631363

13641364
if (ret) {
13651365
return true;
@@ -1369,7 +1369,11 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
13691369
}
13701370

13711371
Callable::CallError ce;
1372-
base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
1372+
if (p_const_calls_only) {
1373+
base.call_const(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
1374+
} else {
1375+
base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
1376+
}
13731377

13741378
if (ce.error != Callable::CallError::CALL_OK) {
13751379
r_error_str = vformat(RTR("On call to '%s':"), String(call->method));
@@ -1408,13 +1412,13 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu
14081412
return OK;
14091413
}
14101414

1411-
Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) {
1415+
Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error, bool p_const_calls_only) {
14121416
ERR_FAIL_COND_V_MSG(error_set, Variant(), "There was previously a parse error: " + error_str + ".");
14131417

14141418
execution_error = false;
14151419
Variant output;
14161420
String error_txt;
1417-
bool err = _execute(p_inputs, p_base, root, output, error_txt);
1421+
bool err = _execute(p_inputs, p_base, root, output, p_const_calls_only, error_txt);
14181422
if (err) {
14191423
execution_error = true;
14201424
error_str = error_txt;
@@ -1434,7 +1438,7 @@ String Expression::get_error_text() const {
14341438

14351439
void Expression::_bind_methods() {
14361440
ClassDB::bind_method(D_METHOD("parse", "expression", "input_names"), &Expression::parse, DEFVAL(Vector<String>()));
1437-
ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true));
1441+
ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error", "const_calls_only"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true), DEFVAL(false));
14381442
ClassDB::bind_method(D_METHOD("has_execute_failed"), &Expression::has_execute_failed);
14391443
ClassDB::bind_method(D_METHOD("get_error_text"), &Expression::get_error_text);
14401444
}

‎core/math/expression.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,14 @@ class Expression : public RefCounted {
256256
Vector<String> input_names;
257257

258258
bool execution_error = false;
259-
bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str);
259+
bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, bool p_const_calls_only, String &r_error_str);
260260

261261
protected:
262262
static void _bind_methods();
263263

264264
public:
265265
Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>());
266-
Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true);
266+
Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true, bool p_const_calls_only = false);
267267
bool has_execute_failed() const;
268268
String get_error_text() const;
269269

‎core/object/object.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a
818818
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
819819
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
820820
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
821+
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
821822
return ret;
822823
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
823824
}
@@ -837,6 +838,54 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a
837838
return ret;
838839
}
839840

841+
Variant Object::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
842+
r_error.error = Callable::CallError::CALL_OK;
843+
844+
if (p_method == CoreStringNames::get_singleton()->_free) {
845+
// Free is not const, so fail.
846+
r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
847+
return Variant();
848+
}
849+
850+
Variant ret;
851+
OBJ_DEBUG_LOCK
852+
853+
if (script_instance) {
854+
ret = script_instance->call_const(p_method, p_args, p_argcount, r_error);
855+
//force jumptable
856+
switch (r_error.error) {
857+
case Callable::CallError::CALL_OK:
858+
return ret;
859+
case Callable::CallError::CALL_ERROR_INVALID_METHOD:
860+
break;
861+
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
862+
break;
863+
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
864+
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
865+
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
866+
return ret;
867+
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
868+
}
869+
}
870+
}
871+
872+
//extension does not need this, because all methods are registered in MethodBind
873+
874+
MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
875+
876+
if (method) {
877+
if (!method->is_const()) {
878+
r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
879+
return ret;
880+
}
881+
ret = method->call(this, p_args, p_argcount, r_error);
882+
} else {
883+
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
884+
}
885+
886+
return ret;
887+
}
888+
840889
void Object::notification(int p_notification, bool p_reversed) {
841890
_notificationv(p_notification, p_reversed);
842891

‎core/object/object.h

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ enum PropertyHint {
7777
PROPERTY_HINT_GLOBAL_DIR, ///< a directory path must be passed
7878
PROPERTY_HINT_RESOURCE_TYPE, ///< a resource object type
7979
PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines
80+
PROPERTY_HINT_EXPRESSION, ///< used for string properties that can contain multiple lines
8081
PROPERTY_HINT_PLACEHOLDER_TEXT, ///< used to set a placeholder text for string properties
8182
PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
8283
PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
@@ -748,6 +749,7 @@ class Object {
748749
Variant callv(const StringName &p_method, const Array &p_args);
749750
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
750751
Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper
752+
virtual Variant call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
751753

752754
void notification(int p_notification, bool p_reversed = false);
753755
virtual String to_string();

‎core/object/script_language.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@ void ScriptServer::save_global_classes() {
294294
}
295295

296296
////////////////////
297+
298+
Variant ScriptInstance::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
299+
return call(p_method, p_args, p_argcount, r_error);
300+
}
301+
297302
void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state) {
298303
List<PropertyInfo> pinfo;
299304
get_property_list(&pinfo);

‎core/object/script_language.h

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ class ScriptInstance {
178178
virtual bool has_method(const StringName &p_method) const = 0;
179179
virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST);
180180
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0;
181+
virtual Variant call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); // implement if language supports const functions
181182
virtual void notification(int p_notification) = 0;
182183
virtual String to_string(bool *r_valid) {
183184
if (r_valid) {

‎core/variant/callable.h

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class Callable {
6161
CALL_ERROR_TOO_MANY_ARGUMENTS, // expected is number of arguments
6262
CALL_ERROR_TOO_FEW_ARGUMENTS, // expected is number of arguments
6363
CALL_ERROR_INSTANCE_IS_NULL,
64+
CALL_ERROR_METHOD_NOT_CONST,
6465
};
6566
Error error = Error::CALL_OK;
6667
int argument = 0;

‎core/variant/variant.cpp

+46
Original file line numberDiff line numberDiff line change
@@ -3360,6 +3360,46 @@ Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
33603360
return ret;
33613361
}
33623362

3363+
Variant Variant::call_const(const StringName &p_method, VARIANT_ARG_DECLARE) {
3364+
VARIANT_ARGPTRS;
3365+
int argc = 0;
3366+
for (int i = 0; i < VARIANT_ARG_MAX; i++) {
3367+
if (argptr[i]->get_type() == Variant::NIL) {
3368+
break;
3369+
}
3370+
argc++;
3371+
}
3372+
3373+
Callable::CallError error;
3374+
3375+
Variant ret;
3376+
call_const(p_method, argptr, argc, ret, error);
3377+
3378+
switch (error.error) {
3379+
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
3380+
String err = "Invalid type for argument #" + itos(error.argument) + ", expected '" + Variant::get_type_name(Variant::Type(error.expected)) + "'.";
3381+
ERR_PRINT(err.utf8().get_data());
3382+
3383+
} break;
3384+
case Callable::CallError::CALL_ERROR_INVALID_METHOD: {
3385+
String err = "Invalid method '" + p_method + "' for type '" + Variant::get_type_name(type) + "'.";
3386+
ERR_PRINT(err.utf8().get_data());
3387+
} break;
3388+
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: {
3389+
String err = "Too many arguments for method '" + p_method + "'";
3390+
ERR_PRINT(err.utf8().get_data());
3391+
} break;
3392+
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST: {
3393+
String err = "Method is not const '" + p_method + "' and call_const used";
3394+
ERR_PRINT(err.utf8().get_data());
3395+
} break;
3396+
default: {
3397+
}
3398+
}
3399+
3400+
return ret;
3401+
}
3402+
33633403
void Variant::construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct, void *p_construct_ud) {
33643404
r_value = Variant();
33653405
}
@@ -3389,6 +3429,8 @@ String Variant::get_call_error_text(const StringName &p_method, const Variant **
33893429
err_text = "Method not found.";
33903430
} else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
33913431
err_text = "Instance is null";
3432+
} else if (ce.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) {
3433+
err_text = "Method not const in const instance";
33923434
} else if (ce.error == Callable::CallError::CALL_OK) {
33933435
return "Call OK";
33943436
}
@@ -3413,6 +3455,8 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
34133455
err_text = "Method not found.";
34143456
} else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
34153457
err_text = "Instance is null";
3458+
} else if (ce.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) {
3459+
err_text = "Method not const in const instance";
34163460
} else if (ce.error == Callable::CallError::CALL_OK) {
34173461
return "Call OK";
34183462
}
@@ -3443,6 +3487,8 @@ String Variant::get_callable_error_text(const Callable &p_callable, const Varian
34433487
err_text = "Method not found.";
34443488
} else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
34453489
err_text = "Instance is null";
3490+
} else if (ce.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) {
3491+
err_text = "Method not const in const instance";
34463492
} else if (ce.error == Callable::CallError::CALL_OK) {
34473493
return "Call OK";
34483494
}

‎core/variant/variant.h

+3
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,9 @@ class Variant {
511511
void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
512512
Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant());
513513

514+
void call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
515+
Variant call_const(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant());
516+
514517
static void call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
515518

516519
static String get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);

0 commit comments

Comments
 (0)
Please sign in to comment.