diff options
author | David Cole <40234707+DavidArthurCole@users.noreply.github.com> | 2024-09-08 03:29:27 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-08 09:29:27 +0200 |
commit | 3db3627ec03baa134940a92e596e591f2d88aa0c (patch) | |
tree | 1914554bf7e8b6b898e75213c0ba218c670afa16 | |
parent | 9352ace3e97c92645b176f88b6cef6e638121b95 (diff) | |
download | skyhanni-3db3627ec03baa134940a92e596e591f2d88aa0c.tar.gz skyhanni-3db3627ec03baa134940a92e596e591f2d88aa0c.tar.bz2 skyhanni-3db3627ec03baa134940a92e596e591f2d88aa0c.zip |
Feature: Hoppity Call Warning (#2272)
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
5 files changed, 220 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityCallWarningConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityCallWarningConfig.java new file mode 100644 index 000000000..6e4ccf027 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityCallWarningConfig.java @@ -0,0 +1,47 @@ +package at.hannibal2.skyhanni.config.features.event.hoppity; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.utils.OSUtils; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorButton; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorColour; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorKeybind; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorText; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import io.github.notenoughupdates.moulconfig.observer.Property; +import org.lwjgl.input.Keyboard; + +public class HoppityCallWarningConfig { + + @Expose + @ConfigOption(name = "Hoppity Call Warning", desc = "Warn when hoppity is calling you.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = true; + + @Expose + @ConfigOption( + name = "Accept Call Hotkey", + desc = "Accept the call from hoppity by pressing this keybind." + ) + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE) + public int acceptHotkey = Keyboard.KEY_NONE; + + @Expose + @ConfigOption(name = "Warning Sound", desc = "The sound that plays when hoppity calls.\n" + + "§eYou can use custom sounds, put it in the §bskyhanni/sounds §efolder in your resource pack.\n" + + "§eThen write §bskyhanni:yourfilename\n" + + "§cMust be a .ogg file") + @ConfigEditorText + public Property<String> hoppityCallSound = Property.of("note.pling"); + + @Expose + @ConfigOption(name = "Flash Color", desc = "Color of the screen when flashing") + @ConfigEditorColour + public String flashColor = "0:127:0:238:255"; + + @ConfigOption(name = "Sounds", desc = "Click to open the list of available sounds.") + @ConfigEditorButton(buttonText = "OPEN") + public Runnable sounds = () -> OSUtils.openBrowser("https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2213619-1-8-all-playsound-sound-arguments"); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java index 50a5731a5..c270dae8b 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java @@ -15,6 +15,11 @@ import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; public class HoppityEggsConfig { @Expose + @ConfigOption(name = "Hoppity Abiphone Calls", desc = "") + @Accordion + public HoppityCallWarningConfig hoppityCallWarning = new HoppityCallWarningConfig(); + + @Expose @ConfigOption(name = "Event Summary", desc = "") @Accordion public HoppityEventSummaryConfig eventSummary = new HoppityEventSummaryConfig(); diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCallWarning.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCallWarning.kt new file mode 100644 index 000000000..57bc0975f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCallWarning.kt @@ -0,0 +1,155 @@ +package at.hannibal2.skyhanni.features.event.hoppity + +import at.hannibal2.skyhanni.events.ConfigLoadEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.LorenzKeyPressEvent +import at.hannibal2.skyhanni.events.SecondPassedEvent +import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ColorUtils.toChromaColorInt +import at.hannibal2.skyhanni.utils.ConditionalUtils +import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.HypixelCommands +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.SoundUtils +import at.hannibal2.skyhanni.utils.StringUtils.isValidUuid +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Gui +import net.minecraft.client.renderer.GlStateManager +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import org.lwjgl.input.Keyboard +import java.time.Instant +import kotlin.math.sin +import kotlin.time.Duration.Companion.seconds + +@SkyHanniModule +object HoppityCallWarning { + + /** + * Test messages (and the real ones from Hypixel) have a space at the end of + * them that the IDE kills. So it's "§r§e ✆ " + * + * REGEX-TEST: §e✆ §r§bHoppity§r§e ✆ + * REGEX-TEST: §e✆ §r§aHoppity§r§e ✆ + */ + private val initHoppityCallPattern by ChocolateFactoryAPI.patternGroup.pattern( + "hoppity.call.init", + "§e✆ §r(?:§a|§b)Hoppity§r§e ✆.*", + ) + + /** + * REGEX-TEST: §a✆ RING... §r §r§2§l[PICK UP] + * REGEX-TEST: §a✆ RING... RING... §r §r§2§l[PICK UP] + * REGEX-TEST: §a✆ RING... RING... RING... §r §r§2§l[PICK UP] + * REGEX-TEST: §a✆ RING... RING... RING... + */ + private val callRingPattern by ChocolateFactoryAPI.patternGroup.pattern( + "hoppity.call.ring", + "§a✆ (?:RING\\.{3} ?){1,3}(?:§r §r§2§l\\[PICK UP])?", + ) + + /** + * REGEX-TEST: §e[NPC] §aHoppity§f: §b✆ §f§rWhat's up, §boBlazin§f? + */ + private val pickupHoppityCallPattern by ChocolateFactoryAPI.patternGroup.pattern( + "hoppity.call.pickup", + "§e\\[NPC] §aHoppity§f: §b✆ §f§rWhat's up, .*§f\\?", + ) + + private val config get() = HoppityEggsManager.config.hoppityCallWarning + private var warningSound = SoundUtils.createSound("note.pling", 1f) + private var activeWarning = false + private var nextWarningTime: Instant? = null + private var finalWarningTime: Instant? = null + private val callLength = 7.seconds + private var acceptUUID: String? = null + + @SubscribeEvent + fun onKeyPress(event: LorenzKeyPressEvent) { + if (config.acceptHotkey == Keyboard.KEY_NONE || config.acceptHotkey != event.keyCode) return + acceptUUID?.let { + HypixelCommands.callback(acceptUUID!!) + acceptUUID = null + } + } + + @SubscribeEvent + fun onConfigLoad(event: ConfigLoadEvent) { + val soundProperty = config.hoppityCallSound + ConditionalUtils.onToggle(soundProperty) { + warningSound = SoundUtils.createSound(soundProperty.get(), 1f) + } + nextWarningTime = null + finalWarningTime = null + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + fun onChat(event: LorenzChatEvent) { + if (callRingPattern.matches(event.message) && acceptUUID == null) readPickupUuid(event) + if (!isEnabled()) return + if (initHoppityCallPattern.matches(event.message)) startWarningUser() + if (pickupHoppityCallPattern.matches(event.message)) stopWarningUser() + } + + @SubscribeEvent + fun onTick(event: SecondPassedEvent) { + if (!isEnabled()) return + if (!activeWarning) return + if (nextWarningTime == null || finalWarningTime == null) return + val currentTime = Instant.now() + if (currentTime.isAfter(nextWarningTime)) { + SoundUtils.repeatSound(100, 10, warningSound) + nextWarningTime = currentTime.plusMillis(100) + } + if (currentTime >= finalWarningTime) stopWarningUser() + } + + @SubscribeEvent + fun onRender(event: GuiRenderEvent.GuiOverlayRenderEvent) { + if (!isEnabled() || !activeWarning) return + val minecraft = Minecraft.getMinecraft() + // Calculate a fluctuating alpha value based on the sine of time, for a smooth oscillation + val randomizationAlphaDouble = ((2 + sin(Instant.now().toEpochMilli().toDouble() / 1000)) * 255 / 4) + // Ensure the alpha value is an integer and within the valid range (0-255) + val randomizationAlphaInt = randomizationAlphaDouble.toInt().coerceIn(0..255) + // Shift the alpha value 24 bits to the left to position it in the color's alpha channel. + val shiftedRandomAlpha = randomizationAlphaInt shl 24 + Gui.drawRect( + 0, + 0, + minecraft.displayWidth, + minecraft.displayHeight, + // Apply the shifted alpha and combine it with the RGB components of flashColor. + shiftedRandomAlpha or (config.flashColor.toChromaColorInt() and 0xFFFFFF), + ) + GlStateManager.color(1F, 1F, 1F, 1F) + } + + private fun readPickupUuid(event: LorenzChatEvent) { + val siblings = event.chatComponent.siblings.takeIf { it.size >= 3 } ?: return + val clickEvent = siblings[2]?.chatStyle?.chatClickEvent ?: return + if (clickEvent.action.name.lowercase() != "run_command" || !clickEvent.value.lowercase().startsWith("/cb")) return + acceptUUID = clickEvent.value.lowercase().replace("/cb ", "").takeIf { it.isValidUuid() } + if (acceptUUID != null) DelayedRun.runDelayed(12.seconds) { acceptUUID = null } + } + + private fun startWarningUser() { + if (activeWarning) return + activeWarning = true + SoundUtils.repeatSound(100, 10, warningSound) + val currentTime = Instant.now() + nextWarningTime = currentTime.plusMillis(100) + finalWarningTime = finalWarningTime ?: currentTime.plusMillis(callLength.inWholeMilliseconds) + } + + private fun stopWarningUser() { + activeWarning = false + finalWarningTime = null + nextWarningTime = null + } + + private fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/HypixelCommands.kt b/src/main/java/at/hannibal2/skyhanni/utils/HypixelCommands.kt index c788d019a..176afe8c0 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/HypixelCommands.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/HypixelCommands.kt @@ -150,6 +150,10 @@ object HypixelCommands { send("chatprompt $prompt") } + fun callback(uuid: String) { + send("cb $uuid") + } + private fun send(command: String) { @Suppress("DEPRECATION") // TODO rename function diff --git a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt index 14e4a989f..e1a01e5df 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt @@ -561,4 +561,13 @@ object StringUtils { fun String.width(): Int = Minecraft.getMinecraft().fontRendererObj.getStringWidth(this) fun String.lastColorCode(): String? = minecraftColorCodesPattern.findAll(this).lastOrNull() + + fun String.isValidUuid(): Boolean { + return try { + UUID.fromString(this) + true + } catch (e: IllegalArgumentException) { + false + } + } } |