diff --git a/src/main/java/at/hannibal2/skyhanni/data/NotificationManager.kt b/src/main/java/at/hannibal2/skyhanni/data/NotificationManager.kt new file mode 100644 index 000000000000..748e46892865 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/NotificationManager.kt @@ -0,0 +1,112 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.api.event.HandleEvent +import at.hannibal2.skyhanni.config.commands.CommandCategory +import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzKeyPressEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.GuiRenderUtils +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.TimeUtils.format +import at.hannibal2.skyhanni.utils.compat.GuiScreenUtils +import io.github.notenoughupdates.moulconfig.internal.RenderUtils +import net.minecraft.client.Minecraft +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import org.lwjgl.input.Keyboard +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds + +@SkyHanniModule +object NotificationManager { + + private val notificationQueue = mutableListOf() + + private var currentNotification: SkyHanniNotification? = null + private var lastNotificationClosed = SimpleTimeMark.farPast() + + private const val CLOSE_TEXT = "§c[X] Close" + + @SubscribeEvent + fun onKeyClick(event: LorenzKeyPressEvent) { + currentNotification ?: return + if (lastNotificationClosed.passedSince() < 200.milliseconds) return + if (event.keyCode != Keyboard.KEY_X) return + currentNotification = null + lastNotificationClosed = SimpleTimeMark.now() + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent) { + val notification = getCurrentNotification() ?: return + + if (InventoryUtils.inInventory() && !notification.showOverInventory) return + + val midX = GuiScreenUtils.scaledWindowWidth / 2 + val topY = (GuiScreenUtils.scaledWindowHeight * 0.75 - notification.height / 2).toInt() + + RenderUtils.drawFloatingRectDark(midX - notification.width / 2, topY, notification.width, notification.height) + val closeTextWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(CLOSE_TEXT) + + GuiRenderUtils.drawString(CLOSE_TEXT, midX + notification.width / 2 - 3 - closeTextWidth, topY + 4) + + if (notification.length.isFinite()) { + val remainingTime = "§8" + notification.endTime.timeUntil().format() + GuiRenderUtils.drawString(remainingTime, midX - notification.width / 2 + 4, topY + 4) + } + + notification.message.forEachIndexed { index, line -> + GuiRenderUtils.drawStringCentered("§7$line", midX, topY + 19 + index * 10) + } + } + + private fun getCurrentNotification(): SkyHanniNotification? { + currentNotification?.let { + if (it.endTime.isInPast()) currentNotification = null + } + if (currentNotification == null) { + currentNotification = notificationQueue.removeFirstOrNull() + currentNotification?.setEndTime() + } + return currentNotification + } + + fun queueNotification(notification: SkyHanniNotification) { + notificationQueue.add(notification) + } + + @HandleEvent + fun onCommandRegistration(event: CommandRegistrationEvent) { + event.register("shtestnotification") { + description = "Shows a test notification" + category = CommandCategory.DEVELOPER_TEST + callback { + val testingText = it.joinToString(" ").replace("\\n", "\n") + queueNotification(SkyHanniNotification(testingText, Duration.INFINITE)) + } + } + } +} + +data class SkyHanniNotification( + val message: List, + val length: Duration, + val showOverInventory: Boolean = false, +) { + constructor(message: String, length: Duration, showOverInventory: Boolean = false) : this( + message.lines(), + length, + showOverInventory, + ) + + var endTime = SimpleTimeMark.farFuture() + + val width by lazy { (message.maxOfOrNull { Minecraft.getMinecraft().fontRendererObj.getStringWidth(it) } ?: 0) + 8 } + val height by lazy { message.size * 10 + 18 } + + fun setEndTime() { + if (length.isInfinite()) return + endTime = SimpleTimeMark.now() + length + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt index d39b37c8abb1..1198ed7ae6a2 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt @@ -1,6 +1,8 @@ package at.hannibal2.skyhanni.utils +import at.hannibal2.skyhanni.data.NotificationManager import at.hannibal2.skyhanni.data.PetAPI +import at.hannibal2.skyhanni.data.SkyHanniNotification import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.features.misc.items.EstimatedItemValueCalculator.getAttributeName import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -19,8 +21,6 @@ import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.isRecombobulated import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.StringUtils.removeResets import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import com.google.common.collect.Lists -import io.github.moulberry.notenoughupdates.util.NotificationHandler import net.minecraft.client.Minecraft import net.minecraft.init.Items import net.minecraft.item.Item @@ -32,6 +32,8 @@ import net.minecraftforge.common.util.Constants import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.util.LinkedList import java.util.regex.Matcher +import kotlin.time.Duration.Companion.INFINITE +import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds @SkyHanniModule @@ -40,6 +42,7 @@ object ItemUtils { private val itemNameCache = mutableMapOf() // internal name -> item name private val missingRepoItems = mutableSetOf() + private var lastRepoWarning = SimpleTimeMark.farPast() fun ItemStack.cleanName() = this.displayName.removeColor() @@ -544,20 +547,19 @@ object ItemUtils { fun addMissingRepoItem(name: String, message: String) { if (!missingRepoItems.add(name)) return ChatUtils.debug(message) -// showRepoWarning() + + if (lastRepoWarning.passedSince() < 3.minutes) return + lastRepoWarning = SimpleTimeMark.now() + showRepoWarning(name) } - // Running NEU's function `Utils.showOutdatedRepoNotification()` caused a NoSuchMethodError in dev env. - // Therefore we run NotificationHandler.displayNotification directly - private fun showRepoWarning() { - NotificationHandler.displayNotification( - Lists.newArrayList( - "§c§lMissing repo data", - "§cData used for some SkyHanni features is not up to date, this should normally not be the case.", - "§cYou can try §l/neuresetrepo§r§c and restart your game to see if that fixes the issue.", - "§cIf the problem persists please join the SkyHanni Discord and message in §l#support§r§c to get support.", - ), - true, true, + private fun showRepoWarning(item: String) { + val text = listOf( + "§c§lMissing repo data for item: $item", + "§cData used for some SkyHanni features is not up to date, this should normally not be the case.", + "§cYou can try §l/neuresetrepo§r§c and restart your game to see if that fixes the issue.", + "§cIf the problem persists please join the SkyHanni Discord and message in §l#support§r§c to get support.", ) + NotificationManager.queueNotification(SkyHanniNotification(text, INFINITE, true)) } }