Merge pull request #92303 from Hilderin/fix-synchronization-global-class-name
Fix synchronization of global class name
This commit is contained in:
commit
d4b7ede882
|
@ -55,11 +55,6 @@ void EditorAutoloadSettings::_notification(int p_what) {
|
||||||
file_dialog->add_filter("*." + E);
|
file_dialog->add_filter("*." + E);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const AutoloadInfo &info : autoload_cache) {
|
|
||||||
if (info.node && info.in_editor) {
|
|
||||||
callable_mp((Node *)get_tree()->get_root(), &Node::add_child).call_deferred(info.node, false, Node::INTERNAL_MODE_DISABLED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
browse_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
|
browse_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -419,6 +414,8 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
|
||||||
|
|
||||||
Ref<Script> scr = res;
|
Ref<Script> scr = res;
|
||||||
if (scr.is_valid()) {
|
if (scr.is_valid()) {
|
||||||
|
ERR_FAIL_COND_V_MSG(!scr->is_valid(), nullptr, vformat("Failed to create an autoload, script '%s' is not compiling.", p_path));
|
||||||
|
|
||||||
StringName ibt = scr->get_instance_base_type();
|
StringName ibt = scr->get_instance_base_type();
|
||||||
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
|
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
|
||||||
ERR_FAIL_COND_V_MSG(!valid_type, nullptr, vformat("Failed to create an autoload, script '%s' does not inherit from 'Node'.", p_path));
|
ERR_FAIL_COND_V_MSG(!valid_type, nullptr, vformat("Failed to create an autoload, script '%s' does not inherit from 'Node'.", p_path));
|
||||||
|
@ -436,6 +433,35 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorAutoloadSettings::init_autoloads() {
|
||||||
|
for (AutoloadInfo &info : autoload_cache) {
|
||||||
|
info.node = _create_autoload(info.path);
|
||||||
|
|
||||||
|
if (info.node) {
|
||||||
|
Ref<Script> scr = info.node->get_script();
|
||||||
|
info.in_editor = scr.is_valid() && scr->is_tool();
|
||||||
|
info.node->set_name(info.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.is_singleton) {
|
||||||
|
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||||
|
ScriptServer::get_language(i)->add_named_global_constant(info.name, info.node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.is_singleton && !info.in_editor && info.node != nullptr) {
|
||||||
|
memdelete(info.node);
|
||||||
|
info.node = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const AutoloadInfo &info : autoload_cache) {
|
||||||
|
if (info.node && info.in_editor) {
|
||||||
|
callable_mp((Node *)get_tree()->get_root(), &Node::add_child).call_deferred(info.node, false, Node::INTERNAL_MODE_DISABLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorAutoloadSettings::update_autoload() {
|
void EditorAutoloadSettings::update_autoload() {
|
||||||
if (updating_autoload) {
|
if (updating_autoload) {
|
||||||
return;
|
return;
|
||||||
|
@ -857,27 +883,6 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
|
||||||
autoload_cache.push_back(info);
|
autoload_cache.push_back(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (AutoloadInfo &info : autoload_cache) {
|
|
||||||
info.node = _create_autoload(info.path);
|
|
||||||
|
|
||||||
if (info.node) {
|
|
||||||
Ref<Script> scr = info.node->get_script();
|
|
||||||
info.in_editor = scr.is_valid() && scr->is_tool();
|
|
||||||
info.node->set_name(info.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.is_singleton) {
|
|
||||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
|
||||||
ScriptServer::get_language(i)->add_named_global_constant(info.name, info.node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info.is_singleton && !info.in_editor && info.node != nullptr) {
|
|
||||||
memdelete(info.node);
|
|
||||||
info.node = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HBoxContainer *hbc = memnew(HBoxContainer);
|
HBoxContainer *hbc = memnew(HBoxContainer);
|
||||||
add_child(hbc);
|
add_child(hbc);
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,7 @@ protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void init_autoloads();
|
||||||
void update_autoload();
|
void update_autoload();
|
||||||
bool autoload_add(const String &p_name, const String &p_path);
|
bool autoload_add(const String &p_name, const String &p_path);
|
||||||
void autoload_remove(const String &p_name);
|
void autoload_remove(const String &p_name);
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "editor/editor_paths.h"
|
#include "editor/editor_paths.h"
|
||||||
#include "editor/editor_resource_preview.h"
|
#include "editor/editor_resource_preview.h"
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
|
#include "editor/project_settings_editor.h"
|
||||||
#include "scene/resources/packed_scene.h"
|
#include "scene/resources/packed_scene.h"
|
||||||
|
|
||||||
EditorFileSystem *EditorFileSystem::singleton = nullptr;
|
EditorFileSystem *EditorFileSystem::singleton = nullptr;
|
||||||
|
@ -206,17 +207,68 @@ EditorFileSystemDirectory::EditorFileSystemDirectory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorFileSystemDirectory::~EditorFileSystemDirectory() {
|
EditorFileSystemDirectory::~EditorFileSystemDirectory() {
|
||||||
for (int i = 0; i < files.size(); i++) {
|
for (EditorFileSystemDirectory::FileInfo *fi : files) {
|
||||||
memdelete(files[i]);
|
memdelete(fi);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < subdirs.size(); i++) {
|
for (EditorFileSystemDirectory *dir : subdirs) {
|
||||||
memdelete(subdirs[i]);
|
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() {
|
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
|
//read .fscache
|
||||||
String cpath;
|
String cpath;
|
||||||
|
@ -318,23 +370,33 @@ void EditorFileSystem::_scan_filesystem() {
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorProgressBG scan_progress("efs", "ScanFS", 1000);
|
EditorProgressBG scan_progress("efs", "ScanFS", 1000);
|
||||||
|
|
||||||
ScanProgress sp;
|
ScanProgress sp;
|
||||||
sp.low = 0;
|
sp.hi = nb_files_total;
|
||||||
sp.hi = 1;
|
|
||||||
sp.progress = &scan_progress;
|
sp.progress = &scan_progress;
|
||||||
|
|
||||||
new_filesystem = memnew(EditorFileSystemDirectory);
|
new_filesystem = memnew(EditorFileSystemDirectory);
|
||||||
new_filesystem->parent = nullptr;
|
new_filesystem->parent = nullptr;
|
||||||
|
|
||||||
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
ScannedDirectory *sd;
|
||||||
d->change_dir("res://");
|
// On the first scan, the first_scan_root_dir is created in _first_scan_filesystem.
|
||||||
_scan_new_dir(new_filesystem, d, sp);
|
if (first_scan) {
|
||||||
dep_update_list.clear();
|
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
|
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
|
//on the first scan this is done from the main thread after re-importing
|
||||||
_save_filesystem_cache();
|
_save_filesystem_cache();
|
||||||
}
|
}
|
||||||
|
@ -567,6 +629,10 @@ bool EditorFileSystem::_scan_import_support(const Vector<String> &reimports) {
|
||||||
bool EditorFileSystem::_update_scan_actions() {
|
bool EditorFileSystem::_update_scan_actions() {
|
||||||
sources_changed.clear();
|
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;
|
bool fs_changed = false;
|
||||||
|
|
||||||
Vector<String> reimports;
|
Vector<String> reimports;
|
||||||
|
@ -615,7 +681,7 @@ bool EditorFileSystem::_update_scan_actions() {
|
||||||
fs_changed = true;
|
fs_changed = true;
|
||||||
|
|
||||||
if (ClassDB::is_parent_class(ia.new_file->type, SNAME("Script"))) {
|
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")) {
|
if (ia.new_file->type == SNAME("PackedScene")) {
|
||||||
_queue_update_scene_groups(ia.dir->get_file_path(idx));
|
_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);
|
int idx = ia.dir->find_file_index(ia.file);
|
||||||
ERR_CONTINUE(idx == -1);
|
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"))) {
|
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")) {
|
if (ia.dir->files[idx]->type == SNAME("PackedScene")) {
|
||||||
_queue_update_scene_groups(ia.dir->get_file_path(idx));
|
_queue_update_scene_groups(ia.dir->get_file_path(idx));
|
||||||
|
@ -637,6 +704,15 @@ bool EditorFileSystem::_update_scan_actions() {
|
||||||
memdelete(ia.dir->files[idx]);
|
memdelete(ia.dir->files[idx]);
|
||||||
ia.dir->files.remove_at(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;
|
fs_changed = true;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
@ -667,10 +743,11 @@ bool EditorFileSystem::_update_scan_actions() {
|
||||||
ERR_CONTINUE(idx == -1);
|
ERR_CONTINUE(idx == -1);
|
||||||
String full_path = ia.dir->get_file_path(idx);
|
String full_path = ia.dir->get_file_path(idx);
|
||||||
|
|
||||||
if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
|
const EditorFileSystemDirectory::FileInfo *fi = ia.dir->files[idx];
|
||||||
_queue_update_script_class(full_path);
|
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);
|
_queue_update_scene_groups(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,6 +788,10 @@ bool EditorFileSystem::_update_scan_actions() {
|
||||||
_save_filesystem_cache();
|
_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()) {
|
if (reloads.size()) {
|
||||||
emit_signal(SNAME("resources_reload"), reloads);
|
emit_signal(SNAME("resources_reload"), reloads);
|
||||||
}
|
}
|
||||||
|
@ -728,6 +809,14 @@ void EditorFileSystem::scan() {
|
||||||
return;
|
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();
|
_update_extensions();
|
||||||
|
|
||||||
if (!use_threads) {
|
if (!use_threads) {
|
||||||
|
@ -741,14 +830,14 @@ void EditorFileSystem::scan() {
|
||||||
filesystem = new_filesystem;
|
filesystem = new_filesystem;
|
||||||
new_filesystem = nullptr;
|
new_filesystem = nullptr;
|
||||||
_update_scan_actions();
|
_update_scan_actions();
|
||||||
scanning = false;
|
|
||||||
_update_pending_script_classes();
|
|
||||||
_update_pending_scene_groups();
|
|
||||||
// Update all icons so they are loaded for the FileSystemDock.
|
// Update all icons so they are loaded for the FileSystemDock.
|
||||||
_update_files_icon_path();
|
_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("filesystem_changed"));
|
||||||
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
|
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
|
||||||
first_scan = false;
|
|
||||||
} else {
|
} else {
|
||||||
ERR_FAIL_COND(thread.is_started());
|
ERR_FAIL_COND(thread.is_started());
|
||||||
set_process(true);
|
set_process(true);
|
||||||
|
@ -762,28 +851,19 @@ void EditorFileSystem::scan() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorFileSystem::ScanProgress::update(int p_current, int p_total) const {
|
void EditorFileSystem::ScanProgress::increment() {
|
||||||
float ratio = low + ((hi - low) / p_total) * p_current;
|
current++;
|
||||||
progress->step(ratio * 1000);
|
float ratio = current / MAX(hi, 1.0f);
|
||||||
|
progress->step(ratio * 1000.0f);
|
||||||
EditorFileSystem::singleton->scan_total = ratio;
|
EditorFileSystem::singleton->scan_total = ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorFileSystem::ScanProgress EditorFileSystem::ScanProgress::get_sub(int p_current, int p_total) const {
|
int EditorFileSystem::_scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da) {
|
||||||
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) {
|
|
||||||
List<String> dirs;
|
List<String> dirs;
|
||||||
List<String> files;
|
List<String> files;
|
||||||
|
|
||||||
String cd = da->get_current_dir();
|
String cd = da->get_current_dir();
|
||||||
|
|
||||||
p_dir->modified_time = FileAccess::get_modified_time(cd);
|
|
||||||
|
|
||||||
da->list_dir_begin();
|
da->list_dir_begin();
|
||||||
while (true) {
|
while (true) {
|
||||||
String f = da->get_next();
|
String f = da->get_next();
|
||||||
|
@ -816,55 +896,59 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
|
||||||
dirs.sort_custom<FileNoCaseComparator>();
|
dirs.sort_custom<FileNoCaseComparator>();
|
||||||
files.sort_custom<FileNoCaseComparator>();
|
files.sort_custom<FileNoCaseComparator>();
|
||||||
|
|
||||||
int total = dirs.size() + files.size();
|
int nb_files_total_scan = 0;
|
||||||
int idx = 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) {
|
if (da->change_dir(E->get()) == OK) {
|
||||||
String d = da->get_current_dir();
|
String d = da->get_current_dir();
|
||||||
|
|
||||||
if (d == cd || !d.begins_with(cd)) {
|
if (d == cd || !d.begins_with(cd)) {
|
||||||
da->change_dir(cd); //avoid recursion
|
da->change_dir(cd); //avoid recursion
|
||||||
} else {
|
} 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;
|
nb_files_total_scan += _scan_new_dir(sd, da);
|
||||||
efd->name = E->get();
|
|
||||||
|
|
||||||
_scan_new_dir(efd, da, p_progress.get_sub(idx, total));
|
p_dir->subdirs.push_back(sd);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
da->change_dir("..");
|
da->change_dir("..");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ERR_PRINT("Cannot go into subdir '" + E->get() + "'.");
|
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++) {
|
p_dir->files = files;
|
||||||
String ext = E->get().get_extension().to_lower();
|
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)) {
|
if (!valid_extensions.has(ext)) {
|
||||||
|
p_progress.increment();
|
||||||
continue; //invalid
|
continue; //invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
|
String path = p_scan_dir->full_path.path_join(scan_file);
|
||||||
fi->file = E->get();
|
|
||||||
|
|
||||||
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);
|
FileCache *fc = file_cache.getptr(path);
|
||||||
uint64_t mt = FileAccess::get_modified_time(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;
|
ItemAction ia;
|
||||||
ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
|
ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
|
||||||
ia.dir = p_dir;
|
ia.dir = p_dir;
|
||||||
ia.file = E->get();
|
ia.file = fi->file;
|
||||||
scan_actions.push_back(ia);
|
scan_actions.push_back(ia);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -923,7 +1007,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
|
||||||
ItemAction ia;
|
ItemAction ia;
|
||||||
ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
|
ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
|
||||||
ia.dir = p_dir;
|
ia.dir = p_dir;
|
||||||
ia.file = E->get();
|
ia.file = fi->file;
|
||||||
scan_actions.push_back(ia);
|
scan_actions.push_back(ia);
|
||||||
}
|
}
|
||||||
} else {
|
} 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_name = fc->script_class_name;
|
||||||
fi->script_class_extends = fc->script_class_extends;
|
fi->script_class_extends = fc->script_class_extends;
|
||||||
fi->script_class_icon_path = fc->script_class_icon_path;
|
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 {
|
} else {
|
||||||
//new or modified time
|
//new or modified time
|
||||||
fi->type = ResourceLoader::get_resource_type(path);
|
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.
|
// 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 (!dep_update_list.has(path)) {
|
||||||
if (ClassDB::is_parent_class(fi->type, SNAME("Script"))) {
|
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")) {
|
if (fi->type == SNAME("PackedScene")) {
|
||||||
_queue_update_scene_groups(path);
|
_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.increment();
|
||||||
p_progress.update(idx, total);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
uint64_t current_mtime = FileAccess::get_modified_time(p_dir->get_path());
|
||||||
|
|
||||||
bool updated_dir = false;
|
bool updated_dir = false;
|
||||||
String cd = p_dir->get_path();
|
String cd = p_dir->get_path();
|
||||||
|
int diff_nb_files = 0;
|
||||||
|
|
||||||
if (current_mtime != p_dir->modified_time || using_fat32_or_exfat) {
|
if (current_mtime != p_dir->modified_time || using_fat32_or_exfat) {
|
||||||
updated_dir = true;
|
updated_dir = true;
|
||||||
|
@ -999,6 +1098,8 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
||||||
p_dir->get_subdir(i)->verified = false;
|
p_dir->get_subdir(i)->verified = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diff_nb_files -= p_dir->files.size();
|
||||||
|
|
||||||
//then scan files and directories and check what's different
|
//then scan files and directories and check what's different
|
||||||
|
|
||||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
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);
|
int idx = p_dir->find_dir_index(f);
|
||||||
if (idx == -1) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorFileSystemDirectory *efd = memnew(EditorFileSystemDirectory);
|
ScannedDirectory sd;
|
||||||
|
sd.name = f;
|
||||||
|
sd.full_path = dir_path;
|
||||||
|
|
||||||
|
EditorFileSystemDirectory *efd = memnew(EditorFileSystemDirectory);
|
||||||
efd->parent = p_dir;
|
efd->parent = p_dir;
|
||||||
efd->name = f;
|
efd->name = f;
|
||||||
|
|
||||||
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||||
d->change_dir(cd.path_join(f));
|
d->change_dir(dir_path);
|
||||||
_scan_new_dir(efd, d, p_progress.get_sub(1, 1));
|
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;
|
ItemAction ia;
|
||||||
ia.action = ItemAction::ACTION_DIR_ADD;
|
ia.action = ItemAction::ACTION_DIR_ADD;
|
||||||
|
@ -1088,7 +1197,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
||||||
ia.file = f;
|
ia.file = f;
|
||||||
scan_actions.push_back(ia);
|
scan_actions.push_back(ia);
|
||||||
}
|
}
|
||||||
|
diff_nb_files++;
|
||||||
} else {
|
} else {
|
||||||
p_dir->files[idx]->verified = true;
|
p_dir->files[idx]->verified = true;
|
||||||
}
|
}
|
||||||
|
@ -1106,6 +1215,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
||||||
ia.dir = p_dir;
|
ia.dir = p_dir;
|
||||||
ia.file = p_dir->files[i]->file;
|
ia.file = p_dir->files[i]->file;
|
||||||
scan_actions.push_back(ia);
|
scan_actions.push_back(ia);
|
||||||
|
diff_nb_files--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1152,10 +1262,16 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
||||||
scan_actions.push_back(ia);
|
scan_actions.push_back(ia);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p_progress.increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < p_dir->subdirs.size(); i++) {
|
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())) {
|
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
|
//this directory was removed or ignored, add action to remove it
|
||||||
ItemAction ia;
|
ItemAction ia;
|
||||||
ia.action = ItemAction::ACTION_DIR_REMOVE;
|
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);
|
_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) {
|
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) {
|
void EditorFileSystem::_thread_func_sources(void *_userdata) {
|
||||||
EditorFileSystem *efs = (EditorFileSystem *)_userdata;
|
EditorFileSystem *efs = (EditorFileSystem *)_userdata;
|
||||||
if (efs->filesystem) {
|
if (efs->filesystem) {
|
||||||
EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
|
EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
|
||||||
ScanProgress sp;
|
ScanProgress sp;
|
||||||
sp.progress = ≺
|
sp.progress = ≺
|
||||||
sp.hi = 1;
|
sp.hi = efs->nb_files_total;
|
||||||
sp.low = 0;
|
|
||||||
efs->_scan_fs_changes(efs->filesystem, sp);
|
efs->_scan_fs_changes(efs->filesystem, sp);
|
||||||
}
|
}
|
||||||
efs->scanning_changes_done.set();
|
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() {
|
void EditorFileSystem::scan_changes() {
|
||||||
if (first_scan || // Prevent a premature changes scan from inhibiting the first full scan
|
if (first_scan || // Prevent a premature changes scan from inhibiting the first full scan
|
||||||
scanning || scanning_changes || thread.is_started()) {
|
scanning || scanning_changes || thread.is_started()) {
|
||||||
|
@ -1210,14 +1373,10 @@ void EditorFileSystem::scan_changes() {
|
||||||
EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
|
EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
|
||||||
ScanProgress sp;
|
ScanProgress sp;
|
||||||
sp.progress = ≺
|
sp.progress = ≺
|
||||||
sp.hi = 1;
|
sp.hi = nb_files_total;
|
||||||
sp.low = 0;
|
|
||||||
scan_total = 0;
|
scan_total = 0;
|
||||||
_scan_fs_changes(filesystem, sp);
|
_scan_fs_changes(filesystem, sp);
|
||||||
bool changed = _update_scan_actions();
|
if (_update_scan_actions()) {
|
||||||
_update_pending_script_classes();
|
|
||||||
_update_pending_scene_groups();
|
|
||||||
if (changed) {
|
|
||||||
emit_signal(SNAME("filesystem_changed"));
|
emit_signal(SNAME("filesystem_changed"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1282,13 +1441,13 @@ void EditorFileSystem::_notification(int p_what) {
|
||||||
thread_sources.wait_to_finish();
|
thread_sources.wait_to_finish();
|
||||||
}
|
}
|
||||||
bool changed = _update_scan_actions();
|
bool changed = _update_scan_actions();
|
||||||
_update_pending_script_classes();
|
// Set first_scan to false before the signals so the function doing_first_scan can return false
|
||||||
_update_pending_scene_groups();
|
// in editor_node to start the export if needed.
|
||||||
|
first_scan = false;
|
||||||
if (changed) {
|
if (changed) {
|
||||||
emit_signal(SNAME("filesystem_changed"));
|
emit_signal(SNAME("filesystem_changed"));
|
||||||
}
|
}
|
||||||
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
|
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.
|
scanning_changes = false; // Changed to false here to prevent recursive triggering of scan thread.
|
||||||
done_importing = true;
|
done_importing = true;
|
||||||
}
|
}
|
||||||
|
@ -1302,13 +1461,13 @@ void EditorFileSystem::_notification(int p_what) {
|
||||||
new_filesystem = nullptr;
|
new_filesystem = nullptr;
|
||||||
thread.wait_to_finish();
|
thread.wait_to_finish();
|
||||||
_update_scan_actions();
|
_update_scan_actions();
|
||||||
_update_pending_script_classes();
|
|
||||||
_update_pending_scene_groups();
|
|
||||||
// Update all icons so they are loaded for the FileSystemDock.
|
// Update all icons so they are loaded for the FileSystemDock.
|
||||||
_update_files_icon_path();
|
_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("filesystem_changed"));
|
||||||
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
|
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
|
||||||
first_scan = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (done_importing && scan_changes_pending) {
|
if (done_importing && scan_changes_pending) {
|
||||||
|
@ -1323,7 +1482,7 @@ void EditorFileSystem::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorFileSystem::is_scanning() const {
|
bool EditorFileSystem::is_scanning() const {
|
||||||
return scanning || scanning_changes;
|
return scanning || scanning_changes || first_scan;
|
||||||
}
|
}
|
||||||
|
|
||||||
float EditorFileSystem::get_scanning_progress() const {
|
float EditorFileSystem::get_scanning_progress() const {
|
||||||
|
@ -1624,14 +1783,41 @@ void EditorFileSystem::_update_files_icon_path(EditorFileSystemDirectory *edp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorFileSystem::_update_script_classes() {
|
void EditorFileSystem::_update_script_classes() {
|
||||||
update_script_mutex.lock();
|
if (update_script_paths.is_empty()) {
|
||||||
|
return;
|
||||||
for (const String &path : update_script_paths) {
|
|
||||||
EditorFileSystem::get_singleton()->register_global_class_script(path, path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse documentation second, as it requires the class names to be correct and registered
|
update_script_mutex.lock();
|
||||||
for (const String &path : update_script_paths) {
|
|
||||||
|
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;
|
int index = -1;
|
||||||
EditorFileSystemDirectory *efd = find_file(path, &index);
|
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();
|
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() {
|
void EditorFileSystem::_process_update_pending() {
|
||||||
if (!update_script_paths.is_empty()) {
|
_update_script_classes();
|
||||||
_update_script_classes();
|
// Parse documentation second, as it requires the class names to be loaded
|
||||||
} else {
|
// because _update_script_documentation loads the scripts completely.
|
||||||
// In case the class cache file was removed somehow, regenerate it.
|
_update_script_documentation();
|
||||||
if (!FileAccess::exists(ScriptServer::get_global_class_cache_file_path())) {
|
_update_pending_scene_groups();
|
||||||
ScriptServer::save_global_classes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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_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();
|
update_script_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorFileSystem::_update_scene_groups() {
|
void EditorFileSystem::_update_scene_groups() {
|
||||||
|
if (update_scene_paths.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EditorProgress *ep = nullptr;
|
EditorProgress *ep = nullptr;
|
||||||
if (update_scene_paths.size() > 1) {
|
if (update_scene_paths.size() > 1) {
|
||||||
ep = memnew(EditorProgress("update_scene_groups", TTR("Update Scene Groups"), update_scene_paths.size()));
|
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"))) {
|
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()) {
|
if (!fs->files[cpos]->script_class_icon_path.is_empty()) {
|
||||||
update_files_icon_cache = true;
|
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_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]->type = type;
|
||||||
fs->files[cpos]->resource_script_class = script_class;
|
fs->files[cpos]->resource_script_class = script_class;
|
||||||
fs->files[cpos]->uid = uid;
|
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);
|
EditorResourcePreview::get_singleton()->check_for_invalidation(file);
|
||||||
|
|
||||||
if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
|
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")) {
|
if (fs->files[cpos]->type == SNAME("PackedScene")) {
|
||||||
_queue_update_scene_groups(file);
|
_queue_update_scene_groups(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs->files[cpos]->type == SNAME("Resource")) {
|
if (fs->files[cpos]->type == SNAME("Resource")) {
|
||||||
files_to_update_icon_path.push_back(fs->files[cpos]);
|
files_to_update_icon_path.push_back(fs->files[cpos]);
|
||||||
} else if (old_script_class_icon_path != fs->files[cpos]->script_class_icon_path) {
|
} else if (old_script_class_icon_path != fs->files[cpos]->script_class_icon_path) {
|
||||||
update_files_icon_cache = true;
|
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;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated) {
|
if (updated) {
|
||||||
_update_pending_script_classes();
|
_process_update_pending();
|
||||||
_update_pending_scene_groups();
|
|
||||||
if (update_files_icon_cache) {
|
if (update_files_icon_cache) {
|
||||||
_update_files_icon_path();
|
_update_files_icon_path();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1894,31 +2088,37 @@ HashSet<String> EditorFileSystem::get_valid_extensions() const {
|
||||||
return valid_extensions;
|
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
|
ScriptServer::remove_global_class_by_path(p_search_path); // First remove, just in case it changed
|
||||||
|
|
||||||
int index = -1;
|
if (p_script_class_name.is_empty()) {
|
||||||
EditorFileSystemDirectory *efd = find_file(p_search_path, &index);
|
|
||||||
|
|
||||||
if (!efd || index < 0) {
|
|
||||||
// The file was removed
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!efd->files[index]->script_class_name.is_empty()) {
|
String lang;
|
||||||
String lang;
|
for (int j = 0; j < ScriptServer::get_language_count(); j++) {
|
||||||
for (int j = 0; j < ScriptServer::get_language_count(); j++) {
|
if (ScriptServer::get_language(j)->handles_global_class_type(p_type)) {
|
||||||
if (ScriptServer::get_language(j)->handles_global_class_type(efd->files[index]->type)) {
|
lang = ScriptServer::get_language(j)->get_name();
|
||||||
lang = ScriptServer::get_language(j)->get_name();
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lang.is_empty()) {
|
|
||||||
return; // No lang found that can handle this global class
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
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);
|
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(efd->files[index]->script_class_name, efd->files[index]->script_class_icon_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, efd->files[index]->script_class_name);
|
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.
|
ResourceUID::get_singleton()->update_cache(); // After reimporting, update the cache.
|
||||||
|
|
||||||
_save_filesystem_cache();
|
_save_filesystem_cache();
|
||||||
_update_pending_script_classes();
|
_process_update_pending();
|
||||||
_update_pending_scene_groups();
|
|
||||||
importing = false;
|
importing = false;
|
||||||
if (!is_scanning()) {
|
if (!is_scanning()) {
|
||||||
emit_signal(SNAME("filesystem_changed"));
|
emit_signal(SNAME("filesystem_changed"));
|
||||||
|
|
|
@ -159,11 +159,21 @@ class EditorFileSystem : public Node {
|
||||||
EditorFileSystemDirectory::FileInfo *new_file = nullptr;
|
EditorFileSystemDirectory::FileInfo *new_file = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ScannedDirectory {
|
||||||
|
String name;
|
||||||
|
String full_path;
|
||||||
|
Vector<ScannedDirectory *> subdirs;
|
||||||
|
List<String> files;
|
||||||
|
|
||||||
|
~ScannedDirectory();
|
||||||
|
};
|
||||||
|
|
||||||
bool use_threads = false;
|
bool use_threads = false;
|
||||||
Thread thread;
|
Thread thread;
|
||||||
static void _thread_func(void *_userdata);
|
static void _thread_func(void *_userdata);
|
||||||
|
|
||||||
EditorFileSystemDirectory *new_filesystem = nullptr;
|
EditorFileSystemDirectory *new_filesystem = nullptr;
|
||||||
|
ScannedDirectory *first_scan_root_dir = nullptr;
|
||||||
|
|
||||||
bool scanning = false;
|
bool scanning = false;
|
||||||
bool importing = false;
|
bool importing = false;
|
||||||
|
@ -172,8 +182,11 @@ class EditorFileSystem : public Node {
|
||||||
float scan_total;
|
float scan_total;
|
||||||
String filesystem_settings_version_for_import;
|
String filesystem_settings_version_for_import;
|
||||||
bool revalidate_import_files = false;
|
bool revalidate_import_files = false;
|
||||||
|
int nb_files_total = 0;
|
||||||
|
|
||||||
void _scan_filesystem();
|
void _scan_filesystem();
|
||||||
|
void _first_scan_filesystem();
|
||||||
|
void _first_scan_process_scripts(const ScannedDirectory *p_scan_dir, HashSet<String> &p_existing_class_names);
|
||||||
|
|
||||||
HashSet<String> late_update_files;
|
HashSet<String> late_update_files;
|
||||||
|
|
||||||
|
@ -202,11 +215,10 @@ class EditorFileSystem : public Node {
|
||||||
HashSet<String> dep_update_list;
|
HashSet<String> dep_update_list;
|
||||||
|
|
||||||
struct ScanProgress {
|
struct ScanProgress {
|
||||||
float low = 0;
|
|
||||||
float hi = 0;
|
float hi = 0;
|
||||||
mutable EditorProgressBG *progress = nullptr;
|
int current = 0;
|
||||||
void update(int p_current, int p_total) const;
|
EditorProgressBG *progress = nullptr;
|
||||||
ScanProgress get_sub(int p_current, int p_total) const;
|
void increment();
|
||||||
};
|
};
|
||||||
|
|
||||||
void _save_filesystem_cache();
|
void _save_filesystem_cache();
|
||||||
|
@ -214,15 +226,17 @@ class EditorFileSystem : public Node {
|
||||||
|
|
||||||
bool _find_file(const String &p_file, EditorFileSystemDirectory **r_d, int &r_file_pos) const;
|
bool _find_file(const String &p_file, EditorFileSystemDirectory **r_d, int &r_file_pos) const;
|
||||||
|
|
||||||
void _scan_fs_changes(EditorFileSystemDirectory *p_dir, const ScanProgress &p_progress);
|
void _scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress &p_progress);
|
||||||
|
|
||||||
void _delete_internal_files(const String &p_file);
|
void _delete_internal_files(const String &p_file);
|
||||||
|
int _insert_actions_delete_files_directory(EditorFileSystemDirectory *p_dir);
|
||||||
|
|
||||||
HashSet<String> textfile_extensions;
|
HashSet<String> textfile_extensions;
|
||||||
HashSet<String> valid_extensions;
|
HashSet<String> valid_extensions;
|
||||||
HashSet<String> import_extensions;
|
HashSet<String> import_extensions;
|
||||||
|
|
||||||
void _scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAccess> &da, const ScanProgress &p_progress);
|
int _scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da);
|
||||||
|
void _process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress);
|
||||||
|
|
||||||
Thread thread_sources;
|
Thread thread_sources;
|
||||||
bool scanning_changes = false;
|
bool scanning_changes = false;
|
||||||
|
@ -256,11 +270,20 @@ class EditorFileSystem : public Node {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ScriptInfo {
|
||||||
|
String type;
|
||||||
|
String script_class_name;
|
||||||
|
String script_class_extends;
|
||||||
|
String script_class_icon_path;
|
||||||
|
};
|
||||||
|
|
||||||
Mutex update_script_mutex;
|
Mutex update_script_mutex;
|
||||||
HashSet<String> update_script_paths;
|
HashMap<String, ScriptInfo> update_script_paths;
|
||||||
void _queue_update_script_class(const String &p_path);
|
HashSet<String> update_script_paths_documentation;
|
||||||
|
void _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);
|
||||||
void _update_script_classes();
|
void _update_script_classes();
|
||||||
void _update_pending_script_classes();
|
void _update_script_documentation();
|
||||||
|
void _process_update_pending();
|
||||||
|
|
||||||
Mutex update_scene_mutex;
|
Mutex update_scene_mutex;
|
||||||
HashSet<String> update_scene_paths;
|
HashSet<String> update_scene_paths;
|
||||||
|
@ -300,6 +323,10 @@ class EditorFileSystem : public Node {
|
||||||
|
|
||||||
void _update_file_icon_path(EditorFileSystemDirectory::FileInfo *file_info);
|
void _update_file_icon_path(EditorFileSystemDirectory::FileInfo *file_info);
|
||||||
void _update_files_icon_path(EditorFileSystemDirectory *edp = nullptr);
|
void _update_files_icon_path(EditorFileSystemDirectory *edp = nullptr);
|
||||||
|
void _remove_invalid_global_class_names(const HashSet<String> &p_existing_class_names);
|
||||||
|
String _get_file_by_class_name(EditorFileSystemDirectory *p_dir, const String &p_class_name, EditorFileSystemDirectory::FileInfo *&r_file_info);
|
||||||
|
|
||||||
|
void _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);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
|
|
@ -706,23 +706,7 @@ void EditorNode::_notification(int p_what) {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_READY: {
|
case NOTIFICATION_READY: {
|
||||||
{
|
started_timestamp = Time::get_singleton()->get_unix_time_from_system();
|
||||||
started_timestamp = Time::get_singleton()->get_unix_time_from_system();
|
|
||||||
_initializing_plugins = true;
|
|
||||||
Vector<String> addons;
|
|
||||||
if (ProjectSettings::get_singleton()->has_setting("editor_plugins/enabled")) {
|
|
||||||
addons = GLOBAL_GET("editor_plugins/enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < addons.size(); i++) {
|
|
||||||
set_addon_plugin_enabled(addons[i], true);
|
|
||||||
}
|
|
||||||
_initializing_plugins = false;
|
|
||||||
|
|
||||||
if (!pending_addons.is_empty()) {
|
|
||||||
EditorFileSystem::get_singleton()->connect("script_classes_updated", callable_mp(this, &EditorNode::_enable_pending_addons));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderingServer::get_singleton()->viewport_set_disable_2d(get_scene_root()->get_viewport_rid(), true);
|
RenderingServer::get_singleton()->viewport_set_disable_2d(get_scene_root()->get_viewport_rid(), true);
|
||||||
RenderingServer::get_singleton()->viewport_set_environment_mode(get_viewport()->get_viewport_rid(), RenderingServer::VIEWPORT_ENVIRONMENT_DISABLED);
|
RenderingServer::get_singleton()->viewport_set_environment_mode(get_viewport()->get_viewport_rid(), RenderingServer::VIEWPORT_ENVIRONMENT_DISABLED);
|
||||||
|
@ -860,6 +844,23 @@ void EditorNode::_update_update_spinner() {
|
||||||
OS::get_singleton()->set_low_processor_usage_mode(!update_continuously);
|
OS::get_singleton()->set_low_processor_usage_mode(!update_continuously);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorNode::init_plugins() {
|
||||||
|
_initializing_plugins = true;
|
||||||
|
Vector<String> addons;
|
||||||
|
if (ProjectSettings::get_singleton()->has_setting("editor_plugins/enabled")) {
|
||||||
|
addons = GLOBAL_GET("editor_plugins/enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const String &addon : addons) {
|
||||||
|
set_addon_plugin_enabled(addon, true);
|
||||||
|
}
|
||||||
|
_initializing_plugins = false;
|
||||||
|
|
||||||
|
if (!pending_addons.is_empty()) {
|
||||||
|
EditorFileSystem::get_singleton()->connect("script_classes_updated", callable_mp(this, &EditorNode::_enable_pending_addons), CONNECT_ONE_SHOT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_name) {
|
void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_name) {
|
||||||
Ref<Script> scr = Object::cast_to<Script>(p_script);
|
Ref<Script> scr = Object::cast_to<Script>(p_script);
|
||||||
if (scr.is_null()) {
|
if (scr.is_null()) {
|
||||||
|
@ -954,6 +955,7 @@ void EditorNode::_fs_changed() {
|
||||||
// FIXME: Move this to a cleaner location, it's hacky to do this in _fs_changed.
|
// FIXME: Move this to a cleaner location, it's hacky to do this in _fs_changed.
|
||||||
String export_error;
|
String export_error;
|
||||||
Error err = OK;
|
Error err = OK;
|
||||||
|
// It's important to wait for the first scan to finish; otherwise, scripts or resources might not be imported.
|
||||||
if (!export_defer.preset.is_empty() && !EditorFileSystem::get_singleton()->is_scanning()) {
|
if (!export_defer.preset.is_empty() && !EditorFileSystem::get_singleton()->is_scanning()) {
|
||||||
String preset_name = export_defer.preset;
|
String preset_name = export_defer.preset;
|
||||||
// Ensures export_project does not loop infinitely, because notifications may
|
// Ensures export_project does not loop infinitely, because notifications may
|
||||||
|
|
|
@ -683,6 +683,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Public for use with callable_mp.
|
// Public for use with callable_mp.
|
||||||
|
void init_plugins();
|
||||||
void _on_plugin_ready(Object *p_script, const String &p_activate_name);
|
void _on_plugin_ready(Object *p_script, const String &p_activate_name);
|
||||||
|
|
||||||
void editor_select(int p_which);
|
void editor_select(int p_which);
|
||||||
|
|
|
@ -546,7 +546,7 @@ void FileSystemDock::_notification(int p_what) {
|
||||||
|
|
||||||
case NOTIFICATION_PROCESS: {
|
case NOTIFICATION_PROCESS: {
|
||||||
if (EditorFileSystem::get_singleton()->is_scanning()) {
|
if (EditorFileSystem::get_singleton()->is_scanning()) {
|
||||||
scanning_progress->set_value(EditorFileSystem::get_singleton()->get_scanning_progress() * 100);
|
scanning_progress->set_value(EditorFileSystem::get_singleton()->get_scanning_progress() * 100.0f);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -414,13 +414,19 @@ void EditorPlugin::remove_translation_parser_plugin(const Ref<EditorTranslationP
|
||||||
void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer, bool p_first_priority) {
|
void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer, bool p_first_priority) {
|
||||||
ERR_FAIL_COND(!p_importer.is_valid());
|
ERR_FAIL_COND(!p_importer.is_valid());
|
||||||
ResourceFormatImporter::get_singleton()->add_importer(p_importer, p_first_priority);
|
ResourceFormatImporter::get_singleton()->add_importer(p_importer, p_first_priority);
|
||||||
callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred();
|
// Plugins are now loaded during the first scan. It's important not to start another scan,
|
||||||
|
// even a deferred one, as it would cause a scan during a scan at the next main thread iteration.
|
||||||
|
if (!EditorFileSystem::get_singleton()->doing_first_scan()) {
|
||||||
|
callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) {
|
void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) {
|
||||||
ERR_FAIL_COND(!p_importer.is_valid());
|
ERR_FAIL_COND(!p_importer.is_valid());
|
||||||
ResourceFormatImporter::get_singleton()->remove_importer(p_importer);
|
ResourceFormatImporter::get_singleton()->remove_importer(p_importer);
|
||||||
if (!EditorNode::get_singleton()->is_exiting()) {
|
// Plugins are now loaded during the first scan. It's important not to start another scan,
|
||||||
|
// even a deferred one, as it would cause a scan during a scan at the next main thread iteration.
|
||||||
|
if (!EditorNode::get_singleton()->is_exiting() && !EditorFileSystem::get_singleton()->doing_first_scan()) {
|
||||||
callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred();
|
callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan).call_deferred();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,10 @@ void ProjectSettingsEditor::update_plugins() {
|
||||||
plugin_settings->update_plugins();
|
plugin_settings->update_plugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectSettingsEditor::init_autoloads() {
|
||||||
|
autoload_settings->init_autoloads();
|
||||||
|
}
|
||||||
|
|
||||||
void ProjectSettingsEditor::_setting_edited(const String &p_name) {
|
void ProjectSettingsEditor::_setting_edited(const String &p_name) {
|
||||||
queue_save();
|
queue_save();
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,7 @@ public:
|
||||||
void set_plugins_page();
|
void set_plugins_page();
|
||||||
void set_general_page(const String &p_category);
|
void set_general_page(const String &p_category);
|
||||||
void update_plugins();
|
void update_plugins();
|
||||||
|
void init_autoloads();
|
||||||
|
|
||||||
EditorAutoloadSettings *get_autoload_settings() { return autoload_settings; }
|
EditorAutoloadSettings *get_autoload_settings() { return autoload_settings; }
|
||||||
GroupSettingsEditor *get_group_settings() { return group_settings; }
|
GroupSettingsEditor *get_group_settings() { return group_settings; }
|
||||||
|
|
|
@ -2759,7 +2759,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
|
||||||
String source = f->get_as_utf8_string();
|
String source = f->get_as_utf8_string();
|
||||||
|
|
||||||
GDScriptParser parser;
|
GDScriptParser parser;
|
||||||
err = parser.parse(source, p_path, false);
|
err = parser.parse(source, p_path, false, false);
|
||||||
|
|
||||||
const GDScriptParser::ClassNode *c = parser.get_tree();
|
const GDScriptParser::ClassNode *c = parser.get_tree();
|
||||||
if (!c) {
|
if (!c) {
|
||||||
|
|
|
@ -309,13 +309,14 @@ void GDScriptParser::set_last_completion_call_arg(int p_argument) {
|
||||||
completion_call_stack.back()->get().argument = p_argument;
|
completion_call_stack.back()->get().argument = p_argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error GDScriptParser::parse(const String &p_source_code, const String &p_script_path, bool p_for_completion) {
|
Error GDScriptParser::parse(const String &p_source_code, const String &p_script_path, bool p_for_completion, bool p_parse_body) {
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
String source = p_source_code;
|
String source = p_source_code;
|
||||||
int cursor_line = -1;
|
int cursor_line = -1;
|
||||||
int cursor_column = -1;
|
int cursor_column = -1;
|
||||||
for_completion = p_for_completion;
|
for_completion = p_for_completion;
|
||||||
|
parse_body = p_parse_body;
|
||||||
|
|
||||||
int tab_size = 4;
|
int tab_size = 4;
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
@ -689,6 +690,12 @@ void GDScriptParser::parse_program() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When the only thing needed is the class name and the icon, we don't need to parse the hole file.
|
||||||
|
// It really speed up the call to GDScriptLanguage::get_global_class_name especially for large script.
|
||||||
|
if (!parse_body) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#undef PUSH_PENDING_ANNOTATIONS_TO_HEAD
|
#undef PUSH_PENDING_ANNOTATIONS_TO_HEAD
|
||||||
|
|
||||||
parse_class_body(true);
|
parse_class_body(true);
|
||||||
|
|
|
@ -1329,6 +1329,7 @@ private:
|
||||||
bool _is_tool = false;
|
bool _is_tool = false;
|
||||||
String script_path;
|
String script_path;
|
||||||
bool for_completion = false;
|
bool for_completion = false;
|
||||||
|
bool parse_body = true;
|
||||||
bool panic_mode = false;
|
bool panic_mode = false;
|
||||||
bool can_break = false;
|
bool can_break = false;
|
||||||
bool can_continue = false;
|
bool can_continue = false;
|
||||||
|
@ -1560,7 +1561,7 @@ private:
|
||||||
#endif // TOOLS_ENABLED
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Error parse(const String &p_source_code, const String &p_script_path, bool p_for_completion);
|
Error parse(const String &p_source_code, const String &p_script_path, bool p_for_completion, bool p_parse_body = true);
|
||||||
Error parse_binary(const Vector<uint8_t> &p_binary, const String &p_script_path);
|
Error parse_binary(const Vector<uint8_t> &p_binary, const String &p_script_path);
|
||||||
ClassNode *get_tree() const { return head; }
|
ClassNode *get_tree() const { return head; }
|
||||||
bool is_tool() const { return _is_tool; }
|
bool is_tool() const { return _is_tool; }
|
||||||
|
|
Loading…
Reference in New Issue