Beispiel #1
0
Node *SceneState::instance(bool p_gen_edit_state) const {

	// nodes where instancing failed (because something is missing)
	List<Node*> stray_instances;

#define NODE_FROM_ID(p_name,p_id)\
	Node *p_name;\
	if (p_id&FLAG_ID_IS_PATH) {\
		NodePath np=node_paths[p_id&FLAG_MASK];\
		p_name=ret_nodes[0]->_get_node(np);\
	} else {\
		ERR_FAIL_INDEX_V(p_id&FLAG_MASK,nc,NULL);\
		p_name=ret_nodes[p_id&FLAG_MASK];\
	}

	int nc = nodes.size();
	ERR_FAIL_COND_V(nc==0,NULL);

	const StringName*snames=NULL;
	int sname_count=names.size();
	if (sname_count)
		snames=&names[0];

	const Variant*props=NULL;
	int prop_count=variants.size();
	if (prop_count)
		props=&variants[0];

	//Vector<Variant> properties;

	const NodeData *nd = &nodes[0];

	Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc );

	bool gen_node_path_cache=p_gen_edit_state && node_path_cache.empty();

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

		const NodeData &n=nd[i];

		Node *parent=NULL;

		if (i>0) {

			NODE_FROM_ID(nparent,n.parent);
#ifdef DEBUG_ENABLED
			if (!nparent && n.parent&FLAG_ID_IS_PATH) {

				WARN_PRINT(String("Parent path '"+String(node_paths[n.parent&FLAG_MASK])+"' for node '"+String(snames[n.name])+"' has vanished when instancing: '"+get_path()+"'.").ascii().get_data());

			}
#endif
			parent=nparent;
		}

		Node *node=NULL;


		if (i==0 && base_scene_idx>=0) {
			//scene inheritance on root node
            //print_line("scene inherit");
			Ref<PackedScene> sdata = props[ base_scene_idx ];
			ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
			node = sdata->instance(p_gen_edit_state);
			ERR_FAIL_COND_V(!node,NULL);
			if (p_gen_edit_state) {
				node->set_scene_inherited_state(sdata->get_state());
			}

		} else if (n.instance>=0) {
			//instance a scene into this node
            //print_line("instance");
			if (n.instance&FLAG_INSTANCE_IS_PLACEHOLDER) {

				String path = props[n.instance&FLAG_MASK];
				if (disable_placeholders) {

					Ref<PackedScene> sdata = ResourceLoader::load(path,"PackedScene");
					ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
					node = sdata->instance(p_gen_edit_state);
					ERR_FAIL_COND_V(!node,NULL);
				} else {
					InstancePlaceholder *ip = memnew( InstancePlaceholder );
					ip->set_instance_path(path);
					node=ip;
				}
				node->set_scene_instance_load_placeholder(true);
			} else {
				Ref<PackedScene> sdata = props[ n.instance&FLAG_MASK ];
				ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
				node = sdata->instance(p_gen_edit_state);
				ERR_FAIL_COND_V(!node,NULL);

			}

		} else if (n.type==TYPE_INSTANCED) {
			//print_line("instanced");
			//get the node from somewhere, it likely already exists from another instance
			if (parent) {
				node=parent->_get_child_by_name(snames[n.name]);
#ifdef DEBUG_ENABLED
				if (!node) {
					WARN_PRINT(String("Node '"+String(ret_nodes[0]->get_path_to(parent))+"/"+String(snames[n.name])+"' was modified from inside a instance, but it has vanished.").ascii().get_data());
				}
#endif
			}
		} else if (ObjectTypeDB::is_type_enabled(snames[n.type])) {
            //print_line("created");
			//node belongs to this scene and must be created
			Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
			if (!obj || !obj->cast_to<Node>()) {
				if (obj) {
					memdelete(obj);
					obj=NULL;
				}
				WARN_PRINT(String("Warning node of type "+snames[n.type].operator String()+" does not exist.").ascii().get_data());
				if (n.parent>=0 && n.parent<nc && ret_nodes[n.parent]) {
					if (ret_nodes[n.parent]->cast_to<Spatial>()) {
						obj = memnew( Spatial );
					} else if (ret_nodes[n.parent]->cast_to<Control>()) {
						obj = memnew( Control );
					} else if (ret_nodes[n.parent]->cast_to<Node2D>()) {
						obj = memnew( Node2D );
					}

				}
				if (!obj) {
					obj = memnew( Node );
				}
			}

			node = obj->cast_to<Node>();

		}


		if (node) {
			// may not have found the node (part of instanced scene and removed)
			// if found all is good, otherwise ignore

			//properties
			int nprop_count=n.properties.size();
			if (nprop_count) {

				const NodeData::Property* nprops=&n.properties[0];

				for(int j=0;j<nprop_count;j++) {

					bool valid;
					ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL );
					ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL );

					if (snames[ nprops[j].name ]==CoreStringNames::get_singleton()->_script) {
						//work around to avoid old script variables from disappearing, should be the proper fix to:
						//https://github.com/godotengine/godot/issues/2958

						//store old state
						List<Pair<StringName,Variant> > old_state;
						if (node->get_script_instance()) {
							node->get_script_instance()->get_property_state(old_state);
						}

						node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);

						//restore old state for new script, if exists
						for (List<Pair<StringName,Variant> >::Element *E=old_state.front();E;E=E->next()) {
							node->set(E->get().first,E->get().second);
						}
					} else {

						node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
					}
				}
			}

			//name

			//groups
			for(int j=0;j<n.groups.size();j++) {

				ERR_FAIL_INDEX_V( n.groups[j], sname_count, NULL );
				node->add_to_group( snames[ n.groups[j] ], true );
			}

			if (n.instance>=0 || n.type!=TYPE_INSTANCED || i==0) {
				//if node was not part of instance, must set it's name, parenthood and ownership
				if (i>0) {
					if (parent) {
						parent->_add_child_nocheck(node,snames[n.name]);
					} else {
						//it may be possible that an instanced scene has changed
						//and the node has nowhere to go anymore
						stray_instances.push_back(node); //can't be added, go to stray list
					}
				} else {
					node->_set_name_nocheck( snames[ n.name ] );
				}

			}

			if (n.owner>=0) {

				NODE_FROM_ID(owner,n.owner);
				if (owner)
					node->_set_owner_nocheck(owner);
			}


		}


		ret_nodes[i]=node;

		if (node && gen_node_path_cache && ret_nodes[0]) {
			NodePath n = ret_nodes[0]->get_path_to(node);
			node_path_cache[n]=i;
		}
	}


	//do connections

	int cc = connections.size();
	const ConnectionData *cdata = connections.ptr();

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

		const ConnectionData &c=cdata[i];
		//ERR_FAIL_INDEX_V( c.from, nc, NULL );
		//ERR_FAIL_INDEX_V( c.to, nc, NULL );

		NODE_FROM_ID(cfrom,c.from);
		NODE_FROM_ID(cto,c.to);

		if (!cfrom || !cto)
			continue;

		Vector<Variant> binds;
		if (c.binds.size()) {
			binds.resize(c.binds.size());
			for(int j=0;j<c.binds.size();j++)
				binds[j]=props[ c.binds[j] ];
		}


		cfrom->connect( snames[ c.signal], cto, snames[ c.method], binds,CONNECT_PERSIST|c.flags );
	}

	//Node *s = ret_nodes[0];

	//remove nodes that could not be added, likely as a result that
	while(stray_instances.size()) {
		memdelete(stray_instances.front()->get());
		stray_instances.pop_front();;
	}

	for(int i=0;i<editable_instances.size();i++) {
		Node *ei = ret_nodes[0]->_get_node(editable_instances[i]);
		if (ei) {
			ret_nodes[0]->set_editable_instance(ei,true);
		}
	}

	return ret_nodes[0];

}
Beispiel #2
0
Node *Node::duplicate(bool p_use_instancing) const {


	Node *node=NULL;

	bool instanced=false;

	if (cast_to<InstancePlaceholder>()) {

		const InstancePlaceholder *ip = cast_to<const InstancePlaceholder>();
		InstancePlaceholder *nip = memnew( InstancePlaceholder );
		nip->set_instance_path( ip->get_instance_path() );
		node=nip;

	} else if (p_use_instancing && get_filename()!=String()) {

		Ref<PackedScene> res = ResourceLoader::load(get_filename());
		ERR_FAIL_COND_V(res.is_null(),NULL);
		node=res->instance();
		ERR_FAIL_COND_V(!node,NULL);

		instanced=true;

	} else {

		Object *obj = ObjectTypeDB::instance(get_type());
		ERR_FAIL_COND_V(!obj,NULL);
		node = obj->cast_to<Node>();
		if (!node)
			memdelete(obj);
		ERR_FAIL_COND_V(!node,NULL);
	}


	if (get_filename()!="") { //an instance
		node->set_filename(get_filename());
	}

	List<PropertyInfo> plist;

	get_property_list(&plist);

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

		if (!(E->get().usage&PROPERTY_USAGE_STORAGE))
			continue;
		String name = E->get().name;
		node->set( name, get(name) );

	}

	node->set_name(get_name());

	List<GroupInfo> gi;
	get_groups(&gi);
	for (List<GroupInfo>::Element *E=gi.front();E;E=E->next()) {

		node->add_to_group(E->get().name, E->get().persistent);
	}

	_duplicate_signals(this, node);

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

		if (get_child(i)->data.parent_owned)
			continue;
		if (instanced && get_child(i)->data.owner==this)
			continue; //part of instance

		Node *dup = get_child(i)->duplicate(p_use_instancing);
		if (!dup) {

			memdelete(node);
			return NULL;
		}

		node->add_child(dup);
	}

	return node;
}