2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* packed_scene.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
2016-01-01 13:50:53 +00:00
/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
2014-02-10 01:10:30 +00:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2014-02-23 13:35:05 +00:00
# include "packed_scene.h"
# include "globals.h"
# include "io/resource_loader.h"
2014-10-07 04:31:49 +00:00
# include "scene/3d/spatial.h"
# include "scene/gui/control.h"
# include "scene/2d/node_2d.h"
2015-10-16 22:11:23 +00:00
# include "scene/main/instance_placeholder.h"
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
# define PACK_VERSION 2
bool SceneState : : can_instance ( ) const {
2014-02-23 13:35:05 +00:00
return nodes . size ( ) > 0 ;
}
2015-10-10 12:09:09 +00:00
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 ] ; \
}
2014-02-23 13:35:05 +00:00
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 ] ;
2015-06-29 03:29:49 +00:00
//Vector<Variant> properties;
2014-02-23 13:35:05 +00:00
const NodeData * nd = & nodes [ 0 ] ;
Node * * ret_nodes = ( Node * * ) alloca ( sizeof ( Node * ) * nc ) ;
2015-10-10 12:09:09 +00:00
bool gen_node_path_cache = p_gen_edit_state & & node_path_cache . empty ( ) ;
2014-02-23 13:35:05 +00:00
for ( int i = 0 ; i < nc ; i + + ) {
const NodeData & n = nd [ i ] ;
2015-10-10 12:09:09 +00:00
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 ;
2014-02-23 13:35:05 +00:00
}
Node * node = NULL ;
2015-10-10 12:09:09 +00:00
if ( i = = 0 & & base_scene_idx > = 0 ) {
//scene inheritance on root node
2015-10-17 18:48:42 +00:00
//print_line("scene inherit");
2015-10-10 12:09:09 +00:00
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
2015-10-17 18:48:42 +00:00
//print_line("instance");
2015-10-16 22:11:23 +00:00
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 ) ;
2015-11-13 23:56:44 +00:00
ip - > set_instance_path ( path ) ;
2015-10-16 22:11:23 +00:00
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 ) ;
}
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
} else if ( n . type = = TYPE_INSTANCED ) {
2015-10-16 22:11:23 +00:00
//print_line("instanced");
2015-10-10 12:09:09 +00:00
//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 ] ) ) {
2015-10-17 18:48:42 +00:00
//print_line("created");
2015-10-10 12:09:09 +00:00
//node belongs to this scene and must be created
2014-02-23 13:35:05 +00:00
Object * obj = ObjectTypeDB : : instance ( snames [ n . type ] ) ;
2014-10-07 04:31:49 +00:00
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 ) ;
}
}
2014-02-23 13:35:05 +00:00
2014-10-07 13:25:30 +00:00
node = obj - > cast_to < Node > ( ) ;
2014-02-23 13:35:05 +00:00
}
2015-10-10 12:09:09 +00:00
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 ) {
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
const NodeData : : Property * nprops = & n . properties [ 0 ] ;
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
for ( int j = 0 ; j < nprop_count ; j + + ) {
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
bool valid ;
ERR_FAIL_INDEX_V ( nprops [ j ] . name , sname_count , NULL ) ;
ERR_FAIL_INDEX_V ( nprops [ j ] . value , prop_count , NULL ) ;
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
node - > set ( snames [ nprops [ j ] . name ] , props [ nprops [ j ] . value ] , & valid ) ;
}
2014-02-23 13:35:05 +00:00
}
2015-10-10 12:09:09 +00:00
//name
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
//groups
for ( int j = 0 ; j < n . groups . size ( ) ; j + + ) {
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
ERR_FAIL_INDEX_V ( n . groups [ j ] , sname_count , NULL ) ;
node - > add_to_group ( snames [ n . groups [ j ] ] , true ) ;
}
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
if ( n . instance > = 0 | | n . type ! = TYPE_INSTANCED ) {
//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 ] ) ;
}
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
}
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
if ( n . owner > = 0 ) {
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
NODE_FROM_ID ( owner , n . owner ) ;
if ( owner )
node - > _set_owner_nocheck ( owner ) ;
}
2014-02-23 13:35:05 +00:00
}
2015-10-10 12:09:09 +00:00
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 ;
}
2014-02-23 13:35:05 +00:00
}
//do connections
int cc = connections . size ( ) ;
const ConnectionData * cdata = connections . ptr ( ) ;
for ( int i = 0 ; i < cc ; i + + ) {
const ConnectionData & c = cdata [ i ] ;
2015-10-10 12:09:09 +00:00
//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 ;
2014-02-23 13:35:05 +00:00
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 ] ] ;
}
2015-10-10 12:09:09 +00:00
cfrom - > connect ( snames [ c . signal ] , cto , snames [ c . method ] , binds , CONNECT_PERSIST | c . flags ) ;
2014-02-23 13:35:05 +00:00
}
2015-10-10 12:09:09 +00:00
//Node *s = ret_nodes[0];
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
//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 ) ;
}
}
2015-05-04 21:30:57 +00:00
2014-02-23 13:35:05 +00:00
return ret_nodes [ 0 ] ;
}
static int _nm_get_string ( const String & p_string , Map < StringName , int > & name_map ) {
if ( name_map . has ( p_string ) )
return name_map [ p_string ] ;
int idx = name_map . size ( ) ;
name_map [ p_string ] = idx ;
return idx ;
}
static int _vm_get_variant ( const Variant & p_variant , HashMap < Variant , int , VariantHasher > & variant_map ) {
if ( variant_map . has ( p_variant ) )
return variant_map [ p_variant ] ;
int idx = variant_map . size ( ) ;
variant_map [ p_variant ] = idx ;
return idx ;
}
2015-10-10 12:09:09 +00:00
Error SceneState : : _parse_node ( Node * p_owner , Node * p_node , int p_parent_idx , Map < StringName , int > & name_map , HashMap < Variant , int , VariantHasher > & variant_map , Map < Node * , int > & node_map , Map < Node * , int > & nodepath_map ) {
// this function handles all the work related to properly packing scenes, be it
// instanced or inherited.
// given the complexity of this process, an attempt will be made to properly
// document it. if you fail to understand something, please ask!
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
//discard nodes that do not belong to be processed
if ( p_node ! = p_owner & & p_node - > get_owner ( ) ! = p_owner & & ! p_owner - > is_editable_instance ( p_node - > get_owner ( ) ) )
return OK ;
// save the child instanced scenes that are chosen as editable, so they can be restored
// upon load back
if ( p_node ! = p_owner & & p_node - > get_filename ( ) ! = String ( ) & & p_owner - > is_editable_instance ( p_node ) )
editable_instances . push_back ( p_owner - > get_path_to ( p_node ) ) ;
2014-02-23 13:35:05 +00:00
NodeData nd ;
nd . name = _nm_get_string ( p_node - > get_name ( ) , name_map ) ;
2015-10-10 12:09:09 +00:00
nd . instance = - 1 ; //not instanced by default
// if this node is part of an instanced scene or sub-instanced scene
// we need to get the corresponding instance states.
// with the instance states, we can query for identical properties/groups
// and only save what has changed
List < PackState > pack_state_stack ;
bool instanced_by_owner = true ;
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
{
Node * n = p_node ;
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
while ( n ) {
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
if ( n = = p_owner ) {
Ref < SceneState > state = n - > get_scene_inherited_state ( ) ;
if ( state . is_valid ( ) ) {
int node = state - > find_node_by_path ( n - > get_path_to ( p_node ) ) ;
if ( node > = 0 ) {
//this one has state for this node, save
PackState ps ;
ps . node = node ;
ps . state = state ;
pack_state_stack . push_front ( ps ) ;
instanced_by_owner = false ;
}
}
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
if ( p_node - > get_filename ( ) ! = String ( ) & & p_node - > get_owner ( ) = = p_owner & & instanced_by_owner ) {
2015-10-16 22:11:23 +00:00
if ( p_node - > get_scene_instance_load_placeholder ( ) ) {
//it's a placeholder, use the placeholder path
nd . instance = _vm_get_variant ( p_node - > get_filename ( ) , variant_map ) ;
nd . instance | = FLAG_INSTANCE_IS_PLACEHOLDER ;
} else {
//must instance ourselves
Ref < PackedScene > instance = ResourceLoader : : load ( p_node - > get_filename ( ) ) ;
if ( ! instance . is_valid ( ) ) {
return ERR_CANT_OPEN ;
}
nd . instance = _vm_get_variant ( instance , variant_map ) ;
}
2015-10-10 12:09:09 +00:00
}
n = NULL ;
} else {
if ( n - > get_filename ( ) ! = String ( ) ) {
//is an instance
Ref < SceneState > state = n - > get_scene_instance_state ( ) ;
if ( state . is_valid ( ) ) {
int node = state - > find_node_by_path ( n - > get_path_to ( p_node ) ) ;
if ( node > = 0 ) {
//this one has state for this node, save
PackState ps ;
ps . node = node ;
ps . state = state ;
pack_state_stack . push_back ( ps ) ;
}
}
}
n = n - > get_owner ( ) ;
}
}
}
#if 0
Ref < SceneState > base_scene = p_node - > get_scene_inherited_state ( ) ; //for inheritance
Ref < SceneState > instance_state ;
int instance_state_node = - 1 ;
if ( base_scene . is_valid ( ) & & ( p_node = = p_owner | | p_node - > get_owner ( ) = = p_owner ) ) {
//scene inheritance in use, see if this node is actually inherited
NodePath path = p_owner - > get_path_to ( p_node ) ;
instance_state_node = base_scene - > find_node_by_path ( path ) ;
if ( instance_state_node > = 0 ) {
instance_state = base_scene ;
}
}
// check that this is a directly instanced scene from the scene being packed, if so
// this information must be saved. Of course, if using scene instancing and this node
// does belong to base scene, ignore.
if ( instance_state . is_null ( ) & & p_node ! = p_owner & & p_node - > get_owner ( ) = = p_owner & & p_node - > get_filename ( ) ! = " " ) {
//instanced, only direct sub-scnes are supported of course
2014-02-23 13:35:05 +00:00
Ref < PackedScene > instance = ResourceLoader : : load ( p_node - > get_filename ( ) ) ;
if ( ! instance . is_valid ( ) ) {
return ERR_CANT_OPEN ;
}
nd . instance = _vm_get_variant ( instance , variant_map ) ;
2015-10-10 12:09:09 +00:00
2014-02-23 13:35:05 +00:00
} else {
nd . instance = - 1 ;
}
2015-10-10 12:09:09 +00:00
// finally, if this does not belong to scene inheritance, check
// if it belongs to scene instancing
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
if ( instance_state . is_null ( ) & & p_node ! = p_owner ) {
//if not affected by scene inheritance, this may be
if ( p_node - > get_owner ( ) = = p_owner & & p_node - > get_filename ( ) ! = String ( ) ) {
instance_state = p_node - > get_scene_instance_state ( ) ;
if ( instance_state . is_valid ( ) ) {
instance_state_node = instance_state - > find_node_by_path ( p_node - > get_path_to ( p_node ) ) ;
}
} else if ( p_node - > get_owner ( ) ! = p_owner & & p_owner - > is_editable_instance ( p_node - > get_owner ( ) ) ) {
instance_state = p_node - > get_owner ( ) - > get_scene_instance_state ( ) ;
if ( instance_state . is_valid ( ) ) {
instance_state_node = instance_state - > find_node_by_path ( p_node - > get_owner ( ) - > get_path_to ( p_node ) ) ;
}
}
}
# endif
int subscene_prop_search_from = 0 ;
// all setup, we then proceed to check all properties for the node
// and save the ones that are worth saving
2014-02-23 13:35:05 +00:00
List < PropertyInfo > plist ;
p_node - > get_property_list ( & plist ) ;
2015-10-10 12:09:09 +00:00
2014-02-23 13:35:05 +00:00
for ( List < PropertyInfo > : : Element * E = plist . front ( ) ; E ; E = E - > next ( ) ) {
2014-10-03 03:10:51 +00:00
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) ) {
2014-02-23 13:35:05 +00:00
continue ;
2014-10-03 03:10:51 +00:00
}
2014-02-23 13:35:05 +00:00
String name = E - > get ( ) . name ;
Variant value = p_node - > get ( E - > get ( ) . name ) ;
2015-10-10 12:09:09 +00:00
bool isdefault = ( ( E - > get ( ) . usage & PROPERTY_USAGE_STORE_IF_NONZERO ) & & value . is_zero ( ) ) | | ( ( E - > get ( ) . usage & PROPERTY_USAGE_STORE_IF_NONONE ) & & value . is_one ( ) ) ;
// if (nd.instance<0 && ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one())) {
// continue;
// }
2014-02-23 13:35:05 +00:00
2014-10-03 03:10:51 +00:00
2015-10-10 12:09:09 +00:00
//print_line("PASSED!");
//print_line("at: "+String(p_node->get_name())+"::"+name+": - nz: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO)+" no: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONONE));
//print_line("value: "+String(value)+" is zero: "+itos(value.is_zero())+" is one" +itos(value.is_one()));
if ( pack_state_stack . size ( ) ) {
// we are on part of an instanced subscene
// or part of instanced scene.
// only save what has been changed
// only save changed properties in instance
if ( E - > get ( ) . usage & PROPERTY_USAGE_NO_INSTANCE_STATE | | E - > get ( ) . name = = " __meta__ " ) {
//property has requested that no instance state is saved, sorry
//also, meta won't be overriden or saved
2014-02-23 13:35:05 +00:00
continue ;
2015-10-10 12:09:09 +00:00
}
bool exists = false ;
Variant original ;
for ( List < PackState > : : Element * F = pack_state_stack . back ( ) ; F ; F = F - > prev ( ) ) {
//check all levels of pack to see if the property exists somewhere
const PackState & ps = F - > get ( ) ;
original = ps . state - > get_property_value ( ps . node , E - > get ( ) . name , exists ) ;
if ( exists ) {
break ;
}
}
2015-12-12 19:46:25 +00:00
if ( exists & & p_node - > get_script_instance ( ) ) {
//if this is an overriden value by another script, save it anyway
//as the script change will erase it
//https://github.com/godotengine/godot/issues/2958
bool valid = false ;
p_node - > get_script_instance ( ) - > get_property_type ( name , & valid ) ;
if ( valid ) {
exists = false ;
isdefault = false ;
}
}
2014-10-03 03:10:51 +00:00
2015-10-10 12:09:09 +00:00
if ( exists & & bool ( Variant : : evaluate ( Variant : : OP_EQUAL , value , original ) ) ) {
//exists and did not change
2014-11-02 14:31:01 +00:00
continue ;
}
2015-10-10 12:09:09 +00:00
if ( ! exists & & isdefault ) {
//does not exist in original node, but it's the default value
//so safe to skip too.
2014-02-23 13:35:05 +00:00
continue ;
2014-10-03 03:10:51 +00:00
}
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
} else {
if ( isdefault ) {
//it's the default value, no point in saving it
continue ;
}
2014-02-23 13:35:05 +00:00
}
NodeData : : Property prop ;
prop . name = _nm_get_string ( name , name_map ) ;
prop . value = _vm_get_variant ( value , variant_map ) ;
nd . properties . push_back ( prop ) ;
}
2015-10-10 12:09:09 +00:00
// save the groups this node is into
// discard groups that come from the original scene
2014-02-23 13:35:05 +00:00
List < Node : : GroupInfo > groups ;
p_node - > get_groups ( & groups ) ;
for ( List < Node : : GroupInfo > : : Element * E = groups . front ( ) ; E ; E = E - > next ( ) ) {
Node : : GroupInfo & gi = E - > get ( ) ;
if ( ! gi . persistent )
continue ;
2015-10-10 12:09:09 +00:00
// if (instance_state_node>=0 && instance_state->is_node_in_group(instance_state_node,gi.name))
// continue; //group was instanced, don't add here
bool skip = false ;
for ( List < PackState > : : Element * F = pack_state_stack . front ( ) ; F ; F = F - > next ( ) ) {
//check all levels of pack to see if the group was added somewhere
const PackState & ps = F - > get ( ) ;
if ( ps . state - > is_node_in_group ( ps . node , gi . name ) ) {
skip = true ;
break ;
}
}
if ( skip )
continue ;
2014-02-23 13:35:05 +00:00
nd . groups . push_back ( _nm_get_string ( gi . name , name_map ) ) ;
}
2015-10-10 12:09:09 +00:00
// save the right owner
// for the saved scene root this is -1
// for nodes of the saved scene this is 0
// for nodes of instanced scenes this is >0
if ( p_node = = p_owner ) {
//saved scene root
nd . owner = - 1 ;
} else if ( p_node - > get_owner ( ) = = p_owner ) {
//part of saved scene
nd . owner = 0 ;
} else {
2014-02-23 13:35:05 +00:00
nd . owner = - 1 ;
2015-10-10 12:09:09 +00:00
#if 0
// this is pointless, if this was instanced by something else,
// the owner will already be set.
if ( node_map . has ( p_node - > get_owner ( ) ) ) {
//maybe an existing saved node
nd . owner = node_map [ p_node - > get_owner ( ) ] ;
} else {
//not saved, use nodepath map
int sidx ;
if ( nodepath_map . has ( p_node - > get_owner ( ) ) ) {
sidx = nodepath_map [ p_node - > get_owner ( ) ] ;
} else {
sidx = nodepath_map . size ( ) ;
nodepath_map [ p_node - > get_owner ( ) ] = sidx ;
}
nd . owner = FLAG_ID_IS_PATH | sidx ;
}
# endif
}
// Save the right type. If this node was created by an instance
// then flag that the node should not be created but reused
if ( pack_state_stack . empty ( ) ) {
//this node is not part of an instancing process, so save the type
nd . type = _nm_get_string ( p_node - > get_type ( ) , name_map ) ;
} else {
// this node is part of an instanced process, so do not save the type.
// instead, save that it was instanced
nd . type = TYPE_INSTANCED ;
}
// determine whether to save this node or not
// if this node is part of an instanced sub-scene, we can skip storing it if basically
// no properties changed and no groups were added to it.
// below condition is true for all nodes of the scene being saved, and ones in subscenes
// that hold changes
bool save_node = nd . properties . size ( ) | | nd . groups . size ( ) ; // some local properties or groups exist
save_node = save_node | | p_node = = p_owner ; // owner is always saved
save_node = save_node | | ( p_node - > get_owner ( ) = = p_owner & & instanced_by_owner ) ; //part of scene and not instanced
2014-02-23 13:35:05 +00:00
int idx = nodes . size ( ) ;
2015-10-10 12:09:09 +00:00
int parent_node = NO_PARENT_SAVED ;
if ( save_node ) {
//don't save the node if nothing and subscene
node_map [ p_node ] = idx ;
//ok validate parent node
if ( p_parent_idx = = NO_PARENT_SAVED ) {
int sidx ;
if ( nodepath_map . has ( p_node - > get_parent ( ) ) ) {
sidx = nodepath_map [ p_node - > get_parent ( ) ] ;
} else {
sidx = nodepath_map . size ( ) ;
nodepath_map [ p_node - > get_parent ( ) ] = sidx ;
}
nd . parent = FLAG_ID_IS_PATH | sidx ;
} else {
nd . parent = p_parent_idx ;
}
parent_node = idx ;
nodes . push_back ( nd ) ;
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
}
2014-02-23 13:35:05 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
Node * c = p_node - > get_child ( i ) ;
2015-10-10 12:09:09 +00:00
Error err = _parse_node ( p_owner , c , parent_node , name_map , variant_map , node_map , nodepath_map ) ;
2014-02-23 13:35:05 +00:00
if ( err )
return err ;
}
return OK ;
}
2015-10-10 12:09:09 +00:00
Error SceneState : : _parse_connections ( Node * p_owner , Node * p_node , Map < StringName , int > & name_map , HashMap < Variant , int , VariantHasher > & variant_map , Map < Node * , int > & node_map , Map < Node * , int > & nodepath_map ) {
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
if ( p_node ! = p_owner & & p_node - > get_owner ( ) & & p_node - > get_owner ( ) ! = p_owner & & ! p_owner - > is_editable_instance ( p_node - > get_owner ( ) ) )
return OK ;
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
List < MethodInfo > _signals ;
p_node - > get_signal_list ( & _signals ) ;
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
//ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG);
//NodeData &nd = nodes[node_map[p_node]];
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
for ( List < MethodInfo > : : Element * E = _signals . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-23 13:35:05 +00:00
List < Node : : Connection > conns ;
p_node - > get_signal_connection_list ( E - > get ( ) . name , & conns ) ;
for ( List < Node : : Connection > : : Element * F = conns . front ( ) ; F ; F = F - > next ( ) ) {
const Node : : Connection & c = F - > get ( ) ;
2015-10-10 12:09:09 +00:00
if ( ! ( c . flags & CONNECT_PERSIST ) ) //only persistent connections get saved
2014-02-23 13:35:05 +00:00
continue ;
2015-10-10 12:09:09 +00:00
// only connections that originate or end into main saved scene are saved
// everything else is discarded
2014-02-23 13:35:05 +00:00
Node * n = c . target - > cast_to < Node > ( ) ;
2015-10-10 12:09:09 +00:00
if ( ! n ) {
2014-02-23 13:35:05 +00:00
continue ;
2015-10-10 12:09:09 +00:00
}
//source node is outside saved scene?
bool src_is_out = p_node ! = p_owner & & ( p_node - > get_filename ( ) ! = String ( ) | | p_node - > get_owner ( ) ! = p_owner ) ;
//target node is outside saved scene?
bool dst_is_out = n ! = p_owner & & ( n - > get_filename ( ) ! = String ( ) | | n - > get_owner ( ) ! = p_owner ) ;
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
//if both are out, ignore connection
if ( src_is_out & & dst_is_out ) {
2014-02-23 13:35:05 +00:00
continue ;
}
2015-10-10 12:09:09 +00:00
{
Node * nl = p_node ;
bool exists = false ;
while ( nl ) {
if ( nl = = p_owner ) {
Ref < SceneState > state = nl - > get_scene_inherited_state ( ) ;
if ( state . is_valid ( ) ) {
int from_node = state - > find_node_by_path ( nl - > get_path_to ( p_node ) ) ;
int to_node = state - > find_node_by_path ( nl - > get_path_to ( n ) ) ;
if ( from_node > = 0 & & to_node > = 0 ) {
//this one has state for this node, save
if ( state - > is_connection ( from_node , c . signal , to_node , c . method ) ) {
exists = true ;
break ;
}
}
}
nl = NULL ;
} else {
if ( nl - > get_filename ( ) ! = String ( ) ) {
//is an instance
Ref < SceneState > state = nl - > get_scene_instance_state ( ) ;
if ( state . is_valid ( ) ) {
int from_node = state - > find_node_by_path ( nl - > get_path_to ( p_node ) ) ;
int to_node = state - > find_node_by_path ( nl - > get_path_to ( n ) ) ;
if ( from_node > = 0 & & to_node > = 0 ) {
//this one has state for this node, save
if ( state - > is_connection ( from_node , c . signal , to_node , c . method ) ) {
exists = true ;
break ;
}
}
}
}
nl = nl - > get_owner ( ) ;
}
}
if ( exists ) {
continue ;
}
}
int src_id ;
if ( node_map . has ( p_node ) ) {
src_id = node_map [ p_node ] ;
} else {
if ( nodepath_map . has ( p_node ) ) {
src_id = FLAG_ID_IS_PATH | nodepath_map [ p_node ] ;
} else {
int sidx = nodepath_map . size ( ) ;
nodepath_map [ p_node ] = sidx ;
src_id = FLAG_ID_IS_PATH | sidx ;
}
}
int target_id ;
if ( node_map . has ( n ) ) {
target_id = node_map [ n ] ;
} else {
if ( nodepath_map . has ( n ) ) {
target_id = FLAG_ID_IS_PATH | nodepath_map [ n ] ;
} else {
int sidx = nodepath_map . size ( ) ;
nodepath_map [ n ] = sidx ;
target_id = FLAG_ID_IS_PATH | sidx ;
}
}
2014-02-23 13:35:05 +00:00
ConnectionData cd ;
2015-10-10 12:09:09 +00:00
cd . from = src_id ;
cd . to = target_id ;
2014-02-23 13:35:05 +00:00
cd . method = _nm_get_string ( c . method , name_map ) ;
cd . signal = _nm_get_string ( c . signal , name_map ) ;
cd . flags = c . flags ;
for ( int i = 0 ; i < c . binds . size ( ) ; i + + ) {
cd . binds . push_back ( _vm_get_variant ( c . binds [ i ] , variant_map ) ) ;
}
connections . push_back ( cd ) ;
}
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
Node * c = p_node - > get_child ( i ) ;
2015-10-10 12:09:09 +00:00
Error err = _parse_connections ( p_owner , c , name_map , variant_map , node_map , nodepath_map ) ;
2014-02-23 13:35:05 +00:00
if ( err )
return err ;
}
return OK ;
}
2015-10-10 12:09:09 +00:00
Error SceneState : : pack ( Node * p_scene ) {
2014-02-23 13:35:05 +00:00
ERR_FAIL_NULL_V ( p_scene , ERR_INVALID_PARAMETER ) ;
clear ( ) ;
Node * scene = p_scene ;
Map < StringName , int > name_map ;
HashMap < Variant , int , VariantHasher > variant_map ;
Map < Node * , int > node_map ;
2015-10-10 12:09:09 +00:00
Map < Node * , int > nodepath_map ;
//if using scene inheritance, pack the scene it inherits from
if ( scene - > get_scene_inherited_state ( ) . is_valid ( ) ) {
String path = scene - > get_scene_inherited_state ( ) - > get_path ( ) ;
Ref < PackedScene > instance = ResourceLoader : : load ( path ) ;
if ( instance . is_valid ( ) ) {
base_scene_idx = _vm_get_variant ( instance , variant_map ) ;
}
}
//instanced, only direct sub-scnes are supported of course
2014-02-23 13:35:05 +00:00
2015-10-10 12:09:09 +00:00
Error err = _parse_node ( scene , scene , - 1 , name_map , variant_map , node_map , nodepath_map ) ;
2014-02-23 13:35:05 +00:00
if ( err ) {
clear ( ) ;
ERR_FAIL_V ( err ) ;
}
2015-10-10 12:09:09 +00:00
err = _parse_connections ( scene , scene , name_map , variant_map , node_map , nodepath_map ) ;
2014-02-23 13:35:05 +00:00
if ( err ) {
clear ( ) ;
ERR_FAIL_V ( err ) ;
}
names . resize ( name_map . size ( ) ) ;
for ( Map < StringName , int > : : Element * E = name_map . front ( ) ; E ; E = E - > next ( ) ) {
names [ E - > get ( ) ] = E - > key ( ) ;
}
variants . resize ( variant_map . size ( ) ) ;
const Variant * K = NULL ;
while ( ( K = variant_map . next ( K ) ) ) {
int idx = variant_map [ * K ] ;
variants [ idx ] = * K ;
}
2015-10-10 12:09:09 +00:00
node_paths . resize ( nodepath_map . size ( ) ) ;
for ( Map < Node * , int > : : Element * E = nodepath_map . front ( ) ; E ; E = E - > next ( ) ) {
node_paths [ E - > get ( ) ] = scene - > get_path_to ( E - > key ( ) ) ;
}
2014-02-23 13:35:05 +00:00
return OK ;
}
2015-10-10 12:09:09 +00:00
void SceneState : : set_path ( const String & p_path ) {
path = p_path ;
}
String SceneState : : get_path ( ) const {
return path ;
}
void SceneState : : clear ( ) {
2014-02-23 13:35:05 +00:00
names . clear ( ) ;
variants . clear ( ) ;
nodes . clear ( ) ;
connections . clear ( ) ;
2015-10-10 12:09:09 +00:00
node_path_cache . clear ( ) ;
node_paths . clear ( ) ;
editable_instances . clear ( ) ;
base_scene_idx = - 1 ;
2014-02-23 13:35:05 +00:00
}
2015-10-10 12:09:09 +00:00
Ref < SceneState > SceneState : : _get_base_scene_state ( ) const {
if ( base_scene_idx > = 0 ) {
Ref < PackedScene > ps = variants [ base_scene_idx ] ;
if ( ps . is_valid ( ) ) {
return ps - > get_state ( ) ;
}
}
return Ref < SceneState > ( ) ;
}
int SceneState : : find_node_by_path ( const NodePath & p_node ) const {
if ( ! node_path_cache . has ( p_node ) ) {
if ( _get_base_scene_state ( ) . is_valid ( ) ) {
int idx = _get_base_scene_state ( ) - > find_node_by_path ( p_node ) ;
if ( idx > = 0 ) {
if ( ! base_scene_node_remap . has ( idx ) ) {
int ridx = nodes . size ( ) + base_scene_node_remap . size ( ) ;
base_scene_node_remap [ ridx ] = idx ;
}
return base_scene_node_remap [ idx ] ;
}
}
return - 1 ;
}
int nid = node_path_cache [ p_node ] ;
if ( _get_base_scene_state ( ) . is_valid ( ) & & ! base_scene_node_remap . has ( nid ) ) {
//for nodes that _do_ exist in current scene, still try to look for
//the node in the instanced scene, as a property may be missing
//from the local one
int idx = _get_base_scene_state ( ) - > find_node_by_path ( p_node ) ;
base_scene_node_remap [ nid ] = idx ;
}
return nid ;
}
Variant SceneState : : get_property_value ( int p_node , const StringName & p_property , bool & found ) const {
found = false ;
ERR_FAIL_COND_V ( p_node < 0 , Variant ( ) ) ;
if ( p_node < nodes . size ( ) ) {
//find in built-in nodes
int pc = nodes [ p_node ] . properties . size ( ) ;
const StringName * namep = names . ptr ( ) ;
const NodeData : : Property * p = nodes [ p_node ] . properties . ptr ( ) ;
for ( int i = 0 ; i < pc ; i + + ) {
if ( p_property = = namep [ p [ i ] . name ] ) {
found = true ;
return variants [ p [ i ] . value ] ;
}
}
}
//property not found, try on instance
if ( base_scene_node_remap . has ( p_node ) ) {
return _get_base_scene_state ( ) - > get_property_value ( base_scene_node_remap [ p_node ] , p_property , found ) ;
}
return Variant ( ) ;
}
bool SceneState : : is_node_in_group ( int p_node , const StringName & p_group ) const {
ERR_FAIL_COND_V ( p_node < 0 , false ) ;
if ( p_node < nodes . size ( ) ) {
const StringName * namep = names . ptr ( ) ;
for ( int i = 0 ; i < nodes [ p_node ] . groups . size ( ) ; i + + ) {
if ( namep [ nodes [ p_node ] . groups [ i ] ] = = p_group )
return true ;
}
}
if ( base_scene_node_remap . has ( p_node ) ) {
return _get_base_scene_state ( ) - > is_node_in_group ( base_scene_node_remap [ p_node ] , p_group ) ;
}
return false ;
}
2015-10-16 22:11:23 +00:00
bool SceneState : : disable_placeholders = false ;
void SceneState : : set_disable_placeholders ( bool p_disable ) {
disable_placeholders = p_disable ;
}
2015-10-10 12:09:09 +00:00
bool SceneState : : is_connection ( int p_node , const StringName & p_signal , int p_to_node , const StringName & p_to_method ) const {
ERR_FAIL_COND_V ( p_node < 0 , false ) ;
ERR_FAIL_COND_V ( p_to_node < 0 , false ) ;
if ( p_node < nodes . size ( ) & & p_to_node < nodes . size ( ) ) {
int signal_idx = - 1 ;
int method_idx = - 1 ;
for ( int i = 0 ; i < names . size ( ) ; i + + ) {
if ( names [ i ] = = p_signal ) {
signal_idx = i ;
} else if ( names [ i ] = = p_to_method ) {
method_idx = i ;
}
}
if ( signal_idx > = 0 & & method_idx > = 0 ) {
//signal and method strings are stored..
for ( int i = 0 ; i < connections . size ( ) ; i + + ) {
if ( connections [ i ] . from = = p_node & & connections [ i ] . to = = p_to_node & & connections [ i ] . signal = = signal_idx & & connections [ i ] . method = = method_idx ) {
return true ;
}
}
}
}
if ( base_scene_node_remap . has ( p_node ) & & base_scene_node_remap . has ( p_to_node ) ) {
return _get_base_scene_state ( ) - > is_connection ( base_scene_node_remap [ p_node ] , p_signal , base_scene_node_remap [ p_to_node ] , p_to_method ) ;
}
return false ;
}
void SceneState : : set_bundled_scene ( const Dictionary & d ) {
2014-02-23 13:35:05 +00:00
ERR_FAIL_COND ( ! d . has ( " names " ) ) ;
ERR_FAIL_COND ( ! d . has ( " variants " ) ) ;
ERR_FAIL_COND ( ! d . has ( " node_count " ) ) ;
ERR_FAIL_COND ( ! d . has ( " nodes " ) ) ;
ERR_FAIL_COND ( ! d . has ( " conn_count " ) ) ;
ERR_FAIL_COND ( ! d . has ( " conns " ) ) ;
// ERR_FAIL_COND( !d.has("path"));
2015-10-10 12:09:09 +00:00
int version = 1 ;
if ( d . has ( " version " ) )
version = d [ " version " ] ;
if ( version > PACK_VERSION ) {
ERR_EXPLAIN ( " Save format version too new! " ) ;
ERR_FAIL ( ) ;
}
2014-02-23 13:35:05 +00:00
DVector < String > snames = d [ " names " ] ;
if ( snames . size ( ) ) {
int namecount = snames . size ( ) ;
names . resize ( namecount ) ;
DVector < String > : : Read r = snames . read ( ) ;
for ( int i = 0 ; i < names . size ( ) ; i + + )
names [ i ] = r [ i ] ;
}
Array svariants = d [ " variants " ] ;
if ( svariants . size ( ) ) {
int varcount = svariants . size ( ) ;
variants . resize ( varcount ) ;
for ( int i = 0 ; i < varcount ; i + + ) {
variants [ i ] = svariants [ i ] ;
}
} else {
variants . clear ( ) ;
}
nodes . resize ( d [ " node_count " ] ) ;
int nc = nodes . size ( ) ;
if ( nc ) {
DVector < int > snodes = d [ " nodes " ] ;
DVector < int > : : Read r = snodes . read ( ) ;
int idx = 0 ;
for ( int i = 0 ; i < nc ; i + + ) {
NodeData & nd = nodes [ i ] ;
nd . parent = r [ idx + + ] ;
nd . owner = r [ idx + + ] ;
nd . type = r [ idx + + ] ;
nd . name = r [ idx + + ] ;
nd . instance = r [ idx + + ] ;
nd . properties . resize ( r [ idx + + ] ) ;
for ( int j = 0 ; j < nd . properties . size ( ) ; j + + ) {
nd . properties [ j ] . name = r [ idx + + ] ;
nd . properties [ j ] . value = r [ idx + + ] ;
}
nd . groups . resize ( r [ idx + + ] ) ;
for ( int j = 0 ; j < nd . groups . size ( ) ; j + + ) {
nd . groups [ j ] = r [ idx + + ] ;
}
}
}
connections . resize ( d [ " conn_count " ] ) ;
int cc = connections . size ( ) ;
if ( cc ) {
DVector < int > sconns = d [ " conns " ] ;
DVector < int > : : Read r = sconns . read ( ) ;
int idx = 0 ;
for ( int i = 0 ; i < cc ; i + + ) {
ConnectionData & cd = connections [ i ] ;
cd . from = r [ idx + + ] ;
cd . to = r [ idx + + ] ;
cd . signal = r [ idx + + ] ;
cd . method = r [ idx + + ] ;
cd . flags = r [ idx + + ] ;
cd . binds . resize ( r [ idx + + ] ) ;
for ( int j = 0 ; j < cd . binds . size ( ) ; j + + ) {
cd . binds [ j ] = r [ idx + + ] ;
}
}
}
2015-10-10 12:09:09 +00:00
Array np ;
if ( d . has ( " node_paths " ) ) {
np = d [ " node_paths " ] ;
}
node_paths . resize ( np . size ( ) ) ;
for ( int i = 0 ; i < np . size ( ) ; i + + ) {
node_paths [ i ] = np [ i ] ;
}
Array ei ;
if ( d . has ( " editable_instances " ) ) {
ei = d [ " editable_instances " ] ;
}
if ( d . has ( " base_scene " ) ) {
base_scene_idx = d [ " base_scene " ] ;
}
editable_instances . resize ( ei . size ( ) ) ;
for ( int i = 0 ; i < editable_instances . size ( ) ; i + + ) {
editable_instances [ i ] = ei [ i ] ;
}
2014-02-23 13:35:05 +00:00
// path=d["path"];
}
2015-10-10 12:09:09 +00:00
Dictionary SceneState : : get_bundled_scene ( ) const {
2014-02-23 13:35:05 +00:00
DVector < String > rnames ;
rnames . resize ( names . size ( ) ) ;
if ( names . size ( ) ) {
DVector < String > : : Write r = rnames . write ( ) ;
for ( int i = 0 ; i < names . size ( ) ; i + + )
r [ i ] = names [ i ] ;
}
Dictionary d ;
d [ " names " ] = rnames ;
d [ " variants " ] = variants ;
Vector < int > rnodes ;
d [ " node_count " ] = nodes . size ( ) ;
for ( int i = 0 ; i < nodes . size ( ) ; i + + ) {
const NodeData & nd = nodes [ i ] ;
rnodes . push_back ( nd . parent ) ;
rnodes . push_back ( nd . owner ) ;
rnodes . push_back ( nd . type ) ;
rnodes . push_back ( nd . name ) ;
rnodes . push_back ( nd . instance ) ;
rnodes . push_back ( nd . properties . size ( ) ) ;
for ( int j = 0 ; j < nd . properties . size ( ) ; j + + ) {
rnodes . push_back ( nd . properties [ j ] . name ) ;
rnodes . push_back ( nd . properties [ j ] . value ) ;
}
rnodes . push_back ( nd . groups . size ( ) ) ;
for ( int j = 0 ; j < nd . groups . size ( ) ; j + + ) {
rnodes . push_back ( nd . groups [ j ] ) ;
}
}
d [ " nodes " ] = rnodes ;
Vector < int > rconns ;
d [ " conn_count " ] = connections . size ( ) ;
for ( int i = 0 ; i < connections . size ( ) ; i + + ) {
const ConnectionData & cd = connections [ i ] ;
rconns . push_back ( cd . from ) ;
rconns . push_back ( cd . to ) ;
rconns . push_back ( cd . signal ) ;
rconns . push_back ( cd . method ) ;
rconns . push_back ( cd . flags ) ;
rconns . push_back ( cd . binds . size ( ) ) ;
for ( int j = 0 ; j < cd . binds . size ( ) ; j + + )
rconns . push_back ( cd . binds [ j ] ) ;
}
d [ " conns " ] = rconns ;
2015-10-10 12:09:09 +00:00
Array rnode_paths ;
rnode_paths . resize ( node_paths . size ( ) ) ;
for ( int i = 0 ; i < node_paths . size ( ) ; i + + ) {
rnode_paths [ i ] = node_paths [ i ] ;
}
d [ " node_paths " ] = rnode_paths ;
Array reditable_instances ;
reditable_instances . resize ( editable_instances . size ( ) ) ;
for ( int i = 0 ; i < editable_instances . size ( ) ; i + + ) {
reditable_instances [ i ] = editable_instances [ i ] ;
}
d [ " editable_instances " ] = reditable_instances ;
if ( base_scene_idx > = 0 ) {
d [ " base_scene " ] = base_scene_idx ;
}
d [ " version " ] = PACK_VERSION ;
2014-02-23 13:35:05 +00:00
// d["path"]=path;
return d ;
}
2015-10-10 12:09:09 +00:00
int SceneState : : get_node_count ( ) const {
return nodes . size ( ) ;
}
StringName SceneState : : get_node_type ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , nodes . size ( ) , StringName ( ) ) ;
if ( nodes [ p_idx ] . type = = TYPE_INSTANCED )
return StringName ( ) ;
return names [ nodes [ p_idx ] . type ] ;
}
StringName SceneState : : get_node_name ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , nodes . size ( ) , StringName ( ) ) ;
return names [ nodes [ p_idx ] . name ] ;
}
Ref < PackedScene > SceneState : : get_node_instance ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , nodes . size ( ) , Ref < PackedScene > ( ) ) ;
2015-11-28 23:56:14 +00:00
2015-10-10 12:09:09 +00:00
if ( nodes [ p_idx ] . instance > = 0 ) {
return variants [ nodes [ p_idx ] . instance ] ;
2015-11-28 23:56:14 +00:00
} else if ( nodes [ p_idx ] . parent < 0 | | nodes [ p_idx ] . parent = = NO_PARENT_SAVED ) {
2015-10-10 12:09:09 +00:00
if ( base_scene_idx > = 0 ) {
return variants [ base_scene_idx ] ;
}
}
2015-11-28 23:56:14 +00:00
2015-10-10 12:09:09 +00:00
return Ref < PackedScene > ( ) ;
}
Vector < StringName > SceneState : : get_node_groups ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , nodes . size ( ) , Vector < StringName > ( ) ) ;
Vector < StringName > groups ;
for ( int i = 0 ; i < nodes [ p_idx ] . groups . size ( ) ; i + + ) {
groups . push_back ( names [ nodes [ p_idx ] . groups [ i ] ] ) ;
}
return groups ;
}
NodePath SceneState : : get_node_path ( int p_idx , bool p_for_parent ) const {
ERR_FAIL_INDEX_V ( p_idx , nodes . size ( ) , NodePath ( ) ) ;
if ( nodes [ p_idx ] . parent < 0 | | nodes [ p_idx ] . parent = = NO_PARENT_SAVED ) {
if ( p_for_parent ) {
return NodePath ( ) ;
} else {
return NodePath ( " . " ) ;
}
}
Vector < StringName > sub_path ;
NodePath base_path ;
int nidx = p_idx ;
while ( true ) {
if ( nodes [ nidx ] . parent = = NO_PARENT_SAVED | | nodes [ nidx ] . parent < 0 ) {
sub_path . insert ( 0 , " . " ) ;
break ;
}
if ( ! p_for_parent | | p_idx ! = nidx ) {
sub_path . insert ( 0 , names [ nodes [ nidx ] . name ] ) ;
}
if ( nodes [ nidx ] . parent & FLAG_ID_IS_PATH ) {
base_path = node_paths [ nodes [ nidx ] . parent & FLAG_MASK ] ;
break ;
} else {
nidx = nodes [ nidx ] . parent & FLAG_MASK ;
}
}
for ( int i = 0 ; i < base_path . get_name_count ( ) ; i + + ) {
StringName sn = base_path . get_name ( i ) ;
sub_path . insert ( 0 , base_path . get_name ( i ) ) ;
}
if ( sub_path . empty ( ) ) {
return NodePath ( " . " ) ;
}
return NodePath ( sub_path , false ) ;
}
int SceneState : : get_node_property_count ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , nodes . size ( ) , - 1 ) ;
return nodes [ p_idx ] . properties . size ( ) ;
}
StringName SceneState : : get_node_property_name ( int p_idx , int p_prop ) const {
ERR_FAIL_INDEX_V ( p_idx , nodes . size ( ) , StringName ( ) ) ;
ERR_FAIL_INDEX_V ( p_prop , nodes [ p_idx ] . properties . size ( ) , StringName ( ) ) ;
return names [ nodes [ p_idx ] . properties [ p_prop ] . name ] ;
}
Variant SceneState : : get_node_property_value ( int p_idx , int p_prop ) const {
ERR_FAIL_INDEX_V ( p_idx , nodes . size ( ) , Variant ( ) ) ;
ERR_FAIL_INDEX_V ( p_prop , nodes [ p_idx ] . properties . size ( ) , Variant ( ) ) ;
return variants [ nodes [ p_idx ] . properties [ p_prop ] . value ] ;
}
NodePath SceneState : : get_node_owner_path ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , nodes . size ( ) , NodePath ( ) ) ;
if ( nodes [ p_idx ] . owner < 0 | | nodes [ p_idx ] . owner = = NO_PARENT_SAVED )
return NodePath ( ) ; //root likely
if ( nodes [ p_idx ] . owner & FLAG_ID_IS_PATH ) {
return node_paths [ nodes [ p_idx ] . owner & FLAG_MASK ] ;
} else {
return get_node_path ( nodes [ p_idx ] . owner & FLAG_MASK ) ;
}
}
int SceneState : : get_connection_count ( ) const {
return connections . size ( ) ;
}
NodePath SceneState : : get_connection_source ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , connections . size ( ) , NodePath ( ) ) ;
if ( connections [ p_idx ] . from & FLAG_ID_IS_PATH ) {
return node_paths [ connections [ p_idx ] . from & FLAG_MASK ] ;
} else {
return get_node_path ( connections [ p_idx ] . from & FLAG_MASK ) ;
}
}
StringName SceneState : : get_connection_signal ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , connections . size ( ) , StringName ( ) ) ;
return names [ connections [ p_idx ] . signal ] ;
}
NodePath SceneState : : get_connection_target ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , connections . size ( ) , NodePath ( ) ) ;
if ( connections [ p_idx ] . to & FLAG_ID_IS_PATH ) {
return node_paths [ connections [ p_idx ] . to & FLAG_MASK ] ;
} else {
return get_node_path ( connections [ p_idx ] . to & FLAG_MASK ) ;
}
}
StringName SceneState : : get_connection_method ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , connections . size ( ) , StringName ( ) ) ;
return names [ connections [ p_idx ] . method ] ;
}
int SceneState : : get_connection_flags ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , connections . size ( ) , - 1 ) ;
return connections [ p_idx ] . flags ;
}
Array SceneState : : get_connection_binds ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , connections . size ( ) , - 1 ) ;
Array binds ;
for ( int i = 0 ; i < connections [ p_idx ] . binds . size ( ) ; i + + ) {
binds . push_back ( variants [ connections [ p_idx ] . binds [ i ] ] ) ;
}
return binds ;
}
Vector < NodePath > SceneState : : get_editable_instances ( ) const {
return editable_instances ;
}
2015-11-28 23:56:14 +00:00
//add
int SceneState : : add_name ( const StringName & p_name ) {
names . push_back ( p_name ) ;
return names . size ( ) - 1 ;
}
int SceneState : : add_value ( const Variant & p_value ) {
variants . push_back ( p_value ) ;
return variants . size ( ) - 1 ;
}
int SceneState : : add_node_path ( const NodePath & p_path ) {
node_paths . push_back ( p_path ) ;
return ( node_paths . size ( ) - 1 ) | FLAG_ID_IS_PATH ;
}
int SceneState : : add_node ( int p_parent , int p_owner , int p_type , int p_name , int p_instance ) {
NodeData nd ;
nd . parent = p_parent ;
nd . owner = p_owner ;
nd . type = p_type ;
nd . name = p_name ;
nd . instance = p_instance ;
nodes . push_back ( nd ) ;
return nodes . size ( ) - 1 ;
}
void SceneState : : add_node_property ( int p_node , int p_name , int p_value ) {
ERR_FAIL_INDEX ( p_node , nodes . size ( ) ) ;
ERR_FAIL_INDEX ( p_name , names . size ( ) ) ;
ERR_FAIL_INDEX ( p_value , variants . size ( ) ) ;
NodeData : : Property prop ;
prop . name = p_name ;
prop . value = p_value ;
nodes [ p_node ] . properties . push_back ( prop ) ;
}
void SceneState : : add_node_group ( int p_node , int p_group ) {
ERR_FAIL_INDEX ( p_node , nodes . size ( ) ) ;
ERR_FAIL_INDEX ( p_group , names . size ( ) ) ;
nodes [ p_node ] . groups . push_back ( p_group ) ;
}
void SceneState : : set_base_scene ( int p_idx ) {
ERR_FAIL_INDEX ( p_idx , variants . size ( ) ) ;
base_scene_idx = p_idx ;
}
void SceneState : : add_connection ( int p_from , int p_to , int p_signal , int p_method , int p_flags , const Vector < int > & p_binds ) {
ERR_FAIL_INDEX ( p_signal , names . size ( ) ) ;
ERR_FAIL_INDEX ( p_method , names . size ( ) ) ;
for ( int i = 0 ; i < p_binds . size ( ) ; i + + ) {
ERR_FAIL_INDEX ( p_binds [ i ] , variants . size ( ) ) ;
}
ConnectionData c ;
c . from = p_from ;
c . to = p_to ;
c . signal = p_signal ;
c . method = p_method ;
c . flags = p_flags ;
c . binds = p_binds ;
connections . push_back ( c ) ;
}
void SceneState : : add_editable_instance ( const NodePath & p_path ) {
editable_instances . push_back ( p_path ) ;
}
2016-01-23 15:01:42 +00:00
DVector < String > SceneState : : _get_node_groups ( int p_idx ) const {
2015-10-10 12:09:09 +00:00
2016-01-23 15:01:42 +00:00
Vector < StringName > groups = get_node_groups ( p_idx ) ;
DVector < String > ret ;
for ( int i = 0 ; i < groups . size ( ) ; i + + )
ret . push_back ( groups [ i ] ) ;
return ret ;
}
void SceneState : : _bind_methods ( ) {
//unbuild API
ObjectTypeDB : : bind_method ( _MD ( " get_node_count " ) , & SceneState : : get_node_count ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_type " , " idx " ) , & SceneState : : get_node_type ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_name " , " idx " ) , & SceneState : : get_node_name ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_path " , " idx " , " for_parent " ) , & SceneState : : get_node_path , DEFVAL ( false ) ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_owner_path " , " idx " ) , & SceneState : : get_node_owner_path ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_instance:PackedScene " , " idx " ) , & SceneState : : get_node_instance ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_groups " , " idx " ) , & SceneState : : _get_node_groups ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_property_count " , " idx " ) , & SceneState : : get_node_property_count ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_property_name " , " idx " , " prop_idx " ) , & SceneState : : get_node_property_name ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_property_value " , " idx " , " prop_idx " ) , & SceneState : : get_node_property_value ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_connection_count " ) , & SceneState : : get_connection_count ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_connection_source " , " idx " ) , & SceneState : : get_connection_source ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_connection_signal " , " idx " ) , & SceneState : : get_connection_signal ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_connection_target " , " idx " ) , & SceneState : : get_connection_target ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_connection_method " , " idx " ) , & SceneState : : get_connection_method ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_connection_flags " , " idx " ) , & SceneState : : get_connection_flags ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_connection_binds " , " idx " ) , & SceneState : : get_connection_binds ) ;
}
2015-10-10 12:09:09 +00:00
SceneState : : SceneState ( ) {
base_scene_idx = - 1 ;
2015-12-13 23:39:01 +00:00
last_modified_time = 0 ;
2015-10-10 12:09:09 +00:00
}
////////////////
void PackedScene : : _set_bundled_scene ( const Dictionary & d ) {
state - > set_bundled_scene ( d ) ;
}
Dictionary PackedScene : : _get_bundled_scene ( ) const {
return state - > get_bundled_scene ( ) ;
}
Error PackedScene : : pack ( Node * p_scene ) {
return state - > pack ( p_scene ) ;
}
void PackedScene : : clear ( ) {
state - > clear ( ) ;
}
bool PackedScene : : can_instance ( ) const {
return state - > can_instance ( ) ;
}
Node * PackedScene : : instance ( bool p_gen_edit_state ) const {
# ifndef TOOLS_ENABLED
if ( p_gen_edit_state ) {
ERR_EXPLAIN ( " Edit state is only for editors, does not work without tools compiled " ) ;
ERR_FAIL_COND_V ( p_gen_edit_state , NULL ) ;
}
# endif
Node * s = state - > instance ( p_gen_edit_state ) ;
if ( ! s )
return NULL ;
if ( p_gen_edit_state ) {
s - > set_scene_instance_state ( state ) ;
}
if ( get_path ( ) ! = " " & & get_path ( ) . find ( " :: " ) = = - 1 )
s - > set_filename ( get_path ( ) ) ;
s - > notification ( Node : : NOTIFICATION_INSTANCED ) ;
return s ;
}
2016-01-14 14:06:20 +00:00
void PackedScene : : replace_state ( Ref < SceneState > p_by ) {
state = p_by ;
state - > set_path ( get_path ( ) ) ;
# ifdef TOOLS_ENABLED
state - > set_last_modified_time ( get_last_modified_time ( ) ) ;
# endif
}
2015-12-13 23:39:01 +00:00
void PackedScene : : recreate_state ( ) {
state = Ref < SceneState > ( memnew ( SceneState ) ) ;
state - > set_path ( get_path ( ) ) ;
# ifdef TOOLS_ENABLED
state - > set_last_modified_time ( get_last_modified_time ( ) ) ;
# endif
}
2015-10-10 12:09:09 +00:00
Ref < SceneState > PackedScene : : get_state ( ) {
return state ;
}
void PackedScene : : set_path ( const String & p_path , bool p_take_over ) {
state - > set_path ( p_path ) ;
Resource : : set_path ( p_path , p_take_over ) ;
}
2015-12-13 23:39:01 +00:00
2014-02-23 13:35:05 +00:00
void PackedScene : : _bind_methods ( ) {
ObjectTypeDB : : bind_method ( _MD ( " pack " , " path:Node " ) , & PackedScene : : pack ) ;
2015-10-10 12:09:09 +00:00
ObjectTypeDB : : bind_method ( _MD ( " instance:Node " , " gen_edit_state " ) , & PackedScene : : instance , DEFVAL ( false ) ) ;
2014-02-23 13:35:05 +00:00
ObjectTypeDB : : bind_method ( _MD ( " can_instance " ) , & PackedScene : : can_instance ) ;
ObjectTypeDB : : bind_method ( _MD ( " _set_bundled_scene " ) , & PackedScene : : _set_bundled_scene ) ;
ObjectTypeDB : : bind_method ( _MD ( " _get_bundled_scene " ) , & PackedScene : : _get_bundled_scene ) ;
2016-01-23 15:01:42 +00:00
ObjectTypeDB : : bind_method ( _MD ( " get_state:SceneState " ) , & PackedScene : : get_state ) ;
2014-02-23 13:35:05 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : DICTIONARY , " _bundled " ) , _SCS ( " _set_bundled_scene " ) , _SCS ( " _get_bundled_scene " ) ) ;
}
PackedScene : : PackedScene ( ) {
2015-10-10 12:09:09 +00:00
state = Ref < SceneState > ( memnew ( SceneState ) ) ;
2014-02-23 13:35:05 +00:00
}