diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 329af9068e5e..8a86f4e1c168 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -67,6 +67,10 @@ String ProjectSettings::get_resource_path() const { return resource_path; } +String ProjectSettings::get_main_pack_path() const { + return main_pack_path; +} + String ProjectSettings::get_imported_files_path() const { return get_project_data_path().path_join("imported"); } @@ -477,6 +481,10 @@ bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_f return false; } + if (main_pack_path.is_empty()) { + main_pack_path = p_pack.get_base_dir(); + } + //if data.pck is found, all directory access will be from here DirAccess::make_default(DirAccess::ACCESS_RESOURCES); using_datapack = true; diff --git a/core/config/project_settings.h b/core/config/project_settings.h index 55d5957ad152..6bdee2df6572 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -96,6 +96,7 @@ class ProjectSettings : public Object { RBMap props; // NOTE: Key order is used e.g. in the save_custom method. String resource_path; + String main_pack_path; HashMap custom_prop_info; bool using_datapack = false; bool project_loaded = false; @@ -176,6 +177,7 @@ class ProjectSettings : public Object { String get_project_data_dir_name() const; String get_project_data_path() const; String get_resource_path() const; + String get_main_pack_path() const; String get_imported_files_path() const; static ProjectSettings *get_singleton(); diff --git a/core/extension/gdextension.compat.inc b/core/extension/gdextension.compat.inc new file mode 100644 index 000000000000..381bb12b626c --- /dev/null +++ b/core/extension/gdextension.compat.inc @@ -0,0 +1,43 @@ +/**************************************************************************/ +/* gdextension.compat.inc */ +/**************************************************************************/ +/* 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 DISABLE_DEPRECATED + +#include "gdextension.h" + +Error GDExtension::_open_library_bind_compat_88049(const String &p_path, const String &p_entry_symbol) { + return open_library(p_path, p_entry_symbol, Vector()); +} + +void GDExtension::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::_open_library_bind_compat_88049); +} + +#endif diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index aba96befd6b4..89bc07e88376 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -35,6 +35,7 @@ #include "core/object/method_bind.h" #include "core/os/os.h" #include "core/version.h" +#include "gdextension.compat.inc" #include "gdextension_manager.h" extern void gdextension_setup_interface(); @@ -679,7 +680,7 @@ GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(const String return *function; } -Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) { +Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol, const Vector &p_lookup_paths) { String abs_path = ProjectSettings::get_singleton()->globalize_path(p_path); #if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) // If running on the editor on Windows, we copy the library and open the copy. @@ -716,6 +717,22 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb } #endif + if (!p_lookup_paths.is_empty() && !FileAccess::exists(abs_path) && !DirAccess::exists(abs_path)) { + // Try using custom lookup paths. + for (const String &dir : p_lookup_paths) { + String lookup_dir = dir; + lookup_dir = lookup_dir.begins_with("pck_dir://") ? lookup_dir.replace_first("pck_dir:/", ProjectSettings::get_singleton()->get_main_pack_path()) : lookup_dir; + lookup_dir = lookup_dir.begins_with("bundle_dir://") ? lookup_dir.replace_first("bundle_dir:/", OS::get_singleton()->get_bundle_resource_dir()) : lookup_dir; + lookup_dir = lookup_dir.begins_with("exe_dir://") ? lookup_dir.replace_first("exe_dir:/", OS::get_singleton()->get_executable_path().get_base_dir()) : lookup_dir; + lookup_dir = lookup_dir.path_join(abs_path.get_file()); + lookup_dir = ProjectSettings::get_singleton()->globalize_path(lookup_dir); + if (FileAccess::exists(lookup_dir) || DirAccess::exists(lookup_dir)) { + abs_path = lookup_dir; + break; + } + } + } + Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, true, &library_path); ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, "GDExtension dynamic library not found: " + abs_path); ERR_FAIL_COND_V_MSG(err != OK, err, "Can't open GDExtension dynamic library: " + abs_path); @@ -801,7 +818,7 @@ void GDExtension::deinitialize_library(InitializationLevel p_level) { } void GDExtension::_bind_methods() { - ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library); + ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol", "lookup_paths"), &GDExtension::open_library, DEFVAL(Vector())); ClassDB::bind_method(D_METHOD("close_library"), &GDExtension::close_library); ClassDB::bind_method(D_METHOD("is_library_open"), &GDExtension::is_library_open); @@ -932,8 +949,9 @@ Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path, FileAccess::get_modified_time(p_path), FileAccess::get_modified_time(library_path)); #endif + Vector lookup_paths = config->get_value("configuration", "lookup_paths", Vector()); - err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol); + err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol, lookup_paths); if (err != OK) { #if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) // If the DLL fails to load, make sure that temporary DLL copies are cleaned up. diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 588efed0177f..45badccb1e39 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -110,6 +110,12 @@ class GDExtension : public Resource { static HashMap gdextension_interface_functions; protected: +#ifndef DISABLE_DEPRECATED + Error _open_library_bind_compat_88049(const String &p_path, const String &p_entry_symbol); + + static void _bind_compatibility_methods(); +#endif + static void _bind_methods(); public: @@ -120,7 +126,7 @@ class GDExtension : public Resource { static String get_extension_list_config_file(); static String find_extension_library(const String &p_path, Ref p_config, std::function p_has_feature, PackedStringArray *r_tags = nullptr); - Error open_library(const String &p_path, const String &p_entry_symbol); + Error open_library(const String &p_path, const String &p_entry_symbol, const Vector &p_lookup_paths = Vector()); void close_library(); #if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) diff --git a/doc/classes/GDExtension.xml b/doc/classes/GDExtension.xml index 533b32218f6f..7dc10aa53116 100644 --- a/doc/classes/GDExtension.xml +++ b/doc/classes/GDExtension.xml @@ -43,6 +43,7 @@ + Opens the library at the specified [param path]. [b]Note:[/b] You normally should not call this method directly. This is handled automatically by [method GDExtensionManager.load_extension]. diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected index 04e046ec932a..8e1053447d43 100644 --- a/misc/extension_api_validation/4.2-stable.expected +++ b/misc/extension_api_validation/4.2-stable.expected @@ -82,3 +82,10 @@ Validate extension JSON: Error: Field 'classes/GPUParticles3D/properties/process Validate extension JSON: Error: Field 'classes/Sky/properties/sky_material': type changed value in new API, from "ShaderMaterial,PanoramaSkyMaterial,ProceduralSkyMaterial,PhysicalSkyMaterial" to "PanoramaSkyMaterial,ProceduralSkyMaterial,PhysicalSkyMaterial,ShaderMaterial". Property hints reordered to improve editor usability. The types allowed are still the same as before. No adjustments should be necessary. + + +GH-88049 +-------- +Validate extension JSON: Error: Field 'classes/GDExtension/methods/open_library/arguments': size changed value in new API, from 2 to 3. + +Added optional "lookup_paths" argument. Compatibility method registered.