aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/fishing/FishingConfig.java5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/fishing/TotemOfCorruptionConfig.java51
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/fishing/TotemOfCorruption.kt143
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt83
5 files changed, 284 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
index 125f3f0a7..d1fdbd9ea 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
@@ -294,6 +294,7 @@ import at.hannibal2.skyhanni.features.misc.ServerRestartTitle
import at.hannibal2.skyhanni.features.misc.SkyBlockKickDuration
import at.hannibal2.skyhanni.features.misc.SuperpairsClicksAlert
import at.hannibal2.skyhanni.features.misc.TimeFeatures
+import at.hannibal2.skyhanni.features.fishing.TotemOfCorruption
import at.hannibal2.skyhanni.features.misc.TpsCounter
import at.hannibal2.skyhanni.features.misc.compacttablist.AdvancedPlayerList
import at.hannibal2.skyhanni.features.misc.compacttablist.TabListReader
@@ -785,6 +786,7 @@ class SkyHanniMod {
loadModule(PresentWaypoints())
loadModule(MiningEventTracker())
loadModule(JyrreTimer())
+ loadModule(TotemOfCorruption())
loadModule(NewYearCakeReminder())
loadModule(SulphurSkitterBox())
loadModule(HighlightInquisitors())
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/fishing/FishingConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/FishingConfig.java
index d0bf5d1f3..0814f3a40 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/fishing/FishingConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/FishingConfig.java
@@ -56,6 +56,11 @@ public class FishingConfig {
public FishingProfitTrackerConfig fishingProfitTracker = new FishingProfitTrackerConfig();
@Expose
+ @ConfigOption(name = "Totem of Corruption", desc = "")
+ @Accordion
+ public TotemOfCorruptionConfig totemOfCorruption = new TotemOfCorruptionConfig();
+
+ @Expose
@ConfigOption(name = "Sea Creature Tracker", desc = "")
@Accordion
public SeaCreatureTrackerConfig seaCreatureTracker = new SeaCreatureTrackerConfig();
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/fishing/TotemOfCorruptionConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/TotemOfCorruptionConfig.java
new file mode 100644
index 000000000..67dbf364f
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/TotemOfCorruptionConfig.java
@@ -0,0 +1,51 @@
+package at.hannibal2.skyhanni.config.features.fishing;
+
+import at.hannibal2.skyhanni.config.FeatureToggle;
+import at.hannibal2.skyhanni.config.core.config.Position;
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean;
+import io.github.moulberry.moulconfig.annotations.ConfigEditorColour;
+import io.github.moulberry.moulconfig.annotations.ConfigEditorSlider;
+import io.github.moulberry.moulconfig.annotations.ConfigOption;
+
+public class TotemOfCorruptionConfig {
+
+ @Expose
+ @ConfigOption(name = "Show Overlay", desc = "Show the Totem of Corruption overlay." +
+ "\nShows the totem, in which effective area you are in, with the longest time left." +
+ "\n§cThis needs to be enabled for the other options to work.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean showOverlay = true;
+
+ @Expose
+ @ConfigOption(name = "Distance Threshold", desc = "The minimum distance to the Totem of Corruption for the overlay." +
+ "\nThe effective distance of the totem is 16." +
+ "\n§cLimited by how far you can see the nametags.")
+ @ConfigEditorSlider(minValue = 0, maxValue = 100, minStep = 1)
+ public int distanceThreshold = 16;
+
+ @Expose
+ @ConfigOption(name = "Hide Particles", desc = "Hide the particles of the Totem of Corruption.")
+ @ConfigEditorBoolean
+ public boolean hideParticles = true;
+
+ @Expose
+ @ConfigOption(name = "Show Effective Area", desc = "Show the effective area (16 blocks) of the Totem of Corruption.")
+ @ConfigEditorBoolean
+ public boolean showEffectiveArea = true;
+
+ @Expose
+ @ConfigOption(name = "Color of the area", desc = "The color of the area of the Totem of Corruption.")
+ @ConfigEditorColour
+ public String color = "0:153:18:159:85";
+
+ @Expose
+ @ConfigOption(name = "Warn when about to expire", desc = "Select the time in seconds when the totem is about to expire to warn you." +
+ "\nSelect 0 to disable.")
+ @ConfigEditorSlider(minValue = 0, maxValue = 60, minStep = 1)
+ public int warnWhenAboutToExpire = 5;
+
+ @Expose
+ public Position position = new Position(50, 20, false, true);
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/TotemOfCorruption.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/TotemOfCorruption.kt
new file mode 100644
index 000000000..2deb676af
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/TotemOfCorruption.kt
@@ -0,0 +1,143 @@
+package at.hannibal2.skyhanni.features.fishing
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.GuiRenderEvent
+import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent
+import at.hannibal2.skyhanni.events.LorenzTickEvent
+import at.hannibal2.skyhanni.events.ReceiveParticleEvent
+import at.hannibal2.skyhanni.utils.ColorUtils.toChromaColor
+import at.hannibal2.skyhanni.utils.EntityUtils
+import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.sendTitle
+import at.hannibal2.skyhanni.utils.LorenzVec
+import at.hannibal2.skyhanni.utils.RenderUtils.drawSphereInWorld
+import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings
+import at.hannibal2.skyhanni.utils.SoundUtils.playPlingSound
+import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
+import at.hannibal2.skyhanni.utils.StringUtils.matches
+import at.hannibal2.skyhanni.utils.TimeUnit
+import at.hannibal2.skyhanni.utils.TimeUtils.format
+import at.hannibal2.skyhanni.utils.getLorenzVec
+import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
+import net.minecraft.entity.item.EntityArmorStand
+import net.minecraft.util.EnumParticleTypes
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
+
+class TotemOfCorruption {
+
+ private val config get() = SkyHanniMod.feature.fishing.totemOfCorruption
+
+ private var display = emptyList<String>()
+ private var totems: List<Totem> = emptyList()
+
+ private val group = RepoPattern.group("fishing.totemofcorruption")
+ private val totemNamePattern by group.pattern(
+ "totemname",
+ "§5§lTotem of Corruption"
+ )
+ private val timeRemainingPattern by group.pattern(
+ "timeremaining",
+ "§7Remaining: §e(?:(?<min>\\d+)m )?(?<sec>\\d+)s"
+ )
+ private val ownerPattern by group.pattern(
+ "owner",
+ "§7Owner: §e(?<owner>.+)"
+ )
+
+ @SubscribeEvent
+ fun onRender(event: GuiRenderEvent.GuiOverlayRenderEvent) {
+ if (!isOverlayEnabled() || display.isEmpty()) return
+ config.position.renderStrings(display, posLabel = "Totem of Corruption")
+ }
+
+ @SubscribeEvent
+ fun onTick(event: LorenzTickEvent) {
+ if (!event.repeatSeconds(2)) return
+ if (!isOverlayEnabled()) return
+
+ totems = getTotems()
+ display = createDisplay()
+ }
+
+ @SubscribeEvent
+ fun onChatPacket(event: ReceiveParticleEvent) {
+ if (!isHideParticlesEnabled()) return
+
+ for (totem in totems) {
+ if (event.type == EnumParticleTypes.SPELL_WITCH && event.speed == 0.0f) {
+ if (totem.location.distance(event.location) < 4.0) {
+ event.isCanceled = true
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onRenderWorld(event: LorenzRenderWorldEvent) {
+ if (!isEffectiveAreaEnabled()) return
+
+ val color = config.color.toChromaColor()
+ for (totem in totems) {
+ // The center of the totem is the upper part
+ event.drawSphereInWorld(color, totem.location.add(y = 1), 16f)
+ }
+ }
+
+ private fun getTimeRemaining(totem: EntityArmorStand): Duration? =
+ EntityUtils.getEntitiesNearby<EntityArmorStand>(totem.getLorenzVec(), 2.0)
+ .firstNotNullOfOrNull { entity ->
+ timeRemainingPattern.matchMatcher(entity.name) {
+ val minutes = group("min")?.toIntOrNull() ?: 0
+ val seconds = group("sec")?.toInt() ?: 0
+ (minutes * 60 + seconds).seconds
+ }
+ }
+
+ private fun getOwner(totem: EntityArmorStand): String? =
+ EntityUtils.getEntitiesNearby<EntityArmorStand>(totem.getLorenzVec(), 2.0)
+ .firstNotNullOfOrNull { entity ->
+ ownerPattern.matchMatcher(entity.name) {
+ group("owner")
+ }
+ }
+
+
+ private fun createDisplay() = buildList {
+ val totem = getTotemToShow() ?: return@buildList
+ add("§5§lTotem of Corruption")
+ add("§7Remaining: §e${totem.timeRemaining.format(TimeUnit.MINUTE)}")
+ add("§7Owner: §e${totem.ownerName}")
+ }
+
+ private fun getTotemToShow(): Totem? = totems
+ .filter { it.distance < config.distanceThreshold }
+ .maxByOrNull { it.timeRemaining }
+
+ private fun getTotems(): List<Totem> = EntityUtils.getEntitiesNextToPlayer<EntityArmorStand>(100.0)
+ .filter { totemNamePattern.matches(it.name) }.toList()
+ .mapNotNull { totem ->
+ val timeRemaining = getTimeRemaining(totem) ?: return@mapNotNull null
+ val owner = getOwner(totem) ?: return@mapNotNull null
+
+ val timeToWarn = config.warnWhenAboutToExpire.seconds
+ if (timeToWarn > 0.seconds && timeRemaining == timeToWarn) {
+ playPlingSound()
+ sendTitle("§c§lTotem of Corruption §eabout to expire!", 5.seconds)
+ }
+ Totem(totem.getLorenzVec(), timeRemaining, owner)
+ }
+
+ private fun isOverlayEnabled() = LorenzUtils.inSkyBlock && config.showOverlay
+ private fun isHideParticlesEnabled() = LorenzUtils.inSkyBlock && config.hideParticles
+ private fun isEffectiveAreaEnabled() = LorenzUtils.inSkyBlock && config.showEffectiveArea
+}
+
+class Totem(
+ val location: LorenzVec,
+ val timeRemaining: Duration,
+ val ownerName: String,
+ val distance: Double = location.distanceToPlayer()
+)
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt
index 53a228625..c253c91ee 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt
@@ -702,6 +702,89 @@ object RenderUtils {
GlStateManager.popMatrix()
}
+ fun LorenzRenderWorldEvent.drawSphereInWorld(
+ color: Color,
+ location: LorenzVec,
+ radius: Float,
+ ) {
+ drawSphereInWorld(color, location.x, location.y, location.z, radius)
+ }
+
+ fun LorenzRenderWorldEvent.drawSphereInWorld(
+ color: Color,
+ x: Double,
+ y: Double,
+ z: Double,
+ radius: Float,
+ ) {
+ GlStateManager.pushMatrix()
+ GL11.glNormal3f(0.0f, 1.0f, 0.0f)
+
+ GlStateManager.enableDepth()
+ GlStateManager.enableBlend()
+ GlStateManager.depthFunc(GL11.GL_LEQUAL)
+ GlStateManager.disableCull()
+ GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0)
+ GlStateManager.enableAlpha()
+ GlStateManager.disableTexture2D()
+ color.bindColor()
+
+ var x1 = x
+ var y1 = y
+ var z1 = z
+ val renderViewEntity = Minecraft.getMinecraft().renderViewEntity
+ val viewX =
+ renderViewEntity.prevPosX + (renderViewEntity.posX - renderViewEntity.prevPosX) * partialTicks.toDouble()
+ val viewY =
+ renderViewEntity.prevPosY + (renderViewEntity.posY - renderViewEntity.prevPosY) * partialTicks.toDouble()
+ val viewZ =
+ renderViewEntity.prevPosZ + (renderViewEntity.posZ - renderViewEntity.prevPosZ) * partialTicks.toDouble()
+ x1 -= viewX
+ y1 -= viewY
+ z1 -= viewZ
+
+ val tessellator = Tessellator.getInstance()
+ val worldrenderer = tessellator.worldRenderer
+ worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION)
+
+ val segments = 32
+
+ for (phi in 0 until segments) {
+ for (theta in 0 until segments * 2) {
+ val x2 = x1 + radius * sin(Math.PI * phi / segments) * cos(2.0 * Math.PI * theta / (segments * 2))
+ val y2 = y1 + radius * cos(Math.PI * phi / segments)
+ val z2 = z1 + radius * sin(Math.PI * phi / segments) * sin(2.0 * Math.PI * theta / (segments * 2))
+
+ val x3 = x1 + radius * sin(Math.PI * (phi + 1) / segments) * cos(2.0 * Math.PI * theta / (segments * 2))
+ val y3 = y1 + radius * cos(Math.PI * (phi + 1) / segments)
+ val z3 = z1 + radius * sin(Math.PI * (phi + 1) / segments) * sin(2.0 * Math.PI * theta / (segments * 2))
+
+ worldrenderer.pos(x2, y2, z2).endVertex()
+ worldrenderer.pos(x3, y3, z3).endVertex()
+
+ val x4 = x1 + radius * sin(Math.PI * (phi + 1) / segments) * cos(2.0 * Math.PI * (theta + 1) / (segments * 2))
+ val y4 = y1 + radius * cos(Math.PI * (phi + 1) / segments)
+ val z4 = z1 + radius * sin(Math.PI * (phi + 1) / segments) * sin(2.0 * Math.PI * (theta + 1) / (segments * 2))
+
+ val x5 = x1 + radius * sin(Math.PI * phi / segments) * cos(2.0 * Math.PI * (theta + 1) / (segments * 2))
+ val y5 = y1 + radius * cos(Math.PI * phi / segments)
+ val z5 = z1 + radius * sin(Math.PI * phi / segments) * sin(2.0 * Math.PI * (theta + 1) / (segments * 2))
+
+ worldrenderer.pos(x4, y4, z4).endVertex()
+ worldrenderer.pos(x5, y5, z5).endVertex()
+ }
+ }
+
+ tessellator.draw()
+
+ GlStateManager.enableCull()
+ GlStateManager.enableTexture2D()
+ GlStateManager.enableDepth()
+ GlStateManager.disableBlend()
+ GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f)
+ GlStateManager.popMatrix()
+ }
+
private fun Color.bindColor() =
GlStateManager.color(this.red / 255f, this.green / 255f, this.blue / 255f, this.alpha / 255f)