void ResourcePreloaderEditor::_paste_pressed() {

	RES r = EditorSettings::get_singleton()->get_resource_clipboard();
	if (!r.is_valid()) {
		dialog->set_text(TTR("Resource clipboard is empty!"));
		dialog->set_title(TTR("Error!"));
		dialog->get_ok()->set_text(TTR("Close"));
		dialog->popup_centered_minsize();
		return; ///beh should show an error i guess
	}

	String name = r->get_name();
	if (name == "")
		name = r->get_path().get_file();
	if (name == "")
		name = r->get_class();

	String basename = name;
	int counter = 1;
	while (preloader->has_resource(name)) {
		counter++;
		name = basename + " " + itos(counter);
	}

	undo_redo->create_action(TTR("Paste Resource"));
	undo_redo->add_do_method(preloader, "add_resource", name, r);
	undo_redo->add_undo_method(preloader, "remove_resource", name);
	undo_redo->add_do_method(this, "_update_library");
	undo_redo->add_undo_method(this, "_update_library");
	undo_redo->commit_action();
}
Example #2
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;
}
void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {

	if (!can_drop_data_fw(p_point, p_data, p_from))
		return;

	Dictionary d = p_data;

	if (!d.has("type"))
		return;

	if (String(d["type"]) == "resource" && d.has("resource")) {
		RES r = d["resource"];

		if (r.is_valid()) {

			String basename;
			if (r->get_name() != "") {
				basename = r->get_name();
			} else if (r->get_path().is_resource_file()) {
				basename = r->get_path().get_basename();
			} else {
				basename = "Resource";
			}

			String name = basename;
			int counter = 0;
			while (preloader->has_resource(name)) {
				counter++;
				name = basename + "_" + itos(counter);
			}

			undo_redo->create_action(TTR("Add Resource"));
			undo_redo->add_do_method(preloader, "add_resource", name, r);
			undo_redo->add_undo_method(preloader, "remove_resource", name);
			undo_redo->add_do_method(this, "_update_library");
			undo_redo->add_undo_method(this, "_update_library");
			undo_redo->commit_action();
		}
	}

	if (String(d["type"]) == "files") {

		Vector<String> files = d["files"];

		_files_load_request(files);
	}
}
void ResourcePreloaderEditor::_update_library() {

	tree->clear();
	tree->set_hide_root(true);
	TreeItem *root = tree->create_item(NULL);

	List<StringName> rnames;
	preloader->get_resource_list(&rnames);

	List<String> names;
	for (List<StringName>::Element *E = rnames.front(); E; E = E->next()) {
		names.push_back(E->get());
	}

	names.sort();

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

		TreeItem *ti = tree->create_item(root);
		ti->set_cell_mode(0, TreeItem::CELL_MODE_STRING);
		ti->set_editable(0, true);
		ti->set_selectable(0, true);
		ti->set_text(0, E->get());
		ti->set_metadata(0, E->get());

		RES r = preloader->get_resource(E->get());

		ERR_CONTINUE(r.is_null());

		String type = r->get_class();
		ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(type, "Object"));
		ti->set_tooltip(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type);

		ti->set_text(1, r->get_path());
		ti->set_editable(1, false);
		ti->set_selectable(1, false);

		if (type == "PackedScene") {
			ti->add_button(1, get_icon("InstanceOptions", "EditorIcons"), BUTTON_OPEN_SCENE, false, TTR("Open in Editor"));
		} else {
			ti->add_button(1, get_icon("Load", "EditorIcons"), BUTTON_EDIT_RESOURCE, false, TTR("Open in Editor"));
		}
		ti->add_button(1, get_icon("Remove", "EditorIcons"), BUTTON_REMOVE, false, TTR("Remove"));
	}

	//player->add_resource("default",resource);
}
Example #5
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: {}
	}

}
Example #6
0
String ResourceFormatSaverTextInstance::_write_resource(const RES& res) {

	if (external_resources.has(res)) {

		return "ExtResource( "+itos(external_resources[res]+1)+" )";
	} else {

		if (internal_resources.has(res)) {
			return "SubResource( "+itos(internal_resources[res])+" )";
		} else 	if (res->get_path().length() && res->get_path().find("::")==-1) {

			//external resource
			String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
			return "Resource( \""+path+"\" )";
		} else {
			ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
			ERR_FAIL_V("null");
			//internal resource
		}
	}

	return "null";
}
void ResourcePreloaderEditor::_update_library() {

	tree->clear();
	tree->set_hide_root(true);
	TreeItem *root = tree->create_item(NULL);

	List<StringName> rnames;
	preloader->get_resource_list(&rnames);

	List<String> names;
	for(List<StringName>::Element *E=rnames.front();E;E=E->next()) {
		names.push_back(E->get());
	}

	names.sort();

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

		TreeItem *ti = tree->create_item(root);
		ti->set_cell_mode(0,TreeItem::CELL_MODE_STRING);
		ti->set_editable(0,true);
		ti->set_selectable(0,true);
		ti->set_text(0,E->get());
		ti->set_metadata(0,E->get());



		RES r = preloader->get_resource(E->get());

		ERR_CONTINUE(r.is_null());

		ti->set_tooltip(0,r->get_path());
		String type = r->get_type();
		ti->set_text(1,type);
		ti->set_selectable(1,false);

		if (has_icon(type,"EditorIcons"))
			ti->set_icon( 1, get_icon(type,"EditorIcons") );

	}

	//player->add_resource("default",resource);
}
void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) {

	Object *obj = ObjectDB::get_instance(p_id);
	if (!obj)
		return;

	typedef Pair<PropertyInfo, Variant> PropertyDesc;
	List<PropertyDesc> properties;

	if (ScriptInstance *si = obj->get_script_instance()) {
		if (!si->get_script().is_null()) {

			typedef Map<const Script *, Set<StringName> > ScriptMemberMap;
			typedef Map<const Script *, Map<StringName, Variant> > ScriptConstantsMap;

			ScriptMemberMap members;
			members[si->get_script().ptr()] = Set<StringName>();
			si->get_script()->get_members(&(members[si->get_script().ptr()]));

			ScriptConstantsMap constants;
			constants[si->get_script().ptr()] = Map<StringName, Variant>();
			si->get_script()->get_constants(&(constants[si->get_script().ptr()]));

			Ref<Script> base = si->get_script()->get_base_script();
			while (base.is_valid()) {

				members[base.ptr()] = Set<StringName>();
				base->get_members(&(members[base.ptr()]));

				constants[base.ptr()] = Map<StringName, Variant>();
				base->get_constants(&(constants[base.ptr()]));

				base = base->get_base_script();
			}

			for (ScriptMemberMap::Element *sm = members.front(); sm; sm = sm->next()) {
				for (Set<StringName>::Element *E = sm->get().front(); E; E = E->next()) {
					Variant m;
					if (si->get(E->get(), m)) {
						String script_path = sm->key() == si->get_script().ptr() ? "" : sm->key()->get_path().get_file() + "/";
						PropertyInfo pi(m.get_type(), "Members/" + script_path + E->get());
						properties.push_back(PropertyDesc(pi, m));
					}
				}
			}

			for (ScriptConstantsMap::Element *sc = constants.front(); sc; sc = sc->next()) {
				for (Map<StringName, Variant>::Element *E = sc->get().front(); E; E = E->next()) {
					String script_path = sc->key() == si->get_script().ptr() ? "" : sc->key()->get_path().get_file() + "/";
					if (E->value().get_type() == Variant::OBJECT) {
						Variant id = ((Object *)E->value())->get_instance_id();
						PropertyInfo pi(id.get_type(), "Constants/" + E->key(), PROPERTY_HINT_OBJECT_ID, "Object");
						properties.push_back(PropertyDesc(pi, id));
					} else {
						PropertyInfo pi(E->value().get_type(), "Constants/" + script_path + E->key());
						properties.push_back(PropertyDesc(pi, E->value()));
					}
				}
			}
		}
	}
	if (Node *node = Object::cast_to<Node>(obj)) {
		PropertyInfo pi(Variant::NODE_PATH, String("Node/path"));
		properties.push_front(PropertyDesc(pi, node->get_path()));
	} else if (Resource *res = Object::cast_to<Resource>(obj)) {
		if (Script *s = Object::cast_to<Script>(res)) {
			Map<StringName, Variant> constants;
			s->get_constants(&constants);
			for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
				if (E->value().get_type() == Variant::OBJECT) {
					Variant id = ((Object *)E->value())->get_instance_id();
					PropertyInfo pi(id.get_type(), "Constants/" + E->key(), PROPERTY_HINT_OBJECT_ID, "Object");
					properties.push_front(PropertyDesc(pi, E->value()));
				} else {
					PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key());
					properties.push_front(PropertyDesc(pi, E->value()));
				}
			}
		}
	}

	List<PropertyInfo> pinfo;
	obj->get_property_list(&pinfo, true);
	for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
		if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) {
			properties.push_back(PropertyDesc(E->get(), obj->get(E->get().name)));
		}
	}

	Array send_props;
	for (int i = 0; i < properties.size(); i++) {
		const PropertyInfo &pi = properties[i].first;
		Variant &var = properties[i].second;

		WeakRef *ref = Object::cast_to<WeakRef>(var);
		if (ref) {
			var = ref->get_ref();
		}

		RES res = var;

		Array prop;
		prop.push_back(pi.name);
		prop.push_back(pi.type);

		//only send information that can be sent..
		int len = 0; //test how big is this to encode
		encode_variant(var, NULL, len);
		if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size
			prop.push_back(PROPERTY_HINT_OBJECT_TOO_BIG);
			prop.push_back("");
			prop.push_back(pi.usage);
			prop.push_back(Variant());
		} else {
			prop.push_back(pi.hint);
			prop.push_back(pi.hint_string);
			prop.push_back(pi.usage);

			if (!res.is_null()) {
				var = res->get_path();
			}

			prop.push_back(var);
		}
		send_props.push_back(prop);
	}

	packet_peer_stream->put_var("message:inspect_object");
	packet_peer_stream->put_var(3);
	packet_peer_stream->put_var(p_id);
	packet_peer_stream->put_var(obj->get_class());
	packet_peer_stream->put_var(send_props);
}
Example #9
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;
}
Example #10
0
void ResourceFormatSaverTextInstance::_find_resources(const Variant& p_variant,bool p_main) {


	switch(p_variant.get_type()) {
		case Variant::OBJECT: {


			RES res = p_variant.operator RefPtr();

			if (res.is_null() || external_resources.has(res))
				return;

			if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
				int index = external_resources.size();
				external_resources[res]=index;
				return;
			}

			if (resource_set.has(res))
				return;

			List<PropertyInfo> property_list;

			res->get_property_list( &property_list );
			property_list.sort();

			List<PropertyInfo>::Element *I=property_list.front();

			while(I) {

				PropertyInfo pi=I->get();

				if (pi.usage&PROPERTY_USAGE_STORAGE || (bundle_resources && pi.usage&PROPERTY_USAGE_BUNDLE)) {

					Variant v=res->get(I->get().name);
					_find_resources(v);
				}

				I=I->next();
			}

			resource_set.insert( res ); //saved after, so the childs it needs are available when loaded
			saved_resources.push_back(res);

		} break;
		case Variant::ARRAY: {

			Array varray=p_variant;
			int len=varray.size();
			for(int i=0;i<len;i++) {

				Variant v=varray.get(i);
				_find_resources(v);
			}

		} break;
		case Variant::DICTIONARY: {

			Dictionary d=p_variant;
			List<Variant> keys;
			d.get_key_list(&keys);
			for(List<Variant>::Element *E=keys.front();E;E=E->next()) {

				Variant v = d[E->get()];
				_find_resources(v);
			}
		} break;
		default: {}
	}

}
Example #11
0
void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) {

	Object *obj = ObjectDB::get_instance(p_id);
	if (!obj)
		return;

	typedef Pair<PropertyInfo, Variant> PropertyDesc;
	List<PropertyDesc> properties;

	if (ScriptInstance *si = obj->get_script_instance()) {
		if (!si->get_script().is_null()) {

			Set<StringName> members;
			si->get_script()->get_members(&members);
			for (Set<StringName>::Element *E = members.front(); E; E = E->next()) {

				Variant m;
				if (si->get(E->get(), m)) {
					PropertyInfo pi(m.get_type(), String("Members/") + E->get());
					properties.push_back(PropertyDesc(pi, m));
				}
			}

			Map<StringName, Variant> constants;
			si->get_script()->get_constants(&constants);
			for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
				PropertyInfo pi(E->value().get_type(), (String("Constants/") + E->key()));
				properties.push_back(PropertyDesc(pi, E->value()));
			}
		}
	}
	if (Node *node = Object::cast_to<Node>(obj)) {
		PropertyInfo pi(Variant::NODE_PATH, String("Node/path"));
		properties.push_front(PropertyDesc(pi, node->get_path()));
	} else if (Resource *res = Object::cast_to<Resource>(obj)) {
		if (Script *s = Object::cast_to<Script>(res)) {
			Map<StringName, Variant> constants;
			s->get_constants(&constants);
			for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
				PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key());
				properties.push_front(PropertyDesc(pi, E->value()));
			}
		}
	}

	List<PropertyInfo> pinfo;
	obj->get_property_list(&pinfo, true);
	for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
		if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) {
			properties.push_back(PropertyDesc(E->get(), obj->get(E->get().name)));
		}
	}

	Array send_props;
	for (int i = 0; i < properties.size(); i++) {
		const PropertyInfo &pi = properties[i].first;
		Variant &var = properties[i].second;

		WeakRef *ref = Object::cast_to<WeakRef>(var);
		if (ref) {
			var = ref->get_ref();
		}

		RES res = var;

		Array prop;
		prop.push_back(pi.name);
		prop.push_back(pi.type);

		//only send information that can be sent..
		int len = 0; //test how big is this to encode
		encode_variant(var, NULL, len);
		if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size
			prop.push_back(PROPERTY_HINT_OBJECT_TOO_BIG);
			prop.push_back("");
			prop.push_back(pi.usage);
			prop.push_back(Variant());
		} else {
			prop.push_back(pi.hint);
			if (res.is_null())
				prop.push_back(pi.hint_string);
			else
				prop.push_back(String("RES:") + res->get_path());
			prop.push_back(pi.usage);
			prop.push_back(var);
		}
		send_props.push_back(prop);
	}

	packet_peer_stream->put_var("message:inspect_object");
	packet_peer_stream->put_var(3);
	packet_peer_stream->put_var(p_id);
	packet_peer_stream->put_var(obj->get_class());
	packet_peer_stream->put_var(send_props);
}
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;
	no_extensions=p_flags&ResourceSaver::FLAG_NO_EXTENSION;

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

	//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();
		if (no_extensions)
			path=path.basename()+".*";
		save_unicode_string(path);
	}
	// save internal resource table
	f->store_32(saved_resources.size()); //amount of internal resources
	Vector<uint64_t> ofs_pos;
	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)
			save_unicode_string("local://"+itos(ofs_pos.size()));
		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();
	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));
		}
		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

	f->close();


	return OK;
}
void ResourceFormatSaverBinaryInstance::_find_resources(const Variant& p_variant,bool p_main) {


	switch(p_variant.get_type()) {
		case Variant::OBJECT: {


			RES res = p_variant.operator RefPtr();

			if (res.is_null())
				return;

			if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
				external_resources.insert(res);
				return;
			}


			if (resource_map.has(res))
				return;

			List<PropertyInfo> property_list;

			res->get_property_list(&property_list);

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

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

					_find_resources(res->get(E->get().name));
				}
			}

			resource_map[ res ] = saved_resources.size();
			saved_resources.push_back(res);

		} break;

		case Variant::ARRAY: {

			Array varray=p_variant;
			int len=varray.size();
			for(int i=0;i<len;i++) {

				Variant v=varray.get(i);
				_find_resources(v);
			}

		} break;

		case Variant::DICTIONARY: {

			Dictionary d=p_variant;
			List<Variant> keys;
			d.get_key_list(&keys);
			for(List<Variant>::Element *E=keys.front();E;E=E->next()) {

				_find_resources(E->get());
				Variant v = d[E->get()];
				_find_resources(v);
			}
		} break;
		case Variant::NODE_PATH: {
			//take the chance and save node path strings
			NodePath np = p_variant;
			for(int i=0;i<np.get_name_count();i++)
				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: {}
	}

}
void ResourceFormatSaverBinaryInstance::write_variant(const Variant& p_property,const PropertyInfo& p_hint) {

	switch(p_property.get_type()) {

		case Variant::NIL: {

			f->store_32(VARIANT_NIL);
			// don't store anything
		} break;
		case Variant::BOOL: {

			f->store_32(VARIANT_BOOL);
			bool val=p_property;
			f->store_32(val);
		} break;
		case Variant::INT: {

			f->store_32(VARIANT_INT);
			int val=p_property;
			f->store_32(val);
		} break;
		case Variant::REAL: {

			f->store_32(VARIANT_REAL);
			real_t val=p_property;
			f->store_real(val);

		} break;
		case Variant::STRING: {

			f->store_32(VARIANT_STRING);
			String val=p_property;
			save_unicode_string(val);

		} break;
		case Variant::VECTOR2: {

			f->store_32(VARIANT_VECTOR2);
			Vector2 val=p_property;
			f->store_real(val.x);
			f->store_real(val.y);

		} break;
		case Variant::RECT2: {

			f->store_32(VARIANT_RECT2);
			Rect2 val=p_property;
			f->store_real(val.pos.x);
			f->store_real(val.pos.y);
			f->store_real(val.size.x);
			f->store_real(val.size.y);

		} break;
		case Variant::VECTOR3: {

			f->store_32(VARIANT_VECTOR3);
			Vector3 val=p_property;
			f->store_real(val.x);
			f->store_real(val.y);
			f->store_real(val.z);

		} break;
		case Variant::PLANE: {

			f->store_32(VARIANT_PLANE);
			Plane val=p_property;
			f->store_real(val.normal.x);
			f->store_real(val.normal.y);
			f->store_real(val.normal.z);
			f->store_real(val.d);

		} break;
		case Variant::QUAT: {

			f->store_32(VARIANT_QUAT);
			Quat val=p_property;
			f->store_real(val.x);
			f->store_real(val.y);
			f->store_real(val.z);
			f->store_real(val.w);

		} break;
		case Variant::_AABB: {

			f->store_32(VARIANT_AABB);
			AABB val=p_property;
			f->store_real(val.pos.x);
			f->store_real(val.pos.y);
			f->store_real(val.pos.z);
			f->store_real(val.size.x);
			f->store_real(val.size.y);
			f->store_real(val.size.z);

		} break;
		case Variant::MATRIX32: {

			f->store_32(VARIANT_MATRIX32);
			Matrix32 val=p_property;
			f->store_real(val.elements[0].x);
			f->store_real(val.elements[0].y);
			f->store_real(val.elements[1].x);
			f->store_real(val.elements[1].y);
			f->store_real(val.elements[2].x);
			f->store_real(val.elements[2].y);

		} break;
		case Variant::MATRIX3: {

			f->store_32(VARIANT_MATRIX3);
			Matrix3 val=p_property;
			f->store_real(val.elements[0].x);
			f->store_real(val.elements[0].y);
			f->store_real(val.elements[0].z);
			f->store_real(val.elements[1].x);
			f->store_real(val.elements[1].y);
			f->store_real(val.elements[1].z);
			f->store_real(val.elements[2].x);
			f->store_real(val.elements[2].y);
			f->store_real(val.elements[2].z);

		} break;
		case Variant::TRANSFORM: {

			f->store_32(VARIANT_TRANSFORM);
			Transform val=p_property;
			f->store_real(val.basis.elements[0].x);
			f->store_real(val.basis.elements[0].y);
			f->store_real(val.basis.elements[0].z);
			f->store_real(val.basis.elements[1].x);
			f->store_real(val.basis.elements[1].y);
			f->store_real(val.basis.elements[1].z);
			f->store_real(val.basis.elements[2].x);
			f->store_real(val.basis.elements[2].y);
			f->store_real(val.basis.elements[2].z);
			f->store_real(val.origin.x);
			f->store_real(val.origin.y);
			f->store_real(val.origin.z);

		} break;
		case Variant::COLOR: {

			f->store_32(VARIANT_COLOR);
			Color val=p_property;
			f->store_real(val.r);
			f->store_real(val.g);
			f->store_real(val.b);
			f->store_real(val.a);

		} break;
		case Variant::IMAGE: {

			f->store_32(VARIANT_IMAGE);
			Image val =p_property;
			if (val.empty()) {
				f->store_32(IMAGE_ENCODING_EMPTY);
				break;
			}

			int encoding=IMAGE_ENCODING_RAW;
			float quality=0.7;

			if (val.get_format() <= Image::FORMAT_INDEXED_ALPHA) {
				//can only compress uncompressed stuff

				if (p_hint.hint==PROPERTY_HINT_IMAGE_COMPRESS_LOSSY && Image::lossy_packer) {
					encoding=IMAGE_ENCODING_LOSSY;
					float qs=p_hint.hint_string.to_double();
					if (qs!=0.0)
						quality=qs;

				} else if (p_hint.hint==PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS && Image::lossless_packer) {
					encoding=IMAGE_ENCODING_LOSSLESS;

				}
			}

			f->store_32(encoding); //raw encoding

			if (encoding==IMAGE_ENCODING_RAW) {


				f->store_32(val.get_width());
				f->store_32(val.get_height());
				f->store_32(val.get_mipmaps());
				switch(val.get_format()) {

					case Image::FORMAT_GRAYSCALE: f->store_32(IMAGE_FORMAT_GRAYSCALE ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
					case Image::FORMAT_INTENSITY: f->store_32(IMAGE_FORMAT_INTENSITY ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
					case Image::FORMAT_GRAYSCALE_ALPHA: f->store_32(IMAGE_FORMAT_GRAYSCALE_ALPHA ); break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255
					case Image::FORMAT_RGB: f->store_32(IMAGE_FORMAT_RGB ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B
					case Image::FORMAT_RGBA: f->store_32(IMAGE_FORMAT_RGBA ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A
					case Image::FORMAT_INDEXED: f->store_32(IMAGE_FORMAT_INDEXED ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*3 bytes of palette
					case Image::FORMAT_INDEXED_ALPHA: f->store_32(IMAGE_FORMAT_INDEXED_ALPHA ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*4 bytes of palette (alpha)
					case Image::FORMAT_BC1: f->store_32(IMAGE_FORMAT_BC1 ); break; // DXT1
					case Image::FORMAT_BC2: f->store_32(IMAGE_FORMAT_BC2 ); break; // DXT3
					case Image::FORMAT_BC3: f->store_32(IMAGE_FORMAT_BC3 ); break; // DXT5
					case Image::FORMAT_BC4: f->store_32(IMAGE_FORMAT_BC4 ); break; // ATI1
					case Image::FORMAT_BC5: f->store_32(IMAGE_FORMAT_BC5 ); break; // ATI2
					case Image::FORMAT_PVRTC2: f->store_32(IMAGE_FORMAT_PVRTC2 ); break;
					case Image::FORMAT_PVRTC2_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC2_ALPHA ); break;
					case Image::FORMAT_PVRTC4: f->store_32(IMAGE_FORMAT_PVRTC4 ); break;
					case Image::FORMAT_PVRTC4_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC4_ALPHA ); break;
					case Image::FORMAT_ETC: f->store_32(IMAGE_FORMAT_ETC); break;
					case Image::FORMAT_CUSTOM: f->store_32(IMAGE_FORMAT_CUSTOM ); break;
					default: {}

				}

				int dlen = val.get_data().size();
				f->store_32(dlen);
				DVector<uint8_t>::Read r = val.get_data().read();
				f->store_buffer(r.ptr(),dlen);
				_pad_buffer(dlen);
			} else {

				DVector<uint8_t> data;
				if (encoding==IMAGE_ENCODING_LOSSY) {
					data=Image::lossy_packer(val,quality);

				} else if (encoding==IMAGE_ENCODING_LOSSLESS) {
					data=Image::lossless_packer(val);

				}

				int ds=data.size();
				f->store_32(ds);
				if (ds>0) {
					DVector<uint8_t>::Read r = data.read();
					f->store_buffer(r.ptr(),ds);

					_pad_buffer(ds);

				}
			}

		} break;
		case Variant::NODE_PATH: {
			f->store_32(VARIANT_NODE_PATH);
			NodePath np=p_property;
			f->store_16(np.get_name_count());
			uint16_t snc = np.get_subname_count();
			if (np.is_absolute())
				snc|=0x8000;
			f->store_16(snc);
			for(int i=0;i<np.get_name_count();i++)
				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: {

			f->store_32(VARIANT_RID);
			WARN_PRINT("Can't save RIDs");
			RID val = p_property;
			f->store_32(val.get_id());
		} break;
		case Variant::OBJECT: {

			f->store_32(VARIANT_OBJECT);
			RES res = p_property;
			if (res.is_null()) {
				f->store_32(OBJECT_EMPTY);
				return; // don't save it
			}

			if (res->get_path().length() && res->get_path().find("::")==-1) {
				f->store_32(OBJECT_EXTERNAL_RESOURCE);
				save_unicode_string(res->get_save_type());
				String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
				if (no_extensions)
					path=path.basename()+".*";
				save_unicode_string(path);
			} else {

				if (!resource_map.has(res)) {
					f->store_32(OBJECT_EMPTY);
					ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
					ERR_FAIL();
				}

				f->store_32(OBJECT_INTERNAL_RESOURCE);
				f->store_32(resource_map[res]);
				//internal resource
			}


		} break;
		case Variant::INPUT_EVENT: {

			f->store_32(VARIANT_INPUT_EVENT);
			WARN_PRINT("Can't save InputEvent (maybe it could..)");
		} break;
		case Variant::DICTIONARY: {

			f->store_32(VARIANT_DICTIONARY);
			Dictionary d = p_property;
            f->store_32(uint32_t(d.size())|(d.is_shared()?0x80000000:0));

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

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

				//if (!_check_type(dict[E->get()]))
				//	continue;

				write_variant(E->get());
				write_variant(d[E->get()]);
			}


		} break;
		case Variant::ARRAY: {

			f->store_32(VARIANT_ARRAY);
			Array a=p_property;
			f->store_32(uint32_t(a.size())|(a.is_shared()?0x80000000:0));
			for(int i=0;i<a.size();i++) {

				write_variant(a[i]);
			}

		} break;
		case Variant::RAW_ARRAY: {

			f->store_32(VARIANT_RAW_ARRAY);
			DVector<uint8_t> arr = p_property;
			int len=arr.size();
			f->store_32(len);
			DVector<uint8_t>::Read r = arr.read();
			f->store_buffer(r.ptr(),len);
			_pad_buffer(len);

		} break;
		case Variant::INT_ARRAY: {

			f->store_32(VARIANT_INT_ARRAY);
			DVector<int> arr = p_property;
			int len=arr.size();
			f->store_32(len);
			DVector<int>::Read r = arr.read();
			for(int i=0;i<len;i++)
				f->store_32(r[i]);

		} break;
		case Variant::REAL_ARRAY: {

			f->store_32(VARIANT_REAL_ARRAY);
			DVector<real_t> arr = p_property;
			int len=arr.size();
			f->store_32(len);
			DVector<real_t>::Read r = arr.read();
			for(int i=0;i<len;i++) {
				f->store_real(r[i]);
			}

		} break;
		case Variant::STRING_ARRAY: {

			f->store_32(VARIANT_STRING_ARRAY);
			DVector<String> arr = p_property;
			int len=arr.size();
			f->store_32(len);
			DVector<String>::Read r = arr.read();
			for(int i=0;i<len;i++) {
				save_unicode_string(r[i]);
			}

		} break;
		case Variant::VECTOR3_ARRAY: {

			f->store_32(VARIANT_VECTOR3_ARRAY);
			DVector<Vector3> arr = p_property;
			int len=arr.size();
			f->store_32(len);
			DVector<Vector3>::Read r = arr.read();
			for(int i=0;i<len;i++) {
				f->store_real(r[i].x);
				f->store_real(r[i].y);
				f->store_real(r[i].z);
			}

		} break;
		case Variant::VECTOR2_ARRAY: {

			f->store_32(VARIANT_VECTOR2_ARRAY);
			DVector<Vector2> arr = p_property;
			int len=arr.size();
			f->store_32(len);
			DVector<Vector2>::Read r = arr.read();
			for(int i=0;i<len;i++) {
				f->store_real(r[i].x);
				f->store_real(r[i].y);
			}

		} break;
		case Variant::COLOR_ARRAY: {

			f->store_32(VARIANT_COLOR_ARRAY);
			DVector<Color> arr = p_property;
			int len=arr.size();
			f->store_32(len);
			DVector<Color>::Read r = arr.read();
			for(int i=0;i<len;i++) {
				f->store_real(r[i].r);
				f->store_real(r[i].g);
				f->store_real(r[i].b);
				f->store_real(r[i].a);
			}

		} break;
		default: {

			ERR_EXPLAIN("Invalid variant");
			ERR_FAIL();
		}
	}
}
Example #15
0
Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from) {

	return generate_from_path(p_from->get_path());
}