Error ResourceSaver::save(const String &p_path,const RES& p_resource,uint32_t p_flags) { String extension=p_path.extension(); Error err=ERR_FILE_UNRECOGNIZED; for (int i=0;i<saver_count;i++) { if (!saver[i]->recognize(p_resource)) continue; List<String> extensions; bool recognized=false; saver[i]->get_recognized_extensions(p_resource,&extensions); for (List<String>::Element *E=extensions.front();E;E=E->next()) { if (E->get().nocasecmp_to(extension.extension())==0) recognized=true; } if (!recognized) continue; String old_path=p_resource->get_path(); String local_path=Globals::get_singleton()->localize_path(p_path); RES rwcopy = p_resource; if (p_flags&FLAG_CHANGE_PATH) rwcopy->set_path(local_path); err = saver[i]->save(p_path,p_resource,p_flags); if (err == OK ) { #ifdef TOOLS_ENABLED ((Resource*)p_resource.ptr())->set_edited(false); if (timestamp_on_save) { uint64_t mt = FileAccess::get_modified_time(p_path); ((Resource*)p_resource.ptr())->set_last_modified_time(mt); } #endif if (p_flags&FLAG_CHANGE_PATH) rwcopy->set_path(old_path); if (save_callback && p_path.begins_with("res://")) save_callback(p_path); return OK; } else { } } return err; }
bool AnimationTree::_update_caches(AnimationPlayer *player) { setup_pass++; if (!player->has_node(player->get_root())) { ERR_PRINT("AnimationTree: AnimationPlayer root is invalid."); set_active(false); return false; } Node *parent = player->get_node(player->get_root()); List<StringName> sname; player->get_animation_list(&sname); for (List<StringName>::Element *E = sname.front(); E; E = E->next()) { Ref<Animation> anim = player->get_animation(E->get()); for (int i = 0; i < anim->get_track_count(); i++) { NodePath path = anim->track_get_path(i); Animation::TrackType track_type = anim->track_get_type(i); TrackCache *track = NULL; if (track_cache.has(path)) { track = track_cache.get(path); } //if not valid, delete track if (track && (track->type != track_type || ObjectDB::get_instance(track->object_id) == NULL)) { playing_caches.erase(track); memdelete(track); track_cache.erase(path); track = NULL; } if (!track) { RES resource; Vector<StringName> leftover_path; Node *child = parent->get_node_and_resource(path, resource, leftover_path); if (!child) { ERR_PRINTS("AnimationTree: '" + String(E->get()) + "', couldn't resolve track: '" + String(path) + "'"); continue; } if (!child->is_connected("tree_exited", this, "_node_removed")) { child->connect("tree_exited", this, "_node_removed", varray(child)); } switch (track_type) { case Animation::TYPE_VALUE: { TrackCacheValue *track_value = memnew(TrackCacheValue); if (resource.is_valid()) { track_value->object = resource.ptr(); } else { track_value->object = child; } track_value->subpath = leftover_path; track_value->object_id = track_value->object->get_instance_id(); track = track_value; } break; case Animation::TYPE_TRANSFORM: { Spatial *spatial = Object::cast_to<Spatial>(child); if (!spatial) { ERR_PRINTS("AnimationTree: '" + String(E->get()) + "', transform track does not point to spatial: '" + String(path) + "'"); continue; } TrackCacheTransform *track_xform = memnew(TrackCacheTransform); track_xform->spatial = spatial; track_xform->skeleton = NULL; track_xform->bone_idx = -1; if (path.get_subname_count() == 1 && Object::cast_to<Skeleton>(spatial)) { Skeleton *sk = Object::cast_to<Skeleton>(spatial); int bone_idx = sk->find_bone(path.get_subname(0)); if (bone_idx != -1 && !sk->is_bone_ignore_animation(bone_idx)) { track_xform->skeleton = sk; track_xform->bone_idx = bone_idx; } } track_xform->object = spatial; track_xform->object_id = track_xform->object->get_instance_id(); track = track_xform; } break; case Animation::TYPE_METHOD: { TrackCacheMethod *track_method = memnew(TrackCacheMethod); if (resource.is_valid()) { track_method->object = resource.ptr(); } else { track_method->object = child; } track_method->object_id = track_method->object->get_instance_id(); track = track_method; } break; case Animation::TYPE_BEZIER: { TrackCacheBezier *track_bezier = memnew(TrackCacheBezier); if (resource.is_valid()) { track_bezier->object = resource.ptr(); } else { track_bezier->object = child; } track_bezier->subpath = leftover_path; track_bezier->object_id = track_bezier->object->get_instance_id(); track = track_bezier; } break; case Animation::TYPE_AUDIO: { TrackCacheAudio *track_audio = memnew(TrackCacheAudio); track_audio->object = child; track_audio->object_id = track_audio->object->get_instance_id(); track = track_audio; } break; case Animation::TYPE_ANIMATION: { TrackCacheAnimation *track_animation = memnew(TrackCacheAnimation); track_animation->object = child; track_animation->object_id = track_animation->object->get_instance_id(); track = track_animation; } break; default: { ERR_PRINT("Animation corrupted (invalid track type)"); continue; } } track_cache[path] = track; } track->setup_pass = setup_pass; } } List<NodePath> to_delete; const NodePath *K = NULL; while ((K = track_cache.next(K))) { TrackCache *tc = track_cache[*K]; if (tc->setup_pass != setup_pass) { to_delete.push_back(*K); } } while (to_delete.front()) { NodePath np = to_delete.front()->get(); memdelete(track_cache[np]); track_cache.erase(np); to_delete.pop_front(); } state.track_map.clear(); K = NULL; int idx = 0; while ((K = track_cache.next(K))) { state.track_map[*K] = idx; idx++; } state.track_count = idx; cache_valid = true; return true; }
void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) { Node *parent = get_node(root); ERR_FAIL_COND(!parent); Animation *a = p_anim->animation.operator->(); p_anim->node_cache.resize(a->get_track_count()); for (int i = 0; i < a->get_track_count(); i++) { p_anim->node_cache[i] = NULL; RES resource; Node *child = parent->get_node_and_resource(a->track_get_path(i), resource); if (!child) { ERR_EXPLAIN("On Animation: '" + p_anim->name + "', couldn't resolve track: '" + String(a->track_get_path(i)) + "'"); } ERR_CONTINUE(!child); // couldn't find the child node 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)) { bone_idx = Object::cast_to<Skeleton>(child)->find_bone(a->track_get_path(i).get_property()); if (bone_idx == -1) { continue; } } { if (!child->is_connected("tree_exited", this, "_node_removed")) child->connect("tree_exited", this, "_node_removed", make_binds(child), CONNECT_ONESHOT); } TrackNodeCacheKey key; key.id = id; key.bone_idx = bone_idx; if (node_cache_map.has(key)) { p_anim->node_cache[i] = &node_cache_map[key]; } else { node_cache_map[key] = TrackNodeCache(); p_anim->node_cache[i] = &node_cache_map[key]; p_anim->node_cache[i]->path = a->track_get_path(i); p_anim->node_cache[i]->node = child; p_anim->node_cache[i]->resource = resource; p_anim->node_cache[i]->node_2d = Object::cast_to<Node2D>(child); if (a->track_get_type(i) == Animation::TYPE_TRANSFORM) { // special cases and caches for transform tracks // cache spatial p_anim->node_cache[i]->spatial = Object::cast_to<Spatial>(child); // cache skeleton 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() != "") { 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) { // broken track (nonexistent bone) p_anim->node_cache[i]->skeleton = NULL; p_anim->node_cache[i]->spatial = NULL; printf("bone is %ls\n", String(bone_name).c_str()); ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0); } else { } } else { // no property, just use spatialnode p_anim->node_cache[i]->skeleton = NULL; } } } } 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)) { TrackNodeCache::PropertyAnim pa; pa.prop = property; 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) pa.special = SP_NODE2D_POS; else if (pa.prop == SceneStringNames::get_singleton()->transform_rot) pa.special = SP_NODE2D_ROT; else if (pa.prop == SceneStringNames::get_singleton()->transform_scale) pa.special = SP_NODE2D_SCALE; } p_anim->node_cache[i]->property_anim[property] = pa; } } } }
void AnimationCache::_update_cache() { cache_valid=false; ERR_FAIL_COND(!root); ERR_FAIL_COND(!root->is_inside_tree()); ERR_FAIL_COND(animation.is_null()); for(int i=0;i<animation->get_track_count();i++) { NodePath np = animation->track_get_path(i); Node *node = root->get_node(np); if (!node) { path_cache.push_back(Path()); ERR_EXPLAIN("Invalid Track Path in Animation: "+np); ERR_CONTINUE(!node); } Path path; Ref<Resource> res; if (np.get_subname_count()) { if (animation->track_get_type(i)==Animation::TYPE_TRANSFORM) { 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; } if (res.is_null()) { path_cache.push_back(Path()); ERR_EXPLAIN("Invalid Track SubPath in Animation: "+np); ERR_CONTINUE(res.is_null()); } path.resource=res; path.object=res.ptr(); } else { if (animation->track_get_type(i)==Animation::TYPE_TRANSFORM) { StringName property = np.get_property(); String ps = property; Spatial *sp = node->cast_to<Spatial>(); if (!sp) { path_cache.push_back(Path()); ERR_EXPLAIN("Transform track not of type Spatial: "+np); ERR_CONTINUE(!sp); } if (ps!="") { Skeleton *sk = node->cast_to<Skeleton>(); 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; } path.spatial=sp; } path.node=node; path.object=node; } if (animation->track_get_type(i)==Animation::TYPE_VALUE) { if (np.get_property().operator String()=="") { path_cache.push_back(Path()); ERR_EXPLAIN("Value Track lacks property: "+np); ERR_CONTINUE(np.get_property().operator String()==""); } path.property=np.get_property(); } else if (animation->track_get_type(i)==Animation::TYPE_METHOD) { if (np.get_property().operator String()!="") { path_cache.push_back(Path()); ERR_EXPLAIN("Method Track has property: "+np); ERR_CONTINUE(np.get_property().operator String()!=""); } } path.valid=true; path_cache.push_back(path); if (!connected_nodes.has(path.node)) { connected_nodes.insert(path.node); path.node->connect("exit_tree",this,"_node_exit_tree",Node::make_binds(path.node),CONNECT_ONESHOT); } } cache_dirty=false; cache_valid=true; }