瀏覽代碼

Merge pull request #46076 from m4gr3d/expose_godot_plugin_utility_methods

[3.2] Expose GodotPlugin's utility methods
Rémi Verschelde 4 年之前
父節點
當前提交
23a6ff2782

+ 74 - 19
platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java

@@ -45,7 +45,9 @@ import androidx.annotation.Nullable;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -107,14 +109,47 @@ public abstract class GodotPlugin {
 	 * This method is invoked on the render thread.
 	 */
 	public final void onRegisterPluginWithGodotNative() {
-		nativeRegisterSingleton(getPluginName(), this);
+		registeredSignals.putAll(registerPluginWithGodotNative(this, new GodotPluginInfoProvider() {
+			@NonNull
+			@Override
+			public String getPluginName() {
+				return GodotPlugin.this.getPluginName();
+			}
+
+			@NonNull
+			@Override
+			public List<String> getPluginMethods() {
+				return GodotPlugin.this.getPluginMethods();
+			}
+
+			@NonNull
+			@Override
+			public Set<SignalInfo> getPluginSignals() {
+				return GodotPlugin.this.getPluginSignals();
+			}
+
+			@NonNull
+			@Override
+			public Set<String> getPluginGDNativeLibrariesPaths() {
+				return GodotPlugin.this.getPluginGDNativeLibrariesPaths();
+			}
+		}));
+	}
 
-		Class clazz = getClass();
+	/**
+	 * Register the plugin with Godot native code.
+	 *
+	 * This method must be invoked on the render thread.
+	 */
+	public static Map<String, SignalInfo> registerPluginWithGodotNative(Object pluginObject, GodotPluginInfoProvider pluginInfoProvider) {
+		nativeRegisterSingleton(pluginInfoProvider.getPluginName(), pluginObject);
+
+		Class clazz = pluginObject.getClass();
 		Method[] methods = clazz.getDeclaredMethods();
 		for (Method method : methods) {
 			boolean found = false;
 
-			for (String s : getPluginMethods()) {
+			for (String s : pluginInfoProvider.getPluginMethods()) {
 				if (s.equals(method.getName())) {
 					found = true;
 					break;
@@ -123,7 +158,7 @@ public abstract class GodotPlugin {
 			if (!found)
 				continue;
 
-			List<String> ptr = new ArrayList<String>();
+			List<String> ptr = new ArrayList<>();
 
 			Class[] paramTypes = method.getParameterTypes();
 			for (Class c : paramTypes) {
@@ -133,21 +168,24 @@ public abstract class GodotPlugin {
 			String[] pt = new String[ptr.size()];
 			ptr.toArray(pt);
 
-			nativeRegisterMethod(getPluginName(), method.getName(), method.getReturnType().getName(), pt);
+			nativeRegisterMethod(pluginInfoProvider.getPluginName(), method.getName(), method.getReturnType().getName(), pt);
 		}
 
 		// Register the signals for this plugin.
-		for (SignalInfo signalInfo : getPluginSignals()) {
+		Map<String, SignalInfo> registeredSignals = new HashMap<>();
+		for (SignalInfo signalInfo : pluginInfoProvider.getPluginSignals()) {
 			String signalName = signalInfo.getName();
-			nativeRegisterSignal(getPluginName(), signalName, signalInfo.getParamTypesNames());
+			nativeRegisterSignal(pluginInfoProvider.getPluginName(), signalName, signalInfo.getParamTypesNames());
 			registeredSignals.put(signalName, signalInfo);
 		}
 
 		// Get the list of gdnative libraries to register.
-		Set<String> gdnativeLibrariesPaths = getPluginGDNativeLibrariesPaths();
+		Set<String> gdnativeLibrariesPaths = pluginInfoProvider.getPluginGDNativeLibrariesPaths();
 		if (!gdnativeLibrariesPaths.isEmpty()) {
 			nativeRegisterGDNativeLibraries(gdnativeLibrariesPaths.toArray(new String[0]));
 		}
+
+		return registeredSignals;
 	}
 
 	/**
@@ -274,8 +312,8 @@ public abstract class GodotPlugin {
 
 	/**
 	 * Emit a registered Godot signal.
-	 * @param signalName
-	 * @param signalArgs
+	 * @param signalName Name of the signal to emit. It will be validated against the set of registered signals.
+	 * @param signalArgs Arguments used to populate the emitted signal. The arguments will be validated against the {@link SignalInfo} matching the registered signalName parameter.
 	 */
 	protected void emitSignal(final String signalName, final Object... signalArgs) {
 		try {
@@ -285,6 +323,27 @@ public abstract class GodotPlugin {
 				throw new IllegalArgumentException(
 						"Signal " + signalName + " is not registered for this plugin.");
 			}
+			emitSignal(getGodot(), getPluginName(), signalInfo, signalArgs);
+		} catch (IllegalArgumentException exception) {
+			Log.w(TAG, exception.getMessage());
+			if (BuildConfig.DEBUG) {
+				throw exception;
+			}
+		}
+	}
+
+	/**
+	 * Emit a Godot signal.
+	 * @param godot
+	 * @param pluginName Name of the Godot plugin the signal will be emitted from. The plugin must already be registered with the Godot engine.
+	 * @param signalInfo Information about the signal to emit.
+	 * @param signalArgs Arguments used to populate the emitted signal. The arguments will be validated against the given {@link SignalInfo} parameter.
+	 */
+	public static void emitSignal(Godot godot, String pluginName, SignalInfo signalInfo, final Object... signalArgs) {
+		try {
+			if (signalInfo == null) {
+				throw new IllegalArgumentException("Signal must be non null.");
+			}
 
 			// Validate the arguments count.
 			Class<?>[] signalParamTypes = signalInfo.getParamTypes();
@@ -301,12 +360,8 @@ public abstract class GodotPlugin {
 				}
 			}
 
-			runOnRenderThread(new Runnable() {
-				@Override
-				public void run() {
-					nativeEmitSignal(getPluginName(), signalName, signalArgs);
-				}
-			});
+			godot.runOnRenderThread(() -> nativeEmitSignal(pluginName, signalInfo.getName(), signalArgs));
+
 		} catch (IllegalArgumentException exception) {
 			Log.w(TAG, exception.getMessage());
 			if (BuildConfig.DEBUG) {
@@ -334,7 +389,7 @@ public abstract class GodotPlugin {
 	 * Used to register gdnative libraries bundled by the plugin.
 	 * @param gdnlibPaths Paths to the libraries relative to the 'assets' directory.
 	 */
-	private native void nativeRegisterGDNativeLibraries(String[] gdnlibPaths);
+	private static native void nativeRegisterGDNativeLibraries(String[] gdnlibPaths);
 
 	/**
 	 * Used to complete registration of the {@link GodotPlugin} instance's methods.
@@ -342,7 +397,7 @@ public abstract class GodotPlugin {
 	 * @param signalName Name of the signal to register
 	 * @param signalParamTypes Signal parameters types
 	 */
-	private native void nativeRegisterSignal(String pluginName, String signalName, String[] signalParamTypes);
+	private static native void nativeRegisterSignal(String pluginName, String signalName, String[] signalParamTypes);
 
 	/**
 	 * Used to emit signal by {@link GodotPlugin} instance.
@@ -350,5 +405,5 @@ public abstract class GodotPlugin {
 	 * @param signalName Name of the signal to emit
 	 * @param signalParams Signal parameters
 	 */
-	private native void nativeEmitSignal(String pluginName, String signalName, Object[] signalParams);
+	private static native void nativeEmitSignal(String pluginName, String signalName, Object[] signalParams);
 }

+ 68 - 0
platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java

@@ -0,0 +1,68 @@
+/*************************************************************************/
+/*  GodotPluginInfoProvider.java                                         */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+package org.godotengine.godot.plugin;
+
+import androidx.annotation.NonNull;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Provides the set of information expected from a Godot plugin.
+ */
+public interface GodotPluginInfoProvider {
+
+	/**
+	 * Returns the name of the plugin.
+	 */
+	@NonNull
+	String getPluginName();
+
+	/**
+	 * Returns the list of methods to be exposed to Godot.
+	 */
+	@NonNull
+	List<String> getPluginMethods();
+
+	/**
+	 * Returns the list of signals to be exposed to Godot.
+	 */
+	@NonNull
+	Set<SignalInfo> getPluginSignals();
+
+	/**
+	 * Returns the paths for the plugin's gdnative libraries (if any).
+	 *
+	 * The paths must be relative to the 'assets' directory and point to a '*.gdnlib' file.
+	 */
+	@NonNull
+	Set<String> getPluginGDNativeLibrariesPaths();
+}

+ 3 - 3
platform/android/plugin/godot_plugin_jni.cpp

@@ -87,7 +87,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
 	s->add_method(mname, mid, types, get_jni_type(retval));
 }
 
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jclass clazz, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types) {
 	String singleton_name = jstring_to_string(j_plugin_name, env);
 
 	ERR_FAIL_COND(!jni_singletons.has(singleton_name));
@@ -109,7 +109,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
 	singleton->add_signal(signal_name, types);
 }
 
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jclass clazz, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params) {
 	String singleton_name = jstring_to_string(j_plugin_name, env);
 
 	ERR_FAIL_COND(!jni_singletons.has(singleton_name));
@@ -134,7 +134,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitS
 	singleton->emit_signal(signal_name, args, count);
 }
 
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jclass clazz, jobjectArray gdnlib_paths) {
 	int gdnlib_count = env->GetArrayLength(gdnlib_paths);
 	if (gdnlib_count == 0) {
 		return;

+ 3 - 3
platform/android/plugin/godot_plugin_jni.h

@@ -37,9 +37,9 @@
 extern "C" {
 JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jclass clazz, jstring name, jobject obj);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterMethod(JNIEnv *env, jclass clazz, jstring sname, jstring name, jstring ret, jobjectArray args);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jclass clazz, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jclass clazz, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jclass clazz, jobjectArray gdnlib_paths);
 }
 
 #endif // GODOT_PLUGIN_JNI_H