aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-10-14 00:07:21 +0200
committerLinnea Gräf <nea@nea.moe>2024-10-14 00:07:21 +0200
commit854ec336cc6a0a3bb60f33acfac28ed45b491a15 (patch)
tree257e5a44f6cf2c4e12894a53dd6c99491f18f438 /src
parenta40c50b99186d425b3fcf42336940c29b97a8219 (diff)
downloadfirmament-854ec336cc6a0a3bb60f33acfac28ed45b491a15.tar.gz
firmament-854ec336cc6a0a3bb60f33acfac28ed45b491a15.tar.bz2
firmament-854ec336cc6a0a3bb60f33acfac28ed45b491a15.zip
Add /firm exporthotm to save hotm presets
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/Firmament.kt4
-rw-r--r--src/main/kotlin/events/SlotRenderEvents.kt10
-rw-r--r--src/main/kotlin/features/mining/CommissionFeatures.kt3
-rw-r--r--src/main/kotlin/features/mining/HotmPresets.kt241
-rw-r--r--src/main/kotlin/util/TemplateUtil.kt3
-rw-r--r--src/main/kotlin/util/mc/CommonTextures.kt7
-rw-r--r--src/main/resources/assets/firmament/lang/en_us.json6
-rw-r--r--src/main/resources/assets/firmament/textures/gui/sprites/generic_vanilla_widget.pngbin0 -> 4314 bytes
-rw-r--r--src/main/resources/assets/firmament/textures/gui/sprites/generic_vanilla_widget.png.mcmeta10
-rw-r--r--src/main/resources/assets/firmament/textures/gui/sprites/hotm_perk_preset.pngbin0 -> 558 bytes
10 files changed, 281 insertions, 3 deletions
diff --git a/src/main/kotlin/Firmament.kt b/src/main/kotlin/Firmament.kt
index 343ec40..d8a309b 100644
--- a/src/main/kotlin/Firmament.kt
+++ b/src/main/kotlin/Firmament.kt
@@ -65,6 +65,10 @@ object Firmament {
ignoreUnknownKeys = true
encodeDefaults = true
}
+ val tightJson = Json(from = json) {
+ prettyPrint = false
+ }
+
val httpClient by lazy {
HttpClient {
diff --git a/src/main/kotlin/events/SlotRenderEvents.kt b/src/main/kotlin/events/SlotRenderEvents.kt
index 8352581..5431573 100644
--- a/src/main/kotlin/events/SlotRenderEvents.kt
+++ b/src/main/kotlin/events/SlotRenderEvents.kt
@@ -3,7 +3,10 @@
package moe.nea.firmament.events
import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.texture.Sprite
import net.minecraft.screen.slot.Slot
+import net.minecraft.util.Identifier
+import moe.nea.firmament.util.MC
interface SlotRenderEvents {
val context: DrawContext
@@ -12,6 +15,13 @@ interface SlotRenderEvents {
val mouseY: Int
val delta: Float
+ fun highlight(sprite: Sprite) {
+ context.drawSprite(
+ slot.x, slot.y, 0, 16, 16,
+ sprite
+ )
+ }
+
data class Before(
override val context: DrawContext, override val slot: Slot,
override val mouseX: Int,
diff --git a/src/main/kotlin/features/mining/CommissionFeatures.kt b/src/main/kotlin/features/mining/CommissionFeatures.kt
index d1b501e..d0acdfd 100644
--- a/src/main/kotlin/features/mining/CommissionFeatures.kt
+++ b/src/main/kotlin/features/mining/CommissionFeatures.kt
@@ -20,8 +20,7 @@ object CommissionFeatures {
if (MC.screenName != "Commissions") return
val stack = event.slot.stack
if(stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) {
- event.context.drawSprite(
- event.slot.x, event.slot.y, 0, 16, 16,
+ event.highlight(
MC.guiAtlasManager.getSprite(Identifier.of("firmament:completed_commission_background"))
)
}
diff --git a/src/main/kotlin/features/mining/HotmPresets.kt b/src/main/kotlin/features/mining/HotmPresets.kt
new file mode 100644
index 0000000..329ff77
--- /dev/null
+++ b/src/main/kotlin/features/mining/HotmPresets.kt
@@ -0,0 +1,241 @@
+package moe.nea.firmament.features.mining
+
+import me.shedaniel.math.Rectangle
+import kotlinx.serialization.Serializable
+import kotlin.time.Duration.Companion.seconds
+import net.minecraft.block.Blocks
+import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.gui.screen.ingame.HandledScreen
+import net.minecraft.entity.player.PlayerInventory
+import net.minecraft.item.Items
+import net.minecraft.screen.GenericContainerScreenHandler
+import net.minecraft.screen.ScreenHandler
+import net.minecraft.screen.slot.Slot
+import net.minecraft.screen.slot.SlotActionType
+import net.minecraft.text.Text
+import moe.nea.firmament.Firmament
+import moe.nea.firmament.annotations.Subscribe
+import moe.nea.firmament.commands.thenExecute
+import moe.nea.firmament.events.ChestInventoryUpdateEvent
+import moe.nea.firmament.events.CommandEvent
+import moe.nea.firmament.events.ScreenChangeEvent
+import moe.nea.firmament.events.SlotRenderEvents
+import moe.nea.firmament.gui.config.ManagedConfig
+import moe.nea.firmament.mixins.accessor.AccessorHandledScreen
+import moe.nea.firmament.util.ClipboardUtils
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.TemplateUtil
+import moe.nea.firmament.util.TimeMark
+import moe.nea.firmament.util.customgui.CustomGui
+import moe.nea.firmament.util.customgui.customGui
+import moe.nea.firmament.util.mc.CommonTextures
+import moe.nea.firmament.util.mc.displayNameAccordingToNbt
+import moe.nea.firmament.util.unformattedString
+import moe.nea.firmament.util.useMatch
+
+object HotmPresets {
+ object Config : ManagedConfig("hotm-presets", Category.MINING) {
+ }
+
+ val SHARE_PREFIX = "FIRMHOTM/"
+
+ @Serializable
+ data class HotmPreset(
+ val perks: List<PerkPreset>,
+ )
+
+ @Serializable
+ data class PerkPreset(val perkName: String)
+
+ var hotmCommandSent = TimeMark.farPast()
+ val hotmInventoryName = "Heart of the Mountain"
+
+ @Subscribe
+ fun onScreenOpen(event: ScreenChangeEvent) {
+ val title = event.new?.title?.unformattedString
+ if (title != hotmInventoryName) return
+ val screen = event.new as? HandledScreen<*> ?: return
+ val oldHandler = (event.old as? HandledScreen<*>)?.customGui
+ if (oldHandler is HotmScrollPrompt) {
+ event.new.customGui = oldHandler
+ oldHandler.setNewScreen(screen)
+ return
+ }
+ if (hotmCommandSent.passedTime() > 5.seconds) return
+ hotmCommandSent = TimeMark.farPast()
+ screen.customGui = HotmScrollPrompt(screen)
+ }
+
+ class HotmScrollPrompt(var screen: HandledScreen<*>) : CustomGui() {
+ var bounds = Rectangle(
+ 0, 0, 0, 0
+ )
+
+ fun setNewScreen(screen: HandledScreen<*>) {
+ this.screen = screen
+ onInit()
+ hasScrolled = false
+ }
+
+ override fun render(drawContext: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {
+ drawContext.drawGuiTexture(
+ CommonTextures.genericWidget(),
+ bounds.x, bounds.y, 0,
+ bounds.width,
+ bounds.height,
+ )
+ drawContext.drawCenteredTextWithShadow(
+ MC.font,
+ if (hasAll) {
+ Text.translatable("firmament.hotmpreset.copied")
+ } else if (!hasScrolled) {
+ Text.translatable("firmament.hotmpreset.scrollprompt")
+ } else {
+ Text.translatable("firmament.hotmpreset.scrolled")
+ },
+ bounds.centerX,
+ bounds.centerY - 5,
+ -1
+ )
+ }
+
+
+ var hasScrolled = false
+ var hasAll = false
+
+ fun Slot.clickMiddleMouseButton(handler: ScreenHandler) {
+ MC.interactionManager?.clickSlot(
+ handler.syncId,
+ this.id,
+ 2,
+ SlotActionType.CLONE,
+ MC.player
+ )
+ }
+
+ fun Slot.clickRightMouseButton(handler: ScreenHandler) {
+ MC.interactionManager?.clickSlot(
+ handler.syncId,
+ this.id,
+ 1,
+ SlotActionType.PICKUP,
+ MC.player
+ )
+ }
+
+ override fun mouseClick(mouseX: Double, mouseY: Double, button: Int): Boolean {
+ if (!hasScrolled) {
+ val slot = screen.screenHandler.getSlot(8)
+ println("Clicking ${slot.stack}")
+ slot.clickRightMouseButton(screen.screenHandler)
+ }
+ hasScrolled = true
+ return super.mouseClick(mouseX, mouseY, button)
+ }
+
+ override fun shouldDrawForeground(): Boolean {
+ return false
+ }
+
+ override fun getBounds(): List<Rectangle> {
+ return listOf(bounds)
+ }
+
+ override fun onInit() {
+ bounds = Rectangle(
+ screen.width / 2 - 150,
+ screen.height / 2 - 100,
+ 300, 200
+ )
+ val screen = screen as AccessorHandledScreen
+ screen.x_Firmament = bounds.x
+ screen.y_Firmament = bounds.y
+ screen.backgroundWidth_Firmament = bounds.width
+ screen.backgroundHeight_Firmament = bounds.height
+ }
+
+ override fun moveSlot(slot: Slot) {
+ slot.x = -10000
+ }
+
+ val coveredRows = mutableSetOf<Int>()
+ val unlockedPerks = mutableSetOf<String>()
+ val allRows = (1..10).toSet()
+
+ fun onNewItems(event: ChestInventoryUpdateEvent) {
+ val handler = screen.screenHandler as? GenericContainerScreenHandler ?: return
+ for (it in handler.slots) {
+ if (it.inventory is PlayerInventory) continue
+ val stack = it.stack
+ val name = stack.displayNameAccordingToNbt.unformattedString
+ tierRegex.useMatch(name) {
+ coveredRows.add(group("tier").toInt())
+ }
+ if (stack.item == Items.DIAMOND
+ || stack.item == Items.EMERALD
+ || stack.item == Blocks.EMERALD_BLOCK.asItem()
+ ) {
+ unlockedPerks.add(name)
+ }
+ }
+ if (allRows == coveredRows) {
+ ClipboardUtils.setTextContent(TemplateUtil.encodeTemplate(SHARE_PREFIX, HotmPreset(
+ unlockedPerks.map { PerkPreset(it) }
+ )))
+ hasAll = true
+ }
+ }
+ }
+
+ val tierRegex = "Tier (?<tier>[0-9]+)".toPattern()
+ var highlightedPerks: Set<String> = emptySet()
+
+ @Subscribe
+ fun onSlotUpdates(event: ChestInventoryUpdateEvent) {
+ val customGui = (event.inventory as? HandledScreen<*>)?.customGui
+ if (customGui is HotmScrollPrompt) {
+ customGui.onNewItems(event)
+ }
+ }
+
+ @Subscribe
+ fun resetOnScreen(event: ScreenChangeEvent) {
+ if (event.new != null && event.new.title.unformattedString != hotmInventoryName) {
+ highlightedPerks = emptySet()
+ }
+ }
+
+ @Subscribe
+ fun onSlotRender(event: SlotRenderEvents.Before) {
+ if (hotmInventoryName == MC.screenName
+ && event.slot.stack.displayNameAccordingToNbt.unformattedString in highlightedPerks
+ ) {
+ event.highlight(MC.guiAtlasManager.getSprite(Firmament.identifier("hotm_perk_preset")))
+ }
+ }
+
+ @Subscribe
+ fun onCommand(event: CommandEvent.SubCommand) {
+ event.subcommand("exporthotm") {
+ thenExecute {
+ hotmCommandSent = TimeMark.now()
+ MC.sendCommand("hotm")
+ source.sendFeedback(Text.translatable("firmament.hotmpreset.openinghotm"))
+ }
+ }
+ event.subcommand("importhotm") {
+ thenExecute {
+ val template =
+ TemplateUtil.maybeDecodeTemplate<HotmPreset>(SHARE_PREFIX, ClipboardUtils.getTextContents())
+ if (template == null) {
+ source.sendFeedback(Text.translatable("firmament.hotmpreset.failedimport"))
+ } else {
+ highlightedPerks = template.perks.mapTo(mutableSetOf()) { it.perkName }
+ source.sendFeedback(Text.translatable("firmament.hotmpreset.okayimport"))
+ MC.sendCommand("hotm")
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/kotlin/util/TemplateUtil.kt b/src/main/kotlin/util/TemplateUtil.kt
index 11100e9..f4ff37c 100644
--- a/src/main/kotlin/util/TemplateUtil.kt
+++ b/src/main/kotlin/util/TemplateUtil.kt
@@ -5,6 +5,7 @@ package moe.nea.firmament.util
import java.util.*
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
+import kotlinx.serialization.json.Json
import kotlinx.serialization.serializer
import moe.nea.firmament.Firmament
@@ -61,7 +62,7 @@ object TemplateUtil {
fun <T> encodeTemplate(sharePrefix: String, data: T, serializer: SerializationStrategy<T>): String {
require(sharePrefix.endsWith("/"))
- return intoBase64Encoded(sharePrefix + Firmament.json.encodeToString(serializer, data))
+ return intoBase64Encoded(sharePrefix + Firmament.tightJson.encodeToString(serializer, data))
}
inline fun <reified T : Any> maybeDecodeTemplate(sharePrefix: String, data: String): T? =
diff --git a/src/main/kotlin/util/mc/CommonTextures.kt b/src/main/kotlin/util/mc/CommonTextures.kt
new file mode 100644
index 0000000..6b847df
--- /dev/null
+++ b/src/main/kotlin/util/mc/CommonTextures.kt
@@ -0,0 +1,7 @@
+package moe.nea.firmament.util.mc
+
+import moe.nea.firmament.Firmament
+
+object CommonTextures {
+ fun genericWidget() = (Firmament.identifier("generic_vanilla_widget"))
+}
diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json
index eb0e551..1f2bbeb 100644
--- a/src/main/resources/assets/firmament/lang/en_us.json
+++ b/src/main/resources/assets/firmament/lang/en_us.json
@@ -94,6 +94,12 @@
"firmament.config.category.meta": "Meta & Firmament",
"firmament.config.category.dev": "Developer & Debug",
"firmament.ursa.debugrequest.start": "Ursa request launched",
+ "firmament.hotmpreset.openinghotm": "Opening /hotm menu for export.",
+ "firmament.hotmpreset.scrollprompt": "We need to scroll! Please click anywhere to continue.",
+ "firmament.hotmpreset.scrolled": "Just scrolled. Waiting on server to update items.",
+ "firmament.hotmpreset.copied": "Collected all HOTM perks to clipboard. Use /firm importhotm to import.",
+ "firmament.hotmpreset.okayimport": "Imported a HOTM perk preset.",
+ "firmament.hotmpreset.failedimport": "Could not find a HOTM perk preset in your clipboard. You can export your current HOTM perks with /firm exporthotm",
"firmament.ursa.debugrequest.result": "Ursa request succeeded: %s",
"firmament.sbinfo.nolocraw": "No locraw data available",
"firmament.sbinfo.profile": "Current profile cutename: %s",
diff --git a/src/main/resources/assets/firmament/textures/gui/sprites/generic_vanilla_widget.png b/src/main/resources/assets/firmament/textures/gui/sprites/generic_vanilla_widget.png
new file mode 100644
index 0000000..83fae16
--- /dev/null
+++ b/src/main/resources/assets/firmament/textures/gui/sprites/generic_vanilla_widget.png
Binary files differ
diff --git a/src/main/resources/assets/firmament/textures/gui/sprites/generic_vanilla_widget.png.mcmeta b/src/main/resources/assets/firmament/textures/gui/sprites/generic_vanilla_widget.png.mcmeta
new file mode 100644
index 0000000..9d84425
--- /dev/null
+++ b/src/main/resources/assets/firmament/textures/gui/sprites/generic_vanilla_widget.png.mcmeta
@@ -0,0 +1,10 @@
+{
+ "gui": {
+ "scaling": {
+ "type": "nine_slice",
+ "width": 24,
+ "height": 41,
+ "border": 5
+ }
+ }
+}
diff --git a/src/main/resources/assets/firmament/textures/gui/sprites/hotm_perk_preset.png b/src/main/resources/assets/firmament/textures/gui/sprites/hotm_perk_preset.png
new file mode 100644
index 0000000..a19f227
--- /dev/null
+++ b/src/main/resources/assets/firmament/textures/gui/sprites/hotm_perk_preset.png
Binary files differ