예제 #1
0
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;
}
예제 #2
0
RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {

	if (r_error)
		*r_error = ERR_CANT_OPEN;

	String local_path;
	if (p_path.is_rel_path())
		local_path = "res://" + p_path;
	else
		local_path = GlobalConfig::get_singleton()->localize_path(p_path);

	ERR_FAIL_COND_V(local_path == "", RES());

	if (!p_no_cache && ResourceCache::has(local_path)) {

		if (OS::get_singleton()->is_stdout_verbose())
			print_line("load resource: " + local_path + " (cached)");

		return RES(ResourceCache::get(local_path));
	}

	if (OS::get_singleton()->is_stdout_verbose())
		print_line("load resource: " + local_path);
	bool found = false;

	for (int i = 0; i < loader_count; i++) {

		if (!loader[i]->recognize_path(local_path, p_type_hint)) {
			print_line("path not recognized");
			continue;
		}
		found = true;
		RES res = loader[i]->load(local_path, local_path, r_error);
		if (res.is_null()) {
			continue;
		}
		if (!p_no_cache)
			res->set_path(local_path);
#ifdef TOOLS_ENABLED

		res->set_edited(false);
		if (timestamp_on_load) {
			uint64_t mt = FileAccess::get_modified_time(local_path);
			//printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt);
			res->set_last_modified_time(mt);
		}
#endif

		return res;
	}

	if (found) {
		ERR_EXPLAIN("Failed loading resource: " + p_path);
	} else {
		ERR_EXPLAIN("No loader found for resource: " + p_path);
	}
	ERR_FAIL_V(RES());
	return RES();
}
예제 #3
0
RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_no_cache) {

	String local_path = Globals::get_singleton()->localize_path(p_path);

	local_path=find_complete_path(p_path,p_type_hint);
	ERR_FAIL_COND_V(local_path=="",RES());

	if (!p_no_cache && ResourceCache::has(local_path)) {

		if (OS::get_singleton()->is_stdout_verbose())
			print_line("load resource: "+local_path+" (cached)");

		return RES( ResourceCache::get(local_path ) );
	}

	String remapped_path = PathRemap::get_singleton()->get_remap(local_path);

	if (OS::get_singleton()->is_stdout_verbose())
		print_line("load resource: "+remapped_path);

	String extension=remapped_path.extension();
	bool found=false;
	
	for (int i=0;i<loader_count;i++) {
		
		if (!loader[i]->recognize(extension))
			continue;
		if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
			continue;
		found=true;
		RES res = loader[i]->load(remapped_path,local_path);
		if (res.is_null())
			continue;
		if (!p_no_cache)
			res->set_path(local_path);
#ifdef TOOLS_ENABLED

		res->set_edited(false);
		if (timestamp_on_load) {
			uint64_t mt = FileAccess::get_modified_time(remapped_path);
			//printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt);
			res->set_last_modified_time(mt);
		}
#endif

		return res;
	}

	if (found) {
		ERR_EXPLAIN("Failed loading resource: "+p_path);
	} else {
		ERR_EXPLAIN("No loader found for resource: "+p_path);
	}
	ERR_FAIL_V(RES());
	return RES();
}
예제 #4
0
void Object::_clear_internal_resource_paths(const Variant &p_var) {

	switch(p_var.get_type()) {

		case Variant::OBJECT: {

			RES r = p_var;
			if (!r.is_valid())
				return;

			if (!r->get_path().begins_with("res://") || r->get_path().find("::")==-1)
				return; //not an internal resource

			Object *object=p_var;
			if (!object)
				return;

			r->set_path("");
			r->clear_internal_resource_paths();
		} break;
		case Variant::ARRAY: {

			Array a=p_var;
			for(int i=0;i<a.size();i++) {
				_clear_internal_resource_paths(a[i]);
			}

		} break;
		case Variant::DICTIONARY: {

			Dictionary d=p_var;
			List<Variant> keys;
			d.get_key_list(&keys);

			for (List<Variant>::Element *E=keys.front();E;E=E->next()) {

				_clear_internal_resource_paths(E->get());
				_clear_internal_resource_paths(d[E->get()]);
			}
		} break;
		default: {}
	}

}
예제 #5
0
RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {

	if (r_error)
		*r_error = ERR_CANT_OPEN;

	String local_path;
	if (p_path.is_rel_path())
		local_path = "res://" + p_path;
	else
		local_path = ProjectSettings::get_singleton()->localize_path(p_path);

	if (!p_no_cache) {

		{
			bool success = _add_to_loading_map(local_path);
			if (!success) {
				ERR_EXPLAIN("Resource: '" + local_path + "' is already being loaded. Cyclic reference?");
				ERR_FAIL_V(RES());
			}
		}

		//lock first if possible
		if (ResourceCache::lock) {
			ResourceCache::lock->read_lock();
		}

		//get ptr
		Resource **rptr = ResourceCache::resources.getptr(local_path);

		if (rptr) {
			RES res(*rptr);
			//it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
			if (res.is_valid()) {
				//referencing is fine
				if (r_error)
					*r_error = OK;
				if (ResourceCache::lock) {
					ResourceCache::lock->read_unlock();
				}
				_remove_from_loading_map(local_path);
				return res;
			}
		}
		if (ResourceCache::lock) {
			ResourceCache::lock->read_unlock();
		}
	}

	bool xl_remapped = false;
	String path = _path_remap(local_path, &xl_remapped);

	if (path == "") {
		if (!p_no_cache) {
			_remove_from_loading_map(local_path);
		}
		ERR_EXPLAIN("Remapping '" + local_path + "'failed.");
		ERR_FAIL_V(RES());
	}

	print_verbose("Loading resource: " + path);
	RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error);

	if (res.is_null()) {
		if (!p_no_cache) {
			_remove_from_loading_map(local_path);
		}
		return RES();
	}
	if (!p_no_cache)
		res->set_path(local_path);

	if (xl_remapped)
		res->set_as_translation_remapped(true);

#ifdef TOOLS_ENABLED

	res->set_edited(false);
	if (timestamp_on_load) {
		uint64_t mt = FileAccess::get_modified_time(path);
		//printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt);
		res->set_last_modified_time(mt);
	}
#endif

	if (!p_no_cache) {
		_remove_from_loading_map(local_path);
	}

	if (_loaded_callback) {
		_loaded_callback(res, p_path);
	}

	return res;
}
예제 #6
0
Error ResourceFormatSaverTextInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {

	if (p_path.ends_with(".tscn")) {
		packed_scene=p_resource;
	}

	Error err;
	f = FileAccess::open(p_path, FileAccess::WRITE,&err);
	ERR_FAIL_COND_V( err, ERR_CANT_OPEN );
	FileAccessRef _fref(f);

	local_path = Globals::get_singleton()->localize_path(p_path);

	relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS;
	skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
	bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES;
	takeover_paths=p_flags&ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
	if (!p_path.begins_with("res://")) {
		takeover_paths=false;
	}

	// save resources
	_find_resources(p_resource,true);

	if (packed_scene.is_valid()) {
		//add instances to external resources if saving a packed scene
		for(int i=0;i<packed_scene->get_state()->get_node_count();i++) {
			if (packed_scene->get_state()->is_node_instance_placeholder(i))
				continue;

			Ref<PackedScene> instance=packed_scene->get_state()->get_node_instance(i);
			if (instance.is_valid() && !external_resources.has(instance)) {
				int index = external_resources.size();
				external_resources[instance]=index;
			}
		}
	}


	ERR_FAIL_COND_V(err!=OK,err);

	{
		String title=packed_scene.is_valid()?"[gd_scene ":"[gd_resource ";
		if (packed_scene.is_null())
			title+="type=\""+p_resource->get_type()+"\" ";
		int load_steps=saved_resources.size()+external_resources.size();
		//if (packed_scene.is_valid()) {
		//	load_steps+=packed_scene->get_node_count();
		//}
		//no, better to not use load steps from nodes, no point to that

		if (load_steps>1) {
			title+="load_steps="+itos(load_steps)+" ";
		}
		title+="format="+itos(FORMAT_VERSION)+"";
		//title+="engine_version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\"";

		f->store_string(title);
		f->store_line("]\n"); //one empty line
	}


	Vector<RES> sorted_er;
	sorted_er.resize(external_resources.size());

	for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) {

		sorted_er[E->get()]=E->key();
	}

	for(int i=0;i<sorted_er.size();i++) {
		String p = sorted_er[i]->get_path();

		f->store_string("[ext_resource path=\""+p+"\" type=\""+sorted_er[i]->get_save_type()+"\" id="+itos(i+1)+"]\n"); //bundled
	}

	if (external_resources.size())
		f->store_line(String()); //separate

	Set<int> used_indices;

	for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {

		RES res = E->get();
		if (E->next() && (res->get_path()=="" || res->get_path().find("::") != -1 )) {

			if (res->get_subindex()!=0) {
				if (used_indices.has(res->get_subindex())) {
					res->set_subindex(0); //repeated
				} else {
					used_indices.insert(res->get_subindex());
				}
			}
		}
	}

	for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {

		RES res = E->get();
		ERR_CONTINUE(!resource_set.has(res));
		bool main = (E->next()==NULL);

		if (main && packed_scene.is_valid())
			break; //save as a scene

		if (main) {
			f->store_line("[resource]\n");
		} else {
			String line="[sub_resource ";
			if (res->get_subindex()==0) {
				int new_subindex=1;
				if (used_indices.size()) {
					new_subindex=used_indices.back()->get()+1;
				}

				res->set_subindex(new_subindex);
				used_indices.insert(new_subindex);
			}

			int idx = res->get_subindex();
			line+="type=\""+res->get_type()+"\" id="+itos(idx);
			f->store_line(line+"]\n");
			if (takeover_paths) {
				res->set_path(p_path+"::"+itos(idx),true);
			}

			internal_resources[res]=idx;

		}


		List<PropertyInfo> property_list;
		res->get_property_list(&property_list);
//		property_list.sort();
		for(List<PropertyInfo>::Element *PE = property_list.front();PE;PE=PE->next()) {


			if (skip_editor && PE->get().name.begins_with("__editor"))
				continue;

			if (PE->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && PE->get().usage&PROPERTY_USAGE_BUNDLE)) {

				String name = PE->get().name;
				Variant value = res->get(name);


				if ((PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())||(PE->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && value.is_one()) )
					continue;

				if (PE->get().type==Variant::OBJECT && value.is_zero() && !(PE->get().usage&PROPERTY_USAGE_STORE_IF_NULL))
					continue;

				String vars;
				VariantWriter::write_to_string(value,vars,_write_resources,this);
				f->store_string(_valprop(name)+" = "+vars+"\n");
			}


		}

		f->store_string("\n");

	}

	if (packed_scene.is_valid()) {
		//if this is a scene, save nodes and connections!
		Ref<SceneState> state = packed_scene->get_state();
		for(int i=0;i<state->get_node_count();i++) {

			StringName type = state->get_node_type(i);
			StringName name = state->get_node_name(i);
			NodePath path = state->get_node_path(i,true);
			NodePath owner = state->get_node_owner_path(i);
			Ref<PackedScene> instance = state->get_node_instance(i);
			String instance_placeholder = state->get_node_instance_placeholder(i);
			Vector<StringName> groups = state->get_node_groups(i);



			String header="[node";
			header+=" name=\""+String(name)+"\"";
			if (type!=StringName()) {
				header+=" type=\""+String(type)+"\"";
			}
			if (path!=NodePath()) {
				header+=" parent=\""+String(path.simplified())+"\"";
			}
			if (owner!=NodePath() && owner!=NodePath(".")) {
				header+=" owner=\""+String(owner.simplified())+"\"";
			}

			if (groups.size()) {
				String sgroups=" groups=[ ";
				for(int j=0;j<groups.size();j++) {
					if (j>0)
						sgroups+=", ";
					sgroups+="\""+groups[j].operator String().c_escape()+"\"";
				}
				sgroups+=" ]";
				header+=sgroups;
			}

			f->store_string(header);

			if (instance_placeholder!=String()) {

				String vars;
				f->store_string(" instance_placeholder=");
				VariantWriter::write_to_string(instance_placeholder,vars,_write_resources,this);
				f->store_string(vars);
			}

			if (instance.is_valid()) {

				String vars;
				f->store_string(" instance=");
				VariantWriter::write_to_string(instance,vars,_write_resources,this);
				f->store_string(vars);

			}

			f->store_line("]\n");

			for(int j=0;j<state->get_node_property_count(i);j++) {

				String vars;
				VariantWriter::write_to_string(state->get_node_property_value(i,j),vars,_write_resources,this);

				f->store_string(_valprop(String(state->get_node_property_name(i,j)))+" = "+vars+"\n");
			}

			if (state->get_node_property_count(i)) {
				//add space
				f->store_line(String());
			}

		}

		for(int i=0;i<state->get_connection_count();i++) {

			String connstr="[connection";
			connstr+=" signal=\""+String(state->get_connection_signal(i))+"\"";
			connstr+=" from=\""+String(state->get_connection_source(i).simplified())+"\"";
			connstr+=" to=\""+String(state->get_connection_target(i).simplified())+"\"";
			connstr+=" method=\""+String(state->get_connection_method(i))+"\"";
			int flags = state->get_connection_flags(i);
			if (flags!=Object::CONNECT_PERSIST) {
				connstr+=" flags="+itos(flags);
			}

			Array binds=state->get_connection_binds(i);
			f->store_string(connstr);
			if (binds.size()) {
				String vars;
				VariantWriter::write_to_string(binds,vars,_write_resources,this);
				f->store_string(" binds= "+vars);

			}

			f->store_line("]\n");
		}

		f->store_line(String());

		Vector<NodePath> editable_instances = state->get_editable_instances();
		for(int i=0;i<editable_instances.size();i++) {
			f->store_line("[editable path=\""+editable_instances[i].operator String()+"\"]");
		}
	}

	if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
		f->close();
		return ERR_CANT_CREATE;
	}

	f->close();
	//memdelete(f);

	return OK;
}
예제 #7
0
Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {

	Error err;
	if (p_flags&ResourceSaver::FLAG_COMPRESS) {
		FileAccessCompressed *fac = memnew( FileAccessCompressed );
		fac->configure("RSCC");
		f=fac;
		err = fac->_open(p_path,FileAccess::WRITE);
		if (err)
			memdelete(f);

	} else {
		f=FileAccess::open(p_path,FileAccess::WRITE,&err);
	}


	ERR_FAIL_COND_V(err,err);
	FileAccessRef _fref(f);


	relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS;
	skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
	bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES;
	big_endian=p_flags&ResourceSaver::FLAG_SAVE_BIG_ENDIAN;
	takeover_paths=p_flags&ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;

	if (!p_path.begins_with("res://"))
		takeover_paths=false;

	local_path=p_path.get_base_dir();
	//bin_meta_idx = get_string_index("__bin_meta__"); //is often used, so create

	_find_resources(p_resource,true);

	if (!(p_flags&ResourceSaver::FLAG_COMPRESS)) {
		//save header compressed
		static const uint8_t header[4]={'R','S','R','C'};
		f->store_buffer(header,4);
	}

	if (big_endian) {
		f->store_32(1);
		f->set_endian_swap(true);
	} else
		f->store_32(0);

	f->store_32(0); //64 bits file, false for now
	f->store_32(VERSION_MAJOR);
	f->store_32(VERSION_MINOR);
	f->store_32(FORMAT_VERSION);

	if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
		f->close();
		return ERR_CANT_CREATE;
	}

	//f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed
	save_unicode_string(p_resource->get_type());
	uint64_t md_at = f->get_pos();
	f->store_64(0); //offset to impoty metadata
	for(int i=0;i<14;i++)
		f->store_32(0); // reserved


	List<ResourceData> resources;


	{


		for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {


			ResourceData &rd = resources.push_back(ResourceData())->get();
			rd.type=E->get()->get_type();

			List<PropertyInfo> property_list;
			E->get()->get_property_list( &property_list );

			for(List<PropertyInfo>::Element *F=property_list.front();F;F=F->next()) {

				if (skip_editor && F->get().name.begins_with("__editor"))
					continue;
				if (F->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && F->get().usage&PROPERTY_USAGE_BUNDLE)) {
					Property p;
					p.name_idx=get_string_index(F->get().name);
					p.value=E->get()->get(F->get().name);
					if (F->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && p.value.is_zero())
						continue;
					p.pi=F->get();										

					rd.properties.push_back(p);

				}
			}



		}
	}


	f->store_32(strings.size()); //string table size
	for(int i=0;i<strings.size();i++) {
		//print_bl("saving string: "+strings[i]);
		save_unicode_string(strings[i]);
	}

	// save external resource table
	f->store_32(external_resources.size()); //amount of external resources
	for(Set<RES>::Element *E=external_resources.front();E;E=E->next()) {

		save_unicode_string(E->get()->get_save_type());
		String path = E->get()->get_path();
		save_unicode_string(path);
	}
	// save internal resource table
	f->store_32(saved_resources.size()); //amount of internal resources
	Vector<uint64_t> ofs_pos;
	Set<int> used_indices;

	for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {

		RES r = E->get();
		if (r->get_path()=="" || r->get_path().find("::")!=-1) {

			if (r->get_subindex()!=0) {
				if (used_indices.has(r->get_subindex())) {
					r->set_subindex(0); //repeated
				} else {
					used_indices.insert(r->get_subindex());
				}
			}
		}

	}


	for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {


		RES r = E->get();
		if (r->get_path()=="" || r->get_path().find("::")!=-1) {
			if (r->get_subindex()==0) {
				int new_subindex=1;
				if (used_indices.size()) {
					new_subindex=used_indices.back()->get()+1;
				}

				r->set_subindex(new_subindex);
				used_indices.insert(new_subindex);

			}

			save_unicode_string("local://"+itos(r->get_subindex()));
			if (takeover_paths) {
				r->set_path(p_path+"::"+itos(ofs_pos.size()),true);
			}
		} else
			save_unicode_string(r->get_path()); //actual external
		ofs_pos.push_back(f->get_pos());
		f->store_64(0); //offset in 64 bits
	}

	Vector<uint64_t> ofs_table;
//	int saved_idx=0;
	//now actually save the resources

	for(List<ResourceData>::Element *E=resources.front();E;E=E->next()) {

		ResourceData & rd = E->get();

		ofs_table.push_back(f->get_pos());
		save_unicode_string(rd.type);
		f->store_32(rd.properties.size());

		for (List<Property>::Element *F=rd.properties.front();F;F=F->next()) {

			Property &p=F->get();
			f->store_32(p.name_idx);
			write_variant(p.value,F->get().pi);
		}

	}

	for(int i=0;i<ofs_table.size();i++) {
		f->seek(ofs_pos[i]);
		f->store_64(ofs_table[i]);
	}

	f->seek_end();
	print_line("SAVING: "+p_path);
	if (p_resource->get_import_metadata().is_valid()) {
		uint64_t md_pos = f->get_pos();
		Ref<ResourceImportMetadata> imd=p_resource->get_import_metadata();
		save_unicode_string(imd->get_editor());
		f->store_32(imd->get_source_count());
		for(int i=0;i<imd->get_source_count();i++) {
			save_unicode_string(imd->get_source_path(i));
			save_unicode_string(imd->get_source_md5(i));
			print_line("SAVE PATH: "+imd->get_source_path(i));
			print_line("SAVE MD5: "+imd->get_source_md5(i));
		}
		List<String> options;
		imd->get_options(&options);
		f->store_32(options.size());
		for(List<String>::Element *E=options.front();E;E=E->next()) {
			save_unicode_string(E->get());
			write_variant(imd->get_option(E->get()));
		}

		f->seek(md_at);
		f->store_64(md_pos);
		f->seek_end();
	}


	f->store_buffer((const uint8_t*)"RSRC",4); //magic at end

	if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
		f->close();
		return ERR_CANT_CREATE;
	}

	f->close();


	return OK;
}