godot.core.Variant.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of godot-library-debug Show documentation
Show all versions of godot-library-debug Show documentation
Contains godot api as kotlin classes and jvm cpp interaction code.
package godot.core
import godot.Object
import godot.core.VariantType.AABB
import godot.core.VariantType.ANY
import godot.core.VariantType.ARRAY
import godot.core.VariantType.BASIS
import godot.core.VariantType.BOOL
import godot.core.VariantType.CALLABLE
import godot.core.VariantType.COLOR
import godot.core.VariantType.DICTIONARY
import godot.core.VariantType.DOUBLE
import godot.core.VariantType.JVM_BYTE
import godot.core.VariantType.JVM_FLOAT
import godot.core.VariantType.JVM_INT
import godot.core.VariantType.LONG
import godot.core.VariantType.NIL
import godot.core.VariantType.NODE_PATH
import godot.core.VariantType.PACKED_BYTE_ARRAY
import godot.core.VariantType.PACKED_COLOR_ARRAY
import godot.core.VariantType.PACKED_FLOAT_32_ARRAY
import godot.core.VariantType.PACKED_FLOAT_64_ARRAY
import godot.core.VariantType.PACKED_INT_32_ARRAY
import godot.core.VariantType.PACKED_INT_64_ARRAY
import godot.core.VariantType.PACKED_STRING_ARRAY
import godot.core.VariantType.PACKED_VECTOR2_ARRAY
import godot.core.VariantType.PACKED_VECTOR3_ARRAY
import godot.core.VariantType.PLANE
import godot.core.VariantType.PROJECTION
import godot.core.VariantType.QUATERNION
import godot.core.VariantType.RECT2
import godot.core.VariantType.RECT2I
import godot.core.VariantType.SIGNAL
import godot.core.VariantType.STRING
import godot.core.VariantType.STRING_NAME
import godot.core.VariantType.TRANSFORM2D
import godot.core.VariantType.TRANSFORM3D
import godot.core.VariantType.VECTOR2
import godot.core.VariantType.VECTOR2I
import godot.core.VariantType.VECTOR3
import godot.core.VariantType.VECTOR3I
import godot.core.VariantType.VECTOR4
import godot.core.VariantType.VECTOR4I
import godot.core.VariantType._RID
import godot.core.memory.MemoryManager
import godot.signals.Signal
import godot.util.toRealT
import java.nio.ByteBuffer
@PublishedApi
internal val variantMapper = mutableMapOf(
Unit::class to NIL,
Any::class to ANY,
java.lang.Object::class to ANY,
Boolean::class to BOOL,
Int::class to JVM_INT,
Long::class to LONG,
Float::class to JVM_FLOAT,
Byte::class to JVM_BYTE,
Double::class to DOUBLE,
String::class to STRING,
godot.core.AABB::class to AABB,
Basis::class to BASIS,
Color::class to COLOR,
StringName::class to STRING_NAME,
Dictionary::class to DICTIONARY,
VariantArray::class to ARRAY,
Plane::class to PLANE,
NodePath::class to NODE_PATH,
Quaternion::class to QUATERNION,
Rect2::class to RECT2,
Rect2i::class to RECT2I,
RID::class to _RID,
Transform3D::class to TRANSFORM3D,
Transform2D::class to TRANSFORM2D,
Vector2::class to VECTOR2,
Vector2i::class to VECTOR2I,
Vector3::class to VECTOR3,
Vector3i::class to VECTOR3I,
Vector4::class to VECTOR4,
Vector4i::class to VECTOR4I,
Projection::class to PROJECTION,
Callable::class to CALLABLE,
Signal::class to SIGNAL,
PackedByteArray::class to PACKED_BYTE_ARRAY,
PackedColorArray::class to PACKED_COLOR_ARRAY,
PackedInt32Array::class to PACKED_INT_32_ARRAY,
PackedInt64Array::class to PACKED_INT_64_ARRAY,
PackedFloat32Array::class to PACKED_FLOAT_32_ARRAY,
PackedFloat64Array::class to PACKED_FLOAT_64_ARRAY,
PackedStringArray::class to PACKED_STRING_ARRAY,
PackedVector2Array::class to PACKED_VECTOR2_ARRAY,
PackedVector3Array::class to PACKED_VECTOR3_ARRAY
)
private var ByteBuffer.bool: Boolean
get() = int == 1
set(value) {
putInt(if (value) 1 else 0)
}
private var ByteBuffer.vector2: Vector2
get() = Vector2(float.toRealT(), float.toRealT())
set(value) {
putFloat(value.x.toFloat())
putFloat(value.y.toFloat())
}
private var ByteBuffer.vector2i: Vector2i
get() = Vector2i(int, int)
set(value) {
putInt(value.x)
putInt(value.y)
}
private var ByteBuffer.vector3: Vector3
get() = Vector3(float.toRealT(), float.toRealT(), float.toRealT())
set(value) {
putFloat(value.x.toFloat())
putFloat(value.y.toFloat())
putFloat(value.z.toFloat())
}
private var ByteBuffer.vector3i: Vector3i
get() = Vector3i(int, int, int)
set(value) {
putInt(value.x)
putInt(value.y)
putInt(value.z)
}
private var ByteBuffer.vector4: Vector4
get() = Vector4(float.toRealT(), float.toRealT(), float.toRealT(), float.toRealT())
set(value) {
putFloat(value.x.toFloat())
putFloat(value.y.toFloat())
putFloat(value.z.toFloat())
putFloat(value.w.toFloat())
}
private var ByteBuffer.vector4i: Vector4i
get() = Vector4i(int, int, int, int)
set(value) {
putInt(value.x)
putInt(value.y)
putInt(value.z)
putInt(value.w)
}
private var ByteBuffer.basis: Basis
get() = Basis().also {
it._x = vector3
it._y = vector3
it._z = vector3
}
set(value) {
vector3 = value._x
vector3 = value._y
vector3 = value._z
}
private var ByteBuffer.stringName: Any
get() {
val ptr = long
return MemoryManager.getNativeCoreTypeInstance(ptr) ?: StringName(ptr)
}
set(value) {
STRING_NAME.toGodotNativeCoreType(this, value)
}
private var ByteBuffer.obj: KtObject
get() {
val ptr = long
val constructorIndex = int
val id = long
return MemoryManager.getInstance(id) ?: KtObject.instantiateWith(
ptr,
id,
TypeManager.engineTypesConstructors[constructorIndex],
)
}
set(value) {
putLong(value.rawPtr)
}
private var ByteBuffer.variantType: Int
get() = int
set(value) {
putInt(value)
}
inline fun Any.asObject(): T = this as T
@Suppress("EnumEntryName")
enum class VariantType(
val id: Long,
private val toKotlinWithoutNullCheck: (ByteBuffer, expectedType: Int) -> Any,
private val toGodotWithoutNullCheck: (ByteBuffer, any: Any) -> Unit,
) {
NIL(
0,
{ _: ByteBuffer, _: Int ->
Unit
},
{ buffer: ByteBuffer, _: Any ->
buffer.variantType = NIL.ordinal
}
),
// atomic types
BOOL(
1,
{ buffer: ByteBuffer, _: Int ->
buffer.bool
},
{ buffer: ByteBuffer, any: Any ->
require(any is Boolean)
buffer.variantType = BOOL.ordinal
buffer.bool = any
}
),
LONG(
2,
{ buffer: ByteBuffer, _: Int ->
buffer.long
},
{ buffer: ByteBuffer, any: Any ->
require(any is Long)
buffer.variantType = LONG.ordinal
buffer.putLong(any)
}
),
DOUBLE(
3,
{ buffer: ByteBuffer, _: Int ->
buffer.double
},
{ buffer: ByteBuffer, any: Any ->
require(any is Double)
buffer.variantType = DOUBLE.ordinal
buffer.putDouble(any)
}
),
STRING(
4,
{ buffer: ByteBuffer, _: Int ->
val isLong = buffer.bool
if (isLong) {
val str = LongStringQueue.pollString()
str
} else {
/**
* A CString is read from the buffer, they all end with a 0 character except if the String is empty
* "" has a size of 0, but "a" has a size of 2.
* We only read the buffer if the size is superior to 0.
* When it's the case, we create a string without the last 0 character.
*/
val stringSize = buffer.int
val str = if (stringSize == 0) {
String()
} else {
val charArray = ByteArray(stringSize)
buffer.get(charArray, 0, stringSize)
String(charArray, 0, stringSize - 1, Charsets.UTF_8)
}
str
}
},
{ buffer: ByteBuffer, any: Any ->
require(any is String)
buffer.variantType = STRING.ordinal
val stringBytes = any.encodeToByteArray()
//TODO: Think of a way to reuse the encoded String
if (stringBytes.size > LongStringQueue.stringMaxSize) {
buffer.bool = true
LongStringQueue.sendStringToCPP(any)
} else {
buffer.bool = false
buffer.putInt(stringBytes.size)
buffer.put(stringBytes)
}
}
),
// math types
VECTOR2(
5,
{ buffer: ByteBuffer, _: Int ->
buffer.vector2
},
{ buffer: ByteBuffer, any: Any ->
require(any is Vector2)
buffer.variantType = VECTOR2.ordinal
buffer.vector2 = any
}
),
VECTOR2I(
6,
{ buffer: ByteBuffer, _: Int ->
buffer.vector2i
},
{ buffer: ByteBuffer, any: Any ->
require(any is Vector2i)
buffer.variantType = VECTOR2I.ordinal
buffer.vector2i = any
}
),
RECT2(
7,
{ buffer: ByteBuffer, _: Int ->
Rect2(
buffer.vector2,
buffer.vector2
)
},
{ buffer: ByteBuffer, any: Any ->
require(any is Rect2)
buffer.variantType = RECT2.ordinal
buffer.vector2 = any._position
buffer.vector2 = any._size
}
),
RECT2I(
8,
{ buffer: ByteBuffer, _: Int ->
Rect2i(
buffer.vector2i,
buffer.vector2i
)
},
{ buffer: ByteBuffer, any: Any ->
require(any is Rect2i)
buffer.variantType = RECT2I.ordinal
buffer.vector2i = any._position
buffer.vector2i = any._size
}
),
VECTOR3(
9,
{ buffer: ByteBuffer, _: Int ->
buffer.vector3
},
{ buffer: ByteBuffer, any: Any ->
require(any is Vector3)
buffer.variantType = VECTOR3.ordinal
buffer.vector3 = any
}
),
VECTOR3I(
10,
{ buffer: ByteBuffer, _: Int ->
buffer.vector3i
},
{ buffer: ByteBuffer, any: Any ->
require(any is Vector3i)
buffer.variantType = VECTOR3I.ordinal
buffer.vector3i = any
}
),
TRANSFORM2D(
11,
{ buffer: ByteBuffer, _: Int ->
val x = buffer.vector2
val y = buffer.vector2
val origin = buffer.vector2
Transform2D(x, y, origin)
},
{ buffer: ByteBuffer, any: Any ->
require(any is Transform2D)
buffer.variantType = TRANSFORM2D.ordinal
buffer.vector2 = any._x
buffer.vector2 = any._y
buffer.vector2 = any.origin
}
),
VECTOR4(
12,
{ buffer: ByteBuffer, _: Int ->
buffer.vector4
},
{ buffer: ByteBuffer, any: Any ->
require(any is Vector4)
buffer.variantType = VECTOR4.ordinal
buffer.vector4 = any
}
),
VECTOR4I(
13,
{ buffer: ByteBuffer, _: Int ->
buffer.vector4i
},
{ buffer: ByteBuffer, any: Any ->
require(any is Vector4i)
buffer.variantType = VECTOR4I.ordinal
buffer.vector4i = any
}
),
PLANE(
14,
{ buffer: ByteBuffer, _: Int ->
val normal = buffer.vector3
val d = buffer.float.toRealT()
Plane(normal, d)
},
{ buffer: ByteBuffer, any: Any ->
require(any is Plane)
buffer.variantType = PLANE.ordinal
buffer.vector3 = any._normal
buffer.putFloat(any.d.toFloat())
}
),
QUATERNION(
15,
{ buffer: ByteBuffer, _: Int ->
val x = buffer.float.toRealT()
val y = buffer.float.toRealT()
val z = buffer.float.toRealT()
val w = buffer.float.toRealT()
Quaternion(x, y, z, w)
},
{ buffer: ByteBuffer, any: Any ->
require(any is Quaternion)
buffer.variantType = QUATERNION.ordinal
buffer.putFloat(any.x.toFloat())
buffer.putFloat(any.y.toFloat())
buffer.putFloat(any.z.toFloat())
buffer.putFloat(any.w.toFloat())
}
),
AABB(
16,
{ buffer: ByteBuffer, _: Int ->
val position = buffer.vector3
val size = buffer.vector3
AABB(position, size)
},
{ buffer: ByteBuffer, any: Any ->
require(any is godot.core.AABB)
buffer.variantType = AABB.ordinal
buffer.vector3 = any._position
buffer.vector3 = any._size
}
),
BASIS(
17,
{ buffer: ByteBuffer, _: Int ->
buffer.basis
},
{ buffer: ByteBuffer, any: Any ->
require(any is Basis)
buffer.variantType = BASIS.ordinal
buffer.basis = any
}
),
TRANSFORM3D(
18,
{ buffer: ByteBuffer, _: Int ->
val basis = buffer.basis
val origin = buffer.vector3
Transform3D(basis, origin)
},
{ buffer: ByteBuffer, any: Any ->
require(any is Transform3D)
buffer.variantType = TRANSFORM3D.ordinal
buffer.basis = any._basis
buffer.vector3 = any._origin
}
),
PROJECTION(
19,
{ buffer: ByteBuffer, _: Int ->
Projection(
buffer.vector4,
buffer.vector4,
buffer.vector4,
buffer.vector4
)
},
{ buffer: ByteBuffer, any: Any ->
require(any is Projection)
buffer.variantType = PROJECTION.ordinal
buffer.vector4 = any._x
buffer.vector4 = any._y
buffer.vector4 = any._z
buffer.vector4 = any._w
}
),
// misc types
COLOR(
20,
{ buffer: ByteBuffer, _: Int ->
Color(buffer.float, buffer.float, buffer.float, buffer.float)
},
{ buffer: ByteBuffer, any: Any ->
require(any is Color)
buffer.variantType = COLOR.ordinal
buffer.putFloat(any.r.toFloat())
buffer.putFloat(any.g.toFloat())
buffer.putFloat(any.b.toFloat())
buffer.putFloat(any.a.toFloat())
}
),
STRING_NAME(
21,
{ buffer: ByteBuffer, _: Int ->
buffer.stringName
},
{ buffer: ByteBuffer, any: Any ->
buffer.stringName = any
}
),
NODE_PATH(
22,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
MemoryManager.getNativeCoreTypeInstance(ptr) ?: NodePath(ptr)
},
{ buffer: ByteBuffer, any: Any ->
NODE_PATH.toGodotNativeCoreType(buffer, any)
}
),
_RID(
23,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
MemoryManager.getNativeCoreTypeInstance(ptr) ?: RID(ptr)
},
{ buffer: ByteBuffer, any: Any ->
_RID.toGodotNativeCoreType(buffer, any)
}
),
OBJECT(
24,
{ buffer: ByteBuffer, _: Int ->
buffer.obj
},
{ buffer: ByteBuffer, any: Any ->
require(any is KtObject)
buffer.variantType = OBJECT.ordinal
buffer.obj = any
}
),
CALLABLE(
25,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
MemoryManager.getNativeCoreTypeInstance(ptr) ?: Callable(ptr)
},
{ buffer: ByteBuffer, any: Any ->
CALLABLE.toGodotNativeCoreType(buffer, any)
}
),
SIGNAL(
26,
{ buffer: ByteBuffer, _: Int ->
val obj = buffer.obj
val name = buffer.stringName
require(obj is Object)
require(name is StringName)
Signal(obj, name)
},
{ buffer: ByteBuffer, any: Any ->
require(any is Signal)
buffer.obj = any.godotObject
buffer.stringName = any.name
}
),
DICTIONARY(
27,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
MemoryManager.getNativeCoreTypeInstance(ptr) ?: Dictionary(ptr)
},
{ buffer: ByteBuffer, any: Any ->
DICTIONARY.toGodotNativeCoreType>(buffer, any)
}
),
ARRAY(
28,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
MemoryManager.getNativeCoreTypeInstance(ptr) ?: VariantArray(ptr)
},
{ buffer: ByteBuffer, any: Any ->
ARRAY.toGodotNativeCoreType>(buffer, any)
}
),
// arrays
PACKED_BYTE_ARRAY(
29,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
PackedByteArray(ptr)
},
{ buffer: ByteBuffer, any: Any ->
PACKED_BYTE_ARRAY.toGodotNativeCoreType(buffer, any)
}
),
PACKED_INT_32_ARRAY(
30,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
PackedInt32Array(ptr)
},
{ buffer: ByteBuffer, any: Any ->
PACKED_INT_32_ARRAY.toGodotNativeCoreType(buffer, any)
}
),
PACKED_INT_64_ARRAY(
31,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
PackedInt64Array(ptr)
},
{ buffer: ByteBuffer, any: Any ->
PACKED_INT_64_ARRAY.toGodotNativeCoreType(buffer, any)
}
),
PACKED_FLOAT_32_ARRAY(
32,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
PackedFloat32Array(ptr)
},
{ buffer: ByteBuffer, any: Any ->
PACKED_FLOAT_32_ARRAY.toGodotNativeCoreType(buffer, any)
}
),
PACKED_FLOAT_64_ARRAY(
33,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
PackedFloat64Array(ptr)
},
{ buffer: ByteBuffer, any: Any ->
PACKED_FLOAT_64_ARRAY.toGodotNativeCoreType(buffer, any)
}
),
PACKED_STRING_ARRAY(
34,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
PackedStringArray(ptr)
},
{ buffer: ByteBuffer, any: Any ->
PACKED_STRING_ARRAY.toGodotNativeCoreType(buffer, any)
}
),
PACKED_VECTOR2_ARRAY(
35,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
PackedVector2Array(ptr)
},
{ buffer: ByteBuffer, any: Any ->
PACKED_VECTOR2_ARRAY.toGodotNativeCoreType(buffer, any)
}
),
PACKED_VECTOR3_ARRAY(
36,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
PackedVector3Array(ptr)
},
{ buffer: ByteBuffer, any: Any ->
PACKED_VECTOR3_ARRAY.toGodotNativeCoreType(buffer, any)
}
),
PACKED_COLOR_ARRAY(
37,
{ buffer: ByteBuffer, _: Int ->
val ptr = buffer.long
PackedColorArray(ptr)
},
{ buffer: ByteBuffer, any: Any ->
PACKED_COLOR_ARRAY.toGodotNativeCoreType(buffer, any)
}
),
VARIANT_MAX(
38,
{ _: ByteBuffer, _: Int ->
throw UnsupportedOperationException("Received VARIANT_MAX type, which should not happen.")
},
{ _: ByteBuffer, _: Any ->
throw UnsupportedOperationException("Try to send a VARIANT_MAX type, which should not be done.")
}
),
JVM_INT(
LONG,
{ any -> (any as Long).toInt() },
{ any ->
(any as Int).toLong()
}
),
JVM_FLOAT(
DOUBLE,
{ any -> (any as Double).toFloat() },
{ any ->
(any as Float).toDouble()
}
),
JVM_BYTE(
LONG,
{ any -> (any as Long).toByte() },
{ any ->
(any as Byte).toLong()
}
),
ANY(
ANY_VARIANT_TYPE,
{ buffer: ByteBuffer, expectedType: Int ->
entries[expectedType].toKotlinWithoutNullCheck(buffer, expectedType)
},
{ buffer: ByteBuffer, any: Any ->
val type = variantMapper[any::class] ?: throw UnsupportedOperationException("Can't convert type ${any::class} to Variant")
type.toGodotWithoutNullCheck(buffer, any)
}
);
var baseOrdinal = ordinal
constructor(
originalVariantType: VariantType,
toKotlinConverter: (Any) -> Any,
toGodotConverter: (Any) -> Any
) : this(
originalVariantType.id,
{ buffer: ByteBuffer, expectedType: Int ->
toKotlinConverter(originalVariantType.toKotlinWithoutNullCheck(buffer, expectedType))
},
{ buffer: ByteBuffer, any: Any -> originalVariantType.toGodotWithoutNullCheck(buffer, toGodotConverter(any)) }
) {
baseOrdinal = originalVariantType.ordinal
}
internal val toGodot = { buffer: ByteBuffer, any: Any? ->
if (any == null) {
NIL.toGodotWithoutNullCheck(buffer, Unit)
} else {
toGodotWithoutNullCheck(buffer, any)
}
}
internal val toKotlin = this.getToKotlinLambdaToExecute(toKotlinWithoutNullCheck)
companion object {
fun from(value: Long) = entries[value.toInt()]
}
}
internal fun VariantType.getToKotlinLambdaToExecute(defaultLambda: (ByteBuffer, Int) -> Any?): (ByteBuffer, Boolean) -> Any? {
return if (this.id == ANY_VARIANT_TYPE) {
{ buffer: ByteBuffer, isNullable: Boolean ->
val variantType = buffer.variantType
if (variantType == NIL.ordinal) {
if (!isNullable) throw TypeCastException("Expected a non nullable ${this.name} but received a null.")
null
} else defaultLambda(buffer, variantType)
}
} else {
{ buffer: ByteBuffer, isNullable: Boolean ->
when (val variantType = buffer.variantType) {
baseOrdinal -> {
defaultLambda(buffer, variantType)
}
NIL.ordinal -> {
if (!isNullable) throw TypeCastException("Expected a non nullable ${this.name} but received a null.")
null
}
else -> throw TypeCastException("Cannot match $variantType to ${this.baseOrdinal}")
}
}
}
}
private inline fun VariantType.toGodotNativeCoreType(buffer: ByteBuffer, any: Any) {
require(any is T)
buffer.variantType = ordinal
buffer.putLong(any._handle)
}
private const val ANY_VARIANT_TYPE = Long.MAX_VALUE
© 2015 - 2024 Weber Informatics LLC | Privacy Policy