1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Merge pull request #111135 from m4gr3d/add_emit_signal_overload

[Android] Minor updates to the `GodotPlugin` APIs
This commit is contained in:
Thaddeus Crews
2025-10-21 15:10:55 -05:00
6 changed files with 44 additions and 45 deletions

View File

@@ -70,6 +70,7 @@ class JavaClass : public RefCounted {
RBMap<StringName, Variant> constant_map;
struct MethodInfo {
bool _public = false;
bool _static = false;
bool _constructor = false;
Vector<uint32_t> param_types;
@@ -276,7 +277,7 @@ class JavaClassWrapper : public Object {
Ref<JavaObject> exception;
Ref<JavaClass> _wrap(const String &p_class, bool p_allow_non_public_methods_access);
Ref<JavaClass> _wrap(const String &p_class, bool p_allow_non_public_methods_access = false);
static JavaClassWrapper *singleton;
@@ -295,7 +296,7 @@ public:
}
#ifdef ANDROID_ENABLED
Ref<JavaClass> wrap_jclass(jclass p_class, bool p_allow_private_methods_access = false);
Ref<JavaClass> wrap_jclass(jclass p_class, bool p_allow_non_public_methods_access = false);
#endif
JavaClassWrapper();
};

View File

@@ -61,31 +61,15 @@ public:
}
// Check the method we're looking for is in the JNISingleton map.
// This is done because JNISingletons register methods differently than wrapped JavaClass / JavaObject to allow
// for access to private methods annotated with the @UsedByGodot annotation.
// In the future, we should remove access to private methods and require that JNISingletons' methods exposed to
// GDScript be all public, similarly to what we do for wrapped JavaClass / JavaObject methods. Doing so will
// also allow dropping and deprecating the @UsedByGodot annotation.
RBMap<StringName, MethodData>::Element *E = method_map.find(p_method);
if (E) {
if (wrapped_object.is_valid()) {
// Check that the arguments match.
int method_arg_count = E->get().argtypes.size();
if (p_argcount < method_arg_count) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
} else if (p_argcount > method_arg_count) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
} else {
// Check the arguments are valid.
bool arguments_valid = true;
for (int i = 0; i < p_argcount; i++) {
if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
arguments_valid = false;
break;
}
}
if (arguments_valid) {
return wrapped_object->callp(p_method, p_args, p_argcount, r_error);
} else {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
}
}
return wrapped_object->callp(p_method, p_args, p_argcount, r_error);
} else {
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
}

View File

@@ -361,7 +361,7 @@ public abstract class GodotPlugin {
/**
* Emit a registered Godot signal.
* @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.
* @param signalArgs Arguments used to populate the emitted signal. The arguments will be validated against the registered {@link SignalInfo} matching the signalName parameter.
*/
protected void emitSignal(final String signalName, final Object... signalArgs) {
try {
@@ -380,6 +380,15 @@ public abstract class GodotPlugin {
}
}
/**
* Emit a registered Godot signal.
* @param signal 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 registered {@link SignalInfo} matching the signal parameter.
*/
protected void emitSignal(SignalInfo signal, final Object... signalArgs) {
emitSignal(signal.getName(), signalArgs);
}
/**
* Emit a Godot signal.
* @param godot Godot instance
@@ -402,7 +411,8 @@ public abstract class GodotPlugin {
// Validate the argument's types.
for (int i = 0; i < signalParamTypes.length; i++) {
if (!signalParamTypes[i].isInstance(signalArgs[i])) {
Object signalArg = signalArgs[i];
if (signalArg != null && !signalParamTypes[i].isInstance(signalArg)) {
throw new IllegalArgumentException(
"Invalid type for argument #" + i + ". Should be of type " + signalParamTypes[i].getName());
}

View File

@@ -199,7 +199,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
case ARG_ARRAY_BIT | ARG_TYPE_CHARSEQUENCE: {
if (p_args[i]->get_type() == Variant::ARRAY) {
Array arr = *p_args[i];
if (arr.is_typed() && arr.get_typed_builtin() != Variant::STRING) {
if (arr.is_typed() && (arr.get_typed_builtin() != Variant::STRING || arr.get_typed_builtin() != Variant::STRING_NAME)) {
arg_expected = Variant::ARRAY;
}
} else if (p_args[i]->get_type() != Variant::PACKED_STRING_ARRAY) {
@@ -1527,6 +1527,7 @@ Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_non_p
}
JavaClass::MethodInfo mi;
mi._public = is_public;
mi._static = (mods & 0x8) != 0;
mi._constructor = is_constructor;
bool valid = true;
@@ -1686,7 +1687,7 @@ Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_non_p
return java_class;
}
Ref<JavaClass> JavaClassWrapper::wrap_jclass(jclass p_class, bool p_allow_private_methods_access) {
Ref<JavaClass> JavaClassWrapper::wrap_jclass(jclass p_class, bool p_allow_non_public_methods_access) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL_V(env, Ref<JavaClass>());
@@ -1694,7 +1695,7 @@ Ref<JavaClass> JavaClassWrapper::wrap_jclass(jclass p_class, bool p_allow_privat
String class_name_string = jstring_to_string(class_name, env);
env->DeleteLocalRef(class_name);
return _wrap(class_name_string, p_allow_private_methods_access);
return _wrap(class_name_string, p_allow_non_public_methods_access);
}
JavaClassWrapper *JavaClassWrapper::singleton = nullptr;

View File

@@ -55,16 +55,18 @@ Callable jcallable_to_callable(JNIEnv *p_env, jobject p_jcallable_obj) {
ERR_FAIL_NULL_V(p_env, Callable());
const Variant *callable_variant = nullptr;
jclass callable_class = jni_find_class(p_env, "org/godotengine/godot/variant/Callable");
if (callable_class && p_env->IsInstanceOf(p_jcallable_obj, callable_class)) {
jmethodID get_native_pointer = p_env->GetMethodID(callable_class, "getNativePointer", "()J");
jlong native_callable = p_env->CallLongMethod(p_jcallable_obj, get_native_pointer);
if (p_jcallable_obj) {
jclass callable_class = jni_find_class(p_env, "org/godotengine/godot/variant/Callable");
if (callable_class && p_env->IsInstanceOf(p_jcallable_obj, callable_class)) {
jmethodID get_native_pointer = p_env->GetMethodID(callable_class, "getNativePointer", "()J");
jlong native_callable = p_env->CallLongMethod(p_jcallable_obj, get_native_pointer);
callable_variant = reinterpret_cast<const Variant *>(native_callable);
callable_variant = reinterpret_cast<const Variant *>(native_callable);
}
p_env->DeleteLocalRef(callable_class);
}
p_env->DeleteLocalRef(callable_class);
ERR_FAIL_NULL_V(callable_variant, Callable());
return *callable_variant;
}
@@ -73,16 +75,18 @@ String charsequence_to_string(JNIEnv *p_env, jobject p_charsequence) {
ERR_FAIL_NULL_V(p_env, String());
String result;
jclass bclass = jni_find_class(p_env, "java/lang/CharSequence");
if (bclass && p_env->IsInstanceOf(p_charsequence, bclass)) {
jmethodID to_string = p_env->GetMethodID(bclass, "toString", "()Ljava/lang/String;");
jstring obj_string = (jstring)p_env->CallObjectMethod(p_charsequence, to_string);
if (p_charsequence) {
jclass bclass = jni_find_class(p_env, "java/lang/CharSequence");
if (bclass && p_env->IsInstanceOf(p_charsequence, bclass)) {
jmethodID to_string = p_env->GetMethodID(bclass, "toString", "()Ljava/lang/String;");
jstring obj_string = (jstring)p_env->CallObjectMethod(p_charsequence, to_string);
result = jstring_to_string(obj_string, p_env);
p_env->DeleteLocalRef(obj_string);
result = jstring_to_string(obj_string, p_env);
p_env->DeleteLocalRef(obj_string);
}
p_env->DeleteLocalRef(bclass);
}
p_env->DeleteLocalRef(bclass);
return result;
}

View File

@@ -128,7 +128,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitS
for (int i = 0; i < count; i++) {
jobject j_param = env->GetObjectArrayElement(j_signal_params, i);
ERR_FAIL_NULL(j_param);
memnew_placement(&variant_params[i], Variant(_jobject_to_variant(env, j_param)));
args[i] = &variant_params[i];
env->DeleteLocalRef(j_param);