@@ -1027,7 +1027,9 @@ void EditorFileSystem::scan() {
10271027void EditorFileSystem::ScanProgress::increment () {
10281028 current++;
10291029 float ratio = current / MAX (hi, 1 .0f );
1030- progress->step (ratio * 1000 .0f );
1030+ if (progress) {
1031+ progress->step (ratio * 1000 .0f );
1032+ }
10311033 EditorFileSystem::singleton->scan_total = ratio;
10321034}
10331035
@@ -1293,7 +1295,7 @@ void EditorFileSystem::_process_removed_files(const HashSet<String> &p_processed
12931295 }
12941296}
12951297
1296- void EditorFileSystem::_scan_fs_changes (EditorFileSystemDirectory *p_dir, ScanProgress &p_progress) {
1298+ void EditorFileSystem::_scan_fs_changes (EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, bool p_recursive ) {
12971299 uint64_t current_mtime = FileAccess::get_modified_time (p_dir->get_path ());
12981300
12991301 bool updated_dir = false ;
@@ -1487,7 +1489,9 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanPr
14871489 scan_actions.push_back (ia);
14881490 continue ;
14891491 }
1490- _scan_fs_changes (p_dir->get_subdir (i), p_progress);
1492+ if (p_recursive) {
1493+ _scan_fs_changes (p_dir->get_subdir (i), p_progress);
1494+ }
14911495 }
14921496
14931497 nb_files_total = MAX (nb_files_total + diff_nb_files, 0 );
@@ -2912,6 +2916,96 @@ void EditorFileSystem::reimport_file_with_custom_parameters(const String &p_file
29122916 emit_signal (SNAME (" resources_reimported" ), reloads);
29132917}
29142918
2919+ Error EditorFileSystem::_copy_file (const String &p_from, const String &p_to) {
2920+ Ref<DirAccess> da = DirAccess::create (DirAccess::ACCESS_RESOURCES);
2921+ if (FileAccess::exists (p_from + " .import" )) {
2922+ Error err = da->copy (p_from, p_to);
2923+ if (err != OK) {
2924+ return err;
2925+ }
2926+
2927+ // Remove uid from .import file to avoid conflict.
2928+ Ref<ConfigFile> cfg;
2929+ cfg.instantiate ();
2930+ cfg->load (p_from + " .import" );
2931+ cfg->erase_section_key (" remap" , " uid" );
2932+ err = cfg->save (p_to + " .import" );
2933+ if (err != OK) {
2934+ return err;
2935+ }
2936+ } else if (ResourceLoader::get_resource_uid (p_from) == ResourceUID::INVALID_ID) {
2937+ // Files which do not use an uid can just be copied.
2938+ Error err = da->copy (p_from, p_to);
2939+ if (err != OK) {
2940+ return err;
2941+ }
2942+ } else {
2943+ // Load the resource and save it again in the new location (this generates a new UID).
2944+ Error err;
2945+ Ref<Resource> res = ResourceLoader::load (p_from, " " , ResourceFormatLoader::CACHE_MODE_REUSE, &err);
2946+ if (err == OK && res.is_valid ()) {
2947+ err = ResourceSaver::save (res, p_to, ResourceSaver::FLAG_COMPRESS);
2948+ if (err != OK) {
2949+ return err;
2950+ }
2951+ } else if (err != OK) {
2952+ // When loading files like text files the error is OK but the resource is still null.
2953+ // We can ignore such files.
2954+ return err;
2955+ }
2956+ }
2957+ return OK;
2958+ }
2959+
2960+ bool EditorFileSystem::_copy_directory (const String &p_from, const String &p_to, List<CopiedFile> *p_files) {
2961+ Ref<DirAccess> old_dir = DirAccess::open (p_from);
2962+ ERR_FAIL_COND_V (old_dir.is_null (), false );
2963+
2964+ Error err = make_dir_recursive (p_to);
2965+ if (err != OK && err != ERR_ALREADY_EXISTS) {
2966+ return false ;
2967+ }
2968+
2969+ bool success = true ;
2970+ old_dir->set_include_navigational (false );
2971+ old_dir->list_dir_begin ();
2972+
2973+ for (String F = old_dir->_get_next (); !F.is_empty (); F = old_dir->_get_next ()) {
2974+ if (old_dir->current_is_dir ()) {
2975+ success = _copy_directory (p_from.path_join (F), p_to.path_join (F), p_files) && success;
2976+ } else if (F.get_extension () != " import" ) {
2977+ CopiedFile copy;
2978+ copy.from = p_from.path_join (F);
2979+ copy.to = p_to.path_join (F);
2980+ p_files->push_back (copy);
2981+ }
2982+ }
2983+ return success;
2984+ }
2985+
2986+ void EditorFileSystem::_queue_refresh_filesystem () {
2987+ if (refresh_queued) {
2988+ return ;
2989+ }
2990+ refresh_queued = true ;
2991+ get_tree ()->connect (SNAME (" process_frame" ), callable_mp (this , &EditorFileSystem::_refresh_filesystem), CONNECT_ONE_SHOT);
2992+ }
2993+
2994+ void EditorFileSystem::_refresh_filesystem () {
2995+ for (const ObjectID &id : folders_to_sort) {
2996+ EditorFileSystemDirectory *dir = Object::cast_to<EditorFileSystemDirectory>(ObjectDB::get_instance (id));
2997+ if (dir) {
2998+ dir->subdirs .sort_custom <DirectoryComparator>();
2999+ }
3000+ }
3001+ folders_to_sort.clear ();
3002+
3003+ _update_scan_actions ();
3004+
3005+ emit_signal (SNAME (" filesystem_changed" ));
3006+ refresh_queued = false ;
3007+ }
3008+
29153009void EditorFileSystem::_reimport_thread (uint32_t p_index, ImportThreadData *p_import_data) {
29163010 int current_max = p_import_data->reimport_from + int (p_index);
29173011 p_import_data->max_index .exchange_if_greater (current_max);
@@ -3235,10 +3329,9 @@ Error EditorFileSystem::make_dir_recursive(const String &p_path, const String &p
32353329 const String path = da->get_current_dir ();
32363330 EditorFileSystemDirectory *parent = get_filesystem_path (path);
32373331 ERR_FAIL_NULL_V (parent, ERR_FILE_NOT_FOUND);
3332+ folders_to_sort.insert (parent->get_instance_id ());
32383333
32393334 const PackedStringArray folders = p_path.trim_prefix (path).trim_suffix (" /" ).split (" /" );
3240- bool first = true ;
3241-
32423335 for (const String &folder : folders) {
32433336 const int current = parent->find_dir_index (folder);
32443337 if (current > -1 ) {
@@ -3250,18 +3343,59 @@ Error EditorFileSystem::make_dir_recursive(const String &p_path, const String &p
32503343 efd->parent = parent;
32513344 efd->name = folder;
32523345 parent->subdirs .push_back (efd);
3253-
3254- if (first) {
3255- parent->subdirs .sort_custom <DirectoryComparator>();
3256- first = false ;
3257- }
32583346 parent = efd;
32593347 }
32603348
3261- emit_signal ( SNAME ( " filesystem_changed " ) );
3349+ _queue_refresh_filesystem ( );
32623350 return OK;
32633351}
32643352
3353+ Error EditorFileSystem::copy_file (const String &p_from, const String &p_to) {
3354+ _copy_file (p_from, p_to);
3355+
3356+ EditorFileSystemDirectory *parent = get_filesystem_path (p_to.get_base_dir ());
3357+ ERR_FAIL_NULL_V (parent, ERR_FILE_NOT_FOUND);
3358+
3359+ ScanProgress sp;
3360+ _scan_fs_changes (parent, sp, false );
3361+
3362+ _queue_refresh_filesystem ();
3363+ return OK;
3364+ }
3365+
3366+ Error EditorFileSystem::copy_directory (const String &p_from, const String &p_to) {
3367+ List<CopiedFile> files;
3368+ bool success = _copy_directory (p_from, p_to, &files);
3369+
3370+ EditorProgress *ep = nullptr ;
3371+ if (files.size () > 10 ) {
3372+ ep = memnew (EditorProgress (" _copy_files" , TTR (" Copying files..." ), files.size ()));
3373+ }
3374+
3375+ int i = 0 ;
3376+ for (const CopiedFile &F : files) {
3377+ if (_copy_file (F.from , F.to ) != OK) {
3378+ success = false ;
3379+ }
3380+ if (ep) {
3381+ ep->step (F.from .get_file (), i++, false );
3382+ }
3383+ }
3384+ memdelete_notnull (ep);
3385+
3386+ EditorFileSystemDirectory *efd = get_filesystem_path (p_to);
3387+ ERR_FAIL_NULL_V (efd, FAILED);
3388+ ERR_FAIL_NULL_V (efd->get_parent (), FAILED);
3389+
3390+ folders_to_sort.insert (efd->get_parent ()->get_instance_id ());
3391+
3392+ ScanProgress sp;
3393+ _scan_fs_changes (efd, sp);
3394+
3395+ _queue_refresh_filesystem ();
3396+ return success ? OK : FAILED;
3397+ }
3398+
32653399ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path (const String &p_path, bool p_generate) {
32663400 if (!p_path.is_resource_file () || p_path.begins_with (ProjectSettings::get_singleton ()->get_project_data_path ())) {
32673401 // Saved externally (configuration file) or internal file, do not assign an ID.
0 commit comments