diff --git a/build.gradle.kts b/build.gradle.kts index 5f08c3c..5d25e7d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,6 +52,16 @@ dependencies { implementation("maven.modrinth:fuuu3xnx:bvFby61J") // https://modrinth.com/mod/controlling/versions?l=fabric implementation("maven.modrinth:xv94TkTM:rAp2jljs") +// https://modrinth.com/mod/notenoughcrashes/versions?l=fabric + implementation("maven.modrinth:yM94ont6:3oHxOFPT") +// https://modrinth.com/mod/scoreboard-overhaul/versions + implementation("maven.modrinth:2YIQkF2v:HI1qkixZ") +// https://modrinth.com/plugin/plasmo-voice/versions?l=fabric + implementation("maven.modrinth:1bZhdhsH:I0T9OQcy") +// https://modrinth.com/mod/first-person-model/versions?l=fabric + implementation("maven.modrinth:H5XMjpHi:6sgz2HEq") +// https://modrinth.com/mod/entityculling/versions?l=fabric + implementation("maven.modrinth:NNAgCjsB:iiF6U3Ne") } tasks.processResources { diff --git a/gradle.properties b/gradle.properties index c4078fb..abe0b38 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ loom_version=1.17-SNAPSHOT fabric_kotlin_version=1.13.13+kotlin.2.4.10 # Mod Properties -version=1.0.0 +version=1.1.0 group=xyz.thewhitedog9487 OutputFileBasename=WhoProvideThisKeybind diff --git a/src/client/java/xyz/thewhitedog9487/client/mixin/KeyMappingMixin.java b/src/client/java/xyz/thewhitedog9487/client/mixin/KeyMappingMixin.java new file mode 100644 index 0000000..a0e6631 --- /dev/null +++ b/src/client/java/xyz/thewhitedog9487/client/mixin/KeyMappingMixin.java @@ -0,0 +1,57 @@ +package xyz.thewhitedog9487.client.mixin; + +import com.mojang.blaze3d.platform.InputConstants; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.client.KeyMapping; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.include.com.google.common.io.Files; +import xyz.thewhitedog9487.client.MiscellaneousKt; +import xyz.thewhitedog9487.client.ModInfo; +import xyz.thewhitedog9487.client.WhoProvideThisKeybindModClient; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Optional; +import java.util.function.Function; + +@Mixin(KeyMapping.class) +public class KeyMappingMixin { + @Inject(method = "(Ljava/lang/String;Lcom/mojang/blaze3d/platform/InputConstants$Type;ILnet/minecraft/client/KeyMapping$Category;I)V", + at = @At("TAIL")) + void DiscoverStackTrace(String name, InputConstants.Type type, int value, KeyMapping.Category category, int order, CallbackInfo ci) throws IOException, ClassNotFoundException { + var StackTraceCLassNames = Arrays.stream(Thread.currentThread().getStackTrace()) + .map(StackTraceElement::getClassName) + .toList(); + for (String ClassName : StackTraceCLassNames) { + if (IsFrameworkClass(ClassName)) continue; + for (String PartOfClassName : ClassName.split("\\.")) { + Optional CandidateModContainer = FabricLoader.getInstance().getModContainer(PartOfClassName); + if (CandidateModContainer.isPresent() && CandidateModContainer.get() != MiscellaneousKt.getVanillaMinecraftContainer()) { + var ModInfo = new ModInfo(CandidateModContainer.get()); + MiscellaneousKt.getKeyMappingToMod().put((KeyMapping) (Object) this, ModInfo); + return; } } } } + + @Unique + boolean IsFrameworkClass(@NotNull String ClassName) { + return ClassName.startsWith("java.") + || ClassName.startsWith("jdk.") + || ClassName.startsWith("sun.") + || ClassName.startsWith("com.sun.") + || ClassName.startsWith("kotlin.") + || ClassName.startsWith("net.minecraft") + || ClassName.startsWith("net.fabricmc") + || ClassName.startsWith("org.spongepowered.") + + // ↓ 第三方Mod兼容条目 + || ClassName.startsWith("dev.tr7zw.transition"); } } diff --git a/src/client/kotlin/xyz/thewhitedog9487/client/Miscellaneous.kt b/src/client/kotlin/xyz/thewhitedog9487/client/Miscellaneous.kt index 6ab8857..ac42f84 100644 --- a/src/client/kotlin/xyz/thewhitedog9487/client/Miscellaneous.kt +++ b/src/client/kotlin/xyz/thewhitedog9487/client/Miscellaneous.kt @@ -7,17 +7,22 @@ import net.minecraft.client.KeyMapping import net.minecraft.client.gui.components.Button import net.minecraft.client.gui.components.Tooltip import net.minecraft.network.chat.Component +import kotlin.io.path.pathString val VanillaMinecraftContainer: ModContainer = FabricLoader .getInstance() .getModContainer("minecraft") .get() +val KeyMappingToMod: HashMap = HashMap() + val KeyMapping.Provider: ModInfo get() { + if (SettingsInstance.SearchInStackTrace) { + KeyMappingToMod[this]?.let { return it } } + val KeyBindTranslationKey = name val CandidateModIds = KeyBindTranslationKey.split(".") if (CandidateModIds.size == 1){ - WhoProvideThisKeybindModClient.ClientLogger.warn("这是个什么东西,按键绑定ID只有一个部分,ID: $KeyBindTranslationKey") return ModInfo(null) } for (CandidateModId in CandidateModIds) { val ModContainer = FabricLoader.getInstance().getModContainer(CandidateModId) diff --git a/src/client/kotlin/xyz/thewhitedog9487/client/ModMenuEntryPoint.kt b/src/client/kotlin/xyz/thewhitedog9487/client/ModMenuEntryPoint.kt index ba4bf9c..7fa0835 100644 --- a/src/client/kotlin/xyz/thewhitedog9487/client/ModMenuEntryPoint.kt +++ b/src/client/kotlin/xyz/thewhitedog9487/client/ModMenuEntryPoint.kt @@ -44,6 +44,13 @@ class ModMenuEntryPoint: ModMenuApi { .binding( false, { SettingsInstance.ShowDebugInfo }, { SettingsInstance.ShowDebugInfo = it } ) .controller(BooleanControllerBuilder::create ) .build() } + .option { + Option.createBuilder() + .name(Component.translatable("option.SearchInStackTrace")) + .description { OptionDescription.of(Component.translatable("option.SearchInStackTrace.description") ) } + .binding( false, { SettingsInstance.SearchInStackTrace }, { SettingsInstance.SearchInStackTrace = it } ) + .controller(BooleanControllerBuilder::create ) + .build() } .build() } .build() .generateScreen(ParentScreen) } } \ No newline at end of file diff --git a/src/client/kotlin/xyz/thewhitedog9487/client/Settings.kt b/src/client/kotlin/xyz/thewhitedog9487/client/Settings.kt index fd43a44..6187b38 100644 --- a/src/client/kotlin/xyz/thewhitedog9487/client/Settings.kt +++ b/src/client/kotlin/xyz/thewhitedog9487/client/Settings.kt @@ -57,7 +57,26 @@ class Settings { 取值范围:true false 默认值:false """) - var ShowDebugInfo = false } + var ShowDebugInfo = false + + @SerialEntry(comment = + """ + 是否注入KeyMapping构造函数,在每次注册按键绑定时查询线程的调用栈信息来进行强力匹配 + 警告:在部分情况下可能产生更多误报,请按需选择 + 类型:布尔值 + 取值范围:true false + 默认值:false + """) + var SearchInStackTrace = false + + @SerialEntry(comment = + """ + 是否在悬停信息中显示Mod的文件路径 + 类型:布尔值 + 取值范围:true false + 默认值:false + """) + var ShowFilePath = false } var SettingsHandler: ConfigClassHandler? = null diff --git a/src/client/resources/whoprovidethiskeybind.client.mixins.json b/src/client/resources/whoprovidethiskeybind.client.mixins.json index 7be9397..fe667a4 100644 --- a/src/client/resources/whoprovidethiskeybind.client.mixins.json +++ b/src/client/resources/whoprovidethiskeybind.client.mixins.json @@ -3,7 +3,8 @@ "package": "xyz.thewhitedog9487.client.mixin", "compatibilityLevel": "JAVA_25", "client": [ - "KeyBindsListKeyEntryMixin" + "KeyBindsListKeyEntryMixin", + "KeyMappingMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/assets/whoprovidethiskeybind/lang/en_us.json b/src/main/resources/assets/whoprovidethiskeybind/lang/en_us.json index 42b36ca..16c6695 100644 --- a/src/main/resources/assets/whoprovidethiskeybind/lang/en_us.json +++ b/src/main/resources/assets/whoprovidethiskeybind/lang/en_us.json @@ -13,8 +13,11 @@ "option.ShowKeybindID.description": "Display the keybind's own ID in the tooltip", "option.ShowDebugInfo": "Show Debug Info", "option.ShowDebugInfo.description": "This information is used to troubleshoot issues related to this mod; it generally does not need to be enabled", + "option.SearchInStackTrace": "Enable aggressive search via stack trace lookup", + "option.SearchInStackTrace.description": "Injects into the KeyMapping class constructor and queries the current thread's call stack each time a keybind is registered for aggressive matching\nWarning: In some cases, this may produce more false positives; enable as needed", "tooltip.provided_by": "Provided by: %s", "tooltip.provider_mod_id": "Provider Mod ID: %s", "tooltip.key_id": "Keybind ID: %s", - "special_provider_UNKNOWN": "Unknown" + "tooltip.mod_file_path": "Mod File Path: %s", + "special_string_UNKNOWN": "Unknown" } diff --git a/src/main/resources/assets/whoprovidethiskeybind/lang/zh_cn.json b/src/main/resources/assets/whoprovidethiskeybind/lang/zh_cn.json index bbbb0b6..ffa3977 100644 --- a/src/main/resources/assets/whoprovidethiskeybind/lang/zh_cn.json +++ b/src/main/resources/assets/whoprovidethiskeybind/lang/zh_cn.json @@ -13,8 +13,11 @@ "option.ShowKeybindID.description": "在提示信息中显示该按键本身的ID", "option.ShowDebugInfo": "是否显示调试信息", "option.ShowDebugInfo.description": "这些信息用于出现和本Mod相关的问题时进行排查,一般情况下不需要开启", + "option.SearchInStackTrace": "是否要通过查询堆栈信息来进行强力搜索", + "option.SearchInStackTrace.description": "注入KeyMapping类的构造函数,在每次注册按键绑定时查询线程的调用栈信息来进行强力匹配\n警告:部分情况下可能产生更多误报,请按需选择", "tooltip.provided_by": "提供者:%s", "tooltip.provider_mod_id": "提供者ID:%s", "tooltip.key_id": "键位ID:%s", - "special_provider_UNKNOWN": "未知" + "tooltip.mod_file_path": "Mod文件路径:%s", + "special_string_UNKNOWN": "未知" } \ No newline at end of file