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
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import godot.codegen.generation.task.EnrichedClassTask
import godot.codegen.generation.task.FileTask
import godot.codegen.models.traits.GenerationType
import godot.codegen.models.ApiType
import godot.codegen.models.EnumValue
import godot.codegen.models.enriched.EnrichedClass
import godot.codegen.models.enriched.EnrichedMethod
import godot.codegen.models.enriched.EnrichedNativeStructure
Expand All @@ -25,6 +26,42 @@ import godot.tools.common.constants.GodotKotlinJvmTypes
import godot.tools.common.constants.GodotTypes
import godot.tools.common.constants.TO_GODOT_NAME_UTIL_FUNCTION

class UseConnectFlagRule : GodotApiRule<ApiTask>() {
override fun apply(task: ApiTask, context: GenerationContext) {
val objectClassIndex = context.api.classes.indexOfFirst { it.name == GodotKotlinJvmTypes.obj }
val objectRawClass = context.api.classes[objectClassIndex]

val connectEnumIndex = objectRawClass.enums!!.indexOfFirst { it.name == "ConnectFlags" }
val connectRawEnum = objectRawClass.enums[connectEnumIndex]

val newValues = listOf(
EnumValue(
"DEFAULT",
0,
"Default connections that are immediately emitted"
)
) + connectRawEnum.values
val newEnum = connectRawEnum.copy(values = newValues)

val enumList = objectRawClass.enums.toMutableList()
enumList[connectEnumIndex] = newEnum

val connectMethodIndex = objectRawClass.methods!!.indexOfFirst { it.name == "connect" }
val connectMethod = objectRawClass.methods[connectMethodIndex]

val flagArgumentIndex = connectMethod.arguments!!.indexOfFirst { it.name == "flags" }
val flagArgument = connectMethod.arguments[flagArgumentIndex]

val newArgument = flagArgument.copy(type="enum::Object.ConnectFlags", meta = null)
val newMethod = connectMethod.copy(arguments = connectMethod.arguments.dropLast(1) + newArgument)
val newMethodList = objectRawClass.methods.toMutableList()
newMethodList[connectMethodIndex] = newMethod

val newClass = objectRawClass.copy(enums = enumList, methods = newMethodList)
context.api.classes[objectClassIndex] = newClass
}
}

class EnrichedCoreRule : GodotApiRule<ApiTask>() {
override fun apply(task: ApiTask, context: GenerationContext) {
val coreTypes = context.api.builtinClasses.associate { it.name to (it.enums?.toEnriched(GenerationType(it.name)) ?: listOf()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import godot.codegen.models.ApiDescription
import godot.codegen.services.IApiGenerationService
import godot.codegen.services.impl.ApiGenerationService
import godot.codegen.services.impl.AwaitGenerationService
import godot.codegen.services.impl.LambdaCallableGenerationService
import godot.codegen.services.impl.ConnectorGenerationService
import godot.codegen.services.impl.CallableGenerationService
import godot.codegen.services.impl.SignalGenerationService
import java.io.File

Expand All @@ -15,12 +16,9 @@ fun generateApiFrom(jsonSource: File, coreDir: File, apiDir: File) {
val generationService: IApiGenerationService = ApiGenerationService(apiDescription)
generationService.generateApi(coreDir, apiDir)

LambdaCallableGenerationService.generate(coreDir)
SignalGenerationService.generateCore(coreDir)
}

fun generateExtension(outputDir: File) {
SignalGenerationService.generateExtension(outputDir)
SignalGenerationService.generate(coreDir)
CallableGenerationService.generate(coreDir)
ConnectorGenerationService.generate(coreDir)
}

fun generateCoroutine(outputDir: File) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

data class ApiDescription @JsonCreator constructor(
@JsonProperty("header") val header: Header,
@JsonProperty("builtin_class_sizes") val builtinClassSizes: List<BuiltinClassSizes>,
@JsonProperty("builtin_class_member_offsets") val builtinClassMemberOffsets: List<BuiltinClassMemberOffsets>,
@JsonProperty("global_constants") val globalConstants: List<Constant>,
@JsonProperty("global_enums") val globalEnums: List<Enum>,
@JsonProperty("utility_functions") val utilityFunctions: List<UtilityFunction>,
@JsonProperty("builtin_classes") val builtinClasses: List<BuiltinClass>,
@JsonProperty("classes") val classes: List<Class>,
@JsonProperty("singletons") val singletons: List<Singleton>,
@JsonProperty("native_structures") val nativeStructures: List<NativeStructure>
@JsonProperty("header") var header: Header,
@JsonProperty("builtin_class_sizes") var builtinClassSizes: MutableList<BuiltinClassSizes>,
@JsonProperty("builtin_class_member_offsets") var builtinClassMemberOffsets: MutableList<BuiltinClassMemberOffsets>,
@JsonProperty("global_constants") var globalConstants: MutableList<Constant>,
@JsonProperty("global_enums") var globalEnums: MutableList<Enum>,
@JsonProperty("utility_functions") var utilityFunctions: MutableList<UtilityFunction>,
@JsonProperty("builtin_classes") val builtinClasses: MutableList<BuiltinClass>,
@JsonProperty("classes") var classes: MutableList<Class>,
@JsonProperty("singletons") var singletons: MutableList<Singleton>,
@JsonProperty("native_structures") var nativeStructures: MutableList<NativeStructure>
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import com.squareup.kotlinpoet.STRING
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.UNIT
import godot.tools.common.constants.GODOT_ARRAY
import godot.tools.common.constants.GODOT_CALLABLE_BASE
import godot.tools.common.constants.GODOT_CALLABLE
import godot.tools.common.constants.GODOT_DICTIONARY
import godot.tools.common.constants.GodotTypes
import godot.tools.common.constants.VARIANT_CASTER_ANY
Expand Down Expand Up @@ -113,7 +113,7 @@ fun ClassName.Companion.from(type: TypeGenerationTrait) = when {
type.identifier == GodotTypes.float -> DOUBLE
type.identifier == GodotTypes.string -> STRING
type.identifier == GodotTypes.variant -> ANY
type.identifier == GodotTypes.callable -> GODOT_CALLABLE_BASE
type.identifier == GodotTypes.callable -> GODOT_CALLABLE
type.identifier == GodotTypes.array || type.isTypedArray() -> GODOT_ARRAY
type.identifier == GodotTypes.dictionary -> GODOT_DICTIONARY
type.isCoreType() -> ClassName(godotCorePackage, type.identifier)
Expand Down
Loading
Loading