@@ -1017,7 +1017,9 @@ void EditorFileSystem::scan() {
10171017void EditorFileSystem::ScanProgress::increment () {
10181018 current++;
10191019 float ratio = current / MAX (hi, 1 .0f );
1020- progress->step (ratio * 1000 .0f );
1020+ if (progress) {
1021+ progress->step (ratio * 1000 .0f );
1022+ }
10211023 EditorFileSystem::singleton->scan_total = ratio;
10221024}
10231025
@@ -1283,7 +1285,7 @@ void EditorFileSystem::_process_removed_files(const HashSet<String> &p_processed
12831285 }
12841286}
12851287
1286- void EditorFileSystem::_scan_fs_changes (EditorFileSystemDirectory *p_dir, ScanProgress &p_progress) {
1288+ void EditorFileSystem::_scan_fs_changes (EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, bool p_recursive ) {
12871289 uint64_t current_mtime = FileAccess::get_modified_time (p_dir->get_path ());
12881290
12891291 bool updated_dir = false ;
@@ -1477,7 +1479,9 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanPr
14771479 scan_actions.push_back (ia);
14781480 continue ;
14791481 }
1480- _scan_fs_changes (p_dir->get_subdir (i), p_progress);
1482+ if (p_recursive) {
1483+ _scan_fs_changes (p_dir->get_subdir (i), p_progress);
1484+ }
14811485 }
14821486
14831487 nb_files_total = MAX (nb_files_total + diff_nb_files, 0 );
@@ -2902,6 +2906,96 @@ void EditorFileSystem::reimport_file_with_custom_parameters(const String &p_file
29022906 emit_signal (SNAME (" resources_reimported" ), reloads);
29032907}
29042908
2909+ Error EditorFileSystem::_copy_file (const String &p_from, const String &p_to) {
2910+ Ref<DirAccess> da = DirAccess::create (DirAccess::ACCESS_RESOURCES);
2911+ if (FileAccess::exists (p_from + " .import" )) {
2912+ Error err = da->copy (p_from, p_to);
2913+ if (err != OK) {
2914+ return err;
2915+ }
2916+
2917+ // Remove uid from .import file to avoid conflict.
2918+ Ref<ConfigFile> cfg;
2919+ cfg.instantiate ();
2920+ cfg->load (p_from + " .import" );
2921+ cfg->erase_section_key (" remap" , " uid" );
2922+ err = cfg->save (p_to + " .import" );
2923+ if (err != OK) {
2924+ return err;
2925+ }
2926+ } else if (ResourceLoader::get_resource_uid (p_from) == ResourceUID::INVALID_ID) {
2927+ // Files which do not use an uid can just be copied.
2928+ Error err = da->copy (p_from, p_to);
2929+ if (err != OK) {
2930+ return err;
2931+ }
2932+ } else {
2933+ // Load the resource and save it again in the new location (this generates a new UID).
2934+ Error err;
2935+ Ref<Resource> res = ResourceLoader::load (p_from, " " , ResourceFormatLoader::CACHE_MODE_REUSE, &err);
2936+ if (err == OK && res.is_valid ()) {
2937+ err = ResourceSaver::save (res, p_to, ResourceSaver::FLAG_COMPRESS);
2938+ if (err != OK) {
2939+ return err;
2940+ }
2941+ } else if (err != OK) {
2942+ // When loading files like text files the error is OK but the resource is still null.
2943+ // We can ignore such files.
2944+ return err;
2945+ }
2946+ }
2947+ return OK;
2948+ }
2949+
2950+ bool EditorFileSystem::_copy_directory (const String &p_from, const String &p_to, List<CopiedFile> *p_files) {
2951+ Ref<DirAccess> old_dir = DirAccess::open (p_from);
2952+ ERR_FAIL_COND_V (old_dir.is_null (), false );
2953+
2954+ Error err = make_dir_recursive (p_to);
2955+ if (err != OK && err != ERR_ALREADY_EXISTS) {
2956+ return false ;
2957+ }
2958+
2959+ bool success = true ;
2960+ old_dir->set_include_navigational (false );
2961+ old_dir->list_dir_begin ();
2962+
2963+ for (String F = old_dir->_get_next (); !F.is_empty (); F = old_dir->_get_next ()) {
2964+ if (old_dir->current_is_dir ()) {
2965+ success = _copy_directory (p_from.path_join (F), p_to.path_join (F), p_files) && success;
2966+ } else if (F.get_extension () != " import" ) {
2967+ CopiedFile copy;
2968+ copy.from = p_from.path_join (F);
2969+ copy.to = p_to.path_join (F);
2970+ p_files->push_back (copy);
2971+ }
2972+ }
2973+ return success;
2974+ }
2975+
2976+ void EditorFileSystem::_queue_refresh_filesystem () {
2977+ if (refresh_queued) {
2978+ return ;
2979+ }
2980+ refresh_queued = true ;
2981+ get_tree ()->connect (SNAME (" process_frame" ), callable_mp (this , &EditorFileSystem::_refresh_filesystem), CONNECT_ONE_SHOT);
2982+ }
2983+
2984+ void EditorFileSystem::_refresh_filesystem () {
2985+ for (const ObjectID &id : folders_to_sort) {
2986+ EditorFileSystemDirectory *dir = Object::cast_to<EditorFileSystemDirectory>(ObjectDB::get_instance (id));
2987+ if (dir) {
2988+ dir->subdirs .sort_custom <DirectoryComparator>();
2989+ }
2990+ }
2991+ folders_to_sort.clear ();
2992+
2993+ _update_scan_actions ();
2994+
2995+ emit_signal (SNAME (" filesystem_changed" ));
2996+ refresh_queued = false ;
2997+ }
2998+
29052999void EditorFileSystem::_reimport_thread (uint32_t p_index, ImportThreadData *p_import_data) {
29063000 int current_max = p_import_data->reimport_from + int (p_index);
29073001 p_import_data->max_index .exchange_if_greater (current_max);
@@ -3225,10 +3319,9 @@ Error EditorFileSystem::make_dir_recursive(const String &p_path, const String &p
32253319 const String path = da->get_current_dir ();
32263320 EditorFileSystemDirectory *parent = get_filesystem_path (path);
32273321 ERR_FAIL_NULL_V (parent, ERR_FILE_NOT_FOUND);
3322+ folders_to_sort.insert (parent->get_instance_id ());
32283323
32293324 const PackedStringArray folders = p_path.trim_prefix (path).trim_suffix (" /" ).split (" /" );
3230- bool first = true ;
3231-
32323325 for (const String &folder : folders) {
32333326 const int current = parent->find_dir_index (folder);
32343327 if (current > -1 ) {
@@ -3240,18 +3333,59 @@ Error EditorFileSystem::make_dir_recursive(const String &p_path, const String &p
32403333 efd->parent = parent;
32413334 efd->name = folder;
32423335 parent->subdirs .push_back (efd);
3243-
3244- if (first) {
3245- parent->subdirs .sort_custom <DirectoryComparator>();
3246- first = false ;
3247- }
32483336 parent = efd;
32493337 }
32503338
3251- emit_signal ( SNAME ( " filesystem_changed " ) );
3339+ _queue_refresh_filesystem ( );
32523340 return OK;
32533341}
32543342
3343+ Error EditorFileSystem::copy_file (const String &p_from, const String &p_to) {
3344+ _copy_file (p_from, p_to);
3345+
3346+ EditorFileSystemDirectory *parent = get_filesystem_path (p_to.get_base_dir ());
3347+ ERR_FAIL_NULL_V (parent, ERR_FILE_NOT_FOUND);
3348+
3349+ ScanProgress sp;
3350+ _scan_fs_changes (parent, sp, false );
3351+
3352+ _queue_refresh_filesystem ();
3353+ return OK;
3354+ }
3355+
3356+ Error EditorFileSystem::copy_directory (const String &p_from, const String &p_to) {
3357+ List<CopiedFile> files;
3358+ bool success = _copy_directory (p_from, p_to, &files);
3359+
3360+ EditorProgress *ep = nullptr ;
3361+ if (files.size () > 10 ) {
3362+ ep = memnew (EditorProgress (" _copy_files" , TTR (" Copying files..." ), files.size ()));
3363+ }
3364+
3365+ int i = 0 ;
3366+ for (const CopiedFile &F : files) {
3367+ if (_copy_file (F.from , F.to ) != OK) {
3368+ success = false ;
3369+ }
3370+ if (ep) {
3371+ ep->step (F.from .get_file (), i++, false );
3372+ }
3373+ }
3374+ memdelete_notnull (ep);
3375+
3376+ EditorFileSystemDirectory *efd = get_filesystem_path (p_to);
3377+ ERR_FAIL_NULL_V (efd, FAILED);
3378+ ERR_FAIL_NULL_V (efd->get_parent (), FAILED);
3379+
3380+ folders_to_sort.insert (efd->get_parent ()->get_instance_id ());
3381+
3382+ ScanProgress sp;
3383+ _scan_fs_changes (efd, sp);
3384+
3385+ _queue_refresh_filesystem ();
3386+ return success ? OK : FAILED;
3387+ }
3388+
32553389ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path (const String &p_path, bool p_generate) {
32563390 if (!p_path.is_resource_file () || p_path.begins_with (ProjectSettings::get_singleton ()->get_project_data_path ())) {
32573391 // Saved externally (configuration file) or internal file, do not assign an ID.
0 commit comments