mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-06-12 13:17:42 +02:00
refactor: config override (#169)
* refactor: config override * perf: mapper * revert(hooker): inline method - hookAll methods * feat: no friend score delay --------- Co-authored-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
@ -0,0 +1,55 @@
|
||||
package me.rhunk.snapmapper.impl
|
||||
|
||||
import me.rhunk.snapmapper.AbstractClassMapper
|
||||
import me.rhunk.snapmapper.MapperContext
|
||||
import me.rhunk.snapmapper.ext.findConstString
|
||||
import me.rhunk.snapmapper.ext.getClassName
|
||||
import me.rhunk.snapmapper.ext.hasStaticConstructorString
|
||||
import me.rhunk.snapmapper.ext.isEnum
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
class CompositeConfigurationProviderMapper : AbstractClassMapper() {
|
||||
override fun run(context: MapperContext) {
|
||||
for (classDef in context.classes) {
|
||||
val constructor = classDef.methods.firstOrNull { it.name == "<init>" } ?: continue
|
||||
if (constructor.parameterTypes.size == 0 || constructor.parameterTypes[0] != "Ljava/util/List;") continue
|
||||
if (constructor.implementation?.findConstString("CompositeConfigurationProvider") != true) continue
|
||||
|
||||
val getPropertyMethod = classDef.methods.first { method ->
|
||||
method.parameterTypes.size > 1 &&
|
||||
method.returnType == "Ljava/lang/Object;" &&
|
||||
context.getClass(method.parameterTypes[0])?.interfaces?.contains("Ljava/io/Serializable;") == true &&
|
||||
context.getClass(method.parameterTypes[1])?.let { it.isEnum() && it.hasStaticConstructorString("BOOLEAN") } == true
|
||||
}
|
||||
|
||||
val configEnumInterface = context.getClass(getPropertyMethod.parameterTypes[0])!!
|
||||
val enumType = context.getClass(getPropertyMethod.parameterTypes[1])!!
|
||||
|
||||
val observePropertyMethod = classDef.methods.first {
|
||||
it.parameterTypes.size > 2 &&
|
||||
it.parameterTypes[0] == configEnumInterface.type &&
|
||||
it.parameterTypes[1] == "Ljava/lang/String;" &&
|
||||
it.parameterTypes[2] == enumType.type
|
||||
}
|
||||
|
||||
val enumGetDefaultValueMethod = configEnumInterface.methods.first { context.getClass(it.returnType)?.interfaces?.contains("Ljava/io/Serializable;") == true }
|
||||
val defaultValueField = context.getClass(enumGetDefaultValueMethod.returnType)!!.fields.first {
|
||||
Modifier.isFinal(it.accessFlags) &&
|
||||
Modifier.isPublic(it.accessFlags) &&
|
||||
it.type == "Ljava/lang/Object;"
|
||||
}
|
||||
|
||||
context.addMapping("CompositeConfigurationProvider",
|
||||
"class" to classDef.getClassName(),
|
||||
"observeProperty" to observePropertyMethod.name,
|
||||
"getProperty" to getPropertyMethod.name,
|
||||
"enum" to mapOf(
|
||||
"class" to configEnumInterface.getClassName(),
|
||||
"getValue" to enumGetDefaultValueMethod.name,
|
||||
"defaultValueField" to defaultValueField.name
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ class DefaultMediaItemMapper : AbstractClassMapper() {
|
||||
if (constructorParameters.size < 6 || constructorParameters[5] != "J") continue
|
||||
|
||||
context.addMapping("DefaultMediaItem", clazz.type.replace("L", "").replace(";", ""))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -14,59 +14,17 @@ import org.jf.dexlib2.iface.reference.StringReference
|
||||
|
||||
class EnumMapper : AbstractClassMapper() {
|
||||
override fun run(context: MapperContext) {
|
||||
var enumQualityLevel : String? = null
|
||||
val enums = mutableListOf<Pair<String, String>>()
|
||||
lateinit var enumQualityLevel : String
|
||||
|
||||
for (enumClass in context.classes) {
|
||||
if (!enumClass.isEnum()) continue
|
||||
|
||||
if (enumQualityLevel == null && enumClass.hasStaticConstructorString("LEVEL_MAX")) {
|
||||
if (enumClass.hasStaticConstructorString("LEVEL_MAX")) {
|
||||
enumQualityLevel = enumClass.getClassName()
|
||||
}
|
||||
|
||||
if (enumClass.interfaces.isEmpty()) continue
|
||||
|
||||
//check if it's a config enum
|
||||
val serializableInterfaceClass = context.getClass(enumClass.interfaces.first()) ?: continue
|
||||
if (serializableInterfaceClass.methods.none {it.name == "getName" && it.returnType == "Ljava/lang/String;" }) continue
|
||||
|
||||
//find the method which returns the enum name
|
||||
val getEnumMethod = enumClass.virtualMethods.firstOrNull { context.getClass(it.returnType)?.isEnum() == true } ?: continue
|
||||
|
||||
//search for constant field instruction sget-object
|
||||
|
||||
fun getFirstFieldReference21c(opcode: Opcode, method: Method) = method.implementation!!.instructions.firstOrNull {
|
||||
it.opcode == opcode && it is Instruction21c
|
||||
}.let { it as? Instruction21c }?.let {
|
||||
it.reference as? FieldReference
|
||||
}
|
||||
|
||||
val fieldReference = getFirstFieldReference21c(Opcode.SGET_OBJECT, getEnumMethod) ?:
|
||||
getFirstFieldReference21c(Opcode.SGET_OBJECT,enumClass.directMethods.first { it.name == "<init>" }) ?: continue
|
||||
|
||||
//search field name in the <clinit> class
|
||||
val enumClassListEnum = context.getClass(fieldReference.definingClass) ?: continue
|
||||
|
||||
enumClassListEnum.getStaticConstructor()?.let { constructor ->
|
||||
var lastEnumClassName = ""
|
||||
constructor.implementation!!.instructions.forEach {
|
||||
if (it.opcode == Opcode.CONST_STRING) {
|
||||
lastEnumClassName = ((it as Instruction21c).reference as StringReference).string
|
||||
return@forEach
|
||||
}
|
||||
|
||||
if (it.opcode == Opcode.SPUT_OBJECT && it is Instruction21c) {
|
||||
val field = it.reference as? FieldReference ?: return@forEach
|
||||
if (field.name != fieldReference.name || field.type != fieldReference.type) return@forEach
|
||||
|
||||
enums.add(lastEnumClassName to enumClass.getClassName())
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
context.addMapping("EnumQualityLevel", enumQualityLevel!!)
|
||||
|
||||
context.addMapping("enums", *enums.sortedBy { it.first }.toTypedArray())
|
||||
context.addMapping("EnumQualityLevel", enumQualityLevel)
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ class FriendsFeedEventDispatcherMapper : AbstractClassMapper() {
|
||||
"class" to clazz.getClassName(),
|
||||
"viewModelField" to viewModelField
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ class MediaQualityLevelProviderMapper : AbstractClassMapper(EnumMapper::class) {
|
||||
"class" to clazz.type.replace("L", "").replace(";", ""),
|
||||
"method" to it.name
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ class PlatformAnalyticsCreatorMapper : AbstractClassMapper() {
|
||||
if (firstParameterClass.getStaticConstructor()?.implementation?.findConstString("IN_APP_NOTIFICATION") != true) continue
|
||||
|
||||
context.addMapping("PlatformAnalyticsCreator", clazz.type.replace("L", "").replace(";", ""))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ class ScCameraSettingsMapper : AbstractClassMapper() {
|
||||
if (!firstParameter.isEnum() || firstParameter.getStaticConstructor()?.implementation?.findConstString("CONTINUOUS_PICTURE") != true) continue
|
||||
|
||||
context.addMapping("ScCameraSettings", clazz.type.replace("L", "").replace(";", ""))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package me.rhunk.snapmapper.impl
|
||||
|
||||
import me.rhunk.snapmapper.AbstractClassMapper
|
||||
import me.rhunk.snapmapper.MapperContext
|
||||
import me.rhunk.snapmapper.ext.findConstString
|
||||
import me.rhunk.snapmapper.ext.getClassName
|
||||
|
||||
class ScoreUpdateMapper : AbstractClassMapper() {
|
||||
override fun run(context: MapperContext) {
|
||||
for (classDef in context.classes) {
|
||||
classDef.methods.firstOrNull {
|
||||
it.name == "<init>" &&
|
||||
it.parameterTypes.size > 4 &&
|
||||
it.parameterTypes[1] == "Ljava/lang/Long;" &&
|
||||
it.parameterTypes[3] == "Ljava/util/Collection;"
|
||||
} ?: continue
|
||||
if (classDef.methods.firstOrNull {
|
||||
it.name == "toString"
|
||||
}?.implementation?.findConstString("Friend.sq:selectFriendUserScoresNeedToUpdate") != true) continue
|
||||
|
||||
context.addMapping("ScoreUpdate", classDef.getClassName())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ class StoryBoostStateMapper : AbstractClassMapper() {
|
||||
if (storyBoostEnumClass.getStaticConstructor()?.implementation?.findConstString("NeedSubscriptionCannotSubscribe") != true) continue
|
||||
|
||||
context.addMapping("StoryBoostStateClass", clazz.type.replace("L", "").replace(";", ""))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -21,7 +21,9 @@ class TestMappings {
|
||||
PlusSubscriptionMapper::class,
|
||||
ScCameraSettingsMapper::class,
|
||||
StoryBoostStateMapper::class,
|
||||
FriendsFeedEventDispatcherMapper::class
|
||||
FriendsFeedEventDispatcherMapper::class,
|
||||
CompositeConfigurationProviderMapper::class,
|
||||
ScoreUpdateMapper::class,
|
||||
)
|
||||
|
||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
||||
|
Reference in New Issue
Block a user