mirror of
https://github.com/TheWhiteDog9487/WhoProvideThisKeybind.git
synced 2026-09-16 15:04:19 +08:00
Compare commits
4 Commits
v1.0.0+26.2
...
主要
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f0f58a715 | |||
| bce136188a | |||
| 863bcfd0e2 | |||
| e0af7c05eb |
+2
-2
@@ -20,8 +20,8 @@ Display hover text on the keybind modification button to show which mod provides
|
|||||||
|
|
||||||
By default, to avoid disturbing users, information that is not useful to ordinary players is not shown.
|
By default, to avoid disturbing users, information that is not useful to ordinary players is not shown.
|
||||||
If you need it, you can enable additional features in the config screen.
|
If you need it, you can enable additional features in the config screen.
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
# Important Notes
|
# Important Notes
|
||||||
**This mod cannot guarantee 100% accuracy!**
|
**This mod cannot guarantee 100% accuracy!**
|
||||||
|
|||||||
@@ -52,6 +52,16 @@ dependencies {
|
|||||||
implementation("maven.modrinth:fuuu3xnx:bvFby61J")
|
implementation("maven.modrinth:fuuu3xnx:bvFby61J")
|
||||||
// https://modrinth.com/mod/controlling/versions?l=fabric
|
// https://modrinth.com/mod/controlling/versions?l=fabric
|
||||||
implementation("maven.modrinth:xv94TkTM:rAp2jljs")
|
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 {
|
tasks.processResources {
|
||||||
|
|||||||
+1
-1
@@ -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.0.0
|
version=1.1.0
|
||||||
group=xyz.thewhitedog9487
|
group=xyz.thewhitedog9487
|
||||||
|
|
||||||
OutputFileBasename=WhoProvideThisKeybind
|
OutputFileBasename=WhoProvideThisKeybind
|
||||||
|
|||||||
@@ -3,13 +3,9 @@ package xyz.thewhitedog9487.client.mixin;
|
|||||||
import xyz.thewhitedog9487.client.MiscellaneousKt;
|
import xyz.thewhitedog9487.client.MiscellaneousKt;
|
||||||
import xyz.thewhitedog9487.client.SettingsKt;
|
import xyz.thewhitedog9487.client.SettingsKt;
|
||||||
import xyz.thewhitedog9487.client.WhoProvideThisKeybindModClient;
|
import xyz.thewhitedog9487.client.WhoProvideThisKeybindModClient;
|
||||||
import xyz.thewhitedog9487.client.ModInfo;
|
|
||||||
import net.minecraft.client.KeyMapping;
|
import net.minecraft.client.KeyMapping;
|
||||||
import net.minecraft.client.gui.components.Button;
|
import net.minecraft.client.gui.components.Button;
|
||||||
import net.minecraft.client.gui.components.Tooltip;
|
|
||||||
import net.minecraft.client.gui.screens.options.controls.KeyBindsList;
|
import net.minecraft.client.gui.screens.options.controls.KeyBindsList;
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.chat.MutableComponent;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
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 xyz.thewhitedog9487.client.MiscellaneousKt;
|
||||||
|
import xyz.thewhitedog9487.client.ModInfo;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Mixin(KeyMapping.class)
|
||||||
|
public class KeyMappingMixin {
|
||||||
|
@Inject(method = "<init>(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) {
|
||||||
|
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<ModContainer> 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"); } }
|
||||||
@@ -7,17 +7,22 @@ import net.minecraft.client.KeyMapping
|
|||||||
import net.minecraft.client.gui.components.Button
|
import net.minecraft.client.gui.components.Button
|
||||||
import net.minecraft.client.gui.components.Tooltip
|
import net.minecraft.client.gui.components.Tooltip
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
val VanillaMinecraftContainer: ModContainer = FabricLoader
|
val VanillaMinecraftContainer: ModContainer = FabricLoader
|
||||||
.getInstance()
|
.getInstance()
|
||||||
.getModContainer("minecraft")
|
.getModContainer("minecraft")
|
||||||
.get()
|
.get()
|
||||||
|
|
||||||
|
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){
|
if (CandidateModIds.size == 1){
|
||||||
WhoProvideThisKeybindModClient.ClientLogger.warn("这是个什么东西,按键绑定ID只有一个部分,ID: $KeyBindTranslationKey")
|
|
||||||
return ModInfo(null) }
|
return ModInfo(null) }
|
||||||
for (CandidateModId in CandidateModIds) {
|
for (CandidateModId in CandidateModIds) {
|
||||||
val ModContainer = FabricLoader.getInstance().getModContainer(CandidateModId)
|
val ModContainer = FabricLoader.getInstance().getModContainer(CandidateModId)
|
||||||
@@ -29,7 +34,8 @@ 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_provider_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_provider_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 }
|
||||||
|
|
||||||
fun Button.SetNewTooltip(Key: KeyMapping) {
|
fun Button.SetNewTooltip(Key: KeyMapping) {
|
||||||
if (SettingsInstance.ModEnabled == false) return
|
if (SettingsInstance.ModEnabled == false) return
|
||||||
@@ -57,4 +63,9 @@ fun Button.SetNewTooltip(Key: KeyMapping) {
|
|||||||
.append(Component.translatable("tooltip.key_id",
|
.append(Component.translatable("tooltip.key_id",
|
||||||
Component.literal(Key.name))) }
|
Component.literal(Key.name))) }
|
||||||
|
|
||||||
|
// 第四行:文件路径
|
||||||
|
if (SettingsInstance.ShowFilePath) {
|
||||||
|
NewTooltip.append(Component.literal("\n"))
|
||||||
|
.append(Component.translatable("tooltip.mod_file_path", Mod.FilePath)) }
|
||||||
|
|
||||||
setTooltip(Tooltip.create(NewTooltip)) }
|
setTooltip(Tooltip.create(NewTooltip)) }
|
||||||
@@ -44,6 +44,20 @@ class ModMenuEntryPoint: ModMenuApi {
|
|||||||
.binding( false, { SettingsInstance.ShowDebugInfo }, { SettingsInstance.ShowDebugInfo = it } )
|
.binding( false, { SettingsInstance.ShowDebugInfo }, { SettingsInstance.ShowDebugInfo = it } )
|
||||||
.controller(BooleanControllerBuilder::create )
|
.controller(BooleanControllerBuilder::create )
|
||||||
.build() }
|
.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 } )
|
||||||
|
.controller(BooleanControllerBuilder::create )
|
||||||
|
.build() }
|
||||||
.build() }
|
.build() }
|
||||||
.build()
|
.build()
|
||||||
.generateScreen(ParentScreen) } }
|
.generateScreen(ParentScreen) } }
|
||||||
@@ -7,7 +7,6 @@ import net.fabricmc.loader.api.FabricLoader
|
|||||||
import java.nio.file.FileSystems
|
import java.nio.file.FileSystems
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.StandardWatchEventKinds
|
import java.nio.file.StandardWatchEventKinds
|
||||||
import java.nio.file.StandardWatchEventKinds.*
|
|
||||||
|
|
||||||
const val CurrentConfigurationVersionCode: Long = 0
|
const val CurrentConfigurationVersionCode: Long = 0
|
||||||
class Settings {
|
class Settings {
|
||||||
@@ -57,11 +56,30 @@ class Settings {
|
|||||||
取值范围:true false
|
取值范围:true false
|
||||||
默认值: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<Settings>? = null
|
var SettingsHandler: ConfigClassHandler<Settings>? = null
|
||||||
|
|
||||||
val ConfigFilePath = FabricLoader
|
val ConfigFilePath: Path = FabricLoader
|
||||||
.getInstance()
|
.getInstance()
|
||||||
.configDir
|
.configDir
|
||||||
.resolve(WhoProvideThisKeybindModClient.FriendlyModID + ".json5")
|
.resolve(WhoProvideThisKeybindModClient.FriendlyModID + ".json5")
|
||||||
@@ -77,7 +95,7 @@ fun RegisterConfigFileReloadWatcher() {
|
|||||||
val ConfigDirectory = ConfigFilePath.parent
|
val ConfigDirectory = ConfigFilePath.parent
|
||||||
try {
|
try {
|
||||||
val WatchService = FileSystems.getDefault().newWatchService()
|
val WatchService = FileSystems.getDefault().newWatchService()
|
||||||
ConfigDirectory.register(WatchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE)
|
ConfigDirectory.register(WatchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE)
|
||||||
while (!Thread.currentThread().isInterrupted) {
|
while (!Thread.currentThread().isInterrupted) {
|
||||||
val WatchKey = WatchService.take()
|
val WatchKey = WatchService.take()
|
||||||
var ShouldReload = false
|
var ShouldReload = false
|
||||||
@@ -95,7 +113,7 @@ fun RegisterConfigFileReloadWatcher() {
|
|||||||
WhoProvideThisKeybindModClient.ClientLogger.info("检测到配置文件变更,已重新加载设置。") }
|
WhoProvideThisKeybindModClient.ClientLogger.info("检测到配置文件变更,已重新加载设置。") }
|
||||||
if (!WatchKey.reset()) {
|
if (!WatchKey.reset()) {
|
||||||
break } }
|
break } }
|
||||||
} catch (e: InterruptedException) {
|
} catch (_: InterruptedException) {
|
||||||
Thread.currentThread().interrupt()
|
Thread.currentThread().interrupt()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
throw RuntimeException(e) } } }
|
throw RuntimeException(e) } } }
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package xyz.thewhitedog9487.client
|
package xyz.thewhitedog9487.client
|
||||||
|
|
||||||
import net.fabricmc.api.ClientModInitializer
|
import net.fabricmc.api.ClientModInitializer
|
||||||
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import xyz.thewhitedog9487.client.Event.RegisterClientLifecycleEvents
|
import xyz.thewhitedog9487.client.Event.RegisterClientLifecycleEvents
|
||||||
|
|
||||||
object WhoProvideThisKeybindModClient : ClientModInitializer {
|
object WhoProvideThisKeybindModClient : ClientModInitializer {
|
||||||
const val ModID: String = "whoprovidethiskeybind"
|
const val ModID: String = "whoprovidethiskeybind"
|
||||||
const val FriendlyModID = "WhoProvideThisKeybind"
|
const val FriendlyModID = "WhoProvideThisKeybind"
|
||||||
val ClientLogger = LoggerFactory.getLogger(FriendlyModID)
|
val ClientLogger: Logger = LoggerFactory.getLogger(FriendlyModID)
|
||||||
|
|
||||||
override fun onInitializeClient() {
|
override fun onInitializeClient() {
|
||||||
RegisterClientLifecycleEvents() } }
|
RegisterClientLifecycleEvents() } }
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
"package": "xyz.thewhitedog9487.client.mixin",
|
"package": "xyz.thewhitedog9487.client.mixin",
|
||||||
"compatibilityLevel": "JAVA_25",
|
"compatibilityLevel": "JAVA_25",
|
||||||
"client": [
|
"client": [
|
||||||
"KeyBindsListKeyEntryMixin"
|
"KeyBindsListKeyEntryMixin",
|
||||||
|
"KeyMappingMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|||||||
@@ -13,8 +13,13 @@
|
|||||||
"option.ShowKeybindID.description": "Display the keybind's own ID in the tooltip",
|
"option.ShowKeybindID.description": "Display the keybind's own ID in the tooltip",
|
||||||
"option.ShowDebugInfo": "Show Debug Info",
|
"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.ShowDebugInfo.description": "This information is used to troubleshoot issues related to this mod; it generally does not need to be enabled",
|
||||||
|
"option.ShowFilePath": "Show File Path",
|
||||||
|
"option.ShowFilePath.description": "Display the mod file path in the information",
|
||||||
|
"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.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",
|
||||||
"special_provider_UNKNOWN": "Unknown"
|
"tooltip.mod_file_path": "Mod File Path: %s",
|
||||||
|
"special_string_UNKNOWN": "Unknown"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,13 @@
|
|||||||
"option.ShowKeybindID.description": "在提示信息中显示该按键本身的ID",
|
"option.ShowKeybindID.description": "在提示信息中显示该按键本身的ID",
|
||||||
"option.ShowDebugInfo": "是否显示调试信息",
|
"option.ShowDebugInfo": "是否显示调试信息",
|
||||||
"option.ShowDebugInfo.description": "这些信息用于出现和本Mod相关的问题时进行排查,一般情况下不需要开启",
|
"option.ShowDebugInfo.description": "这些信息用于出现和本Mod相关的问题时进行排查,一般情况下不需要开启",
|
||||||
|
"option.ShowFilePath": "是否显示文件路径",
|
||||||
|
"option.ShowFilePath.description": "在信息中显示Mod的文件路径",
|
||||||
|
"option.SearchInStackTrace": "是否要通过查询堆栈信息来进行强力搜索",
|
||||||
|
"option.SearchInStackTrace.description": "注入KeyMapping类的构造函数,在每次注册按键绑定时查询线程的调用栈信息来进行强力匹配\n警告:部分情况下可能产生更多误报,请按需选择",
|
||||||
"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",
|
||||||
"special_provider_UNKNOWN": "未知"
|
"tooltip.mod_file_path": "Mod文件路径:%s",
|
||||||
|
"special_string_UNKNOWN": "未知"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user