aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/firmament/features
diff options
context:
space:
mode:
authornea <nea@nea.moe>2023-10-28 03:36:11 +0200
committerLinnea Gräf <nea@nea.moe>2023-11-12 09:35:33 +0100
commite15406e22ef65b4933274df791632b6c17f594be (patch)
treee1625c713bf95e9f0cb65dfe9a7c9b9ceaa46402 /src/main/kotlin/moe/nea/firmament/features
parent47fbb25ab280b6af9496780672780db78fe36f27 (diff)
downloadfirmament-e15406e22ef65b4933274df791632b6c17f594be.tar.gz
firmament-e15406e22ef65b4933274df791632b6c17f594be.tar.bz2
firmament-e15406e22ef65b4933274df791632b6c17f594be.zip
Add Inventory Buttons
Diffstat (limited to 'src/main/kotlin/moe/nea/firmament/features')
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt2
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt9
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButton.kt66
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonEditor.kt128
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonTemplates.kt39
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt82
6 files changed, 325 insertions, 1 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
index 2683775..4888f54 100644
--- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
+++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
@@ -23,6 +23,7 @@ import moe.nea.firmament.features.inventory.ItemRarityCosmetics
import moe.nea.firmament.features.inventory.PriceData
import moe.nea.firmament.features.inventory.SaveCursorPosition
import moe.nea.firmament.features.inventory.SlotLocking
+import moe.nea.firmament.features.inventory.buttons.InventoryButtons
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlay
import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures
import moe.nea.firmament.features.world.FairySouls
@@ -56,6 +57,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
loadFeature(CraftingOverlay)
loadFeature(PowerUserTools)
loadFeature(ChatLinks)
+ loadFeature(InventoryButtons)
loadFeature(CompatibliltyFeatures)
loadFeature(QuickCommands)
loadFeature(SaveCursorPosition)
diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt b/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt
index e045fa8..7e3203b 100644
--- a/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt
+++ b/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt
@@ -64,6 +64,7 @@ object DeveloperFeatures : FirmamentFeature {
return reloadFuture.thenCompose { client.reloadResources() }
}
+
override fun onLoad() {
HandledScreenKeyPressedEvent.subscribe {
if (it.matches(IKeyBinding.ofKeyCode(GLFW.GLFW_KEY_K))) {
@@ -78,10 +79,16 @@ object DeveloperFeatures : FirmamentFeature {
).setStyle(
Style.EMPTY.withColor(Formatting.AQUA)
.withClickEvent(ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, ident))
- .withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.translatable("firmament.debug.skyblockid.copy")))
+ .withHoverEvent(
+ HoverEvent(
+ HoverEvent.Action.SHOW_TEXT,
+ Text.translatable("firmament.debug.skyblockid.copy")
+ )
+ )
)
)
}
}
}
}
+
diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButton.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButton.kt
new file mode 100644
index 0000000..0383258
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButton.kt
@@ -0,0 +1,66 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.features.inventory.buttons
+
+import me.shedaniel.math.Dimension
+import me.shedaniel.math.Point
+import me.shedaniel.math.Rectangle
+import kotlinx.serialization.Serializable
+import net.minecraft.client.gui.DrawContext
+import net.minecraft.item.ItemStack
+import net.minecraft.util.Identifier
+import moe.nea.firmament.repo.ItemCache.asItemStack
+import moe.nea.firmament.repo.RepoManager
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.SkyblockId
+
+@Serializable
+data class InventoryButton(
+ val x: Int,
+ val y: Int,
+ val anchorRight: Boolean,
+ val anchorBottom: Boolean,
+ var icon: String? = "",
+ var command: String? = "",
+) {
+ companion object {
+ val dimensions = Dimension(18, 18)
+ fun getItemForName(icon: String): ItemStack {
+ return RepoManager.getNEUItem(SkyblockId(icon)).asItemStack(idHint = SkyblockId(icon))
+ }
+ }
+
+ fun render(context: DrawContext) {
+ context.drawSprite(
+ 0,
+ 0,
+ 0,
+ dimensions.width,
+ dimensions.height,
+ MC.guiAtlasManager.getSprite(Identifier("firmament:inventory_button_background"))
+ )
+ context.drawItem(getItem(), 1, 1)
+ }
+
+ fun isValid() = !icon.isNullOrBlank() && !command.isNullOrBlank()
+
+ fun getPosition(guiRect: Rectangle): Point {
+ return Point(
+ (if (anchorRight) guiRect.maxX else guiRect.minX) + x,
+ (if (anchorBottom) guiRect.maxY else guiRect.minY) + y,
+ )
+ }
+
+ fun getBounds(guiRect: Rectangle): Rectangle {
+ return Rectangle(getPosition(guiRect), dimensions)
+ }
+
+ fun getItem(): ItemStack {
+ return getItemForName(icon ?: "")
+ }
+
+}
diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonEditor.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonEditor.kt
new file mode 100644
index 0000000..66be212
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonEditor.kt
@@ -0,0 +1,128 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.features.inventory.buttons
+
+import io.github.moulberry.moulconfig.common.IItemStack
+import io.github.moulberry.moulconfig.xml.Bind
+import io.github.notenoughupdates.moulconfig.platform.ModernItemStack
+import me.shedaniel.math.Point
+import me.shedaniel.math.Rectangle
+import org.lwjgl.glfw.GLFW
+import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.gui.widget.ButtonWidget
+import net.minecraft.text.Text
+import moe.nea.firmament.util.ClipboardUtils
+import moe.nea.firmament.util.FragmentGuiScreen
+import moe.nea.firmament.util.MoulConfigUtils
+
+class InventoryButtonEditor(
+ val lastGuiRect: Rectangle,
+) : FragmentGuiScreen() {
+ inner class Editor(val originalButton: InventoryButton) {
+ @field:Bind
+ var command: String = originalButton.command ?: ""
+
+ @field:Bind
+ var icon: String = originalButton.icon ?: ""
+
+ @Bind
+ fun getItemIcon(): IItemStack {
+ save()
+ return ModernItemStack.of(InventoryButton.getItemForName(icon))
+ }
+
+ @Bind
+ fun delete() {
+ buttons.removeIf { it === originalButton }
+ popup = null
+ }
+
+ fun save() {
+ originalButton.icon = icon
+ originalButton.command = command
+ }
+ }
+
+ var buttons: MutableList<InventoryButton> =
+ InventoryButtons.DConfig.data.buttons.map { it.copy() }.toMutableList()
+
+ override fun close() {
+ InventoryButtons.DConfig.data.buttons = buttons
+ InventoryButtons.DConfig.markDirty()
+ super.close()
+ }
+
+ override fun init() {
+ super.init()
+ addDrawableChild(
+ ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.load-preset")) {
+ val t = ClipboardUtils.getTextContents()
+ val newButtons = InventoryButtonTemplates.loadTemplate(t)
+ if (newButtons != null)
+ buttons = newButtons.toMutableList()
+ }
+ .position(lastGuiRect.minX + 10, lastGuiRect.minY + 35)
+ .width(lastGuiRect.width - 20)
+ .build()
+ )
+ addDrawableChild(
+ ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.save-preset")) {
+ ClipboardUtils.setTextContent(InventoryButtonTemplates.saveTemplate(buttons))
+ }
+ .position(lastGuiRect.minX + 10, lastGuiRect.minY + 60)
+ .width(lastGuiRect.width - 20)
+ .build()
+ )
+ }
+
+ override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
+ context.fill(lastGuiRect.minX, lastGuiRect.minY, lastGuiRect.maxX, lastGuiRect.maxY, -1)
+ context.setShaderColor(1f, 1f, 1f, 1f)
+ super.render(context, mouseX, mouseY, delta)
+ for (button in buttons) {
+ val buttonPosition = button.getBounds(lastGuiRect)
+ context.matrices.push()
+ context.matrices.translate(buttonPosition.minX.toFloat(), buttonPosition.minY.toFloat(), 0F)
+ button.render(context)
+ context.matrices.pop()
+ }
+ }
+
+ override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
+ if (super.keyPressed(keyCode, scanCode, modifiers)) return true
+ if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
+ close()
+ return true
+ }
+ return false
+ }
+
+ override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
+ if (super.mouseClicked(mouseX, mouseY, button)) return true
+ val clickedButton = buttons.firstOrNull { it.getBounds(lastGuiRect).contains(Point(mouseX, mouseY)) }
+ if (clickedButton != null) {
+ createPopup(MoulConfigUtils.loadGui("button_editor_fragment", Editor(clickedButton)), Point(mouseX, mouseY))
+ return true
+ }
+ if (lastGuiRect.contains(mouseX, mouseY) || lastGuiRect.contains(
+ Point(
+ mouseX + InventoryButton.dimensions.width,
+ mouseY + InventoryButton.dimensions.height,
+ )
+ )
+ ) return true
+ val mx = mouseX.toInt()
+ val my = mouseY.toInt()
+ val anchorRight = mx > lastGuiRect.maxX
+ val anchorBottom = my > lastGuiRect.maxY
+ val offsetX = mx - if (anchorRight) lastGuiRect.maxX else lastGuiRect.minX
+ val offsetY = my - if (anchorBottom) lastGuiRect.maxY else lastGuiRect.minY
+ buttons.add(InventoryButton(offsetX, offsetY, anchorRight, anchorBottom, null, null))
+ return true
+ }
+
+}
diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonTemplates.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonTemplates.kt
new file mode 100644
index 0000000..6b551b0
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonTemplates.kt
@@ -0,0 +1,39 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.features.inventory.buttons
+
+import kotlinx.serialization.decodeFromString
+import kotlinx.serialization.encodeToString
+import net.minecraft.text.Text
+import moe.nea.firmament.Firmament
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.TemplateUtil
+
+object InventoryButtonTemplates {
+
+ val legacyPrefix = "NEUBUTTONS/"
+ val modernPrefix = "MAYBEONEDAYIWILLHAVEMYOWNFORMAT"
+
+ fun loadTemplate(t: String): List<InventoryButton>? {
+ val buttons = TemplateUtil.maybeDecodeTemplate<List<String>>(legacyPrefix, t) ?: return null
+ return buttons.mapNotNull {
+ try {
+ Firmament.json.decodeFromString<InventoryButton>(it).also {
+ if (it.icon?.startsWith("extra:") == true || it.command?.any { it.isLowerCase() } == true) {
+ MC.sendChat(Text.translatable("firmament.inventory-buttons.import-failed"))
+ }
+ }
+ } catch (e: Exception) {
+ null
+ }
+ }
+ }
+
+ fun saveTemplate(buttons: List<InventoryButton>): String {
+ return TemplateUtil.encodeTemplate(legacyPrefix, buttons.map { Firmament.json.encodeToString(it) })
+ }
+}
diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt
new file mode 100644
index 0000000..85e1d88
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt
@@ -0,0 +1,82 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.features.inventory.buttons
+
+import me.shedaniel.math.Rectangle
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.serializer
+import moe.nea.firmament.events.HandledScreenClickEvent
+import moe.nea.firmament.events.HandledScreenForegroundEvent
+import moe.nea.firmament.events.HandledScreenPushREIEvent
+import moe.nea.firmament.features.FirmamentFeature
+import moe.nea.firmament.gui.config.ManagedConfig
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.ScreenUtil
+import moe.nea.firmament.util.data.DataHolder
+import moe.nea.firmament.util.getRectangle
+
+object InventoryButtons : FirmamentFeature {
+ override val identifier: String
+ get() = "inventory-buttons"
+
+ object TConfig : ManagedConfig(identifier) {}
+ object DConfig : DataHolder<Data>(serializer(), identifier, ::Data)
+
+ @Serializable
+ data class Data(
+ var buttons: MutableList<InventoryButton> = mutableListOf()
+ )
+
+
+ override val config: ManagedConfig
+ get() = TConfig
+
+ fun getValidButtons() = DConfig.data.buttons.asSequence().filter { it.isValid() }
+ override fun onLoad() {
+ HandledScreenForegroundEvent.subscribe {
+ val bounds = it.screen.getRectangle()
+ for (button in getValidButtons()) {
+ val buttonBounds = button.getBounds(bounds)
+ it.context.matrices.push()
+ it.context.matrices.translate(buttonBounds.minX.toFloat(), buttonBounds.minY.toFloat(), 0F)
+ button.render(it.context)
+ it.context.matrices.pop()
+ }
+ lastRectangle = bounds
+ }
+ HandledScreenClickEvent.subscribe {
+ val bounds = it.screen.getRectangle()
+ for (button in getValidButtons()) {
+ val buttonBounds = button.getBounds(bounds)
+ if (buttonBounds.contains(it.mouseX, it.mouseY)) {
+ MC.sendCommand(button.command!! /* non null invariant covered by getValidButtons */)
+ break
+ }
+ }
+ }
+ HandledScreenPushREIEvent.subscribe {
+ val bounds = it.screen.getRectangle()
+ for (button in getValidButtons()) {
+ val buttonBounds = button.getBounds(bounds)
+ it.block(buttonBounds)
+ }
+ }
+ }
+
+ var lastRectangle: Rectangle? = null
+ fun openEditor() {
+ ScreenUtil.setScreenLater(
+ InventoryButtonEditor(
+ lastRectangle ?: Rectangle(
+ MC.window.scaledWidth / 2 - 100,
+ MC.window.scaledHeight / 2 - 100,
+ 200, 200,
+ )
+ )
+ )
+ }
+}