From 854ec336cc6a0a3bb60f33acfac28ed45b491a15 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Mon, 14 Oct 2024 00:07:21 +0200 Subject: Add /firm exporthotm to save hotm presets --- .../kotlin/features/mining/CommissionFeatures.kt | 3 +- src/main/kotlin/features/mining/HotmPresets.kt | 241 +++++++++++++++++++++ 2 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/features/mining/HotmPresets.kt (limited to 'src/main/kotlin/features') 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, + ) + + @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 { + 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() + val unlockedPerks = mutableSetOf() + 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 (?[0-9]+)".toPattern() + var highlightedPerks: Set = 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(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") + } + } + } + } + +} -- cgit