fix: migration side effects
This commit is contained in:
@@ -1501,7 +1501,8 @@ class BulkMessagingAction : AbstractAction() {
|
||||
val addFriendMethodName = addFriend14Method.get() ?: return@runCatching context.log.error("Could not find add friend method name")
|
||||
val sourceTypeClass = sourceType.getAsClass() ?: return@runCatching context.log.error("Could not find source type class")
|
||||
val pageTypeClass = pageType.getAsClass() ?: return@runCatching context.log.error("Could not find page type class")
|
||||
val method = f9lClass.declaredMethods.firstOrNull { it.name == addFriendMethodName }
|
||||
val method = f9lClass.methods.firstOrNull { it.name == addFriendMethodName }
|
||||
?: f9lClass.declaredMethods.firstOrNull { it.name == addFriendMethodName }
|
||||
?: return@runCatching context.log.error("Could not find $addFriendMethodName method")
|
||||
fun findStaticField(clazz: Class<*>): Any? = clazz.findStaticObjectFieldByType(clazz)
|
||||
val enumClass = method.parameterTypes[2]
|
||||
|
||||
@@ -99,7 +99,8 @@ class ManageFriendList : AbstractAction() {
|
||||
val sourceTypeClass = sourceType.getAsClass() ?: return@runCatching context.log.error("Could not find source type class")
|
||||
val pageTypeClass = pageType.getAsClass() ?: return@runCatching context.log.error("Could not find page type class")
|
||||
|
||||
val method = f9lClass.declaredMethods.firstOrNull { it.name == addFriendMethodName }
|
||||
val method = f9lClass.methods.firstOrNull { it.name == addFriendMethodName }
|
||||
?: f9lClass.declaredMethods.firstOrNull { it.name == addFriendMethodName }
|
||||
?: return@runCatching context.log.error("Could not find $addFriendMethodName method")
|
||||
|
||||
// Helper function to find static field by trying fallback
|
||||
|
||||
@@ -530,11 +530,14 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
}
|
||||
|
||||
val operaLayerList = (param.thisObject() as Any).getObjectField(layerListField.get()!!) as ArrayList<*>
|
||||
val mediaParamMap: ParamMap = operaLayerList.map { Layer(it) }.first().paramMap
|
||||
|
||||
if (!mediaParamMap.containsKey("image_media_info") && !mediaParamMap.containsKey("video_media_info_list")) {
|
||||
return@onOperaViewStateCallback
|
||||
}
|
||||
val mediaParamMap: ParamMap = operaLayerList
|
||||
.asSequence()
|
||||
.mapNotNull { layerObj ->
|
||||
layerObj?.let { runCatching { Layer(it).paramMap }.getOrNull() }
|
||||
}
|
||||
.firstOrNull {
|
||||
it.containsKey("image_media_info") || it.containsKey("video_media_info_list")
|
||||
} ?: return@onOperaViewStateCallback
|
||||
|
||||
val mediaInfoMap = mutableMapOf<SplitMediaAssetType, MediaInfo>()
|
||||
val isVideo = mediaParamMap.containsKey("video_media_info_list")
|
||||
|
||||
@@ -89,7 +89,15 @@ class MessageSender(
|
||||
}
|
||||
|
||||
private fun internalSendMessage(conversations: List<SnapUUID>, localMessageContentTemplate: String, callback: Any) {
|
||||
val sendMessageWithContentMethod = context.classCache.conversationManager.declaredMethods.first { it.name == "sendMessageWithContent" }
|
||||
val sendMessageWithContentMethod = sequence {
|
||||
var current: Class<*>? = context.classCache.conversationManager
|
||||
while (current != null && current != Any::class.java && current != Object::class.java) {
|
||||
yield(current)
|
||||
current = current.superclass
|
||||
}
|
||||
}.flatMap { clazz -> clazz.declaredMethods.asSequence() }
|
||||
.firstOrNull { it.name == "sendMessageWithContent" }
|
||||
?: throw NoSuchMethodException("sendMessageWithContent")
|
||||
|
||||
val localMessageContent = context.gson.fromJson(localMessageContentTemplate, context.classCache.localMessageContent)
|
||||
val messageDestinations = MessageDestinations(AbstractWrapper.newEmptyInstance(context.classCache.messageDestinations)).also {
|
||||
|
||||
@@ -98,11 +98,13 @@ class CoreScriptHooker: AbstractBinding("hooker", BindingSide.CORE) {
|
||||
}
|
||||
|
||||
fun findMethod(clazz: Class<*>, methodName: String): Member? {
|
||||
return clazz.declaredMethods.find { it.name == methodName }
|
||||
return collectMethods(clazz).firstOrNull { it.name == methodName }
|
||||
}
|
||||
|
||||
fun findMethodWithParameters(clazz: Class<*>, methodName: String, vararg types: String): Member? {
|
||||
return clazz.declaredMethods.find { method -> method.name == methodName && method.parameterTypes.map { it.name }.toTypedArray() contentEquals types }
|
||||
return collectMethods(clazz).firstOrNull { method ->
|
||||
method.name == methodName && method.parameterTypes.map { it.name }.toTypedArray() contentEquals types
|
||||
}
|
||||
}
|
||||
|
||||
fun findMethod(className: String, methodName: String): Member? {
|
||||
@@ -159,10 +161,45 @@ class CoreScriptHooker: AbstractBinding("hooker", BindingSide.CORE) {
|
||||
fun hookAllConstructors(className: String, stage: String, callback: HookCallback)
|
||||
= findClassSafe(className)?.let { hookAllConstructors(it, stage, callback) }
|
||||
|
||||
private fun collectMethods(clazz: Class<*>): List<Method> {
|
||||
val methods = LinkedHashMap<String, Method>()
|
||||
val visited = HashSet<Class<*>>()
|
||||
var currentClass: Class<*>? = clazz
|
||||
|
||||
while (currentClass != null && currentClass != Any::class.java && currentClass != Object::class.java) {
|
||||
collectMethodsRecursive(currentClass, methods, visited)
|
||||
currentClass = currentClass.superclass
|
||||
}
|
||||
|
||||
return methods.values.toList()
|
||||
}
|
||||
|
||||
private fun collectMethodsRecursive(
|
||||
clazz: Class<*>,
|
||||
methods: MutableMap<String, Method>,
|
||||
visited: MutableSet<Class<*>>
|
||||
) {
|
||||
if (!visited.add(clazz)) return
|
||||
|
||||
clazz.declaredMethods.forEach { method ->
|
||||
val signature = buildString {
|
||||
append(method.name)
|
||||
append("#")
|
||||
method.parameterTypes.forEach {
|
||||
append(it.name)
|
||||
append(";")
|
||||
}
|
||||
}
|
||||
methods.putIfAbsent(signature, method)
|
||||
}
|
||||
|
||||
clazz.interfaces.forEach { collectMethodsRecursive(it, methods, visited) }
|
||||
}
|
||||
|
||||
override fun onDispose() {
|
||||
hooks.forEach { it() }
|
||||
hooks.clear()
|
||||
}
|
||||
|
||||
override fun getObject() = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,9 +46,8 @@ object Hooker {
|
||||
stage: HookStage,
|
||||
crossinline filter: (HookAdapter) -> Boolean,
|
||||
noinline consumer: (HookAdapter) -> Unit
|
||||
): Set<HookHandle> = clazz.declaredMethods
|
||||
): Set<HookHandle> = collectMethods(clazz, methodName)
|
||||
.asSequence()
|
||||
.filter { it.name == methodName }
|
||||
.map { method ->
|
||||
method.isAccessible = true
|
||||
val hookResult = YukiHookCompat.hookMember(method, newMethodHook(stage, consumer, filter))
|
||||
@@ -167,6 +166,46 @@ object Hooker {
|
||||
unhooks.forEach{ it.unhook() }
|
||||
}.also { unhooks.addAll(it) }
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun collectMethods(clazz: Class<*>, methodName: String): List<Method> {
|
||||
val methods = LinkedHashMap<String, Method>()
|
||||
val visited = HashSet<Class<*>>()
|
||||
var currentClass: Class<*>? = clazz
|
||||
|
||||
while (currentClass != null && currentClass != Any::class.java && currentClass != Object::class.java) {
|
||||
collectMethodsRecursive(currentClass, methodName, methods, visited)
|
||||
currentClass = currentClass.superclass
|
||||
}
|
||||
|
||||
return methods.values.toList()
|
||||
}
|
||||
|
||||
private fun collectMethodsRecursive(
|
||||
clazz: Class<*>,
|
||||
methodName: String,
|
||||
methods: MutableMap<String, Method>,
|
||||
visited: MutableSet<Class<*>>
|
||||
) {
|
||||
if (!visited.add(clazz)) return
|
||||
|
||||
clazz.declaredMethods
|
||||
.asSequence()
|
||||
.filter { it.name == methodName }
|
||||
.forEach { method ->
|
||||
val signature = buildString {
|
||||
append(method.name)
|
||||
append("#")
|
||||
method.parameterTypes.forEach {
|
||||
append(it.name)
|
||||
append(";")
|
||||
}
|
||||
}
|
||||
methods.putIfAbsent(signature, method)
|
||||
}
|
||||
|
||||
clazz.interfaces.forEach { collectMethodsRecursive(it, methodName, methods, visited) }
|
||||
}
|
||||
}
|
||||
|
||||
fun Class<*>.hookConstructor(
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package me.eternal.purrfectsnap.core.util.ktx
|
||||
|
||||
fun Any.getObjectField(fieldName: String): Any? {
|
||||
return KavaRefFieldBridge.getField(this, fieldName)
|
||||
return runCatching {
|
||||
KavaRefFieldBridge.getField(this, fieldName)
|
||||
}.getOrElse {
|
||||
findFieldRecursive(this::class.java, fieldName).also { it.isAccessible = true }.get(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun Any.findFieldNamesByType(type: Class<*>): List<String> {
|
||||
@@ -13,7 +17,11 @@ fun Any.allFieldNames(): List<String> {
|
||||
}
|
||||
|
||||
fun Class<*>.getStaticObjectField(fieldName: String): Any? {
|
||||
return KavaRefFieldBridge.getStaticField(this, fieldName)
|
||||
return runCatching {
|
||||
KavaRefFieldBridge.getStaticField(this, fieldName)
|
||||
}.getOrElse {
|
||||
findFieldRecursive(this, fieldName).also { it.isAccessible = true }.get(null)
|
||||
}
|
||||
}
|
||||
|
||||
fun Class<*>.findStaticObjectFieldByType(type: Class<*>): Any? {
|
||||
@@ -21,14 +29,22 @@ fun Class<*>.findStaticObjectFieldByType(type: Class<*>): Any? {
|
||||
}
|
||||
|
||||
fun Any.setEnumField(fieldName: String, value: String) {
|
||||
val enumType = KavaRefFieldBridge.getFieldType(this, fieldName)
|
||||
val enumType = runCatching {
|
||||
KavaRefFieldBridge.getFieldType(this, fieldName)
|
||||
}.getOrElse {
|
||||
findFieldRecursive(this::class.java, fieldName).type
|
||||
}
|
||||
enumType.enumConstants?.firstOrNull { it.toString() == value }?.let { enum ->
|
||||
setObjectField(fieldName, enum)
|
||||
}
|
||||
}
|
||||
|
||||
fun Any.setObjectField(fieldName: String, value: Any?) {
|
||||
KavaRefFieldBridge.setField(this, fieldName, value)
|
||||
runCatching {
|
||||
KavaRefFieldBridge.setField(this, fieldName, value)
|
||||
}.getOrElse {
|
||||
findFieldRecursive(this::class.java, fieldName).also { f -> f.isAccessible = true }.set(this, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun Any.getObjectFieldOrNull(fieldName: String): Any? {
|
||||
@@ -39,3 +55,12 @@ fun Any.getObjectFieldOrNull(fieldName: String): Any? {
|
||||
}
|
||||
}
|
||||
|
||||
private fun findFieldRecursive(clazz: Class<*>, fieldName: String): java.lang.reflect.Field {
|
||||
var current: Class<*>? = clazz
|
||||
while (current != null && current != Any::class.java && current != Object::class.java) {
|
||||
runCatching { return current.getDeclaredField(fieldName) }
|
||||
current = current.superclass
|
||||
}
|
||||
throw NoSuchFieldException("${clazz.name}#$fieldName")
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,15 @@ class ConversationManager(
|
||||
val context: ModContext,
|
||||
obj: Any
|
||||
) : AbstractWrapper(obj) {
|
||||
private fun findMethodByName(name: String) = context.classCache.conversationManager.declaredMethods.find { it.name == name } ?: throw RuntimeException("Could not find method $name")
|
||||
private fun findMethodByName(name: String) = sequence {
|
||||
var current: Class<*>? = context.classCache.conversationManager
|
||||
while (current != null && current != Any::class.java && current != Object::class.java) {
|
||||
yield(current)
|
||||
current = current.superclass
|
||||
}
|
||||
}.flatMap { clazz -> clazz.declaredMethods.asSequence() }
|
||||
.firstOrNull { it.name == name }
|
||||
?: throw RuntimeException("Could not find method $name")
|
||||
|
||||
private val updateMessageMethod by lazy { findMethodByName("updateMessage") }
|
||||
private val fetchConversationWithMessagesPaginatedMethod by lazy { findMethodByName("fetchConversationWithMessagesPaginated") }
|
||||
@@ -204,4 +212,4 @@ class ConversationManager(
|
||||
.override("onError") { onError(it.arg<Any>(0).toString()) }.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user