diff --git a/core/io/resource.cpp b/core/io/resource.cpp index be75ad7e2598..6cab20a20fa8 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -438,6 +438,15 @@ void Resource::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_path", "get_path"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_name"), "set_name", "get_name"); +#ifdef TOOLS_ENABLED + ClassDB::bind_method(D_METHOD("set_dedicated_server_export_type", "server_export_type"), &Resource::set_dedicated_server_export_type); + ClassDB::bind_method(D_METHOD("get_dedicated_server_export_type"), &Resource::get_dedicated_server_export_type); + ADD_PROPERTY(PropertyInfo(Variant::INT, "resource_dedicated_server_export_type", PROPERTY_HINT_ENUM, "Strip,Keep"), "set_dedicated_server_export_type", "get_dedicated_server_export_type"); + + BIND_ENUM_CONSTANT(DEDICATED_SERVER_EXPORT_STRIP); + BIND_ENUM_CONSTANT(DEDICATED_SERVER_EXPORT_KEEP); +#endif + MethodInfo get_rid_bind("_get_rid"); get_rid_bind.return_val.type = Variant::RID; diff --git a/core/io/resource.h b/core/io/resource.h index a76a3920be67..c951e5edf46e 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -53,6 +53,13 @@ class Resource : public RefCounted { static void register_custom_data_to_otdb() { ClassDB::add_resource_base_extension("res", get_class_static()); } virtual String get_base_extension() const { return "res"; } +#ifdef TOOLS_ENABLED + enum DedicatedServerExportType { + DEDICATED_SERVER_EXPORT_STRIP, + DEDICATED_SERVER_EXPORT_KEEP, + }; +#endif + private: HashSet owners; @@ -67,6 +74,7 @@ class Resource : public RefCounted { uint64_t last_modified_time = 0; uint64_t import_last_modified_time = 0; String import_path; + DedicatedServerExportType dedicated_server_export_type = DEDICATED_SERVER_EXPORT_STRIP; #endif bool local_to_scene = false; @@ -133,6 +141,12 @@ class Resource : public RefCounted { void set_import_path(const String &p_path) { import_path = p_path; } String get_import_path() const { return import_path; } + void set_dedicated_server_export_type(DedicatedServerExportType p_server_export_type) { + dedicated_server_export_type = p_server_export_type; + emit_changed(); + } + DedicatedServerExportType get_dedicated_server_export_type() const { return dedicated_server_export_type; } + #endif void set_as_translation_remapped(bool p_remapped); @@ -150,6 +164,10 @@ class Resource : public RefCounted { ~Resource(); }; +#ifdef TOOLS_ENABLED +VARIANT_ENUM_CAST(Resource::DedicatedServerExportType); +#endif + class ResourceCache { friend class Resource; friend class ResourceLoader; //need the lock diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index 564b37e66233..14d9eb9cbbe7 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -62,6 +62,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy int lines = 0; String error_text; + String section; bool path_found = false; //first match must have priority while (true) { assign = Variant(); @@ -76,7 +77,14 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy return err; } - if (!assign.is_empty()) { + if (assign.is_empty()) { + if (!next_tag.name.is_empty()) { + section = next_tag.name; + } + continue; + } + + if (section == "remap") { if (!path_found && assign.begins_with("path.") && r_path_and_type.path.is_empty()) { String feature = assign.get_slicec('.', 1); if (OS::get_singleton()->has_feature(feature)) { @@ -103,8 +111,15 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy } } - } else if (next_tag.name != "remap") { + } else { +#ifdef TOOLS_ENABLED + if (section == "params" && assign == "dedicated_server/server_export_type") { + r_path_and_type.dedicated_server_export_type = (Resource::DedicatedServerExportType)(int)value; + break; + } +#else break; +#endif // TOOLS_ENABLED } } @@ -141,6 +156,7 @@ Ref ResourceFormatImporter::load(const String &p_path, const String &p if (res.is_valid()) { res->set_import_last_modified_time(res->get_last_modified_time()); //pass this, if used res->set_import_path(pat.path); + res->set_dedicated_server_export_type(pat.dedicated_server_export_type); } #endif @@ -476,6 +492,15 @@ void ResourceImporter::_bind_methods() { BIND_ENUM_CONSTANT(IMPORT_ORDER_SCENE); } +#ifdef TOOLS_ENABLED +void ResourceImporter::get_editor_import_options(const String &p_path, List *r_options, int p_preset) { + get_import_options(p_path, r_options, p_preset); + + // Add default editor options. + r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "dedicated_server/server_export_type", PROPERTY_HINT_ENUM, "Strip,Keep"), 0)); +} +#endif + void ResourceFormatImporter::add_importer(const Ref &p_importer, bool p_first_priority) { ERR_FAIL_COND(p_importer.is_null()); if (p_first_priority) { diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index d0ea98b5983f..64258bbe25ab 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -43,6 +43,9 @@ class ResourceFormatImporter : public ResourceFormatLoader { String group_file; Variant metadata; uint64_t uid = ResourceUID::INVALID_ID; +#ifdef TOOLS_ENABLED + Resource::DedicatedServerExportType dedicated_server_export_type; +#endif }; Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = nullptr) const; @@ -145,6 +148,10 @@ class ResourceImporter : public RefCounted { virtual Error import_group_file(const String &p_group_file, const HashMap> &p_source_file_options, const HashMap &p_base_paths) { return ERR_UNAVAILABLE; } virtual bool are_import_settings_valid(const String &p_path) const { return true; } virtual String get_import_settings_string() const { return String(); } + +#ifdef TOOLS_ENABLED + void get_editor_import_options(const String &p_path, List *r_options, int p_preset = 0); +#endif }; VARIANT_ENUM_CAST(ResourceImporter::ImportOrder); diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml index e533fc1e32ad..c8bac3466f52 100644 --- a/doc/classes/Resource.xml +++ b/doc/classes/Resource.xml @@ -82,6 +82,9 @@ + + Controls how this resource should be handled in a dedicated server export. + If [code]true[/code], the resource is duplicated for each instance of all scenes using it. At run-time, the resource can be modified in one scene without affecting other instances (see [method PackedScene.instantiate]). [b]Note:[/b] Changing this property at run-time has no effect on already created duplicate resources. @@ -107,4 +110,12 @@ + + + Replace this resource with a placeholder (if available) in a dedicated server export. + + + Keep this resource in a dedicated server export. + + diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 14a2640e6399..d79bba3a323c 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -432,7 +432,7 @@ void DocTools::generate(bool p_basic_types) { Variant default_value; if (name == "EditorSettings") { - if (E.name == "resource_local_to_scene" || E.name == "resource_name" || E.name == "resource_path" || E.name == "script") { + if (E.name == "resource_local_to_scene" || E.name == "resource_name" || E.name == "resource_path" || E.name == "resource_dedicated_server_export_type" || E.name == "script") { // Don't include spurious properties in the generated EditorSettings class reference. continue; } diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 5d137ce29013..4a963ef39110 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1667,7 +1667,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector Ref importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name); ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_CORRUPT); List options; - importer->get_import_options(p_files[i], &options); + importer->get_editor_import_options(p_files[i], &options); //set default values for (const ResourceImporter::ImportOption &E : options) { source_file_options[p_files[i]][E.option.name] = E.default_value; @@ -1748,7 +1748,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector //store options in provided order, to avoid file changing. Order is also important because first match is accepted first. List options; - importer->get_import_options(file, &options); + importer->get_editor_import_options(file, &options); //set default values for (const ResourceImporter::ImportOption &F : options) { String base = F.option.name; @@ -1885,7 +1885,7 @@ void EditorFileSystem::_reimport_file(const String &p_file, const HashMap opts; - importer->get_import_options(p_file, &opts); + importer->get_editor_import_options(p_file, &opts); for (const ResourceImporter::ImportOption &E : opts) { if (!params.has(E.option.name)) { //this one is not present params[E.option.name] = E.default_value; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 06e1e8b22eba..aa1014f0de27 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -123,6 +123,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" @@ -7332,6 +7333,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/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index 5c8ef89ac93b..a3f9f606ef8f 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -95,7 +95,7 @@ class SectionedInspectorFilter : public Object { for (PropertyInfo &pi : pinfo) { int sp = pi.name.find("/"); - if (pi.name == "resource_path" || pi.name == "resource_name" || pi.name == "resource_local_to_scene" || pi.name.begins_with("script/") || pi.name.begins_with("_global_script")) { //skip resource stuff + if (pi.name == "resource_path" || pi.name == "resource_name" || pi.name == "resource_local_to_scene" || pi.name == "resource_dedicated_server_export_type" || pi.name.begins_with("script/") || pi.name.begins_with("_global_script")) { //skip resource stuff continue; } @@ -243,7 +243,7 @@ void SectionedInspector::update_category_list() { continue; } - if (pi.name.contains(":") || pi.name == "script" || pi.name == "resource_name" || pi.name == "resource_path" || pi.name == "resource_local_to_scene" || pi.name.begins_with("_global_script")) { + if (pi.name.contains(":") || pi.name == "script" || pi.name == "resource_name" || pi.name == "resource_path" || pi.name == "resource_local_to_scene" || pi.name == "resource_dedicated_server_export_type" || pi.name.begins_with("_global_script")) { continue; } diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 7c5c7da2efbb..9ba80711ec65 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -659,6 +659,9 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector return p_path; // do none } + String import_path = p_path + ".import"; + bool import_exists = FileAccess::exists(import_path); + // Check if a cache exists if (export_cache.has(p_path)) { FileExportCache &fec = export_cache[p_path]; @@ -667,20 +670,22 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector // Destination file exists (was not erased) or not needed uint64_t mod_time = FileAccess::get_modified_time(p_path); - if (fec.source_modified_time == mod_time) { + uint64_t import_mod_time = import_exists ? FileAccess::get_modified_time(import_path) : 0; + if (fec.source_modified_time == mod_time && fec.import_modified_time == import_mod_time) { // Cached (modified time matches). fec.used = true; return fec.saved_path.is_empty() ? p_path : fec.saved_path; } String md5 = FileAccess::get_md5(p_path); - if (FileAccess::exists(p_path + ".import")) { + if (import_exists) { // Also consider the import file in the string - md5 += FileAccess::get_md5(p_path + ".import"); + md5 += FileAccess::get_md5(import_path); } if (fec.source_md5 == md5) { // Cached (md5 matches). fec.source_modified_time = mod_time; + fec.import_modified_time = import_mod_time; fec.used = true; return fec.saved_path.is_empty() ? p_path : fec.saved_path; } @@ -690,11 +695,12 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector FileExportCache fec; fec.used = true; fec.source_modified_time = FileAccess::get_modified_time(p_path); + fec.import_modified_time = import_exists ? FileAccess::get_modified_time(import_path) : 0; String md5 = FileAccess::get_md5(p_path); - if (FileAccess::exists(p_path + ".import")) { + if (import_exists) { // Also consider the import file in the string - md5 += FileAccess::get_md5(p_path + ".import"); + md5 += FileAccess::get_md5(import_path); } fec.source_md5 = md5; @@ -963,12 +969,20 @@ Error EditorExportPlatform::export_project_files(const Ref & String l = f->get_line(); while (l != String()) { Vector fields = l.split("::"); - if (fields.size() == 4) { + if (fields.size() >= 4) { FileExportCache fec; String path = fields[0]; fec.source_md5 = fields[1].strip_edges(); fec.source_modified_time = fields[2].strip_edges().to_int(); - fec.saved_path = fields[3]; + if (fields.size() == 5) { + fec.import_modified_time = fields[3].strip_edges().to_int(); + fec.saved_path = fields[4]; + } else { + // Handle file_cache files from older versions that only + // have 4 fields (no import_modified_time). + fec.import_modified_time = 0; + fec.saved_path = fields[3]; + } fec.used = false; // Assume unused until used. export_cache[path] = fec; } @@ -1184,7 +1198,7 @@ Error EditorExportPlatform::export_project_files(const Ref & if (f.is_valid()) { for (const KeyValue &E : export_cache) { if (E.value.used) { // May be old, unused - String l = E.key + "::" + E.value.source_md5 + "::" + itos(E.value.source_modified_time) + "::" + E.value.saved_path; + String l = E.key + "::" + E.value.source_md5 + "::" + itos(E.value.source_modified_time) + "::" + itos(E.value.import_modified_time) + "::" + E.value.saved_path; f->store_line(l); } } @@ -1214,6 +1228,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 5db79b98d1c6..9c5bcba540f4 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -103,6 +103,7 @@ class EditorExportPlatform : public RefCounted { struct FileExportCache { uint64_t source_modified_time = 0; + uint64_t import_modified_time = 0; String source_md5; String saved_path; bool used = false; diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp index 9de2f94900c4..864f10541831 100644 --- a/editor/export/editor_export_platform_pc.cpp +++ b/editor/export/editor_export_platform_pc.cpp @@ -31,6 +31,7 @@ #include "editor_export_platform_pc.h" #include "core/config/project_settings.h" +#include "editor/plugins/dedicated_server_export_plugin.h" void EditorExportPlatformPC::get_preset_features(const Ref &p_preset, List *r_features) const { if (p_preset->get("texture_format/s3tc")) { @@ -61,6 +62,8 @@ void EditorExportPlatformPC::get_export_options(List *r_options) { r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/no_bptc_fallbacks"), true)); + + DedicatedServerExportPlugin::add_export_options(r_options); } String EditorExportPlatformPC::get_name() const { diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp index f0e841f30710..87cbaf68f136 100644 --- a/editor/export/editor_export_plugin.cpp +++ b/editor/export/editor_export_plugin.cpp @@ -184,6 +184,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 3f37ed40beee..b221f147d49b 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) const; // 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) const; // 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/import_defaults_editor.cpp b/editor/import_defaults_editor.cpp index a801a678fcc0..675960c64cc4 100644 --- a/editor/import_defaults_editor.cpp +++ b/editor/import_defaults_editor.cpp @@ -137,7 +137,7 @@ void ImportDefaultsEditor::_update_importer() { if (importer.is_valid()) { List options; - importer->get_import_options("", &options); + importer->get_editor_import_options("", &options); Dictionary d; if (ProjectSettings::get_singleton()->has_setting("importer_defaults/" + importer->get_importer_name())) { d = GLOBAL_GET("importer_defaults/" + importer->get_importer_name()); diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index e6ba19172fe6..3551aad923c6 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -160,7 +160,7 @@ void ImportDock::_update_options(const String &p_path, const Ref &p_ List options; if (params->importer.is_valid()) { - params->importer->get_import_options(p_path, &options); + params->importer->get_editor_import_options(p_path, &options); } params->properties.clear(); @@ -241,7 +241,7 @@ void ImportDock::set_edit_multiple_paths(const Vector &p_paths) { base_path = p_paths[0]; } List options; - params->importer->get_import_options(base_path, &options); + params->importer->get_editor_import_options(base_path, &options); params->properties.clear(); params->values.clear(); @@ -407,7 +407,7 @@ void ImportDock::_preset_selected(int p_idx) { default: { List options; - params->importer->get_import_options(params->base_options_path, &options, p_idx); + params->importer->get_editor_import_options(params->base_options_path, &options, p_idx); if (params->checking) { params->checked.clear(); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index ef9477abea16..d320a699d4c5 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -2144,7 +2144,7 @@ void EditorAnimationMultiTransitionEdit::_get_property_list(List * p_list->push_back(prop_transition_path); for (List::Element *F = plist.front(); F; F = F->next()) { - if (F->get().name == "script" || F->get().name == "resource_name" || F->get().name == "resource_path" || F->get().name == "resource_local_to_scene") { + if (F->get().name == "script" || F->get().name == "resource_name" || F->get().name == "resource_path" || F->get().name == "resource_local_to_scene" || F->get().name == "resource_dedicated_server_export_type") { continue; } diff --git a/editor/plugins/dedicated_server_export_plugin.cpp b/editor/plugins/dedicated_server_export_plugin.cpp new file mode 100644 index 000000000000..f460a609af42 --- /dev/null +++ b/editor/plugins/dedicated_server_export_plugin.cpp @@ -0,0 +1,126 @@ +/*************************************************************************/ +/* dedicated_server_export_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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" + +#define EXPORT_OPTION_IS_DEDICATED_SERVER "dedicated_server/is_server" + +void DedicatedServerExportPlugin::add_export_options(List *r_options) { + r_options->push_back(EditorExportPlatform::ExportOption(PropertyInfo(Variant::BOOL, EXPORT_OPTION_IS_DEDICATED_SERVER), false)); +} + +bool DedicatedServerExportPlugin::is_dedicated_server() const { + Ref preset = get_export_preset(); + ERR_FAIL_COND_V(preset.is_null(), false); + + bool valid_prop = false; + bool is_server = preset->get(EXPORT_OPTION_IS_DEDICATED_SERVER, &valid_prop); + + if (valid_prop) { + return is_server; + } + + return false; +} + +PackedStringArray DedicatedServerExportPlugin::_get_export_features(const Ref &p_platform, bool p_debug) const { + PackedStringArray ret; + if (is_dedicated_server()) { + ret.append("dedicated_server"); + } + return ret; +} + +uint64_t DedicatedServerExportPlugin::_get_customization_configuration_hash() const { + return (uint64_t)is_dedicated_server(); +} + +bool DedicatedServerExportPlugin::_begin_customize_resources(const Ref &p_platform, const Vector &p_features) const { + return is_dedicated_server(); +} + +Ref DedicatedServerExportPlugin::_customize_resource(const Ref &p_resource, const String &p_path) { + if (p_resource->get_dedicated_server_export_type() == Resource::DEDICATED_SERVER_EXPORT_KEEP) { + return Ref(); + } + + if (const Texture2D *texture = Object::cast_to(p_resource.ptr())) { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(texture->get_size()); + return placeholder; + } + + if (const Texture2DArray *texture = Object::cast_to(p_resource.ptr())) { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(Size2i(texture->get_width(), texture->get_height())); + placeholder->set_layers(texture->get_layers()); + return placeholder; + } + + if (const Texture3D *texture = Object::cast_to(p_resource.ptr())) { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(Vector3i(texture->get_width(), texture->get_height(), texture->get_depth())); + return placeholder; + } + + if (const Cubemap *cubemap = Object::cast_to(p_resource.ptr())) { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(Size2i(cubemap->get_width(), cubemap->get_height())); + placeholder->set_layers(cubemap->get_layers()); + return placeholder; + } + + if (const CubemapArray *cubemap = Object::cast_to(p_resource.ptr())) { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_size(Size2i(cubemap->get_width(), cubemap->get_height())); + placeholder->set_layers(cubemap->get_layers()); + return placeholder; + } + + if (Object::cast_to(p_resource.ptr()) != nullptr) { + Ref placeholder; + placeholder.instantiate(); + return placeholder; + } + + if (const Mesh *mesh = Object::cast_to(p_resource.ptr())) { + Ref placeholder; + placeholder.instantiate(); + placeholder->set_aabb(mesh->get_aabb()); + return placeholder; + } + + return Ref(); +} diff --git a/editor/plugins/dedicated_server_export_plugin.h b/editor/plugins/dedicated_server_export_plugin.h new file mode 100644 index 000000000000..2e431d35cbd2 --- /dev/null +++ b/editor/plugins/dedicated_server_export_plugin.h @@ -0,0 +1,51 @@ +/*************************************************************************/ +/* dedicated_server_export_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 { +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_resources(const Ref &p_platform, const Vector &p_features) const override; + Ref _customize_resource(const Ref &p_resource, const String &p_path) override; + + bool is_dedicated_server() const; + +public: + static void add_export_options(List *r_options); +}; + +#endif // DEDICATED_SERVER_EXPORT_PLUGIN_H diff --git a/main/main.cpp b/main/main.cpp index 2d0843a331ba..6b15fac7ec7d 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1351,6 +1351,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 = "Dummy"; + display_driver = "headless"; + } + ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/multithreaded_server/rid_pool_prealloc", PropertyInfo(Variant::INT, "memory/limits/multithreaded_server/rid_pool_prealloc",