aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornea <nea@nea.moe>2023-08-25 14:18:43 +0200
committernea <nea@nea.moe>2023-08-25 14:18:43 +0200
commit784231941661a3108549a1b5cd499bc5f7de2e46 (patch)
tree1e7c85001aef50af5d0491b2d97ae4fa09bb87d7
parenta79452c25406e17b81dd0ed1209f590d01991c68 (diff)
downloadfirmament-784231941661a3108549a1b5cd499bc5f7de2e46.tar.gz
firmament-784231941661a3108549a1b5cd499bc5f7de2e46.tar.bz2
firmament-784231941661a3108549a1b5cd499bc5f7de2e46.zip
Add better key binding support
-rw-r--r--TODO.txt1
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MixinKeybindsScreen.java53
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt2
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt16
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/config/KeyBindingHandler.kt113
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt35
-rw-r--r--src/main/kotlin/moe/nea/firmament/keybindings/FirmamentKeyBindings.kt23
-rw-r--r--src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt36
-rw-r--r--src/main/kotlin/moe/nea/firmament/util/ScreenUtil.kt6
-rw-r--r--src/main/resources/assets/firmament/lang/en_us.json3
10 files changed, 262 insertions, 26 deletions
diff --git a/TODO.txt b/TODO.txt
index 77314c8..fd20256 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -50,6 +50,7 @@ Priority 3:
- bits?
- collection?
- pretty graphs!
+- Maintain scroll percentage in vanilla guis when reinitializing
- and much more that i will add as i go along
diff --git a/src/main/java/moe/nea/firmament/mixins/MixinKeybindsScreen.java b/src/main/java/moe/nea/firmament/mixins/MixinKeybindsScreen.java
new file mode 100644
index 0000000..23bc26c
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/MixinKeybindsScreen.java
@@ -0,0 +1,53 @@
+package moe.nea.firmament.mixins;
+
+import moe.nea.firmament.gui.config.ManagedConfig;
+import moe.nea.firmament.keybindings.FirmamentKeyBindings;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.screen.option.ControlsListWidget;
+import net.minecraft.client.gui.widget.ButtonWidget;
+import net.minecraft.client.option.KeyBinding;
+import net.minecraft.text.Text;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Mutable;
+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.ModifyArg;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(ControlsListWidget.KeyBindingEntry.class)
+public class MixinKeybindsScreen {
+
+ @Mutable
+ @Shadow
+ @Final
+ private ButtonWidget editButton;
+
+ @Shadow
+ @Final
+ private KeyBinding binding;
+
+ @Shadow
+ @Final
+ private ButtonWidget resetButton;
+
+ @ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/ButtonWidget;builder(Lnet/minecraft/text/Text;Lnet/minecraft/client/gui/widget/ButtonWidget$PressAction;)Lnet/minecraft/client/gui/widget/ButtonWidget$Builder;"))
+ public ButtonWidget.PressAction onInit(ButtonWidget.PressAction action) {
+ ManagedConfig config = FirmamentKeyBindings.INSTANCE.getKeyBindings().get(binding);
+ if (config == null) return action;
+ return button -> {
+ config.showConfigEditor(MinecraftClient.getInstance().currentScreen);
+ };
+ }
+
+ @Inject(method = "update", at = @At("HEAD"), cancellable = true)
+ public void onUpdate(CallbackInfo ci) {
+ ManagedConfig config = FirmamentKeyBindings.INSTANCE.getKeyBindings().get(binding);
+ if (config == null) return;
+ resetButton.active = false;
+ editButton.setMessage(Text.translatable("firmament.keybinding.external"));
+ ci.cancel();
+ }
+
+}
diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
index 0c8acb9..facb821 100644
--- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
+++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
@@ -12,7 +12,6 @@ import moe.nea.firmament.Firmament
import moe.nea.firmament.features.chat.ChatLinks
import moe.nea.firmament.features.debug.DebugView
import moe.nea.firmament.features.debug.DeveloperFeatures
-import moe.nea.firmament.features.fishing.FishingWarning
import moe.nea.firmament.features.fixes.Fixes
import moe.nea.firmament.features.inventory.CraftingOverlay
import moe.nea.firmament.features.inventory.SaveCursorPosition
@@ -54,6 +53,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
loadFeature(DeveloperFeatures)
loadFeature(DebugView)
}
+ allFeatures.forEach { it.config }
hasAutoloaded = true
}
}
diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt
index f6a197c..ec86341 100644
--- a/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt
+++ b/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt
@@ -8,17 +8,17 @@ package moe.nea.firmament.features.inventory
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
-import net.minecraft.client.gui.DrawContext
-import net.minecraft.entity.player.PlayerInventory
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
import moe.nea.firmament.events.IsSlotProtectedEvent
import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.FirmamentFeature
-import moe.nea.firmament.keybindings.FirmamentKeyBindings
+import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.mixins.accessor.AccessorHandledScreen
import moe.nea.firmament.util.CommonSoundEffects
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
+import net.minecraft.entity.player.PlayerInventory
+import org.lwjgl.glfw.GLFW
object SlotLocking : FirmamentFeature {
override val identifier: String
@@ -29,13 +29,19 @@ object SlotLocking : FirmamentFeature {
val lockedSlots: MutableSet<Int> = mutableSetOf(),
)
+ object TConfig : ManagedConfig(identifier) {
+ val lock by keyBinding("lock") { GLFW.GLFW_KEY_L }
+ }
+
+ override val config: TConfig
+ get() = TConfig
+
object DConfig : ProfileSpecificDataHolder<Data>(serializer(), "locked-slots", ::Data)
- val keyBinding by FirmamentKeyBindings::SLOT_LOCKING
val lockedSlots get() = DConfig.data?.lockedSlots
override fun onLoad() {
HandledScreenKeyPressedEvent.subscribe {
- if (!it.matches(keyBinding)) return@subscribe
+ if (!it.matches(TConfig.lock)) return@subscribe
val inventory = MC.handledScreen ?: return@subscribe
inventory as AccessorHandledScreen
diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/KeyBindingHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/KeyBindingHandler.kt
new file mode 100644
index 0000000..5a4e3af
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/gui/config/KeyBindingHandler.kt
@@ -0,0 +1,113 @@
+package moe.nea.firmament.gui.config
+
+import io.github.cottonmc.cotton.gui.widget.WButton
+import io.github.cottonmc.cotton.gui.widget.data.InputResult
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.decodeFromJsonElement
+import kotlinx.serialization.json.encodeToJsonElement
+import moe.nea.firmament.keybindings.FirmamentKeyBindings
+import moe.nea.firmament.keybindings.SavedKeyBinding
+import net.minecraft.client.util.InputUtil
+import net.minecraft.text.Text
+import net.minecraft.util.Formatting
+import org.lwjgl.glfw.GLFW
+
+class KeyBindingHandler(name: String, managedConfig: ManagedConfig) : ManagedConfig.OptionHandler<SavedKeyBinding> {
+ init {
+ FirmamentKeyBindings.registerKeyBinding(name, managedConfig)
+ }
+
+ override fun toJson(element: SavedKeyBinding): JsonElement? {
+ return Json.encodeToJsonElement(element)
+ }
+
+ override fun fromJson(element: JsonElement): SavedKeyBinding {
+ return Json.decodeFromJsonElement(element)
+ }
+
+ override fun emitGuiElements(opt: ManagedOption<SavedKeyBinding>, guiAppender: GuiAppender) {
+ var editing = false
+ var lastPressed = 0
+ var lastPressedNonModifier = 0
+ var updateButton: (() -> Unit)? = null
+ val button = object : WButton() {
+ override fun onKeyPressed(ch: Int, key: Int, modifiers: Int): InputResult {
+ if (!editing) {
+ return super.onKeyPressed(ch, key, modifiers)
+ }
+ if (ch == GLFW.GLFW_KEY_ESCAPE) {
+ lastPressedNonModifier = 0
+ editing = false
+ lastPressed = 0
+ updateButton!!()
+ return InputResult.PROCESSED
+ }
+ if (ch == GLFW.GLFW_KEY_LEFT_SHIFT || ch == GLFW.GLFW_KEY_RIGHT_SHIFT
+ || ch == GLFW.GLFW_KEY_LEFT_ALT || ch == GLFW.GLFW_KEY_RIGHT_ALT
+ || ch == GLFW.GLFW_KEY_LEFT_CONTROL || ch == GLFW.GLFW_KEY_RIGHT_CONTROL
+ ) {
+ lastPressed = ch
+ } else {
+ opt.value = SavedKeyBinding(
+ ch, modifiers
+ )
+ editing = false
+ lastPressed = 0
+ lastPressedNonModifier = 0
+ }
+ updateButton!!()
+ return InputResult.PROCESSED
+ }
+
+ override fun onFocusLost() {
+ super.onFocusLost()
+ lastPressedNonModifier = 0
+ editing = false
+ lastPressed = 0
+ updateButton!!()
+ }
+
+ override fun onKeyReleased(ch: Int, key: Int, modifiers: Int): InputResult {
+ if (!editing)
+ return super.onKeyReleased(ch, key, modifiers)
+ if (lastPressedNonModifier == ch || (lastPressedNonModifier == 0 && ch == lastPressed)) {
+ opt.value = SavedKeyBinding(
+ ch, modifiers
+ )
+ editing = false
+ lastPressed = 0
+ lastPressedNonModifier = 0
+ }
+ updateButton!!()
+ return InputResult.PROCESSED
+ }
+ }
+
+ fun updateLabel() {
+ val stroke = Text.literal("")
+ if (opt.value.shift) {
+ stroke.append("SHIFT + ") // TODO: translations?
+ }
+ if (opt.value.alt) {
+ stroke.append("ALT + ")
+ }
+ if (opt.value.ctrl) {
+ stroke.append("CTRL + ")
+ }
+ stroke.append(InputUtil.Type.KEYSYM.createFromCode(opt.value.keyCode).localizedText)
+ if (editing)
+ stroke.styled { it.withColor(Formatting.YELLOW) }
+ button.setLabel(stroke)
+ }
+ updateButton = ::updateLabel
+ updateButton()
+ button.setOnClick {
+ editing = true
+ button.requestFocus()
+ updateButton()
+ }
+ guiAppender.appendLabeledRow(opt.labelText, button)
+ }
+
+}
diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt
index 56aca46..8743293 100644
--- a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt
+++ b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt
@@ -14,21 +14,22 @@ import io.github.cottonmc.cotton.gui.widget.WLabel
import io.github.cottonmc.cotton.gui.widget.data.Axis
import io.github.cottonmc.cotton.gui.widget.data.Insets
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
-import moe.nea.jarvis.api.Point
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
-import kotlin.io.path.createDirectories
-import kotlin.io.path.readText
-import kotlin.io.path.writeText
-import kotlin.time.Duration
-import net.minecraft.client.gui.screen.Screen
-import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.gui.WTightScrollPanel
+import moe.nea.firmament.keybindings.SavedKeyBinding
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.ScreenUtil.setScreenLater
+import moe.nea.jarvis.api.Point
+import net.minecraft.client.gui.screen.Screen
+import net.minecraft.text.Text
+import kotlin.io.path.createDirectories
+import kotlin.io.path.readText
+import kotlin.io.path.writeText
+import kotlin.time.Duration
abstract class ManagedConfig(override val name: String) : ManagedConfigElement() {
@@ -106,6 +107,18 @@ abstract class ManagedConfig(override val name: String) : ManagedConfigElement()
}, HudMetaHandler(this, label, width, height))
}
+ protected fun keyBinding(
+ propertyName: String,
+ default: () -> Int,
+ ): ManagedOption<SavedKeyBinding> = keyBindingWithDefaultModifiers(propertyName) { SavedKeyBinding(default()) }
+
+ protected fun keyBindingWithDefaultModifiers(
+ propertyName: String,
+ default: () -> SavedKeyBinding,
+ ): ManagedOption<SavedKeyBinding> {
+ return option(propertyName, default, KeyBindingHandler("firmament.config.${name}.${propertyName}", this))
+ }
+
protected fun integer(
propertyName: String,
min: Int,
@@ -125,7 +138,7 @@ abstract class ManagedConfig(override val name: String) : ManagedConfigElement()
fun reloadGui() {
- latestGuiAppender?.reloadables?.forEach {it() }
+ latestGuiAppender?.reloadables?.forEach { it() }
}
fun getConfigEditor(parent: Screen? = null): CottonClientScreen {
@@ -137,7 +150,11 @@ abstract class ManagedConfig(override val name: String) : ManagedConfigElement()
guiapp.appendFullRow(WBox(Axis.HORIZONTAL).also {
it.add(WButton(Text.literal("←")).also {
it.setOnClick {
- AllConfigsGui.showAllGuis()
+ if (parent != null) {
+ setScreenLater(parent)
+ } else {
+ AllConfigsGui.showAllGuis()
+ }
}
})
it.add(WLabel(Text.translatable("firmament.config.${name}")).also {
diff --git a/src/main/kotlin/moe/nea/firmament/keybindings/FirmamentKeyBindings.kt b/src/main/kotlin/moe/nea/firmament/keybindings/FirmamentKeyBindings.kt
index a7f25c0..770f4f6 100644
--- a/src/main/kotlin/moe/nea/firmament/keybindings/FirmamentKeyBindings.kt
+++ b/src/main/kotlin/moe/nea/firmament/keybindings/FirmamentKeyBindings.kt
@@ -7,17 +7,24 @@
package moe.nea.firmament.keybindings
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper
-import org.lwjgl.glfw.GLFW
import net.minecraft.client.option.KeyBinding
import net.minecraft.client.util.InputUtil
+import moe.nea.firmament.features.inventory.SlotLocking
+import moe.nea.firmament.gui.config.ManagedConfig
object FirmamentKeyBindings {
- val SLOT_LOCKING = KeyBindingHelper.registerKeyBinding(
- KeyBinding(
- "firmament.key.slotlocking",
- InputUtil.Type.KEYSYM,
- GLFW.GLFW_KEY_L,
- "firmament.key.category"
+ fun registerKeyBinding(name: String, config: ManagedConfig) {
+ val vanillaKeyBinding = KeyBindingHelper.registerKeyBinding(
+ KeyBinding(
+ name,
+ InputUtil.Type.KEYSYM,
+ -1,
+ "firmament.key.category"
+ )
)
- )
+ keyBindings[vanillaKeyBinding] = config
+ }
+
+ val keyBindings = mutableMapOf<KeyBinding, ManagedConfig>()
+
}
diff --git a/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt b/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt
new file mode 100644
index 0000000..f73eb49
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt
@@ -0,0 +1,36 @@
+package moe.nea.firmament.keybindings
+
+import kotlinx.serialization.Serializable
+import org.lwjgl.glfw.GLFW
+
+@Serializable
+data class SavedKeyBinding(
+ val keyCode: Int,
+ val shift: Boolean = false,
+ val ctrl: Boolean = false,
+ val alt: Boolean = false,
+) : IKeyBinding {
+ constructor(keyCode: Int, mods: Triple<Boolean, Boolean, Boolean>) : this(
+ keyCode,
+ mods.first && keyCode != GLFW.GLFW_KEY_LEFT_SHIFT && keyCode != GLFW.GLFW_KEY_RIGHT_SHIFT,
+ mods.second && keyCode != GLFW.GLFW_KEY_LEFT_CONTROL && keyCode != GLFW.GLFW_KEY_RIGHT_CONTROL,
+ mods.third && keyCode != GLFW.GLFW_KEY_LEFT_ALT && keyCode != GLFW.GLFW_KEY_RIGHT_ALT,
+ )
+
+ constructor(keyCode: Int, mods: Int) : this(keyCode, getMods(mods))
+
+ companion object {
+ fun getMods(modifiers: Int): Triple<Boolean, Boolean, Boolean> {
+ return Triple(
+ modifiers and GLFW.GLFW_MOD_SHIFT != 0,
+ modifiers and GLFW.GLFW_MOD_CONTROL != 0,
+ modifiers and GLFW.GLFW_MOD_ALT != 0
+ )
+ }
+ }
+
+ override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
+ return keyCode == this.keyCode && getMods(modifiers) == Triple(shift, ctrl, alt)
+ }
+
+}
diff --git a/src/main/kotlin/moe/nea/firmament/util/ScreenUtil.kt b/src/main/kotlin/moe/nea/firmament/util/ScreenUtil.kt
index 39d4541..25c603a 100644
--- a/src/main/kotlin/moe/nea/firmament/util/ScreenUtil.kt
+++ b/src/main/kotlin/moe/nea/firmament/util/ScreenUtil.kt
@@ -6,10 +6,10 @@
package moe.nea.firmament.util
-import moe.nea.firmament.Firmament
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.Screen
+import moe.nea.firmament.Firmament
object ScreenUtil {
init {
@@ -29,10 +29,10 @@ object ScreenUtil {
private var nextOpenedGui: Screen? = null
- fun setScreenLater(nextScreen: Screen) {
+ fun setScreenLater(nextScreen: Screen?) {
val nog = nextOpenedGui
if (nog != null) {
- Firmament.logger.warn("Setting screen ${nextScreen::class.qualifiedName} to be opened later, but ${nog::class.qualifiedName} is already queued.")
+ Firmament.logger.warn("Setting screen ${if (nextScreen == null) "null" else nextScreen::class.qualifiedName} to be opened later, but ${nog::class.qualifiedName} is already queued.")
return
}
nextOpenedGui = nextScreen
diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json
index 5df94a7..ad799e2 100644
--- a/src/main/resources/assets/firmament/lang/en_us.json
+++ b/src/main/resources/assets/firmament/lang/en_us.json
@@ -79,6 +79,9 @@
"firmament.config.chat-links.allowed-hosts": "Allowed Image Hosts",
"firmament.config.chat-links.position": "Chat Image Preview",
"firmament.hud.edit": "Edit %s",
+ "firmament.keybinding.external": "External",
+ "firmament.config.slot-locking": "Slot Locking",
+ "firmament.config.slot-locking.lock": "Lock Slot",
"firmament.config.custom-skyblock-textures": "Custom SkyBlock Item Textures",
"firmament.config.custom-skyblock-textures.cache-duration": "Model Cache Duration",
"firmament.config.custom-skyblock-textures.enabled": "Enable Custom Item Textures",