Skip to content

Commit

Permalink
Improvement + Fix: Barn Fishing Timer (#1960)
Browse files Browse the repository at this point in the history
Co-authored-by: Cal <cwolfson58@gmail.com>
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Co-authored-by: ItsEmpa <itsempa@users.noreply.github.com>
  • Loading branch information
4 people authored Jul 26, 2024
1 parent bde6b2a commit 19d4d4e
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,55 @@
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider;
import io.github.notenoughupdates.moulconfig.annotations.ConfigLink;
import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
import io.github.notenoughupdates.moulconfig.observer.Property;
import org.lwjgl.input.Keyboard;

public class BarnTimerConfig {
@Expose
@ConfigOption(
name = "Barn Fishing Timer",
desc = "Show the time and amount of sea creatures while fishing on the barn via hub."
desc = "Show the time and amount of own sea creatures nearby while barn fishing."
)
@ConfigEditorBoolean
@FeatureToggle
public boolean enabled = true;
public Property<Boolean> enabled = Property.of(true);

@Expose
@ConfigOption(
name = "Worm Fishing",
desc = "Show the Barn Fishing Timer in the Crystal Hollows."
)
@ConfigEditorBoolean
public boolean crystalHollows = true;
public Property<Boolean> crystalHollows = Property.of(true);

@Expose
@ConfigOption(
name = "Lava Fishing",
desc = "Show the Barn Fishing Timer in the Crimson Isle."
)
@ConfigEditorBoolean
public boolean crimsonIsle = true;
public Property<Boolean> crimsonIsle = Property.of(true);

@Expose
@ConfigOption(
name = "Winter Fishing",
desc = "Show the Barn Fishing Timer on the Jerry's Workshop island."
)
@ConfigEditorBoolean
public boolean winterIsland = true;
public Property<Boolean> winterIsland = Property.of(true);

@Expose
@ConfigOption(
name = "Stranded Fishing",
desc = "Show the Barn Fishing Timer on all the different islands that Stranded players can visit."
)
@ConfigEditorBoolean
public boolean forStranded = true;
public Property<Boolean> forStranded = Property.of(true);

@Expose
@ConfigOption(
name = "Worm Cap Alert",
desc = "Alerts you with title and sound if you hit the Worm Sea Creature limit of 60."
desc = "Alerts you with title and sound if you hit the Worm Sea Creature limit of 20."
)
@ConfigEditorBoolean
public boolean wormLimitAlert = true;
Expand All @@ -74,6 +75,16 @@ public class BarnTimerConfig {
)
public int alertTime = 330;

@Expose
@ConfigOption(name = "Fishing Cap Alert", desc = "Gives a warning when you reach a certain amount of mobs.")
@ConfigEditorBoolean
public boolean fishingCapAlert = true;

@Expose
@ConfigOption(name = "Fishing Cap Amount", desc = "Amount of mobs at which to trigger the Fishing Cap Alert.")
@ConfigEditorSlider(minValue = 10, maxValue = 60, minStep = 1)
public int fishingCapAmount = 30;

@Expose
@ConfigLink(owner = BarnTimerConfig.class, field = "enabled")
public Position pos = new Position(10, 10, false, true);
Expand Down
222 changes: 164 additions & 58 deletions src/main/java/at/hannibal2/skyhanni/features/fishing/FishingTimer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,126 +3,232 @@ package at.hannibal2.skyhanni.features.fishing
import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator
import at.hannibal2.skyhanni.data.IslandType
import at.hannibal2.skyhanni.data.mob.Mob
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.LorenzKeyPressEvent
import at.hannibal2.skyhanni.events.LorenzTickEvent
import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent
import at.hannibal2.skyhanni.events.MobEvent
import at.hannibal2.skyhanni.events.SeaCreatureFishEvent
import at.hannibal2.skyhanni.events.SecondPassedEvent
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.EntityUtils
import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld
import at.hannibal2.skyhanni.utils.LocationUtils
import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyClicked
import at.hannibal2.skyhanni.utils.LocationUtils.distanceTo
import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland
import at.hannibal2.skyhanni.utils.LorenzVec
import at.hannibal2.skyhanni.utils.RecalculatingValue
import at.hannibal2.skyhanni.utils.RenderUtils.renderString
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.SoundUtils
import at.hannibal2.skyhanni.utils.StringUtils
import at.hannibal2.skyhanni.utils.TimeLimitedSet
import at.hannibal2.skyhanni.utils.TimeUnit
import at.hannibal2.skyhanni.utils.TimeUtils.format
import at.hannibal2.skyhanni.utils.getLorenzVec
import net.minecraft.client.Minecraft
import net.minecraft.entity.item.EntityArmorStand
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds

@SkyHanniModule
object FishingTimer {

private val config get() = SkyHanniMod.feature.fishing.barnTimer
private val barnLocation = LorenzVec(108, 89, -252)
private val mobDespawnTime = mutableMapOf<Mob, SimpleTimeMark>()

private var lastSeaCreatureFished = SimpleTimeMark.farPast()
private var display: String? = null
private var lastNameFished: String? = null

private var babyMagmaSlugsToFind = 0
private var lastMagmaSlugLocation: LorenzVec? = null
private var lastMagmaSlugTime = SimpleTimeMark.farPast()
private var recentBabyMagmaSlugs = TimeLimitedSet<Mob>(2.seconds)

private var mobsToFind = 0

private val recentMobs = TimeLimitedSet<Mob>(2.seconds)
private val currentCap by RecalculatingValue(1.seconds) {
when (LorenzUtils.skyBlockIsland) {
IslandType.CRYSTAL_HOLLOWS -> 20
IslandType.CRIMSON_ISLE -> 5
else -> config.fishingCapAmount
}
}

private var rightLocation = false
private var currentCount = 0
private var startTime = SimpleTimeMark.farPast()
private var inHollows = false

@SubscribeEvent
fun onTick(event: LorenzTickEvent) {
if (!LorenzUtils.inSkyBlock) return
if (!config.enabled) return

if (event.repeatSeconds(3)) {
rightLocation = isRightLocation()
fun onSecondPassed(event: SecondPassedEvent) {
if (!isEnabled()) return
updateLocation()
if (startTime.passedSince().inWholeSeconds - config.alertTime in 0..3) {
playSound()
}
if (config.wormLimitAlert && IslandType.CRYSTAL_HOLLOWS.isInIsland()) {
if (currentCount >= 20) {
playSound()
LorenzUtils.sendTitle("§cWORM CAP FULL!!!", 2.seconds)
}
} else if (config.fishingCapAlert && currentCount >= currentCap) {
playSound()
}
}

if (!rightLocation) return
private fun playSound() = SoundUtils.repeatSound(250, 4, SoundUtils.plingSound)

if (event.isMod(5)) checkMobs()
if (event.isMod(7)) tryPlaySound()
if (config.manualResetTimer.isKeyHeld() && Minecraft.getMinecraft().currentScreen == null) {
startTime = SimpleTimeMark.now()
@SubscribeEvent
fun onMobSpawn(event: MobEvent.Spawn.SkyblockMob) {
if (!isEnabled()) return
val mob = event.mob
if (babyMagmaSlugsToFind != 0 && mob.name == "Baby Magma Slug") {
recentBabyMagmaSlugs += mob
handleBabySlugs()
return
}
if (mob.name !in SeaCreatureManager.allFishingMobs) return
recentMobs += mob
handle()
}

private fun tryPlaySound() {
if (currentCount == 0) return

val passedSince = startTime.passedSince()
val barnTimerAlertTime = (config.alertTime * 1_000).milliseconds
if (passedSince in barnTimerAlertTime..(barnTimerAlertTime + 3.seconds)) {
SoundUtils.playBeepSound()
@SubscribeEvent
fun onMobDeSpawn(event: MobEvent.DeSpawn.SkyblockMob) {
if (!isEnabled()) return
val mob = event.mob
if (mob in mobDespawnTime) {
mobDespawnTime -= mob
if (mob.name == "Magma Slug") {
lastMagmaSlugLocation = mob.baseEntity.getLorenzVec()
babyMagmaSlugsToFind += 3
lastMagmaSlugTime = SimpleTimeMark.now()
handleBabySlugs()
}
}
recentMobs -= mob
updateInfo()
}

private fun checkMobs() {
val newCount = countMobs()
@SubscribeEvent
fun onSeaCreatureFish(event: SeaCreatureFishEvent) {
if (!isEnabled()) return
if (!rightLocation) return
lastSeaCreatureFished = SimpleTimeMark.now()
lastNameFished = event.seaCreature.name
mobsToFind = if (event.doubleHook) 2 else 1
handle()
}

if (currentCount == 0 && newCount > 0) {
startTime = SimpleTimeMark.now()
private fun handle() {
if (lastSeaCreatureFished.passedSince() > 2.seconds) return
val name = lastNameFished ?: return
val mobs = recentMobs.filter { it.name == name && it !in mobDespawnTime }
.sortedBy { it.baseEntity.distanceToPlayer() }
.take(mobsToFind).ifEmpty { return }
mobsToFind -= mobs.size
mobs.forEach { mobDespawnTime[it] = SimpleTimeMark.now() }
if (mobsToFind == 0) {
recentMobs.clear()
lastNameFished = null
}
updateInfo()
}

currentCount = newCount
if (newCount == 0) {
startTime = SimpleTimeMark.farPast()
private fun handleBabySlugs() {
if (lastMagmaSlugTime.passedSince() > 2.seconds) return
if (babyMagmaSlugsToFind == 0) return
val location = lastMagmaSlugLocation ?: return
val slugs = recentBabyMagmaSlugs.filter { it !in mobDespawnTime }
.sortedBy { it.baseEntity.distanceTo(location) }
.take(babyMagmaSlugsToFind).ifEmpty { return }
babyMagmaSlugsToFind -= slugs.size
slugs.forEach { mobDespawnTime[it] = SimpleTimeMark.now() }
if (babyMagmaSlugsToFind == 0) {
recentBabyMagmaSlugs.clear()
lastMagmaSlugLocation = null
}
updateInfo()
}

if (inHollows && newCount >= 60 && config.wormLimitAlert) {
SoundUtils.playBeepSound()
LorenzUtils.sendTitle("§cWORM CAP FULL!!!", 2.seconds)
@SubscribeEvent
fun onKeyPress(event: LorenzKeyPressEvent) {
if (!isEnabled()) return
if (Minecraft.getMinecraft().currentScreen != null) return
if (config.manualResetTimer.isKeyClicked()) {
mobDespawnTime.replaceAll { _, _ ->
SimpleTimeMark.now()
}
}
}

private fun countMobs() =
EntityUtils.getEntities<EntityArmorStand>().map { entity -> FishingAPI.seaCreatureCount(entity) }.sum()

private fun isRightLocation(): Boolean {
inHollows = false

if (config.forStranded && LorenzUtils.isStrandedProfile) return true

if (config.crystalHollows && IslandType.CRYSTAL_HOLLOWS.isInIsland()) {
inHollows = true
return true
private fun updateInfo() {
currentCount = mobDespawnTime.entries.sumOf {
1 + it.key.extraEntities.size
}
startTime = mobDespawnTime.maxByOrNull { it.value.passedSince() }?.value ?: SimpleTimeMark.farPast()
display = createDisplay()
}

if (config.crimsonIsle && IslandType.CRIMSON_ISLE.isInIsland()) return true

if (config.winterIsland && IslandType.WINTER.isInIsland()) return true

if (!IslandType.THE_FARMING_ISLANDS.isInIsland()) {
return LocationUtils.playerLocation().distance(barnLocation) < 50
private fun updateLocation() {
rightLocation = when (LorenzUtils.skyBlockIsland) {
IslandType.CRYSTAL_HOLLOWS -> config.crystalHollows.get()
IslandType.CRIMSON_ISLE -> config.crimsonIsle.get()
IslandType.WINTER -> config.winterIsland.get()
IslandType.HUB -> barnLocation.distanceToPlayer() < 50
IslandType.PRIVATE_ISLAND -> config.forStranded.get() && LorenzUtils.isStrandedProfile
else -> false
}
}

return false
@SubscribeEvent
fun onTick(event: LorenzTickEvent) {
if (!isEnabled()) return
if (!rightLocation) return
if (currentCount == 0) return
if (!FishingAPI.isFishing()) return

display = createDisplay()
}

@SubscribeEvent
fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) {
if (!LorenzUtils.inSkyBlock) return
if (!config.enabled) return
if (!isEnabled()) return
if (!rightLocation) return
if (currentCount == 0) return
if (!FishingAPI.isFishing()) return

val text = display ?: return
config.pos.renderString(text, posLabel = "BarnTimer")
}

private fun createDisplay(): String {
val passedSince = startTime.passedSince()
val barnTimerAlertTime = (config.alertTime * 1_000).milliseconds
val color = if (passedSince > barnTimerAlertTime) "§c" else "§e"
val timeColor = if (passedSince > config.alertTime.seconds) "§c" else "§e"
val timeFormat = passedSince.format(TimeUnit.MINUTE)
val countColor = if (config.fishingCapAlert && currentCount >= currentCap) "§c" else "§e"
val name = StringUtils.pluralize(currentCount, "sea creature")
val text = "$color$timeFormat §8(§e$currentCount §b$name§8)"
return "$timeColor$timeFormat §8($countColor$currentCount §b$name§8)"
}

config.pos.renderString(text, posLabel = "BarnTimer")
@SubscribeEvent
fun onWorldChange(event: LorenzWorldChangeEvent) {
mobDespawnTime.clear()
recentMobs.clear()
babyMagmaSlugsToFind = 0
display = null
lastMagmaSlugLocation = null
lastMagmaSlugTime = SimpleTimeMark.farPast()
recentBabyMagmaSlugs.clear()
mobsToFind = 0
currentCount = 0
startTime = SimpleTimeMark.farPast()
}

private fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled.get()

@SubscribeEvent
fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) {
event.move(3, "fishing.barnTimer", "fishing.barnTimer.enabled")
Expand Down

0 comments on commit 19d4d4e

Please sign in to comment.