diff --git a/src/main/kotlin/at/raven/ravenAddons/config/ravenAddonsConfig.kt b/src/main/kotlin/at/raven/ravenAddons/config/ravenAddonsConfig.kt index afa2f06d..c06455af 100644 --- a/src/main/kotlin/at/raven/ravenAddons/config/ravenAddonsConfig.kt +++ b/src/main/kotlin/at/raven/ravenAddons/config/ravenAddonsConfig.kt @@ -1,7 +1,9 @@ package at.raven.ravenAddons.config +import at.raven.ravenAddons.config.guieditor.data.GuiPosition import gg.essential.vigilance.Vigilant import gg.essential.vigilance.data.Property +import gg.essential.vigilance.data.PropertyInfo import gg.essential.vigilance.data.PropertyType import java.awt.Color import kotlin.reflect.KProperty @@ -66,6 +68,38 @@ object ravenAddonsConfig : Vigilant( ) var highlightRequiredPantsType = false + @Property( + type = PropertyType.SWITCH, + name = "Upcoming Events Display", + description = "Displays a list of upcoming events.", + category = "Pit", + subcategory = "Events" + ) + var upcomingEventsDisplay = false + + @Property( + type = PropertyType.NUMBER, + name = "Upcoming Events Display Amount", + description = "Choose the amount of events that should be display in the upcoming events display.", + category = "Pit", + subcategory = "Events", + min = 1, + max = 50, + increment = 1 + ) + var upcomingEventsDisplayAmount = 10 + + @Property( + type = PropertyType.CUSTOM, + name = "Upcoming Events Display Position", + description = "Where to display the upcoming events display.", + category = "Pit", + subcategory = "Events", + hidden = true, + customPropertyInfo = PropertyInfo::class + ) + var upcomingEventsDisplayPosition = GuiPosition() + @Property( type = PropertyType.SWITCH, name = "DROP Alerts", @@ -509,6 +543,7 @@ object ravenAddonsConfig : Vigilant( this::carePackageHighlighterColour requires this::carePackageHighlighter this::highlightRequiredPantsType requires this::requiredPantsType + this::upcomingEventsDisplayAmount requires this::upcomingEventsDisplay this::dropAlertUserName requires this::dropAlert diff --git a/src/main/kotlin/at/raven/ravenAddons/features/pit/UpcomingEventsDisplay.kt b/src/main/kotlin/at/raven/ravenAddons/features/pit/UpcomingEventsDisplay.kt new file mode 100644 index 00000000..a3eea868 --- /dev/null +++ b/src/main/kotlin/at/raven/ravenAddons/features/pit/UpcomingEventsDisplay.kt @@ -0,0 +1,104 @@ +package at.raven.ravenAddons.features.pit + +import at.raven.ravenAddons.config.ravenAddonsConfig +import at.raven.ravenAddons.data.HypixelGame +import at.raven.ravenAddons.event.GameLoadEvent +import at.raven.ravenAddons.event.render.RenderOverlayEvent +import at.raven.ravenAddons.loadmodule.LoadModule +import at.raven.ravenAddons.utils.APIUtils +import at.raven.ravenAddons.utils.SimpleTimeMark +import at.raven.ravenAddons.utils.render.GuiRenderUtils.renderStrings +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration +import kotlin.time.DurationUnit + +@LoadModule +object UpcomingEventsDisplay { + + private var eventCache = mutableListOf() + private var initialized = false + private val gson = Gson() + + private val actualEventNames = mapOf( + "All bounty" to "§6Everyone Gets a Bounty", + "Quick Maths" to "§dQuick Maths", + "Dragon Egg" to "§dDragon Egg", + "2x Rewards" to "§22x Rewards", + "Care Package" to "§6Care Package", + "KOTL" to "§aKing of the Ladder", + "KOTH" to "§bKing of the Hill", + "Auction" to "§eAuction", + "Giant Cake" to "§dGiant Cake", + "Squads" to "§bSquads", + "Beast" to "§aBeast", + "Pizza" to "§cPizza", + "Rage Pit" to "§cRage Pit", + "Spire" to "§dSpire", + "Robbery" to "§6Robbery", + "Blockhead" to "§9Blockhead", + "Raffle" to "§6Raffle", + "Team Deathmatch" to "§dTeam Deathmatch", + ) + + private data class PitEventData( + val event: String, + val timestamp: Long, + val type: String, + ) + + + @SubscribeEvent + fun onGameLoaded(event: GameLoadEvent) { + if (!ravenAddonsConfig.upcomingEventsDisplay) return + getPitEventData() + initialized = true + } + + @SubscribeEvent + fun onRenderOverlay(event: RenderOverlayEvent) { + if (!HypixelGame.inPit || !ravenAddonsConfig.upcomingEventsDisplay) return + if (eventCache.isEmpty() && !initialized) getPitEventData().also { initialized = true } + + updatePitEventData() + ravenAddonsConfig.upcomingEventsDisplayPosition.renderStrings(buildDisplay(), "upcomingEventsDisplay") + } + + private fun buildDisplay(): List { + val nextEvents = eventCache.take(ravenAddonsConfig.upcomingEventsDisplayAmount) + + return buildList { + nextEvents.forEach { eventData -> + val timeUntil = eventData.timestamp.toSimpleTimeMark().timeUntil() + val formattedName = actualEventNames[eventData.event] ?: eventData.event + + add("$formattedName §7- ${timeUntil.getDurationString()}") + } + } + } + + private fun Duration.getDurationString(): String { + return when { + inWholeMinutes <= 0L -> toString(DurationUnit.SECONDS) + inWholeMinutes in 1L..59L -> toString(DurationUnit.MINUTES) + inWholeMinutes in 60L..1439L -> "${inWholeHours}h ${inWholeMinutes % 60}m" + else -> "${inWholeDays}d ${inWholeHours % 24}h" + } + } + + private fun getPitEventData() { + val rawData = + APIUtils.getJsonArrayResponse("https://raw.githubusercontent.com/BrookeAFK/brookeafk-api/main/events.js") ?: return + + val parsedEvents: List = gson.fromJson(rawData, object : TypeToken>() {}.type) + + eventCache += parsedEvents.filterNot { + it.timestamp.toSimpleTimeMark().isInPast() + } + } + + private fun updatePitEventData() = eventCache.removeAll { SimpleTimeMark(it.timestamp).isInPast() } + + private fun Long.toSimpleTimeMark() = SimpleTimeMark(this) +} diff --git a/src/main/kotlin/at/raven/ravenAddons/utils/render/GuiRenderUtils.kt b/src/main/kotlin/at/raven/ravenAddons/utils/render/GuiRenderUtils.kt index 22799ce5..0007c6be 100644 --- a/src/main/kotlin/at/raven/ravenAddons/utils/render/GuiRenderUtils.kt +++ b/src/main/kotlin/at/raven/ravenAddons/utils/render/GuiRenderUtils.kt @@ -112,4 +112,35 @@ object GuiRenderUtils { fontRenderer.drawString(string, 0f, 0f, Color.WHITE.rgb, dropShadow) GlStateManager.popMatrix() } + + fun GuiPosition.renderStrings( + strings: List, + label: String, + yOffset: Int = 0, + dropShadow: Boolean = true, + ) { + if (strings.isEmpty()) return + val fontRenderer = fontRenderer + + val maxWidth = fontRenderer.getStringWidth(strings.maxBy { it.length }) * scale + val stringHeight = 10 * scale + val totalHeight = stringHeight * strings.size + + GuiPositionEditorManager.add( + this, + label, + maxWidth.toInt(), + totalHeight.toInt(), + ) + + GlStateManager.pushMatrix() + GlStateManager.translate(x.toFloat(), (y + yOffset).toFloat(), 0f) + GlStateManager.scale(scale, scale, scale) + var top = 0.0 + strings.forEach { + fontRenderer.drawString(it, 0f, top.toFloat(), Color.WHITE.rgb, dropShadow).also { top += stringHeight } + } + + GlStateManager.popMatrix() + } }