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.slot.Slot 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.SlotUtils.clickRightMouseButton import moe.nea.firmament.util.mc.displayNameAccordingToNbt import moe.nea.firmament.util.render.drawGuiTexture 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, 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 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((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") } } } } }