|
|
|
@ -44,6 +44,7 @@
|
|
|
|
|
#include "editor/editor_paths.h"
|
|
|
|
|
#include "editor/editor_resource_preview.h"
|
|
|
|
|
#include "editor/editor_settings.h"
|
|
|
|
|
#include "editor/project_settings_editor.h"
|
|
|
|
|
#include "scene/resources/packed_scene.h"
|
|
|
|
|
|
|
|
|
|
EditorFileSystem *EditorFileSystem::singleton = nullptr;
|
|
|
|
@ -206,17 +207,68 @@ EditorFileSystemDirectory::EditorFileSystemDirectory() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditorFileSystemDirectory::~EditorFileSystemDirectory() {
|
|
|
|
|
for (int i = 0; i < files.size(); i++) {
|
|
|
|
|
memdelete(files[i]);
|
|
|
|
|
for (EditorFileSystemDirectory::FileInfo *fi : files) {
|
|
|
|
|
memdelete(fi);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < subdirs.size(); i++) {
|
|
|
|
|
memdelete(subdirs[i]);
|
|
|
|
|
for (EditorFileSystemDirectory *dir : subdirs) {
|
|
|
|
|
memdelete(dir);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditorFileSystem::ScannedDirectory::~ScannedDirectory() {
|
|
|
|
|
for (ScannedDirectory *dir : subdirs) {
|
|
|
|
|
memdelete(dir);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_first_scan_filesystem() {
|
|
|
|
|
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
|
|
|
|
first_scan_root_dir = memnew(ScannedDirectory);
|
|
|
|
|
first_scan_root_dir->full_path = "res://";
|
|
|
|
|
HashSet<String> existing_class_names;
|
|
|
|
|
|
|
|
|
|
nb_files_total = _scan_new_dir(first_scan_root_dir, d);
|
|
|
|
|
|
|
|
|
|
// This loads the global class names from the scripts and ensures that even if the
|
|
|
|
|
// global_script_class_cache.cfg was missing or invalid, the global class names are valid in ScriptServer.
|
|
|
|
|
_first_scan_process_scripts(first_scan_root_dir, existing_class_names);
|
|
|
|
|
|
|
|
|
|
// Removing invalid global class to prevent having invalid paths in ScriptServer.
|
|
|
|
|
_remove_invalid_global_class_names(existing_class_names);
|
|
|
|
|
|
|
|
|
|
// Now that all the global class names should be loaded, create autoloads and plugins.
|
|
|
|
|
// This is done after loading the global class names because autoloads and plugins can use
|
|
|
|
|
// global class names.
|
|
|
|
|
ProjectSettingsEditor::get_singleton()->init_autoloads();
|
|
|
|
|
EditorNode::get_singleton()->init_plugins();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_first_scan_process_scripts(const ScannedDirectory *p_scan_dir, HashSet<String> &p_existing_class_names) {
|
|
|
|
|
for (ScannedDirectory *scan_sub_dir : p_scan_dir->subdirs) {
|
|
|
|
|
_first_scan_process_scripts(scan_sub_dir, p_existing_class_names);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const String &scan_file : p_scan_dir->files) {
|
|
|
|
|
String path = p_scan_dir->full_path.path_join(scan_file);
|
|
|
|
|
String type = ResourceLoader::get_resource_type(path);
|
|
|
|
|
|
|
|
|
|
if (ClassDB::is_parent_class(type, SNAME("Script"))) {
|
|
|
|
|
String script_class_extends;
|
|
|
|
|
String script_class_icon_path;
|
|
|
|
|
String script_class_name = _get_global_script_class(type, path, &script_class_extends, &script_class_icon_path);
|
|
|
|
|
_register_global_class_script(path, path, type, script_class_name, script_class_extends, script_class_icon_path);
|
|
|
|
|
|
|
|
|
|
if (!script_class_name.is_empty()) {
|
|
|
|
|
p_existing_class_names.insert(script_class_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_scan_filesystem() {
|
|
|
|
|
ERR_FAIL_COND(!scanning || new_filesystem);
|
|
|
|
|
// On the first scan, the first_scan_root_dir is created in _first_scan_filesystem.
|
|
|
|
|
ERR_FAIL_COND(!scanning || new_filesystem || (first_scan && !first_scan_root_dir));
|
|
|
|
|
|
|
|
|
|
//read .fscache
|
|
|
|
|
String cpath;
|
|
|
|
@ -318,23 +370,33 @@ void EditorFileSystem::_scan_filesystem() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditorProgressBG scan_progress("efs", "ScanFS", 1000);
|
|
|
|
|
|
|
|
|
|
ScanProgress sp;
|
|
|
|
|
sp.low = 0;
|
|
|
|
|
sp.hi = 1;
|
|
|
|
|
sp.hi = nb_files_total;
|
|
|
|
|
sp.progress = &scan_progress;
|
|
|
|
|
|
|
|
|
|
new_filesystem = memnew(EditorFileSystemDirectory);
|
|
|
|
|
new_filesystem->parent = nullptr;
|
|
|
|
|
|
|
|
|
|
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
|
|
|
|
d->change_dir("res://");
|
|
|
|
|
_scan_new_dir(new_filesystem, d, sp);
|
|
|
|
|
dep_update_list.clear();
|
|
|
|
|
ScannedDirectory *sd;
|
|
|
|
|
// On the first scan, the first_scan_root_dir is created in _first_scan_filesystem.
|
|
|
|
|
if (first_scan) {
|
|
|
|
|
sd = first_scan_root_dir;
|
|
|
|
|
} else {
|
|
|
|
|
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
|
|
|
|
sd = memnew(ScannedDirectory);
|
|
|
|
|
sd->full_path = "res://";
|
|
|
|
|
nb_files_total = _scan_new_dir(sd, d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_process_file_system(sd, new_filesystem, sp);
|
|
|
|
|
|
|
|
|
|
dep_update_list.clear();
|
|
|
|
|
file_cache.clear(); //clear caches, no longer needed
|
|
|
|
|
|
|
|
|
|
if (!first_scan) {
|
|
|
|
|
if (first_scan) {
|
|
|
|
|
memdelete(first_scan_root_dir);
|
|
|
|
|
first_scan_root_dir = nullptr;
|
|
|
|
|
} else {
|
|
|
|
|
//on the first scan this is done from the main thread after re-importing
|
|
|
|
|
_save_filesystem_cache();
|
|
|
|
|
}
|
|
|
|
@ -567,6 +629,10 @@ bool EditorFileSystem::_scan_import_support(const Vector<String> &reimports) {
|
|
|
|
|
bool EditorFileSystem::_update_scan_actions() {
|
|
|
|
|
sources_changed.clear();
|
|
|
|
|
|
|
|
|
|
// We need to update the script global class names before the reimports to be sure that
|
|
|
|
|
// all the importer classes that depends on class names will work.
|
|
|
|
|
_update_script_classes();
|
|
|
|
|
|
|
|
|
|
bool fs_changed = false;
|
|
|
|
|
|
|
|
|
|
Vector<String> reimports;
|
|
|
|
@ -615,7 +681,7 @@ bool EditorFileSystem::_update_scan_actions() {
|
|
|
|
|
fs_changed = true;
|
|
|
|
|
|
|
|
|
|
if (ClassDB::is_parent_class(ia.new_file->type, SNAME("Script"))) {
|
|
|
|
|
_queue_update_script_class(ia.dir->get_file_path(idx));
|
|
|
|
|
_queue_update_script_class(ia.dir->get_file_path(idx), ia.new_file->type, ia.new_file->script_class_name, ia.new_file->script_class_extends, ia.new_file->script_class_icon_path);
|
|
|
|
|
}
|
|
|
|
|
if (ia.new_file->type == SNAME("PackedScene")) {
|
|
|
|
|
_queue_update_scene_groups(ia.dir->get_file_path(idx));
|
|
|
|
@ -626,8 +692,9 @@ bool EditorFileSystem::_update_scan_actions() {
|
|
|
|
|
int idx = ia.dir->find_file_index(ia.file);
|
|
|
|
|
ERR_CONTINUE(idx == -1);
|
|
|
|
|
|
|
|
|
|
String script_class_name = ia.dir->files[idx]->script_class_name;
|
|
|
|
|
if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
|
|
|
|
|
_queue_update_script_class(ia.dir->get_file_path(idx));
|
|
|
|
|
_queue_update_script_class(ia.dir->get_file_path(idx), "", "", "", "");
|
|
|
|
|
}
|
|
|
|
|
if (ia.dir->files[idx]->type == SNAME("PackedScene")) {
|
|
|
|
|
_queue_update_scene_groups(ia.dir->get_file_path(idx));
|
|
|
|
@ -637,6 +704,15 @@ bool EditorFileSystem::_update_scan_actions() {
|
|
|
|
|
memdelete(ia.dir->files[idx]);
|
|
|
|
|
ia.dir->files.remove_at(idx);
|
|
|
|
|
|
|
|
|
|
// Restore another script with the same global class name if it exists.
|
|
|
|
|
if (!script_class_name.is_empty()) {
|
|
|
|
|
EditorFileSystemDirectory::FileInfo *old_fi = nullptr;
|
|
|
|
|
String old_file = _get_file_by_class_name(filesystem, script_class_name, old_fi);
|
|
|
|
|
if (!old_file.is_empty() && old_fi) {
|
|
|
|
|
_queue_update_script_class(old_file, old_fi->type, old_fi->script_class_name, old_fi->script_class_extends, old_fi->script_class_icon_path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fs_changed = true;
|
|
|
|
|
|
|
|
|
|
} break;
|
|
|
|
@ -667,10 +743,11 @@ bool EditorFileSystem::_update_scan_actions() {
|
|
|
|
|
ERR_CONTINUE(idx == -1);
|
|
|
|
|
String full_path = ia.dir->get_file_path(idx);
|
|
|
|
|
|
|
|
|
|
if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
|
|
|
|
|
_queue_update_script_class(full_path);
|
|
|
|
|
const EditorFileSystemDirectory::FileInfo *fi = ia.dir->files[idx];
|
|
|
|
|
if (ClassDB::is_parent_class(fi->type, SNAME("Script"))) {
|
|
|
|
|
_queue_update_script_class(full_path, fi->type, fi->script_class_name, fi->script_class_extends, fi->script_class_icon_path);
|
|
|
|
|
}
|
|
|
|
|
if (ia.dir->files[idx]->type == SNAME("PackedScene")) {
|
|
|
|
|
if (fi->type == SNAME("PackedScene")) {
|
|
|
|
|
_queue_update_scene_groups(full_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -711,6 +788,10 @@ bool EditorFileSystem::_update_scan_actions() {
|
|
|
|
|
_save_filesystem_cache();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Moving the processing of pending updates before the resources_reload event to be sure all global class names
|
|
|
|
|
// are updated. Script.cpp listens on resources_reload and reloads updated scripts.
|
|
|
|
|
_process_update_pending();
|
|
|
|
|
|
|
|
|
|
if (reloads.size()) {
|
|
|
|
|
emit_signal(SNAME("resources_reload"), reloads);
|
|
|
|
|
}
|
|
|
|
@ -728,6 +809,14 @@ void EditorFileSystem::scan() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The first scan must be on the main thread because, after the first scan and update
|
|
|
|
|
// of global class names, we load the plugins and autoloads. These need to
|
|
|
|
|
// be added on the main thread because they are nodes, and we need to wait for them
|
|
|
|
|
// to be loaded to continue the scan and reimportations.
|
|
|
|
|
if (first_scan) {
|
|
|
|
|
_first_scan_filesystem();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_update_extensions();
|
|
|
|
|
|
|
|
|
|
if (!use_threads) {
|
|
|
|
@ -741,14 +830,14 @@ void EditorFileSystem::scan() {
|
|
|
|
|
filesystem = new_filesystem;
|
|
|
|
|
new_filesystem = nullptr;
|
|
|
|
|
_update_scan_actions();
|
|
|
|
|
scanning = false;
|
|
|
|
|
_update_pending_script_classes();
|
|
|
|
|
_update_pending_scene_groups();
|
|
|
|
|
// Update all icons so they are loaded for the FileSystemDock.
|
|
|
|
|
_update_files_icon_path();
|
|
|
|
|
scanning = false;
|
|
|
|
|
// Set first_scan to false before the signals so the function doing_first_scan can return false
|
|
|
|
|
// in editor_node to start the export if needed.
|
|
|
|
|
first_scan = false;
|
|
|
|
|
emit_signal(SNAME("filesystem_changed"));
|
|
|
|
|
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
|
|
|
|
|
first_scan = false;
|
|
|
|
|
} else {
|
|
|
|
|
ERR_FAIL_COND(thread.is_started());
|
|
|
|
|
set_process(true);
|
|
|
|
@ -762,28 +851,19 @@ void EditorFileSystem::scan() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::ScanProgress::update(int p_current, int p_total) const {
|
|
|
|
|
float ratio = low + ((hi - low) / p_total) * p_current;
|
|
|
|
|
progress->step(ratio * 1000);
|
|
|
|
|
void EditorFileSystem::ScanProgress::increment() {
|
|
|
|
|
current++;
|
|
|
|
|
float ratio = current / MAX(hi, 1.0f);
|
|
|
|
|
progress->step(ratio * 1000.0f);
|
|
|
|
|
EditorFileSystem::singleton->scan_total = ratio;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditorFileSystem::ScanProgress EditorFileSystem::ScanProgress::get_sub(int p_current, int p_total) const {
|
|
|
|
|
ScanProgress sp = *this;
|
|
|
|
|
float slice = (sp.hi - sp.low) / p_total;
|
|
|
|
|
sp.low += slice * p_current;
|
|
|
|
|
sp.hi = slice;
|
|
|
|
|
return sp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAccess> &da, const ScanProgress &p_progress) {
|
|
|
|
|
int EditorFileSystem::_scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da) {
|
|
|
|
|
List<String> dirs;
|
|
|
|
|
List<String> files;
|
|
|
|
|
|
|
|
|
|
String cd = da->get_current_dir();
|
|
|
|
|
|
|
|
|
|
p_dir->modified_time = FileAccess::get_modified_time(cd);
|
|
|
|
|
|
|
|
|
|
da->list_dir_begin();
|
|
|
|
|
while (true) {
|
|
|
|
|
String f = da->get_next();
|
|
|
|
@ -816,55 +896,59 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
|
|
|
|
|
dirs.sort_custom<FileNoCaseComparator>();
|
|
|
|
|
files.sort_custom<FileNoCaseComparator>();
|
|
|
|
|
|
|
|
|
|
int total = dirs.size() + files.size();
|
|
|
|
|
int idx = 0;
|
|
|
|
|
int nb_files_total_scan = 0;
|
|
|
|
|
|
|
|
|
|
for (List<String>::Element *E = dirs.front(); E; E = E->next(), idx++) {
|
|
|
|
|
for (List<String>::Element *E = dirs.front(); E; E = E->next()) {
|
|
|
|
|
if (da->change_dir(E->get()) == OK) {
|
|
|
|
|
String d = da->get_current_dir();
|
|
|
|
|
|
|
|
|
|
if (d == cd || !d.begins_with(cd)) {
|
|
|
|
|
da->change_dir(cd); //avoid recursion
|
|
|
|
|
} else {
|
|
|
|
|
EditorFileSystemDirectory *efd = memnew(EditorFileSystemDirectory);
|
|
|
|
|
ScannedDirectory *sd = memnew(ScannedDirectory);
|
|
|
|
|
sd->name = E->get();
|
|
|
|
|
sd->full_path = p_dir->full_path.path_join(sd->name);
|
|
|
|
|
|
|
|
|
|
efd->parent = p_dir;
|
|
|
|
|
efd->name = E->get();
|
|
|
|
|
nb_files_total_scan += _scan_new_dir(sd, da);
|
|
|
|
|
|
|
|
|
|
_scan_new_dir(efd, da, p_progress.get_sub(idx, total));
|
|
|
|
|
|
|
|
|
|
int idx2 = 0;
|
|
|
|
|
for (int i = 0; i < p_dir->subdirs.size(); i++) {
|
|
|
|
|
if (efd->name.filenocasecmp_to(p_dir->subdirs[i]->name) < 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
idx2++;
|
|
|
|
|
}
|
|
|
|
|
if (idx2 == p_dir->subdirs.size()) {
|
|
|
|
|
p_dir->subdirs.push_back(efd);
|
|
|
|
|
} else {
|
|
|
|
|
p_dir->subdirs.insert(idx2, efd);
|
|
|
|
|
}
|
|
|
|
|
p_dir->subdirs.push_back(sd);
|
|
|
|
|
|
|
|
|
|
da->change_dir("..");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ERR_PRINT("Cannot go into subdir '" + E->get() + "'.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p_progress.update(idx, total);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (List<String>::Element *E = files.front(); E; E = E->next(), idx++) {
|
|
|
|
|
String ext = E->get().get_extension().to_lower();
|
|
|
|
|
p_dir->files = files;
|
|
|
|
|
nb_files_total_scan += files.size();
|
|
|
|
|
|
|
|
|
|
return nb_files_total_scan;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress) {
|
|
|
|
|
p_dir->modified_time = FileAccess::get_modified_time(p_scan_dir->full_path);
|
|
|
|
|
|
|
|
|
|
for (ScannedDirectory *scan_sub_dir : p_scan_dir->subdirs) {
|
|
|
|
|
EditorFileSystemDirectory *sub_dir = memnew(EditorFileSystemDirectory);
|
|
|
|
|
sub_dir->parent = p_dir;
|
|
|
|
|
sub_dir->name = scan_sub_dir->name;
|
|
|
|
|
p_dir->subdirs.push_back(sub_dir);
|
|
|
|
|
_process_file_system(scan_sub_dir, sub_dir, p_progress);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const String &scan_file : p_scan_dir->files) {
|
|
|
|
|
String ext = scan_file.get_extension().to_lower();
|
|
|
|
|
if (!valid_extensions.has(ext)) {
|
|
|
|
|
p_progress.increment();
|
|
|
|
|
continue; //invalid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
|
|
|
|
|
fi->file = E->get();
|
|
|
|
|
String path = p_scan_dir->full_path.path_join(scan_file);
|
|
|
|
|
|
|
|
|
|
String path = cd.path_join(fi->file);
|
|
|
|
|
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
|
|
|
|
|
fi->file = scan_file;
|
|
|
|
|
p_dir->files.push_back(fi);
|
|
|
|
|
|
|
|
|
|
FileCache *fc = file_cache.getptr(path);
|
|
|
|
|
uint64_t mt = FileAccess::get_modified_time(path);
|
|
|
|
@ -894,7 +978,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
|
|
|
|
|
ItemAction ia;
|
|
|
|
|
ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
|
|
|
|
|
ia.dir = p_dir;
|
|
|
|
|
ia.file = E->get();
|
|
|
|
|
ia.file = fi->file;
|
|
|
|
|
scan_actions.push_back(ia);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -923,7 +1007,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
|
|
|
|
|
ItemAction ia;
|
|
|
|
|
ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
|
|
|
|
|
ia.dir = p_dir;
|
|
|
|
|
ia.file = E->get();
|
|
|
|
|
ia.file = fi->file;
|
|
|
|
|
scan_actions.push_back(ia);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
@ -939,6 +1023,21 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
|
|
|
|
|
fi->script_class_name = fc->script_class_name;
|
|
|
|
|
fi->script_class_extends = fc->script_class_extends;
|
|
|
|
|
fi->script_class_icon_path = fc->script_class_icon_path;
|
|
|
|
|
|
|
|
|
|
if (first_scan && ClassDB::is_parent_class(fi->type, SNAME("Script"))) {
|
|
|
|
|
bool update_script = false;
|
|
|
|
|
String old_class_name = fi->script_class_name;
|
|
|
|
|
fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path);
|
|
|
|
|
if (old_class_name != fi->script_class_name) {
|
|
|
|
|
update_script = true;
|
|
|
|
|
} else if (!fi->script_class_name.is_empty() && (!ScriptServer::is_global_class(fi->script_class_name) || ScriptServer::get_global_class_path(fi->script_class_name) != path)) {
|
|
|
|
|
// This script has a class name but is not in the global class names or the path of the class has changed.
|
|
|
|
|
update_script = true;
|
|
|
|
|
}
|
|
|
|
|
if (update_script) {
|
|
|
|
|
_queue_update_script_class(path, fi->type, fi->script_class_name, fi->script_class_extends, fi->script_class_icon_path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
//new or modified time
|
|
|
|
|
fi->type = ResourceLoader::get_resource_type(path);
|
|
|
|
@ -956,7 +1055,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
|
|
|
|
|
// Files in dep_update_list are forced for rescan to update dependencies. They don't need other updates.
|
|
|
|
|
if (!dep_update_list.has(path)) {
|
|
|
|
|
if (ClassDB::is_parent_class(fi->type, SNAME("Script"))) {
|
|
|
|
|
_queue_update_script_class(path);
|
|
|
|
|
_queue_update_script_class(path, fi->type, fi->script_class_name, fi->script_class_extends, fi->script_class_icon_path);
|
|
|
|
|
}
|
|
|
|
|
if (fi->type == SNAME("PackedScene")) {
|
|
|
|
|
_queue_update_scene_groups(path);
|
|
|
|
@ -973,16 +1072,16 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p_dir->files.push_back(fi);
|
|
|
|
|
p_progress.update(idx, total);
|
|
|
|
|
p_progress.increment();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const ScanProgress &p_progress) {
|
|
|
|
|
void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress &p_progress) {
|
|
|
|
|
uint64_t current_mtime = FileAccess::get_modified_time(p_dir->get_path());
|
|
|
|
|
|
|
|
|
|
bool updated_dir = false;
|
|
|
|
|
String cd = p_dir->get_path();
|
|
|
|
|
int diff_nb_files = 0;
|
|
|
|
|
|
|
|
|
|
if (current_mtime != p_dir->modified_time || using_fat32_or_exfat) {
|
|
|
|
|
updated_dir = true;
|
|
|
|
@ -999,6 +1098,8 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
|
|
|
|
p_dir->get_subdir(i)->verified = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diff_nb_files -= p_dir->files.size();
|
|
|
|
|
|
|
|
|
|
//then scan files and directories and check what's different
|
|
|
|
|
|
|
|
|
|
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
|
|
|
@ -1024,17 +1125,25 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
|
|
|
|
|
|
|
|
|
int idx = p_dir->find_dir_index(f);
|
|
|
|
|
if (idx == -1) {
|
|
|
|
|
if (_should_skip_directory(cd.path_join(f))) {
|
|
|
|
|
String dir_path = cd.path_join(f);
|
|
|
|
|
if (_should_skip_directory(dir_path)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditorFileSystemDirectory *efd = memnew(EditorFileSystemDirectory);
|
|
|
|
|
ScannedDirectory sd;
|
|
|
|
|
sd.name = f;
|
|
|
|
|
sd.full_path = dir_path;
|
|
|
|
|
|
|
|
|
|
EditorFileSystemDirectory *efd = memnew(EditorFileSystemDirectory);
|
|
|
|
|
efd->parent = p_dir;
|
|
|
|
|
efd->name = f;
|
|
|
|
|
|
|
|
|
|
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
|
|
|
|
d->change_dir(cd.path_join(f));
|
|
|
|
|
_scan_new_dir(efd, d, p_progress.get_sub(1, 1));
|
|
|
|
|
d->change_dir(dir_path);
|
|
|
|
|
int nb_files_dir = _scan_new_dir(&sd, d);
|
|
|
|
|
p_progress.hi += nb_files_dir;
|
|
|
|
|
diff_nb_files += nb_files_dir;
|
|
|
|
|
_process_file_system(&sd, efd, p_progress);
|
|
|
|
|
|
|
|
|
|
ItemAction ia;
|
|
|
|
|
ia.action = ItemAction::ACTION_DIR_ADD;
|
|
|
|
@ -1088,7 +1197,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
|
|
|
|
ia.file = f;
|
|
|
|
|
scan_actions.push_back(ia);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diff_nb_files++;
|
|
|
|
|
} else {
|
|
|
|
|
p_dir->files[idx]->verified = true;
|
|
|
|
|
}
|
|
|
|
@ -1106,6 +1215,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
|
|
|
|
ia.dir = p_dir;
|
|
|
|
|
ia.file = p_dir->files[i]->file;
|
|
|
|
|
scan_actions.push_back(ia);
|
|
|
|
|
diff_nb_files--;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1152,10 +1262,16 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
|
|
|
|
scan_actions.push_back(ia);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p_progress.increment();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < p_dir->subdirs.size(); i++) {
|
|
|
|
|
if ((updated_dir && !p_dir->subdirs[i]->verified) || _should_skip_directory(p_dir->subdirs[i]->get_path())) {
|
|
|
|
|
// Add all the files of the folder to be sure _update_scan_actions process the removed files
|
|
|
|
|
// for global class names.
|
|
|
|
|
diff_nb_files += _insert_actions_delete_files_directory(p_dir->subdirs[i]);
|
|
|
|
|
|
|
|
|
|
//this directory was removed or ignored, add action to remove it
|
|
|
|
|
ItemAction ia;
|
|
|
|
|
ia.action = ItemAction::ACTION_DIR_REMOVE;
|
|
|
|
@ -1165,6 +1281,8 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
|
|
|
|
}
|
|
|
|
|
_scan_fs_changes(p_dir->get_subdir(i), p_progress);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nb_files_total = MAX(nb_files_total + diff_nb_files, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_delete_internal_files(const String &p_file) {
|
|
|
|
@ -1179,19 +1297,64 @@ void EditorFileSystem::_delete_internal_files(const String &p_file) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int EditorFileSystem::_insert_actions_delete_files_directory(EditorFileSystemDirectory *p_dir) {
|
|
|
|
|
int nb_files = 0;
|
|
|
|
|
for (EditorFileSystemDirectory::FileInfo *fi : p_dir->files) {
|
|
|
|
|
ItemAction ia;
|
|
|
|
|
ia.action = ItemAction::ACTION_FILE_REMOVE;
|
|
|
|
|
ia.dir = p_dir;
|
|
|
|
|
ia.file = fi->file;
|
|
|
|
|
scan_actions.push_back(ia);
|
|
|
|
|
nb_files++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (EditorFileSystemDirectory *sub_dir : p_dir->subdirs) {
|
|
|
|
|
nb_files += _insert_actions_delete_files_directory(sub_dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nb_files;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_thread_func_sources(void *_userdata) {
|
|
|
|
|
EditorFileSystem *efs = (EditorFileSystem *)_userdata;
|
|
|
|
|
if (efs->filesystem) {
|
|
|
|
|
EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
|
|
|
|
|
ScanProgress sp;
|
|
|
|
|
sp.progress = ≺
|
|
|
|
|
sp.hi = 1;
|
|
|
|
|
sp.low = 0;
|
|
|
|
|
sp.hi = efs->nb_files_total;
|
|
|
|
|
efs->_scan_fs_changes(efs->filesystem, sp);
|
|
|
|
|
}
|
|
|
|
|
efs->scanning_changes_done.set();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_remove_invalid_global_class_names(const HashSet<String> &p_existing_class_names) {
|
|
|
|
|
List<StringName> global_classes;
|
|
|
|
|
ScriptServer::get_global_class_list(&global_classes);
|
|
|
|
|
for (const StringName &class_name : global_classes) {
|
|
|
|
|
if (!p_existing_class_names.has(class_name)) {
|
|
|
|
|
ScriptServer::remove_global_class(class_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String EditorFileSystem::_get_file_by_class_name(EditorFileSystemDirectory *p_dir, const String &p_class_name, EditorFileSystemDirectory::FileInfo *&r_file_info) {
|
|
|
|
|
for (EditorFileSystemDirectory::FileInfo *fi : p_dir->files) {
|
|
|
|
|
if (fi->script_class_name == p_class_name) {
|
|
|
|
|
r_file_info = fi;
|
|
|
|
|
return p_dir->get_path().path_join(fi->file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (EditorFileSystemDirectory *sub_dir : p_dir->subdirs) {
|
|
|
|
|
String file = _get_file_by_class_name(sub_dir, p_class_name, r_file_info);
|
|
|
|
|
if (!file.is_empty()) {
|
|
|
|
|
return file;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
r_file_info = nullptr;
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::scan_changes() {
|
|
|
|
|
if (first_scan || // Prevent a premature changes scan from inhibiting the first full scan
|
|
|
|
|
scanning || scanning_changes || thread.is_started()) {
|
|
|
|
@ -1210,14 +1373,10 @@ void EditorFileSystem::scan_changes() {
|
|
|
|
|
EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
|
|
|
|
|
ScanProgress sp;
|
|
|
|
|
sp.progress = ≺
|
|
|
|
|
sp.hi = 1;
|
|
|
|
|
sp.low = 0;
|
|
|
|
|
sp.hi = nb_files_total;
|
|
|
|
|
scan_total = 0;
|
|
|
|
|
_scan_fs_changes(filesystem, sp);
|
|
|
|
|
bool changed = _update_scan_actions();
|
|
|
|
|
_update_pending_script_classes();
|
|
|
|
|
_update_pending_scene_groups();
|
|
|
|
|
if (changed) {
|
|
|
|
|
if (_update_scan_actions()) {
|
|
|
|
|
emit_signal(SNAME("filesystem_changed"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1282,13 +1441,13 @@ void EditorFileSystem::_notification(int p_what) {
|
|
|
|
|
thread_sources.wait_to_finish();
|
|
|
|
|
}
|
|
|
|
|
bool changed = _update_scan_actions();
|
|
|
|
|
_update_pending_script_classes();
|
|
|
|
|
_update_pending_scene_groups();
|
|
|
|
|
// Set first_scan to false before the signals so the function doing_first_scan can return false
|
|
|
|
|
// in editor_node to start the export if needed.
|
|
|
|
|
first_scan = false;
|
|
|
|
|
if (changed) {
|
|
|
|
|
emit_signal(SNAME("filesystem_changed"));
|
|
|
|
|
}
|
|
|
|
|
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
|
|
|
|
|
first_scan = false;
|
|
|
|
|
scanning_changes = false; // Changed to false here to prevent recursive triggering of scan thread.
|
|
|
|
|
done_importing = true;
|
|
|
|
|
}
|
|
|
|
@ -1302,13 +1461,13 @@ void EditorFileSystem::_notification(int p_what) {
|
|
|
|
|
new_filesystem = nullptr;
|
|
|
|
|
thread.wait_to_finish();
|
|
|
|
|
_update_scan_actions();
|
|
|
|
|
_update_pending_script_classes();
|
|
|
|
|
_update_pending_scene_groups();
|
|
|
|
|
// Update all icons so they are loaded for the FileSystemDock.
|
|
|
|
|
_update_files_icon_path();
|
|
|
|
|
// Set first_scan to false before the signals so the function doing_first_scan can return false
|
|
|
|
|
// in editor_node to start the export if needed.
|
|
|
|
|
first_scan = false;
|
|
|
|
|
emit_signal(SNAME("filesystem_changed"));
|
|
|
|
|
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
|
|
|
|
|
first_scan = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (done_importing && scan_changes_pending) {
|
|
|
|
@ -1323,7 +1482,7 @@ void EditorFileSystem::_notification(int p_what) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool EditorFileSystem::is_scanning() const {
|
|
|
|
|
return scanning || scanning_changes;
|
|
|
|
|
return scanning || scanning_changes || first_scan;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float EditorFileSystem::get_scanning_progress() const {
|
|
|
|
@ -1624,14 +1783,41 @@ void EditorFileSystem::_update_files_icon_path(EditorFileSystemDirectory *edp) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_update_script_classes() {
|
|
|
|
|
update_script_mutex.lock();
|
|
|
|
|
|
|
|
|
|
for (const String &path : update_script_paths) {
|
|
|
|
|
EditorFileSystem::get_singleton()->register_global_class_script(path, path);
|
|
|
|
|
if (update_script_paths.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse documentation second, as it requires the class names to be correct and registered
|
|
|
|
|
for (const String &path : update_script_paths) {
|
|
|
|
|
update_script_mutex.lock();
|
|
|
|
|
|
|
|
|
|
for (const KeyValue<String, ScriptInfo> &E : update_script_paths) {
|
|
|
|
|
_register_global_class_script(E.key, E.key, E.value.type, E.value.script_class_name, E.value.script_class_extends, E.value.script_class_icon_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_script_paths.clear();
|
|
|
|
|
update_script_mutex.unlock();
|
|
|
|
|
|
|
|
|
|
ScriptServer::save_global_classes();
|
|
|
|
|
EditorNode::get_editor_data().script_class_save_icon_paths();
|
|
|
|
|
|
|
|
|
|
emit_signal("script_classes_updated");
|
|
|
|
|
|
|
|
|
|
// Rescan custom loaders and savers.
|
|
|
|
|
// Doing the following here because the `filesystem_changed` signal fires multiple times and isn't always followed by script classes update.
|
|
|
|
|
// So I thought it's better to do this when script classes really get updated
|
|
|
|
|
ResourceLoader::remove_custom_loaders();
|
|
|
|
|
ResourceLoader::add_custom_loaders();
|
|
|
|
|
ResourceSaver::remove_custom_savers();
|
|
|
|
|
ResourceSaver::add_custom_savers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_update_script_documentation() {
|
|
|
|
|
if (update_script_paths_documentation.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_script_mutex.lock();
|
|
|
|
|
|
|
|
|
|
for (const String &path : update_script_paths_documentation) {
|
|
|
|
|
int index = -1;
|
|
|
|
|
EditorFileSystemDirectory *efd = find_file(path, &index);
|
|
|
|
|
|
|
|
|
@ -1655,40 +1841,38 @@ void EditorFileSystem::_update_script_classes() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_script_paths.clear();
|
|
|
|
|
update_script_paths_documentation.clear();
|
|
|
|
|
update_script_mutex.unlock();
|
|
|
|
|
|
|
|
|
|
ScriptServer::save_global_classes();
|
|
|
|
|
EditorNode::get_editor_data().script_class_save_icon_paths();
|
|
|
|
|
emit_signal("script_classes_updated");
|
|
|
|
|
|
|
|
|
|
// Rescan custom loaders and savers.
|
|
|
|
|
// Doing the following here because the `filesystem_changed` signal fires multiple times and isn't always followed by script classes update.
|
|
|
|
|
// So I thought it's better to do this when script classes really get updated
|
|
|
|
|
ResourceLoader::remove_custom_loaders();
|
|
|
|
|
ResourceLoader::add_custom_loaders();
|
|
|
|
|
ResourceSaver::remove_custom_savers();
|
|
|
|
|
ResourceSaver::add_custom_savers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_update_pending_script_classes() {
|
|
|
|
|
if (!update_script_paths.is_empty()) {
|
|
|
|
|
_update_script_classes();
|
|
|
|
|
} else {
|
|
|
|
|
// In case the class cache file was removed somehow, regenerate it.
|
|
|
|
|
if (!FileAccess::exists(ScriptServer::get_global_class_cache_file_path())) {
|
|
|
|
|
ScriptServer::save_global_classes();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void EditorFileSystem::_process_update_pending() {
|
|
|
|
|
_update_script_classes();
|
|
|
|
|
// Parse documentation second, as it requires the class names to be loaded
|
|
|
|
|
// because _update_script_documentation loads the scripts completely.
|
|
|
|
|
_update_script_documentation();
|
|
|
|
|
_update_pending_scene_groups();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_queue_update_script_class(const String &p_path) {
|
|
|
|
|
void EditorFileSystem::_queue_update_script_class(const String &p_path, const String &p_type, const String &p_script_class_name, const String &p_script_class_extends, const String &p_script_class_icon_path) {
|
|
|
|
|
update_script_mutex.lock();
|
|
|
|
|
update_script_paths.insert(p_path);
|
|
|
|
|
|
|
|
|
|
ScriptInfo si;
|
|
|
|
|
si.type = p_type;
|
|
|
|
|
si.script_class_name = p_script_class_name;
|
|
|
|
|
si.script_class_extends = p_script_class_extends;
|
|
|
|
|
si.script_class_icon_path = p_script_class_icon_path;
|
|
|
|
|
update_script_paths.insert(p_path, si);
|
|
|
|
|
|
|
|
|
|
update_script_paths_documentation.insert(p_path);
|
|
|
|
|
|
|
|
|
|
update_script_mutex.unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::_update_scene_groups() {
|
|
|
|
|
if (update_scene_paths.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EditorProgress *ep = nullptr;
|
|
|
|
|
if (update_scene_paths.size() > 1) {
|
|
|
|
|
ep = memnew(EditorProgress("update_scene_groups", TTR("Update Scene Groups"), update_scene_paths.size()));
|
|
|
|
@ -1787,7 +1971,7 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
|
|
|
|
|
_queue_update_script_class(file);
|
|
|
|
|
_queue_update_script_class(file, fs->files[cpos]->type, "", "", "");
|
|
|
|
|
if (!fs->files[cpos]->script_class_icon_path.is_empty()) {
|
|
|
|
|
update_files_icon_cache = true;
|
|
|
|
|
}
|
|
|
|
@ -1840,6 +2024,7 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const String old_script_class_icon_path = fs->files[cpos]->script_class_icon_path;
|
|
|
|
|
const String old_class_name = fs->files[cpos]->script_class_name;
|
|
|
|
|
fs->files[cpos]->type = type;
|
|
|
|
|
fs->files[cpos]->resource_script_class = script_class;
|
|
|
|
|
fs->files[cpos]->uid = uid;
|
|
|
|
@ -1862,23 +2047,32 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
|
|
|
|
|
EditorResourcePreview::get_singleton()->check_for_invalidation(file);
|
|
|
|
|
|
|
|
|
|
if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
|
|
|
|
|
_queue_update_script_class(file);
|
|
|
|
|
_queue_update_script_class(file, fs->files[cpos]->type, fs->files[cpos]->script_class_name, fs->files[cpos]->script_class_extends, fs->files[cpos]->script_class_icon_path);
|
|
|
|
|
}
|
|
|
|
|
if (fs->files[cpos]->type == SNAME("PackedScene")) {
|
|
|
|
|
_queue_update_scene_groups(file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fs->files[cpos]->type == SNAME("Resource")) {
|
|
|
|
|
files_to_update_icon_path.push_back(fs->files[cpos]);
|
|
|
|
|
} else if (old_script_class_icon_path != fs->files[cpos]->script_class_icon_path) {
|
|
|
|
|
update_files_icon_cache = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Restore another script as the global class name if multiple scripts had the same old class name.
|
|
|
|
|
if (!old_class_name.is_empty() && fs->files[cpos]->script_class_name != old_class_name && ClassDB::is_parent_class(type, SNAME("Script"))) {
|
|
|
|
|
EditorFileSystemDirectory::FileInfo *old_fi = nullptr;
|
|
|
|
|
String old_file = _get_file_by_class_name(filesystem, old_class_name, old_fi);
|
|
|
|
|
if (!old_file.is_empty() && old_fi) {
|
|
|
|
|
_queue_update_script_class(old_file, old_fi->type, old_fi->script_class_name, old_fi->script_class_extends, old_fi->script_class_icon_path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
updated = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (updated) {
|
|
|
|
|
_update_pending_script_classes();
|
|
|
|
|
_update_pending_scene_groups();
|
|
|
|
|
_process_update_pending();
|
|
|
|
|
if (update_files_icon_cache) {
|
|
|
|
|
_update_files_icon_path();
|
|
|
|
|
} else {
|
|
|
|
@ -1894,31 +2088,37 @@ HashSet<String> EditorFileSystem::get_valid_extensions() const {
|
|
|
|
|
return valid_extensions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::register_global_class_script(const String &p_search_path, const String &p_target_path) {
|
|
|
|
|
void EditorFileSystem::_register_global_class_script(const String &p_search_path, const String &p_target_path, const String &p_type, const String &p_script_class_name, const String &p_script_class_extends, const String &p_script_class_icon_path) {
|
|
|
|
|
ScriptServer::remove_global_class_by_path(p_search_path); // First remove, just in case it changed
|
|
|
|
|
|
|
|
|
|
int index = -1;
|
|
|
|
|
EditorFileSystemDirectory *efd = find_file(p_search_path, &index);
|
|
|
|
|
|
|
|
|
|
if (!efd || index < 0) {
|
|
|
|
|
// The file was removed
|
|
|
|
|
if (p_script_class_name.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!efd->files[index]->script_class_name.is_empty()) {
|
|
|
|
|
String lang;
|
|
|
|
|
for (int j = 0; j < ScriptServer::get_language_count(); j++) {
|
|
|
|
|
if (ScriptServer::get_language(j)->handles_global_class_type(efd->files[index]->type)) {
|
|
|
|
|
lang = ScriptServer::get_language(j)->get_name();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (lang.is_empty()) {
|
|
|
|
|
return; // No lang found that can handle this global class
|
|
|
|
|
String lang;
|
|
|
|
|
for (int j = 0; j < ScriptServer::get_language_count(); j++) {
|
|
|
|
|
if (ScriptServer::get_language(j)->handles_global_class_type(p_type)) {
|
|
|
|
|
lang = ScriptServer::get_language(j)->get_name();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (lang.is_empty()) {
|
|
|
|
|
return; // No lang found that can handle this global class
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ScriptServer::add_global_class(efd->files[index]->script_class_name, efd->files[index]->script_class_extends, lang, p_target_path);
|
|
|
|
|
EditorNode::get_editor_data().script_class_set_icon_path(efd->files[index]->script_class_name, efd->files[index]->script_class_icon_path);
|
|
|
|
|
EditorNode::get_editor_data().script_class_set_name(p_target_path, efd->files[index]->script_class_name);
|
|
|
|
|
ScriptServer::add_global_class(p_script_class_name, p_script_class_extends, lang, p_target_path);
|
|
|
|
|
EditorNode::get_editor_data().script_class_set_icon_path(p_script_class_name, p_script_class_icon_path);
|
|
|
|
|
EditorNode::get_editor_data().script_class_set_name(p_target_path, p_script_class_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorFileSystem::register_global_class_script(const String &p_search_path, const String &p_target_path) {
|
|
|
|
|
int index_file;
|
|
|
|
|
EditorFileSystemDirectory *efsd = find_file(p_search_path, &index_file);
|
|
|
|
|
if (efsd) {
|
|
|
|
|
const EditorFileSystemDirectory::FileInfo *fi = efsd->files[index_file];
|
|
|
|
|
EditorFileSystem::get_singleton()->_register_global_class_script(p_search_path, p_target_path, fi->type, fi->script_class_name, fi->script_class_extends, fi->script_class_icon_path);
|
|
|
|
|
} else {
|
|
|
|
|
ScriptServer::remove_global_class_by_path(p_search_path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2542,8 +2742,7 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
|
|
|
|
|
ResourceUID::get_singleton()->update_cache(); // After reimporting, update the cache.
|
|
|
|
|
|
|
|
|
|
_save_filesystem_cache();
|
|
|
|
|
_update_pending_script_classes();
|
|
|
|
|
_update_pending_scene_groups();
|
|
|
|
|
_process_update_pending();
|
|
|
|
|
importing = false;
|
|
|
|
|
if (!is_scanning()) {
|
|
|
|
|
emit_signal(SNAME("filesystem_changed"));
|
|
|
|
|