All Downloads are FREE. Search and download functionalities are using the official Maven repository.

godot.runtime.Registration.kt Maven / Gradle / Ivy

There is a newer version: 0.2.0-3.3.2
Show newest version
package godot.runtime

import godot.core.*
import godot.util.camelToSnakeCase
import kotlin.reflect.*

class KtPropertyInfoBuilderDsl {
    var type: VariantType? = null
    var name: String = ""
    var className: String? = null
    var hint: PropertyHint = PropertyHint.NONE
    var hintString: String = ""
    var rpcModeId: Int = 0

    internal fun build() = KtPropertyInfo(checkNotNull(type), name, checkNotNull(className), hint, hintString, rpcModeId)
}

data class KtFunctionArgument(
    val type: VariantType,
    val className: String,
    val name: String = "" //empty for return type
) {
    internal fun toKtPropertyInfo() = KtPropertyInfo(
        type,
        name,
        className,
        PropertyHint.NONE,
        "", //always empty. Only used for properties
    0 // always RPCMode.DISABLED. Only used for properties
    )
}


class ClassBuilderDsl(
    @PublishedApi internal val name: String,
    private val registeredName: String,
    private val superClass: String,
    private val baseGodotClass: String
) {
    private val constructors = mutableMapOf>()

    private val functions = mutableMapOf>()

    @PublishedApi
    internal val properties = mutableMapOf>()

    private val signals = mutableMapOf()

    fun constructor(constructor: KtConstructor) {
        require(!constructors.containsKey(constructor.parameterCount)) {
            "A constructor with ${constructor.parameterCount} argument(s) already exists."
        }
        require(constructor.parameterCount <= CONSTRUCTOR_MAX_ARGS) {
            "Cannot register a constructor with ${constructor.parameterCount} arguments, max argument count is $CONSTRUCTOR_MAX_ARGS"
        }
        constructors[constructor.parameterCount] = constructor
    }

    fun 

property( kProperty: KMutableProperty1, variantType: VariantType, type: VariantType, className: String, hint: PropertyHint = PropertyHint.NONE, hintString: String = "", defaultArgument: P?, rpcModeId: Int = 0, isRef: Boolean = false ) { val propertyName = kProperty.name.camelToSnakeCase() require(!properties.contains(propertyName)) { "Found two properties with name $propertyName for class $name" } properties[propertyName] = KtProperty( KtPropertyInfo( type, propertyName, className, hint, hintString, rpcModeId ), kProperty, variantType, defaultArgument, isRef ) } inline fun > enumProperty( kProperty: KMutableProperty1, defaultValue: P, rpcModeId: Int = 0 ) { val propertyName = kProperty.name.camelToSnakeCase() require(!properties.contains(propertyName)) { "Found two properties with name $propertyName for class $name" } properties[propertyName] = KtEnumProperty( KtPropertyInfo( VariantType.LONG, propertyName, "Int", PropertyHint.ENUM, enumValues

().joinToString { it.name }, rpcModeId ), kProperty, //TODO change when nullable enum are here. defaultValue, { enum: P? -> enum?.ordinal ?: 1 }, { i -> enumValues

()[i] } ) } //TODO: uncomment and fixup once collections are supported in KtVariant // inline fun > enumListProperty( // kProperty: KMutableProperty1> // ) { // val propertyName = kProperty.name.camelToSnakeCase() // require(!properties.contains(propertyName)) { // "Found two properties with name $propertyName for class $name" // } // // properties[propertyName] = KtProperty( // KtPropertyInfo( // VariantType.LONG, // propertyName, // "Int", // PropertyHint.ENUM, // "2/3:${enumValues

().joinToString(",") { it.name }}" //2 = VariantType.LONG.ordinal | 3 = PropertyHint.ENUM.ordinal // ), // kProperty, // { enumList -> // KtVariant(enumList.map { it.ordinal } as Collection) // }, // { ktVariant -> enumValues

()[ktVariant.asInt()] } // ) // } @JvmName("enumFlagPropertyMutable") inline fun > enumFlagProperty( kProperty: KMutableProperty1>, defaultValue: MutableSet

, rpcModeId: Int ) = enumFlagProperty(kProperty as KMutableProperty1>, defaultValue, rpcModeId) inline fun > enumFlagProperty( kProperty: KMutableProperty1>, defaultValue: Set

, rpcModeId: Int ) { val propertyName = kProperty.name.camelToSnakeCase() require(!properties.contains(propertyName)) { "Found two properties with name $propertyName for class $name" } properties[propertyName] = KtEnumProperty( KtPropertyInfo( VariantType.LONG, propertyName, "Int", PropertyHint.FLAGS, enumValues

().joinToString { it.name }, rpcModeId ), kProperty, //TODO : Change when null default values are supported defaultValue, { enumSet -> var intFlag = 0 enumSet?.forEach { enum -> intFlag += 1 shl enum.ordinal } intFlag }, { value -> val intFlag = (value as P).ordinal val enums = mutableSetOf

() var bit = 1 for (i in 0 until Int.SIZE_BITS) { if ((intFlag and bit) > 0) { val element = enumValues

().firstOrNull { it.ordinal == i } if (element != null) { enums.add(element) } } bit = bit shl 1 if (bit > intFlag) break } enums } ) } fun property( kProperty: KMutableProperty1, variantType: VariantType, setValueConverter: ((Any?) -> P), isRef: Boolean = false, defaultArgument: P, rpcModeId: Int = 0, pib: KtPropertyInfoBuilderDsl.() -> Unit ) { val builder = KtPropertyInfoBuilderDsl() builder.name = kProperty.name.camelToSnakeCase() builder.rpcModeId = rpcModeId builder.pib() val property = builder.build() require(!properties.contains(property.name)) { "Found two properties with name ${property.name} for class $name" } properties[property.name] = KtProperty(property, kProperty, variantType, defaultArgument, isRef) } fun function( func: KFunction1, variantType: VariantType, returnType: KtFunctionArgument, rpcModeId: Int = 0 ) { appendFunction( KtFunction0( KtFunctionInfo( func.name.camelToSnakeCase(), listOf(), KtPropertyInfo( returnType.type, "", returnType.className, PropertyHint.NONE, "", 0 // always RPCMode.DISABLED. Only used for properties ), rpcModeId ), func, variantType ) ) } fun function( func: KFunction1, variantType: VariantType, returns: KtPropertyInfoBuilderDsl.() -> Unit, rpcModeId: Int = 0 ) { val returnBuilder = KtPropertyInfoBuilderDsl() returnBuilder.returns() appendFunction( KtFunction0( KtFunctionInfo(func.name.camelToSnakeCase(), listOf(), returnBuilder.build(), rpcModeId), func, variantType ) ) } fun function( func: KFunction2, variantType: VariantType, p0Type: Pair, p0: KtFunctionArgument, returnType: KtFunctionArgument, rpcModeId: Int = 0 ) { appendFunction( KtFunction1( KtFunctionInfo( func.name.camelToSnakeCase(), listOf( p0.toKtPropertyInfo() ), returnType.toKtPropertyInfo(), rpcModeId ), func, variantType, p0Type ) ) } fun function( func: KFunction2, variantType: VariantType, p0Type: Pair, arg: KtPropertyInfoBuilderDsl.() -> Unit, returns: KtPropertyInfoBuilderDsl.() -> Unit, rpcModeId: Int = 0 ) { val (arguments, returnType) = argumentsAndReturnType(returns, arg) appendFunction( KtFunction1( KtFunctionInfo(func.name.camelToSnakeCase(), arguments, returnType, rpcModeId), func, variantType, p0Type ) ) } fun function( func: KFunction3, variantType: VariantType, p0Type: Pair, p1Type: Pair, p0: KtFunctionArgument, p1: KtFunctionArgument, returnType: KtFunctionArgument, rpcModeId: Int = 0 ) { appendFunction( KtFunction2( KtFunctionInfo( func.name.camelToSnakeCase(), listOf( p0.toKtPropertyInfo(), p1.toKtPropertyInfo(), ), returnType.toKtPropertyInfo(), rpcModeId ), func, variantType, p0Type, p1Type ) ) } fun function( func: KFunction3, variantType: VariantType, p0Type: Pair, p1Type: Pair, args: Array Unit>, returns: KtPropertyInfoBuilderDsl.() -> Unit, rpcModeId: Int = 0 ) { val (arguments, returnType) = argumentsAndReturnType(returns, *args) require(args.size == 2) { "Function ${func.name.camelToSnakeCase()} should have 2 arguments, found ${args.size}" } appendFunction( KtFunction2( KtFunctionInfo(func.name.camelToSnakeCase(), arguments, returnType, rpcModeId), func, variantType, p0Type, p1Type ) ) } fun function( func: KFunction4, variantType: VariantType, p0Type: Pair, p1Type: Pair, p2Type: Pair, p0: KtFunctionArgument, p1: KtFunctionArgument, p2: KtFunctionArgument, returnType: KtFunctionArgument, rpcModeId: Int = 0 ) { appendFunction( KtFunction3( KtFunctionInfo( func.name.camelToSnakeCase(), listOf( p0.toKtPropertyInfo(), p1.toKtPropertyInfo(), p2.toKtPropertyInfo(), ), returnType.toKtPropertyInfo(), rpcModeId ), func, variantType, p0Type, p1Type, p2Type ) ) } fun function( func: KFunction4, variantType: VariantType, p0Type: Pair, p1Type: Pair, p2Type: Pair, args: Array Unit>, returns: KtPropertyInfoBuilderDsl.() -> Unit, rpcModeId: Int = 0 ) { val (arguments, returnType) = argumentsAndReturnType(returns, *args) require(args.size == 3) { "Function ${func.name.camelToSnakeCase()} should have 3 arguments, found ${args.size}" } appendFunction( KtFunction3( KtFunctionInfo(func.name.camelToSnakeCase(), arguments, returnType, rpcModeId), func, variantType, p0Type, p1Type, p2Type ) ) } fun function( func: KFunction5, variantType: VariantType, p0Type: Pair, p1Type: Pair, p2Type: Pair, p3Type: Pair, p0: KtFunctionArgument, p1: KtFunctionArgument, p2: KtFunctionArgument, p3: KtFunctionArgument, returnType: KtFunctionArgument, rpcModeId: Int = 0 ) { appendFunction( KtFunction4( KtFunctionInfo( func.name.camelToSnakeCase(), listOf( p0.toKtPropertyInfo(), p1.toKtPropertyInfo(), p2.toKtPropertyInfo(), p3.toKtPropertyInfo(), ), returnType.toKtPropertyInfo(), rpcModeId ), func, variantType, p0Type, p1Type, p2Type, p3Type ) ) } fun function( func: KFunction5, variantType: VariantType, p0Type: Pair, p1Type: Pair, p2Type: Pair, p3Type: Pair, args: Array Unit>, returns: KtPropertyInfoBuilderDsl.() -> Unit, rpcModeId: Int = 0 ) { val (arguments, returnType) = argumentsAndReturnType(returns, *args) require(args.size == 4) { "Function ${func.name.camelToSnakeCase()} should have 4 arguments, found ${args.size}" } appendFunction( KtFunction4( KtFunctionInfo(func.name.camelToSnakeCase(), arguments, returnType, rpcModeId), func, variantType, p0Type, p1Type, p2Type, p3Type ) ) } fun function( func: KFunction6, variantType: VariantType, p0Type: Pair, p1Type: Pair, p2Type: Pair, p3Type: Pair, p4Type: Pair, p0: KtFunctionArgument, p1: KtFunctionArgument, p2: KtFunctionArgument, p3: KtFunctionArgument, p4: KtFunctionArgument, returnType: KtFunctionArgument, rpcModeId: Int = 0 ) { appendFunction( KtFunction5( KtFunctionInfo( func.name.camelToSnakeCase(), listOf( p0.toKtPropertyInfo(), p1.toKtPropertyInfo(), p2.toKtPropertyInfo(), p3.toKtPropertyInfo(), p4.toKtPropertyInfo() ), returnType.toKtPropertyInfo(), rpcModeId ), func, variantType, p0Type, p1Type, p2Type, p3Type, p4Type ) ) } fun function( func: KFunction6, variantType: VariantType, p0Type: Pair, p1Type: Pair, p2Type: Pair, p3Type: Pair, p4Type: Pair, args: Array Unit>, returns: KtPropertyInfoBuilderDsl.() -> Unit, rpcModeId: Int = 0 ) { val (arguments, returnType) = argumentsAndReturnType(returns, *args) require(args.size == 5) { "Function ${func.name.camelToSnakeCase()} should have 5 arguments, found ${args.size}" } appendFunction( KtFunction5( KtFunctionInfo(func.name.camelToSnakeCase(), arguments, returnType, rpcModeId), func, variantType, p0Type, p1Type, p2Type, p3Type, p4Type ) ) } fun signal(kProperty: KProperty) { appendSignal( KtSignalInfo(kProperty.name.removePrefix("signal").camelToSnakeCase(), listOf()) ) } fun signal( kProperty: KProperty, p0: KtFunctionArgument ) { appendSignal( KtSignalInfo( kProperty.name.removePrefix("signal").camelToSnakeCase(), listOf( p0.toKtPropertyInfo() ) ) ) } fun signal( kProperty: KProperty, p0: KtFunctionArgument, p1: KtFunctionArgument ) { appendSignal( KtSignalInfo( kProperty.name.removePrefix("signal").camelToSnakeCase(), listOf( p0.toKtPropertyInfo(), p1.toKtPropertyInfo() ) ) ) } fun signal( kProperty: KProperty, p0: KtFunctionArgument, p1: KtFunctionArgument, p2: KtFunctionArgument ) { appendSignal( KtSignalInfo( kProperty.name.removePrefix("signal").camelToSnakeCase(), listOf( p0.toKtPropertyInfo(), p1.toKtPropertyInfo(), p2.toKtPropertyInfo() ) ) ) } fun signal( kProperty: KProperty, p0: KtFunctionArgument, p1: KtFunctionArgument, p2: KtFunctionArgument, p3: KtFunctionArgument ) { appendSignal( KtSignalInfo( kProperty.name.removePrefix("signal").camelToSnakeCase(), listOf( p0.toKtPropertyInfo(), p1.toKtPropertyInfo(), p2.toKtPropertyInfo(), p3.toKtPropertyInfo() ) ) ) } fun signal( kProperty: KProperty, p0: KtFunctionArgument, p1: KtFunctionArgument, p2: KtFunctionArgument, p3: KtFunctionArgument, p4: KtFunctionArgument ) { appendSignal( KtSignalInfo( kProperty.name.removePrefix("signal").camelToSnakeCase(), listOf( p0.toKtPropertyInfo(), p1.toKtPropertyInfo(), p2.toKtPropertyInfo(), p3.toKtPropertyInfo(), p4.toKtPropertyInfo() ) ) ) } fun signal(kProperty: KProperty, args: Array Unit> = arrayOf()) { appendSignal( KtSignalInfo(kProperty.name.removePrefix("signal").camelToSnakeCase(), args.applyArgumentsDsl()) ) } private fun argumentsAndReturnType( returns: KtPropertyInfoBuilderDsl.() -> Unit, vararg args: KtPropertyInfoBuilderDsl.() -> Unit ): Pair, KtPropertyInfo> { val returnBuilder = KtPropertyInfoBuilderDsl() returnBuilder.returns() val returnInfo = returnBuilder.build() return args.applyArgumentsDsl() to returnInfo } private fun appendFunction(function: KtFunction) { require(!functions.containsKey(function.functionInfo.name)) { "A method with ${function.functionInfo.name} already exists." } functions[function.functionInfo.name] = function } @PublishedApi internal fun appendSignal(signalInfo: KtSignalInfo) { require(!signals.containsKey(signalInfo.name)) { "A signal with ${signalInfo.name} already exists." } signals[signalInfo.name] = signalInfo } internal fun build(): KtClass { check(constructors.isNotEmpty()) { "Please provide at least one constructor." } // CONSTRUCTOR_MAX_ARGS + 1 because we have no arg constructor. val constructorArray = arrayOfNulls>(CONSTRUCTOR_MAX_ARGS + 1) constructors.forEach { constructorArray[it.key] = it.value } return KtClass(name, registeredName, superClass, constructorArray, properties, functions, signals, baseGodotClass) } @PublishedApi internal fun Array Unit>.applyArgumentsDsl(): List { val argumentsCheckList = mutableSetOf() return map { val builder = KtPropertyInfoBuilderDsl() builder.it() val propertyInfo = builder.build() require(!argumentsCheckList.contains(propertyInfo.name)) { "Cannot have two arguments with name ${propertyInfo.name}" } require(propertyInfo.name.isNotEmpty()) { "Function parameters should have names." } argumentsCheckList.add(propertyInfo.name) propertyInfo } } } class ClassRegistry { val classes = mutableListOf>() fun registerClass( resPath: String, superClass: String, kClass: KClass, isTool: Boolean = false, baseGodotClass: String, registeredName: String = resPath.replace('.', '_'), cb: ClassBuilderDsl.() -> Unit ) { val builder = ClassBuilderDsl(resPath, registeredName, superClass, baseGodotClass) builder.cb() TypeManager.registerUserType(resPath, kClass) registerClass(builder.build()) } private fun registerClass(cls: KtClass) { classes.add(cls) } } interface ClassRegistrar { fun register(registry: ClassRegistry) }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy