aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorappable <enzospiacitelli@gmail.com>2023-12-16 03:13:06 -0800
committerGitHub <noreply@github.com>2023-12-16 12:13:06 +0100
commitcdcc7b35e38ddb5e00d8a4d900c4cad77bd6e1f5 (patch)
tree89ec49b38cbb17a758375454de6c546d6b333d93 /src/main/java
parentf2711d19b3a727eb0f204d064f49cb7355540282 (diff)
downloadskyhanni-cdcc7b35e38ddb5e00d8a4d900c4cad77bd6e1f5.tar.gz
skyhanni-cdcc7b35e38ddb5e00d8a4d900c4cad77bd6e1f5.tar.bz2
skyhanni-cdcc7b35e38ddb5e00d8a4d900c4cad77bd6e1f5.zip
Feature: Active spray display and expiry notification (#800)
Added Spray Display and Spray Expiration Notice. #800
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/garden/pests/SprayConfig.java21
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/GardenPlotAPI.kt68
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/pests/SprayDisplay.kt66
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/pests/SprayFeatures.kt9
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt11
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt15
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt9
8 files changed, 186 insertions, 15 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
index 0a8e08ce5..7bcf31f72 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
@@ -185,6 +185,7 @@ import at.hannibal2.skyhanni.features.garden.inventory.SkyMartCopperPrice
import at.hannibal2.skyhanni.features.garden.pests.PestFinder
import at.hannibal2.skyhanni.features.garden.pests.PestSpawn
import at.hannibal2.skyhanni.features.garden.pests.PestSpawnTimer
+import at.hannibal2.skyhanni.features.garden.pests.SprayDisplay
import at.hannibal2.skyhanni.features.garden.pests.SprayFeatures
import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorColorNames
import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorDropStatistics
@@ -675,6 +676,7 @@ class SkyHanniMod {
loadModule(PestSpawnTimer)
loadModule(PestFinder())
loadModule(SprayFeatures())
+ loadModule(SprayDisplay())
loadModule(HighlightPlaceableNpcs())
loadModule(PresentWaypoints())
loadModule(JyrreTimer())
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/pests/SprayConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/pests/SprayConfig.java
index da715712f..07f73ba78 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/pests/SprayConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/pests/SprayConfig.java
@@ -25,4 +25,25 @@ public class SprayConfig {
@Expose
public Position position = new Position(315, -200, 2.3f);
+
+ @Expose
+ @ConfigOption(
+ name = "Spray Display",
+ desc = "Show the active spray and duration for your current plot."
+ )
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean displayEnabled = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Spray Expiration Notice",
+ desc = "Show a notification in chat when a spray runs out in any plot. Only active in Garden."
+ )
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean expiryNotification = true;
+
+ @Expose
+ public Position displayPosition = new Position(390, 75, false, true);
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenPlotAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenPlotAPI.kt
index f55f87c4c..7dde87771 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenPlotAPI.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenPlotAPI.kt
@@ -1,13 +1,16 @@
package at.hannibal2.skyhanni.features.garden
import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent
+import at.hannibal2.skyhanni.events.LorenzChatEvent
import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent
+import at.hannibal2.skyhanni.features.garden.pests.SprayType
import at.hannibal2.skyhanni.features.misc.LockMouseLook
import at.hannibal2.skyhanni.utils.ItemUtils.name
import at.hannibal2.skyhanni.utils.LocationUtils.isPlayerInside
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.LorenzVec
import at.hannibal2.skyhanni.utils.RenderUtils.draw3DLine
+import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import com.google.gson.annotations.Expose
@@ -15,11 +18,18 @@ import net.minecraft.util.AxisAlignedBB
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import java.awt.Color
import kotlin.math.floor
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.minutes
object GardenPlotAPI {
private val plotNamePattern by RepoPattern.pattern("garden.plot.name", "§.Plot §7- §b(?<name>.*)")
+ private val plotSprayedPattern by RepoPattern.pattern(
+ "garden.plot.spray.target",
+ "§a§lSPRAYONATOR! §r§7You sprayed §r§aPlot §r§7- §r§b(?<plot>.*) §r§7with §r§a(?<spray>.*)§r§7!"
+ )
+
var plots = listOf<Plot>()
fun getCurrentPlot(): Plot? {
@@ -36,10 +46,24 @@ object GardenPlotAPI {
var name: String,
@Expose
- var pests: Int
+ var pests: Int,
+
+ @Expose
+ var sprayExpiryTime: SimpleTimeMark?,
+
+ @Expose
+ var sprayType: SprayType?,
+
+ @Expose
+ var sprayHasNotified: Boolean
+ )
+
+ data class SprayData(
+ val expiry: SimpleTimeMark,
+ val type: SprayType
)
- private fun Plot.getData() = GardenAPI.storage?.plotData?.getOrPut(id) { PlotData(id, "$id", 0) }
+ private fun Plot.getData() = GardenAPI.storage?.plotData?.getOrPut(id) { PlotData(id, "$id", 0, null, null, false) }
var Plot.name: String
get() = getData()?.name ?: "$id"
@@ -53,6 +77,31 @@ object GardenPlotAPI {
getData()?.pests = value
}
+ val Plot.currentSpray: SprayData?
+ get() = this.getData()?.let { plot ->
+ val expiry = plot.sprayExpiryTime?.takeIf { !it.isInPast() } ?: return null
+ val type = plot.sprayType ?: return null
+ return SprayData(expiry, type)
+ }
+
+ val Plot.isSprayExpired: Boolean
+ get() = this.getData()?.let {
+ !it.sprayHasNotified && it.sprayExpiryTime?.isInPast() == true
+ } == true
+
+
+ fun Plot.markExpiredSprayAsNotified() {
+ getData()?.apply { sprayHasNotified = true }
+ }
+
+ private fun Plot.setSpray(spray: SprayType, duration: Duration) {
+ getData()?.apply {
+ sprayType = spray
+ sprayExpiryTime = SimpleTimeMark.now() + duration
+ sprayHasNotified = false
+ }
+ }
+
fun Plot.isBarn() = id == -1
fun Plot.isPlayerInside() = box.isPlayerInside()
@@ -91,6 +140,21 @@ object GardenPlotAPI {
}
@SubscribeEvent
+ fun onChat(event: LorenzChatEvent) {
+ if (!GardenAPI.inGarden()) return
+
+ plotSprayedPattern.matchMatcher(event.message) {
+ val sprayName = group("spray")
+ val plotName = group("plot")
+
+ val plot = getPlotByName(plotName)
+ val spray = SprayType.getByName(sprayName) ?: return
+
+ plot?.setSpray(spray, 30.minutes)
+ }
+ }
+
+ @SubscribeEvent
fun onInventoryOpen(event: InventoryFullyOpenedEvent) {
if (!GardenAPI.inGarden()) return
if (event.inventoryName != "Configure Plots") return
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/SprayDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/SprayDisplay.kt
new file mode 100644
index 000000000..cfee8face
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/SprayDisplay.kt
@@ -0,0 +1,66 @@
+package at.hannibal2.skyhanni.features.garden.pests
+
+import at.hannibal2.skyhanni.data.IslandType
+import at.hannibal2.skyhanni.events.GuiRenderEvent
+import at.hannibal2.skyhanni.events.IslandChangeEvent
+import at.hannibal2.skyhanni.events.LorenzTickEvent
+import at.hannibal2.skyhanni.features.garden.GardenAPI
+import at.hannibal2.skyhanni.features.garden.GardenPlotAPI
+import at.hannibal2.skyhanni.features.garden.GardenPlotAPI.currentSpray
+import at.hannibal2.skyhanni.features.garden.GardenPlotAPI.isSprayExpired
+import at.hannibal2.skyhanni.features.garden.GardenPlotAPI.markExpiredSprayAsNotified
+import at.hannibal2.skyhanni.features.garden.GardenPlotAPI.name
+import at.hannibal2.skyhanni.features.garden.GardenPlotAPI.plots
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.RenderUtils.renderString
+import at.hannibal2.skyhanni.utils.StringUtils
+import at.hannibal2.skyhanni.utils.TimeUtils.timerColor
+import at.hannibal2.skyhanni.utils.TimeUtils.format
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+
+class SprayDisplay {
+ private val config get() = PestAPI.config.spray
+ private var display: String? = null
+
+ @SubscribeEvent
+ fun onTick(event: LorenzTickEvent) {
+ if (!GardenAPI.inGarden() || !event.isMod(5)) return
+
+ if (config.displayEnabled) {
+ val plot = GardenPlotAPI.getCurrentPlot() ?: return
+ display = plot.currentSpray?.let {
+ val timer = it.expiry.timeUntil()
+ "§eSprayed with §a${it.type.displayName} §7- ${timer.timerColor("§b")}${timer.format()}"
+ }
+ }
+
+ if (config.expiryNotification) {
+ sendExpiredPlotsToChat(false)
+ }
+ }
+
+ @SubscribeEvent
+ fun onJoin(event: IslandChangeEvent) {
+ if (!config.expiryNotification || event.newIsland != IslandType.GARDEN) return
+ sendExpiredPlotsToChat(true)
+ }
+
+ @SubscribeEvent
+ fun onRenderOverlay(ignored: GuiRenderEvent.GuiOverlayRenderEvent) {
+ if (!GardenAPI.inGarden() || !config.displayEnabled) return
+ val display = display ?: return
+ config.displayPosition.renderString(display, posLabel = "Active Plot Spray Display")
+ }
+
+ private fun sendExpiredPlotsToChat(wasAway: Boolean) {
+ val expiredPlots = plots.filter { it.isSprayExpired }
+ if (expiredPlots.isEmpty()) return
+
+ expiredPlots.forEach { it.markExpiredSprayAsNotified() }
+ val wasAwayString = if (wasAway) "§7While you were away, your" else "§7Your"
+ val plotString = StringUtils.createCommaSeparatedList(expiredPlots.map { "§b${it.name}" }, "§7")
+ val sprayString = if (expiredPlots.size > 1) "sprays" else "spray"
+ val out = "$wasAwayString $sprayString on §aPlot §7- $plotString §7expired."
+ LorenzUtils.chat(out)
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/SprayFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/SprayFeatures.kt
index c51070f03..f3a21f6be 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/SprayFeatures.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/SprayFeatures.kt
@@ -9,13 +9,12 @@ import at.hannibal2.skyhanni.features.garden.GardenPlotAPI.renderPlot
import at.hannibal2.skyhanni.features.garden.pests.PestAPI.getPests
import at.hannibal2.skyhanni.test.command.ErrorManager
import at.hannibal2.skyhanni.utils.InventoryUtils
-import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
import at.hannibal2.skyhanni.utils.LorenzColor
import at.hannibal2.skyhanni.utils.LorenzUtils
-import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName
import at.hannibal2.skyhanni.utils.RenderUtils.renderString
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
+import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.time.Duration.Companion.seconds
@@ -25,8 +24,10 @@ class SprayFeatures {
private var display: String? = null
private var lastChangeTime = SimpleTimeMark.farPast()
- // TODO repo
- private val pattern = "§a§lSPRAYONATOR! §r§7Your selected material is now §r§a(?<spray>.*)§r§7!".toPattern()
+ private val pattern by RepoPattern.pattern(
+ "garden.spray.material",
+ "§a§lSPRAYONATOR! §r§7Your selected material is now §r§a(?<spray>.*)§r§7!"
+ )
@SubscribeEvent
fun onChat(event: LorenzChatEvent) {
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt
index d08dd888a..d9a478d4e 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt
@@ -18,11 +18,11 @@ import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings
import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
import at.hannibal2.skyhanni.utils.TimeUnit
import at.hannibal2.skyhanni.utils.TimeUtils
+import at.hannibal2.skyhanni.utils.TimeUtils.timerColor
import at.hannibal2.skyhanni.utils.Timer
import net.minecraft.network.play.server.S47PacketPlayerListHeaderFooter
import net.minecraftforge.fml.common.eventhandler.EventPriority
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.minutes
@@ -123,7 +123,7 @@ class NonGodPotEffectDisplay {
val remaining = time.remaining.coerceAtLeast(0.seconds)
val format = TimeUtils.formatDuration(remaining.inWholeMilliseconds, TimeUnit.HOUR)
- val color = colorForTime(remaining)
+ val color = remaining.timerColor()
val displayName = effect.tabListName
newDisplay.add("$displayName $color$format")
@@ -137,13 +137,6 @@ class NonGodPotEffectDisplay {
return newDisplay
}
- private fun colorForTime(duration: Duration) = when (duration) {
- in 0.seconds..60.seconds -> "§c"
- in 60.seconds..3.minutes -> "§6"
- in 3.minutes..10.minutes -> "§e"
- else -> "§f"
- }
-
@SubscribeEvent
fun onTick(event: LorenzTickEvent) {
if (!isEnabled()) return
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt
index daa619982..a9ac0ca82 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt
@@ -156,6 +156,21 @@ object StringUtils {
}
}
+ /**
+ * Creates a comma-separated list using natural formatting (a, b, and c).
+ * @param list - the list of strings to join into a string, containing 0 or more elements.
+ * @param delimiterColor - the color code of the delimiter, inserted before each delimiter (commas and "and").
+ * @return a string representing the list joined with the Oxford comma and the word "and".
+ */
+ fun createCommaSeparatedList(list: List<String>, delimiterColor: String = ""): String {
+ if (list.isEmpty()) return ""
+ if (list.size == 1) return list[0]
+ if (list.size == 2) return "${list[0]}$delimiterColor and ${list[1]}"
+ val lastIndex = list.size - 1
+ val allButLast = list.subList(0, lastIndex).joinToString("$delimiterColor, ")
+ return "$allButLast$delimiterColor, and ${list[lastIndex]}"
+ }
+
fun optionalPlural(number: Int, singular: String, plural: String) =
"${number.addSeparators()} " + canBePlural(number, singular, plural)
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
index ecb842f63..6aa418f85 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
@@ -6,6 +6,8 @@ import io.github.moulberry.notenoughupdates.util.SkyBlockTime
import java.time.LocalDate
import java.time.ZoneId
import kotlin.time.Duration
+import kotlin.time.Duration.Companion.minutes
+import kotlin.time.Duration.Companion.seconds
import kotlin.time.DurationUnit
import kotlin.time.toDuration
@@ -30,6 +32,13 @@ object TimeUtils {
inWholeMilliseconds - 999, biggestUnit, showMilliSeconds, longName, maxUnits
)
+ fun Duration.timerColor(default: String = "§f") = when (this) {
+ in 0.seconds..60.seconds -> "§c"
+ in 60.seconds..3.minutes -> "§6"
+ in 3.minutes..10.minutes -> "§e"
+ else -> default
+ }
+
fun formatDuration(
millis: Long,
biggestUnit: TimeUnit = TimeUnit.YEAR,