Path: blob/master/editor/file_system/editor_file_system.h
9902 views
/**************************************************************************/1/* editor_file_system.h */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#pragma once3132#include "core/io/dir_access.h"33#include "core/io/resource_importer.h"34#include "core/io/resource_loader.h"35#include "core/os/thread.h"36#include "core/os/thread_safe.h"37#include "core/templates/hash_set.h"38#include "core/templates/safe_refcount.h"39#include "scene/main/node.h"4041class FileAccess;4243struct EditorProgressBG;44class EditorFileSystemDirectory : public Object {45GDCLASS(EditorFileSystemDirectory, Object);4647String name;48uint64_t modified_time;49bool verified = false; //used for checking changes5051EditorFileSystemDirectory *parent = nullptr;52Vector<EditorFileSystemDirectory *> subdirs;5354struct FileInfo {55String file;56StringName type;57StringName resource_script_class; // If any resource has script with a global class name, its found here.58ResourceUID::ID uid = ResourceUID::INVALID_ID;59uint64_t modified_time = 0;60uint64_t import_modified_time = 0;61String import_md5;62Vector<String> import_dest_paths;63bool import_valid = false;64String import_group_file;65Vector<String> deps;66bool verified = false; //used for checking changes67// This is for script resources only.68struct ScriptClassInfo {69String name;70String extends;71String icon_path;72bool is_abstract = false;73bool is_tool = false;74};75ScriptClassInfo class_info;76};7778Vector<FileInfo *> files;7980static void _bind_methods();8182friend class EditorFileSystem;8384public:85String get_name();86String get_path() const;8788int get_subdir_count() const;89EditorFileSystemDirectory *get_subdir(int p_idx);90int get_file_count() const;91String get_file(int p_idx) const;92String get_file_path(int p_idx) const;93StringName get_file_type(int p_idx) const;94StringName get_file_resource_script_class(int p_idx) const;95Vector<String> get_file_deps(int p_idx) const;96bool get_file_import_is_valid(int p_idx) const;97uint64_t get_file_modified_time(int p_idx) const;98uint64_t get_file_import_modified_time(int p_idx) const;99String get_file_script_class_name(int p_idx) const; //used for scripts100String get_file_script_class_extends(int p_idx) const; //used for scripts101String get_file_script_class_icon_path(int p_idx) const; //used for scripts102String get_file_icon_path(int p_idx) const; //used for FileSystemDock103104EditorFileSystemDirectory *get_parent();105106int find_file_index(const String &p_file) const;107int find_dir_index(const String &p_dir) const;108109void force_update();110111EditorFileSystemDirectory();112~EditorFileSystemDirectory();113};114115class EditorFileSystemImportFormatSupportQuery : public RefCounted {116GDCLASS(EditorFileSystemImportFormatSupportQuery, RefCounted);117118protected:119GDVIRTUAL0RC_REQUIRED(bool, _is_active)120GDVIRTUAL0RC_REQUIRED(Vector<String>, _get_file_extensions)121GDVIRTUAL0RC_REQUIRED(bool, _query)122static void _bind_methods() {123GDVIRTUAL_BIND(_is_active);124GDVIRTUAL_BIND(_get_file_extensions);125GDVIRTUAL_BIND(_query);126}127128public:129virtual bool is_active() const {130bool ret = false;131GDVIRTUAL_CALL(_is_active, ret);132return ret;133}134virtual Vector<String> get_file_extensions() const {135Vector<String> ret;136GDVIRTUAL_CALL(_get_file_extensions, ret);137return ret;138}139virtual bool query() {140bool ret = false;141GDVIRTUAL_CALL(_query, ret);142return ret;143}144};145146class EditorFileSystem : public Node {147GDCLASS(EditorFileSystem, Node);148149_THREAD_SAFE_CLASS_150151struct ItemAction {152enum Action {153ACTION_NONE,154ACTION_DIR_ADD,155ACTION_DIR_REMOVE,156ACTION_FILE_ADD,157ACTION_FILE_REMOVE,158ACTION_FILE_TEST_REIMPORT,159ACTION_FILE_RELOAD160};161162Action action = ACTION_NONE;163EditorFileSystemDirectory *dir = nullptr;164String file;165EditorFileSystemDirectory *new_dir = nullptr;166EditorFileSystemDirectory::FileInfo *new_file = nullptr;167};168169struct ScannedDirectory {170String name;171String full_path;172Vector<ScannedDirectory *> subdirs;173List<String> files;174175~ScannedDirectory();176};177178bool use_threads = false;179Thread thread;180static void _thread_func(void *_userdata);181182EditorFileSystemDirectory *new_filesystem = nullptr;183static ScannedDirectory *first_scan_root_dir;184185bool filesystem_changed_queued = false;186bool scanning = false;187bool importing = false;188bool first_scan = true;189bool scan_changes_pending = false;190float scan_total;191String filesystem_settings_version_for_import;192bool revalidate_import_files = false;193static int nb_files_total;194195void _notify_filesystem_changed();196void _scan_filesystem();197void _first_scan_filesystem();198void _first_scan_process_scripts(const ScannedDirectory *p_scan_dir, List<String> &p_gdextension_extensions, HashSet<String> &p_existing_class_names, HashSet<String> &p_extensions);199200static void _scan_for_uid_directory(const ScannedDirectory *p_scan_dir, const HashSet<String> &p_import_extensions);201202static void _load_first_scan_root_dir();203204HashSet<String> late_update_files;205206void _save_late_updated_files();207208EditorFileSystemDirectory *filesystem = nullptr;209210static EditorFileSystem *singleton;211212using ScriptClassInfo = EditorFileSystemDirectory::FileInfo::ScriptClassInfo;213214/* Used for reading the filesystem cache file */215struct FileCache {216StringName type;217String resource_script_class;218ResourceUID::ID uid = ResourceUID::INVALID_ID;219uint64_t modification_time = 0;220uint64_t import_modification_time = 0;221String import_md5;222Vector<String> import_dest_paths;223Vector<String> deps;224bool import_valid = false;225String import_group_file;226ScriptClassInfo class_info;227};228229HashMap<String, FileCache> file_cache;230HashSet<String> dep_update_list;231232struct ScanProgress {233float hi = 0;234int current = 0;235EditorProgressBG *progress = nullptr;236void increment();237};238239struct DirectoryComparator {240bool operator()(const EditorFileSystemDirectory *p_a, const EditorFileSystemDirectory *p_b) const {241return p_a->name.filenocasecmp_to(p_b->name) < 0;242}243};244245void _save_filesystem_cache();246void _save_filesystem_cache(EditorFileSystemDirectory *p_dir, Ref<FileAccess> p_file);247248bool _find_file(const String &p_file, EditorFileSystemDirectory **r_d, int &r_file_pos) const;249250void _scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, bool p_recursive = true);251252void _delete_internal_files(const String &p_file);253int _insert_actions_delete_files_directory(EditorFileSystemDirectory *p_dir);254255HashSet<String> textfile_extensions;256HashSet<String> other_file_extensions;257HashSet<String> valid_extensions;258HashSet<String> import_extensions;259260static int _scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da);261void _process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, HashSet<String> *p_processed_files);262263Thread thread_sources;264bool scanning_changes = false;265SafeFlag scanning_changes_done;266267static void _thread_func_sources(void *_userdata);268269List<String> sources_changed;270List<ItemAction> scan_actions;271272bool _update_scan_actions();273274void _update_extensions();275276Error _reimport_file(const String &p_file, const HashMap<StringName, Variant> &p_custom_options = HashMap<StringName, Variant>(), const String &p_custom_importer = String(), Variant *generator_parameters = nullptr, bool p_update_file_system = true);277Error _reimport_group(const String &p_group_file, const Vector<String> &p_files);278279bool _test_for_reimport(const String &p_path, const String &p_expected_import_md5);280bool _is_test_for_reimport_needed(const String &p_path, uint64_t p_last_modification_time, uint64_t p_modification_time, uint64_t p_last_import_modification_time, uint64_t p_import_modification_time, const Vector<String> &p_import_dest_paths);281bool _can_import_file(const String &p_path);282Vector<String> _get_import_dest_paths(const String &p_path);283284bool reimport_on_missing_imported_files;285286Vector<String> _get_dependencies(const String &p_path);287288struct ImportFile {289String path;290String importer;291bool threaded = false;292int order = 0;293bool operator<(const ImportFile &p_if) const {294return order == p_if.order ? (importer < p_if.importer) : (order < p_if.order);295}296};297298struct ScriptClassInfoUpdate : public ScriptClassInfo {299StringName type;300ScriptClassInfoUpdate() = default;301explicit ScriptClassInfoUpdate(const ScriptClassInfo &p_info) :302ScriptClassInfo(p_info) {}303static ScriptClassInfoUpdate from_file_info(const EditorFileSystemDirectory::FileInfo *p_fi) {304ScriptClassInfoUpdate update;305update.type = p_fi->type;306update.name = p_fi->class_info.name;307update.extends = p_fi->class_info.extends;308update.icon_path = p_fi->class_info.icon_path;309update.is_abstract = p_fi->class_info.is_abstract;310update.is_tool = p_fi->class_info.is_tool;311return update;312}313};314315Mutex update_script_mutex;316HashMap<String, ScriptClassInfoUpdate> update_script_paths;317HashSet<String> update_script_paths_documentation;318void _queue_update_script_class(const String &p_path, const ScriptClassInfoUpdate &p_script_update);319void _update_script_classes();320void _update_script_documentation();321void _process_update_pending();322void _process_removed_files(const HashSet<String> &p_processed_files);323bool _should_reload_script(const String &p_path);324325Mutex update_scene_mutex;326HashSet<String> update_scene_paths;327void _queue_update_scene_groups(const String &p_path);328void _update_scene_groups();329void _update_pending_scene_groups();330void _get_all_scenes(EditorFileSystemDirectory *p_dir, HashSet<String> &r_list);331332ScriptClassInfo _get_global_script_class(const String &p_type, const String &p_path) const;333334static Error _resource_import(const String &p_path);335static Ref<Resource> _load_resource_on_startup(ResourceFormatImporter *p_importer, const String &p_path, Error *r_error, bool p_use_sub_threads, float *r_progress, ResourceFormatLoader::CacheMode p_cache_mode);336337bool using_fat32_or_exfat; // Workaround for projects in FAT32 or exFAT filesystem (pendrives, most of the time)338339void _find_group_files(EditorFileSystemDirectory *efd, HashMap<String, Vector<String>> &group_files, HashSet<String> &groups_to_reimport);340341void _move_group_files(EditorFileSystemDirectory *efd, const String &p_group_file, const String &p_new_location);342343HashSet<String> group_file_cache;344HashMap<String, String> file_icon_cache;345346bool refresh_queued = false;347HashSet<ObjectID> folders_to_sort;348349Error _copy_file(const String &p_from, const String &p_to);350bool _copy_directory(const String &p_from, const String &p_to, HashMap<String, String> *p_files);351void _queue_refresh_filesystem();352void _refresh_filesystem();353354struct ImportThreadData {355const ImportFile *reimport_files;356int reimport_from;357Semaphore *imported_sem = nullptr;358};359360void _reimport_thread(uint32_t p_index, ImportThreadData *p_import_data);361362static ResourceUID::ID _resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate);363364bool _scan_extensions();365bool _scan_import_support(const Vector<String> &reimports);366367Vector<Ref<EditorFileSystemImportFormatSupportQuery>> import_support_queries;368369void _update_file_icon_path(EditorFileSystemDirectory::FileInfo *file_info);370void _update_files_icon_path(EditorFileSystemDirectory *edp = nullptr);371bool _remove_invalid_global_class_names(const HashSet<String> &p_existing_class_names);372String _get_file_by_class_name(EditorFileSystemDirectory *p_dir, const String &p_class_name, EditorFileSystemDirectory::FileInfo *&r_file_info);373374void _register_global_class_script(const String &p_search_path, const String &p_target_path, const ScriptClassInfoUpdate &p_script_update);375376protected:377void _notification(int p_what);378static void _bind_methods();379380public:381static EditorFileSystem *get_singleton() { return singleton; }382383EditorFileSystemDirectory *get_filesystem();384bool is_scanning() const;385bool is_importing() const { return importing; }386bool doing_first_scan() const { return first_scan; }387float get_scanning_progress() const;388void scan();389void scan_changes();390void update_file(const String &p_file);391void update_files(const Vector<String> &p_script_paths);392HashSet<String> get_valid_extensions() const;393void register_global_class_script(const String &p_search_path, const String &p_target_path);394395EditorFileSystemDirectory *get_filesystem_path(const String &p_path);396String get_file_type(const String &p_file) const;397EditorFileSystemDirectory *find_file(const String &p_file, int *r_index) const;398ResourceUID::ID get_file_uid(const String &p_path) const;399400void reimport_files(const Vector<String> &p_files);401Error reimport_append(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters);402403void reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const HashMap<StringName, Variant> &p_custom_params);404405bool is_group_file(const String &p_path) const;406void move_group_file(const String &p_path, const String &p_new_path);407408Error make_dir_recursive(const String &p_path, const String &p_base_path = String());409Error copy_file(const String &p_from, const String &p_to);410Error copy_directory(const String &p_from, const String &p_to);411412static bool _should_skip_directory(const String &p_path);413414static void scan_for_uid();415416void add_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);417void remove_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);418EditorFileSystem();419~EditorFileSystem();420};421422423