Allow for getting/setting indexed properties of objects using get/set_indexed

Performance is around the same as using pure set() through GDScript.
This commit is contained in:
Bojidar Marinov 2017-05-30 23:20:15 +03:00
parent 7bbde636e8
commit 0cf9597758
No known key found for this signature in database
GPG Key ID: 4D546A8F1E091856
23 changed files with 416 additions and 246 deletions

View File

@ -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();

View File

@ -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: {}

View File

@ -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(const Vector<StringName> &p_path, bool p_absolute, const String &p_property) {
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) {
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)

View File

@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -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());

View File

@ -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";

View File

@ -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 {

View File

@ -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);

View File

@ -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;
}

View File

@ -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"]

View File

@ -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);

View File

@ -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;
Spatial *sp = Object::cast_to<Spatial>(node);
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;
}
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);
if (!sp) {
Skeleton *sk = Object::cast_to<Skeleton>(node);
if (!sk) {
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!: " + np);
ERR_CONTINUE(!sk);
}
if (ps != "") {
Skeleton *sk = Object::cast_to<Skeleton>(node);
if (!sk) {
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("Property defined in Transform track, but not a Skeleton Bone!: " + np);
ERR_CONTINUE(idx == -1);
}
path.bone_idx = idx;
path.skeleton = sk;
int idx = sk->find_bone(ps);
if (idx == -1) {
path_cache.push_back(Path());
ERR_EXPLAIN("Property defined in Transform track, but not a Skeleton Bone!: " + np);
ERR_CONTINUE(idx == -1);
}
path.spatial = sp;
path.bone_idx = idx;
path.skeleton = sk;
}
path.node = node;
path.object = node;
path.spatial = sp;
} else {
if (np.get_subname_count() > 0) {
RES res;
Vector<StringName> leftover_subpath;
// 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);
if (res.is_valid()) {
path.resource = res;
} else {
path.node = node;
}
path.object = res.is_valid() ? res.ptr() : (Object *)node;
path.subpath = leftover_subpath;
} else {
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) {

View File

@ -46,7 +46,7 @@ class AnimationCache : public Object {
Spatial *spatial;
int bone_idx;
StringName property;
Vector<StringName> subpath;
bool valid;
Path() {
object = NULL;

View File

@ -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");

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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));
}
}

View File

@ -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 {