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

Implement project-wide node groups #60965

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
77 changes: 77 additions & 0 deletions core/config/project_settings.cpp
Expand Up @@ -281,6 +281,11 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
if (autoloads.has(node_name)) {
remove_autoload(node_name);
}
} else if (p_name.operator String().begins_with("global_group/")) {
String group_name = p_name.operator String().get_slice("/", 1);
if (global_groups.has(group_name)) {
remove_global_group(group_name);
}
}
} else {
if (p_name == CoreStringNames::get_singleton()->_custom_features) {
Expand Down Expand Up @@ -327,6 +332,9 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
autoload.path = path;
}
add_autoload(autoload);
} else if (p_name.operator String().begins_with("global_group/")) {
String group_name = p_name.operator String().get_slice("/", 1);
add_global_group(group_name, p_value);
}
}

Expand Down Expand Up @@ -674,6 +682,8 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo

Compression::gzip_level = GLOBAL_GET("compression/formats/gzip/compression_level");

load_scene_groups_cache();

project_loaded = err == OK;
return err;
}
Expand Down Expand Up @@ -1241,6 +1251,73 @@ ProjectSettings::AutoloadInfo ProjectSettings::get_autoload(const StringName &p_
return autoloads[p_name];
}

const HashMap<StringName, String> &ProjectSettings::get_global_groups_list() const {
return global_groups;
}

void ProjectSettings::add_global_group(const StringName &p_name, const String &p_description) {
ERR_FAIL_COND_MSG(p_name == StringName(), "Trying to add global group with no name.");
global_groups[p_name] = p_description;
}

void ProjectSettings::remove_global_group(const StringName &p_name) {
ERR_FAIL_COND_MSG(!global_groups.has(p_name), "Trying to remove non-existent global group.");
global_groups.erase(p_name);
}

bool ProjectSettings::has_global_group(const StringName &p_name) const {
return global_groups.has(p_name);
}

void ProjectSettings::remove_scene_groups_cache(const StringName &p_path) {
scene_groups_cache.erase(p_path);
}

void ProjectSettings::add_scene_groups_cache(const StringName &p_path, const HashSet<StringName> &p_cache) {
scene_groups_cache[p_path] = p_cache;
}

void ProjectSettings::save_scene_groups_cache() {
Ref<ConfigFile> cf;
cf.instantiate();
for (const KeyValue<StringName, HashSet<StringName>> &E : scene_groups_cache) {
if (E.value.is_empty()) {
continue;
}
Array list;
for (const StringName &group : E.value) {
list.push_back(group);
}
cf->set_value(E.key, "groups", list);
}
cf->save(get_scene_groups_cache_path());
}

String ProjectSettings::get_scene_groups_cache_path() const {
return get_project_data_path().path_join("scene_groups_cache.cfg");
}

void ProjectSettings::load_scene_groups_cache() {
Ref<ConfigFile> cf;
cf.instantiate();
if (cf->load(get_scene_groups_cache_path()) == OK) {
List<String> scene_paths;
cf->get_sections(&scene_paths);
for (const String &E : scene_paths) {
Array scene_groups = cf->get_value(E, "groups", Array());
HashSet<StringName> cache;
for (int i = 0; i < scene_groups.size(); ++i) {
cache.insert(scene_groups[i]);
}
add_scene_groups_cache(E, cache);
}
}
}

const HashMap<StringName, HashSet<StringName>> &ProjectSettings::get_scene_groups_cache() const {
return scene_groups_cache;
}

void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting);
ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &ProjectSettings::set_setting);
Expand Down
14 changes: 14 additions & 0 deletions core/config/project_settings.h
Expand Up @@ -106,6 +106,8 @@ class ProjectSettings : public Object {

LocalVector<String> hidden_prefixes;
HashMap<StringName, AutoloadInfo> autoloads;
HashMap<StringName, String> global_groups;
HashMap<StringName, HashSet<StringName>> scene_groups_cache;

Array global_class_list;
bool is_global_class_list_loaded = false;
Expand Down Expand Up @@ -208,6 +210,18 @@ class ProjectSettings : public Object {
bool has_autoload(const StringName &p_autoload) const;
AutoloadInfo get_autoload(const StringName &p_name) const;

const HashMap<StringName, String> &get_global_groups_list() const;
void add_global_group(const StringName &p_name, const String &p_description);
void remove_global_group(const StringName &p_name);
bool has_global_group(const StringName &p_name) const;

const HashMap<StringName, HashSet<StringName>> &get_scene_groups_cache() const;
void add_scene_groups_cache(const StringName &p_path, const HashSet<StringName> &p_cache);
void remove_scene_groups_cache(const StringName &p_path);
void save_scene_groups_cache();
String get_scene_groups_cache_path() const;
void load_scene_groups_cache();

ProjectSettings();
~ProjectSettings();
};
Expand Down
85 changes: 85 additions & 0 deletions editor/editor_file_system.cpp
Expand Up @@ -44,6 +44,7 @@
#include "editor/editor_paths.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_settings.h"
#include "scene/resources/packed_scene.h"

EditorFileSystem *EditorFileSystem::singleton = nullptr;
//the name is the version, to keep compatibility with different versions of Godot
Expand Down Expand Up @@ -615,6 +616,9 @@ bool EditorFileSystem::_update_scan_actions() {
if (ClassDB::is_parent_class(ia.new_file->type, SNAME("Script"))) {
_queue_update_script_class(ia.dir->get_file_path(idx));
}
if (ia.new_file->type == SNAME("PackedScene")) {
_queue_update_scene_groups(ia.dir->get_file_path(idx));
}

} break;
case ItemAction::ACTION_FILE_REMOVE: {
Expand All @@ -624,6 +628,9 @@ bool EditorFileSystem::_update_scan_actions() {
if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
_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));
}

_delete_internal_files(ia.dir->files[idx]->file);
memdelete(ia.dir->files[idx]);
Expand Down Expand Up @@ -662,6 +669,9 @@ bool EditorFileSystem::_update_scan_actions() {
if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
_queue_update_script_class(full_path);
}
if (ia.dir->files[idx]->type == SNAME("PackedScene")) {
_queue_update_scene_groups(full_path);
}

reloads.push_back(full_path);

Expand Down Expand Up @@ -732,6 +742,7 @@ void EditorFileSystem::scan() {
_update_scan_actions();
scanning = false;
_update_pending_script_classes();
_update_pending_scene_groups();
emit_signal(SNAME("filesystem_changed"));
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
first_scan = false;
Expand Down Expand Up @@ -942,6 +953,9 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
if (ClassDB::is_parent_class(fi->type, SNAME("Script"))) {
_queue_update_script_class(path);
}
if (fi->type == SNAME("PackedScene")) {
_queue_update_scene_groups(path);
}
}
}

Expand Down Expand Up @@ -1196,6 +1210,7 @@ void EditorFileSystem::scan_changes() {
_scan_fs_changes(filesystem, sp);
bool changed = _update_scan_actions();
_update_pending_script_classes();
_update_pending_scene_groups();
if (changed) {
emit_signal(SNAME("filesystem_changed"));
}
Expand Down Expand Up @@ -1262,6 +1277,7 @@ void EditorFileSystem::_notification(int p_what) {
}
bool changed = _update_scan_actions();
_update_pending_script_classes();
_update_pending_scene_groups();
if (changed) {
emit_signal(SNAME("filesystem_changed"));
}
Expand All @@ -1281,6 +1297,7 @@ void EditorFileSystem::_notification(int p_what) {
thread.wait_to_finish();
_update_scan_actions();
_update_pending_script_classes();
_update_pending_scene_groups();
emit_signal(SNAME("filesystem_changed"));
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
first_scan = false;
Expand Down Expand Up @@ -1635,6 +1652,65 @@ void EditorFileSystem::_queue_update_script_class(const String &p_path) {
update_script_mutex.unlock();
}

void EditorFileSystem::_update_scene_groups() {
update_scene_mutex.lock();

for (const String &path : update_scene_paths) {
ProjectSettings::get_singleton()->remove_scene_groups_cache(path);

int index = -1;
EditorFileSystemDirectory *efd = find_file(path, &index);

if (!efd || index < 0) {
// The file was removed.
continue;
}

const HashSet<StringName> scene_groups = _get_scene_groups(path);
if (!scene_groups.is_empty()) {
ProjectSettings::get_singleton()->add_scene_groups_cache(path, scene_groups);
}
}

update_scene_paths.clear();
update_scene_mutex.unlock();

ProjectSettings::get_singleton()->save_scene_groups_cache();
}

void EditorFileSystem::_update_pending_scene_groups() {
if (!FileAccess::exists(ProjectSettings::get_singleton()->get_scene_groups_cache_path())) {
_get_all_scenes(get_filesystem(), update_scene_paths);
_update_scene_groups();
} else if (!update_scene_paths.is_empty()) {
_update_scene_groups();
}
}

void EditorFileSystem::_queue_update_scene_groups(const String &p_path) {
update_scene_mutex.lock();
update_scene_paths.insert(p_path);
update_scene_mutex.unlock();
}

void EditorFileSystem::_get_all_scenes(EditorFileSystemDirectory *p_dir, HashSet<String> &r_list) {
for (int i = 0; i < p_dir->get_file_count(); i++) {
if (p_dir->get_file_type(i) == SNAME("PackedScene")) {
r_list.insert(p_dir->get_file_path(i));
}
}

for (int i = 0; i < p_dir->get_subdir_count(); i++) {
_get_all_scenes(p_dir->get_subdir(i), r_list);
}
}

HashSet<StringName> EditorFileSystem::_get_scene_groups(const String &p_path) {
Ref<PackedScene> packed_scene = ResourceLoader::load(p_path);
ERR_FAIL_COND_V(packed_scene.is_null(), HashSet<StringName>());
return packed_scene->get_state()->get_all_groups();
}

void EditorFileSystem::update_file(const String &p_file) {
ERR_FAIL_COND(p_file.is_empty());
EditorFileSystemDirectory *fs = nullptr;
Expand All @@ -1658,12 +1734,16 @@ void EditorFileSystem::update_file(const String &p_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);
}

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;
}
Expand Down Expand Up @@ -1730,8 +1810,12 @@ void EditorFileSystem::update_file(const String &p_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);
}

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

Expand Down Expand Up @@ -2341,6 +2425,7 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {

_save_filesystem_cache();
_update_pending_script_classes();
_update_pending_scene_groups();
importing = false;
if (!is_scanning()) {
emit_signal(SNAME("filesystem_changed"));
Expand Down
8 changes: 8 additions & 0 deletions editor/editor_file_system.h
Expand Up @@ -267,6 +267,14 @@ class EditorFileSystem : public Node {
void _update_script_classes();
void _update_pending_script_classes();

Mutex update_scene_mutex;
HashSet<String> update_scene_paths;
void _queue_update_scene_groups(const String &p_path);
void _update_scene_groups();
void _update_pending_scene_groups();
HashSet<StringName> _get_scene_groups(const String &p_path);
void _get_all_scenes(EditorFileSystemDirectory *p_dir, HashSet<String> &r_list);

String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const;

static Error _resource_import(const String &p_path);
Expand Down