diff options
author | nobaboy <84668101+nobaboy@users.noreply.github.com> | 2024-06-01 12:55:40 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-01 11:55:40 +0200 |
commit | a5af0b8e09d46d445c610d5eaf90b81739652a47 (patch) | |
tree | 9fa102ac75aa3fe4828296f3d31441d349ec0e2c /src/main/java/at/hannibal2/skyhanni/features | |
parent | 8f7011f956cec5b104c3142ac53e57c4a3798844 (diff) | |
download | skyhanni-a5af0b8e09d46d445c610d5eaf90b81739652a47.tar.gz skyhanni-a5af0b8e09d46d445c610d5eaf90b81739652a47.tar.bz2 skyhanni-a5af0b8e09d46d445c610d5eaf90b81739652a47.zip |
Feature: Glacite Mineshafts QOL (#1500)
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/features')
-rw-r--r-- | src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/CorpseLocator.kt | 124 | ||||
-rw-r--r-- | src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoint.kt | 10 | ||||
-rw-r--r-- | src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypointType.kt | 29 | ||||
-rw-r--r-- | src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoints.kt | 96 | ||||
-rw-r--r-- | src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpseAPI.kt | 8 | ||||
-rw-r--r-- | src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpseType.kt (renamed from src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpeType.kt) | 2 |
6 files changed, 264 insertions, 5 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/CorpseLocator.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/CorpseLocator.kt new file mode 100644 index 000000000..e1c56ce69 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/CorpseLocator.kt @@ -0,0 +1,124 @@ +package at.hannibal2.skyhanni.features.mining.glacitemineshaft + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.data.PartyAPI +import at.hannibal2.skyhanni.data.hypixel.chat.event.PartyChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PlayerAllChatEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import at.hannibal2.skyhanni.events.SecondPassedEvent +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.EntityUtils +import at.hannibal2.skyhanni.utils.HypixelCommands +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +import at.hannibal2.skyhanni.utils.LocationUtils.canBeSeen +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.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.getLorenzVec +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.entity.item.EntityArmorStand +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +// TODO: Maybe implement automatic warp-in for chosen players if the user is not in a party. +object CorpseLocator { + private val config get() = SkyHanniMod.feature.mining.glaciteMineshaft.corpseLocator + + /** + * REGEX-TEST: x: -164, y: 8, z: -154 | (Lapis Corpse) + * REGEX-TEST: x: 141, y: 14, z: -131 + * REGEX-TEST: x: -9, y: 135, z: 20 | (Tungsten Corpse) + */ + private val mineshaftCoordsPattern by RepoPattern.pattern( + "mineshaft.corpse.coords", + "x: (?<x>-?\\d+), y: (?<y>-?\\d+), z: (?<z>-?\\d+)(?:.+)?" + ) + + private val sharedWaypoints: MutableList<LorenzVec> = mutableListOf() + + private fun findCorpse() { + EntityUtils.getAllEntities().filterIsInstance<EntityArmorStand>() + .filterNot { corpse -> MineshaftWaypoints.waypoints.any { it.location.distance(corpse.getLorenzVec()) <= 3 } } + .filter { entity -> + entity.showArms && entity.hasNoBasePlate() && !entity.isInvisible + } + .forEach { entity -> + val helmetName = entity.getCurrentArmor(3).getInternalName() + val corpseType = MineshaftWaypointType.getByHelmetOrNull(helmetName) ?: return + + val canSee = entity.getLorenzVec().canBeSeen(-1..3) + if (canSee) { + ChatUtils.chat("Located a ${corpseType.displayText} and marked its location with a waypoint.") + MineshaftWaypoints.waypoints.add( + MineshaftWaypoint( + waypointType = corpseType, + location = entity.getLorenzVec().add(y = 1), + isCorpse = true + ) + ) + } + } + } + + private fun shareCorpse() { + val closestCorpse = MineshaftWaypoints.waypoints.filter { it.isCorpse && !it.shared } + .filterNot { corpse -> + sharedWaypoints.any { corpse.location.distance(it) <= 5 } + } + .filter { it.location.distanceToPlayer() <= 5} + .minByOrNull { it.location.distanceToPlayer() } ?: return + + val (x, y, z) = closestCorpse.location.toDoubleArray().map { it.toInt() } + val type = closestCorpse.waypointType.displayText + + HypixelCommands.partyChat("x: $x, y: $y, z: $z | ($type)") + closestCorpse.shared = true + } + + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) { + if (sharedWaypoints.isNotEmpty()) sharedWaypoints.clear() + } + + @SubscribeEvent + fun onSecondPassed(event: SecondPassedEvent) { + if (!isEnabled()) return + + findCorpse() + + if (!config.autoSendLocation) return + if (MineshaftWaypoints.waypoints.isEmpty()) return + if (PartyAPI.partyMembers.isEmpty()) return + shareCorpse() + } + + @SubscribeEvent + fun onPartyChat(event: PartyChatEvent) { + handleChatEvent(event.author, event.message) + } + + @SubscribeEvent + fun onAllChat(event: PlayerAllChatEvent) { + handleChatEvent(event.author, event.message) + } + + private fun handleChatEvent(author: String, message: String) { + if (!isEnabled()) return + if (LorenzUtils.getPlayerName() in author) return + + mineshaftCoordsPattern.matchMatcher(message) { + val (x, y, z) = listOf(group("x"), group("y"), group("z")).map { it.formatInt() } + val location = LorenzVec(x, y, z) + + // Return if someone had already sent a location nearby + if (sharedWaypoints.any { it.distance(location) <= 5 }) return + sharedWaypoints.add(location) + } + } + + fun isEnabled() = IslandType.MINESHAFT.isInIsland() && config.enabled +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoint.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoint.kt new file mode 100644 index 000000000..b45cf9588 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoint.kt @@ -0,0 +1,10 @@ +package at.hannibal2.skyhanni.features.mining.glacitemineshaft + +import at.hannibal2.skyhanni.utils.LorenzVec + +data class MineshaftWaypoint( + val waypointType: MineshaftWaypointType, + val location: LorenzVec, + var shared: Boolean = false, + var isCorpse: Boolean = false +) diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypointType.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypointType.kt new file mode 100644 index 000000000..31d7a42ce --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypointType.kt @@ -0,0 +1,29 @@ +package at.hannibal2.skyhanni.features.mining.glacitemineshaft + +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName + +enum class MineshaftWaypointType( + val displayText: String, + val color: LorenzColor, + private val itemName: String? = null +) { + LAPIS("Lapis Corpse", LorenzColor.DARK_BLUE, "LAPIS_ARMOR_HELMET"), + UMBER("Umber Corpse", LorenzColor.GOLD, "ARMOR_OF_YOG_HELMET"), + TUNGSTEN("Tungsten Corpse", LorenzColor.GRAY, "MINERAL_HELMET"), + VANGUARD("Vanguard Corpse", LorenzColor.BLUE, "VANGUARD_HELMET"), + ENTRANCE("Entrance", LorenzColor.YELLOW), + LADDER("Ladder", LorenzColor.YELLOW) + ; + + val helmet by lazy { + itemName?.asInternalName() + } + + companion object { + fun getByHelmetOrNull(internalName: NEUInternalName): MineshaftWaypointType? { + return entries.firstOrNull { it.helmet == internalName } + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoints.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoints.kt new file mode 100644 index 000000000..162ef31ef --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoints.kt @@ -0,0 +1,96 @@ +package at.hannibal2.skyhanni.features.mining.glacitemineshaft + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.data.PartyAPI +import at.hannibal2.skyhanni.events.IslandChangeEvent +import at.hannibal2.skyhanni.events.LorenzKeyPressEvent +import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import at.hannibal2.skyhanni.test.GriffinUtils.drawWaypointFilled +import at.hannibal2.skyhanni.utils.HypixelCommands +import at.hannibal2.skyhanni.utils.LocationUtils +import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import net.minecraft.client.Minecraft +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.milliseconds + +// TODO rename to something else to reduce confusion +object MineshaftWaypoints { + private val config get() = SkyHanniMod.feature.mining.glaciteMineshaft + + private const val BLOCKS_FORWARD: Int = 7 + + val waypoints: MutableList<MineshaftWaypoint> = mutableListOf() + private var timeLastShared = SimpleTimeMark.farPast() + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) { + waypoints.clear() + } + + @SubscribeEvent + fun onIslandChange(event: IslandChangeEvent) { + if (event.newIsland != IslandType.MINESHAFT) return + + val playerLocation = LocationUtils.playerLocation().round(0).add(y = -1) + + if (config.mineshaftWaypoints.entranceLocation) { + waypoints.add(MineshaftWaypoint(waypointType = MineshaftWaypointType.ENTRANCE, location = playerLocation)) + } + + if (config.mineshaftWaypoints.ladderLocation) { + val vec = Minecraft.getMinecraft().thePlayer.horizontalFacing.directionVec + val location = playerLocation + // Move 7 blocks in front of the player to be in the ladder shaft + .add(x = vec.x * BLOCKS_FORWARD, z = vec.z * BLOCKS_FORWARD) + // Adjust 2 blocks to the right to be in the center of the ladder shaft + .add(x = vec.z * -2, z = vec.x * 2) + // Move 15 blocks down to be at the bottom of the ladder shaft + .add(y = -15) + waypoints.add(MineshaftWaypoint(waypointType = MineshaftWaypointType.LADDER, location = location)) + } + } + + @SubscribeEvent + fun onKeyPress(event: LorenzKeyPressEvent) { + if (Minecraft.getMinecraft().currentScreen != null) return + if (event.keyCode != config.shareWaypointLocation) return + if (timeLastShared.passedSince() < 500.milliseconds) return + + val closestWaypoint = waypoints.filter { it.location.distanceToPlayer() <= 5 } + .minByOrNull { it.location.distanceToPlayer() } ?: return + + timeLastShared = SimpleTimeMark.now() + val location = closestWaypoint.location + val (x, y, z) = location.toDoubleArray().map { it.toInt() } + val type = closestWaypoint.waypointType.displayText + + val message = "x: $x, y: $y, z: $z | ($type)" + + if (PartyAPI.partyMembers.isNotEmpty()) { + HypixelCommands.partyChat(message) + } else { + HypixelCommands.allChat(message) + } + } + + @SubscribeEvent + fun onWorldRender(event: LorenzRenderWorldEvent) { + if (waypoints.isEmpty()) return + + waypoints + .filter { + (it.isCorpse && config.corpseLocator.enabled) || (!it.isCorpse && config.mineshaftWaypoints.enabled) + } + .forEach { + event.drawWaypointFilled(it.location, it.waypointType.color.toColor(), seeThroughBlocks = true) + event.drawDynamicText(it.location, "§e${it.waypointType.displayText}", 1.0) + } + } + + fun isEnabled() = IslandType.MINESHAFT.isInIsland() && config.mineshaftWaypoints.enabled +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpseAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpseAPI.kt index b388a15a8..e8fc4509d 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpseAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpseAPI.kt @@ -39,7 +39,7 @@ class CorpseAPI { private var inLoot = false private val loot = mutableListOf<Pair<String, Int>>() - private var corpeType: CorpeType? = null + private var corpseType: CorpseType? = null @SubscribeEvent fun onChat(event: LorenzChatEvent) { @@ -50,17 +50,17 @@ class CorpseAPI { startPattern.matchMatcher(message) { inLoot = true val name = group("name") - corpeType = CorpeType.valueOf(name) + corpseType = CorpseType.valueOf(name) return } if (!inLoot) return if (endPattern.matches(message)) { - corpeType?.let { + corpseType?.let { CorpseLootedEvent(it, loot.toList()).postAndCatch() } - corpeType = null + corpseType = null loot.clear() inLoot = false return diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpeType.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpseType.kt index e2d385de5..7ddfca867 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpeType.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/mineshaft/CorpseType.kt @@ -2,7 +2,7 @@ package at.hannibal2.skyhanni.features.mining.mineshaft import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName -enum class CorpeType(val displayName: String, private val keyName: String? = null) { +enum class CorpseType(val displayName: String, private val keyName: String? = null) { LAPIS("§9Lapis"), TUNGSTEN("§7Tungsten", "TUNGSTEN_KEY"), UMBER("§6Umber", "UMBER_KEY"), |