diff options
| -rw-r--r-- | core/io/marshalls.cpp | 20 | ||||
| -rw-r--r-- | core/io/resource_format_binary.cpp | 6 | ||||
| -rw-r--r-- | core/node_path.cpp | 76 | ||||
| -rw-r--r-- | core/node_path.h | 13 | ||||
| -rw-r--r-- | core/object.cpp | 123 | ||||
| -rw-r--r-- | core/object.h | 5 | ||||
| -rw-r--r-- | core/variant_call.cpp | 4 | ||||
| -rw-r--r-- | editor/animation_editor.cpp | 40 | ||||
| -rw-r--r-- | editor/plugins/animation_tree_editor_plugin.cpp | 6 | ||||
| -rw-r--r-- | editor/scene_tree_dock.cpp | 2 | ||||
| -rw-r--r-- | modules/gdnative/gdnative/node_path.cpp | 4 | ||||
| -rw-r--r-- | modules/gdnative/gdnative_api.json | 2 | ||||
| -rw-r--r-- | modules/gdnative/include/gdnative/node_path.h | 2 | ||||
| -rw-r--r-- | scene/animation/animation_cache.cpp | 95 | ||||
| -rw-r--r-- | scene/animation/animation_cache.h | 2 | ||||
| -rw-r--r-- | scene/animation/animation_player.cpp | 30 | ||||
| -rw-r--r-- | scene/animation/animation_player.h | 2 | ||||
| -rw-r--r-- | scene/animation/animation_tree_player.cpp | 20 | ||||
| -rw-r--r-- | scene/animation/animation_tree_player.h | 6 | ||||
| -rw-r--r-- | scene/animation/tween.cpp | 128 | ||||
| -rw-r--r-- | scene/animation/tween.h | 27 | ||||
| -rwxr-xr-x | scene/main/node.cpp | 37 | ||||
| -rw-r--r-- | scene/main/node.h | 2 | 
23 files changed, 411 insertions, 241 deletions
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index d388a622de..69ae9311fb 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -324,7 +324,6 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int  				ERR_FAIL_COND_V(len < 12, ERR_INVALID_DATA);  				Vector<StringName> names;  				Vector<StringName> subnames; -				StringName prop;  				uint32_t namecount = strlen &= 0x7FFFFFFF;  				uint32_t subnamecount = decode_uint32(buf + 4); @@ -333,9 +332,10 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int  				len -= 12;  				buf += 12; +				if (flags & 2) // Obsolete format with property seperate from subpath +					subnamecount++; +  				uint32_t total = namecount + subnamecount; -				if (flags & 2) -					total++;  				if (r_len)  					(*r_len) += 12; @@ -359,10 +359,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int  					if (i < namecount)  						names.push_back(str); -					else if (i < namecount + subnamecount) -						subnames.push_back(str);  					else -						prop = str; +						subnames.push_back(str);  					buf += strlen + pad;  					len -= strlen + pad; @@ -371,7 +369,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int  						(*r_len) += 4 + strlen + pad;  				} -				r_variant = NodePath(names, subnames, flags & 1, prop); +				r_variant = NodePath(names, subnames, flags & 1);  			} else {  				//old format, just a string @@ -919,8 +917,6 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo  				uint32_t flags = 0;  				if (np.is_absolute())  					flags |= 1; -				if (np.get_property() != StringName()) -					flags |= 2;  				encode_uint32(flags, buf + 8); @@ -930,8 +926,6 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo  			r_len += 12;  			int total = np.get_name_count() + np.get_subname_count(); -			if (np.get_property() != StringName()) -				total++;  			for (int i = 0; i < total; i++) { @@ -939,10 +933,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo  				if (i < np.get_name_count())  					str = np.get_name(i); -				else if (i < np.get_name_count() + np.get_subname_count()) -					str = np.get_subname(i - np.get_subname_count());  				else -					str = np.get_property(); +					str = np.get_subname(i - np.get_name_count());  				CharString utf8 = str.utf8(); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 03c3c5f615..ad6ac568ff 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -267,7 +267,6 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) {  			Vector<StringName> names;  			Vector<StringName> subnames; -			StringName property;  			bool absolute;  			int name_count = f->get_16(); @@ -279,9 +278,8 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) {  				names.push_back(_get_string());  			for (uint32_t i = 0; i < subname_count; i++)  				subnames.push_back(_get_string()); -			property = _get_string(); -			NodePath np = NodePath(names, subnames, absolute, property); +			NodePath np = NodePath(names, subnames, absolute);  			r_v = np; @@ -1454,7 +1452,6 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property,  				f->store_32(get_string_index(np.get_name(i)));  			for (int i = 0; i < np.get_subname_count(); i++)  				f->store_32(get_string_index(np.get_subname(i))); -			f->store_32(get_string_index(np.get_property()));  		} break;  		case Variant::_RID: { @@ -1685,7 +1682,6 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant  				get_string_index(np.get_name(i));  			for (int i = 0; i < np.get_subname_count(); i++)  				get_string_index(np.get_subname(i)); -			get_string_index(np.get_property());  		} break;  		default: {} diff --git a/core/node_path.cpp b/core/node_path.cpp index 15f950f605..a01bb420a5 100644 --- a/core/node_path.cpp +++ b/core/node_path.cpp @@ -48,8 +48,6 @@ uint32_t NodePath::hash() const {  		h = h ^ ssn[i].hash();  	} -	h = h ^ data->property.hash(); -  	return h;  } @@ -81,13 +79,6 @@ StringName NodePath::get_name(int p_idx) const {  	return data->path[p_idx];  } -StringName NodePath::get_property() const { - -	if (!data) -		return StringName(); -	return data->property; -} -  int NodePath::get_subname_count() const {  	if (!data) @@ -128,9 +119,6 @@ bool NodePath::operator==(const NodePath &p_path) const {  	if (data->subpath.size() != p_path.data->subpath.size())  		return false; -	if (data->property != p_path.data->property) -		return false; -  	for (int i = 0; i < data->path.size(); i++) {  		if (data->path[i] != p_path.data->path[i]) @@ -184,8 +172,6 @@ NodePath::operator String() const {  		ret += ":" + data->subpath[i].operator String();  	} -	if (data->property.operator String() != "") -		ret += ":" + String(data->property);  	return ret;  } @@ -205,6 +191,7 @@ Vector<StringName> NodePath::get_names() const {  		return data->path;  	return Vector<StringName>();  } +  Vector<StringName> NodePath::get_subnames() const {  	if (data) @@ -212,6 +199,21 @@ Vector<StringName> NodePath::get_subnames() const {  	return Vector<StringName>();  } +StringName NodePath::get_concatenated_subnames() const { +	ERR_FAIL_COND_V(!data, StringName()); + +	if (!data->concatenated_subpath) { +		int spc = data->subpath.size(); +		String concatenated; +		const StringName *ssn = data->subpath.ptr(); +		for (int i = 0; i < spc; i++) { +			concatenated += i == 0 ? ssn[i].operator String() : "." + ssn[i]; +		} +		data->concatenated_subpath = concatenated; +	} +	return data->concatenated_subpath; +} +  NodePath NodePath::rel_path_to(const NodePath &p_np) const {  	ERR_FAIL_COND_V(!is_absolute(), NodePath()); @@ -250,10 +252,23 @@ NodePath NodePath::rel_path_to(const NodePath &p_np) const {  	if (relpath.size() == 0)  		relpath.push_back("."); -	return NodePath(relpath, p_np.get_subnames(), false, p_np.get_property()); +	return NodePath(relpath, p_np.get_subnames(), false); +} + +NodePath NodePath::get_as_property_path() const { + +	if (data->has_slashes || !data->path.size()) { +		return NodePath(Vector<StringName>(), data->subpath, false); +	} else { +		ERR_FAIL_COND_V(data->path.size() != 1, NodePath()); + +		Vector<StringName> new_path = data->subpath; +		new_path.insert(0, data->path[0]); +		return NodePath(Vector<StringName>(), new_path, false); +	}  } -NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute, const String &p_property) { +NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) {  	data = NULL; @@ -264,14 +279,14 @@ NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute, const Stri  	data->refcount.init();  	data->absolute = p_absolute;  	data->path = p_path; -	data->property = p_property; +	data->has_slashes = true;  } -NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute, const String &p_property) { +NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute) {  	data = NULL; -	if (p_path.size() == 0) +	if (p_path.size() == 0 && p_subpath.size() == 0)  		return;  	data = memnew(Data); @@ -279,7 +294,7 @@ NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p  	data->absolute = p_absolute;  	data->path = p_path;  	data->subpath = p_subpath; -	data->property = p_property; +	data->has_slashes = true;  }  void NodePath::simplify() { @@ -325,6 +340,7 @@ NodePath::NodePath(const String &p_path) {  	int absolute = (path[0] == '/') ? 1 : 0;  	bool last_is_slash = true; +	bool has_slashes = false;  	int slices = 0;  	int subpath_pos = path.find(":"); @@ -337,16 +353,13 @@ NodePath::NodePath(const String &p_path) {  			if (path[i] == ':' || path[i] == 0) {  				String str = path.substr(from, i - from); -				if (path[i] == ':') { -					if (str == "") { -						ERR_EXPLAIN("Invalid NodePath: " + p_path); -						ERR_FAIL(); -					} -					subpath.push_back(str); -				} else { -					//property can be empty -					property = str; +				if (str == "") { +					if (path[i] == 0) continue; // Allow end-of-path : + +					ERR_EXPLAIN("Invalid NodePath: " + p_path); +					ERR_FAIL();  				} +				subpath.push_back(str);  				from = i + 1;  			} @@ -360,6 +373,7 @@ NodePath::NodePath(const String &p_path) {  		if (path[i] == '/') {  			last_is_slash = true; +			has_slashes = true;  		} else {  			if (last_is_slash) @@ -369,13 +383,13 @@ NodePath::NodePath(const String &p_path) {  		}  	} -	if (slices == 0 && !absolute && !property) +	if (slices == 0 && !absolute && !subpath.size())  		return;  	data = memnew(Data);  	data->refcount.init();  	data->absolute = absolute ? true : false; -	data->property = property; +	data->has_slashes = has_slashes;  	data->subpath = subpath;  	if (slices == 0) diff --git a/core/node_path.h b/core/node_path.h index eb5b9eb6cf..063c4f62db 100644 --- a/core/node_path.h +++ b/core/node_path.h @@ -41,10 +41,11 @@ class NodePath {  	struct Data {  		SafeRefCount refcount; -		StringName property;  		Vector<StringName> path;  		Vector<StringName> subpath; +		StringName concatenated_subpath;  		bool absolute; +		bool has_slashes;  	};  	Data *data; @@ -53,7 +54,7 @@ class NodePath {  public:  	_FORCE_INLINE_ StringName get_sname() const { -		if (data && data->path.size() == 1 && data->subpath.empty() && !data->property) { +		if (data && data->path.size() == 1 && data->subpath.empty()) {  			return data->path[0];  		} else {  			return operator String(); @@ -67,13 +68,13 @@ public:  	StringName get_subname(int p_idx) const;  	Vector<StringName> get_names() const;  	Vector<StringName> get_subnames() const; +	StringName get_concatenated_subnames() const;  	NodePath rel_path_to(const NodePath &p_np) const; +	NodePath get_as_property_path() const;  	void prepend_period(); -	StringName get_property() const; -  	NodePath get_parent() const;  	uint32_t hash() const; @@ -88,8 +89,8 @@ public:  	void simplify();  	NodePath simplified() const; -	NodePath(const Vector<StringName> &p_path, bool p_absolute, const String &p_property = ""); -	NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute, const String &p_property = ""); +	NodePath(const Vector<StringName> &p_path, bool p_absolute); +	NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute);  	NodePath(const NodePath &p_path);  	NodePath(const String &p_path);  	NodePath(); diff --git a/core/object.cpp b/core/object.cpp index 823cbe14d4..631676d827 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -517,6 +517,80 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {  	}  } +void Object::set_indexed(const Vector<StringName> &p_names, const Variant &p_value, bool *r_valid) { +	if (p_names.empty()) { +		if (r_valid) +			*r_valid = false; +		return; +	} +	if (p_names.size() == 1) { +		set(p_names[0], p_value, r_valid); +		return; +	} + +	bool valid = false; +	if (!r_valid) r_valid = &valid; + +	List<Variant> value_stack; + +	value_stack.push_back(get(p_names[0], r_valid)); + +	if (!*r_valid) { +		value_stack.clear(); +		return; +	} + +	for (int i = 1; i < p_names.size() - 1; i++) { +		value_stack.push_back(value_stack.back()->get().get_named(p_names[i], r_valid)); + +		if (!*r_valid) { +			value_stack.clear(); +			return; +		} +	} + +	value_stack.push_back(p_value); // p_names[p_names.size() - 1] + +	for (int i = p_names.size() - 1; i > 0; i--) { + +		value_stack.back()->prev()->get().set_named(p_names[i], value_stack.back()->get(), r_valid); +		value_stack.pop_back(); + +		if (!*r_valid) { +			value_stack.clear(); +			return; +		} +	} + +	set(p_names[0], value_stack.back()->get(), r_valid); +	value_stack.pop_back(); + +	ERR_FAIL_COND(!value_stack.empty()); +} + +Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) const { +	if (p_names.empty()) { +		if (r_valid) +			*r_valid = false; +		return Variant(); +	} +	bool valid = false; + +	Variant current_value = get(p_names[0]); +	for (int i = 1; i < p_names.size(); i++) { +		current_value = current_value.get_named(p_names[i], &valid); + +		if (!valid) { +			if (r_valid) +				*r_valid = false; +			return Variant(); +		} +	} +	if (r_valid) +		*r_valid = true; +	return current_value; +} +  void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) const {  	if (script_instance && p_reversed) { @@ -1416,6 +1490,16 @@ Variant Object::_get_bind(const String &p_name) const {  	return get(p_name);  } +void Object::_set_indexed_bind(const NodePath &p_name, const Variant &p_value) { + +	set_indexed(p_name.get_as_property_path().get_subnames(), p_value); +} + +Variant Object::_get_indexed_bind(const NodePath &p_name) const { + +	return get_indexed(p_name.get_as_property_path().get_subnames()); +} +  void Object::initialize_class() {  	static bool initialized = false; @@ -1513,6 +1597,8 @@ void Object::_bind_methods() {  	ClassDB::bind_method(D_METHOD("is_class", "type"), &Object::is_class);  	ClassDB::bind_method(D_METHOD("set", "property", "value"), &Object::_set_bind);  	ClassDB::bind_method(D_METHOD("get", "property"), &Object::_get_bind); +	ClassDB::bind_method(D_METHOD("set_indexed", "property", "value"), &Object::_set_indexed_bind); +	ClassDB::bind_method(D_METHOD("get_indexed", "property"), &Object::_get_indexed_bind);  	ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);  	ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);  	ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false)); @@ -1661,6 +1747,43 @@ Variant::Type Object::get_static_property_type(const StringName &p_property, boo  	return Variant::NIL;  } +Variant::Type Object::get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid) const { + +	bool valid = false; +	Variant::Type t = get_static_property_type(p_path[0], &valid); +	if (!valid) { +		if (r_valid) +			*r_valid = false; + +		return Variant::NIL; +	} + +	Variant::CallError ce; +	Variant check = Variant::construct(t, NULL, 0, ce); + +	for (int i = 1; i < p_path.size(); i++) { +		if (check.get_type() == Variant::OBJECT || check.get_type() == Variant::DICTIONARY || check.get_type() == Variant::ARRAY) { +			// We cannot be sure about the type of properties this types can have +			if (r_valid) +				*r_valid = false; +			return Variant::NIL; +		} + +		check = check.get_named(p_path[i], &valid); + +		if (!valid) { +			if (r_valid) +				*r_valid = false; +			return Variant::NIL; +		} +	} + +	if (r_valid) +		*r_valid = true; + +	return check.get_type(); +} +  bool Object::is_queued_for_deletion() const {  	return _is_queued_for_deletion;  } diff --git a/core/object.h b/core/object.h index 7af2c78fc3..3ac699f978 100644 --- a/core/object.h +++ b/core/object.h @@ -477,6 +477,8 @@ private:  	Array _get_incoming_connections() const;  	void _set_bind(const String &p_set, const Variant &p_value);  	Variant _get_bind(const String &p_name) const; +	void _set_indexed_bind(const NodePath &p_name, const Variant &p_value); +	Variant _get_indexed_bind(const NodePath &p_name) const;  	void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; @@ -627,6 +629,8 @@ public:  	void set(const StringName &p_name, const Variant &p_value, bool *r_valid = NULL);  	Variant get(const StringName &p_name, bool *r_valid = NULL) const; +	void set_indexed(const Vector<StringName> &p_names, const Variant &p_value, bool *r_valid = NULL); +	Variant get_indexed(const Vector<StringName> &p_names, bool *r_valid = NULL) const;  	void get_property_list(List<PropertyInfo> *p_list, bool p_reversed = false) const; @@ -687,6 +691,7 @@ public:  	bool is_blocking_signals() const;  	Variant::Type get_static_property_type(const StringName &p_property, bool *r_valid = NULL) const; +	Variant::Type get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid = NULL) const;  	virtual void get_translatable_strings(List<String> *p_strings) const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 05f0478003..83c92500d0 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -446,7 +446,7 @@ struct _VariantCall {  	VCALL_LOCALMEM1R(NodePath, get_name);  	VCALL_LOCALMEM0R(NodePath, get_subname_count);  	VCALL_LOCALMEM1R(NodePath, get_subname); -	VCALL_LOCALMEM0R(NodePath, get_property); +	VCALL_LOCALMEM0R(NodePath, get_concatenated_subnames);  	VCALL_LOCALMEM0R(NodePath, is_empty);  	VCALL_LOCALMEM0R(Dictionary, size); @@ -1590,7 +1590,7 @@ void register_variant_methods() {  	ADDFUNC1R(NODE_PATH, STRING, NodePath, get_name, INT, "idx", varray());  	ADDFUNC0R(NODE_PATH, INT, NodePath, get_subname_count, varray());  	ADDFUNC1R(NODE_PATH, STRING, NodePath, get_subname, INT, "idx", varray()); -	ADDFUNC0R(NODE_PATH, STRING, NodePath, get_property, varray()); +	ADDFUNC0R(NODE_PATH, STRING, NodePath, get_concatenated_subnames, varray());  	ADDFUNC0R(NODE_PATH, BOOL, NodePath, is_empty, varray());  	ADDFUNC0R(DICTIONARY, INT, Dictionary, size, varray()); diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp index 54eb695178..e6dcd651b3 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -966,7 +966,9 @@ void AnimationKeyEditor::_cleanup_animation(Ref<Animation> p_animation) {  		Object *obj = NULL;  		RES res; -		Node *node = root->get_node_and_resource(p_animation->track_get_path(i), res); +		Vector<StringName> leftover_path; + +		Node *node = root->get_node_and_resource(p_animation->track_get_path(i), res, leftover_path);  		if (res.is_valid()) {  			obj = res.ptr(); @@ -975,7 +977,7 @@ void AnimationKeyEditor::_cleanup_animation(Ref<Animation> p_animation) {  		}  		if (obj && p_animation->track_get_type(i) == Animation::TYPE_VALUE) { -			valid_type = obj->get_static_property_type(p_animation->track_get_path(i).get_property(), &prop_exists); +			valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists);  		}  		if (!obj && cleanup_tracks->is_pressed()) { @@ -1315,7 +1317,9 @@ void AnimationKeyEditor::_track_editor_draw() {  		Object *obj = NULL;  		RES res; -		Node *node = root ? root->get_node_and_resource(animation->track_get_path(idx), res) : (Node *)NULL; +		Vector<StringName> leftover_path; + +		Node *node = root ? root->get_node_and_resource(animation->track_get_path(idx), res, leftover_path) : (Node *)NULL;  		if (res.is_valid()) {  			obj = res.ptr(); @@ -1324,7 +1328,8 @@ void AnimationKeyEditor::_track_editor_draw() {  		}  		if (obj && animation->track_get_type(idx) == Animation::TYPE_VALUE) { -			valid_type = obj->get_static_property_type(animation->track_get_path(idx).get_property(), &prop_exists); +			// While leftover_path might be still empty, we wouldn't be able to get here anyway +			valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists);  		}  		if (/*mouse_over.over!=MouseOver::OVER_NONE &&*/ idx == mouse_over.track) { @@ -1649,26 +1654,34 @@ PropertyInfo AnimationKeyEditor::_find_hint_for_track(int p_idx, NodePath &r_bas  		return PropertyInfo();  	RES res; -	Node *node = root->get_node_and_resource(path, res); +	Vector<StringName> leftover_path; +	Node *node = root->get_node_and_resource(path, res, leftover_path, true);  	if (node) {  		r_base_path = node->get_path();  	} -	String property = path.get_property(); -	if (property == "") +	if (leftover_path.empty())  		return PropertyInfo(); -	List<PropertyInfo> pinfo; +	Variant property_info_base;  	if (res.is_valid()) -		res->get_property_list(&pinfo); +		property_info_base = res;  	else if (node) -		node->get_property_list(&pinfo); +		property_info_base = node; + +	for (int i = 0; i < leftover_path.size() - 1; i++) { +		property_info_base = property_info_base.get_named(leftover_path[i]); +	} + +	List<PropertyInfo> pinfo; +	property_info_base.get_property_list(&pinfo);  	for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { -		if (E->get().name == property) +		if (E->get().name == leftover_path[leftover_path.size() - 1]) {  			return E->get(); +		}  	}  	return PropertyInfo(); @@ -2780,7 +2793,8 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input)  							Object *obj = NULL;  							RES res; -							Node *node = root->get_node_and_resource(animation->track_get_path(idx), res); +							Vector<StringName> leftover_path; +							Node *node = root->get_node_and_resource(animation->track_get_path(idx), res, leftover_path);  							if (res.is_valid()) {  								obj = res.ptr(); @@ -2789,7 +2803,7 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input)  							}  							if (obj) { -								valid_type = obj->get_static_property_type(animation->track_get_path(idx).get_property(), &prop_exists); +								valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists);  							}  							text += "type: " + Variant::get_type_name(v.get_type()) + "\n"; diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 22d23e1c72..8fe6538653 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -1196,14 +1196,14 @@ void AnimationTreeEditor::_edit_filters() {  		if (base) {  			NodePath np = E->get(); -			if (np.get_property() != StringName()) { +			if (np.get_subname_count() == 1) {  				Node *n = base->get_node(np);  				Skeleton *s = Object::cast_to<Skeleton>(n);  				if (s) {  					String skelbase = E->get().substr(0, E->get().find(":")); -					int bidx = s->find_bone(np.get_property()); +					int bidx = s->find_bone(np.get_subname(0));  					if (bidx != -1) {  						int bparent = s->get_bone_parent(bidx); @@ -1213,7 +1213,7 @@ void AnimationTreeEditor::_edit_filters() {  							String bpn = skelbase + ":" + s->get_bone_name(bparent);  							if (pm.has(bpn)) {  								parent = pm[bpn]; -								descr = np.get_property(); +								descr = np.get_subname(0);  							}  						} else { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 6b008838e5..172f1891f1 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1050,7 +1050,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP  									//will be renamed  									NodePath rel_path = new_root_path.rel_path_to(E->get().second); -									NodePath new_path = NodePath(rel_path.get_names(), track_np.get_subnames(), false, track_np.get_property()); +									NodePath new_path = NodePath(rel_path.get_names(), track_np.get_subnames(), false);  									if (new_path == track_np)  										continue; //bleh  									editor_data->get_undo_redo().add_do_method(anim.ptr(), "track_set_path", i, new_path); diff --git a/modules/gdnative/gdnative/node_path.cpp b/modules/gdnative/gdnative/node_path.cpp index 50fade5b94..0124efe4ba 100644 --- a/modules/gdnative/gdnative/node_path.cpp +++ b/modules/gdnative/gdnative/node_path.cpp @@ -93,10 +93,10 @@ godot_string GDAPI godot_node_path_get_subname(const godot_node_path *p_self, co  	return dest;  } -godot_string GDAPI godot_node_path_get_property(const godot_node_path *p_self) { +godot_string GDAPI godot_node_path_get_concatenated_subnames(const godot_node_path *p_self) {  	godot_string dest;  	const NodePath *self = (const NodePath *)p_self; -	memnew_placement(&dest, String(self->get_property())); +	memnew_placement(&dest, String(self->get_concatenated_subnames()));  	return dest;  } diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 770fb429c7..6555bc83b7 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -2898,7 +2898,7 @@          ]        },        { -        "name": "godot_node_path_get_property", +        "name": "godot_node_path_get_concatenated_subnames",          "return_type": "godot_string",          "arguments": [            ["const godot_node_path *", "p_self"] diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h index 42446175d8..b5a59fd325 100644 --- a/modules/gdnative/include/gdnative/node_path.h +++ b/modules/gdnative/include/gdnative/node_path.h @@ -73,7 +73,7 @@ godot_int GDAPI godot_node_path_get_subname_count(const godot_node_path *p_self)  godot_string GDAPI godot_node_path_get_subname(const godot_node_path *p_self, const godot_int p_idx); -godot_string GDAPI godot_node_path_get_property(const godot_node_path *p_self); +godot_string GDAPI godot_node_path_get_concatenated_subnames(const godot_node_path *p_self);  godot_bool GDAPI godot_node_path_is_empty(const godot_node_path *p_self); diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp index b35b2568d1..fbe2593362 100644 --- a/scene/animation/animation_cache.cpp +++ b/scene/animation/animation_cache.cpp @@ -87,95 +87,90 @@ void AnimationCache::_update_cache() {  		Ref<Resource> res; -		if (np.get_subname_count()) { - -			if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM) { +		if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM) { +			if (np.get_subname_count() > 1) {  				path_cache.push_back(Path());  				ERR_EXPLAIN("Transform tracks can't have a subpath: " + np);  				ERR_CONTINUE(animation->track_get_type(i) == Animation::TYPE_TRANSFORM);  			} -			RES res; - -			for (int j = 0; j < np.get_subname_count(); j++) { -				res = j == 0 ? node->get(np.get_subname(j)) : res->get(np.get_subname(j)); -				if (res.is_null()) -					break; -			} +			Spatial *sp = Object::cast_to<Spatial>(node); -			if (res.is_null()) { +			if (!sp) {  				path_cache.push_back(Path()); -				ERR_EXPLAIN("Invalid Track SubPath in Animation: " + np); -				ERR_CONTINUE(res.is_null()); +				ERR_EXPLAIN("Transform track not of type Spatial: " + np); +				ERR_CONTINUE(!sp);  			} -			path.resource = res; -			path.object = res.ptr(); - -		} else { - -			if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM) { -				StringName property = np.get_property(); +			if (np.get_subname_count() == 1) { +				StringName property = np.get_subname(0);  				String ps = property; -				Spatial *sp = Object::cast_to<Spatial>(node); +				Skeleton *sk = Object::cast_to<Skeleton>(node); +				if (!sk) { -				if (!sp) { +					path_cache.push_back(Path()); +					ERR_EXPLAIN("Property defined in Transform track, but not a Skeleton!: " + np); +					ERR_CONTINUE(!sk); +				} +				int idx = sk->find_bone(ps); +				if (idx == -1) {  					path_cache.push_back(Path()); -					ERR_EXPLAIN("Transform track not of type Spatial: " + np); -					ERR_CONTINUE(!sp); +					ERR_EXPLAIN("Property defined in Transform track, but not a Skeleton Bone!: " + np); +					ERR_CONTINUE(idx == -1);  				} -				if (ps != "") { +				path.bone_idx = idx; +				path.skeleton = sk; +			} -					Skeleton *sk = Object::cast_to<Skeleton>(node); -					if (!sk) { +			path.spatial = sp; -						path_cache.push_back(Path()); -						ERR_EXPLAIN("Property defined in Transform track, but not a Skeleton!: " + np); -						ERR_CONTINUE(!sk); -					} +		} else { +			if (np.get_subname_count() > 0) { -					int idx = sk->find_bone(ps); -					if (idx == -1) { +				RES res; +				Vector<StringName> leftover_subpath; -						path_cache.push_back(Path()); -						ERR_EXPLAIN("Property defined in Transform track, but not a Skeleton Bone!: " + np); -						ERR_CONTINUE(idx == -1); -					} +				// We don't want to cache the last resource unless it is a method call +				bool is_method = animation->track_get_type(i) == Animation::TYPE_METHOD; +				root->get_node_and_resource(np, res, leftover_subpath, is_method); -					path.bone_idx = idx; -					path.skeleton = sk; +				if (res.is_valid()) { +					path.resource = res; +				} else { +					path.node = node;  				} +				path.object = res.is_valid() ? res.ptr() : (Object *)node; +				path.subpath = leftover_subpath; -				path.spatial = sp; -			} +			} else { -			path.node = node; -			path.object = node; +				path.node = node; +				path.object = node; +				path.subpath = np.get_subnames(); +			}  		}  		if (animation->track_get_type(i) == Animation::TYPE_VALUE) { -			if (np.get_property().operator String() == "") { +			if (np.get_subname_count() == 0) {  				path_cache.push_back(Path());  				ERR_EXPLAIN("Value Track lacks property: " + np); -				ERR_CONTINUE(np.get_property().operator String() == ""); +				ERR_CONTINUE(np.get_subname_count() == 0);  			} -			path.property = np.get_property(); -  		} else if (animation->track_get_type(i) == Animation::TYPE_METHOD) { -			if (np.get_property().operator String() != "") { +			if (path.subpath.size() != 0) { // Trying to call a method of a non-resource  				path_cache.push_back(Path());  				ERR_EXPLAIN("Method Track has property: " + np); -				ERR_CONTINUE(np.get_property().operator String() != ""); +				ERR_CONTINUE(path.subpath.size() != 0);  			}  		} @@ -226,7 +221,7 @@ void AnimationCache::set_track_value(int p_idx, const Variant &p_value) {  		return;  	ERR_FAIL_COND(!p.object); -	p.object->set(p.property, p_value); +	p.object->set_indexed(p.subpath, p_value);  }  void AnimationCache::call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h index e593668df6..481de59730 100644 --- a/scene/animation/animation_cache.h +++ b/scene/animation/animation_cache.h @@ -46,7 +46,7 @@ class AnimationCache : public Object {  		Spatial *spatial;  		int bone_idx; -		StringName property; +		Vector<StringName> subpath;  		bool valid;  		Path() {  			object = NULL; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 80b7748078..a0a554b3aa 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -242,7 +242,8 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {  		p_anim->node_cache[i] = NULL;  		RES resource; -		Node *child = parent->get_node_and_resource(a->track_get_path(i), resource); +		Vector<StringName> leftover_path; +		Node *child = parent->get_node_and_resource(a->track_get_path(i), resource, leftover_path);  		if (!child) {  			ERR_EXPLAIN("On Animation: '" + p_anim->name + "', couldn't resolve track:  '" + String(a->track_get_path(i)) + "'");  		} @@ -250,9 +251,9 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {  		uint32_t id = resource.is_valid() ? resource->get_instance_id() : child->get_instance_id();  		int bone_idx = -1; -		if (a->track_get_path(i).get_property() && Object::cast_to<Skeleton>(child)) { +		if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton>(child)) { -			bone_idx = Object::cast_to<Skeleton>(child)->find_bone(a->track_get_path(i).get_property()); +			bone_idx = Object::cast_to<Skeleton>(child)->find_bone(a->track_get_path(i).get_subname(0));  			if (bone_idx == -1) {  				continue; @@ -289,8 +290,8 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {  				p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton>(child);  				if (p_anim->node_cache[i]->skeleton) { -					StringName bone_name = a->track_get_path(i).get_property(); -					if (bone_name.operator String() != "") { +					if (a->track_get_path(i).get_subname_count() == 1) { +						StringName bone_name = a->track_get_path(i).get_subname(0);  						p_anim->node_cache[i]->bone_idx = p_anim->node_cache[i]->skeleton->find_bone(bone_name);  						if (p_anim->node_cache[i]->bone_idx < 0) { @@ -311,24 +312,23 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {  		if (a->track_get_type(i) == Animation::TYPE_VALUE) { -			StringName property = a->track_get_path(i).get_property(); -			if (!p_anim->node_cache[i]->property_anim.has(property)) { +			if (!p_anim->node_cache[i]->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) {  				TrackNodeCache::PropertyAnim pa; -				pa.prop = property; +				pa.subpath = leftover_path;  				pa.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;  				pa.special = SP_NONE;  				pa.owner = p_anim->node_cache[i];  				if (false && p_anim->node_cache[i]->node_2d) { -					if (pa.prop == SceneStringNames::get_singleton()->transform_pos) +					if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_pos)  						pa.special = SP_NODE2D_POS; -					else if (pa.prop == SceneStringNames::get_singleton()->transform_rot) +					else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_rot)  						pa.special = SP_NODE2D_ROT; -					else if (pa.prop == SceneStringNames::get_singleton()->transform_scale) +					else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_scale)  						pa.special = SP_NODE2D_SCALE;  				} -				p_anim->node_cache[i]->property_anim[property] = pa; +				p_anim->node_cache[i]->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa;  			}  		}  	} @@ -396,7 +396,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float  				//StringName property=a->track_get_path(i).get_property(); -				Map<StringName, TrackNodeCache::PropertyAnim>::Element *E = nc->property_anim.find(a->track_get_path(i).get_property()); +				Map<StringName, TrackNodeCache::PropertyAnim>::Element *E = nc->property_anim.find(a->track_get_path(i).get_concatenated_subnames());  				ERR_CONTINUE(!E); //should it continue, or create a new one?  				TrackNodeCache::PropertyAnim *pa = &E->get(); @@ -434,7 +434,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float  							case SP_NONE: {  								bool valid; -								pa->object->set(pa->prop, value, &valid); //you are not speshul +								pa->object->set_indexed(pa->subpath, value, &valid); //you are not speshul  #ifdef DEBUG_ENABLED  								if (!valid) {  									ERR_PRINTS("Failed setting track value '" + String(pa->owner->path) + "'. Check if property exists or the type of key is valid. Animation '" + a->get_name() + "' at node '" + get_path() + "'."); @@ -615,7 +615,7 @@ void AnimationPlayer::_animation_update_transforms() {  			case SP_NONE: {  				bool valid; -				pa->object->set(pa->prop, pa->value_accum, &valid); //you are not speshul +				pa->object->set_indexed(pa->subpath, pa->value_accum, &valid); //you are not speshul  #ifdef DEBUG_ENABLED  				if (!valid) {  					ERR_PRINTS("Failed setting key at time " + rtos(playback.current.pos) + " in Animation '" + get_current_animation() + "' at Node '" + get_path() + "', Track '" + String(pa->owner->path) + "'. Check if property exists or the type of key is right for the property"); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 83da3b2e5c..e4e021c7fe 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -83,7 +83,7 @@ private:  			TrackNodeCache *owner;  			SpecialProperty special; //small optimization -			StringName prop; +			Vector<StringName> subpath;  			Object *object;  			Variant value_accum;  			uint64_t accum_pass; diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index ad5329c94b..23eccec82f 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -811,7 +811,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) {  		t.scale.y = 0;  		t.scale.z = 0; -		t.value = t.object->get(t.property); +		t.value = t.object->get_indexed(t.subpath);  		t.value.zero();  		t.skip = false; @@ -890,8 +890,8 @@ void AnimationTreePlayer::_process_animation(float p_delta) {  		if (t.skip || !t.object)  			continue; -		if (t.property) { // value track -			t.object->set(t.property, t.value); +		if (t.subpath.size()) { // value track +			t.object->set_indexed(t.subpath, t.value);  			continue;  		} @@ -1475,7 +1475,8 @@ AnimationTreePlayer::Track *AnimationTreePlayer::_find_track(const NodePath &p_p  	ERR_FAIL_COND_V(!parent, NULL);  	RES resource; -	Node *child = parent->get_node_and_resource(p_path, resource); +	Vector<StringName> leftover_path; +	Node *child = parent->get_node_and_resource(p_path, resource, leftover_path);  	if (!child) {  		String err = "Animation track references unknown Node: '" + String(p_path) + "'.";  		WARN_PRINT(err.ascii().get_data()); @@ -1483,21 +1484,18 @@ AnimationTreePlayer::Track *AnimationTreePlayer::_find_track(const NodePath &p_p  	}  	ObjectID id = child->get_instance_id(); -	StringName property;  	int bone_idx = -1; -	if (p_path.get_property()) { +	if (p_path.get_subname_count()) {  		if (Object::cast_to<Skeleton>(child)) -			bone_idx = Object::cast_to<Skeleton>(child)->find_bone(p_path.get_property()); -		if (bone_idx == -1) -			property = p_path.get_property(); +			bone_idx = Object::cast_to<Skeleton>(child)->find_bone(p_path.get_subname(0));  	}  	TrackKey key;  	key.id = id;  	key.bone_idx = bone_idx; -	key.property = property; +	key.subpath_concatenated = p_path.get_concatenated_subnames();  	if (!track_map.has(key)) { @@ -1507,7 +1505,7 @@ AnimationTreePlayer::Track *AnimationTreePlayer::_find_track(const NodePath &p_p  		tr.skeleton = Object::cast_to<Skeleton>(child);  		tr.spatial = Object::cast_to<Spatial>(child);  		tr.bone_idx = bone_idx; -		tr.property = property; +		if (bone_idx == -1) tr.subpath = leftover_path;  		track_map[key] = tr;  	} diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h index 3e2bb88198..c49b0c4d1b 100644 --- a/scene/animation/animation_tree_player.h +++ b/scene/animation/animation_tree_player.h @@ -78,14 +78,14 @@ private:  	struct TrackKey {  		uint32_t id; -		StringName property; +		StringName subpath_concatenated;  		int bone_idx;  		inline bool operator<(const TrackKey &p_right) const {  			if (id == p_right.id) {  				if (bone_idx == p_right.bone_idx) { -					return property < p_right.property; +					return subpath_concatenated < p_right.subpath_concatenated;  				} else  					return bone_idx < p_right.bone_idx;  			} else @@ -99,7 +99,7 @@ private:  		Spatial *spatial;  		Skeleton *skeleton;  		int bone_idx; -		StringName property; +		Vector<StringName> subpath;  		Vector3 loc;  		Quat rot; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index b5e6fc79db..2f0e32d084 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -264,12 +264,12 @@ Variant &Tween::_get_initial_val(InterpolateData &p_data) {  			if (p_data.type == TARGETING_PROPERTY) {  				bool valid = false; -				initial_val = object->get(p_data.target_key, &valid); +				initial_val = object->get_indexed(p_data.target_key, &valid);  				ERR_FAIL_COND_V(!valid, p_data.initial_val);  			} else {  				Variant::CallError error; -				initial_val = object->call(p_data.target_key, NULL, 0, error); +				initial_val = object->call(p_data.target_key[0], NULL, 0, error);  				ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, p_data.initial_val);  			}  			return initial_val; @@ -296,12 +296,12 @@ Variant &Tween::_get_delta_val(InterpolateData &p_data) {  			if (p_data.type == FOLLOW_PROPERTY) {  				bool valid = false; -				final_val = target->get(p_data.target_key, &valid); +				final_val = target->get_indexed(p_data.target_key, &valid);  				ERR_FAIL_COND_V(!valid, p_data.initial_val);  			} else {  				Variant::CallError error; -				final_val = target->call(p_data.target_key, NULL, 0, error); +				final_val = target->call(p_data.target_key[0], NULL, 0, error);  				ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, p_data.initial_val);  			} @@ -462,6 +462,9 @@ Variant Tween::_run_equation(InterpolateData &p_data) {  			result = r;  		} break; +		default: { +			result = initial_val; +		} break;  	};  #undef APPLY_EQUATION @@ -479,7 +482,7 @@ bool Tween::_apply_tween_value(InterpolateData &p_data, Variant &value) {  		case FOLLOW_PROPERTY:  		case TARGETING_PROPERTY: {  			bool valid = false; -			object->set(p_data.key, value, &valid); +			object->set_indexed(p_data.key, value, &valid);  			return valid;  		} @@ -489,9 +492,9 @@ bool Tween::_apply_tween_value(InterpolateData &p_data, Variant &value) {  			Variant::CallError error;  			if (value.get_type() != Variant::NIL) {  				Variant *arg[1] = { &value }; -				object->call(p_data.key, (const Variant **)arg, 1, error); +				object->call(p_data.key[0], (const Variant **)arg, 1, error);  			} else { -				object->call(p_data.key, NULL, 0, error); +				object->call(p_data.key[0], NULL, 0, error);  			}  			if (error.error == Variant::CallError::CALL_OK) @@ -548,7 +551,7 @@ void Tween::_tween_process(float p_delta) {  			continue;  		else if (prev_delaying) { -			emit_signal("tween_started", object, data.key); +			emit_signal("tween_started", object, NodePath(Vector<StringName>(), data.key, false));  			_apply_tween_value(data, data.initial_val);  		} @@ -562,7 +565,7 @@ void Tween::_tween_process(float p_delta) {  			case INTER_PROPERTY:  			case INTER_METHOD: {  				Variant result = _run_equation(data); -				emit_signal("tween_step", object, data.key, data.elapsed, result); +				emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result);  				_apply_tween_value(data, result);  				if (data.finish)  					_apply_tween_value(data, data.final_val); @@ -574,22 +577,22 @@ void Tween::_tween_process(float p_delta) {  						switch (data.args) {  							case 0: -								object->call_deferred(data.key); +								object->call_deferred(data.key[0]);  								break;  							case 1: -								object->call_deferred(data.key, data.arg[0]); +								object->call_deferred(data.key[0], data.arg[0]);  								break;  							case 2: -								object->call_deferred(data.key, data.arg[0], data.arg[1]); +								object->call_deferred(data.key[0], data.arg[0], data.arg[1]);  								break;  							case 3: -								object->call_deferred(data.key, data.arg[0], data.arg[1], data.arg[2]); +								object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2]);  								break;  							case 4: -								object->call_deferred(data.key, data.arg[0], data.arg[1], data.arg[2], data.arg[3]); +								object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3]);  								break;  							case 5: -								object->call_deferred(data.key, data.arg[0], data.arg[1], data.arg[2], data.arg[3], data.arg[4]); +								object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3], data.arg[4]);  								break;  						}  					} else { @@ -601,17 +604,18 @@ void Tween::_tween_process(float p_delta) {  							&data.arg[3],  							&data.arg[4],  						}; -						object->call(data.key, (const Variant **)arg, data.args, error); +						object->call(data.key[0], (const Variant **)arg, data.args, error);  					}  				}  				break; +			default: {}  		}  		if (data.finish) { -			emit_signal("tween_completed", object, data.key); +			emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false));  			// not repeat mode, remove completed action  			if (!repeat) -				call_deferred("_remove", object, data.key, true); +				call_deferred("_remove", object, NodePath(Vector<StringName>(), data.key, false), true);  		}  	}  	pending_update--; @@ -690,7 +694,7 @@ bool Tween::start() {  	return true;  } -bool Tween::reset(Object *p_object, String p_key) { +bool Tween::reset(Object *p_object, StringName p_key) {  	pending_update++;  	for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { @@ -700,7 +704,7 @@ bool Tween::reset(Object *p_object, String p_key) {  		if (object == NULL)  			continue; -		if (object == p_object && (data.key == p_key || p_key == "")) { +		if (object == p_object && (data.concatenated_key == p_key || p_key == "")) {  			data.elapsed = 0;  			data.finish = false; @@ -727,7 +731,7 @@ bool Tween::reset_all() {  	return true;  } -bool Tween::stop(Object *p_object, String p_key) { +bool Tween::stop(Object *p_object, StringName p_key) {  	pending_update++;  	for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { @@ -736,7 +740,7 @@ bool Tween::stop(Object *p_object, String p_key) {  		Object *object = ObjectDB::get_instance(data.id);  		if (object == NULL)  			continue; -		if (object == p_object && (data.key == p_key || p_key == "")) +		if (object == p_object && (data.concatenated_key == p_key || p_key == ""))  			data.active = false;  	}  	pending_update--; @@ -758,7 +762,7 @@ bool Tween::stop_all() {  	return true;  } -bool Tween::resume(Object *p_object, String p_key) { +bool Tween::resume(Object *p_object, StringName p_key) {  	set_active(true);  	_set_process(true); @@ -770,7 +774,7 @@ bool Tween::resume(Object *p_object, String p_key) {  		Object *object = ObjectDB::get_instance(data.id);  		if (object == NULL)  			continue; -		if (object == p_object && (data.key == p_key || p_key == "")) +		if (object == p_object && (data.concatenated_key == p_key || p_key == ""))  			data.active = true;  	}  	pending_update--; @@ -792,12 +796,12 @@ bool Tween::resume_all() {  	return true;  } -bool Tween::remove(Object *p_object, String p_key) { +bool Tween::remove(Object *p_object, StringName p_key) {  	_remove(p_object, p_key, false);  	return true;  } -void Tween::_remove(Object *p_object, String p_key, bool first_only) { +void Tween::_remove(Object *p_object, StringName p_key, bool first_only) {  	if (pending_update != 0) {  		call_deferred("_remove", p_object, p_key, first_only); @@ -810,7 +814,7 @@ void Tween::_remove(Object *p_object, String p_key, bool first_only) {  		Object *object = ObjectDB::get_instance(data.id);  		if (object == NULL)  			continue; -		if (object == p_object && (data.key == p_key || p_key == "")) { +		if (object == p_object && (data.concatenated_key == p_key || p_key == "")) {  			for_removal.push_back(E);  			if (first_only) {  				break; @@ -850,8 +854,9 @@ bool Tween::seek(real_t p_time) {  			data.finish = true;  			data.elapsed = (data.delay + data.duration); -		} else +		} else {  			data.finish = false; +		}  		switch (data.type) {  			case INTER_PROPERTY: @@ -993,12 +998,14 @@ bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final  	return true;  } -bool Tween::interpolate_property(Object *p_object, String p_property, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { +bool Tween::interpolate_property(Object *p_object, NodePath p_property, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) {  	if (pending_update != 0) {  		_add_pending_command("interpolate_property", p_object, p_property, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay);  		return true;  	} -	if (p_initial_val.get_type() == Variant::NIL) p_initial_val = p_object->get(p_property); +	p_property = p_property.get_as_property_path(); + +	if (p_initial_val.get_type() == Variant::NIL) p_initial_val = p_object->get_indexed(p_property.get_subnames());  	// convert INT to REAL is better for interpolaters  	if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); @@ -1013,7 +1020,7 @@ bool Tween::interpolate_property(Object *p_object, String p_property, Variant p_  	ERR_FAIL_COND_V(p_delay < 0, false);  	bool prop_valid = false; -	p_object->get(p_property, &prop_valid); +	p_object->get_indexed(p_property.get_subnames(), &prop_valid);  	ERR_FAIL_COND_V(!prop_valid, false);  	InterpolateData data; @@ -1023,7 +1030,8 @@ bool Tween::interpolate_property(Object *p_object, String p_property, Variant p_  	data.elapsed = 0;  	data.id = p_object->get_instance_id(); -	data.key = p_property; +	data.key = p_property.get_subnames(); +	data.concatenated_key = p_property.get_concatenated_subnames();  	data.initial_val = p_initial_val;  	data.final_val = p_final_val;  	data.duration = p_duration; @@ -1038,7 +1046,7 @@ bool Tween::interpolate_property(Object *p_object, String p_property, Variant p_  	return true;  } -bool Tween::interpolate_method(Object *p_object, String p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { +bool Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) {  	if (pending_update != 0) {  		_add_pending_command("interpolate_method", p_object, p_method, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay);  		return true; @@ -1065,7 +1073,8 @@ bool Tween::interpolate_method(Object *p_object, String p_method, Variant p_init  	data.elapsed = 0;  	data.id = p_object->get_instance_id(); -	data.key = p_method; +	data.key.push_back(p_method); +	data.concatenated_key = p_method;  	data.initial_val = p_initial_val;  	data.final_val = p_final_val;  	data.duration = p_duration; @@ -1102,7 +1111,8 @@ bool Tween::interpolate_callback(Object *p_object, real_t p_duration, String p_c  	data.elapsed = 0;  	data.id = p_object->get_instance_id(); -	data.key = p_callback; +	data.key.push_back(p_callback); +	data.concatenated_key = p_callback;  	data.duration = p_duration;  	data.delay = 0; @@ -1154,7 +1164,8 @@ bool Tween::interpolate_deferred_callback(Object *p_object, real_t p_duration, S  	data.elapsed = 0;  	data.id = p_object->get_instance_id(); -	data.key = p_callback; +	data.key.push_back(p_callback); +	data.concatenated_key = p_callback;  	data.duration = p_duration;  	data.delay = 0; @@ -1185,12 +1196,15 @@ bool Tween::interpolate_deferred_callback(Object *p_object, real_t p_duration, S  	return true;  } -bool Tween::follow_property(Object *p_object, String p_property, Variant p_initial_val, Object *p_target, String p_target_property, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { +bool Tween::follow_property(Object *p_object, NodePath p_property, Variant p_initial_val, Object *p_target, NodePath p_target_property, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) {  	if (pending_update != 0) {  		_add_pending_command("follow_property", p_object, p_property, p_initial_val, p_target, p_target_property, p_duration, p_trans_type, p_ease_type, p_delay);  		return true;  	} -	if (p_initial_val.get_type() == Variant::NIL) p_initial_val = p_object->get(p_initial_val); +	p_property = p_property.get_as_property_path(); +	p_target_property = p_target_property.get_as_property_path(); + +	if (p_initial_val.get_type() == Variant::NIL) p_initial_val = p_object->get_indexed(p_property.get_subnames());  	// convert INT to REAL is better for interpolaters  	if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); @@ -1205,11 +1219,11 @@ bool Tween::follow_property(Object *p_object, String p_property, Variant p_initi  	ERR_FAIL_COND_V(p_delay < 0, false);  	bool prop_valid = false; -	p_object->get(p_property, &prop_valid); +	p_object->get_indexed(p_property.get_subnames(), &prop_valid);  	ERR_FAIL_COND_V(!prop_valid, false);  	bool target_prop_valid = false; -	Variant target_val = p_target->get(p_target_property, &target_prop_valid); +	Variant target_val = p_target->get_indexed(p_target_property.get_subnames(), &target_prop_valid);  	ERR_FAIL_COND_V(!target_prop_valid, false);  	// convert INT to REAL is better for interpolaters @@ -1223,10 +1237,11 @@ bool Tween::follow_property(Object *p_object, String p_property, Variant p_initi  	data.elapsed = 0;  	data.id = p_object->get_instance_id(); -	data.key = p_property; +	data.key = p_property.get_subnames(); +	data.concatenated_key = p_property.get_concatenated_subnames();  	data.initial_val = p_initial_val;  	data.target_id = p_target->get_instance_id(); -	data.target_key = p_target_property; +	data.target_key = p_target_property.get_subnames();  	data.duration = p_duration;  	data.trans_type = p_trans_type;  	data.ease_type = p_ease_type; @@ -1236,7 +1251,7 @@ bool Tween::follow_property(Object *p_object, String p_property, Variant p_initi  	return true;  } -bool Tween::follow_method(Object *p_object, String p_method, Variant p_initial_val, Object *p_target, String p_target_method, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { +bool Tween::follow_method(Object *p_object, StringName p_method, Variant p_initial_val, Object *p_target, StringName p_target_method, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) {  	if (pending_update != 0) {  		_add_pending_command("follow_method", p_object, p_method, p_initial_val, p_target, p_target_method, p_duration, p_trans_type, p_ease_type, p_delay);  		return true; @@ -1273,10 +1288,11 @@ bool Tween::follow_method(Object *p_object, String p_method, Variant p_initial_v  	data.elapsed = 0;  	data.id = p_object->get_instance_id(); -	data.key = p_method; +	data.key.push_back(p_method); +	data.concatenated_key = p_method;  	data.initial_val = p_initial_val;  	data.target_id = p_target->get_instance_id(); -	data.target_key = p_target_method; +	data.target_key.push_back(p_target_method);  	data.duration = p_duration;  	data.trans_type = p_trans_type;  	data.ease_type = p_ease_type; @@ -1286,11 +1302,15 @@ bool Tween::follow_method(Object *p_object, String p_method, Variant p_initial_v  	return true;  } -bool Tween::targeting_property(Object *p_object, String p_property, Object *p_initial, String p_initial_property, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { +bool Tween::targeting_property(Object *p_object, NodePath p_property, Object *p_initial, NodePath p_initial_property, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { +  	if (pending_update != 0) {  		_add_pending_command("targeting_property", p_object, p_property, p_initial, p_initial_property, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay);  		return true;  	} +	p_property = p_property.get_as_property_path(); +	p_initial_property = p_initial_property.get_as_property_path(); +  	// convert INT to REAL is better for interpolaters  	if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); @@ -1304,11 +1324,11 @@ bool Tween::targeting_property(Object *p_object, String p_property, Object *p_in  	ERR_FAIL_COND_V(p_delay < 0, false);  	bool prop_valid = false; -	p_object->get(p_property, &prop_valid); +	p_object->get_indexed(p_property.get_subnames(), &prop_valid);  	ERR_FAIL_COND_V(!prop_valid, false);  	bool initial_prop_valid = false; -	Variant initial_val = p_initial->get(p_initial_property, &initial_prop_valid); +	Variant initial_val = p_initial->get_indexed(p_initial_property.get_subnames(), &initial_prop_valid);  	ERR_FAIL_COND_V(!initial_prop_valid, false);  	// convert INT to REAL is better for interpolaters @@ -1322,9 +1342,10 @@ bool Tween::targeting_property(Object *p_object, String p_property, Object *p_in  	data.elapsed = 0;  	data.id = p_object->get_instance_id(); -	data.key = p_property; +	data.key = p_property.get_subnames(); +	data.concatenated_key = p_property.get_concatenated_subnames();  	data.target_id = p_initial->get_instance_id(); -	data.target_key = p_initial_property; +	data.target_key = p_initial_property.get_subnames();  	data.initial_val = initial_val;  	data.final_val = p_final_val;  	data.duration = p_duration; @@ -1339,7 +1360,7 @@ bool Tween::targeting_property(Object *p_object, String p_property, Object *p_in  	return true;  } -bool Tween::targeting_method(Object *p_object, String p_method, Object *p_initial, String p_initial_method, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { +bool Tween::targeting_method(Object *p_object, StringName p_method, Object *p_initial, StringName p_initial_method, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) {  	if (pending_update != 0) {  		_add_pending_command("targeting_method", p_object, p_method, p_initial, p_initial_method, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay);  		return true; @@ -1376,9 +1397,10 @@ bool Tween::targeting_method(Object *p_object, String p_method, Object *p_initia  	data.elapsed = 0;  	data.id = p_object->get_instance_id(); -	data.key = p_method; +	data.key.push_back(p_method); +	data.concatenated_key = p_method;  	data.target_id = p_initial->get_instance_id(); -	data.target_key = p_initial_method; +	data.target_key.push_back(p_initial_method);  	data.initial_val = initial_val;  	data.final_val = p_final_val;  	data.duration = p_duration; diff --git a/scene/animation/tween.h b/scene/animation/tween.h index fac1d346b4..44710b25f9 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -86,12 +86,13 @@ private:  		bool call_deferred;  		real_t elapsed;  		ObjectID id; -		StringName key; +		Vector<StringName> key; +		StringName concatenated_key;  		Variant initial_val;  		Variant delta_val;  		Variant final_val;  		ObjectID target_id; -		StringName target_key; +		Vector<StringName> target_key;  		real_t duration;  		TransitionType trans_type;  		EaseType ease_type; @@ -132,7 +133,7 @@ private:  	void _tween_process(float p_delta);  	void _set_process(bool p_process, bool p_force = false); -	void _remove(Object *p_object, String p_key, bool first_only); +	void _remove(Object *p_object, StringName p_key, bool first_only);  protected:  	bool _set(const StringName &p_name, const Variant &p_value); @@ -156,34 +157,34 @@ public:  	float get_speed_scale() const;  	bool start(); -	bool reset(Object *p_object, String p_key); +	bool reset(Object *p_object, StringName p_key);  	bool reset_all(); -	bool stop(Object *p_object, String p_key); +	bool stop(Object *p_object, StringName p_key);  	bool stop_all(); -	bool resume(Object *p_object, String p_key); +	bool resume(Object *p_object, StringName p_key);  	bool resume_all(); -	bool remove(Object *p_object, String p_key); +	bool remove(Object *p_object, StringName p_key);  	bool remove_all();  	bool seek(real_t p_time);  	real_t tell() const;  	real_t get_runtime() const; -	bool interpolate_property(Object *p_object, String p_property, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); +	bool interpolate_property(Object *p_object, NodePath p_property, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); -	bool interpolate_method(Object *p_object, String p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); +	bool interpolate_method(Object *p_object, StringName p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0);  	bool interpolate_callback(Object *p_object, real_t p_duration, String p_callback, VARIANT_ARG_DECLARE);  	bool interpolate_deferred_callback(Object *p_object, real_t p_duration, String p_callback, VARIANT_ARG_DECLARE); -	bool follow_property(Object *p_object, String p_property, Variant p_initial_val, Object *p_target, String p_target_property, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); +	bool follow_property(Object *p_object, NodePath p_property, Variant p_initial_val, Object *p_target, NodePath p_target_property, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); -	bool follow_method(Object *p_object, String p_method, Variant p_initial_val, Object *p_target, String p_target_method, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); +	bool follow_method(Object *p_object, StringName p_method, Variant p_initial_val, Object *p_target, StringName p_target_method, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); -	bool targeting_property(Object *p_object, String p_property, Object *p_initial, String p_initial_property, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); +	bool targeting_property(Object *p_object, NodePath p_property, Object *p_initial, NodePath p_initial_property, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); -	bool targeting_method(Object *p_object, String p_method, Object *p_initial, String p_initial_method, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0); +	bool targeting_method(Object *p_object, StringName p_method, Object *p_initial, StringName p_initial_method, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay = 0);  	Tween();  	~Tween(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index e6e11de177..7a1bdb7425 100755 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2466,24 +2466,19 @@ bool Node::has_node_and_resource(const NodePath &p_path) const {  		return false;  	Node *node = get_node(p_path); -	if (p_path.get_subname_count()) { +	bool result = false; -		RES r; -		for (int j = 0; j < p_path.get_subname_count(); j++) { -			r = j == 0 ? node->get(p_path.get_subname(j)) : r->get(p_path.get_subname(j)); -			if (r.is_null()) -				return false; -		} -	} +	node->get_indexed(p_path.get_subnames(), &result); -	return true; +	return result;  }  Array Node::_get_node_and_resource(const NodePath &p_path) {  	Node *node;  	RES res; -	node = get_node_and_resource(p_path, res); +	Vector<StringName> leftover_path; +	node = get_node_and_resource(p_path, res, leftover_path);  	Array result;  	if (node) @@ -2496,21 +2491,35 @@ Array Node::_get_node_and_resource(const NodePath &p_path) {  	else  		result.push_back(Variant()); +	result.push_back(NodePath(Vector<StringName>(), leftover_path, false)); +  	return result;  } -Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res) const { +Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property) const {  	Node *node = get_node(p_path);  	r_res = RES(); +	r_leftover_subpath = Vector<StringName>();  	if (!node)  		return NULL;  	if (p_path.get_subname_count()) { -		for (int j = 0; j < p_path.get_subname_count(); j++) { -			r_res = j == 0 ? node->get(p_path.get_subname(j)) : r_res->get(p_path.get_subname(j)); -			ERR_FAIL_COND_V(r_res.is_null(), node); +		int j = 0; +		// If not p_last_is_property, we shouldn't consider the last one as part of the resource +		for (; j < p_path.get_subname_count() - p_last_is_property; j++) { +			RES new_res = j == 0 ? node->get(p_path.get_subname(j)) : r_res->get(p_path.get_subname(j)); + +			if (new_res.is_null()) { +				break; +			} + +			r_res = new_res; +		} +		for (; j < p_path.get_subname_count(); j++) { +			// Put the rest of the subpath in the leftover path +			r_leftover_subpath.push_back(p_path.get_subname(j));  		}  	} diff --git a/scene/main/node.h b/scene/main/node.h index c43e96063f..8fd1a386dd 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -242,7 +242,7 @@ public:  	Node *get_node(const NodePath &p_path) const;  	Node *find_node(const String &p_mask, bool p_recursive = true, bool p_owned = true) const;  	bool has_node_and_resource(const NodePath &p_path) const; -	Node *get_node_and_resource(const NodePath &p_path, RES &r_res) const; +	Node *get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property = true) const;  	Node *get_parent() const;  	_FORCE_INLINE_ SceneTree *get_tree() const {  |