Skip to content

Commit

Permalink
Fix #120 (#121)
Browse files Browse the repository at this point in the history
  • Loading branch information
modmuss50 authored Nov 1, 2023
1 parent 88fb7d5 commit efd0ff4
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 47 deletions.
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ org.gradle.jvmargs=-Xmx2G

modId=fabric-language-kotlin
modVersion=1.10.11
minecraftVersion=1.20.1
mappingsVersion=1.20.1+build.9
loaderVersion=0.14.21
minecraftVersion=1.20.2
mappingsVersion=1.20.2+build.4
loaderVersion=0.14.24
group=net.fabricmc
description=Fabric language module for Kotlin
85 changes: 41 additions & 44 deletions src/main/kotlin/net/fabricmc/language/kotlin/KotlinAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,22 @@ import net.fabricmc.loader.api.LanguageAdapter
import net.fabricmc.loader.api.LanguageAdapterException
import net.fabricmc.loader.api.ModContainer
import net.fabricmc.loader.launch.common.FabricLauncherBase
import net.fabricmc.loader.util.DefaultLanguageAdapter
import java.lang.reflect.Proxy
import kotlin.reflect.full.*
import kotlin.reflect.jvm.jvmErasure
import kotlin.reflect.jvm.reflect
import kotlin.system.exitProcess

open class KotlinAdapter : LanguageAdapter {
override fun <T : Any> create(mod: ModContainer, value: String, type: Class<T>): T {
// TODO dont use none API fabric loader
val targetClassLoader = FabricLauncherBase.getLauncher().targetClassLoader
val methodSplit = value.split("::").dropLastWhile { it.isEmpty() }.toTypedArray()
val methodSplitSize = methodSplit.size
if (methodSplitSize >= 3) {
throw LanguageAdapterException("Invalid handle format: $value")
}

val c: Class<Any> = try {
Class.forName(methodSplit[0], true, FabricLauncherBase.getLauncher().targetClassLoader) as Class<Any>
Class.forName(methodSplit[0], true, targetClassLoader) as Class<Any>
} catch (e: ClassNotFoundException) {
throw LanguageAdapterException(e)
}
Expand All @@ -58,56 +57,54 @@ open class KotlinAdapter : LanguageAdapter {
}
}
2 -> {
try {
val instance = k.objectInstance ?: run {
throw LanguageAdapterException("$k is not a object")
}
val methodList = instance::class.memberFunctions.filter { m ->
m.name == methodSplit[1]
}
val instance = k.objectInstance ?: run {
// In Kotlin 1.9.20 objectInstance can return null.
// See: https://github.com/FabricMC/fabric-language-kotlin/issues/120
return LanguageAdapter.getDefault().create(mod, value, type)
}

k.declaredMemberProperties.find {
it.name == methodSplit[1]
}?.let { field ->
try {
val fType = field.returnType
val methodList = instance::class.memberFunctions.filter { m ->
m.name == methodSplit[1]
}

if (methodList.isNotEmpty()) {
throw LanguageAdapterException("Ambiguous $value - refers to both field and method!")
}
k.declaredMemberProperties.find {
it.name == methodSplit[1]
}?.let { field ->
try {
val fType = field.returnType

if (!type.kotlin.isSuperclassOf(fType.jvmErasure)) {
throw LanguageAdapterException("Field " + value + " cannot be cast to " + type.name + "!")
}
if (methodList.isNotEmpty()) {
throw LanguageAdapterException("Ambiguous $value - refers to both field and method!")
}

return field.get(instance) as T
} catch (e: NoSuchFieldException) {
// ignore
} catch (e: IllegalAccessException) {
throw LanguageAdapterException("Field $value cannot be accessed!", e)
if (!type.kotlin.isSuperclassOf(fType.jvmErasure)) {
throw LanguageAdapterException("Field " + value + " cannot be cast to " + type.name + "!")
}
}

if (!type.isInterface) {
throw LanguageAdapterException("Cannot proxy method " + value + " to non-interface type " + type.name + "!")
return field.get(instance) as T
} catch (e: NoSuchFieldException) {
// ignore
} catch (e: IllegalAccessException) {
throw LanguageAdapterException("Field $value cannot be accessed!", e)
}
}

if (methodList.isEmpty()) {
throw LanguageAdapterException("Could not find $value!")
} else if (methodList.size >= 2) {
throw LanguageAdapterException("Found multiple method entries of name $value!")
}
if (!type.isInterface) {
throw LanguageAdapterException("Cannot proxy method " + value + " to non-interface type " + type.name + "!")
}

return Proxy.newProxyInstance(
FabricLauncherBase.getLauncher().targetClassLoader, arrayOf<Class<*>>(type)
) { proxy, method, args ->
val targetMethod = methodList[0]
targetMethod.call(instance)
} as T
} catch(e: UnsupportedOperationException) {
// TODO: detect facades without relying on exceptions
return DefaultLanguageAdapter.INSTANCE.create(mod, value, type)
if (methodList.isEmpty()) {
throw LanguageAdapterException("Could not find $value!")
} else if (methodList.size >= 2) {
throw LanguageAdapterException("Found multiple method entries of name $value!")
}

return Proxy.newProxyInstance(
targetClassLoader, arrayOf<Class<*>>(type)
) { proxy, method, args ->
val targetMethod = methodList[0]
targetMethod.call(instance)
} as T
}
else -> throw LanguageAdapterException("Invalid handle format: $value")
}
Expand Down

0 comments on commit efd0ff4

Please sign in to comment.