From 563685be6ab36812d25666a3c2189e93ca2e742c Mon Sep 17 00:00:00 2001 From: nea Date: Sat, 15 Apr 2023 01:13:31 +0200 Subject: Idle notifier --- .../java/at/hannibal2/skyhanni/SkyHanniMod.java | 1 + .../hannibal2/skyhanni/config/features/Garden.java | 54 +++++++++++++++ .../skyhanni/features/garden/GardenAPI.kt | 7 +- .../skyhanni/features/garden/IdleWarning.kt | 79 ++++++++++++++++++++++ .../at/hannibal2/skyhanni/utils/ResettingTimer.kt | 27 ++++++++ 5 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/IdleWarning.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/ResettingTimer.kt diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java index 76eda7c64..95eb8bf9e 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java @@ -218,6 +218,7 @@ public class SkyHanniMod { loadModule(new CollectionCounter()); loadModule(new HighlightBonzoMasks()); loadModule(new DungeonLevelColor()); + loadModule(new IdleWarning()); loadModule(new BazaarCancelledBuyOrderClipboard()); loadModule(new CompactSplashPotionMessage()); loadModule(new CroesusUnopenedChestTracker()); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java b/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java index 40f55bd83..ecf550df6 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java @@ -901,6 +901,60 @@ public class Garden { @ConfigEditorBoolean public boolean forcefullyEnabledAlwaysFinnegan = false; + @Expose + @ConfigOption(name = "Idle Notifier", desc = "Idle Notifier") + @ConfigEditorAccordion(id = 29) + public boolean idleNotifierAccordion = false; + + @Expose + @ConfigOption(name = "Idle Notifier", desc = "Notify you when you stop gaining crops") + @ConfigAccordionId(id = 29) + @ConfigEditorBoolean + public boolean idleNotifier = false; + @Expose + @ConfigOption(name = "Idle Notifier Strategy", desc = "Flash your screen or play a sound when you stop gaining crops") + @ConfigAccordionId(id = 29) + @ConfigEditorDropdown + public IdleNotifierStrategy idleNotifierStrategy = IdleNotifierStrategy.AUDIBLE; + @Expose + @ConfigOption(name = "Idle Notifier Colour", desc = "In which colour should your screen flash if you stop gaining crops") + @ConfigAccordionId(id = 29) + @ConfigEditorColour + public String idleNotifierColor = "00:50:64:224:208"; + @Expose + @ConfigOption(name = "Idle Notifier Timeout", desc = "How long to wait before notifing the player") + @ConfigAccordionId(id = 29) + @ConfigEditorSlider(minValue = 1, maxValue = 60, minStep = 0.1F) + public float idleNotifierTimeout = 10F; + + @Expose + @ConfigOption(name = "Idle Notifier Keybind", desc = "Keybinding to toggle the idle notifier") + @ConfigAccordionId(id = 29) + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE) + public int idleNotifierKeybinding = Keyboard.KEY_NONE; + + public enum IdleNotifierStrategy { + AUDIBLE("Audio only"), VISUAL("Flash only"), BOTH("Audio and Visual"); + final String display; + + IdleNotifierStrategy(String display) { + this.display = display; + } + + public boolean isAudio() { + return this == AUDIBLE || this == BOTH; + } + + public boolean isVisual() { + return this == VISUAL || this == BOTH; + } + + @Override + public String toString() { + return display; + } + } + @Expose public Position cropSpeedMeterPos = new Position(278, -236, false, true); } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt index 192746e0a..39e18a119 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt @@ -77,7 +77,12 @@ object GardenAPI { return if (isOtherTool(internalName)) internalName else null } - private fun isOtherTool(internalName: String): Boolean { + fun isTool(toolItem: ItemStack?): Boolean { + val internalName = toolItem?.getInternalName() ?: return false + return isOtherTool(internalName) || CropType.values().any { internalName.startsWith(it.toolName) } + } + + fun isOtherTool(internalName: String): Boolean { if (internalName.startsWith("DAEDALUS_AXE")) return true if (internalName.startsWith("BASIC_GARDENING_HOE")) return true diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/IdleWarning.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/IdleWarning.kt new file mode 100644 index 000000000..9eebaf4ec --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/IdleWarning.kt @@ -0,0 +1,79 @@ +package at.hannibal2.skyhanni.features.garden + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.RenderRealOverlayEvent +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.ResettingTimer +import at.hannibal2.skyhanni.utils.SoundUtils +import io.github.moulberry.moulconfig.ChromaColour +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Gui +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.util.EnumChatFormatting +import net.minecraft.util.EnumChatFormatting.GREEN +import net.minecraft.util.EnumChatFormatting.RED +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.InputEvent.KeyInputEvent +import net.minecraftforge.fml.common.gameevent.TickEvent +import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent +import org.lwjgl.input.Keyboard +import kotlin.math.sin +import kotlin.time.Duration.Companion.seconds + +/* + * I disclaim any and all responsibility over the legality of this module. Blame HsFearless + */ +class IdleWarning { + + val config get() = SkyHanniMod.feature.garden + val lastGainedCrops = ResettingTimer() + var lastCropAmount = 0 + + fun isSlackingOff() = lastGainedCrops.hasPassed(config.idleNotifierTimeout.toDouble().seconds) + + @SubscribeEvent + fun onClientTick(event: ClientTickEvent) { + if (event.phase != TickEvent.Phase.END) return + if (!config.idleNotifier) { + lastGainedCrops.reset() + return + } + val player = Minecraft.getMinecraft().thePlayer ?: return + val heldItem = player.heldItem + if (heldItem == null || !GardenAPI.isTool(heldItem)) { + lastGainedCrops.reset() + return + } + val count = GardenAPI.readCounter(heldItem) + if (lastCropAmount != count) { + lastCropAmount = count + lastGainedCrops.reset() + } + if (isSlackingOff() && config.idleNotifierStrategy.isAudio) + SoundUtils.playBeepSound() + } + + @SubscribeEvent + fun onKeybind(event: KeyInputEvent) { + if (!Keyboard.getEventKeyState()) return + val key = if (Keyboard.getEventKey() == 0) Keyboard.getEventCharacter().code + 256 else Keyboard.getEventKey() + if (key == config.idleNotifierKeybinding) { + config.idleNotifier = !config.idleNotifier + LorenzUtils.chat("Idle Notifier ${if (config.idleNotifier) "${GREEN}Enabled" else "${RED}Disabled"}") + } + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + fun onRender(event: RenderRealOverlayEvent) { + if (!config.idleNotifier || !isSlackingOff()) return + if (!config.idleNotifierStrategy.isVisual) return + val mc = Minecraft.getMinecraft() + val alpha = ((1 + sin(System.currentTimeMillis().toDouble() / 1000)) * 255 / 4).toInt().coerceIn(0..255) + Gui.drawRect( + 0, 0, mc.displayWidth, mc.displayHeight, + (alpha shl 24) or (ChromaColour.specialToChromaRGB(config.idleNotifierColor) and 0xFFFFFF) + ) + GlStateManager.color(1F, 1F, 1F, 1F) + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ResettingTimer.kt b/src/main/java/at/hannibal2/skyhanni/utils/ResettingTimer.kt new file mode 100644 index 000000000..cc610ac19 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/ResettingTimer.kt @@ -0,0 +1,27 @@ +package at.hannibal2.skyhanni.utils + +import kotlin.time.Duration +import kotlin.time.ExperimentalTime +import kotlin.time.TimeMark +import kotlin.time.TimeSource + +@OptIn(ExperimentalTime::class) +class ResettingTimer { + /* null represents the far past */ + var timeMark: TimeMark? = null + fun reset() { + timeMark = TimeSource.Monotonic.markNow() + } + + fun hasPassed(duration: Duration): Boolean { + return timeMark?.plus(duration)?.hasPassedNow() ?: true + } + + fun resetIfHasPassed(duration: Duration): Boolean { + val passed = hasPassed(duration) + if (passed) { + reset() + } + return passed + } +} \ No newline at end of file -- cgit