aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/cowtipper/cowlection
diff options
context:
space:
mode:
authorCow <cow@volloeko.de>2020-12-31 14:29:30 +0100
committerCow <cow@volloeko.de>2020-12-31 14:29:30 +0100
commit0c9d088dcb47a422c1566baeefae702c4cad0a0a (patch)
tree792a130c4f192e989f2e4a4aee387bf09c7bc85d /src/main/java/de/cowtipper/cowlection
parent3c3dee8e27ee7e7b3c75456b8ad300516ffb1ce5 (diff)
downloadCowlection-0c9d088dcb47a422c1566baeefae702c4cad0a0a.tar.gz
Cowlection-0c9d088dcb47a422c1566baeefae702c4cad0a0a.tar.bz2
Cowlection-0c9d088dcb47a422c1566baeefae702c4cad0a0a.zip
Small dungeons related fixes
- Fixed deaths sometimes being counted multiple times - Read destroyed crypts from tab list (if available) - Fixed rarely occurring infinite message loop
Diffstat (limited to 'src/main/java/de/cowtipper/cowlection')
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/MooConfig.java4
-rw-r--r--src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java106
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java11
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java6
4 files changed, 89 insertions, 38 deletions
diff --git a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java
index f666181..63856af 100644
--- a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java
+++ b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java
@@ -398,8 +398,8 @@ public class MooConfig {
subCat = configCat.addSubCategory("Performance Overlay");
subCat.addExplanations(EnumChatFormatting.UNDERLINE + "Keeps track of:",
" ‣ skill score " + EnumChatFormatting.GRAY + "(reduced by deaths and failed puzzles)",
- " ‣ speed score " + EnumChatFormatting.GRAY + "(-2.2 points when over 20 minutes)",
- " ‣ bonus score " + EnumChatFormatting.GRAY + "(+1 [max 5] for each destroyed crypt; can only be detected up to ~50 blocks away from the player)",
+ " ‣ speed score " + EnumChatFormatting.GRAY + "(-2.2 points/minute when over 20 minutes)",
+ " ‣ bonus score " + EnumChatFormatting.GRAY + "(+1 [max 5] for each destroyed crypt; if 'enhanced tab list' is disabled: limited to ~50 blocks away from the player)",
"Does " + EnumChatFormatting.ITALIC + "not" + EnumChatFormatting.RESET + " track explorer score " + EnumChatFormatting.GRAY + "(explored rooms, secrets, ...)");
Property propDungOverlayEnabled = subCat.addConfigEntry(cfg.get(configCat.getConfigName(),
diff --git a/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java b/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java
index d7fd5da..e06ba7d 100644
--- a/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java
+++ b/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java
@@ -1,23 +1,31 @@
package de.cowtipper.cowlection.handler;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
import de.cowtipper.cowlection.Cowlection;
import de.cowtipper.cowlection.util.TickDelay;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiPlayerTabOverlay;
+import net.minecraft.client.network.NetworkPlayerInfo;
import net.minecraft.scoreboard.Score;
import net.minecraft.scoreboard.ScoreObjective;
import net.minecraft.scoreboard.ScorePlayerTeam;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.world.WorldSettings;
import java.util.*;
import java.util.stream.Collectors;
public class DungeonCache {
+ private static final Ordering<NetworkPlayerInfo> playerOrderer = Ordering.from(new PlayerComparator());
+
private final Cowlection main;
private final Map<String, Integer> deathCounter;
private final Set<String> deadPlayers;
private final Set<String> failedPuzzles;
private final Set<UUID> destroyedCrypts;
+ private int cryptsOffset;
private boolean isInDungeon;
private int elapsedMinutes;
@@ -32,6 +40,7 @@ public class DungeonCache {
deadPlayers = new HashSet<>();
failedPuzzles = new HashSet<>();
destroyedCrypts = new HashSet<>();
+ cryptsOffset = 0;
}
public boolean isInDungeon() {
@@ -87,36 +96,63 @@ public class DungeonCache {
nextPerformanceSend = System.currentTimeMillis() + 260;
}
- public void updateElapsedMinutesFromScoreboard() {
+ /**
+ * Fetch info from scoreboard (right) and tab list
+ */
+ public void fetchScoreboardData() {
long now = System.currentTimeMillis();
if (now - lastScoreboardCheck > 10000) { // run every 10 seconds
lastScoreboardCheck = now;
- Scoreboard scoreboard = Minecraft.getMinecraft().theWorld.getScoreboard();
- ScoreObjective scoreboardSidebar = scoreboard.getObjectiveInDisplaySlot(1);
- if (scoreboardSidebar != null) {
- Collection<Score> scoreboardLines = scoreboard.getSortedScores(scoreboardSidebar);
- for (Score line : scoreboardLines) {
- ScorePlayerTeam scorePlayerTeam = scoreboard.getPlayersTeam(line.getPlayerName());
- if (scorePlayerTeam != null) {
- String lineWithoutFormatting = EnumChatFormatting.getTextWithoutFormattingCodes(scorePlayerTeam.getColorPrefix() + scorePlayerTeam.getColorSuffix());
-
- String timeElapsed = "Time Elapsed: ";
- if (lineWithoutFormatting.startsWith(timeElapsed)) {
- // dungeon timer: 05m 22s
- String timeString = lineWithoutFormatting.substring(timeElapsed.length());
- try {
- int indexOfMinute = timeString.indexOf('m');
- if (indexOfMinute > -1) {
- elapsedMinutes = (Integer.parseInt(timeString.substring(0, indexOfMinute)));
+ Minecraft mc = Minecraft.getMinecraft();
+ if (mc.theWorld != null) {
+ Scoreboard scoreboard = mc.theWorld.getScoreboard();
+
+ // check scoreboard (right)
+ ScoreObjective scoreboardSidebar = scoreboard.getObjectiveInDisplaySlot(1);
+ if (scoreboardSidebar != null) {
+ Collection<Score> scoreboardLines = scoreboard.getSortedScores(scoreboardSidebar);
+ for (Score line : scoreboardLines) {
+ ScorePlayerTeam scorePlayerTeam = scoreboard.getPlayersTeam(line.getPlayerName());
+ if (scorePlayerTeam != null) {
+ String lineWithoutFormatting = EnumChatFormatting.getTextWithoutFormattingCodes(scorePlayerTeam.getColorPrefix() + scorePlayerTeam.getColorSuffix());
+
+ String timeElapsed = "Time Elapsed: ";
+ if (lineWithoutFormatting.startsWith(timeElapsed)) {
+ // dungeon timer: 05m 22s
+ String timeString = lineWithoutFormatting.substring(timeElapsed.length());
+ try {
+ int indexOfMinute = timeString.indexOf('m');
+ if (indexOfMinute > -1) {
+ elapsedMinutes = (Integer.parseInt(timeString.substring(0, indexOfMinute)));
+ }
+ } catch (NumberFormatException ex) {
+ // couldn't parse dungeon time from scoreboard
+ ex.printStackTrace();
}
- } catch (NumberFormatException ex) {
- // couldn't parse dungeon time from scoreboard
- ex.printStackTrace();
}
}
}
}
}
+
+ // check tab list
+ Collection<NetworkPlayerInfo> playerInfoMap = mc.thePlayer.sendQueue.getPlayerInfoMap();
+ List<NetworkPlayerInfo> networkPlayerInfos = playerOrderer.sortedCopy(playerInfoMap);
+ GuiPlayerTabOverlay tabList = mc.ingameGUI.getTabList();
+ for (NetworkPlayerInfo playerInfo : networkPlayerInfos) {
+ if (playerInfo.getGameProfile().getName().startsWith("!")) {
+ String tabListEntry = EnumChatFormatting.getTextWithoutFormattingCodes(tabList.getPlayerName(playerInfo));
+ if (tabListEntry != null && tabListEntry.startsWith(" Crypts: ")) {
+ try {
+ int cryptsFromTabList = Integer.parseInt(tabListEntry.substring(" Crypts: ".length()).trim());
+ cryptsOffset = cryptsFromTabList - destroyedCrypts.size();
+ } catch (NumberFormatException | IndexOutOfBoundsException ex) {
+ // couldn't parse crypts count from tab list
+ ex.printStackTrace();
+ }
+ }
+ }
+ }
}
}
@@ -125,9 +161,10 @@ public class DungeonCache {
this.queuedFloor = floorNr;
}
- public void addDeath(String playerName, boolean ghostByDisconnecting) {
- if (!deadPlayers.add(playerName) && ghostByDisconnecting) {
- // dead player disconnected from the game; don't count again!
+ public void addDeath(String playerName) {
+ boolean playerWasDeadAlready = !deadPlayers.add(playerName);
+ if (playerWasDeadAlready) {
+ // dead player "died" again (e.g. caused by disconnecting while being dead); don't count again!
return;
}
int previousPlayerDeaths = deathCounter.getOrDefault(playerName, 0);
@@ -148,8 +185,8 @@ public class DungeonCache {
this.classMilestone = classMilestone;
}
- public boolean addDestroyedCrypt(UUID uuid) {
- return destroyedCrypts.add(uuid);
+ public void addDestroyedCrypt(UUID uuid) {
+ destroyedCrypts.add(uuid);
}
// getter
@@ -182,7 +219,7 @@ public class DungeonCache {
}
public int getDestroyedCrypts() {
- return destroyedCrypts.size();
+ return destroyedCrypts.size() + cryptsOffset;
}
public int getElapsedMinutes() {
@@ -195,9 +232,24 @@ public class DungeonCache {
deadPlayers.clear();
failedPuzzles.clear();
destroyedCrypts.clear();
+ cryptsOffset = 0;
elapsedMinutes = 0;
classMilestone = 0;
nextPerformanceSend = 0;
queuedFloor = null;
}
+
+ /**
+ * see: GuiPlayerTabOverlay.PlayerComparator
+ */
+ static class PlayerComparator implements Comparator<NetworkPlayerInfo> {
+ private PlayerComparator() {
+ }
+
+ public int compare(NetworkPlayerInfo playerInfo1, NetworkPlayerInfo playerInfo2) {
+ ScorePlayerTeam scorePlayerTeam1 = playerInfo1.getPlayerTeam();
+ ScorePlayerTeam scorePlayerTeam2 = playerInfo2.getPlayerTeam();
+ return ComparisonChain.start().compareTrueFirst(playerInfo1.getGameType() != WorldSettings.GameType.SPECTATOR, playerInfo2.getGameType() != WorldSettings.GameType.SPECTATOR).compare(scorePlayerTeam1 != null ? scorePlayerTeam1.getRegisteredName() : "", scorePlayerTeam2 != null ? scorePlayerTeam2.getRegisteredName() : "").compare(playerInfo1.getGameProfile().getName(), playerInfo2.getGameProfile().getName()).result();
+ }
+ }
}
diff --git a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java
index 918c63d..5a65a36 100644
--- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java
+++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java
@@ -91,7 +91,7 @@ public class DungeonsListener {
* <li> ☠ You were killed by [mob] and became a ghost.</li>
* </ul>
*/
- private final Pattern DUNGEON_DEATH_PATTERN = Pattern.compile("^ ☠ (\\w+) (.+) and became a ghost\\.$");
+ private final Pattern DUNGEON_DEATH_PATTERN = Pattern.compile("^ ☠ (\\w+) (?:.+) and became a ghost\\.$");
private final Pattern DUNGEON_REVIVED_PATTERN = Pattern.compile("^ ❣ (\\w+) was revived(?:.*?)$");
/**
* Class milestones:
@@ -443,7 +443,7 @@ public class DungeonsListener {
if (playerName.equals("You")) {
playerName = Minecraft.getMinecraft().thePlayer.getName();
}
- main.getDungeonCache().addDeath(playerName, dungeonDeathMatcher.group(2).contains("disconnected"));
+ main.getDungeonCache().addDeath(playerName);
} else if (dungeonRevivedMatcher.matches()) {
main.getDungeonCache().revivedPlayer(dungeonRevivedMatcher.group(1));
} else if (text.trim().equals("> EXTRA STATS <")) {
@@ -559,10 +559,7 @@ public class DungeonsListener {
return;
}
if ("Crypt Undead".equals(e.player.getName())) {
- boolean isNewDestroyedCrypt = main.getDungeonCache().addDestroyedCrypt(e.player.getUniqueID());
- if (isNewDestroyedCrypt) {
- main.getLogger().info("[Dungeon Bonus Score] Crypt Undead spawned @ " + e.player.getPosition() + " - distance to player: " + Math.sqrt(e.player.getPosition().distanceSq(Minecraft.getMinecraft().thePlayer.getPosition())));
- }
+ main.getDungeonCache().addDestroyedCrypt(e.player.getUniqueID());
}
}
@@ -572,7 +569,7 @@ public class DungeonsListener {
DungeonCache dungeonCache = main.getDungeonCache();
if (dungeonCache.isInDungeon()) {
- dungeonCache.updateElapsedMinutesFromScoreboard();
+ dungeonCache.fetchScoreboardData();
}
boolean isEditingDungeonOverlaySettings = MooConfigGui.showDungeonPerformanceOverlay();
diff --git a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java
index 775634d..84a58ee 100644
--- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java
+++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java
@@ -62,10 +62,12 @@ public class DungeonsPartyListener {
@SubscribeEvent(priority = EventPriority.HIGHEST, receiveCanceled = true)
public void onMessageReceived(ClientChatReceivedEvent e) {
if (e.type != 2 && listenForChatMsgs) { // normal chat or system msg (not above action bar), and not stopped
- if (msgCounter > 15) {
+ if (msgCounter == 15) {
// received too many messages without detecting any party-related lines, abort!
+ listenForChatMsgs = false;
+ shutdown();
main.getChatHelper().sendMessage(EnumChatFormatting.RED, "Wasn't able to detect the party member list. Maybe the chat formatting was changed?");
- nextStep = Step.STOP;
+ return;
}
++msgCounter;