aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--FEATURES.md1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/Features.java5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/Garden.java25
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/HyPixelData.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/events/TabListUpdateEvent.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorTimer.kt64
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/CrimsonIsleReputationHelper.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/dailyquest/QuestLoader.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt117
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TabListUtils.kt41
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt28
13 files changed, 251 insertions, 50 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8abfa321e..3ec268ef3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@
+ Added **Show Price** - Show the bazaar price of the items required for the visitors.
+ Added **Crop Milestone** Number - Show the number of the crop milestone in the inventory.
+ Added **Crop Upgrades** Number - Show the number of upgrades in the crop upgrades inventory.
++ Added **Visitor Timer** - Timer when the next visitor will appear, and a number how many visitors are already waiting.
### Features from other Mods
> *The following features are only there because I want them when testing SkyHanni features without other mods present.*
diff --git a/FEATURES.md b/FEATURES.md
index 8cb6670df..7a8c1c211 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -165,6 +165,7 @@
+ **Show Price** - Show the bazaar price of the items required for the visitors.
+ **Crop Milestone** Number - Show the number of the crop milestone in the inventory.
+ **Crop Upgrades** Number - Show the number of upgrades in the crop upgrades inventory.
++ **Visitor Timer** - Timer when the next visitor will appear, and a number how many visitors are already waiting.
## Commands
- /wiki (using hypixel-skyblock.fandom.com instead of Hypixel wiki)
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java
index a848ab072..5fde02e86 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java
@@ -25,6 +25,7 @@ import at.hannibal2.skyhanni.features.event.diana.SoopyGuessBurrow;
import at.hannibal2.skyhanni.features.fishing.*;
import at.hannibal2.skyhanni.features.garden.GardenInventoryNumbers;
import at.hannibal2.skyhanni.features.garden.GardenVisitorFeatures;
+import at.hannibal2.skyhanni.features.garden.GardenVisitorTimer;
import at.hannibal2.skyhanni.features.garden.SkyMartBestProfit;
import at.hannibal2.skyhanni.features.inventory.*;
import at.hannibal2.skyhanni.features.itemabilities.FireVeilWandParticles;
@@ -52,6 +53,7 @@ import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper;
import at.hannibal2.skyhanni.test.LorenzTest;
import at.hannibal2.skyhanni.test.PacketTest;
import at.hannibal2.skyhanni.utils.MinecraftConsoleFilter;
+import at.hannibal2.skyhanni.utils.TabListData;
import kotlin.coroutines.EmptyCoroutineContext;
import kotlinx.coroutines.*;
import net.minecraft.client.Minecraft;
@@ -112,6 +114,7 @@ public class SkyHanniMod {
loadModule(new RenderLivingEntityHelper());
loadModule(new SkillExperience());
loadModule(new InventoryData());
+ loadModule(new TabListData());
//features
loadModule(new BazaarOrderHelper());
@@ -201,6 +204,7 @@ public class SkyHanniMod {
loadModule(new SkyMartBestProfit());
loadModule(new GardenVisitorFeatures());
loadModule(new GardenInventoryNumbers());
+ loadModule(new GardenVisitorTimer());
Commands.INSTANCE.init();
diff --git a/src/main/java/at/hannibal2/skyhanni/config/Features.java b/src/main/java/at/hannibal2/skyhanni/config/Features.java
index 13ebf5106..42c64290d 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/Features.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/Features.java
@@ -146,6 +146,11 @@ public class Features extends Config {
editOverlay(activeConfigCategory, 200, 16, garden.visitorHelperPos);
return;
}
+
+ if (runnableId.equals("visitorHelperTimer")) {
+ editOverlay(activeConfigCategory, 200, 16, garden.visitorHelperTimerPos);
+ return;
+ }
}
@Expose
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java b/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java
index 139567c97..45624e7f4 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java
@@ -29,6 +29,25 @@ public class Garden {
public boolean visitorHelper = false;
@Expose
+ @ConfigOption(name = "Visitor Timer", desc = "")
+ @ConfigAccordionId(id = 1)
+ @ConfigEditorAccordion(id = 2)
+ public boolean visitorHelperTimer = false;
+
+ @Expose
+ @ConfigOption(name = "Visitor Timer", desc = "Timer when the next visitor will appear," +
+ "and a number how many visitors are already waiting.")
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean visitorHelperTimerEnabled = true;
+
+ @Expose
+ @ConfigOption(name = "Visitor Timer Position", desc = "")
+ @ConfigEditorButton(runnableId = "visitorHelperTimer", buttonText = "Edit")
+ @ConfigAccordionId(id = 2)
+ public Position visitorHelperTimerPos = new Position(0, 0, false, true);
+
+ @Expose
@ConfigOption(name = "Visitor Display", desc = "Show all items needed for the visitors.")
@ConfigEditorBoolean
@ConfigAccordionId(id = 1)
@@ -54,18 +73,18 @@ public class Garden {
@Expose
@ConfigOption(name = "Numbers", desc = "")
- @ConfigEditorAccordion(id = 2)
+ @ConfigEditorAccordion(id = 3)
public boolean numbers = false;
@Expose
@ConfigOption(name = "Crop Milestone", desc = "Show the number of the crop milestone in the inventory.")
@ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
+ @ConfigAccordionId(id = 3)
public boolean cropMilestoneNumber = true;
@Expose
@ConfigOption(name = "Crop Upgrades", desc = "Show the number of upgrades in the crop upgrades inventory.")
@ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
+ @ConfigAccordionId(id = 3)
public boolean cropUpgradesNumber = true;
}
diff --git a/src/main/java/at/hannibal2/skyhanni/data/HyPixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HyPixelData.kt
index 174c5d3d0..458d94260 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/HyPixelData.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/HyPixelData.kt
@@ -5,7 +5,7 @@ import at.hannibal2.skyhanni.events.LorenzChatEvent
import at.hannibal2.skyhanni.events.ProfileJoinEvent
import at.hannibal2.skyhanni.utils.LorenzLogger
import at.hannibal2.skyhanni.utils.StringUtils.removeColor
-import at.hannibal2.skyhanni.utils.TabListUtils
+import at.hannibal2.skyhanni.utils.TabListData
import net.minecraft.client.Minecraft
import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
@@ -125,7 +125,7 @@ class HyPixelData {
private fun checkIsland() {
var newIsland = ""
var guesting = false
- for (line in TabListUtils.getTabList()) {
+ for (line in TabListData.getTabList()) {
if (line.startsWith("§b§lArea: ")) {
newIsland = line.split(": ")[1].removeColor()
}
diff --git a/src/main/java/at/hannibal2/skyhanni/events/TabListUpdateEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/TabListUpdateEvent.kt
new file mode 100644
index 000000000..4524cbd05
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/events/TabListUpdateEvent.kt
@@ -0,0 +1,3 @@
+package at.hannibal2.skyhanni.events
+
+class TabListUpdateEvent(val tabList: List<String>): LorenzEvent() \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorTimer.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorTimer.kt
new file mode 100644
index 000000000..3125cfc36
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorTimer.kt
@@ -0,0 +1,64 @@
+package at.hannibal2.skyhanni.features.garden
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.IslandType
+import at.hannibal2.skyhanni.events.TabListUpdateEvent
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.RenderUtils.renderString
+import at.hannibal2.skyhanni.utils.TimeUtils
+import net.minecraftforge.client.event.RenderGameOverlayEvent
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import java.util.regex.Pattern
+
+class GardenVisitorTimer {
+ private val patternNextVisitor = Pattern.compile(" Next Visitor: §r§b(.*)")
+ private val patternVisitors = Pattern.compile("§b§lVisitors: §r§f\\((\\d)\\)")
+ private var render = ""
+ private var lastMillis = 0L
+
+ @SubscribeEvent
+ fun onTick(event: TabListUpdateEvent) {
+ if (!isEnabled()) return
+
+ var visitorsAmount = 0
+ var millis = 15 * 60_000L
+ for (line in event.tabList) {
+ var matcher = patternNextVisitor.matcher(line)
+ if (matcher.matches()) {
+ val rawTime = matcher.group(1)
+ millis = TimeUtils.getMillis(rawTime)
+ }
+
+ matcher = patternVisitors.matcher(line)
+ if (matcher.matches()) {
+ visitorsAmount = matcher.group(1).toInt()
+ }
+ }
+
+ val diff = lastMillis - millis
+ if (diff == 0L) return
+ lastMillis = millis
+
+ val extraSpeed = if (diff in 1001..10_000) {
+ val factor = diff / 1000
+ "§f/§e" + TimeUtils.formatDuration(millis / factor)
+ } else ""
+
+ val visitorLabel = if (visitorsAmount == 1) "Visitor" else "Visitors"
+ val formatDuration = TimeUtils.formatDuration(millis)
+ render = "§b$visitorsAmount $visitorLabel §f(Next in §e$formatDuration$extraSpeed§f)"
+ }
+
+ @SubscribeEvent
+ fun onRenderOverlay(event: RenderGameOverlayEvent.Post) {
+ if (event.type != RenderGameOverlayEvent.ElementType.ALL) return
+ if (!isEnabled()) return
+
+ SkyHanniMod.feature.garden.visitorHelperTimerPos.renderString(render)
+ }
+
+ private fun isEnabled() =
+ LorenzUtils.inSkyBlock &&
+ SkyHanniMod.feature.garden.visitorHelperTimerEnabled &&
+ LorenzUtils.skyBlockIsland == IslandType.GARDEN
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/CrimsonIsleReputationHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/CrimsonIsleReputationHelper.kt
index c4d5d311e..887df0617 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/CrimsonIsleReputationHelper.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/CrimsonIsleReputationHelper.kt
@@ -10,7 +10,7 @@ import at.hannibal2.skyhanni.features.nether.reputationhelper.miniboss.DailyMini
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.LorenzVec
import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems
-import at.hannibal2.skyhanni.utils.TabListUtils
+import at.hannibal2.skyhanni.utils.TabListData
import com.google.gson.JsonObject
import net.minecraftforge.client.event.RenderGameOverlayEvent
import net.minecraftforge.fml.common.eventhandler.EventPriority
@@ -59,7 +59,7 @@ class CrimsonIsleReputationHelper(skyHanniMod: SkyHanniMod) {
tick++
if (tick % 60 == 0) {
- TabListUtils.getTabList()
+ TabListData.getTabList()
.filter { it.contains("Reputation:") }
.forEach {
factionType = if (it.contains("Mage")) {
diff --git a/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/dailyquest/QuestLoader.kt b/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/dailyquest/QuestLoader.kt
index e4bba6494..2444cb0be 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/dailyquest/QuestLoader.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/dailyquest/QuestLoader.kt
@@ -5,7 +5,7 @@ import at.hannibal2.skyhanni.features.nether.reputationhelper.dailyquest.quest.*
import at.hannibal2.skyhanni.utils.InventoryUtils.getInventoryName
import at.hannibal2.skyhanni.utils.ItemUtils.getLore
import at.hannibal2.skyhanni.utils.LorenzUtils
-import at.hannibal2.skyhanni.utils.TabListUtils
+import at.hannibal2.skyhanni.utils.TabListData
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.inventory.GuiChest
import net.minecraft.inventory.ContainerChest
@@ -14,7 +14,7 @@ class QuestLoader(private val dailyQuestHelper: DailyQuestHelper) {
fun loadFromTabList() {
var i = -1
- for (line in TabListUtils.getTabList()) {
+ for (line in TabListData.getTabList()) {
if (line.contains("Faction Quests:")) {
i = 0
continue
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt b/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt
new file mode 100644
index 000000000..760e40450
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt
@@ -0,0 +1,117 @@
+package at.hannibal2.skyhanni.utils
+
+import at.hannibal2.skyhanni.events.PacketEvent
+import at.hannibal2.skyhanni.events.TabListUpdateEvent
+import at.hannibal2.skyhanni.utils.LorenzUtils.sorted
+import net.minecraft.network.play.server.S38PacketPlayerListItem
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import java.util.*
+
+class TabListData {
+
+ private val uuidMap = mutableMapOf<UUID, TabListPlayer>()
+ private val tabListMap = mutableMapOf<TabListPlayer, String>()
+
+ class TabListPlayer(var displayName: String, var internalName: String)
+
+ @SubscribeEvent
+ fun onChatPacket(event: PacketEvent.ReceiveEvent) {
+ val packet = event.packet
+ if (packet is S38PacketPlayerListItem) {
+ val action = packet.action
+ if (action == S38PacketPlayerListItem.Action.UPDATE_LATENCY) return
+
+ val entries = packet.entries
+ if (action == S38PacketPlayerListItem.Action.REMOVE_PLAYER) {
+// println("REMOVE_PLAYER")
+// println("old: " + uuidMap.size)
+ for (entry in entries) {
+ val profile = entry.profile
+ val id = profile.id
+ val key = uuidMap.remove(id)
+ tabListMap.remove(key)
+ }
+// println("new: " + uuidMap.size)
+ update()
+ return
+ }
+
+ val size = entries.size
+ if (size != 1) {
+ println("wrong size: $size")
+ return
+ }
+ val entry = entries[0]
+ val profile = entry.profile
+ val id = profile.id
+ val name = profile.name
+ if (name != null) {
+ if (!name.contains("-")) {
+ return
+ }
+ }
+
+ val text = entry?.displayName?.formattedText ?: ""
+ val formattedName = LorenzUtils.stripVanillaMessage(text)
+ if (action == S38PacketPlayerListItem.Action.ADD_PLAYER) {
+// println("ADD_PLAYER")
+ val tabList = TabListPlayer(formattedName, name)
+
+ if (uuidMap.contains(id)) {
+ val key = uuidMap.remove(id)
+ val internalName = key!!.internalName
+ val displayName = key.displayName
+// println("")
+// println("internalName: $internalName")
+// println("displayName: $displayName")
+ tabListMap.remove(key)
+ }
+
+// println("new name: $name")
+// println("new formattedName: $formattedName")
+
+ uuidMap[id] = tabList
+ tabListMap[tabList] = name
+ update()
+ return
+ }
+
+ if (action == S38PacketPlayerListItem.Action.UPDATE_DISPLAY_NAME) {
+// println("UPDATE_DISPLAY_NAME")
+ val listPlayer = uuidMap[id]!!
+// println("old: '" + listPlayer.displayName + "'")
+// println("new: '$formattedName'")
+
+ listPlayer.displayName = formattedName
+ update()
+ return
+ }
+ }
+ }
+
+ private fun update() {
+ val result = mutableListOf<String>()
+ if (uuidMap.size == 80) {
+ var i = 0
+ for (tabList in tabListMap.sorted().keys) {
+ val contains = uuidMap.values.contains(tabList)
+ if (contains) {
+ val displayName = tabList.displayName
+ result.add(displayName)
+ i++
+ }
+ }
+ } else if (uuidMap.isNotEmpty()) return
+ val list = result.toList()
+ cache = list
+ TabListUpdateEvent(list).postAndCatch()
+
+ }
+
+ companion object {
+ private var cache = listOf<String>()
+
+ // TODO replace with TabListUpdateEvent
+ fun getTabList() = cache
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TabListUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/TabListUtils.kt
deleted file mode 100644
index a81675f74..000000000
--- a/src/main/java/at/hannibal2/skyhanni/utils/TabListUtils.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package at.hannibal2.skyhanni.utils
-
-import com.google.common.collect.ComparisonChain
-import com.google.common.collect.Ordering
-import net.minecraft.client.Minecraft
-import net.minecraft.client.network.NetworkPlayerInfo
-import net.minecraft.world.WorldSettings
-import net.minecraftforge.fml.relauncher.Side
-import net.minecraftforge.fml.relauncher.SideOnly
-
-object TabListUtils {
-
- private val playerOrdering = Ordering.from(PlayerComparator())
-
- @SideOnly(Side.CLIENT)
- internal class PlayerComparator : Comparator<NetworkPlayerInfo> {
- override fun compare(o1: NetworkPlayerInfo, o2: NetworkPlayerInfo): Int {
- val team1 = o1.playerTeam
- val team2 = o2.playerTeam
- return ComparisonChain.start().compareTrueFirst(
- o1.gameType != WorldSettings.GameType.SPECTATOR,
- o2.gameType != WorldSettings.GameType.SPECTATOR
- )
- .compare(
- if (team1 != null) team1.registeredName else "",
- if (team2 != null) team2.registeredName else ""
- )
- .compare(o1.gameProfile.name, o2.gameProfile.name).result()
- }
- }
-
- fun getTabList(): List<String> {
- val players = playerOrdering.sortedCopy(Minecraft.getMinecraft().thePlayer.sendQueue.playerInfoMap)
- val result: MutableList<String> = ArrayList()
- for (info in players) {
- val name = Minecraft.getMinecraft().ingameGUI.tabList.getPlayerName(info)
- result.add(LorenzUtils.stripVanillaMessage(name))
- }
- return result
- }
-} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
index 107395886..f7a684630 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
@@ -1,6 +1,12 @@
package at.hannibal2.skyhanni.utils
+import java.util.regex.Pattern
+
object TimeUtils {
+
+ private val pattern =
+ Pattern.compile("(?:(?<y>\\d+)y(?:\\w* ?)?)?(?:(?<d>\\d+)d(?:\\w* ?)?)?(?:(?<h>\\d+)h(?:\\w* ?)?)?(?:(?<m>\\d+)m(?:\\w* ?)?)?(?:(?<s>\\d+)s(?:\\w* ?)?)?")
+
fun formatDuration(
millis: Long,
biggestUnit: TimeUnit = TimeUnit.YEAR,
@@ -41,6 +47,28 @@ object TimeUtils {
}
return builder.toString()
}
+
+ fun getMillis(string: String): Long {
+ val matcher = pattern.matcher(string.lowercase().trim())
+ if (!matcher.matches()) {
+ throw RuntimeException("Matcher is null for '$string'")
+ }
+
+ val years = matcher.group("y")?.toLong() ?: 0L
+ val days = matcher.group("d")?.toLong() ?: 0L
+ val hours = matcher.group("h")?.toLong() ?: 0L
+ val minutes = matcher.group("m")?.toLong() ?: 0L
+ val seconds = matcher.group("s")?.toLong() ?: 0L
+
+ var millis = 0L
+ millis += seconds * 1000
+ millis += minutes * 60 * 1000
+ millis += hours * 60 * 60 * 1000
+ millis += days * 24 * 60 * 60 * 1000
+ millis += (years * 365.25 * 24 * 60 * 60 * 1000).toLong()
+
+ return millis
+ }
}
private const val FACTOR_SECONDS = 1000L