diff options
Diffstat (limited to 'src/main/kotlin/features/macros')
-rw-r--r-- | src/main/kotlin/features/macros/ComboProcessor.kt | 26 | ||||
-rw-r--r-- | src/main/kotlin/features/macros/HotkeyAction.kt | 7 | ||||
-rw-r--r-- | src/main/kotlin/features/macros/KeyComboTrie.kt | 23 | ||||
-rw-r--r-- | src/main/kotlin/features/macros/MacroData.kt | 11 | ||||
-rw-r--r-- | src/main/kotlin/features/macros/MacroUI.kt | 161 |
5 files changed, 213 insertions, 15 deletions
diff --git a/src/main/kotlin/features/macros/ComboProcessor.kt b/src/main/kotlin/features/macros/ComboProcessor.kt index 55b3f6e..5c5ac0e 100644 --- a/src/main/kotlin/features/macros/ComboProcessor.kt +++ b/src/main/kotlin/features/macros/ComboProcessor.kt @@ -10,6 +10,7 @@ import moe.nea.firmament.events.WorldKeyboardEvent import moe.nea.firmament.keybindings.SavedKeyBinding import moe.nea.firmament.util.MC import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.tr object ComboProcessor { @@ -22,18 +23,13 @@ object ComboProcessor { var isInputting = false var lastInput = TimeMark.farPast() val breadCrumbs = mutableListOf<SavedKeyBinding>() - // TODO: keep breadcrumbs - init { val f = SavedKeyBinding(InputUtil.GLFW_KEY_F) val one = SavedKeyBinding(InputUtil.GLFW_KEY_1) val two = SavedKeyBinding(InputUtil.GLFW_KEY_2) setActions( - listOf( - ComboKeyAction(CommandAction("wardrobe"), listOf(f, one)), - ComboKeyAction(CommandAction("equipment"), listOf(f, two)), - ) + MacroData.DConfig.data.comboActions ) } @@ -68,10 +64,24 @@ object ComboProcessor { 0F ) val breadCrumbText = breadCrumbs.joinToString(" > ") - event.context.drawText(MC.font, breadCrumbText, 0, 0, -1, true) + event.context.drawText( + MC.font, + tr("firmament.combo.active", "Current Combo: ").append(breadCrumbText), + 0, + 0, + -1, + true + ) event.context.matrices.translate(0F, MC.font.fontHeight + 2F, 0F) for ((key, value) in activeTrie.nodes) { - event.context.drawText(MC.font, Text.literal("$breadCrumbText > $key: ").append(value.label), 0, 0, -1, true) + event.context.drawText( + MC.font, + Text.literal("$breadCrumbText > $key: ").append(value.label), + 0, + 0, + -1, + true + ) event.context.matrices.translate(0F, MC.font.fontHeight + 1F, 0F) } event.context.matrices.pop() diff --git a/src/main/kotlin/features/macros/HotkeyAction.kt b/src/main/kotlin/features/macros/HotkeyAction.kt index 51c1baa..011f797 100644 --- a/src/main/kotlin/features/macros/HotkeyAction.kt +++ b/src/main/kotlin/features/macros/HotkeyAction.kt @@ -1,14 +1,19 @@ package moe.nea.firmament.features.macros +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import net.minecraft.text.Text import moe.nea.firmament.util.MC -interface HotkeyAction { +@Serializable +sealed interface HotkeyAction { // TODO: execute val label: Text fun execute() } +@Serializable +@SerialName("command") data class CommandAction(val command: String) : HotkeyAction { override val label: Text get() = Text.literal("/$command") diff --git a/src/main/kotlin/features/macros/KeyComboTrie.kt b/src/main/kotlin/features/macros/KeyComboTrie.kt index 5c14bcd..57ff289 100644 --- a/src/main/kotlin/features/macros/KeyComboTrie.kt +++ b/src/main/kotlin/features/macros/KeyComboTrie.kt @@ -1,7 +1,9 @@ package moe.nea.firmament.features.macros +import kotlinx.serialization.Serializable import net.minecraft.text.Text import moe.nea.firmament.keybindings.SavedKeyBinding +import moe.nea.firmament.util.ErrorUtil sealed interface KeyComboTrie { val label: Text @@ -13,19 +15,27 @@ sealed interface KeyComboTrie { val root = Branch(mutableMapOf()) for (combo in combos) { var p = root - require(combo.keys.isNotEmpty()) + if (combo.keys.isEmpty()) { + ErrorUtil.softUserError("Key Combo for ${combo.action.label.string} is empty") + continue + } for ((index, key) in combo.keys.withIndex()) { val m = (p.nodes as MutableMap) if (index == combo.keys.lastIndex) { - if (key in m) - error("Overlapping actions found for ${combo.keys} (another action ${m[key]} already exists).") + if (key in m) { + ErrorUtil.softUserError("Overlapping actions found for ${combo.keys.joinToString(" > ")} (another action ${m[key]} already exists).") + break + } m[key] = Leaf(combo.action) } else { val c = m.getOrPut(key) { Branch(mutableMapOf()) } - if (c !is Branch) - error("Overlapping actions found for ${combo.keys} (final node exists at index $index) through another action already") - p = c + if (c !is Branch) { + ErrorUtil.softUserError("Overlapping actions found for ${combo.keys} (final node exists at index $index) through another action already") + break + } else { + p = c + } } } } @@ -35,6 +45,7 @@ sealed interface KeyComboTrie { } +@Serializable data class ComboKeyAction( val action: HotkeyAction, val keys: List<SavedKeyBinding>, diff --git a/src/main/kotlin/features/macros/MacroData.kt b/src/main/kotlin/features/macros/MacroData.kt new file mode 100644 index 0000000..78a5948 --- /dev/null +++ b/src/main/kotlin/features/macros/MacroData.kt @@ -0,0 +1,11 @@ +package moe.nea.firmament.features.macros + +import kotlinx.serialization.Serializable +import moe.nea.firmament.util.data.DataHolder + +@Serializable +data class MacroData( + var comboActions: List<ComboKeyAction> = listOf(), +){ + object DConfig : DataHolder<MacroData>(kotlinx.serialization.serializer(), "macros", ::MacroData) +} diff --git a/src/main/kotlin/features/macros/MacroUI.kt b/src/main/kotlin/features/macros/MacroUI.kt new file mode 100644 index 0000000..17fdd0a --- /dev/null +++ b/src/main/kotlin/features/macros/MacroUI.kt @@ -0,0 +1,161 @@ +package moe.nea.firmament.features.macros + +import io.github.notenoughupdates.moulconfig.gui.CloseEventListener +import io.github.notenoughupdates.moulconfig.observer.ObservableList +import io.github.notenoughupdates.moulconfig.xml.Bind +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.commands.thenExecute +import moe.nea.firmament.events.CommandEvent +import moe.nea.firmament.gui.config.AllConfigsGui.toObservableList +import moe.nea.firmament.gui.config.KeyBindingStateManager +import moe.nea.firmament.keybindings.SavedKeyBinding +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.MoulConfigUtils +import moe.nea.firmament.util.ScreenUtil + +class MacroUI { + + + companion object { + @Subscribe + fun onCommands(event: CommandEvent.SubCommand) { + // TODO: add button in config + event.subcommand("macros") { + thenExecute { + ScreenUtil.setScreenLater(MoulConfigUtils.loadScreen("config/macros/index", MacroUI(), null)) + } + } + } + + } + + @field:Bind("combos") + val combos = Combos() + + class Combos { + @field:Bind("actions") + val actions: ObservableList<ActionEditor> = ObservableList( + MacroData.DConfig.data.comboActions.mapTo(mutableListOf()) { + ActionEditor(it, this) + } + ) + + var dontSave = false + + @Bind + fun beforeClose(): CloseEventListener.CloseAction { + if (!dontSave) + save() + return CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE + } + + @Bind + fun addCommand() { + actions.add( + ActionEditor( + ComboKeyAction( + CommandAction("ac Hello from a Firmament Hotkey"), + listOf() + ), + this + ) + ) + } + + @Bind + fun discard() { + dontSave = true + MC.screen?.close() + } + + @Bind + fun saveAndClose() { + save() + MC.screen?.close() + } + + @Bind + fun save() { + MacroData.DConfig.data.comboActions = actions.map { it.asSaveable() } + MacroData.DConfig.markDirty() + ComboProcessor.setActions(MacroData.DConfig.data.comboActions) // TODO: automatically reload those from the config on startup + } + } + + class KeyBindingEditor(var binding: SavedKeyBinding, val parent: ActionEditor) { + val sm = KeyBindingStateManager( + { binding }, + { binding = it }, + ::blur, + ::requestFocus + ) + + @field:Bind + val button = sm.createButton() + + init { + sm.updateLabel() + } + + fun blur() { + button.blur() + } + + @Bind + fun delete() { + parent.combo.removeIf { it === this } + parent.combo.update() + } + + fun requestFocus() { + button.requestFocus() + } + } + + class ActionEditor(val action: ComboKeyAction, val parent: MacroUI.Combos) { + fun asSaveable(): ComboKeyAction { + return ComboKeyAction( + CommandAction(command), + combo.map { it.binding } + ) + } + + @field:Bind("command") + var command: String = (action.action as CommandAction).command + + @field:Bind("combo") + val combo = action.keys.map { KeyBindingEditor(it, this) }.toObservableList() + + @Bind + fun formattedCombo() = + combo.joinToString(" > ") { it.binding.toString() } + + @Bind + fun addStep() { + combo.add(KeyBindingEditor(SavedKeyBinding.unbound(), this)) + } + + @Bind + fun back() { + MC.screen?.close() + } + + @Bind + fun delete() { + parent.actions.removeIf { it === this } + parent.actions.update() + } + @Bind + fun edit() { + MC.screen = MoulConfigUtils.loadScreen("config/macros/editor", this, MC.screen) + } + } +} + +private fun <T> ObservableList<T>.setAll(ts: Collection<T>) { + val observer = this.observer + this.clear() + this.addAll(ts) + this.observer = observer + this.update() +} |