Skip to content

Improve Custom Callables and add SignalConnector #803

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 11, 2025
Merged
40 changes: 20 additions & 20 deletions harness/tests/src/main/java/godot/tests/JavaTestClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@

@RegisterClass
public class JavaTestClass extends Node {
@RegisterSignal
public Signal0 testSignal = Signal0.create(this, "test_signal");

@RegisterSignal(parameters = {"param1", "param2"})
public Signal2<String, String> testSignal2 = Signal2.create(this, "test_signal_2");
//@RegisterSignal
//public Signal0 testSignal = Signal0.create(this, "test_signal");
//
//@RegisterSignal(parameters = {"param1", "param2"})
//public Signal2<String, String> testSignal2 = Signal2.create(this, "test_signal_2");

// The following should NOT work as we cannot extract parameter names. The compiler checks should catch that and throw a build error
// @RegisterSignal
Expand Down Expand Up @@ -71,15 +71,15 @@ public String greeting() {
@RegisterProperty
public Dictionary<Float, String> dictionary = new Dictionary<>(Float.class, String.class);

public LambdaCallable<Void> lambdaCallable = LambdaCallable0.create(
Void.class,
() -> {
System.out.println("Hello from Callable");
return null;
}
);

public NativeCallable methodCallable = Callable.create(this, StringNames.asStringName("DummyName"));
//public LambdaCallable<Void> lambdaCallable = LambdaCallable0.create(
// Void.class,
// () -> {
// System.out.println("Hello from Callable");
// return null;
// }
//);
//
//public NativeCallable methodCallable = Callable.create(this, StringNames.asStringName("DummyName"));

@RegisterFunction
@Override
Expand All @@ -96,12 +96,12 @@ public void _ready() {

@RegisterFunction
public void connectAndTriggerSignal() {
connect(
StringNames.asStringName("test_signal"),
new NativeCallable(this, StringNames.asStringName("signal_callback")),
(int) ConnectFlags.ONE_SHOT.getId()
);
emitSignal(StringNames.asStringName("test_signal"));
//connect(
// StringNames.asStringName("test_signal"),
// new NativeCallable(this, StringNames.asStringName("signal_callback")),
// (int) ConnectFlags.ONE_SHOT.getId()
//);
//emitSignal(StringNames.asStringName("test_signal"));
}

@NotNull
Expand Down
13 changes: 7 additions & 6 deletions harness/tests/src/main/kotlin/godot/tests/FuncRefTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import godot.annotation.RegisterFunction
import godot.annotation.RegisterProperty
import godot.annotation.RegisterSignal
import godot.annotation.Rpc
import godot.core.callable0
import godot.core.callable1
import godot.core.connect
import godot.core.signal0
import godot.extension.call
import godot.extension.callDeferred

@RegisterClass
class FuncRefTest : Node() {
Expand Down Expand Up @@ -51,12 +52,12 @@ class FuncRefTest : Node() {

@RegisterFunction
fun testCallWithoutParam() {
call(this::withoutParamCallback)
callable0(this::withoutParamCallback).call()
}

@RegisterFunction
fun testCallDeferredWithoutParam() {
callDeferred(this::withoutParamCallback)
callable0(this::withoutParamCallback).callDeferred()
}

@RegisterFunction
Expand All @@ -66,11 +67,11 @@ class FuncRefTest : Node() {

@RegisterFunction
fun testCallWithParam() {
call(this::withParamCallback, true)
callable1(this::withParamCallback).call(true)
}

@RegisterFunction
fun testCallDeferredWithParam() {
callDeferred(this::withParamCallback, true)
callable1(this::withParamCallback).callDeferred(true)
}
}
1 change: 1 addition & 0 deletions harness/tests/src/main/kotlin/godot/tests/Invocation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import godot.extension.getNodeAs
import godot.registration.Range
import godot.tests.subpackage.OtherScript
import godot.common.util.RealT
import godot.core.connect
import org.joda.time.DateTime

enum class TestEnum {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import godot.api.Node
import godot.annotation.RegisterClass
import godot.annotation.RegisterFunction
import godot.annotation.RegisterProperty
import godot.core.NativeCallable
import godot.core.MethodCallable
import godot.core.VariantArray
import godot.core.toGodotName
import godot.core.variantArrayOf
import godot.global.GD

Expand All @@ -16,22 +17,22 @@ class CallableMethodBindTest: Node() {

@RegisterFunction
fun callWithMethodWithAllBinds() {
NativeCallable(this, CallableMethodBindTest::readySignalMethodBindTest).bind(1, 2, 3).call()
MethodCallable(this, CallableMethodBindTest::readySignalMethodBindTest.toGodotName()).bindUnsafe(1, 2, 3).callUnsafe()
}

@RegisterFunction
fun callWithMethodWithTwoBinds() {
NativeCallable(this, CallableMethodBindTest::readySignalMethodBindTest).bind(2, 3).call(0)
MethodCallable(this, CallableMethodBindTest::readySignalMethodBindTest.toGodotName()).bindUnsafe(2, 3).callUnsafe(0)
}

@RegisterFunction
fun callWithMethodWithOneBind() {
NativeCallable(this, CallableMethodBindTest::readySignalMethodBindTest).bind(3).call(0, 0)
MethodCallable(this, CallableMethodBindTest::readySignalMethodBindTest.toGodotName()).bindUnsafe(3).callUnsafe(0, 0)
}

@RegisterFunction
fun callWithMethodWithNoBind() {
NativeCallable(this, CallableMethodBindTest::readySignalMethodBindTest).bind().call(0, 0, 0)
MethodCallable(this, CallableMethodBindTest::readySignalMethodBindTest.toGodotName()).bindUnsafe().callUnsafe(0, 0, 0)
}

@RegisterFunction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,7 @@ class CoroutineTest : Object() {
@RegisterFunction
fun asyncLoadResource() {
godotCoroutine {
val resource = ResourceLoader.awaitLoadAs<PackedScene>("res://Spatial.tscn") { progress ->
GD.print("Resource load progress: $progress")
}
val resource = ResourceLoader.awaitLoadAs<PackedScene>("res://Spatial.tscn")

GD.print("Resource: $resource")

Expand Down
12 changes: 6 additions & 6 deletions harness/tests/test/unit/test_call_java_class.gd
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ func test_field_set():
java_scene.free()


func test_signal():
var java_scene: JavaTestClass = load("res://java_test_scene.tscn").instantiate()
get_tree().root.add_child(java_scene)
await get_tree().create_timer(1).timeout
java_scene.connect_and_trigger_signal()
assert_true(java_scene.signal_emitted, "Signal should've been emitted in java")
#func test_signal():
# var java_scene: JavaTestClass = load("res://java_test_scene.tscn").instantiate()
# get_tree().root.add_child(java_scene)
# await get_tree().create_timer(1).timeout
# java_scene.connect_and_trigger_signal()
# assert_true(java_scene.signal_emitted, "Signal should've been emitted in java")
50 changes: 25 additions & 25 deletions harness/tests/test/unit/test_funcref.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,36 @@ extends "res://addons/gut/test.gd"


func test_call_without_param():
var func_ref_test_script = FuncRefTest.new()
func_ref_test_script.test_call_without_param()
assert_true(func_ref_test_script.call_flag)
func_ref_test_script.free()
var func_ref_test_script = FuncRefTest.new()
func_ref_test_script.test_call_without_param()
assert_true(func_ref_test_script.call_flag)
func_ref_test_script.free()

func test_call_deferred_without_param():
var func_ref_test_script = FuncRefTest.new()
func_ref_test_script.test_call_deferred_without_param()
await get_tree().create_timer(1).timeout
assert_true(func_ref_test_script.call_flag)
func_ref_test_script.free()
var func_ref_test_script = FuncRefTest.new()
func_ref_test_script.test_call_deferred_without_param()
await get_tree().create_timer(1).timeout
assert_true(func_ref_test_script.call_flag)
func_ref_test_script.free()

func test_call_with_param():
var func_ref_test_script = FuncRefTest.new()
func_ref_test_script.test_call_with_param()
assert_true(func_ref_test_script.call_with_param_flag)
func_ref_test_script.free()
var func_ref_test_script = FuncRefTest.new()
func_ref_test_script.test_call_with_param()
assert_true(func_ref_test_script.call_with_param_flag)
func_ref_test_script.free()

func test_call_deferred_with_param():
var func_ref_test_script = FuncRefTest.new()
func_ref_test_script.test_call_deferred_with_param()
await get_tree().create_timer(3).timeout
assert_true(func_ref_test_script.call_with_param_flag)
func_ref_test_script.free()
var func_ref_test_script = FuncRefTest.new()
func_ref_test_script.test_call_deferred_with_param()
await get_tree().create_timer(3).timeout
assert_true(func_ref_test_script.call_with_param_flag)
func_ref_test_script.free()

func test_signal_call():
var func_ref_test_script = FuncRefTest.new()
get_tree().root.add_child(func_ref_test_script)
func_ref_test_script.test_signal_call()
await get_tree().create_timer(1).timeout
assert_true(func_ref_test_script.signal_call_flag)
get_tree().root.remove_child(func_ref_test_script)
func_ref_test_script.free()
var func_ref_test_script = FuncRefTest.new()
get_tree().root.add_child(func_ref_test_script)
func_ref_test_script.test_signal_call()
await get_tree().create_timer(1).timeout
assert_true(func_ref_test_script.signal_call_flag)
get_tree().root.remove_child(func_ref_test_script)
func_ref_test_script.free()
66 changes: 33 additions & 33 deletions harness/tests/test/unit/test_signals.gd
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
extends "res://addons/gut/test.gd"

func test_signal_connection_script_instantiation():
var script = SignalTest.new()
get_tree().root.add_child(script)
assert_eq(script.is_connected("no_param_signal_delegate", Callable(script.other_script, "hook_no_param")), true, "signal \"no_param_signal_delegate\" should be connected to \"otherScript::hook_no_param\"")
assert_eq(script.is_connected("one_param_signal_delegate", Callable(script.other_script, "hook_one_param")), true, "signal \"one_param_signal_delegate\" should be connected to \"otherScript::hook_one_param\"")
assert_eq(script.is_connected("two_param_signal_delegate", Callable(script.other_script, "hook_two_param")), true, "signal \"two_param_signal_delegate\" should be connected to \"otherScript::hook_two_param\"")
var script = SignalTest.new()
get_tree().root.add_child(script)
assert_eq(script.is_connected("no_param_signal_delegate", Callable(script.other_script, "hook_no_param")), true, "signal \"no_param_signal_delegate\" should be connected to \"otherScript::hook_no_param\"")
assert_eq(script.is_connected("one_param_signal_delegate", Callable(script.other_script, "hook_one_param")), true, "signal \"one_param_signal_delegate\" should be connected to \"otherScript::hook_one_param\"")
assert_eq(script.is_connected("two_param_signal_delegate", Callable(script.other_script, "hook_two_param")), true, "signal \"two_param_signal_delegate\" should be connected to \"otherScript::hook_two_param\"")

assert_eq(script.is_connected("no_param_signal_field", Callable(script.other_script, "hook_no_param")), true, "signal \"no_param_signal_field\" should be connected to \"otherScript::hook_no_param\"")
assert_eq(script.is_connected("one_param_signal_field", Callable(script.other_script, "hook_one_param")), true, "signal \"one_param_signal_field\" should be connected to \"otherScript::hook_one_param\"")
assert_eq(script.is_connected("two_param_signal_field", Callable(script.other_script, "hook_two_param")), true, "signal \"two_param_signal_field\" should be connected to \"otherScript::hook_two_param\"")
assert_eq(script.is_connected("no_param_signal_field", Callable(script.other_script, "hook_no_param")), true, "signal \"no_param_signal_field\" should be connected to \"otherScript::hook_no_param\"")
assert_eq(script.is_connected("one_param_signal_field", Callable(script.other_script, "hook_one_param")), true, "signal \"one_param_signal_field\" should be connected to \"otherScript::hook_one_param\"")
assert_eq(script.is_connected("two_param_signal_field", Callable(script.other_script, "hook_two_param")), true, "signal \"two_param_signal_field\" should be connected to \"otherScript::hook_two_param\"")

script.free()
script.free()

func test_signal_connection_code():
var invocation_script = load("res://Spatial.tscn").instantiate()
get_tree().root.add_child(invocation_script)
assert_eq(invocation_script.button.is_connected("pressed", Callable(invocation_script.invocation, "hook_no_param")), true, "signal \"pressed\" of button should be connected to \"invocation_script.invocation::hook_no_param\"")
invocation_script.free()
var invocation_script = load("res://Spatial.tscn").instantiate()
get_tree().root.add_child(invocation_script)
assert_eq(invocation_script.button.is_connected("pressed", Callable(invocation_script.invocation, "hook_no_param")), true, "signal \"pressed\" of button should be connected to \"invocation_script.invocation::hook_no_param\"")
invocation_script.free()

func test_signal_emitted_with_multiple_targets():
var script = SignalTest.new()
get_tree().root.add_child(script)
assert_eq(script.array.size(), 16)
assert_eq(script.array[0], Vector2(0,0))
assert_eq(script.array[1], Vector2(1,1))
assert_eq(script.array[2], Vector2(1,2))
assert_eq(script.array[3], Vector2(1,3))
assert_eq(script.array[4], Vector2(1,4))
assert_eq(script.array[5], Vector2(1,5))
assert_eq(script.array[6], Vector2(1,6))
assert_eq(script.array[7], Vector2(1,7))
assert_eq(script.array[8], Vector2(1,7))
assert_eq(script.array[9], Vector2(1,6))
assert_eq(script.array[10], Vector2(1,5))
assert_eq(script.array[11], Vector2(1,4))
assert_eq(script.array[12], Vector2(1,3))
assert_eq(script.array[13], Vector2(1,2))
assert_eq(script.array[14], Vector2(1,1))
assert_eq(script.array[15], Vector2(0,0))
script.free()
var script = SignalTest.new()
get_tree().root.add_child(script)
assert_eq(script.array.size(), 16)
assert_eq(script.array[0], Vector2(0,0))
assert_eq(script.array[1], Vector2(1,1))
assert_eq(script.array[2], Vector2(1,2))
assert_eq(script.array[3], Vector2(1,3))
assert_eq(script.array[4], Vector2(1,4))
assert_eq(script.array[5], Vector2(1,5))
assert_eq(script.array[6], Vector2(1,6))
assert_eq(script.array[7], Vector2(1,7))
assert_eq(script.array[8], Vector2(1,7))
assert_eq(script.array[9], Vector2(1,6))
assert_eq(script.array[10], Vector2(1,5))
assert_eq(script.array[11], Vector2(1,4))
assert_eq(script.array[12], Vector2(1,3))
assert_eq(script.array[13], Vector2(1,2))
assert_eq(script.array[14], Vector2(1,1))
assert_eq(script.array[15], Vector2(0,0))
script.free()
42 changes: 34 additions & 8 deletions install_vulkan_sdk_macos.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@

#!/usr/bin/env sh

set -euo pipefail
IFS=$'\n\t'
new_ver_full=''

# Check currently installed and latest available Vulkan SDK versions.
if command -v jq 2>&1 >/dev/null; then
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/config.json" -o /tmp/vulkan-sdk.json

new_ver_full=`jq -r '.version' /tmp/vulkan-sdk.json`
new_ver=`echo "$new_ver_full" | awk -F. '{ printf("%d%02d%04d%02d\n", $1,$2,$3,$4); }';`

rm -f /tmp/vulkan-sdk.json

for f in $HOME/VulkanSDK/*; do
if [ -d "$f" ]; then
f=`echo "${f##*/}" | awk -F. '{ printf("%d%02d%04d%02d\n", $1,$2,$3,$4); }';`
if [ $f -ge $new_ver ]; then
echo 'Latest or newer Vulkan SDK is already installed. Skipping installation.'
exit 0
fi
fi
done
else
echo 'Error: Could not find 'jq' command. Is jq installed? Try running "brew install jq" or "port install jq" and rerunning this script.'
exit 1
fi

# Download and install the Vulkan SDK.
curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.zip" -o /tmp/vulkan-sdk.zip
unzip -l /tmp/vulkan-sdk.zip | grep 'InstallVulkan.*\.app' | head -n 1 | awk '{print $4}' | tr -d '/' > /tmp/install_app_name

unzip /tmp/vulkan-sdk.zip -d /tmp
install_app_name=$(cat /tmp/install_app_name)
/tmp/$install_app_name/Contents/MacOS/${install_app_name%\.app} \
--accept-licenses --default-answer --confirm-command install

rm -rf /tmp/$install_app_name
if [ -d "/tmp/vulkansdk-macOS-$new_ver_full.app" ]; then
/tmp/vulkansdk-macOS-$new_ver_full.app/Contents/MacOS/vulkansdk-macOS-$new_ver_full --accept-licenses --default-answer --confirm-command install
rm -rf /tmp/vulkansdk-macOS-$new_ver_full.app
else
echo "Couldn't install the Vulkan SDK, the unzipped contents may no longer match what this script expects."
exit 1
fi

rm -f /tmp/vulkan-sdk.zip
rm -f /tmp/install_app_name

echo 'Vulkan SDK installed successfully! You can now build Godot by running "scons".'
echo 'Vulkan SDK installed successfully! You can now build Godot by running "scons".'
Loading
Loading