package at.hannibal2.skyhanni.utils import net.minecraftforge.fml.common.Loader import net.minecraftforge.fml.common.ModContainer import java.lang.reflect.Constructor import java.lang.reflect.Field import java.lang.reflect.Modifier import kotlin.properties.ReadWriteProperty import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KProperty import kotlin.reflect.KProperty0 import kotlin.reflect.KProperty1 import kotlin.reflect.full.isSubtypeOf import kotlin.reflect.full.memberProperties import kotlin.reflect.full.starProjectedType import kotlin.reflect.jvm.isAccessible object ReflectionUtils { // TODO nea? // fun dynamic(block: () -> KMutableProperty0?): ReadWriteProperty { // return object : ReadWriteProperty { // override fun getValue(thisRef: Any?, property: KProperty<*>): T? { // return block()?.get() // } // // override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { // if (value != null) // block()?.set(value) // } // } // } fun dynamic(root: KProperty0, child: KMutableProperty1) = object : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): T? { val rootObj = root.get() ?: return null return child.get(rootObj) } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { if (value == null) return val rootObj = root.get() ?: return child.set(rootObj, value) } } inline fun Any.getPropertiesWithType() = this::class.memberProperties .filter { it.returnType.isSubtypeOf(T::class.starProjectedType) } .map { it.isAccessible = true (it as KProperty1).get(this) } fun Field.makeAccessible() = also { isAccessible = true } fun Constructor.makeAccessible() = also { isAccessible = true } fun Field.removeFinal(): Field { javaClass.getDeclaredField("modifiers").makeAccessible().set(this, modifiers and (Modifier.FINAL.inv())) return this } fun StackTraceElement.getClassInstance(): Class<*> { return Class.forName(this.className) } private val packageLookup by lazy { Loader.instance().modList .flatMap { mod -> mod.ownedPackages.map { it to mod } } .toMap() } val Class<*>.shPackageName get() = canonicalName?.substringBeforeLast('.') fun Class<*>.getModContainer(): ModContainer? { return packageLookup[shPackageName] } fun Class<*>.getDeclaredFieldOrNull(name: String): Field? = declaredFields.firstOrNull { it.name == name } }