diff options
13 files changed, 348 insertions, 7 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 0c8bd913d..5d1bb52ad 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -325,6 +325,8 @@ import at.hannibal2.skyhanni.features.mining.fossilexcavator.FossilExcavatorAPI import at.hannibal2.skyhanni.features.mining.fossilexcavator.GlacitePowderFeatures import at.hannibal2.skyhanni.features.mining.fossilexcavator.ProfitPerExcavation import at.hannibal2.skyhanni.features.mining.fossilexcavator.solver.FossilSolverDisplay +import at.hannibal2.skyhanni.features.mining.glacitemineshaft.CorpseLocator +import at.hannibal2.skyhanni.features.mining.glacitemineshaft.MineshaftWaypoints import at.hannibal2.skyhanni.features.mining.mineshaft.CorpseAPI import at.hannibal2.skyhanni.features.mining.mineshaft.MineshaftCorpseProfitPer import at.hannibal2.skyhanni.features.mining.powdertracker.PowderTracker @@ -778,6 +780,8 @@ class SkyHanniMod { loadModule(ProfitPerExcavation()) loadModule(GlacitePowderFeatures()) loadModule(MineshaftCorpseProfitPer()) + loadModule(MineshaftWaypoints) + loadModule(CorpseLocator) loadModule(CorpseAPI()) loadModule(GardenOptimalSpeed()) loadModule(GardenLevelDisplay()) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseLocatorConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseLocatorConfig.java new file mode 100644 index 000000000..b116bc09e --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseLocatorConfig.java @@ -0,0 +1,20 @@ +package at.hannibal2.skyhanni.config.features.mining; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class CorpseLocatorConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "Locates Corpses that are within line of sight then mark it with a waypoint.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Auto Send Location", desc = "Automatically send the location and type of the corpse in party chat.") + @ConfigEditorBoolean + public boolean autoSendLocation = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/GlaciteMineshaftConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/GlaciteMineshaftConfig.java new file mode 100644 index 000000000..5b50ffcc8 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/GlaciteMineshaftConfig.java @@ -0,0 +1,25 @@ +package at.hannibal2.skyhanni.config.features.mining; + +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorKeybind; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import org.lwjgl.input.Keyboard; + +public class GlaciteMineshaftConfig { + @Expose + @ConfigOption(name = "Mineshaft Waypoints", desc = "General waypoints inside the Mineshaft.") + @Accordion + public MineshaftWaypointsConfig mineshaftWaypoints = new MineshaftWaypointsConfig(); + + @Expose + @ConfigOption(name = "Corpse Locator", desc = "") + @Accordion + public CorpseLocatorConfig corpseLocator = new CorpseLocatorConfig(); + + @Expose + @ConfigOption(name = "Share Waypoint Location", desc = "Shares the location of the nearest waypoint upon key press.\n" + + "§eYou can share the location even if it has already been shared!") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE) + public int shareWaypointLocation = Keyboard.KEY_NONE; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MineshaftWaypointsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MineshaftWaypointsConfig.java new file mode 100644 index 000000000..a8c7b4d55 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MineshaftWaypointsConfig.java @@ -0,0 +1,24 @@ +package at.hannibal2.skyhanni.config.features.mining; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class MineshaftWaypointsConfig { + @Expose + @ConfigOption(name = "Enabled", desc = "Enable features related to the Glacite Mineshaft.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Entrance Location", desc = "Marks the location of the entrance with a waypoint.") + @ConfigEditorBoolean + public boolean entranceLocation = false; + + @Expose + @ConfigOption(name = "Ladder Location", desc = "Marks the location of the ladders at the bottom of the entrance with a waypoint.") + @ConfigEditorBoolean + public boolean ladderLocation = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java index 05ad3fb27..f4b64bf4f 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java @@ -47,6 +47,10 @@ public class MiningConfig { public FossilExcavatorConfig fossilExcavator = new FossilExcavatorConfig(); @Expose + @Category(name = "Glacite Mineshaft", desc = "Settings for the Glacite Mineshaft") + public GlaciteMineshaftConfig glaciteMineshaft = new GlaciteMineshaftConfig(); + + @Expose @ConfigOption(name = "Notifications", desc = "") @Accordion public MiningNotificationsConfig notifications = new MiningNotificationsConfig(); diff --git a/src/main/java/at/hannibal2/skyhanni/events/mining/CorpseLootedEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/mining/CorpseLootedEvent.kt index e73357296..ea1e813d0 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/mining/CorpseLootedEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/mining/CorpseLootedEvent.kt @@ -1,6 +1,6 @@ package at.hannibal2.skyhanni.events.mining import at.hannibal2.skyhanni.events.LorenzEvent -import at.hannibal2.skyhanni.features.mining.mineshaft.CorpeType +import at.hannibal2.skyhanni.features.mining.mineshaft.CorpseType -class CorpseLootedEvent(val corpseType: CorpeType, val loot: List<Pair<String, Int>>) : LorenzEvent() +class CorpseLootedEvent(val corpseType: CorpseType, val loot: List<Pair<String, Int>>) : LorenzEvent() 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"), diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt index ff8fc48be..3d67f9de6 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt @@ -47,6 +47,11 @@ object LocationUtils { return noBlocks && notTooFar && inFov } + fun LorenzVec.canBeSeen(yOffsetRange: IntRange, radius: Double = 150.0): Boolean = + yOffsetRange.any { offset -> + this.add(y = offset).canBeSeen(radius) + } + fun AxisAlignedBB.minBox() = LorenzVec(minX, minY, minZ) fun AxisAlignedBB.maxBox() = LorenzVec(maxX, maxY, maxZ) |