diff --git a/doc/classes/Cubemap.xml b/doc/classes/Cubemap.xml index 46ddede9b147..01ec4c40d7b2 100644 --- a/doc/classes/Cubemap.xml +++ b/doc/classes/Cubemap.xml @@ -11,4 +11,12 @@ + + + + + Creates a placeholder version of this resource ([PlaceholderCubemap]). + + + diff --git a/doc/classes/CubemapArray.xml b/doc/classes/CubemapArray.xml index 2fd55b66c664..1b410671c176 100644 --- a/doc/classes/CubemapArray.xml +++ b/doc/classes/CubemapArray.xml @@ -12,4 +12,12 @@ + + + + + Creates a placeholder version of this resource ([PlaceholderCubemapArray]). + + + diff --git a/doc/classes/Material.xml b/doc/classes/Material.xml index c5d567c1fe61..bdd5cee7971f 100644 --- a/doc/classes/Material.xml +++ b/doc/classes/Material.xml @@ -31,6 +31,12 @@ + + + + Creates a placeholder version of this resource ([PlaceholderMaterial]). + + diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index 1c1f48588fa8..ece3199aabc4 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -114,6 +114,12 @@ [b]Note:[/b] This method typically returns the vertices in reverse order (e.g. clockwise to counterclockwise). + + + + Creates a placeholder version of this resource ([PlaceholderMesh]). + + diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml index aac197090a22..7329ebb868c9 100644 --- a/doc/classes/Texture2D.xml +++ b/doc/classes/Texture2D.xml @@ -74,6 +74,12 @@ Called when a pixel's opaque state in the [Texture2D] is queried at the specified [code](x, y)[/code] position. + + + + Creates a placeholder version of this resource ([PlaceholderTexture2D]). + + diff --git a/doc/classes/Texture2DArray.xml b/doc/classes/Texture2DArray.xml index ec00198db17a..6c9fb55befe4 100644 --- a/doc/classes/Texture2DArray.xml +++ b/doc/classes/Texture2DArray.xml @@ -10,4 +10,12 @@ + + + + + Creates a placeholder version of this resource ([PlaceholderTexture2DArray]). + + + diff --git a/doc/classes/Texture3D.xml b/doc/classes/Texture3D.xml index 1a66932d6218..d2df82a74d1b 100644 --- a/doc/classes/Texture3D.xml +++ b/doc/classes/Texture3D.xml @@ -47,6 +47,12 @@ Called when the presence of mipmaps in the [Texture3D] is queried. + + + + Creates a placeholder version of this resource ([PlaceholderTexture3D]). + + diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index c344812065a0..bbae6e538939 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -125,6 +125,7 @@ #include "editor/plugins/asset_library_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/debugger_editor_plugin.h" +#include "editor/plugins/dedicated_server_export_plugin.h" #include "editor/plugins/editor_preview_plugins.h" #include "editor/plugins/editor_resource_conversion_plugin.h" #include "editor/plugins/gdextension_export_plugin.h" @@ -7878,6 +7879,11 @@ EditorNode::EditorNode() { EditorExport::get_singleton()->add_export_plugin(gdextension_export_plugin); + Ref dedicated_server_export_plugin; + dedicated_server_export_plugin.instantiate(); + + EditorExport::get_singleton()->add_export_plugin(dedicated_server_export_plugin); + Ref packed_scene_translation_parser_plugin; packed_scene_translation_parser_plugin.instantiate(); EditorTranslationParser::get_singleton()->add_parser(packed_scene_translation_parser_plugin, EditorTranslationParser::STANDARD); diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index 1d147cc5b91d..4900ced2e45d 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -45,6 +45,7 @@ void EditorExport::_save() { config->set_value(section, "name", preset->get_name()); config->set_value(section, "platform", preset->get_platform()->get_name()); config->set_value(section, "runnable", preset->is_runnable()); + config->set_value(section, "dedicated_server", preset->is_dedicated_server()); config->set_value(section, "custom_features", preset->get_custom_features()); bool save_files = false; @@ -64,6 +65,11 @@ void EditorExport::_save() { config->set_value(section, "export_filter", "exclude"); save_files = true; } break; + case EditorExportPreset::EXPORT_CUSTOMIZED: { + config->set_value(section, "export_filter", "customized"); + config->set_value(section, "customized_files", preset->get_customized_files()); + save_files = false; + }; } if (save_files) { @@ -213,6 +219,7 @@ void EditorExport::load_config() { preset->set_name(config->get_value(section, "name")); preset->set_runnable(config->get_value(section, "runnable")); + preset->set_dedicated_server(config->get_value(section, "dedicated_server", false)); if (config->has_section_key(section, "custom_features")) { preset->set_custom_features(config->get_value(section, "custom_features")); @@ -233,6 +240,10 @@ void EditorExport::load_config() { } else if (export_filter == "exclude") { preset->set_export_filter(EditorExportPreset::EXCLUDE_SELECTED_RESOURCES); get_files = true; + } else if (export_filter == "customized") { + preset->set_export_filter(EditorExportPreset::EXPORT_CUSTOMIZED); + preset->set_customized_files(config->get_value(section, "customized_files", Dictionary())); + get_files = false; } if (get_files) { diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 27ca0b84a145..9f79eecfb789 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -343,6 +343,24 @@ void EditorExportPlatform::_export_find_resources(EditorFileSystemDirectory *p_d } } +void EditorExportPlatform::_export_find_customized_resources(const Ref &p_preset, EditorFileSystemDirectory *p_dir, EditorExportPreset::FileExportMode p_mode, HashSet &p_paths) { + for (int i = 0; i < p_dir->get_subdir_count(); i++) { + EditorFileSystemDirectory *subdir = p_dir->get_subdir(i); + _export_find_customized_resources(p_preset, subdir, p_preset->get_file_export_mode(subdir->get_path(), p_mode), p_paths); + } + + for (int i = 0; i < p_dir->get_file_count(); i++) { + if (p_dir->get_file_type(i) == "TextFile") { + continue; + } + String path = p_dir->get_file_path(i); + EditorExportPreset::FileExportMode file_mode = p_preset->get_file_export_mode(path, p_mode); + if (file_mode != EditorExportPreset::MODE_FILE_REMOVE) { + p_paths.insert(path); + } + } +} + void EditorExportPlatform::_export_find_dependencies(const String &p_path, HashSet &p_paths) { if (p_paths.has(p_path)) { return; @@ -639,10 +657,20 @@ bool EditorExportPlatform::_export_customize_object(Object *p_object, LocalVecto return changed; } +bool EditorExportPlatform::_is_editable_ancestor(Node *p_root, Node *p_node) { + while (p_node != nullptr && p_node != p_root) { + if (p_root->is_editable_instance(p_node)) { + return true; + } + p_node = p_node->get_owner(); + } + return false; +} + bool EditorExportPlatform::_export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector> &customize_resources_plugins) { bool changed = false; - if (p_node == p_root || p_node->get_owner() == p_root) { + if (p_root == p_node || p_node->get_owner() == p_root || _is_editable_ancestor(p_root, p_node)) { if (_export_customize_object(p_node, customize_resources_plugins)) { changed = true; } @@ -757,10 +785,10 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector break; } } + } - if (_export_customize_object(res.ptr(), customize_resources_plugins)) { - modified = true; - } + if (_export_customize_object(res.ptr(), customize_resources_plugins)) { + modified = true; } if (modified || p_force_save) { @@ -796,6 +824,8 @@ Error EditorExportPlatform::export_project_files(const Ref & for (int i = 0; i < files.size(); i++) { paths.erase(files[i]); } + } else if (p_preset->get_export_filter() == EditorExportPreset::EXPORT_CUSTOMIZED) { + _export_find_customized_resources(p_preset, EditorFileSystem::get_singleton()->get_filesystem(), p_preset->get_file_export_mode("res://"), paths); } else { bool scenes_only = p_preset->get_export_filter() == EditorExportPreset::EXPORT_SELECTED_SCENES; @@ -939,14 +969,14 @@ Error EditorExportPlatform::export_project_files(const Ref & LocalVector> customize_scenes_plugins; for (int i = 0; i < export_plugins.size(); i++) { - if (export_plugins[i]->_begin_customize_resources(Ref(this), features_psa)) { + if (export_plugins.write[i]->_begin_customize_resources(Ref(this), features_psa)) { customize_resources_plugins.push_back(export_plugins[i]); custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash); uint64_t hash = export_plugins[i]->_get_customization_configuration_hash(); custom_resources_hash = hash_murmur3_one_64(hash, custom_resources_hash); } - if (export_plugins[i]->_begin_customize_scenes(Ref(this), features_psa)) { + if (export_plugins.write[i]->_begin_customize_scenes(Ref(this), features_psa)) { customize_scenes_plugins.push_back(export_plugins[i]); custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash); @@ -1218,6 +1248,9 @@ Error EditorExportPlatform::export_project_files(const Ref & } } } + for (int i = 0; i < export_plugins.size(); i++) { + custom_list.append_array(export_plugins[i]->_get_export_features(Ref(this), p_debug)); + } ProjectSettings::CustomMap custom_map; if (path_remaps.size()) { diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index 1fb35759ace5..3b4e92c9bd79 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -91,6 +91,7 @@ class EditorExportPlatform : public RefCounted { Vector messages; void _export_find_resources(EditorFileSystemDirectory *p_dir, HashSet &p_paths); + void _export_find_customized_resources(const Ref &p_preset, EditorFileSystemDirectory *p_dir, EditorExportPreset::FileExportMode p_mode, HashSet &p_paths); void _export_find_dependencies(const String &p_path, HashSet &p_paths); static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); @@ -112,6 +113,7 @@ class EditorExportPlatform : public RefCounted { bool _export_customize_array(Array &array, LocalVector> &customize_resources_plugins); bool _export_customize_object(Object *p_object, LocalVector> &customize_resources_plugins); bool _export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector> &customize_resources_plugins); + bool _is_editable_ancestor(Node *p_root, Node *p_node); String _export_customize(const String &p_path, LocalVector> &customize_resources_plugins, LocalVector> &customize_scenes_plugins, HashMap &export_cache, const String &export_base_path, bool p_force_save); diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp index dfd4520eecab..0add55820f96 100644 --- a/editor/export/editor_export_plugin.cpp +++ b/editor/export/editor_export_plugin.cpp @@ -141,7 +141,7 @@ void EditorExportPlugin::_export_end_script() { // Customization -bool EditorExportPlugin::_begin_customize_resources(const Ref &p_platform, const Vector &p_features) const { +bool EditorExportPlugin::_begin_customize_resources(const Ref &p_platform, const Vector &p_features) { bool ret = false; GDVIRTUAL_CALL(_begin_customize_resources, p_platform, p_features, ret); return ret; @@ -153,7 +153,7 @@ Ref EditorExportPlugin::_customize_resource(const Ref &p_res return ret; } -bool EditorExportPlugin::_begin_customize_scenes(const Ref &p_platform, const Vector &p_features) const { +bool EditorExportPlugin::_begin_customize_scenes(const Ref &p_platform, const Vector &p_features) { bool ret = false; GDVIRTUAL_CALL(_begin_customize_scenes, p_platform, p_features, ret); return ret; @@ -185,6 +185,12 @@ String EditorExportPlugin::_get_name() const { return ret; } +PackedStringArray EditorExportPlugin::_get_export_features(const Ref &p_platform, bool p_debug) const { + PackedStringArray ret; + GDVIRTUAL_CALL(_get_export_features, p_platform, p_debug, ret); + return ret; +} + void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet &p_features) { } diff --git a/editor/export/editor_export_plugin.h b/editor/export/editor_export_plugin.h index 5ac0a70c3ea3..fad647a67bc6 100644 --- a/editor/export/editor_export_plugin.h +++ b/editor/export/editor_export_plugin.h @@ -120,18 +120,22 @@ class EditorExportPlugin : public RefCounted { GDVIRTUAL0(_end_customize_scenes) GDVIRTUAL0(_end_customize_resources) + GDVIRTUAL2RC(PackedStringArray, _get_export_features, const Ref &, bool); + GDVIRTUAL0RC(String, _get_name) - bool _begin_customize_resources(const Ref &p_platform, const Vector &p_features) const; // Return true if this plugin does property export customization - Ref _customize_resource(const Ref &p_resource, const String &p_path); // If nothing is returned, it means do not touch (nothing changed). If something is returned (either the same or a different resource) it means changes are made. + virtual bool _begin_customize_resources(const Ref &p_platform, const Vector &p_features); // Return true if this plugin does property export customization + virtual Ref _customize_resource(const Ref &p_resource, const String &p_path); // If nothing is returned, it means do not touch (nothing changed). If something is returned (either the same or a different resource) it means changes are made. + + virtual bool _begin_customize_scenes(const Ref &p_platform, const Vector &p_features); // Return true if this plugin does property export customization + virtual Node *_customize_scene(Node *p_root, const String &p_path); // Return true if a change was made - bool _begin_customize_scenes(const Ref &p_platform, const Vector &p_features) const; // Return true if this plugin does property export customization - Node *_customize_scene(Node *p_root, const String &p_path); // Return true if a change was made + virtual uint64_t _get_customization_configuration_hash() const; // Hash used for caching customized resources and scenes. - uint64_t _get_customization_configuration_hash() const; // Hash used for caching customized resources and scenes. + virtual void _end_customize_scenes(); + virtual void _end_customize_resources(); - void _end_customize_scenes(); - void _end_customize_resources(); + virtual PackedStringArray _get_export_features(const Ref &p_export_platform, bool p_debug) const; virtual String _get_name() const; diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp index c6365806b3f1..6beef623bccb 100644 --- a/editor/export/editor_export_preset.cpp +++ b/editor/export/editor_export_preset.cpp @@ -64,15 +64,29 @@ Ref EditorExportPreset::get_platform() const { return platform; } -void EditorExportPreset::update_files_to_export() { - Vector to_remove; - for (const String &E : selected_files) { - if (!FileAccess::exists(E)) { - to_remove.push_back(E); +void EditorExportPreset::update_files() { + { + Vector to_remove; + for (const String &E : selected_files) { + if (!FileAccess::exists(E)) { + to_remove.push_back(E); + } + } + for (int i = 0; i < to_remove.size(); ++i) { + selected_files.erase(to_remove[i]); } } - for (int i = 0; i < to_remove.size(); ++i) { - selected_files.erase(to_remove[i]); + + { + Vector to_remove; + for (const KeyValue &E : customized_files) { + if (!FileAccess::exists(E.key) && !DirAccess::exists(E.key)) { + to_remove.push_back(E.key); + } + } + for (int i = 0; i < to_remove.size(); ++i) { + customized_files.erase(to_remove[i]); + } } } @@ -84,6 +98,48 @@ Vector EditorExportPreset::get_files_to_export() const { return files; } +Dictionary EditorExportPreset::get_customized_files() const { + Dictionary files; + for (const KeyValue &E : customized_files) { + String mode; + switch (E.value) { + case MODE_FILE_NOT_CUSTOMIZED: { + continue; + } break; + case MODE_FILE_STRIP: { + mode = "strip"; + } break; + case MODE_FILE_KEEP: { + mode = "keep"; + } break; + case MODE_FILE_REMOVE: { + mode = "remove"; + } + } + files[E.key] = mode; + } + return files; +} + +int EditorExportPreset::get_customized_files_count() const { + return customized_files.size(); +} + +void EditorExportPreset::set_customized_files(const Dictionary &p_files) { + for (const Variant *key = p_files.next(nullptr); key; key = p_files.next(key)) { + EditorExportPreset::FileExportMode mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED; + String value = p_files[*key]; + if (value == "strip") { + mode = EditorExportPreset::MODE_FILE_STRIP; + } else if (value == "keep") { + mode = EditorExportPreset::MODE_FILE_KEEP; + } else if (value == "remove") { + mode = EditorExportPreset::MODE_FILE_REMOVE; + } + set_file_export_mode(*key, mode); + } +} + void EditorExportPreset::set_name(const String &p_name) { name = p_name; EditorExport::singleton->save_presets(); @@ -102,6 +158,15 @@ bool EditorExportPreset::is_runnable() const { return runnable; } +void EditorExportPreset::set_dedicated_server(bool p_enable) { + dedicated_server = p_enable; + EditorExport::singleton->save_presets(); +} + +bool EditorExportPreset::is_dedicated_server() const { + return dedicated_server; +} + void EditorExportPreset::set_export_filter(ExportFilter p_filter) { export_filter = p_filter; EditorExport::singleton->save_presets(); @@ -158,6 +223,23 @@ bool EditorExportPreset::has_export_file(const String &p_path) { return selected_files.has(p_path); } +void EditorExportPreset::set_file_export_mode(const String &p_path, EditorExportPreset::FileExportMode p_mode) { + if (p_mode == FileExportMode::MODE_FILE_NOT_CUSTOMIZED) { + customized_files.erase(p_path); + } else { + customized_files.insert(p_path, p_mode); + } + EditorExport::singleton->save_presets(); +} + +EditorExportPreset::FileExportMode EditorExportPreset::get_file_export_mode(const String &p_path, EditorExportPreset::FileExportMode p_default) const { + HashMap::ConstIterator i = customized_files.find(p_path); + if (i) { + return i->value; + } + return p_default; +} + void EditorExportPreset::set_custom_features(const String &p_custom_features) { custom_features = p_custom_features; EditorExport::singleton->save_presets(); diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h index de208f410e60..db139d8860bf 100644 --- a/editor/export/editor_export_preset.h +++ b/editor/export/editor_export_preset.h @@ -44,6 +44,14 @@ class EditorExportPreset : public RefCounted { EXPORT_SELECTED_SCENES, EXPORT_SELECTED_RESOURCES, EXCLUDE_SELECTED_RESOURCES, + EXPORT_CUSTOMIZED, + }; + + enum FileExportMode { + MODE_FILE_NOT_CUSTOMIZED, + MODE_FILE_STRIP, + MODE_FILE_KEEP, + MODE_FILE_REMOVE, }; private: @@ -55,7 +63,9 @@ class EditorExportPreset : public RefCounted { String exporter; HashSet selected_files; + HashMap customized_files; bool runnable = false; + bool dedicated_server = false; friend class EditorExport; friend class EditorExportPlatform; @@ -85,20 +95,29 @@ class EditorExportPreset : public RefCounted { bool has(const StringName &p_property) const { return values.has(p_property); } - void update_files_to_export(); + void update_files(); Vector get_files_to_export() const; + Dictionary get_customized_files() const; + int get_customized_files_count() const; + void set_customized_files(const Dictionary &p_files); void add_export_file(const String &p_path); void remove_export_file(const String &p_path); bool has_export_file(const String &p_path); + void set_file_export_mode(const String &p_path, FileExportMode p_mode); + FileExportMode get_file_export_mode(const String &p_path, FileExportMode p_default = MODE_FILE_NOT_CUSTOMIZED) const; + void set_name(const String &p_name); String get_name() const; void set_runnable(bool p_enable); bool is_runnable() const; + void set_dedicated_server(bool p_enable); + bool is_dedicated_server() const; + void set_export_filter(ExportFilter p_filter); ExportFilter get_export_filter() const; diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index 2caebc6f04bd..52c192164fc0 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -45,6 +45,7 @@ #include "scene/gui/link_button.h" #include "scene/gui/menu_button.h" #include "scene/gui/option_button.h" +#include "scene/gui/popup_menu.h" #include "scene/gui/split_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" @@ -165,7 +166,7 @@ void ProjectExportDialog::_update_presets() { if (preset->is_runnable()) { preset_name += " (" + TTR("Runnable") + ")"; } - preset->update_files_to_export(); + preset->update_files(); presets->add_item(preset_name, preset->get_platform()->get_logo()); } @@ -244,6 +245,7 @@ void ProjectExportDialog::_edit_preset(int p_index) { export_filter->select(current->get_export_filter()); include_filters->set_text(current->get_include_filter()); exclude_filters->set_text(current->get_exclude_filter()); + server_strip_message->set_visible(current->get_export_filter() == EditorExportPreset::EXPORT_CUSTOMIZED); _fill_resource_tree(); @@ -570,6 +572,7 @@ void ProjectExportDialog::_duplicate_preset() { if (make_runnable) { preset->set_runnable(make_runnable); } + preset->set_dedicated_server(current->is_dedicated_server()); preset->set_export_filter(current->get_export_filter()); preset->set_include_filter(current->get_include_filter()); preset->set_exclude_filter(current->get_exclude_filter()); @@ -692,7 +695,16 @@ void ProjectExportDialog::_export_type_changed(int p_which) { return; } - current->set_export_filter(EditorExportPreset::ExportFilter(p_which)); + EditorExportPreset::ExportFilter filter_type = (EditorExportPreset::ExportFilter)p_which; + current->set_export_filter(filter_type); + current->set_dedicated_server(filter_type == EditorExportPreset::EXPORT_CUSTOMIZED); + server_strip_message->set_visible(filter_type == EditorExportPreset::EXPORT_CUSTOMIZED); + + // Default to stripping everything when first switching to server build. + if (filter_type == EditorExportPreset::EXPORT_CUSTOMIZED && current->get_customized_files_count() == 0) { + current->set_file_export_mode("res://", EditorExportPreset::MODE_FILE_STRIP); + } + updating = true; _fill_resource_tree(); updating = false; @@ -728,25 +740,53 @@ void ProjectExportDialog::_fill_resource_tree() { return; } + TreeItem *root = include_files->create_item(); + + if (f == EditorExportPreset::EXPORT_CUSTOMIZED) { + include_files->set_columns(2); + include_files->set_column_expand(1, false); + include_files->set_column_custom_minimum_width(1, 250 * EDSCALE); + } else { + include_files->set_columns(1); + } + include_label->show(); include_margin->show(); - TreeItem *root = include_files->create_item(); + _fill_tree(EditorFileSystem::get_singleton()->get_filesystem(), root, current, f); +} - _fill_tree(EditorFileSystem::get_singleton()->get_filesystem(), root, current, f == EditorExportPreset::EXPORT_SELECTED_SCENES); +void ProjectExportDialog::_setup_item_for_file_mode(TreeItem *p_item, EditorExportPreset::FileExportMode p_mode) { + if (p_mode == EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED) { + p_item->set_checked(0, false); + p_item->set_cell_mode(1, TreeItem::CELL_MODE_STRING); + p_item->set_text(1, ""); + p_item->set_editable(1, false); + p_item->set_selectable(1, false); + } else { + p_item->set_checked(0, true); + p_item->set_cell_mode(1, TreeItem::CELL_MODE_CUSTOM); + p_item->set_text(1, file_mode_popup->get_item_text(file_mode_popup->get_item_index(p_mode))); + p_item->set_editable(1, true); + p_item->set_selectable(1, true); + } } -bool ProjectExportDialog::_fill_tree(EditorFileSystemDirectory *p_dir, TreeItem *p_item, Ref ¤t, bool p_only_scenes) { +bool ProjectExportDialog::_fill_tree(EditorFileSystemDirectory *p_dir, TreeItem *p_item, Ref ¤t, EditorExportPreset::ExportFilter p_export_filter) { p_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); p_item->set_icon(0, presets->get_theme_icon(SNAME("folder"), SNAME("FileDialog"))); p_item->set_text(0, p_dir->get_name() + "/"); p_item->set_editable(0, true); p_item->set_metadata(0, p_dir->get_path()); + if (p_export_filter == EditorExportPreset::EXPORT_CUSTOMIZED) { + _setup_item_for_file_mode(p_item, current->get_file_export_mode(p_dir->get_path())); + } + bool used = false; for (int i = 0; i < p_dir->get_subdir_count(); i++) { TreeItem *subdir = include_files->create_item(p_item); - if (_fill_tree(p_dir->get_subdir(i), subdir, current, p_only_scenes)) { + if (_fill_tree(p_dir->get_subdir(i), subdir, current, p_export_filter)) { used = true; } else { memdelete(subdir); @@ -755,7 +795,7 @@ bool ProjectExportDialog::_fill_tree(EditorFileSystemDirectory *p_dir, TreeItem for (int i = 0; i < p_dir->get_file_count(); i++) { String type = p_dir->get_file_type(i); - if (p_only_scenes && type != "PackedScene") { + if (p_export_filter == EditorExportPreset::EXPORT_SELECTED_SCENES && type != "PackedScene") { continue; } if (type == "TextFile") { @@ -770,9 +810,14 @@ bool ProjectExportDialog::_fill_tree(EditorFileSystemDirectory *p_dir, TreeItem file->set_icon(0, EditorNode::get_singleton()->get_class_icon(type)); file->set_editable(0, true); - file->set_checked(0, current->has_export_file(path)); file->set_metadata(0, path); - file->propagate_check(0); + + if (p_export_filter == EditorExportPreset::EXPORT_CUSTOMIZED) { + _setup_item_for_file_mode(file, current->get_file_export_mode(path)); + } else { + file->set_checked(0, current->has_export_file(path)); + file->propagate_check(0); + } used = true; } @@ -794,7 +839,19 @@ void ProjectExportDialog::_tree_changed() { return; } - item->propagate_check(0); + if (current->get_export_filter() == EditorExportPreset::EXPORT_CUSTOMIZED) { + EditorExportPreset::FileExportMode file_mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED; + String path = item->get_metadata(0); + + if (item->is_checked(0)) { + file_mode = current->get_file_export_mode(path, EditorExportPreset::MODE_FILE_STRIP); + } + + _setup_item_for_file_mode(item, file_mode); + current->set_file_export_mode(path, file_mode); + } else { + item->propagate_check(0); + } } void ProjectExportDialog::_check_propagated_to_item(Object *p_obj, int column) { @@ -814,6 +871,30 @@ void ProjectExportDialog::_check_propagated_to_item(Object *p_obj, int column) { } } +void ProjectExportDialog::_tree_popup_edited(bool p_arrow_clicked) { + Rect2 bounds = include_files->get_custom_popup_rect(); + bounds.position += get_global_canvas_transform().get_origin(); + bounds.size *= get_global_canvas_transform().get_scale(); + if (!is_embedding_subwindows()) { + bounds.position += get_position(); + } + file_mode_popup->popup(bounds); +} + +void ProjectExportDialog::_set_file_export_mode(int p_id) { + Ref current = get_current_preset(); + if (current.is_null()) { + return; + } + + TreeItem *item = include_files->get_edited(); + String path = item->get_metadata(0); + + current->set_file_export_mode(path, (EditorExportPreset::FileExportMode)p_id); + + item->set_text(1, file_mode_popup->get_item_text(file_mode_popup->get_item_index(p_id))); +} + void ProjectExportDialog::_export_pck_zip() { Ref current = get_current_preset(); ERR_FAIL_COND(current.is_null()); @@ -1068,6 +1149,7 @@ ProjectExportDialog::ProjectExportDialog() { export_filter->add_item(TTR("Export selected scenes (and dependencies)")); export_filter->add_item(TTR("Export selected resources (and dependencies)")); export_filter->add_item(TTR("Export all resources in the project except resources checked below")); + export_filter->add_item(TTR("Export as dedicated server")); resources_vb->add_margin_child(TTR("Export Mode:"), export_filter); export_filter->connect("item_selected", callable_mp(this, &ProjectExportDialog::_export_type_changed)); @@ -1082,6 +1164,36 @@ ProjectExportDialog::ProjectExportDialog() { include_margin->add_child(include_files); include_files->connect("item_edited", callable_mp(this, &ProjectExportDialog::_tree_changed)); include_files->connect("check_propagated_to_item", callable_mp(this, &ProjectExportDialog::_check_propagated_to_item)); + include_files->connect("custom_popup_edited", callable_mp(this, &ProjectExportDialog::_tree_popup_edited)); + + server_strip_message = memnew(Label); + server_strip_message->set_visible(false); + server_strip_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + resources_vb->add_child(server_strip_message); + + { + List resource_names; + ClassDB::get_inheriters_from_class("Resource", &resource_names); + + PackedStringArray strippable; + for (StringName resource_name : resource_names) { + if (ClassDB::has_method(resource_name, "create_placeholder", true)) { + strippable.push_back(resource_name); + } + } + strippable.sort(); + + String message = TTR("\"Strip Visuals\" will replace the following resources with placeholders:") + " "; + message += String(", ").join(strippable); + server_strip_message->set_text(message); + } + + file_mode_popup = memnew(PopupMenu); + add_child(file_mode_popup); + file_mode_popup->add_item(TTR("Strip Visuals"), EditorExportPreset::MODE_FILE_STRIP); + file_mode_popup->add_item(TTR("Keep"), EditorExportPreset::MODE_FILE_KEEP); + file_mode_popup->add_item(TTR("Remove"), EditorExportPreset::MODE_FILE_REMOVE); + file_mode_popup->connect("id_pressed", callable_mp(this, &ProjectExportDialog::_set_file_export_mode)); include_filters = memnew(LineEdit); resources_vb->add_margin_child( diff --git a/editor/export/project_export.h b/editor/export/project_export.h index d392dba2a4d0..63f8fc4a2eaf 100644 --- a/editor/export/project_export.h +++ b/editor/export/project_export.h @@ -31,11 +31,11 @@ #ifndef PROJECT_EXPORT_H #define PROJECT_EXPORT_H +#include "editor/export/editor_export_preset.h" #include "scene/gui/dialogs.h" class CheckBox; class CheckButton; -class EditorExportPreset; class EditorFileDialog; class EditorFileSystemDirectory; class EditorInspector; @@ -43,6 +43,7 @@ class EditorPropertyPath; class ItemList; class MenuButton; class OptionButton; +class PopupMenu; class RichTextLabel; class TabContainer; class Tree; @@ -75,6 +76,8 @@ class ProjectExportDialog : public ConfirmationDialog { LineEdit *include_filters = nullptr; LineEdit *exclude_filters = nullptr; Tree *include_files = nullptr; + Label *server_strip_message = nullptr; + PopupMenu *file_mode_popup = nullptr; Label *include_label = nullptr; MarginContainer *include_margin = nullptr; @@ -113,9 +116,12 @@ class ProjectExportDialog : public ConfirmationDialog { void _export_type_changed(int p_which); void _filter_changed(const String &p_filter); void _fill_resource_tree(); - bool _fill_tree(EditorFileSystemDirectory *p_dir, TreeItem *p_item, Ref ¤t, bool p_only_scenes); + void _setup_item_for_file_mode(TreeItem *p_item, EditorExportPreset::FileExportMode p_mode); + bool _fill_tree(EditorFileSystemDirectory *p_dir, TreeItem *p_item, Ref ¤t, EditorExportPreset::ExportFilter p_export_filter); void _tree_changed(); void _check_propagated_to_item(Object *p_obj, int column); + void _tree_popup_edited(bool p_arrow_clicked); + void _set_file_export_mode(int p_id); Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; diff --git a/editor/plugins/dedicated_server_export_plugin.cpp b/editor/plugins/dedicated_server_export_plugin.cpp new file mode 100644 index 000000000000..013706034eb1 --- /dev/null +++ b/editor/plugins/dedicated_server_export_plugin.cpp @@ -0,0 +1,139 @@ +/**************************************************************************/ +/* dedicated_server_export_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "dedicated_server_export_plugin.h" + +EditorExportPreset::FileExportMode DedicatedServerExportPlugin::_get_export_mode_for_path(const String &p_path) { + Ref preset = get_export_preset(); + ERR_FAIL_COND_V(preset.is_null(), EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED); + + EditorExportPreset::FileExportMode mode = preset->get_file_export_mode(p_path); + if (mode != EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED) { + return mode; + } + + String path = p_path; + if (path.begins_with("res://")) { + path = path.substr(6); + } + + Vector parts = path.split("/"); + + while (parts.size() > 0) { + parts.resize(parts.size() - 1); + + String test_path = "res://"; + if (parts.size() > 0) { + test_path += String("/").join(parts) + "/"; + } + + mode = preset->get_file_export_mode(test_path); + if (mode != EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED) { + break; + } + } + + return mode; +} + +PackedStringArray DedicatedServerExportPlugin::_get_export_features(const Ref &p_platform, bool p_debug) const { + PackedStringArray ret; + + Ref preset = get_export_preset(); + ERR_FAIL_COND_V(preset.is_null(), ret); + + if (preset->is_dedicated_server()) { + ret.append("dedicated_server"); + } + return ret; +} + +uint64_t DedicatedServerExportPlugin::_get_customization_configuration_hash() const { + Ref preset = get_export_preset(); + ERR_FAIL_COND_V(preset.is_null(), 0); + + if (preset->get_export_filter() != EditorExportPreset::EXPORT_CUSTOMIZED) { + return 0; + } + + return preset->get_customized_files().hash(); +} + +bool DedicatedServerExportPlugin::_begin_customize_scenes(const Ref &p_platform, const Vector &p_features) { + Ref preset = get_export_preset(); + ERR_FAIL_COND_V(preset.is_null(), false); + + current_export_mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED; + + return preset->get_export_filter() == EditorExportPreset::EXPORT_CUSTOMIZED; +} + +bool DedicatedServerExportPlugin::_begin_customize_resources(const Ref &p_platform, const Vector &p_features) { + Ref preset = get_export_preset(); + ERR_FAIL_COND_V(preset.is_null(), false); + + current_export_mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED; + + return preset->get_export_filter() == EditorExportPreset::EXPORT_CUSTOMIZED; +} + +Node *DedicatedServerExportPlugin::_customize_scene(Node *p_root, const String &p_path) { + // Simply set the export mode based on the scene path. All the real + // customization happens in _customize_resource(). + current_export_mode = _get_export_mode_for_path(p_path); + return nullptr; +} + +Ref DedicatedServerExportPlugin::_customize_resource(const Ref &p_resource, const String &p_path) { + // If the resource has a path, we use that to get our export mode. But if it + // doesn't, we assume that this resource is embedded in the last resource with + // a path. + if (p_path != "") { + current_export_mode = _get_export_mode_for_path(p_path); + } + + if (p_resource.is_valid() && current_export_mode == EditorExportPreset::MODE_FILE_STRIP && p_resource->has_method("create_placeholder")) { + Callable::CallError err; + Ref result = const_cast(p_resource.ptr())->callp("create_placeholder", nullptr, 0, err); + if (err.error == Callable::CallError::CALL_OK) { + return result; + } + } + + return Ref(); +} + +void DedicatedServerExportPlugin::_end_customize_scenes() { + current_export_mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED; +} + +void DedicatedServerExportPlugin::_end_customize_resources() { + current_export_mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED; +} diff --git a/editor/plugins/dedicated_server_export_plugin.h b/editor/plugins/dedicated_server_export_plugin.h new file mode 100644 index 000000000000..cb014ae52dc2 --- /dev/null +++ b/editor/plugins/dedicated_server_export_plugin.h @@ -0,0 +1,58 @@ +/**************************************************************************/ +/* dedicated_server_export_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DEDICATED_SERVER_EXPORT_PLUGIN_H +#define DEDICATED_SERVER_EXPORT_PLUGIN_H + +#include "editor/export/editor_export.h" + +class DedicatedServerExportPlugin : public EditorExportPlugin { +private: + EditorExportPreset::FileExportMode current_export_mode; + + EditorExportPreset::FileExportMode _get_export_mode_for_path(const String &p_path); + +protected: + String _get_name() const override { return "DedicatedServer"; } + + PackedStringArray _get_export_features(const Ref &p_platform, bool p_debug) const override; + uint64_t _get_customization_configuration_hash() const override; + + bool _begin_customize_scenes(const Ref &p_platform, const Vector &p_features) override; + bool _begin_customize_resources(const Ref &p_platform, const Vector &p_features) override; + + Node *_customize_scene(Node *p_root, const String &p_path) override; + Ref _customize_resource(const Ref &p_resource, const String &p_path) override; + + void _end_customize_scenes() override; + void _end_customize_resources() override; +}; + +#endif // DEDICATED_SERVER_EXPORT_PLUGIN_H diff --git a/main/main.cpp b/main/main.cpp index eff30bee9b0f..c5a9f94417e3 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -208,6 +208,11 @@ static bool dump_extension_api = false; #endif bool profile_gpu = false; +// Constants. + +static const String NULL_DISPLAY_DRIVER("headless"); +static const String NULL_AUDIO_DRIVER("Dummy"); + /* Helper methods */ bool Main::is_cmdline_tool() { @@ -1003,8 +1008,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--headless") { // enable headless mode (no audio, no rendering). - audio_driver = "Dummy"; - display_driver = "headless"; + audio_driver = NULL_AUDIO_DRIVER; + display_driver = NULL_DISPLAY_DRIVER; } else if (I->get() == "--profiling") { // enable profiling @@ -1139,8 +1144,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph // `--doctool` implies `--headless` to avoid spawning an unnecessary window // and speed up class reference generation. - audio_driver = "Dummy"; - display_driver = "headless"; + audio_driver = NULL_AUDIO_DRIVER; + display_driver = NULL_DISPLAY_DRIVER; main_args.push_back(I->get()); #endif } else if (I->get() == "--path") { // set path of project to start or edit @@ -1377,6 +1382,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph ResourceUID::get_singleton()->load_from_cache(); // load UUIDs from cache. + if (ProjectSettings::get_singleton()->has_custom_feature("dedicated_server")) { + audio_driver = NULL_AUDIO_DRIVER; + display_driver = NULL_DISPLAY_DRIVER; + } + GLOBAL_DEF(PropertyInfo(Variant::INT, "network/limits/debugger/max_chars_per_second", PROPERTY_HINT_RANGE, "0, 4096, 1, or_greater"), 32768); GLOBAL_DEF(PropertyInfo(Variant::INT, "network/limits/debugger/max_queued_messages", PROPERTY_HINT_RANGE, "0, 8192, 1, or_greater"), 2048); GLOBAL_DEF(PropertyInfo(Variant::INT, "network/limits/debugger/max_errors_per_second", PROPERTY_HINT_RANGE, "0, 200, 1, or_greater"), 400); @@ -1730,7 +1740,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph // Display driver, e.g. X11, Wayland. // Make sure that headless is the last one, which it is assumed to be by design. - DEV_ASSERT(String("headless") == DisplayServer::get_create_function_name(DisplayServer::get_create_function_count() - 1)); + DEV_ASSERT(NULL_DISPLAY_DRIVER == DisplayServer::get_create_function_name(DisplayServer::get_create_function_count() - 1)); for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { String name = DisplayServer::get_create_function_name(i); if (display_driver == name) { @@ -1755,7 +1765,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } // Make sure that dummy is the last one, which it is assumed to be by design. - DEV_ASSERT(String("Dummy") == AudioDriverManager::get_driver(AudioDriverManager::get_driver_count() - 1)->get_name()); + DEV_ASSERT(NULL_AUDIO_DRIVER == AudioDriverManager::get_driver(AudioDriverManager::get_driver_count() - 1)->get_name()); for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) { if (audio_driver == AudioDriverManager::get_driver(i)->get_name()) { audio_driver_idx = i; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 9c3a2ffb8775..f4aa0637f7a2 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -113,6 +113,12 @@ bool Material::_can_use_render_priority() const { return ret; } +Ref Material::create_placeholder() const { + Ref placeholder; + placeholder.instantiate(); + return placeholder; +} + void Material::_bind_methods() { ClassDB::bind_method(D_METHOD("set_next_pass", "next_pass"), &Material::set_next_pass); ClassDB::bind_method(D_METHOD("get_next_pass"), &Material::get_next_pass); @@ -123,6 +129,8 @@ void Material::_bind_methods() { ClassDB::bind_method(D_METHOD("inspect_native_shader_code"), &Material::inspect_native_shader_code); ClassDB::set_method_flags(get_class_static(), _scs_create("inspect_native_shader_code"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); + ClassDB::bind_method(D_METHOD("create_placeholder"), &Material::create_placeholder); + ADD_PROPERTY(PropertyInfo(Variant::INT, "render_priority", PROPERTY_HINT_RANGE, itos(RENDER_PRIORITY_MIN) + "," + itos(RENDER_PRIORITY_MAX) + ",1"), "set_render_priority", "get_render_priority"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "next_pass", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_next_pass", "get_next_pass"); diff --git a/scene/resources/material.h b/scene/resources/material.h index 83c7a09cc47c..fe1448cd4c6b 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -74,6 +74,9 @@ class Material : public Resource { virtual RID get_rid() const override; virtual RID get_shader_rid() const; virtual Shader::Mode get_shader_mode() const; + + virtual Ref create_placeholder() const; + Material(); virtual ~Material(); }; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 991e060e9448..cf9baa290733 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -615,6 +615,13 @@ Size2i Mesh::get_lightmap_size_hint() const { return lightmap_size_hint; } +Ref Mesh::create_placeholder() const { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_aabb(get_aabb()); + return placeholder; +} + void Mesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &Mesh::set_lightmap_size_hint); ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &Mesh::get_lightmap_size_hint); @@ -627,6 +634,7 @@ void Mesh::_bind_methods() { ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &Mesh::surface_get_blend_shape_arrays); ClassDB::bind_method(D_METHOD("surface_set_material", "surf_idx", "material"), &Mesh::surface_set_material); ClassDB::bind_method(D_METHOD("surface_get_material", "surf_idx"), &Mesh::surface_get_material); + ClassDB::bind_method(D_METHOD("create_placeholder"), &Mesh::create_placeholder); BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 1baa46631228..1b870d996ae8 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -220,6 +220,8 @@ class Mesh : public Resource { virtual int get_builtin_bind_pose_count() const; virtual Transform3D get_builtin_bind_pose(int p_index) const; + virtual Ref create_placeholder() const; + Mesh(); }; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index f106eebff5c9..85e21d605600 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -94,6 +94,13 @@ bool Texture2D::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Re return true; } +Ref Texture2D::create_placeholder() const { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(get_size()); + return placeholder; +} + void Texture2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_width"), &Texture2D::get_width); ClassDB::bind_method(D_METHOD("get_height"), &Texture2D::get_height); @@ -103,6 +110,7 @@ void Texture2D::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose"), &Texture2D::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &Texture2D::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_image"), &Texture2D::get_image); + ClassDB::bind_method(D_METHOD("create_placeholder"), &Texture2D::create_placeholder); ADD_GROUP("", ""); @@ -1137,6 +1145,7 @@ void Texture3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_depth"), &Texture3D::get_depth); ClassDB::bind_method(D_METHOD("has_mipmaps"), &Texture3D::has_mipmaps); ClassDB::bind_method(D_METHOD("get_data"), &Texture3D::_get_datai); + ClassDB::bind_method(D_METHOD("create_placeholder"), &Texture3D::create_placeholder); GDVIRTUAL_BIND(_get_format); GDVIRTUAL_BIND(_get_width); @@ -1145,6 +1154,14 @@ void Texture3D::_bind_methods() { GDVIRTUAL_BIND(_has_mipmaps); GDVIRTUAL_BIND(_get_data); } + +Ref Texture3D::create_placeholder() const { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(Vector3i(get_width(), get_height(), get_depth())); + return placeholder; +} + ////////////////////////////////////////// Image::Format ImageTexture3D::get_format() const { @@ -3048,6 +3065,42 @@ ImageTextureLayered::~ImageTextureLayered() { } } +void Texture2DArray::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_placeholder"), &Texture2DArray::create_placeholder); +} + +Ref Texture2DArray::create_placeholder() const { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(Size2i(get_width(), get_height())); + placeholder->set_layers(get_layers()); + return placeholder; +} + +void Cubemap::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_placeholder"), &Cubemap::create_placeholder); +} + +Ref Cubemap::create_placeholder() const { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(Size2i(get_width(), get_height())); + placeholder->set_layers(get_layers()); + return placeholder; +} + +void CubemapArray::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_placeholder"), &CubemapArray::create_placeholder); +} + +Ref CubemapArray::create_placeholder() const { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(Size2i(get_width(), get_height())); + placeholder->set_layers(get_layers()); + return placeholder; +} + /////////////////////////////////////////// void CompressedTextureLayered::set_path(const String &p_path, bool p_take_over) { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index bb86910c0c63..7f74ae6941c5 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -82,6 +82,8 @@ class Texture2D : public Texture { virtual Ref get_image() const { return Ref(); } + virtual Ref create_placeholder() const; + Texture2D(); }; @@ -450,25 +452,41 @@ class ImageTextureLayered : public TextureLayered { class Texture2DArray : public ImageTextureLayered { GDCLASS(Texture2DArray, ImageTextureLayered) + +protected: + static void _bind_methods(); + public: Texture2DArray() : ImageTextureLayered(LAYERED_TYPE_2D_ARRAY) {} + + virtual Ref create_placeholder() const; }; class Cubemap : public ImageTextureLayered { GDCLASS(Cubemap, ImageTextureLayered); +protected: + static void _bind_methods(); + public: Cubemap() : ImageTextureLayered(LAYERED_TYPE_CUBEMAP) {} + + virtual Ref create_placeholder() const; }; class CubemapArray : public ImageTextureLayered { GDCLASS(CubemapArray, ImageTextureLayered); +protected: + static void _bind_methods(); + public: CubemapArray() : ImageTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {} + + virtual Ref create_placeholder() const; }; class CompressedTextureLayered : public TextureLayered { @@ -580,6 +598,7 @@ class Texture3D : public Texture { virtual int get_depth() const; virtual bool has_mipmaps() const; virtual Vector> get_data() const; + virtual Ref create_placeholder() const; }; class ImageTexture3D : public Texture3D {