6 Commits

8 changed files with 67 additions and 69 deletions
+3
View File
@@ -38,3 +38,6 @@ hs_err_*.log
replay_*.log replay_*.log
*.hprof *.hprof
*.jfr *.jfr
# kotlin
.kotlin
+1 -1
View File
@@ -14,7 +14,7 @@ loom_version=1.17-SNAPSHOT
fabric_kotlin_version=1.13.13+kotlin.2.4.10 fabric_kotlin_version=1.13.13+kotlin.2.4.10
# Mod Properties # Mod Properties
version=1.1.0 version=1.2.0
group=xyz.thewhitedog9487 group=xyz.thewhitedog9487
OutputFileBasename=WhoProvideThisKeybind OutputFileBasename=WhoProvideThisKeybind
@@ -42,7 +42,4 @@ public class KeyMappingMixin {
|| ClassName.startsWith("kotlin.") || ClassName.startsWith("kotlin.")
|| ClassName.startsWith("net.minecraft") || ClassName.startsWith("net.minecraft")
|| ClassName.startsWith("net.fabricmc") || ClassName.startsWith("net.fabricmc")
|| ClassName.startsWith("org.spongepowered.") || ClassName.startsWith("org.spongepowered."); } }
// ↓ 第三方Mod兼容条目
|| ClassName.startsWith("dev.tr7zw.transition"); } }
@@ -17,25 +17,28 @@ val VanillaMinecraftContainer: ModContainer = FabricLoader
val KeyMappingToMod: HashMap<KeyMapping, ModInfo> = HashMap() val KeyMappingToMod: HashMap<KeyMapping, ModInfo> = HashMap()
val KeyMapping.Provider: ModInfo get() { val KeyMapping.Provider: ModInfo get() {
if (SettingsInstance.SearchInStackTrace) {
KeyMappingToMod[this]?.let { return it } }
val KeyBindTranslationKey = name val KeyBindTranslationKey = name
val CandidateModIds = KeyBindTranslationKey.split(".") val CandidateModIds = KeyBindTranslationKey.split(".")
if (CandidateModIds.size == 1){
return ModInfo(null) }
for (CandidateModId in CandidateModIds) { for (CandidateModId in CandidateModIds) {
val ModContainer = FabricLoader.getInstance().getModContainer(CandidateModId) val ModContainer = FabricLoader.getInstance().getModContainer(CandidateModId)
if (ModContainer.isPresent) { if (ModContainer.isPresent) {
return ModContainer.map(::ModInfo).get() } } return ModContainer.map(::ModInfo).get() } }
KeyMappingToMod[this]?.let { return it }
if (CandidateModIds.size == 1){
return ModInfo(null) }
return ModInfo(VanillaMinecraftContainer) } return ModInfo(VanillaMinecraftContainer) }
data class ModInfo(val ModContainerInstance: ModContainer?) { data class ModInfo(val ModContainerInstance: ModContainer?) {
val ID: String = ModContainerInstance?.metadata?.id ?: Component.translatable("special_provider_UNKNOWN").string val ID: String = ModContainerInstance?.metadata?.id ?: Component.translatable("special_string_UNKNOWN").string
val MetaData: ModMetadata? = ModContainerInstance?.metadata val MetaData: ModMetadata? = ModContainerInstance?.metadata
val DisplayName: String = MetaData?.name ?: Component.translatable("special_provider_UNKNOWN").string val DisplayName: String = MetaData?.name ?: Component.translatable("special_string_UNKNOWN").string
val HumanFriendlyName: Component = Component.translatableWithFallback("modmenu.nameTranslation." + (MetaData?.id ?: "unknown"), DisplayName) val HumanFriendlyName: Component = Component.translatableWithFallback("modmenu.nameTranslation." + (MetaData?.id ?: "unknown"), DisplayName)
val FilePath: String = ModContainerInstance?.origin?.paths?.joinToString("\n") { it.pathString } ?: Component.translatable("special_string_UNKNOWN").string } val FilePath: String get() {
val ModOrigin = ModContainerInstance?.origin
return try {
ModOrigin?.paths?.joinToString("\n") { it.pathString } ?: Component.translatable("special_string_UNKNOWN").string }
catch (_: UnsupportedOperationException) {
Component.translatable("special_string_UNKNOWN").string } } }
fun Button.SetNewTooltip(Key: KeyMapping) { fun Button.SetNewTooltip(Key: KeyMapping) {
if (SettingsInstance.ModEnabled == false) return if (SettingsInstance.ModEnabled == false) return
@@ -18,46 +18,47 @@ class ModMenuEntryPoint: ModMenuApi {
.name(Component.translatable("config.category.general")) .name(Component.translatable("config.category.general"))
.option { .option {
Option.createBuilder<Boolean>() Option.createBuilder<Boolean>()
.name(Component.translatable("option.ModEnabled")) .name(Component.translatable("option.general.ModEnabled"))
.description { OptionDescription.of(Component.translatable("option.ModEnabled.description") ) } .description { OptionDescription.of(Component.translatable("option.general.ModEnabled.description") ) }
.binding( true, { SettingsInstance.ModEnabled }, { SettingsInstance.ModEnabled = it } ) .binding( true, { SettingsInstance.ModEnabled }, { SettingsInstance.ModEnabled = it } )
.controller(BooleanControllerBuilder::create ) .controller(BooleanControllerBuilder::create )
.build() } .build() }
.build() }
.category {
ConfigCategory.createBuilder()
.name(Component.translatable("config.category.feature"))
.option { .option {
Option.createBuilder<Boolean>() Option.createBuilder<Boolean>()
.name(Component.translatable("option.ShowModID")) .name(Component.translatable("option.feature.ShowModID"))
.description { OptionDescription.of(Component.translatable("option.ShowModID.description") ) } .description { OptionDescription.of(Component.translatable("option.feature.ShowModID.description") ) }
.binding( false, { SettingsInstance.ShowModID }, { SettingsInstance.ShowModID = it } ) .binding( false, { SettingsInstance.ShowModID }, { SettingsInstance.ShowModID = it } )
.controller(BooleanControllerBuilder::create ) .controller(BooleanControllerBuilder::create )
.build() } .build() }
.option { .option {
Option.createBuilder<Boolean>() Option.createBuilder<Boolean>()
.name(Component.translatable("option.ShowKeybindID")) .name(Component.translatable("option.feature.ShowKeybindID"))
.description { OptionDescription.of(Component.translatable("option.ShowKeybindID.description") ) } .description { OptionDescription.of(Component.translatable("option.feature.ShowKeybindID.description") ) }
.binding( false, { SettingsInstance.ShowKeybindID }, { SettingsInstance.ShowKeybindID = it } ) .binding( false, { SettingsInstance.ShowKeybindID }, { SettingsInstance.ShowKeybindID = it } )
.controller(BooleanControllerBuilder::create ) .controller(BooleanControllerBuilder::create )
.build() } .build() }
.option { .option {
Option.createBuilder<Boolean>() Option.createBuilder<Boolean>()
.name(Component.translatable("option.ShowDebugInfo")) .name(Component.translatable("option.feature.ShowFilePath"))
.description { OptionDescription.of(Component.translatable("option.ShowDebugInfo.description") ) } .description { OptionDescription.of(Component.translatable("option.feature.ShowFilePath.description") ) }
.binding( false, { SettingsInstance.ShowDebugInfo }, { SettingsInstance.ShowDebugInfo = it } )
.controller(BooleanControllerBuilder::create )
.build() }
.option {
Option.createBuilder<Boolean>()
.name(Component.translatable("option.SearchInStackTrace"))
.description { OptionDescription.of(Component.translatable("option.SearchInStackTrace.description") ) }
.binding( false, { SettingsInstance.SearchInStackTrace }, { SettingsInstance.SearchInStackTrace = it } )
.controller(BooleanControllerBuilder::create )
.build() }
.option {
Option.createBuilder<Boolean>()
.name(Component.translatable("option.ShowFilePath"))
.description { OptionDescription.of(Component.translatable("option.ShowFilePath.description") ) }
.binding( false, { SettingsInstance.ShowFilePath }, { SettingsInstance.ShowFilePath = it } ) .binding( false, { SettingsInstance.ShowFilePath }, { SettingsInstance.ShowFilePath = it } )
.controller(BooleanControllerBuilder::create ) .controller(BooleanControllerBuilder::create )
.build() } .build() }
.build() } .build() }
.category {
ConfigCategory.createBuilder()
.name(Component.translatable("config.category.debug"))
.option {
Option.createBuilder<Boolean>()
.name(Component.translatable("option.debug.ShowDebugInfo"))
.description { OptionDescription.of(Component.translatable("option.debug.ShowDebugInfo.description") ) }
.binding( false, { SettingsInstance.ShowDebugInfo }, { SettingsInstance.ShowDebugInfo = it } )
.controller(BooleanControllerBuilder::create )
.build() }
.build() }
.build() .build()
.generateScreen(ParentScreen) } } .generateScreen(ParentScreen) } }
@@ -9,6 +9,10 @@ import java.nio.file.Path
import java.nio.file.StandardWatchEventKinds import java.nio.file.StandardWatchEventKinds
const val CurrentConfigurationVersionCode: Long = 0 const val CurrentConfigurationVersionCode: Long = 0
/**
* @see ModMenuEntryPoint\
*/
class Settings { class Settings {
@SerialEntry(comment = @SerialEntry(comment =
""" """
@@ -58,16 +62,6 @@ class Settings {
""") """)
var ShowDebugInfo = false var ShowDebugInfo = false
@SerialEntry(comment =
"""
是否注入KeyMapping构造函数,在每次注册按键绑定时查询线程的调用栈信息来进行强力匹配
警告:在部分情况下可能产生更多误报,请按需选择
类型:布尔值
取值范围:true false
默认值:false
""")
var SearchInStackTrace = false
@SerialEntry(comment = @SerialEntry(comment =
""" """
是否在悬停信息中显示Mod的文件路径 是否在悬停信息中显示Mod的文件路径
@@ -5,18 +5,18 @@
"link.blog": "TheWhiteDog9487's Blog", "link.blog": "TheWhiteDog9487's Blog",
"title.config": "Who Provides This Keybind?", "title.config": "Who Provides This Keybind?",
"config.category.general": "General", "config.category.general": "General",
"option.ModEnabled": "Enable Mod Functionality", "config.category.feature": "Feature",
"option.ModEnabled.description": "Changes take effect immediately after modification and save without restarting the game", "config.category.debug": "Debug",
"option.ShowModID": "Show Mod ID", "option.general.ModEnabled": "Enable Mod Functionality",
"option.ShowModID.description": "Display the Mod ID of the provider in the tooltip", "option.general.ModEnabled.description": "Changes take effect immediately after modification and save without restarting the game",
"option.ShowKeybindID": "Show Keybind ID", "option.feature.ShowModID": "Show Mod ID",
"option.ShowKeybindID.description": "Display the keybind's own ID in the tooltip", "option.feature.ShowModID.description": "Display the Mod ID of the provider in the tooltip",
"option.ShowDebugInfo": "Show Debug Info", "option.feature.ShowKeybindID": "Show Keybind ID",
"option.ShowDebugInfo.description": "This information is used to troubleshoot issues related to this mod; it generally does not need to be enabled", "option.feature.ShowKeybindID.description": "Display the keybind's own ID in the tooltip",
"option.ShowFilePath": "Show File Path", "option.feature.ShowFilePath": "Show File Path",
"option.ShowFilePath.description": "Display the mod file path in the information", "option.feature.ShowFilePath.description": "Display the mod file path in the information",
"option.SearchInStackTrace": "Enable aggressive search via stack trace lookup", "option.debug.ShowDebugInfo": "Show Debug Info",
"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", "option.debug.ShowDebugInfo.description": "This information is used to troubleshoot issues related to this mod; it generally does not need to be enabled",
"tooltip.provided_by": "Provided by: %s", "tooltip.provided_by": "Provided by: %s",
"tooltip.provider_mod_id": "Provider Mod ID: %s", "tooltip.provider_mod_id": "Provider Mod ID: %s",
"tooltip.key_id": "Keybind ID: %s", "tooltip.key_id": "Keybind ID: %s",
@@ -5,18 +5,18 @@
"link.blog": "TheWhiteDog9487的博客", "link.blog": "TheWhiteDog9487的博客",
"title.config": "谁在提供这个键位?", "title.config": "谁在提供这个键位?",
"config.category.general": "通用", "config.category.general": "通用",
"option.ModEnabled": "是否启用模组功能", "config.category.feature": "功能",
"option.ModEnabled.description": "无需重启游戏,修改并保存后立刻生效", "config.category.debug": "调试",
"option.ShowModID": "是否显示Mod ID", "option.general.ModEnabled": "是否启用模组功能",
"option.ShowModID.description": "在提示信息中显示提供该按键的Mod的ID", "option.general.ModEnabled.description": "无需重启游戏,修改并保存后立刻生效",
"option.ShowKeybindID": "是否显示键位ID", "option.feature.ShowModID": "是否显示Mod ID",
"option.ShowKeybindID.description": "在提示信息中显示该按键本身的ID", "option.feature.ShowModID.description": "在提示信息中显示提供该按键的Mod的ID",
"option.ShowDebugInfo": "是否显示调试信息", "option.feature.ShowKeybindID": "是否显示键位ID",
"option.ShowDebugInfo.description": "这些信息用于出现和本Mod相关的问题时进行排查,一般情况下不需要开启", "option.feature.ShowKeybindID.description": "在提示信息中显示该按键本身的ID",
"option.ShowFilePath": "是否显示文件路径", "option.feature.ShowFilePath": "是否显示文件路径",
"option.ShowFilePath.description": "在信息中显示Mod的文件路径", "option.feature.ShowFilePath.description": "在信息中显示Mod的文件路径",
"option.SearchInStackTrace": "是否要通过查询堆栈信息来进行强力搜索", "option.debug.ShowDebugInfo": "是否显示调试信息",
"option.SearchInStackTrace.description": "注入KeyMapping类的构造函数,在每次注册按键绑定时查询线程的调用栈信息来进行强力匹配\n警告:部分情况下可能产生更多误报,请按需选择", "option.debug.ShowDebugInfo.description": "这些信息用于出现和本Mod相关的问题时进行排查,一般情况下不需要开启",
"tooltip.provided_by": "提供者:%s", "tooltip.provided_by": "提供者:%s",
"tooltip.provider_mod_id": "提供者ID%s", "tooltip.provider_mod_id": "提供者ID%s",
"tooltip.key_id": "键位ID%s", "tooltip.key_id": "键位ID%s",