@@ -1368,6 +1368,51 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co
13681368 return p_node;
13691369}
13701370
1371+ Node *ResourceImporterScene::_replace_node_with_type_and_script (Node *p_node, String p_node_type, Ref<Script> p_script) {
1372+ p_node_type = p_node_type.get_slicec (' ' , 0 ); // Full root_type is "ClassName (filename.gd)" for a script global class.
1373+ if (p_script.is_valid ()) {
1374+ // Ensure the node type supports the script, or pick one that does.
1375+ String script_base_type = p_script->get_instance_base_type ();
1376+ if (ClassDB::is_parent_class (script_base_type, " Node" )) {
1377+ if (p_node_type.is_empty () || !ClassDB::is_parent_class (p_node_type, script_base_type)) {
1378+ p_node_type = script_base_type;
1379+ }
1380+ }
1381+ }
1382+ if (!p_node_type.is_empty () && ScriptServer::is_global_class (p_node_type)) {
1383+ // If the user specified a script class, we need to get the base node type.
1384+ if (p_script.is_null ()) {
1385+ p_script = ResourceLoader::load (ScriptServer::get_global_class_path (p_node_type));
1386+ }
1387+ p_node_type = ScriptServer::get_global_class_base (p_node_type);
1388+ }
1389+ if (!p_node_type.is_empty () && p_node->get_class_name () != p_node_type) {
1390+ // If the user specified a Godot node type that does not match
1391+ // what the scene import gave us, replace the root node.
1392+ Node *new_base_node = Object::cast_to<Node>(ClassDB::instantiate (p_node_type));
1393+ if (new_base_node) {
1394+ List<PropertyInfo> old_properties;
1395+ p_node->get_property_list (&old_properties);
1396+ for (const PropertyInfo &prop : old_properties) {
1397+ if (!(prop.usage & PROPERTY_USAGE_STORAGE)) {
1398+ continue ;
1399+ }
1400+ new_base_node->set (prop.name , p_node->get (prop.name ));
1401+ }
1402+ new_base_node->set_name (p_node->get_name ());
1403+ _copy_meta (p_node, new_base_node);
1404+ p_node->replace_by (new_base_node);
1405+ p_node->set_owner (nullptr );
1406+ memdelete (p_node);
1407+ p_node = new_base_node;
1408+ }
1409+ }
1410+ if (p_script.is_valid ()) {
1411+ p_node->set_script (Variant (p_script));
1412+ }
1413+ return p_node;
1414+ }
1415+
13711416Node *ResourceImporterScene::_post_fix_node (Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps, float p_applied_root_scale, const String &p_source_file, const HashMap<StringName, Variant> &p_options) {
13721417 // children first
13731418 for (int i = 0 ; i < p_node->get_child_count (); i++) {
@@ -1842,6 +1887,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
18421887 }
18431888 }
18441889
1890+ String node_type = node_settings.get (" node/node_type" , " " );
1891+ Ref<Script> node_script = node_settings.get (" node/script" , Ref<Script>());
1892+ p_node = _replace_node_with_type_and_script (p_node, node_type, node_script);
1893+
18451894 return p_node;
18461895}
18471896
@@ -2057,9 +2106,12 @@ void ResourceImporterScene::_compress_animations(AnimationPlayer *anim, int p_pa
20572106void ResourceImporterScene::get_internal_import_options (InternalImportCategory p_category, List<ImportOption> *r_options) const {
20582107 switch (p_category) {
20592108 case INTERNAL_IMPORT_CATEGORY_NODE: {
2109+ r_options->push_back (ImportOption (PropertyInfo (Variant::STRING, " node/node_type" , PROPERTY_HINT_TYPE_STRING, " Node" ), " " ));
2110+ r_options->push_back (ImportOption (PropertyInfo (Variant::OBJECT, " node/script" , PROPERTY_HINT_RESOURCE_TYPE, " Script" ), Variant ()));
20602111 r_options->push_back (ImportOption (PropertyInfo (Variant::BOOL, " import/skip_import" , PROPERTY_HINT_NONE, " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false ));
20612112 } break ;
20622113 case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE: {
2114+ r_options->push_back (ImportOption (PropertyInfo (Variant::OBJECT, " node/script" , PROPERTY_HINT_RESOURCE_TYPE, " Script" ), Variant ()));
20632115 r_options->push_back (ImportOption (PropertyInfo (Variant::BOOL, " import/skip_import" , PROPERTY_HINT_NONE, " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false ));
20642116 r_options->push_back (ImportOption (PropertyInfo (Variant::BOOL, " generate/physics" , PROPERTY_HINT_NONE, " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false ));
20652117 r_options->push_back (ImportOption (PropertyInfo (Variant::INT, " generate/navmesh" , PROPERTY_HINT_ENUM, " Disabled,Mesh + NavMesh,NavMesh Only" ), 0 ));
@@ -2140,6 +2192,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
21402192 }
21412193 } break ;
21422194 case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
2195+ r_options->push_back (ImportOption (PropertyInfo (Variant::OBJECT, " node/script" , PROPERTY_HINT_RESOURCE_TYPE, " Script" ), Variant ()));
21432196 r_options->push_back (ImportOption (PropertyInfo (Variant::BOOL, " import/skip_import" , PROPERTY_HINT_NONE, " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false ));
21442197 r_options->push_back (ImportOption (PropertyInfo (Variant::BOOL, " optimizer/enabled" , PROPERTY_HINT_NONE, " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true ));
21452198 r_options->push_back (ImportOption (PropertyInfo (Variant::FLOAT, " optimizer/max_velocity_error" , PROPERTY_HINT_RANGE, " 0,1,0.01" ), 0.01 ));
@@ -2152,6 +2205,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
21522205 r_options->push_back (ImportOption (PropertyInfo (Variant::INT, " import_tracks/scale" , PROPERTY_HINT_ENUM, " IfPresent,IfPresentForAll,Never" ), 1 ));
21532206 } break ;
21542207 case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: {
2208+ r_options->push_back (ImportOption (PropertyInfo (Variant::OBJECT, " node/script" , PROPERTY_HINT_RESOURCE_TYPE, " Script" ), Variant ()));
21552209 r_options->push_back (ImportOption (PropertyInfo (Variant::BOOL, " import/skip_import" , PROPERTY_HINT_NONE, " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false ));
21562210 r_options->push_back (ImportOption (PropertyInfo (Variant::INT, " rest_pose/load_pose" , PROPERTY_HINT_ENUM, " Default Pose,Use AnimationPlayer,Load External Animation" , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0 ));
21572211 r_options->push_back (ImportOption (PropertyInfo (Variant::OBJECT, " rest_pose/external_animation_library" , PROPERTY_HINT_RESOURCE_TYPE, " Animation,AnimationLibrary" , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Variant ()));
@@ -2436,6 +2490,7 @@ bool ResourceImporterScene::get_internal_option_update_view_required(InternalImp
24362490void ResourceImporterScene::get_import_options (const String &p_path, List<ImportOption> *r_options, int p_preset) const {
24372491 r_options->push_back (ImportOption (PropertyInfo (Variant::STRING, " nodes/root_type" , PROPERTY_HINT_TYPE_STRING, " Node" ), " " ));
24382492 r_options->push_back (ImportOption (PropertyInfo (Variant::STRING, " nodes/root_name" ), " " ));
2493+ r_options->push_back (ImportOption (PropertyInfo (Variant::OBJECT, " nodes/root_script" , PROPERTY_HINT_RESOURCE_TYPE, " Script" ), Variant ()));
24392494
24402495 List<String> script_extensions;
24412496 ResourceLoader::get_recognized_extensions_for_type (" Script" , &script_extensions);
@@ -3147,28 +3202,8 @@ Error ResourceImporterScene::import(ResourceUID::ID p_source_id, const String &p
31473202 _post_fix_animations (scene, scene, node_data, animation_data, fps, remove_immutable_tracks);
31483203
31493204 String root_type = p_options[" nodes/root_type" ];
3150- if (!root_type.is_empty ()) {
3151- root_type = root_type.split (" " )[0 ]; // Full root_type is "ClassName (filename.gd)" for a script global class.
3152- Ref<Script> root_script = nullptr ;
3153- if (ScriptServer::is_global_class (root_type)) {
3154- root_script = ResourceLoader::load (ScriptServer::get_global_class_path (root_type));
3155- root_type = ScriptServer::get_global_class_base (root_type);
3156- }
3157- if (scene->get_class_name () != root_type) {
3158- // If the user specified a Godot node type that does not match
3159- // what the scene import gave us, replace the root node.
3160- Node *base_node = Object::cast_to<Node>(ClassDB::instantiate (root_type));
3161- if (base_node) {
3162- scene->replace_by (base_node);
3163- scene->set_owner (nullptr );
3164- memdelete (scene);
3165- scene = base_node;
3166- }
3167- }
3168- if (root_script.is_valid ()) {
3169- scene->set_script (Variant (root_script));
3170- }
3171- }
3205+ Ref<Script> root_script = p_options[" nodes/root_script" ];
3206+ scene = _replace_node_with_type_and_script (scene, root_type, root_script);
31723207
31733208 String root_name = p_options[" nodes/root_name" ];
31743209 if (!root_name.is_empty () && root_name != " Scene Root" ) {
0 commit comments