diff options
author | Fredia Huya-Kouadio <fhuya@meta.com> | 2023-08-17 07:32:10 -0700 |
---|---|---|
committer | Fredia Huya-Kouadio <fhuya@meta.com> | 2023-08-17 11:07:46 -0700 |
commit | 37e27e3db22c0b33d098a0ac1fb2dfe8861be0fb (patch) | |
tree | 741a6563c1795437c0ad5b80c6121b5476861361 | |
parent | e61f1555b696b62152787d0fee14435325aee62b (diff) | |
download | godot-android-samples-37e27e3db22c0b33d098a0ac1fb2dfe8861be0fb.tar.gz godot-android-samples-37e27e3db22c0b33d098a0ac1fb2dfe8861be0fb.tar.bz2 godot-android-samples-37e27e3db22c0b33d098a0ac1fb2dfe8861be0fb.zip |
Add an Android GDExtension plugin sample
This sample shows how to integrate gdextension capabilities with Android java/kotlin code by leveraging JNI.
37 files changed, 1051 insertions, 3 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f304937 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "plugins/hello_gdextension/godot-cpp"] + path = plugins/hello_gdextension/godot-cpp + url = https://github.com/godotengine/godot-cpp diff --git a/build.gradle b/build.gradle index bef5465..aeb7fcd 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,7 @@ buildscript { google() mavenCentral() maven { url "https://plugins.gradle.org/m2/" } + maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/"} } dependencies { classpath "com.android.tools.build:gradle:$versions.gradlePluginVersion" @@ -15,6 +16,6 @@ buildscript { apply from: 'config.gradle' -task clean(type: Delete) { +tasks.register('clean', Delete) { delete rootProject.buildDir } diff --git a/config.gradle b/config.gradle index 532d3ec..6e07526 100644 --- a/config.gradle +++ b/config.gradle @@ -2,7 +2,7 @@ ext { versions = [ gradlePluginVersion: '7.2.1', compileSdk : 33, - minSdk : 29, + minSdk : 21, targetSdk : 33, godotLibVersion : '4.1.0.stable', javaVersion : JavaVersion.VERSION_11, diff --git a/plugins/hello_gdextension/.gitignore b/plugins/hello_gdextension/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/plugins/hello_gdextension/.gitignore @@ -0,0 +1 @@ +/build diff --git a/plugins/hello_gdextension/CMakeLists.txt b/plugins/hello_gdextension/CMakeLists.txt new file mode 100644 index 0000000..dda0257 --- /dev/null +++ b/plugins/hello_gdextension/CMakeLists.txt @@ -0,0 +1,141 @@ +cmake_minimum_required(VERSION 3.22.1) + +## Default configs +# Default android abi is arm64-v8a +if (NOT ANDROID_ABI) + set(ANDROID_ABI "arm64-v8a") +endif (NOT ANDROID_ABI) + +if (ANDROID_ABI STREQUAL "armeabi-v7a") + set(GODOT_CPP_LIB_ABI "arm32") +elseif (ANDROID_ABI STREQUAL "x86") + set(GODOT_CPP_LIB_ABI "x86_32") +elseif (ANDROID_ABI STREQUAL "x86_64") + set(GODOT_CPP_LIB_ABI "x86_64") +else () + set(GODOT_CPP_LIB_ABI "arm64") +endif () + +# Default android platform is android-21 +if (NOT ANDROID_PLATFORM) + set(ANDROID_PLATFORM "android-21") +endif (NOT ANDROID_PLATFORM) + +# Default build type is Debug +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug) +endif (NOT CMAKE_BUILD_TYPE) + +if (CMAKE_BUILD_TYPE MATCHES Debug) + add_definitions(-D_DEBUG) + set(GODOT_CPP_LIB_BUILD_TYPE debug) +else () + add_definitions(-DNDEBUG) + set(GODOT_CPP_LIB_BUILD_TYPE release) +endif (CMAKE_BUILD_TYPE MATCHES Debug) + +if (NOT (ANDROID_STL STREQUAL "c++_shared")) + set(ANDROID_STL "c++_shared") +endif (NOT (ANDROID_STL STREQUAL "c++_shared")) + +# Check if ANDROID_NDK is set. +if (NOT ANDROID_NDK) + # Set to ANDROID_NDK_HOME environment variable if it's set. + if (DEFINED ENV{ANDROID_NDK_HOME}) + set(ANDROID_NDK $ENV{ANDROID_NDK_HOME}) + else (DEFINED ENV{ANDROID_NDK_HOME}) + message(WARNING "ANDROID_NDK_HOME is not set") + endif (DEFINED ENV{ANDROID_NDK_HOME}) +endif (NOT ANDROID_NDK) + +# Check if CMAKE_TOOLCHAIN_FILE is set. +if (NOT CMAKE_TOOLCHAIN_FILE) + set(CMAKE_TOOLCHAIN_FILE "${ANDROID_NDK}/build/cmake/android.toolchain.cmake") +endif (NOT CMAKE_TOOLCHAIN_FILE) + +if (NOT DEFINED BITS) + set(BITS 32) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + set(BITS 64) + endif (CMAKE_SIZEOF_VOID_P EQUAL 8) +endif (NOT DEFINED BITS) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + + +project(hello_gdextension LANGUAGES CXX) + +set(GODOT_COMPILE_FLAGS) +set(GODOT_LINKER_FLAGS) + +set(GODOT_LINKER_FLAGS "-Wl") + +set(GODOT_COMPILE_FLAGS "-fPIC -g -Wwrite-strings") +set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wchar-subscripts -Wcomment -Wdisabled-optimization") +set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wformat -Wformat=2 -Wformat-security -Wformat-y2k") +set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wimport -Winit-self -Winline -Winvalid-pch") +set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wlong-long -Wmissing-braces -Wmissing-format-attribute") +set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpointer-arith") +set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wredundant-decls -Wreturn-type -Wsequence-point") +set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wswitch -Wswitch-enum -Wtrigraphs") +set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused-label") +set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wunused-value -Wvariadic-macros -Wvolatile-register-var -Wno-error=attributes") + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Android") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wno-ignored-attributes") +endif () + +if (CMAKE_BUILD_TYPE MATCHES Debug) + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0") +else () + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3") +endif (CMAKE_BUILD_TYPE MATCHES Debug) + + +## godot-cpp library +set(GODOT_CPP_DIR "${CMAKE_SOURCE_DIR}/godot-cpp") +set(GODOT-CPP "godot-cpp") + +# Use the godot-cpp prebuilt static binary +set(GODOT_CPP_STATIC_LIB "${GODOT_CPP_DIR}/bin/libgodot-cpp.android.template_${GODOT_CPP_LIB_BUILD_TYPE}.${GODOT_CPP_LIB_ABI}.a") + +list(APPEND GODOT_CPP_INCLUDE_DIRECTORIES "${GODOT_CPP_DIR}/include") +list(APPEND GODOT_CPP_INCLUDE_DIRECTORIES "${GODOT_CPP_DIR}/gen/include") +list(APPEND GODOT_CPP_INCLUDE_DIRECTORIES "${GODOT_CPP_DIR}/gdextension") + +add_library(${GODOT-CPP} + STATIC + IMPORTED GLOBAL + INTERFACE_INCLUDE_DIRECTORIES "${GODOT_CPP_INCLUDE_DIRECTORIES}" + ) +set_target_properties(${GODOT-CPP} PROPERTIES IMPORTED_LOCATION ${GODOT_CPP_STATIC_LIB}) + + +## Setup the plugin library +file(GLOB_RECURSE ANDROID_SOURCES ${CMAKE_SOURCE_DIR}/src/main/cpp/*.c**) +file(GLOB_RECURSE ANDROID_HEADERS ${CMAKE_SOURCE_DIR}/src/main/cpp/*.h**) + +add_library(${CMAKE_PROJECT_NAME} SHARED + ${ANDROID_SOURCES} ${ANDROID_HEADERS} + ) + +target_include_directories(${CMAKE_PROJECT_NAME} + SYSTEM PUBLIC + ${GODOT_CPP_INCLUDE_DIRECTORIES} + ) + +# Specifies libraries CMake should link to your target library. You +# can link libraries from various origins, such as libraries defined in this +# build script, prebuilt third-party libraries, or Android system libraries. +target_link_libraries(${CMAKE_PROJECT_NAME} + # List libraries link to the target library + android + log + ${GODOT-CPP} + ) + +# Add the compile flags +set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS}) +set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS ${GODOT_LINKER_FLAGS}) diff --git a/plugins/hello_gdextension/README.md b/plugins/hello_gdextension/README.md new file mode 100644 index 0000000..c7bd3aa --- /dev/null +++ b/plugins/hello_gdextension/README.md @@ -0,0 +1,61 @@ +## Hello GDExtension plugin + +Showcase how to build a Godot Android GDExtension plugin + +### Setup + +Clone the project using `git`: + +``` +git clone https://github.com/m4gr3d/Godot-Android-Samples.git +``` + +The sample has a dependency on the `godot-cpp` library, which is included as a Git submodule. +After cloning the sample, you'll need to execute the following commands to set up the submodule: + +``` +cd Godot-Android-Samples +git submodule update --init +``` + +### Building the C++ bindings + +To generate and compile the C++ bindings, use the following commands: + +``` +cd Godot-Android-Samples/plugins/hello_gdextension/godot-cpp +scons platform=android -j4 target=template_debug +scons platform=android -j4 target=template_release +``` + +When it's completed, you should have static libraries stored in +`plugins/hello_gdextension/godot-cpp/bin/` that will be used for +compilation by the plugin. + +### Building the Hello GDExtension plugin + +Use the following commands to build the plugin: + +``` +cd Godot-Android-Samples +./gradlew :plugins:hello_gdextension:assemble +``` + +The generated artifact can be found under [`demo/addons`](demo/addons). + +### Usage + +Open the [`demo`](demo) project in the Godot Editor + +**Note:** + +It's recommended to generate a version of the gdextension binary for the platform you're running +the Godot Editor onto. To do so: + +``` +cd Godot-Android-Samples/plugins/hello_gdextension +scons -j4 +``` + +Update [`src/main/assets/addons/hello_gdextension_plugin/hello_gdextension.gdextension`](src/main/assets/addons/hello_gdextension_plugin/hello_gdextension.gdextension) +with the path to the generated binary. diff --git a/plugins/hello_gdextension/SConstruct b/plugins/hello_gdextension/SConstruct new file mode 100644 index 0000000..c704717 --- /dev/null +++ b/plugins/hello_gdextension/SConstruct @@ -0,0 +1,30 @@ +#!/usr/bin/env python +import os +import sys + +env = SConscript("godot-cpp/SConstruct") + +# For reference: +# - CCFLAGS are compilation flags shared between C and C++ +# - CFLAGS are for C-specific compilation flags +# - CXXFLAGS are for C++-specific compilation flags +# - CPPFLAGS are for pre-processor flags +# - CPPDEFINES are for pre-processor defines +# - LINKFLAGS are for linking flags + +# tweak this if you want to use different folders, or more folders, to store your source code in. +env.Append(CPPPATH=["src/main/cpp"]) +sources = Glob("src/main/cpp/*.cpp") + +if env["platform"] == "macos": + library = env.SharedLibrary( + "src/main/assets/addons/hello_gdextension_plugin/.bin/libhello_gdextension.{}.{}.framework/libhello_gdextension.{}.{}".format(env["platform"], env["target"], env["platform"], env["target"]), + source=sources, + ) +else: + library = env.SharedLibrary( + "src/main/assets/addons/hello_gdextension_plugin/.bin/libhello_gdextension{}{}".format(env["suffix"], env["SHLIBSUFFIX"]), + source=sources, + ) + +Default(library) diff --git a/plugins/hello_gdextension/build.gradle b/plugins/hello_gdextension/build.gradle new file mode 100644 index 0000000..86bc96f --- /dev/null +++ b/plugins/hello_gdextension/build.gradle @@ -0,0 +1,92 @@ +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} + +android { + compileSdk versions.compileSdk + + defaultConfig { + minSdk versions.minSdk + targetSdk versions.targetSdk + versionCode 1 + versionName "1.0" + externalNativeBuild { + cmake { + cppFlags '' + } + } + ndk { + //noinspection ChromeOsAbiSupport + abiFilters 'arm64-v8a' + } + } + externalNativeBuild { + cmake { + path file('CMakeLists.txt') + version '3.22.1' + } + } + + // Used to customize the name of generated AAR file. + libraryVariants.configureEach { variant -> + variant.outputs.configureEach { output -> + output.outputFileName = "HelloGDExtension.${variant.name}.aar" + } + } + +} + +dependencies { + // TODO: Update the godot dep when 4.2 is stable + compileOnly "io.github.m4gr3d:godot:4.2.0.dev-SNAPSHOT" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlinVersion" +} + +tasks.register('copyDebugAARToAddons', Copy) { + from 'build/outputs/aar' + include 'HelloGDExtension.debug.aar' + into 'src/main/assets/addons/hello_gdextension_plugin/.bin/debug' +} + +tasks.register('copyReleaseAARToAddons', Copy) { + from 'build/outputs/aar' + include 'HelloGDExtension.release.aar' + into 'src/main/assets/addons/hello_gdextension_plugin/.bin/release' +} + +tasks.register('copyDebugSharedLibs', Copy) { + dependsOn(":plugins:hello_gdextension:externalNativeBuildDebug") + + from 'build/intermediates/cmake/debug/obj/arm64-v8a' + include 'libhello_gdextension.so' + into 'src/main/assets/addons/hello_gdextension_plugin/.bin/debug' +} + +tasks.register('copyReleaseSharedLibs', Copy) { + dependsOn(":plugins:hello_gdextension:externalNativeBuildRelease") + + from 'build/intermediates/cmake/release/obj/arm64-v8a' + include 'libhello_gdextension.so' + into 'src/main/assets/addons/hello_gdextension_plugin/.bin/release' +} + +tasks.register('copyAddonsToDemo', Copy) { + dependsOn(copyDebugAARToAddons) + dependsOn(copyReleaseAARToAddons) + dependsOn(copyDebugSharedLibs) + dependsOn(copyReleaseSharedLibs) + + doFirst { + delete('demo/addons/hello_gdextension_plugin') + } + from 'src/main/assets/addons/hello_gdextension_plugin' + into 'demo/addons/hello_gdextension_plugin' + +} + +assemble.finalizedBy(copyDebugAARToAddons) +assemble.finalizedBy(copyReleaseAARToAddons) +assemble.finalizedBy(copyDebugSharedLibs) +assemble.finalizedBy(copyReleaseSharedLibs) +assemble.finalizedBy(copyAddonsToDemo) diff --git a/plugins/hello_gdextension/demo/.gitattributes b/plugins/hello_gdextension/demo/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/plugins/hello_gdextension/demo/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/plugins/hello_gdextension/demo/.gitignore b/plugins/hello_gdextension/demo/.gitignore new file mode 100644 index 0000000..aadc0ba --- /dev/null +++ b/plugins/hello_gdextension/demo/.gitignore @@ -0,0 +1,4 @@ +# Godot 4+ specific ignores +.godot/ +*.import +/android/ diff --git a/plugins/hello_gdextension/demo/addons/.gitignore b/plugins/hello_gdextension/demo/addons/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/plugins/hello_gdextension/demo/addons/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/plugins/hello_gdextension/demo/export_presets.cfg b/plugins/hello_gdextension/demo/export_presets.cfg new file mode 100644 index 0000000..8fcc7e7 --- /dev/null +++ b/plugins/hello_gdextension/demo/export_presets.cfg @@ -0,0 +1,200 @@ +[preset.0] + +name="Android" +platform="Android" +runnable=true +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +gradle_build/use_gradle_build=true +gradle_build/export_format=0 +gradle_build/min_sdk="" +gradle_build/target_sdk="" +architectures/armeabi-v7a=false +architectures/arm64-v8a=true +architectures/x86=false +architectures/x86_64=false +version/code=1 +version/name="" +package/unique_name="org.godotengine.hellogdextension" +package/name="" +package/signed=true +package/app_category=2 +package/retain_data_on_uninstall=false +package/exclude_from_recents=false +package/show_in_android_tv=false +package/show_as_launcher_app=false +launcher_icons/main_192x192="" +launcher_icons/adaptive_foreground_432x432="" +launcher_icons/adaptive_background_432x432="" +graphics/opengl_debug=false +xr_features/xr_mode=0 +screen/immersive_mode=true +screen/support_small=true +screen/support_normal=true +screen/support_large=true +screen/support_xlarge=true +user_data_backup/allow=false +command_line/extra_args="" +apk_expansion/enable=false +apk_expansion/SALT="" +apk_expansion/public_key="" +permissions/custom_permissions=PackedStringArray() +permissions/access_checkin_properties=false +permissions/access_coarse_location=false +permissions/access_fine_location=false +permissions/access_location_extra_commands=false +permissions/access_mock_location=false +permissions/access_network_state=false +permissions/access_surface_flinger=false +permissions/access_wifi_state=false +permissions/account_manager=false +permissions/add_voicemail=false +permissions/authenticate_accounts=false +permissions/battery_stats=false +permissions/bind_accessibility_service=false +permissions/bind_appwidget=false +permissions/bind_device_admin=false +permissions/bind_input_method=false +permissions/bind_nfc_service=false +permissions/bind_notification_listener_service=false +permissions/bind_print_service=false +permissions/bind_remoteviews=false +permissions/bind_text_service=false +permissions/bind_vpn_service=false +permissions/bind_wallpaper=false +permissions/bluetooth=false +permissions/bluetooth_admin=false +permissions/bluetooth_privileged=false +permissions/brick=false +permissions/broadcast_package_removed=false +permissions/broadcast_sms=false +permissions/broadcast_sticky=false +permissions/broadcast_wap_push=false +permissions/call_phone=false +permissions/call_privileged=false +permissions/camera=false +permissions/capture_audio_output=false +permissions/capture_secure_video_output=false +permissions/capture_video_output=false +permissions/change_component_enabled_state=false +permissions/change_configuration=false +permissions/change_network_state=false +permissions/change_wifi_multicast_state=false +permissions/change_wifi_state=false +permissions/clear_app_cache=false +permissions/clear_app_user_data=false +permissions/control_location_updates=false +permissions/delete_cache_files=false +permissions/delete_packages=false +permissions/device_power=false +permissions/diagnostic=false +permissions/disable_keyguard=false +permissions/dump=false +permissions/expand_status_bar=false +permissions/factory_test=false +permissions/flashlight=false +permissions/force_back=false +permissions/get_accounts=false +permissions/get_package_size=false +permissions/get_tasks=false +permissions/get_top_activity_info=false +permissions/global_search=false +permissions/hardware_test=false +permissions/inject_events=false +permissions/install_location_provider=false +permissions/install_packages=false +permissions/install_shortcut=false +permissions/internal_system_window=false +permissions/internet=false +permissions/kill_background_processes=false +permissions/location_hardware=false +permissions/manage_accounts=false +permissions/manage_app_tokens=false +permissions/manage_documents=false +permissions/manage_external_storage=false +permissions/master_clear=false +permissions/media_content_control=false +permissions/modify_audio_settings=false +permissions/modify_phone_state=false +permissions/mount_format_filesystems=false +permissions/mount_unmount_filesystems=false +permissions/nfc=false +permissions/persistent_activity=false +permissions/process_outgoing_calls=false +permissions/read_calendar=false +permissions/read_call_log=false +permissions/read_contacts=false +permissions/read_external_storage=false +permissions/read_frame_buffer=false +permissions/read_history_bookmarks=false +permissions/read_input_state=false +permissions/read_logs=false +permissions/read_phone_state=false +permissions/read_profile=false +permissions/read_sms=false +permissions/read_social_stream=false +permissions/read_sync_settings=false +permissions/read_sync_stats=false +permissions/read_user_dictionary=false +permissions/reboot=false +permissions/receive_boot_completed=false +permissions/receive_mms=false +permissions/receive_sms=false +permissions/receive_wap_push=false +permissions/record_audio=false +permissions/reorder_tasks=false +permissions/restart_packages=false +permissions/send_respond_via_message=false +permissions/send_sms=false +permissions/set_activity_watcher=false +permissions/set_alarm=false +permissions/set_always_finish=false +permissions/set_animation_scale=false +permissions/set_debug_app=false +permissions/set_orientation=false +permissions/set_pointer_speed=false +permissions/set_preferred_applications=false +permissions/set_process_limit=false +permissions/set_time=false +permissions/set_time_zone=false +permissions/set_wallpaper=false +permissions/set_wallpaper_hints=false +permissions/signal_persistent_processes=false +permissions/status_bar=false +permissions/subscribed_feeds_read=false +permissions/subscribed_feeds_write=false +permissions/system_alert_window=false +permissions/transmit_ir=false +permissions/uninstall_shortcut=false +permissions/update_device_stats=false +permissions/use_credentials=false +permissions/use_sip=false +permissions/vibrate=false +permissions/wake_lock=false +permissions/write_apn_settings=false +permissions/write_calendar=false +permissions/write_call_log=false +permissions/write_contacts=false +permissions/write_external_storage=false +permissions/write_gservices=false +permissions/write_history_bookmarks=false +permissions/write_profile=false +permissions/write_secure_settings=false +permissions/write_settings=false +permissions/write_sms=false +permissions/write_social_stream=false +permissions/write_sync_settings=false +permissions/write_user_dictionary=false diff --git a/plugins/hello_gdextension/demo/icon.svg b/plugins/hello_gdextension/demo/icon.svg new file mode 100644 index 0000000..b370ceb --- /dev/null +++ b/plugins/hello_gdextension/demo/icon.svg @@ -0,0 +1 @@ +<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg> diff --git a/plugins/hello_gdextension/demo/main.gd b/plugins/hello_gdextension/demo/main.gd new file mode 100644 index 0000000..c457271 --- /dev/null +++ b/plugins/hello_gdextension/demo/main.gd @@ -0,0 +1,5 @@ +extends Node2D + +func _ready(): + var hello_gdextension_plugin = preload("res://addons/hello_gdextension_plugin/interface/hello_gdextension_plugin.gd").new() + hello_gdextension_plugin.add_gdexample_node(get_path()) diff --git a/plugins/hello_gdextension/demo/main.tscn b/plugins/hello_gdextension/demo/main.tscn new file mode 100644 index 0000000..1ce2c1c --- /dev/null +++ b/plugins/hello_gdextension/demo/main.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=3 format=3 uid="uid://7wuhp5udocan"] + +[ext_resource type="Texture2D" uid="uid://ci0rbwt8c67dx" path="res://icon.svg" id="1_ibk70"] +[ext_resource type="Script" path="res://main.gd" id="1_uldmm"] + +[node name="Main" type="Node2D"] +script = ExtResource("1_uldmm") + +[node name="GDExample" type="GDExample" parent="."] +position = Vector2(2.52749, 8.48129) +texture = ExtResource("1_ibk70") +centered = false diff --git a/plugins/hello_gdextension/demo/project.godot b/plugins/hello_gdextension/demo/project.godot new file mode 100644 index 0000000..c19424e --- /dev/null +++ b/plugins/hello_gdextension/demo/project.godot @@ -0,0 +1,30 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="Hello Gdextension" +run/main_scene="res://main.tscn" +config/features=PackedStringArray("4.2", "GL Compatibility") +config/icon="res://icon.svg" + +[debug] + +settings/stdout/verbose_stdout=true + +[editor_plugins] + +enabled=PackedStringArray("res://addons/hello_gdextension_plugin/plugin.cfg") + +[rendering] + +renderer/rendering_method="gl_compatibility" +renderer/rendering_method.mobile="gl_compatibility" +textures/vram_compression/import_etc2_astc=true diff --git a/plugins/hello_gdextension/godot-cpp b/plugins/hello_gdextension/godot-cpp new file mode 160000 +Subproject 749b0b9ae03ecac470027b17c6414e7a0e73092 diff --git a/plugins/hello_gdextension/src/main/AndroidManifest.xml b/plugins/hello_gdextension/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e65c66c --- /dev/null +++ b/plugins/hello_gdextension/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="fhuyakou.godot.plugin.android.hellogdextension"> + + <application> + <!-- + Plugin metadata: + + - In the `android:name` attribute, the `org.godotengine.plugin.v2` prefix + is required so Godot can recognize the project as a valid Godot + Android plugin. The plugin name following the prefix should match the value + of the plugin name returned by the plugin initializer. + + - The `android:value` attribute should be the classpath to the plugin + initializer. + --> + <meta-data + android:name="org.godotengine.plugin.v2.HelloGDExtension" + android:value="fhuyakou.godot.plugin.android.hellogdextension.HelloGDExtensionPlugin" /> + </application> +</manifest> diff --git a/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.bin/.gdignore b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.bin/.gdignore new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.bin/.gdignore @@ -0,0 +1 @@ + diff --git a/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.bin/.gitignore b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.bin/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.bin/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/.gdignore b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/.gdignore new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/.gdignore @@ -0,0 +1 @@ + diff --git a/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/hello_gdextension_editor_export_plugin.gd b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/hello_gdextension_editor_export_plugin.gd new file mode 100644 index 0000000..5131aa2 --- /dev/null +++ b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/hello_gdextension_editor_export_plugin.gd @@ -0,0 +1,16 @@ +@tool +extends EditorExportPlugin + +func _supports_platform(platform): + if platform is EditorExportPlatformAndroid: + return true + return false + +func _get_android_libraries(platform, debug): + if debug: + return PackedStringArray(["hello_gdextension_plugin/.bin/debug/HelloGDExtension.debug.aar"]) + else: + return PackedStringArray(["hello_gdextension_plugin/.bin/release/HelloGDExtension.release.aar"]) + +func _get_name(): + return "Hello GDExtension plugin" diff --git a/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/hello_gdextension_editor_plugin.gd b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/hello_gdextension_editor_plugin.gd new file mode 100644 index 0000000..f74419c --- /dev/null +++ b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/hello_gdextension_editor_plugin.gd @@ -0,0 +1,15 @@ +@tool +extends EditorPlugin + +# A class member to hold the export plugin during its lifecycle +var export_plugin : EditorExportPlugin + +func _enter_tree(): + # Initialization of the plugin goes here. + export_plugin = preload("hello_gdextension_editor_export_plugin.gd").new() + add_export_plugin(export_plugin) + +func _exit_tree(): + # Clean up of the plugin goes here. + remove_export_plugin(export_plugin) + export_plugin = null diff --git a/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/hello_gdextension.gdextension b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/hello_gdextension.gdextension new file mode 100644 index 0000000..176a194 --- /dev/null +++ b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/hello_gdextension.gdextension @@ -0,0 +1,14 @@ +[configuration] + +entry_symbol = "example_library_init" +compatibility_minimum = 4.1 + +[exportable] + +android=false + +[libraries] + +macos = "res://addons/hello_gdextension_plugin/.bin/libhello_gdextension.macos.template_debug.framework" +android.debug.arm64 = "res://addons/hello_gdextension_plugin/.bin/debug/libhello_gdextension.so" +android.release.arm64 = "res://addons/hello_gdextension_plugin/.bin/release/libhello_gdextension.so" diff --git a/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/interface/android_icon.svg b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/interface/android_icon.svg new file mode 100644 index 0000000..29c0fde --- /dev/null +++ b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/interface/android_icon.svg @@ -0,0 +1,2 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128"><path + d="M40-239q8-106 65-196.5T256-579l-75-129q-3-9-.5-18t10.5-14q9-5 19.5-2t15.5 12l74 127q86-37 180-37t180 37l75-127q5-9 15.5-12t19.5 2q8 5 11.5 14.5T780-708l-76 129q94 53 151 143.5T920-239H40Zm240-110q20 0 35-15t15-35q0-20-15-35t-35-15q-20 0-35 15t-15 35q0 20 15 35t35 15Zm400 0q20 0 35-15t15-35q0-20-15-35t-35-15q-20 0-35 15t-15 35q0 20 15 35t35 15Z"/></svg> diff --git a/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/interface/hello_gdextension_plugin.gd b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/interface/hello_gdextension_plugin.gd new file mode 100644 index 0000000..b46fb27 --- /dev/null +++ b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/interface/hello_gdextension_plugin.gd @@ -0,0 +1,26 @@ +class_name HelloGDExtensionPlugin extends Object + +## Interface used to access the functionality provided by the HelloGDExtension plugin + +var _hello_gdextension_singleton + +func _init(): + if Engine.has_singleton("HelloGDExtension"): + _hello_gdextension_singleton = Engine.get_singleton("HelloGDExtension") + else: + printerr("Couldn't find HelloGDExtension singleton") + + +## Add a GDExample node +func add_gdexample_node(parent_node_path: NodePath): + if _hello_gdextension_singleton: + _hello_gdextension_singleton.addGDExampleNode(parent_node_path) + else: + printerr("Unable to add gdexample node") + +## Update the visibility of the gdexample node +func set_gdexample_visible(visible: bool): + if _hello_gdextension_singleton: + _hello_gdextension_singleton.setGDExampleVisible(visible) + else: + printerr("Unable to update gdexample visibility") diff --git a/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/plugin.cfg b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/plugin.cfg new file mode 100644 index 0000000..5c60f2b --- /dev/null +++ b/plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Hello GDExtension plugin" +description="Showcases how to package an Android GDExtension plugin" +author="Fredia Huya-Kouadio" +version="" +script=".export/hello_gdextension_editor_plugin.gd" diff --git a/plugins/hello_gdextension/src/main/cpp/gdexample.cpp b/plugins/hello_gdextension/src/main/cpp/gdexample.cpp new file mode 100644 index 0000000..1652936 --- /dev/null +++ b/plugins/hello_gdextension/src/main/cpp/gdexample.cpp @@ -0,0 +1,22 @@ +#include "gdexample.h" +#include <godot_cpp/core/class_db.hpp> + +using namespace godot; + +void GDExample::_bind_methods() { + +} + +GDExample::GDExample() { + time_passed = 0.0; +} + +GDExample::~GDExample() {} + +void GDExample::_process(double delta) { + time_passed += delta; + + Vector2 new_position = Vector2(10.0 + (10.0 * sin(time_passed * 2.0)), 10.0 + (10.0 * cos(time_passed * 1.5))); + + set_position(new_position); +} diff --git a/plugins/hello_gdextension/src/main/cpp/gdexample.h b/plugins/hello_gdextension/src/main/cpp/gdexample.h new file mode 100644 index 0000000..6add085 --- /dev/null +++ b/plugins/hello_gdextension/src/main/cpp/gdexample.h @@ -0,0 +1,25 @@ +#ifndef GDEXAMPLE_H +#define GDEXAMPLE_H + +#include <godot_cpp/classes/sprite2d.hpp> + +namespace godot { + +class GDExample : public Sprite2D { + GDCLASS(GDExample, Sprite2D) + +private: + double time_passed; + +protected: + static void _bind_methods(); + +public: + GDExample(); + ~GDExample(); + + void _process(double delta) override; +}; +} + +#endif // GDEXAMPLE_H diff --git a/plugins/hello_gdextension/src/main/cpp/jni/plugin_jni.cpp b/plugins/hello_gdextension/src/main/cpp/jni/plugin_jni.cpp new file mode 100644 index 0000000..36aa658 --- /dev/null +++ b/plugins/hello_gdextension/src/main/cpp/jni/plugin_jni.cpp @@ -0,0 +1,20 @@ +#include <jni.h> + +#include "plugin_manager.h" +#include "utils.h" + +#undef JNI_PACKAGE_NAME +#define JNI_PACKAGE_NAME fhuyakou_godot_plugin_android_hellogdextension + +#undef JNI_CLASS_NAME +#define JNI_CLASS_NAME HelloGDExtensionPlugin + +extern "C" { + JNIEXPORT void JNICALL JNI_METHOD(nativeAddGDExampleNode)(JNIEnv *env, jobject, jstring p_parent_node_path) { + godot::PluginManager::get_singleton()->add_gdexample_node(jstring_to_string(env, p_parent_node_path)); + } + + JNIEXPORT void JNICALL JNI_METHOD(nativeToggleVisibility)(JNIEnv *env, jobject, jboolean p_visible) { + godot::PluginManager::get_singleton()->toggle_visibility(p_visible); + } +}; diff --git a/plugins/hello_gdextension/src/main/cpp/jni/plugin_manager.cpp b/plugins/hello_gdextension/src/main/cpp/jni/plugin_manager.cpp new file mode 100644 index 0000000..647dd3e --- /dev/null +++ b/plugins/hello_gdextension/src/main/cpp/jni/plugin_manager.cpp @@ -0,0 +1,87 @@ +#include "plugin_manager.h" + +#include <godot_cpp/classes/engine.hpp> +#include <godot_cpp/classes/main_loop.hpp> +#include <godot_cpp/classes/resource.hpp> +#include <godot_cpp/classes/resource_loader.hpp> +#include <godot_cpp/classes/scene_tree.hpp> +#include <godot_cpp/classes/window.hpp> + +#include "utils.h" + +namespace godot { + +PluginManager *PluginManager::singleton = nullptr; + +PluginManager::PluginManager() { + gdexample_node = memnew(GDExample); + + Ref<Resource> resource_ref = ResourceLoader::get_singleton()->load("res://addons/hello_gdextension_plugin/interface/android_icon.svg"); + gdexample_node->set_texture(resource_ref); +} + +PluginManager::~PluginManager() { + memdelete(gdexample_node); +} + +PluginManager *PluginManager::get_singleton() { + if (singleton == nullptr) { + singleton = new PluginManager(); + } + return singleton; +} + +void PluginManager::toggle_visibility(bool p_visible) { + ALOG_ASSERT(gdexample_node != nullptr, "Uninitialized gdexample node"); + + gdexample_node->set_visible(p_visible); +} + +void PluginManager::add_gdexample_node(const String &p_parent_node_path) { + ALOG_ASSERT(gdexample_node != nullptr, "Uninitialized gdexample node"); + + if (p_parent_node_path.is_empty()) { + ALOGW("Empty parent node path, aborting..."); + return; + } + + // Retrieve the parent node. + Node *parent_node = get_node(p_parent_node_path); + if (!parent_node) { + ALOGE("Unable to retrieve parent node with path %s", p_parent_node_path.utf8().get_data()); + return; + } + + if (gdexample_node->get_parent() != nullptr) { + gdexample_node->get_parent()->remove_child(gdexample_node); + } + + parent_node->add_child(gdexample_node); + gdexample_node->set_owner(parent_node); + gdexample_node->set_centered(false); +} + +Node *PluginManager::get_node(const String &p_node_path) { + if (p_node_path.is_empty()) { + ALOGW("Empty node path argument."); + return nullptr; + } + + MainLoop *main_loop = Engine::get_singleton()->get_main_loop(); + auto *scene_tree = Object::cast_to<SceneTree>(main_loop); + if (!scene_tree) { + ALOGW("Unable to retrieve the scene tree."); + return nullptr; + } + + const Window *window = scene_tree->get_root(); + NodePath node_path(p_node_path); + Node *node = window->get_node_or_null(node_path); + if (!node) { + // Try again by treating the parameter as the node's name + node = window->find_child(p_node_path, true, false); + } + + return node; +} +} diff --git a/plugins/hello_gdextension/src/main/cpp/jni/plugin_manager.h b/plugins/hello_gdextension/src/main/cpp/jni/plugin_manager.h new file mode 100644 index 0000000..473a7e6 --- /dev/null +++ b/plugins/hello_gdextension/src/main/cpp/jni/plugin_manager.h @@ -0,0 +1,32 @@ +#ifndef PLUGIN_MANAGER_H +#define PLUGIN_MANAGER_H + +#include <godot_cpp/variant/string.hpp> + +#include "../gdexample.h" + +namespace godot { + +class PluginManager { +public: + static PluginManager *get_singleton(); + + void add_gdexample_node(const String &p_parent_node_path); + + void toggle_visibility(bool p_visible); + +private: + PluginManager(); + + ~PluginManager(); + + static Node *get_node(const String &p_node_path); + + static PluginManager *singleton; + + GDExample *gdexample_node = nullptr; +}; + +} + +#endif // PLUGIN_MANAGER_H diff --git a/plugins/hello_gdextension/src/main/cpp/jni/utils.h b/plugins/hello_gdextension/src/main/cpp/jni/utils.h new file mode 100644 index 0000000..e55cb6b --- /dev/null +++ b/plugins/hello_gdextension/src/main/cpp/jni/utils.h @@ -0,0 +1,75 @@ +#ifndef UTILS_H +#define UTILS_H + +#include <android/log.h> +#include <godot_cpp/variant/string.hpp> +#include <jni.h> + +#define LOG_TAG "HelloGDExtension" + +#define ALOG_ASSERT(_cond, ...) \ + if (!(_cond)) __android_log_assert("conditional", LOG_TAG, __VA_ARGS__) +#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) +#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) +#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) + +/** Auxiliary macros */ +#define __JNI_METHOD_BUILD(package, class_name, method) \ + Java_ ## package ## _ ## class_name ## _ ## method +#define __JNI_METHOD_EVAL(package, class_name, method) \ + __JNI_METHOD_BUILD(package, class_name, method) + +/** + * Expands the JNI signature for a JNI method. + * + * Requires to redefine the macros JNI_PACKAGE_NAME and JNI_CLASS_NAME. + * Not doing so will raise preprocessor errors during build. + * + * JNI_PACKAGE_NAME must be the JNI representation Java class package name. + * JNI_CLASS_NAME must be the JNI representation of the Java class name. + * + * For example, for the class com.example.package.SomeClass: + * JNI_PACKAGE_NAME: com_example_package + * JNI_CLASS_NAME: SomeClass + * + * Note that underscores in Java package and class names are replaced with "_1" + * in their JNI representations. + */ +#define JNI_METHOD(method) \ + __JNI_METHOD_EVAL(JNI_PACKAGE_NAME, JNI_CLASS_NAME, method) + +/** + * Expands a Java class name using slashes as package separators into its + * JNI type string representation. + * + * For example, to get the JNI type representation of a Java String: + * JAVA_TYPE("java/lang/String") + */ +#define JAVA_TYPE(class_name) "L" class_name ";" + +/** + * Default definitions for the macros required in JNI_METHOD. + * Used to raise build errors if JNI_METHOD is used without redefining them. + */ +#define JNI_CLASS_NAME "Error: JNI_CLASS_NAME not redefined" +#define JNI_PACKAGE_NAME "Error: JNI_PACKAGE_NAME not redefined" + +/** +* Converts JNI jstring to Godot String. +* @param source Source JNI string. If null an empty string is returned. +* @param env JNI environment instance. +* @return Godot string instance. +*/ +static inline godot::String jstring_to_string(JNIEnv *env, jstring source) { + if (env && source) { + const char *const source_utf8 = env->GetStringUTFChars(source, NULL); + if (source_utf8) { + godot::String result(source_utf8); + env->ReleaseStringUTFChars(source, source_utf8); + return result; + } + } + return godot::String(); +} + +#endif // UTILS_H diff --git a/plugins/hello_gdextension/src/main/cpp/register_types.cpp b/plugins/hello_gdextension/src/main/cpp/register_types.cpp new file mode 100644 index 0000000..e6be489 --- /dev/null +++ b/plugins/hello_gdextension/src/main/cpp/register_types.cpp @@ -0,0 +1,41 @@ +#include "register_types.h" + +#include "gdexample.h" + +#include <gdextension_interface.h> +#include <godot_cpp/core/defs.hpp> +#include <godot_cpp/core/class_db.hpp> +#include <godot_cpp/godot.hpp> + +using namespace godot; + +void initialize_example_module(ModuleInitializationLevel p_level) { + if (p_level!=godot::MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + + ClassDB::register_class<GDExample>(); +} + +void uninitialize_example_module(ModuleInitializationLevel p_level) { + if (p_level!=godot::MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } +} + +extern "C" { +// Initialization +GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress + p_get_proc_address, + const GDExtensionClassLibraryPtr p_library, + GDExtensionInitialization + *r_initialization) { + godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); + + init_obj.register_initializer(initialize_example_module); + init_obj.register_terminator(uninitialize_example_module); + init_obj.set_minimum_library_initialization_level(godot::MODULE_INITIALIZATION_LEVEL_SCENE); + + return init_obj.init(); +} +} diff --git a/plugins/hello_gdextension/src/main/cpp/register_types.h b/plugins/hello_gdextension/src/main/cpp/register_types.h new file mode 100644 index 0000000..d01d663 --- /dev/null +++ b/plugins/hello_gdextension/src/main/cpp/register_types.h @@ -0,0 +1,7 @@ +#ifndef REGISTER_TYPES_H +#define REGISTER_TYPES_H + +void initialize_example_module(); +void uninitialize_example_module(); + +#endif // REGISTER_TYPES_H diff --git a/plugins/hello_gdextension/src/main/java/fhuyakou/godot/plugin/android/hellogdextension/HelloGDExtensionPlugin.kt b/plugins/hello_gdextension/src/main/java/fhuyakou/godot/plugin/android/hellogdextension/HelloGDExtensionPlugin.kt new file mode 100644 index 0000000..85a28ab --- /dev/null +++ b/plugins/hello_gdextension/src/main/java/fhuyakou/godot/plugin/android/hellogdextension/HelloGDExtensionPlugin.kt @@ -0,0 +1,48 @@ +package fhuyakou.godot.plugin.android.hellogdextension + +import android.util.Log +import org.godotengine.godot.Godot +import org.godotengine.godot.plugin.GodotPlugin +import org.godotengine.godot.plugin.UsedByGodot + +/** + * Entry point for the 'HelloGDExtension' Android plugin. + * + * This plugin provides a couple of methods to add and manipulate a GDExample node. + * The GDExample node is implemented and integrated within Godot using GDExtension. + */ +class HelloGDExtensionPlugin(godot: Godot) : GodotPlugin(godot) { + + companion object { + val TAG = HelloGDExtensionPlugin::class.java.simpleName + + init { + try { + Log.v(TAG, "Loading hello_gdextension library") + System.loadLibrary("hello_gdextension") + } catch (e: UnsatisfiedLinkError) { + Log.e(TAG, "Unable to load the hello_gdextension shared library") + } + } + } + + @UsedByGodot + private fun addGDExampleNode(parentNodePath: String) { + Log.i(TAG, "Adding GDExample node to $parentNodePath") + nativeAddGDExampleNode(parentNodePath) + } + + @UsedByGodot + private fun setGDExampleVisible(visible: Boolean) { + Log.i(TAG, "Updating GDExample node visibility to $visible") + nativeToggleVisibility(visible) + } + + override fun getPluginName() = "HelloGDExtension" + + override fun getPluginGDExtensionModulesPaths() = setOf("res://addons/hello_gdextension_plugin/hello_gdextension.gdextension") + + private external fun nativeAddGDExampleNode(parentNodePath: String) + + private external fun nativeToggleVisibility(visible: Boolean) +} diff --git a/settings.gradle b/settings.gradle index 680d1ad..06e2d45 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,7 +12,9 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url "https://plugins.gradle.org/m2/" } + maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/"} } } rootProject.name = "Godot Android Samples" -include ':plugins:hello_world', ':plugins:hello_signals' +include ':plugins:hello_world', ':plugins:hello_signals', ':plugins:hello_gdextension' |