summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFredia Huya-Kouadio <fhuya@meta.com>2023-08-17 11:49:20 -0700
committerGitHub <noreply@github.com>2023-08-17 11:49:20 -0700
commit1f04b16320add64cea98e33fe541b426ff321713 (patch)
tree741a6563c1795437c0ad5b80c6121b5476861361
parente61f1555b696b62152787d0fee14435325aee62b (diff)
parent37e27e3db22c0b33d098a0ac1fb2dfe8861be0fb (diff)
downloadgodot-android-samples-1f04b16320add64cea98e33fe541b426ff321713.tar.gz
godot-android-samples-1f04b16320add64cea98e33fe541b426ff321713.tar.bz2
godot-android-samples-1f04b16320add64cea98e33fe541b426ff321713.zip
Merge pull request #2 from m4gr3d/add_gdextension_plugin_sample
Add an Android GDExtension plugin sample
-rw-r--r--.gitmodules3
-rw-r--r--build.gradle3
-rw-r--r--config.gradle2
-rw-r--r--plugins/hello_gdextension/.gitignore1
-rw-r--r--plugins/hello_gdextension/CMakeLists.txt141
-rw-r--r--plugins/hello_gdextension/README.md61
-rw-r--r--plugins/hello_gdextension/SConstruct30
-rw-r--r--plugins/hello_gdextension/build.gradle92
-rw-r--r--plugins/hello_gdextension/demo/.gitattributes2
-rw-r--r--plugins/hello_gdextension/demo/.gitignore4
-rw-r--r--plugins/hello_gdextension/demo/addons/.gitignore2
-rw-r--r--plugins/hello_gdextension/demo/export_presets.cfg200
-rw-r--r--plugins/hello_gdextension/demo/icon.svg1
-rw-r--r--plugins/hello_gdextension/demo/main.gd5
-rw-r--r--plugins/hello_gdextension/demo/main.tscn12
-rw-r--r--plugins/hello_gdextension/demo/project.godot30
m---------plugins/hello_gdextension/godot-cpp0
-rw-r--r--plugins/hello_gdextension/src/main/AndroidManifest.xml20
-rw-r--r--plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.bin/.gdignore1
-rw-r--r--plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.bin/.gitignore2
-rw-r--r--plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/.gdignore1
-rw-r--r--plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/hello_gdextension_editor_export_plugin.gd16
-rw-r--r--plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/.export/hello_gdextension_editor_plugin.gd15
-rw-r--r--plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/hello_gdextension.gdextension14
-rw-r--r--plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/interface/android_icon.svg2
-rw-r--r--plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/interface/hello_gdextension_plugin.gd26
-rw-r--r--plugins/hello_gdextension/src/main/assets/addons/hello_gdextension_plugin/plugin.cfg7
-rw-r--r--plugins/hello_gdextension/src/main/cpp/gdexample.cpp22
-rw-r--r--plugins/hello_gdextension/src/main/cpp/gdexample.h25
-rw-r--r--plugins/hello_gdextension/src/main/cpp/jni/plugin_jni.cpp20
-rw-r--r--plugins/hello_gdextension/src/main/cpp/jni/plugin_manager.cpp87
-rw-r--r--plugins/hello_gdextension/src/main/cpp/jni/plugin_manager.h32
-rw-r--r--plugins/hello_gdextension/src/main/cpp/jni/utils.h75
-rw-r--r--plugins/hello_gdextension/src/main/cpp/register_types.cpp41
-rw-r--r--plugins/hello_gdextension/src/main/cpp/register_types.h7
-rw-r--r--plugins/hello_gdextension/src/main/java/fhuyakou/godot/plugin/android/hellogdextension/HelloGDExtensionPlugin.kt48
-rw-r--r--settings.gradle4
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'