mirror of
https://github.com/TheWhiteDog9487/WhoProvideThisKeybind.git
synced 2026-09-16 23:10:28 +08:00
⭐ init: 完成
This commit is contained in:
+9
@@ -0,0 +1,9 @@
|
||||
package xyz.thewhitedog9487.client.mixin.Compatibility.Controlling;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
|
||||
public class MixinPlugin implements IMixinConfigPlugin {
|
||||
@Override
|
||||
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
|
||||
return FabricLoader.getInstance().isModLoaded(("controlling")); } }
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package xyz.thewhitedog9487.client.mixin.Compatibility.Controlling;
|
||||
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Pseudo;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
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.SettingsKt;
|
||||
import xyz.thewhitedog9487.client.WhoProvideThisKeybindModClient;
|
||||
|
||||
/**
|
||||
* <a href="https://modrinth.com/mod/controlling">Controlling</a>把原版的UI直接给换了,因此需要注入到修改之后的UI中
|
||||
*
|
||||
* @see xyz.thewhitedog9487.client.mixin.Compatibility.Controlling.MixinPlugin
|
||||
*/
|
||||
@Pseudo
|
||||
@Mixin(targets = "com.blamejared.controlling.client.NewKeyBindsList$KeyEntry")
|
||||
public abstract class NewKeyBindsListMixin {
|
||||
@Shadow @Final private KeyMapping key;
|
||||
@Shadow @Final private Button btnChangeKeyBinding;
|
||||
@Inject(method = "refreshEntry", at = @At("TAIL"))
|
||||
private void SetNewTooltipInControllingUI(final CallbackInfo ci) {
|
||||
if (SettingsKt.getSettingsInstance().getShowDebugInfo()) {
|
||||
WhoProvideThisKeybindModClient.INSTANCE.getClientLogger().debug("SetNewTooltipInControllingUI函数被调用,Key:{}", key.getName()); }
|
||||
MiscellaneousKt.SetNewTooltip(btnChangeKeyBinding, key); } }
|
||||
@@ -0,0 +1,32 @@
|
||||
package xyz.thewhitedog9487.client.mixin;
|
||||
|
||||
import xyz.thewhitedog9487.client.MiscellaneousKt;
|
||||
import xyz.thewhitedog9487.client.SettingsKt;
|
||||
import xyz.thewhitedog9487.client.WhoProvideThisKeybindModClient;
|
||||
import xyz.thewhitedog9487.client.ModInfo;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
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.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* 针对原版的实现
|
||||
*/
|
||||
@Mixin(KeyBindsList.KeyEntry.class)
|
||||
public abstract class KeyBindsListKeyEntryMixin {
|
||||
@Shadow @Final private KeyMapping key;
|
||||
@Shadow @Final private Button changeButton;
|
||||
|
||||
@Inject(method = "refreshEntry", at = @At("RETURN"))
|
||||
private void SetTooltip(CallbackInfo ci) {
|
||||
if (SettingsKt.getSettingsInstance().getShowDebugInfo()) {
|
||||
WhoProvideThisKeybindModClient.INSTANCE.getClientLogger().debug("SetTooltip函数被调用,Key:{}", key.getName()); }
|
||||
MiscellaneousKt.SetNewTooltip(changeButton, key); } }
|
||||
@@ -0,0 +1,44 @@
|
||||
package xyz.thewhitedog9487.client.Event
|
||||
|
||||
import com.google.gson.GsonBuilder
|
||||
import dev.isxander.yacl3.config.v2.api.ConfigClassHandler
|
||||
import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
|
||||
import net.minecraft.resources.Identifier
|
||||
import xyz.thewhitedog9487.client.ConfigFilePath
|
||||
import xyz.thewhitedog9487.client.CurrentConfigurationVersionCode
|
||||
import xyz.thewhitedog9487.client.RegisterConfigFileReloadWatcher
|
||||
import xyz.thewhitedog9487.client.Settings
|
||||
import xyz.thewhitedog9487.client.SettingsHandler
|
||||
import xyz.thewhitedog9487.client.SettingsInstance
|
||||
import xyz.thewhitedog9487.client.WhoProvideThisKeybindModClient
|
||||
|
||||
fun RegisterClientLifecycleEvents() {
|
||||
ClientLifecycleEvents.CLIENT_STARTED.register { ClientInstance ->
|
||||
try {
|
||||
SettingsHandler = ConfigClassHandler
|
||||
.createBuilder(Settings::class.java)
|
||||
.id(Identifier.fromNamespaceAndPath(WhoProvideThisKeybindModClient.ModID, "settings_confighandler"))
|
||||
.serializer {
|
||||
GsonConfigSerializerBuilder.create(it)
|
||||
.setPath(ConfigFilePath)
|
||||
.setJson5(true)
|
||||
.appendGsonBuilder(GsonBuilder::setPrettyPrinting)
|
||||
.build() }
|
||||
.build()
|
||||
|
||||
WhoProvideThisKeybindModClient.ClientLogger.info("正在从${ConfigFilePath}加载设置...")
|
||||
SettingsHandler!!.load()
|
||||
SettingsInstance = SettingsHandler!!.instance()
|
||||
if (SettingsInstance.ConfigurationVersionCode != CurrentConfigurationVersionCode) {
|
||||
// 必要时手动处理升降级,现在不必要,就这么办了
|
||||
SettingsInstance.ConfigurationVersionCode = CurrentConfigurationVersionCode
|
||||
SettingsHandler!!.save() }
|
||||
RegisterConfigFileReloadWatcher() }
|
||||
catch (_: NoClassDefFoundError) {
|
||||
SettingsInstance = Settings()
|
||||
WhoProvideThisKeybindModClient.ClientLogger.warn("当前没有安装YetAnotherConfigLib,因此无法在调整和保持Mod配置") } }
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register { ClientInstance ->
|
||||
if (SettingsHandler == null) return@register
|
||||
WhoProvideThisKeybindModClient.ClientLogger.info("正在保存设置到$ConfigFilePath...")
|
||||
SettingsHandler!!.save() } }
|
||||
@@ -0,0 +1,60 @@
|
||||
package xyz.thewhitedog9487.client
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader
|
||||
import net.fabricmc.loader.api.ModContainer
|
||||
import net.fabricmc.loader.api.metadata.ModMetadata
|
||||
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
|
||||
|
||||
val VanillaMinecraftContainer: ModContainer = FabricLoader
|
||||
.getInstance()
|
||||
.getModContainer("minecraft")
|
||||
.get()
|
||||
|
||||
val KeyMapping.Provider: ModInfo get() {
|
||||
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)
|
||||
if (ModContainer.isPresent) {
|
||||
return ModContainer.map(::ModInfo).get() } }
|
||||
return ModInfo(VanillaMinecraftContainer) }
|
||||
|
||||
data class ModInfo(val ModContainerInstance: ModContainer?) {
|
||||
val ID: String = ModContainerInstance?.metadata?.id ?: Component.translatable("special_provider_UNKNOWN").string
|
||||
val MetaData: ModMetadata? = ModContainerInstance?.metadata
|
||||
val DisplayName: String = MetaData?.name ?: Component.translatable("special_provider_UNKNOWN").string
|
||||
val HumanFriendlyName: Component = Component.translatableWithFallback("modmenu.nameTranslation." + (MetaData?.id ?: "unknown"), DisplayName) }
|
||||
|
||||
fun Button.SetNewTooltip(Key: KeyMapping) {
|
||||
if (SettingsInstance.ModEnabled == false) return
|
||||
|
||||
val Mod = Key.Provider
|
||||
val NewTooltip = tooltip
|
||||
.get()
|
||||
?.message
|
||||
?.copy()
|
||||
?.append(Component.literal("\n"))
|
||||
?.append(Component.literal("\n"))
|
||||
?: Component.empty()
|
||||
|
||||
// 第一行:Mod的人类可读名称
|
||||
NewTooltip.append(Component.translatable("tooltip.provided_by",
|
||||
Mod.HumanFriendlyName))
|
||||
// 第二行:Mod的ID
|
||||
if (SettingsInstance.ShowModID) {
|
||||
NewTooltip.append(Component.literal("\n"))
|
||||
.append(Component.translatable("tooltip.provider_mod_id",
|
||||
Component.literal(Mod.ID))); }
|
||||
// 第三行:按键自身的ID
|
||||
if (SettingsInstance.ShowKeybindID) {
|
||||
NewTooltip.append(Component.literal("\n"))
|
||||
.append(Component.translatable("tooltip.key_id",
|
||||
Component.literal(Key.name))) }
|
||||
|
||||
setTooltip(Tooltip.create(NewTooltip)) }
|
||||
@@ -0,0 +1,49 @@
|
||||
package xyz.thewhitedog9487.client
|
||||
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi
|
||||
import dev.isxander.yacl3.api.ConfigCategory
|
||||
import dev.isxander.yacl3.api.Option
|
||||
import dev.isxander.yacl3.api.OptionDescription
|
||||
import dev.isxander.yacl3.api.YetAnotherConfigLib
|
||||
import dev.isxander.yacl3.api.controller.BooleanControllerBuilder
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
class ModMenuEntryPoint: ModMenuApi {
|
||||
override fun getModConfigScreenFactory() = ConfigScreenFactory { ParentScreen ->
|
||||
YetAnotherConfigLib.createBuilder()
|
||||
.title(Component.translatable("title.config"))
|
||||
.category {
|
||||
ConfigCategory.createBuilder()
|
||||
.name(Component.translatable("config.category.general"))
|
||||
.option {
|
||||
Option.createBuilder<Boolean>()
|
||||
.name(Component.translatable("option.ModEnabled"))
|
||||
.description { OptionDescription.of(Component.translatable("option.ModEnabled.description") ) }
|
||||
.binding( true, { SettingsInstance.ModEnabled }, { SettingsInstance.ModEnabled = it } )
|
||||
.controller(BooleanControllerBuilder::create )
|
||||
.build() }
|
||||
.option {
|
||||
Option.createBuilder<Boolean>()
|
||||
.name(Component.translatable("option.ShowModID"))
|
||||
.description { OptionDescription.of(Component.translatable("option.ShowModID.description") ) }
|
||||
.binding( false, { SettingsInstance.ShowModID }, { SettingsInstance.ShowModID = it } )
|
||||
.controller(BooleanControllerBuilder::create )
|
||||
.build() }
|
||||
.option {
|
||||
Option.createBuilder<Boolean>()
|
||||
.name(Component.translatable("option.ShowKeybindID"))
|
||||
.description { OptionDescription.of(Component.translatable("option.ShowKeybindID.description") ) }
|
||||
.binding( false, { SettingsInstance.ShowKeybindID }, { SettingsInstance.ShowKeybindID = it } )
|
||||
.controller(BooleanControllerBuilder::create )
|
||||
.build() }
|
||||
.option {
|
||||
Option.createBuilder<Boolean>()
|
||||
.name(Component.translatable("option.ShowDebugInfo"))
|
||||
.description { OptionDescription.of(Component.translatable("option.ShowDebugInfo.description") ) }
|
||||
.binding( false, { SettingsInstance.ShowDebugInfo }, { SettingsInstance.ShowDebugInfo = it } )
|
||||
.controller(BooleanControllerBuilder::create )
|
||||
.build() }
|
||||
.build() }
|
||||
.build()
|
||||
.generateScreen(ParentScreen) } }
|
||||
@@ -0,0 +1,102 @@
|
||||
package xyz.thewhitedog9487.client
|
||||
|
||||
import dev.isxander.yacl3.config.v2.api.ConfigClassHandler
|
||||
import dev.isxander.yacl3.config.v2.api.SerialEntry
|
||||
import kotlinx.io.IOException
|
||||
import net.fabricmc.loader.api.FabricLoader
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardWatchEventKinds
|
||||
import java.nio.file.StandardWatchEventKinds.*
|
||||
|
||||
const val CurrentConfigurationVersionCode: Long = 0
|
||||
class Settings {
|
||||
@SerialEntry(comment =
|
||||
"""
|
||||
配置文件版本号
|
||||
用于在配置文件结构发生变化且需要手动干预时进行兼容性处理
|
||||
非必要情况下你不应该手动修改这个数据,否则可能导致本Mod的配置文件出现损坏或其他问题
|
||||
类型:整数
|
||||
取值范围:0 ~ Long.MAX_VALUE
|
||||
当前值:0
|
||||
""")
|
||||
var ConfigurationVersionCode = CurrentConfigurationVersionCode
|
||||
|
||||
@SerialEntry(comment =
|
||||
"""
|
||||
是否启用本模组的功能
|
||||
类型:布尔值
|
||||
取值范围:true false
|
||||
默认值:true
|
||||
""")
|
||||
var ModEnabled = true
|
||||
|
||||
@SerialEntry(comment =
|
||||
"""
|
||||
是否在悬停信息中显示键位提供者的ID
|
||||
类型:布尔值
|
||||
取值范围:true false
|
||||
默认值:false
|
||||
""")
|
||||
var ShowModID = false
|
||||
|
||||
@SerialEntry(comment =
|
||||
"""
|
||||
是否在悬停信息中显示键位本身的ID
|
||||
类型:布尔值
|
||||
取值范围:true false
|
||||
默认值:false
|
||||
""")
|
||||
var ShowKeybindID = false
|
||||
|
||||
@SerialEntry(comment =
|
||||
"""
|
||||
是否显示调试信息
|
||||
这些信息用于出现和本Mod相关的问题时进行排查,一般情况下不需要开启
|
||||
类型:布尔值
|
||||
取值范围:true false
|
||||
默认值:false
|
||||
""")
|
||||
var ShowDebugInfo = false }
|
||||
|
||||
var SettingsHandler: ConfigClassHandler<Settings>? = null
|
||||
|
||||
val ConfigFilePath = FabricLoader
|
||||
.getInstance()
|
||||
.configDir
|
||||
.resolve(WhoProvideThisKeybindModClient.FriendlyModID + ".json5")
|
||||
.toAbsolutePath()
|
||||
|
||||
@Volatile var SettingsInstance = Settings()
|
||||
|
||||
// region 配置文件变更监听器
|
||||
fun RegisterConfigFileReloadWatcher() {
|
||||
// 由GPT 5.4 Mini生成
|
||||
Thread.startVirtualThread {
|
||||
WhoProvideThisKeybindModClient.ClientLogger.info("正在为${ConfigFilePath}注册配置文件变更监听器...")
|
||||
val ConfigDirectory = ConfigFilePath.parent
|
||||
try {
|
||||
val WatchService = FileSystems.getDefault().newWatchService()
|
||||
ConfigDirectory.register(WatchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE)
|
||||
while (!Thread.currentThread().isInterrupted) {
|
||||
val WatchKey = WatchService.take()
|
||||
var ShouldReload = false
|
||||
|
||||
for (EventInstance in WatchKey.pollEvents()) {
|
||||
val EventKind = EventInstance.kind()
|
||||
if (EventKind == StandardWatchEventKinds.OVERFLOW) {
|
||||
continue }
|
||||
val ChangedPath = EventInstance.context() as Path?
|
||||
if (ChangedPath != null && ChangedPath == ConfigFilePath.fileName) {
|
||||
ShouldReload = true } }
|
||||
if (ShouldReload) {
|
||||
SettingsHandler!!.load()
|
||||
SettingsInstance = SettingsHandler!!.instance()
|
||||
WhoProvideThisKeybindModClient.ClientLogger.info("检测到配置文件变更,已重新加载设置。") }
|
||||
if (!WatchKey.reset()) {
|
||||
break } }
|
||||
} catch (e: InterruptedException) {
|
||||
Thread.currentThread().interrupt()
|
||||
} catch (e: IOException) {
|
||||
throw RuntimeException(e) } } }
|
||||
// endregion
|
||||
@@ -0,0 +1,13 @@
|
||||
package xyz.thewhitedog9487.client
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer
|
||||
import org.slf4j.LoggerFactory
|
||||
import xyz.thewhitedog9487.client.Event.RegisterClientLifecycleEvents
|
||||
|
||||
object WhoProvideThisKeybindModClient : ClientModInitializer {
|
||||
const val ModID: String = "whoprovidethiskeybind"
|
||||
const val FriendlyModID = "WhoProvideThisKeybind"
|
||||
val ClientLogger = LoggerFactory.getLogger(FriendlyModID)
|
||||
|
||||
override fun onInitializeClient() {
|
||||
RegisterClientLifecycleEvents() } }
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"required": false,
|
||||
"package": "xyz.thewhitedog9487.client.mixin.Compatibility.Controlling",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"plugin": "xyz.thewhitedog9487.client.mixin.Compatibility.Controlling.MixinPlugin",
|
||||
"client": [
|
||||
"NewKeyBindsListMixin" ],
|
||||
"injectors": {
|
||||
"defaultRequire": 0 }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "xyz.thewhitedog9487.client.mixin",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"client": [
|
||||
"KeyBindsListKeyEntryMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"overwrites": {
|
||||
"requireAnnotations": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user