Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix freeze after building C# project with a lot of files #92893

Merged
merged 1 commit into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 86 additions & 79 deletions editor/editor_file_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1714,105 +1714,112 @@ HashSet<StringName> EditorFileSystem::_get_scene_groups(const String &p_path) {

void EditorFileSystem::update_file(const String &p_file) {
ERR_FAIL_COND(p_file.is_empty());
EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
update_files({ p_file });
}

if (!_find_file(p_file, &fs, cpos)) {
if (!fs) {
return;
void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
for (const String &file : p_script_paths) {
ERR_CONTINUE(file.is_empty());
EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;

if (!_find_file(file, &fs, cpos)) {
if (!fs) {
return;
}
}
}

if (!FileAccess::exists(p_file)) {
//was removed
_delete_internal_files(p_file);
if (cpos != -1) { // Might've never been part of the editor file system (*.* files deleted in Open dialog).
if (fs->files[cpos]->uid != ResourceUID::INVALID_ID) {
if (ResourceUID::get_singleton()->has_id(fs->files[cpos]->uid)) {
ResourceUID::get_singleton()->remove_id(fs->files[cpos]->uid);
if (!FileAccess::exists(file)) {
//was removed
_delete_internal_files(file);
if (cpos != -1) { // Might've never been part of the editor file system (*.* files deleted in Open dialog).
if (fs->files[cpos]->uid != ResourceUID::INVALID_ID) {
if (ResourceUID::get_singleton()->has_id(fs->files[cpos]->uid)) {
ResourceUID::get_singleton()->remove_id(fs->files[cpos]->uid);
}
}
}
if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
_queue_update_script_class(p_file);
}
if (fs->files[cpos]->type == SNAME("PackedScene")) {
_queue_update_scene_groups(p_file);
if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
_queue_update_script_class(file);
}
if (fs->files[cpos]->type == SNAME("PackedScene")) {
_queue_update_scene_groups(file);
}

memdelete(fs->files[cpos]);
fs->files.remove_at(cpos);
}

memdelete(fs->files[cpos]);
fs->files.remove_at(cpos);
_update_pending_script_classes();
_update_pending_scene_groups();
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later
return;
}

_update_pending_script_classes();
_update_pending_scene_groups();
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later
return;
}

String type = ResourceLoader::get_resource_type(p_file);
if (type.is_empty() && textfile_extensions.has(p_file.get_extension())) {
type = "TextFile";
}
String script_class = ResourceLoader::get_resource_script_class(p_file);
String type = ResourceLoader::get_resource_type(file);
if (type.is_empty() && textfile_extensions.has(file.get_extension())) {
type = "TextFile";
}
String script_class = ResourceLoader::get_resource_script_class(file);

ResourceUID::ID uid = ResourceLoader::get_resource_uid(p_file);
ResourceUID::ID uid = ResourceLoader::get_resource_uid(file);

if (cpos == -1) {
// The file did not exist, it was added.
int idx = 0;
String file_name = p_file.get_file();
if (cpos == -1) {
// The file did not exist, it was added.
int idx = 0;
String file_name = file.get_file();

for (int i = 0; i < fs->files.size(); i++) {
if (p_file.filenocasecmp_to(fs->files[i]->file) < 0) {
break;
for (int i = 0; i < fs->files.size(); i++) {
if (file.filenocasecmp_to(fs->files[i]->file) < 0) {
break;
}
idx++;
}
idx++;
}

EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
fi->file = file_name;
fi->import_modified_time = 0;
fi->import_valid = type == "TextFile" ? true : ResourceLoader::is_import_valid(p_file);
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
fi->file = file_name;
fi->import_modified_time = 0;
fi->import_valid = type == "TextFile" ? true : ResourceLoader::is_import_valid(file);

if (idx == fs->files.size()) {
fs->files.push_back(fi);
if (idx == fs->files.size()) {
fs->files.push_back(fi);
} else {
fs->files.insert(idx, fi);
}
cpos = idx;
} else {
fs->files.insert(idx, fi);
//the file exists and it was updated, and was not added in this step.
//this means we must force upon next restart to scan it again, to get proper type and dependencies
late_update_files.insert(file);
_save_late_updated_files(); //files need to be updated in the re-scan
}
cpos = idx;
} else {
//the file exists and it was updated, and was not added in this step.
//this means we must force upon next restart to scan it again, to get proper type and dependencies
late_update_files.insert(p_file);
_save_late_updated_files(); //files need to be updated in the re-scan
}

fs->files[cpos]->type = type;
fs->files[cpos]->resource_script_class = script_class;
fs->files[cpos]->uid = uid;
fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends, &fs->files[cpos]->script_class_icon_path);
fs->files[cpos]->import_group_file = ResourceLoader::get_import_group_file(p_file);
fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
fs->files[cpos]->deps = _get_dependencies(p_file);
fs->files[cpos]->import_valid = type == "TextFile" ? true : ResourceLoader::is_import_valid(p_file);
fs->files[cpos]->type = type;
fs->files[cpos]->resource_script_class = script_class;
fs->files[cpos]->uid = uid;
fs->files[cpos]->script_class_name = _get_global_script_class(type, file, &fs->files[cpos]->script_class_extends, &fs->files[cpos]->script_class_icon_path);
fs->files[cpos]->import_group_file = ResourceLoader::get_import_group_file(file);
fs->files[cpos]->modified_time = FileAccess::get_modified_time(file);
fs->files[cpos]->deps = _get_dependencies(file);
fs->files[cpos]->import_valid = type == "TextFile" ? true : ResourceLoader::is_import_valid(file);

if (uid != ResourceUID::INVALID_ID) {
if (ResourceUID::get_singleton()->has_id(uid)) {
ResourceUID::get_singleton()->set_id(uid, p_file);
} else {
ResourceUID::get_singleton()->add_id(uid, p_file);
}
if (uid != ResourceUID::INVALID_ID) {
if (ResourceUID::get_singleton()->has_id(uid)) {
ResourceUID::get_singleton()->set_id(uid, file);
} else {
ResourceUID::get_singleton()->add_id(uid, file);
}

ResourceUID::get_singleton()->update_cache();
}
// Update preview
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
ResourceUID::get_singleton()->update_cache();
}
// Update preview
EditorResourcePreview::get_singleton()->check_for_invalidation(file);

if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
_queue_update_script_class(p_file);
}
if (fs->files[cpos]->type == SNAME("PackedScene")) {
_queue_update_scene_groups(p_file);
if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
_queue_update_script_class(file);
}
if (fs->files[cpos]->type == SNAME("PackedScene")) {
_queue_update_scene_groups(file);
}
}

_update_pending_script_classes();
Expand Down
1 change: 1 addition & 0 deletions editor/editor_file_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ class EditorFileSystem : public Node {
void scan();
void scan_changes();
void update_file(const String &p_file);
void update_files(const Vector<String> &p_script_paths);
HashSet<String> get_valid_extensions() const;
void register_global_class_script(const String &p_search_path, const String &p_target_path);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,11 @@ static void LookupScriptForClass(Type type)
// This method may be called before initialization.
if (NativeFuncs.godotsharp_dotnet_module_is_initialized().ToBool() && Engine.IsEditorHint())
{
foreach (var scriptPath in _pathTypeBiMap.Paths)
if (_pathTypeBiMap.Paths.Count > 0)
{
using godot_string nativeScriptPath = Marshaling.ConvertStringToNative(scriptPath);
NativeFuncs.godotsharp_internal_editor_file_system_update_file(nativeScriptPath);
string[] scriptPaths = _pathTypeBiMap.Paths.ToArray();
using godot_packed_string_array scriptPathsNative = Marshaling.ConvertSystemArrayToNativePackedStringArray(scriptPaths);
NativeFuncs.godotsharp_internal_editor_file_system_update_files(scriptPathsNative);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
Expand Down Expand Up @@ -64,7 +65,7 @@ private class PathScriptTypeBiMap
private System.Collections.Generic.Dictionary<string, Type> _pathTypeMap = new();
private System.Collections.Generic.Dictionary<Type, string> _typePathMap = new();

public System.Collections.Generic.IEnumerable<string> Paths => _pathTypeMap.Keys;
public IReadOnlyCollection<string> Paths => _pathTypeMap.Keys;

public void Add(string scriptPath, Type scriptType)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ internal static partial Error godotsharp_stack_info_vector_resize(
internal static partial void godotsharp_stack_info_vector_destroy(
ref DebuggingUtils.godot_stack_info_vector p_stack_info_vector);

internal static partial void godotsharp_internal_editor_file_system_update_file(in godot_string p_script_path);
internal static partial void godotsharp_internal_editor_file_system_update_files(in godot_packed_string_array p_script_paths);

internal static partial void godotsharp_internal_script_debugger_send_error(in godot_string p_func,
in godot_string p_file, int p_line, in godot_string p_err, in godot_string p_descr,
Expand Down
6 changes: 3 additions & 3 deletions modules/mono/glue/runtime_interop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,13 +315,13 @@ void godotsharp_internal_new_csharp_script(Ref<CSharpScript> *r_dest) {
memnew_placement(r_dest, Ref<CSharpScript>(memnew(CSharpScript)));
}

void godotsharp_internal_editor_file_system_update_file(const String *p_script_path) {
void godotsharp_internal_editor_file_system_update_files(const PackedStringArray &p_script_paths) {
#ifdef TOOLS_ENABLED
// If the EditorFileSystem singleton is available, update the file;
// otherwise, the file will be updated when the singleton becomes available.
EditorFileSystem *efs = EditorFileSystem::get_singleton();
if (efs) {
efs->update_file(*p_script_path);
efs->update_files(p_script_paths);
}
#else
// EditorFileSystem is only available when running in the Godot editor.
Expand Down Expand Up @@ -1450,7 +1450,7 @@ static const void *unmanaged_callbacks[]{
(void *)godotsharp_engine_get_singleton,
(void *)godotsharp_stack_info_vector_resize,
(void *)godotsharp_stack_info_vector_destroy,
(void *)godotsharp_internal_editor_file_system_update_file,
(void *)godotsharp_internal_editor_file_system_update_files,
(void *)godotsharp_internal_script_debugger_send_error,
(void *)godotsharp_internal_script_debugger_is_active,
(void *)godotsharp_internal_object_get_associated_gchandle,
Expand Down
Loading