summaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/features/combat
diff options
context:
space:
mode:
authorHiZe <super@hize.be>2024-05-24 19:34:54 +0200
committerGitHub <noreply@github.com>2024-05-24 19:34:54 +0200
commit6e4a3b7284d9f5b7f40d604a6713f3259641ed9e (patch)
tree11c6455020d0099dbbe893ffb9a3df41d6fdbd10 /src/main/java/at/hannibal2/skyhanni/features/combat
parent9399de6e5814cd599aec276aa3663d0f95cc127f (diff)
downloadskyhanni-6e4a3b7284d9f5b7f40d604a6713f3259641ed9e.tar.gz
skyhanni-6e4a3b7284d9f5b7f40d604a6713f3259641ed9e.tar.bz2
skyhanni-6e4a3b7284d9f5b7f40d604a6713f3259641ed9e.zip
Feature: Flare Display (#1803)
Co-authored-by: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/features/combat')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/combat/FlareDisplay.kt199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/FlareDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/FlareDisplay.kt
new file mode 100644
index 000000000..4dcadb3a5
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/combat/FlareDisplay.kt
@@ -0,0 +1,199 @@
+package at.hannibal2.skyhanni.features.combat
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.config.features.combat.FlareConfig
+import at.hannibal2.skyhanni.events.GuiRenderEvent
+import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent
+import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent
+import at.hannibal2.skyhanni.events.ReceiveParticleEvent
+import at.hannibal2.skyhanni.events.SecondPassedEvent
+import at.hannibal2.skyhanni.utils.ChatUtils
+import at.hannibal2.skyhanni.utils.ColorUtils.toChromaColor
+import at.hannibal2.skyhanni.utils.EntityUtils
+import at.hannibal2.skyhanni.utils.EntityUtils.canBeSeen
+import at.hannibal2.skyhanni.utils.EntityUtils.hasSkullTexture
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzVec
+import at.hannibal2.skyhanni.utils.RenderUtils
+import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText
+import at.hannibal2.skyhanni.utils.RenderUtils.drawSphereInWorld
+import at.hannibal2.skyhanni.utils.RenderUtils.drawSphereWireframeInWorld
+import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables
+import at.hannibal2.skyhanni.utils.TimeUtils.format
+import at.hannibal2.skyhanni.utils.TimeUtils.ticks
+import at.hannibal2.skyhanni.utils.getLorenzVec
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+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.minutes
+import kotlin.time.Duration.Companion.seconds
+
+object FlareDisplay {
+
+ private val config get() = SkyHanniMod.feature.combat.flare
+ private var display = emptyList<Renderable>()
+ private var flares = mutableListOf<Flare>()
+
+ class Flare(val type: FlareType, val entity: EntityArmorStand, val location: LorenzVec = entity.getLorenzVec())
+
+ private val MAX_FLARE_TIME = 3.minutes
+
+ private val flareSkins = mapOf(
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0NjY4NzMwNjIyMywKICAicHJvZmlsZUlkIiA6ICI0MWQzYWJjMmQ3NDk0MDBjOTA5MGQ1NDM0ZDAzODMxYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZWdha2xvb24iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjJlMmJmNmMxZWMzMzAyNDc5MjdiYTYzNDc5ZTU4NzJhYzY2YjA2OTAzYzg2YzgyYjUyZGFjOWYxYzk3MTQ1OCIKICAgIH0KICB9Cn0="
+ to FlareType.WARNING,
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0NjY4NzMyNjQzMiwKICAicHJvZmlsZUlkIiA6ICI0MWQzYWJjMmQ3NDk0MDBjOTA5MGQ1NDM0ZDAzODMxYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZWdha2xvb24iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWQyYmY5ODY0NzIwZDg3ZmQwNmI4NGVmYTgwYjc5NWM0OGVkNTM5YjE2NTIzYzNiMWYxOTkwYjQwYzAwM2Y2YiIKICAgIH0KICB9Cn0="
+ to FlareType.ALERT,
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0NjY4NzM0NzQ4OSwKICAicHJvZmlsZUlkIiA6ICI0MWQzYWJjMmQ3NDk0MDBjOTA5MGQ1NDM0ZDAzODMxYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZWdha2xvb24iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzAwNjJjYzk4ZWJkYTcyYTZhNGI4OTc4M2FkY2VmMjgxNWI0ODNhMDFkNzNlYTg3YjNkZjc2MDcyYTg5ZDEzYiIKICAgIH0KICB9Cn0="
+ to FlareType.SOS
+ )
+
+ @SubscribeEvent
+ fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) {
+ if (!isEnabled()) return
+ if (config.displayType == FlareConfig.DisplayType.WORLD) return
+ config.position.renderRenderables(display, posLabel = "Flare Timer")
+ }
+
+ @SubscribeEvent
+ fun onRenderWorld(event: LorenzRenderWorldEvent) {
+ if (!isEnabled()) return
+ if (config.displayType == FlareConfig.DisplayType.GUI) return
+
+ for (flare in flares) {
+ val location = flare.location.add(-0.5, 0.0, -0.5)
+ val name = flare.type.displayName
+ val time = "§b${getRemainingTime(flare).format()}"
+ event.drawDynamicText(location, name, 1.5, ignoreBlocks = false)
+ event.drawDynamicText(location, time, 1.5, yOff = 10f, ignoreBlocks = false)
+ }
+ }
+
+ @SubscribeEvent
+ fun onSecondsPassed(event: SecondPassedEvent) {
+ if (!isEnabled()) return
+ flares.removeIf { !it.entity.isEntityAlive }
+ for (entity in EntityUtils.getAllEntities().filterIsInstance<EntityArmorStand>()) {
+ if (!entity.canBeSeen()) continue
+ if (entity.ticksExisted.ticks > MAX_FLARE_TIME) continue
+ if (isAlreadyKnownFlare(entity)) continue
+ getFlareTypeForTexuture(entity)?.let {
+ flares.add(Flare(it, entity))
+ }
+ }
+ var newDisplay: List<Renderable>? = null
+ for (type in FlareType.entries) {
+ val flare = getFlareForType(type) ?: continue
+ val remainingTime = getRemainingTime(flare)
+
+ val name = type.displayName
+ if (newDisplay == null) {
+ newDisplay = buildList {
+ add(Renderable.string("$name: §b${remainingTime.format()}"))
+ if (config.showManaBuff) {
+ type.manaBuff?.let {
+ add(Renderable.string(" §b$it §7mana regen"))
+ }
+ }
+ }
+ }
+ if (remainingTime > 5.seconds) continue
+ val message = "$name §eexpires in: §b${remainingTime.inWholeSeconds}s"
+ when (config.alertType) {
+ FlareConfig.AlertType.CHAT -> {
+ ChatUtils.chat(message)
+ }
+
+ FlareConfig.AlertType.TITLE -> {
+ LorenzUtils.sendTitle(message, 1.seconds)
+ }
+
+ FlareConfig.AlertType.CHAT_TITLE -> {
+ ChatUtils.chat(message)
+ LorenzUtils.sendTitle(message, 1.seconds)
+ }
+
+ else -> {}
+ }
+ }
+ display = newDisplay ?: emptyList()
+ }
+
+ private fun getRemainingTime(flare: Flare): Duration {
+ val entity = flare.entity
+ val aliveTime = entity.ticksExisted.ticks
+ val remainingTime = (MAX_FLARE_TIME - aliveTime)
+ return remainingTime
+ }
+
+ private fun getFlareForType(type: FlareType): Flare? = flares.firstOrNull { it.type == type }
+
+ private fun getFlareTypeForTexuture(entity: EntityArmorStand): FlareType? =
+ flareSkins.entries.firstOrNull { entity.hasSkullTexture(it.key) }?.value
+
+ private fun isAlreadyKnownFlare(entity: EntityArmorStand): Boolean =
+ flares.any { it.entity.entityId == entity.entityId }
+
+ @SubscribeEvent
+ fun onWorldChange(event: LorenzWorldChangeEvent) {
+ flares.clear()
+ display = emptyList()
+ }
+
+ @SubscribeEvent
+ fun onRender(event: LorenzRenderWorldEvent) {
+ if (!isEnabled()) return
+ if (config.outlineType == FlareConfig.OutlineType.NONE) return
+
+ for (flare in flares) {
+ val entity = flare.entity
+ val location = flare.location
+
+ val color = when (flare.type) {
+ FlareType.WARNING -> config.warningColor
+ FlareType.ALERT -> config.alertColor
+ FlareType.SOS -> config.sosColor
+ }.toChromaColor()
+
+ when (config.outlineType) {
+ FlareConfig.OutlineType.FILLED -> {
+ event.drawSphereInWorld(color, location, 40f)
+ }
+
+ FlareConfig.OutlineType.WIREFRAME -> {
+ event.drawSphereWireframeInWorld(color, location, 40f)
+ }
+
+ FlareConfig.OutlineType.CIRCLE -> {
+ RenderUtils.drawCircle(entity, event.partialTicks, 40.0, color)
+ }
+
+ else -> {}
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onReceiveParticle(event: ReceiveParticleEvent) {
+ if (!isEnabled()) return
+ if (!config.hideParticles) return
+
+ val location = event.location
+ val distance = flares.minOfOrNull { it.location.distance(location) } ?: return
+ if (distance < 2.5) {
+ if (event.type == EnumParticleTypes.FLAME) {
+ event.cancel()
+ }
+ }
+ }
+
+ enum class FlareType(val displayName: String, val manaBuff: String?) {
+ SOS("§5SOS Flare", "+125%"),
+ ALERT("§9Alert Flare", "+50%"),
+ WARNING("§aWarning Flare", null),
+ ;
+ }
+
+ private fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled
+}