aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/CountdownCalculator.kt
blob: 68d7a30177a63d0043181ebd7ea574e1bedd554d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright (C) 2022-2024 NotEnoughUpdates contributors
 *
 * This file is part of NotEnoughUpdates.
 *
 * NotEnoughUpdates is free software: you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * NotEnoughUpdates is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
 */
package io.github.moulberry.notenoughupdates.miscfeatures

import io.github.moulberry.notenoughupdates.NotEnoughUpdates
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe
import net.minecraft.client.Minecraft
import net.minecraftforge.event.entity.player.ItemTooltipEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.util.*

/*
   CountdownCalculator.kt
   A Kotlin class by:
   — Erymanthus / RayDeeUx (code base, math, timestamp wrangling, adaptation into overall NEU codebase)
   — nea89 (enum, regex wrangling, ItemTooltipEvent integration, cleanup)
   
   Intended to detect countdowns within item tooltips and then adding that result
   to the user's current system time in Unix epoch form converted into a
   human-readable timestamp relative to the system timezone.
   
   Formerly a feature from SkyBlockCatia, then later attempted to be ported into Skytils.
   Now has a comfy home in the NotEnoughUpdates codebase.
 */

@NEUAutoSubscribe
class CountdownCalculator {

    private val regex =
        "(?:(?<years>\\d+)y )?(?:(?<days>\\d+)d)? ?(?:(?<hours>\\d+)h)? ?(?:(?<minutes>\\d+)m)? ?(?:(?<seconds>\\d+)s)?\\b".toRegex()

    @Suppress("unused")
    private enum class CountdownTypes(
        val match: String,
        val label: String,
        val isRelative: Boolean = false,
    ) {
        STARTING("Starting in:", "Starts at"),
        STARTS("Starts in:", "Starts at"),
        INTEREST("Interest in:", "Interest at"),
        UNTILINTEREST("Until interest:", "Interest at"),
        ENDS("Ends in:", "Ends at"),
        REMAINING("Remaining:", "Ends at"),
        DURATION("Duration:", "Finishes at"),
        TIMELEFT("Time left:", "Ends at"),
        EVENTTIMELEFT("Event lasts for", "Ends at", isRelative = true),
        SHENSUCKS("Auction ends in:", "Auction ends at"),
        TAMINGSIXTYWASAMISTAKE(
            "Ends:",
            "Finishes at"
        ), // There would be a more specific message here seeing as this is for pet XP, but knowing Hypixel it's probably safer to leave it like this in case they use the "Ends:" prefix elsewhere besides the pet training menus.
        CALENDARDETAILS(" (§e", "Starts at"), // calendar details
        COMMUNITYPROJECTSSUCK("Contribute again", "Come back at"), // nopo i just woke up i really hope this works
        CHOCOLATEFACTORY("Next Charge", "Available at"),
        STONKSAUCTION("Auction ends in", "Ends at");
    }

    @SubscribeEvent
    fun onTooltip(event: ItemTooltipEvent) {
        var formatterAsString = when (NotEnoughUpdates.INSTANCE.config.misc.showWhenCountdownEnds) {
            1 -> "EEEE, MMM d h:mm a"
            2 -> "EEEE, MMM d HH:mm"
            else -> return
        }
        if (event.itemStack != null && Minecraft.getMinecraft().thePlayer?.openContainer != null) {
            var i = -1
            var lastTimer: ZonedDateTime? = null
            while (++i < event.toolTip.size) {
                val tooltipLine = event.toolTip[i]
                val countdownKind = CountdownTypes.values().find { it.match in tooltipLine } ?: continue
                val match = regex.findAll(tooltipLine).maxByOrNull { it.value.length } ?: continue
                if (countdownKind == CountdownTypes.CALENDARDETAILS && !event.itemStack.displayName.startsWith("§aDay ")) return
                val years = match.groups["years"]?.value?.toLong() ?: 0L
                val days = match.groups["days"]?.value?.toLong() ?: 0L
                val hours = match.groups["hours"]?.value?.toLong() ?: 0L
                val minutes = match.groups["minutes"]?.value?.toLong() ?: 0L
                val seconds = match.groups["seconds"]?.value?.toLong() ?: 0L
                val totalSeconds =
                    (years * 31_536_000L) + (days * 86_400L) + (hours * 3_600L) + (minutes * 60L) + seconds
                if (totalSeconds == 0L) continue
                if (years != 0L) formatterAsString = "${formatterAsString} yyyy"
                var useFormatter = DateTimeFormatter.ofPattern(formatterAsString)!!
                val countdownTarget = if (countdownKind.isRelative) {
                    if (lastTimer == null) {
                        event.toolTip.add(
                            ++i,
                            "§r§cThe above countdown is relative, but I can't find another countdown. [NEU]"
                        )
                        continue
                    } else lastTimer.addTime(years, days, hours, minutes, seconds)
                } else ZonedDateTime.now().addTime(years, days, hours, minutes, seconds)
                if (NotEnoughUpdates.INSTANCE.config.misc.useEnglishCountdown) useFormatter = useFormatter.withLocale(
                    Locale.ENGLISH
                )
                val countdownTargetFormatted = useFormatter.format(countdownTarget)
                event.toolTip.add(
                    ++i,
                    "§r§b${countdownKind.label}: $countdownTargetFormatted"
                )
                lastTimer = countdownTarget
            }
        }
    }

    private fun ZonedDateTime.addTime(
        years: Long,
        days: Long,
        hours: Long,
        minutes: Long,
        seconds: Long
    ): ZonedDateTime {
        return this.plusYears(years).plusDays(days).plusHours(hours).plusMinutes(minutes).plusSeconds(seconds)
    }
}