diff options
Diffstat (limited to 'platform')
14 files changed, 100 insertions, 127 deletions
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle index 974f072c18..d60f97e3e7 100644 --- a/platform/android/java/build.gradle +++ b/platform/android/java/build.gradle @@ -25,7 +25,7 @@ allprojects { ext { supportedAbis = ["arm32", "arm64", "x86_32", "x86_64"] supportedFlavors = ["editor", "template"] - supportedEditorVendors = ["google", "meta"] + supportedAndroidDistributions = ["android", "horizonos"] supportedFlavorsBuildTypes = [ "editor": ["dev", "debug", "release"], "template": ["dev", "debug", "release"] @@ -94,17 +94,17 @@ def templateExcludedBuildTask() { /** * Generates the build tasks for the given flavor * @param flavor Must be one of the supported flavors ('template' / 'editor') - * @param editorVendor Must be one of the supported editor vendors ('google' / 'meta') + * @param androidDistro Must be one of the supported Android distributions ('android' / 'horizonos') */ -def generateBuildTasks(String flavor = "template", String editorVendor = "google") { +def generateBuildTasks(String flavor = "template", String androidDistro = "android") { if (!supportedFlavors.contains(flavor)) { throw new GradleException("Invalid build flavor: $flavor") } - if (!supportedEditorVendors.contains(editorVendor)) { - throw new GradleException("Invalid editor vendor: $editorVendor") + if (!supportedAndroidDistributions.contains(androidDistro)) { + throw new GradleException("Invalid Android distribution: $androidDistro") } - String capitalizedEditorVendor = editorVendor.capitalize() + String capitalizedAndroidDistro = androidDistro.capitalize() def buildTasks = [] // Only build the binary files for which we have native shared libraries unless we intend @@ -170,28 +170,28 @@ def generateBuildTasks(String flavor = "template", String editorVendor = "google } } else { // Copy the generated editor apk to the bin directory. - String copyEditorApkTaskName = "copyEditor${capitalizedEditorVendor}${capitalizedTarget}ApkToBin" + String copyEditorApkTaskName = "copyEditor${capitalizedAndroidDistro}${capitalizedTarget}ApkToBin" if (tasks.findByName(copyEditorApkTaskName) != null) { buildTasks += tasks.getByName(copyEditorApkTaskName) } else { buildTasks += tasks.create(name: copyEditorApkTaskName, type: Copy) { - dependsOn ":editor:assemble${capitalizedEditorVendor}${capitalizedTarget}" - from("editor/build/outputs/apk/${editorVendor}/${target}") + dependsOn ":editor:assemble${capitalizedAndroidDistro}${capitalizedTarget}" + from("editor/build/outputs/apk/${androidDistro}/${target}") into(androidEditorBuildsDir) - include("android_editor-${editorVendor}-${target}*.apk") + include("android_editor-${androidDistro}-${target}*.apk") } } // Copy the generated editor aab to the bin directory. - String copyEditorAabTaskName = "copyEditor${capitalizedEditorVendor}${capitalizedTarget}AabToBin" + String copyEditorAabTaskName = "copyEditor${capitalizedAndroidDistro}${capitalizedTarget}AabToBin" if (tasks.findByName(copyEditorAabTaskName) != null) { buildTasks += tasks.getByName(copyEditorAabTaskName) } else { buildTasks += tasks.create(name: copyEditorAabTaskName, type: Copy) { - dependsOn ":editor:bundle${capitalizedEditorVendor}${capitalizedTarget}" - from("editor/build/outputs/bundle/${editorVendor}${capitalizedTarget}") + dependsOn ":editor:bundle${capitalizedAndroidDistro}${capitalizedTarget}" + from("editor/build/outputs/bundle/${androidDistro}${capitalizedTarget}") into(androidEditorBuildsDir) - include("android_editor-${editorVendor}-${target}*.aab") + include("android_editor-${androidDistro}-${target}*.aab") } } } @@ -204,7 +204,7 @@ def generateBuildTasks(String flavor = "template", String editorVendor = "google } /** - * Generate the Godot Editor Android binaries. + * Generate the Godot Editor binaries for Android devices. * * Note: Unless the 'generateNativeLibs` argument is specified, the Godot 'tools' shared libraries * must have been generated (via scons) prior to running this gradle task. @@ -212,19 +212,19 @@ def generateBuildTasks(String flavor = "template", String editorVendor = "google */ task generateGodotEditor { gradle.startParameter.excludedTaskNames += templateExcludedBuildTask() - dependsOn = generateBuildTasks("editor", "google") + dependsOn = generateBuildTasks("editor", "android") } /** - * Generate the Godot Editor Android binaries for Meta devices. + * Generate the Godot Editor binaries for HorizonOS devices. * * Note: Unless the 'generateNativeLibs` argument is specified, the Godot 'tools' shared libraries * must have been generated (via scons) prior to running this gradle task. * The task will only build the binaries for which the shared libraries is available. */ -task generateGodotMetaEditor { +task generateGodotHorizonOSEditor { gradle.startParameter.excludedTaskNames += templateExcludedBuildTask() - dependsOn = generateBuildTasks("editor", "meta") + dependsOn = generateBuildTasks("editor", "horizonos") } /** diff --git a/platform/android/java/editor/build.gradle b/platform/android/java/editor/build.gradle index 54d6b9b5f3..45222ca3b0 100644 --- a/platform/android/java/editor/build.gradle +++ b/platform/android/java/editor/build.gradle @@ -145,14 +145,14 @@ android { } } - flavorDimensions = ["vendor"] + flavorDimensions = ["android_distribution"] productFlavors { - google { - dimension "vendor" + android { + dimension "android_distribution" missingDimensionStrategy 'products', 'editor' } - meta { - dimension "vendor" + horizonos { + dimension "android_distribution" missingDimensionStrategy 'products', 'editor' ndk { //noinspection ChromeOsAbiSupport @@ -176,5 +176,5 @@ dependencies { implementation "org.bouncycastle:bcprov-jdk15to18:1.77" // Meta dependencies - metaImplementation "org.godotengine:godot-openxr-vendors-meta:3.0.0-stable" + horizonosImplementation "org.godotengine:godot-openxr-vendors-meta:3.0.0-stable" } diff --git a/platform/android/java/editor/src/google/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/android/java/org/godotengine/editor/GodotEditor.kt index f15d9f7768..f15d9f7768 100644 --- a/platform/android/java/editor/src/google/java/org/godotengine/editor/GodotEditor.kt +++ b/platform/android/java/editor/src/android/java/org/godotengine/editor/GodotEditor.kt diff --git a/platform/android/java/editor/src/meta/AndroidManifest.xml b/platform/android/java/editor/src/horizonos/AndroidManifest.xml index 06442ac4e6..06442ac4e6 100644 --- a/platform/android/java/editor/src/meta/AndroidManifest.xml +++ b/platform/android/java/editor/src/horizonos/AndroidManifest.xml diff --git a/platform/android/java/editor/src/meta/assets/vr_splash.png b/platform/android/java/editor/src/horizonos/assets/vr_splash.png Binary files differindex 7bddd4325a..7bddd4325a 100644 --- a/platform/android/java/editor/src/meta/assets/vr_splash.png +++ b/platform/android/java/editor/src/horizonos/assets/vr_splash.png diff --git a/platform/android/java/editor/src/meta/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotEditor.kt index 328ff9a3bd..6cb08ae94b 100644 --- a/platform/android/java/editor/src/meta/java/org/godotengine/editor/GodotEditor.kt +++ b/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotEditor.kt @@ -36,7 +36,7 @@ import org.godotengine.godot.utils.isNativeXRDevice /** * Primary window of the Godot Editor. * - * This is the implementation of the editor used when running on Meta devices. + * This is the implementation of the editor used when running on HorizonOS devices. */ open class GodotEditor : BaseGodotEditor() { diff --git a/platform/android/java/editor/src/meta/java/org/godotengine/editor/GodotXRGame.kt b/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotXRGame.kt index 5db2879aad..5db2879aad 100644 --- a/platform/android/java/editor/src/meta/java/org/godotengine/editor/GodotXRGame.kt +++ b/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotXRGame.kt diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/BaseGodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/BaseGodotEditor.kt index d296d6ad03..7b6d1f6bd1 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/BaseGodotEditor.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/BaseGodotEditor.kt @@ -517,6 +517,10 @@ abstract class BaseGodotEditor : GodotActivity() { return isNativeXRDevice(); } + if (featureTag == "horizonos") { + return isHorizonOSDevice() + } + return false } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/DeviceUtils.kt b/platform/android/java/lib/src/org/godotengine/godot/utils/DeviceUtils.kt index abe0c5f885..dff57581fa 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/DeviceUtils.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/DeviceUtils.kt @@ -38,7 +38,7 @@ package org.godotengine.godot.utils import android.os.Build /** - * Returns true if running on Meta's Horizon OS. + * Returns true if running on Meta Horizon OS. */ fun isHorizonOSDevice(): Boolean { return "Oculus".equals(Build.BRAND, true) diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 2074d7228d..a36748efc1 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -327,15 +327,7 @@ void DisplayServerWayland::mouse_set_mode(MouseMode p_mode) { bool show_cursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED); - if (show_cursor) { - if (custom_cursors.has(cursor_shape)) { - wayland_thread.cursor_set_custom_shape(cursor_shape); - } else { - wayland_thread.cursor_set_shape(cursor_shape); - } - } else { - wayland_thread.cursor_hide(); - } + wayland_thread.cursor_set_visible(show_cursor); WaylandThread::PointerConstraint constraint = WaylandThread::PointerConstraint::NONE; @@ -993,11 +985,7 @@ void DisplayServerWayland::cursor_set_shape(CursorShape p_shape) { return; } - if (custom_cursors.has(p_shape)) { - wayland_thread.cursor_set_custom_shape(p_shape); - } else { - wayland_thread.cursor_set_shape(p_shape); - } + wayland_thread.cursor_set_shape(p_shape); } DisplayServerWayland::CursorShape DisplayServerWayland::cursor_get_shape() const { @@ -1009,18 +997,13 @@ DisplayServerWayland::CursorShape DisplayServerWayland::cursor_get_shape() const void DisplayServerWayland::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { MutexLock mutex_lock(wayland_thread.mutex); - bool visible = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED); - if (p_cursor.is_valid()) { HashMap<CursorShape, CustomCursor>::Iterator cursor_c = custom_cursors.find(p_shape); if (cursor_c) { if (cursor_c->value.rid == p_cursor->get_rid() && cursor_c->value.hotspot == p_hotspot) { // We have a cached cursor. Nice. - if (visible) { - wayland_thread.cursor_set_custom_shape(p_shape); - } - + wayland_thread.cursor_set_shape(p_shape); return; } @@ -1039,20 +1022,18 @@ void DisplayServerWayland::cursor_set_custom_image(const Ref<Resource> &p_cursor wayland_thread.cursor_shape_set_custom_image(p_shape, image, p_hotspot); - if (visible) { - wayland_thread.cursor_set_custom_shape(p_shape); - } + wayland_thread.cursor_set_shape(p_shape); } else { // Clear cache and reset to default system cursor. - if (cursor_shape == p_shape && visible) { + wayland_thread.cursor_shape_clear_custom_image(p_shape); + + if (cursor_shape == p_shape) { wayland_thread.cursor_set_shape(p_shape); } if (custom_cursors.has(p_shape)) { custom_cursors.erase(p_shape); } - - wayland_thread.cursor_shape_clear_custom_image(p_shape); } } diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index 08b20c5b42..e066e78e5b 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -265,8 +265,6 @@ bool WaylandThread::_load_cursor_theme(int p_cursor_size) { if (wl_cursor_theme) { wl_cursor_theme_destroy(wl_cursor_theme); wl_cursor_theme = nullptr; - - current_wl_cursor = nullptr; } if (cursor_theme_name.is_empty()) { @@ -357,7 +355,12 @@ void WaylandThread::_update_scale(int p_scale) { int cursor_size = unscaled_cursor_size * p_scale; if (_load_cursor_theme(cursor_size)) { - cursor_set_shape(last_cursor_shape); + for (struct wl_seat *wl_seat : registry.wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + seat_state_update_cursor(ss); + } } } @@ -3074,19 +3077,25 @@ void WaylandThread::seat_state_confine_pointer(SeatState *p_ss) { void WaylandThread::seat_state_update_cursor(SeatState *p_ss) { ERR_FAIL_NULL(p_ss); + + WaylandThread *thread = p_ss->wayland_thread; ERR_FAIL_NULL(p_ss->wayland_thread); - if (p_ss->wl_pointer && p_ss->cursor_surface) { - // NOTE: Those values are valid by default and will hide the cursor when - // unchanged, which happens when both the current custom cursor and the - // current wl_cursor are `nullptr`. - struct wl_buffer *cursor_buffer = nullptr; - uint32_t hotspot_x = 0; - uint32_t hotspot_y = 0; - int scale = 1; + if (!p_ss->wl_pointer || !p_ss->cursor_surface) { + return; + } + + // NOTE: Those values are valid by default and will hide the cursor when + // unchanged. + struct wl_buffer *cursor_buffer = nullptr; + uint32_t hotspot_x = 0; + uint32_t hotspot_y = 0; + int scale = 1; - CustomCursor *custom_cursor = p_ss->wayland_thread->current_custom_cursor; - struct wl_cursor *wl_cursor = p_ss->wayland_thread->current_wl_cursor; + if (thread->cursor_visible) { + DisplayServer::CursorShape shape = thread->cursor_shape; + + struct CustomCursor *custom_cursor = thread->custom_cursors.getptr(shape); if (custom_cursor) { cursor_buffer = custom_cursor->wl_buffer; @@ -3096,7 +3105,13 @@ void WaylandThread::seat_state_update_cursor(SeatState *p_ss) { // We can't really reasonably scale custom cursors, so we'll let the // compositor do it for us (badly). scale = 1; - } else if (wl_cursor) { + } else { + struct wl_cursor *wl_cursor = thread->wl_cursors[shape]; + + if (!wl_cursor) { + return; + } + int frame_idx = 0; if (wl_cursor->image_count > 1) { @@ -3112,24 +3127,24 @@ void WaylandThread::seat_state_update_cursor(SeatState *p_ss) { struct wl_cursor_image *wl_cursor_image = wl_cursor->images[frame_idx]; - scale = p_ss->wayland_thread->cursor_scale; + scale = thread->cursor_scale; cursor_buffer = wl_cursor_image_get_buffer(wl_cursor_image); // As the surface's buffer is scaled (thus the surface is smaller) and the // hotspot must be expressed in surface-local coordinates, we need to scale - // them down accordingly. + // it down accordingly. hotspot_x = wl_cursor_image->hotspot_x / scale; hotspot_y = wl_cursor_image->hotspot_y / scale; } + } - wl_pointer_set_cursor(p_ss->wl_pointer, p_ss->pointer_enter_serial, p_ss->cursor_surface, hotspot_x, hotspot_y); - wl_surface_set_buffer_scale(p_ss->cursor_surface, scale); - wl_surface_attach(p_ss->cursor_surface, cursor_buffer, 0, 0); - wl_surface_damage_buffer(p_ss->cursor_surface, 0, 0, INT_MAX, INT_MAX); + wl_pointer_set_cursor(p_ss->wl_pointer, p_ss->pointer_enter_serial, p_ss->cursor_surface, hotspot_x, hotspot_y); + wl_surface_set_buffer_scale(p_ss->cursor_surface, scale); + wl_surface_attach(p_ss->cursor_surface, cursor_buffer, 0, 0); + wl_surface_damage_buffer(p_ss->cursor_surface, 0, 0, INT_MAX, INT_MAX); - wl_surface_commit(p_ss->cursor_surface); - } + wl_surface_commit(p_ss->cursor_surface); } void WaylandThread::seat_state_echo_keys(SeatState *p_ss) { @@ -3770,25 +3785,8 @@ Error WaylandThread::init() { return OK; } -void WaylandThread::cursor_hide() { - current_wl_cursor = nullptr; - current_custom_cursor = nullptr; - - SeatState *ss = wl_seat_get_seat_state(wl_seat_current); - ERR_FAIL_NULL(ss); - seat_state_update_cursor(ss); -} - -void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) { - if (!wl_cursors[p_cursor_shape]) { - return; - } - - // The point of this method is make the current cursor a "plain" shape and, as - // the custom cursor overrides what gets set, we have to clear it too. - current_custom_cursor = nullptr; - - current_wl_cursor = wl_cursors[p_cursor_shape]; +void WaylandThread::cursor_set_visible(bool p_visible) { + cursor_visible = p_visible; for (struct wl_seat *wl_seat : registry.wl_seats) { SeatState *ss = wl_seat_get_seat_state(wl_seat); @@ -3796,14 +3794,10 @@ void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) seat_state_update_cursor(ss); } - - last_cursor_shape = p_cursor_shape; } -void WaylandThread::cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_shape) { - ERR_FAIL_COND(!custom_cursors.has(p_cursor_shape)); - - current_custom_cursor = &custom_cursors[p_cursor_shape]; +void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) { + cursor_shape = p_cursor_shape; for (struct wl_seat *wl_seat : registry.wl_seats) { SeatState *ss = wl_seat_get_seat_state(wl_seat); @@ -3811,8 +3805,6 @@ void WaylandThread::cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_ seat_state_update_cursor(ss); } - - last_cursor_shape = p_cursor_shape; } void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_cursor_shape, Ref<Image> p_image, const Point2i &p_hotspot) { @@ -3832,23 +3824,21 @@ void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_c CustomCursor &cursor = custom_cursors[p_cursor_shape]; cursor.hotspot = p_hotspot; + if (cursor.wl_buffer) { + // Clean up the old Wayland buffer. + wl_buffer_destroy(cursor.wl_buffer); + } + if (cursor.buffer_data) { // Clean up the old buffer data. munmap(cursor.buffer_data, cursor.buffer_data_size); } - // NOTE: From `wl_keyboard`s of version 7 or later, the spec requires the mmap - // operation to be done with MAP_PRIVATE, as "MAP_SHARED may fail". We'll do it - // regardless of global version. - cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - - if (cursor.wl_buffer) { - // Clean up the old Wayland buffer. - wl_buffer_destroy(cursor.wl_buffer); - } + cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + cursor.buffer_data_size = data_size; // Create the Wayland buffer. - struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(registry.wl_shm, fd, image_size.height * data_size); + struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(registry.wl_shm, fd, data_size); // TODO: Make sure that WL_SHM_FORMAT_ARGB8888 format is supported. It // technically isn't garaunteed to be supported, but I think that'd be a // pretty unlikely thing to stumble upon. @@ -3876,8 +3866,6 @@ void WaylandThread::cursor_shape_clear_custom_image(DisplayServer::CursorShape p CustomCursor cursor = custom_cursors[p_cursor_shape]; custom_cursors.erase(p_cursor_shape); - current_custom_cursor = nullptr; - if (cursor.wl_buffer) { wl_buffer_destroy(cursor.wl_buffer); } diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h index 84e9bdc2dc..ad2e843a74 100644 --- a/platform/linuxbsd/wayland/wayland_thread.h +++ b/platform/linuxbsd/wayland/wayland_thread.h @@ -469,7 +469,6 @@ public: uint32_t *buffer_data = nullptr; uint32_t buffer_data_size = 0; - RID rid; Point2i hotspot; }; @@ -506,10 +505,8 @@ private: HashMap<DisplayServer::CursorShape, CustomCursor> custom_cursors; - struct wl_cursor *current_wl_cursor = nullptr; - struct CustomCursor *current_custom_cursor = nullptr; - - DisplayServer::CursorShape last_cursor_shape = DisplayServer::CURSOR_ARROW; + DisplayServer::CursorShape cursor_shape = DisplayServer::CURSOR_ARROW; + bool cursor_visible = true; PointerConstraint pointer_constraint = PointerConstraint::NONE; @@ -962,7 +959,7 @@ public: DisplayServer::WindowID pointer_get_pointed_window_id() const; BitField<MouseButtonMask> pointer_get_button_mask() const; - void cursor_hide(); + void cursor_set_visible(bool p_visible); void cursor_set_shape(DisplayServer::CursorShape p_cursor_shape); void cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_shape); diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 840cadace3..499df55bef 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -1787,12 +1787,6 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { _send_window_event(windows[p_id], WINDOW_EVENT_MOUSE_EXIT); } - window_set_rect_changed_callback(Callable(), p_id); - window_set_window_event_callback(Callable(), p_id); - window_set_input_event_callback(Callable(), p_id); - window_set_input_text_callback(Callable(), p_id); - window_set_drop_files_callback(Callable(), p_id); - while (wd.transient_children.size()) { window_set_transient(*wd.transient_children.begin(), INVALID_WINDOW_ID); } @@ -1836,6 +1830,12 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { XUnmapWindow(x11_display, wd.x11_window); XDestroyWindow(x11_display, wd.x11_window); + window_set_rect_changed_callback(Callable(), p_id); + window_set_window_event_callback(Callable(), p_id); + window_set_input_event_callback(Callable(), p_id); + window_set_input_text_callback(Callable(), p_id); + window_set_drop_files_callback(Callable(), p_id); + windows.erase(p_id); } diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index 3a82514766..d9086b8c38 100644 --- a/platform/macos/os_macos.mm +++ b/platform/macos/os_macos.mm @@ -230,7 +230,10 @@ Error OS_MacOS::open_dynamic_library(const String &p_path, void *&p_library_hand path = get_framework_executable(get_executable_path().get_base_dir().path_join("../Frameworks").path_join(p_path.get_file())); } - ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND); + if (!FileAccess::exists(path)) { + // Try using path as is. macOS system libraries with `/usr/lib/*` path do not exist as physical files and are loaded from shared cache. + path = p_path; + } p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror())); |