aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md8
-rw-r--r--src/main/java/de/cowtipper/cowlection/command/MooCommand.java2
-rw-r--r--src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java20
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/ChatListener.java4
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java85
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java7
6 files changed, 90 insertions, 36 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7c65f95..2f69cc1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Overlay can be moved more precisely
- Dungeons can be "joined" and "left" manually (if the automatic detection fails): `/moo dungeon <enter/leave>`
- Improved handling of invalid/missing Hypixel API key
+- `/moo stalkskyblock` Switched from sky.lea.moe (discontinued) to sky.shiiyu.moe
+
+### Fixed
+- Fixed crash caused by another, outdated and buggy mod which sadly too many people still use
+- various smaller fixes here and there, e.g.:
+ - 'Create Auction' and 'Create BIN Auction' now show the price per item if multiple items are sold
+ - Dungeon party finder: entered vs queued floor wasn't detected correctly
+ - A dead player was counted as another death when they left the SkyBlock dungeon
## [1.8.9-0.10.2] - 15.09.2020
### Added
diff --git a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java
index edbfc62..d3dc658 100644
--- a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java
+++ b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java
@@ -378,7 +378,7 @@ public class MooCommand extends CommandBase {
wealthHover.appendFreshSibling(new MooChatComponent.KeyValueTooltipComponent("Co-ops' purses sum", Utils.formatNumberWithAbbreviations(activeProfile.getCoopCoinPurses(stalkedPlayer.getUuid()))));
}
- MooChatComponent sbStats = new MooChatComponent("SkyBlock stats of " + stalkedPlayer.getName() + " (" + activeProfile.getCuteName() + ")").gold().bold().setUrl("https://sky.lea.moe/stats/" + stalkedPlayer.getName() + "/" + activeProfile.getCuteName(), "Click to view SkyBlock stats on sky.lea.moe")
+ MooChatComponent sbStats = new MooChatComponent("SkyBlock stats of " + stalkedPlayer.getName() + " (" + activeProfile.getCuteName() + ")").gold().bold().setUrl("https://sky.shiiyu.moe/stats/" + stalkedPlayer.getName() + "/" + activeProfile.getCuteName(), "Click to view SkyBlock stats on sky.shiiyu.moe")
.appendFreshSibling(new MooChatComponent.KeyValueChatComponent("Coins", coinsBankAndPurse).setHover(wealthHover));
// highest skill + skill average:
if (highestSkill != null) {
diff --git a/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java b/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java
index 07a1fe4..d7fd5da 100644
--- a/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java
+++ b/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java
@@ -15,6 +15,7 @@ import java.util.stream.Collectors;
public class DungeonCache {
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;
@@ -22,11 +23,13 @@ public class DungeonCache {
private int elapsedMinutes;
private int classMilestone;
private long lastScoreboardCheck;
+ private long nextPerformanceSend;
private String queuedFloor;
public DungeonCache(Cowlection main) {
this.main = main;
deathCounter = new HashMap<>();
+ deadPlayers = new HashSet<>();
failedPuzzles = new HashSet<>();
destroyedCrypts = new HashSet<>();
}
@@ -58,6 +61,10 @@ public class DungeonCache {
}
public void sendDungeonPerformance() {
+ if (System.currentTimeMillis() < nextPerformanceSend) {
+ // already sent dungeon performance less than 260ms ago
+ return;
+ }
String dungeonPerformance;
boolean hasPointPenalty = false;
if (deathCounter.isEmpty()) {
@@ -77,6 +84,7 @@ public class DungeonCache {
dungeonPerformance += "\n" + EnumChatFormatting.LIGHT_PURPLE + "➜ " + EnumChatFormatting.RED + EnumChatFormatting.BOLD + "Skill " + EnumChatFormatting.RED + "score penalty: " + EnumChatFormatting.DARK_RED + getSkillScorePenalty() + " points";
}
main.getChatHelper().sendMessage(EnumChatFormatting.WHITE, dungeonPerformance);
+ nextPerformanceSend = System.currentTimeMillis() + 260;
}
public void updateElapsedMinutesFromScoreboard() {
@@ -117,13 +125,21 @@ public class DungeonCache {
this.queuedFloor = floorNr;
}
- public void addDeath(String playerName) {
+ public void addDeath(String playerName, boolean ghostByDisconnecting) {
+ if (!deadPlayers.add(playerName) && ghostByDisconnecting) {
+ // dead player disconnected from the game; don't count again!
+ return;
+ }
int previousPlayerDeaths = deathCounter.getOrDefault(playerName, 0);
deathCounter.put(playerName, previousPlayerDeaths + 1);
new TickDelay(this::sendDungeonPerformance, 1);
}
+ public void revivedPlayer(String playerName) {
+ deadPlayers.remove(playerName);
+ }
+
public void addFailedPuzzle(String text) {
failedPuzzles.add(text);
}
@@ -176,10 +192,12 @@ public class DungeonCache {
// resetter
private void resetCounters() {
deathCounter.clear();
+ deadPlayers.clear();
failedPuzzles.clear();
destroyedCrypts.clear();
elapsedMinutes = 0;
classMilestone = 0;
+ nextPerformanceSend = 0;
queuedFloor = null;
}
}
diff --git a/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java b/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java
index 318907d..68d602e 100644
--- a/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java
+++ b/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java
@@ -11,6 +11,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiChat;
import net.minecraft.client.gui.GuiControls;
import net.minecraft.client.gui.GuiNewChat;
+import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.StringUtils;
@@ -73,8 +74,7 @@ public class ChatListener {
}
if (MooConfig.showBestFriendNotifications) {
// replace default (friend/guild) notification with best friend notification
- main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, "" + EnumChatFormatting.DARK_GREEN + EnumChatFormatting.BOLD + "Best friend" + EnumChatFormatting.DARK_GREEN + " > " + EnumChatFormatting.RESET + rank + playerName + joinLeaveSuffix);
- e.setCanceled(true);
+ e.message = new ChatComponentText("" + EnumChatFormatting.DARK_GREEN + EnumChatFormatting.BOLD + "Best friend" + EnumChatFormatting.DARK_GREEN + " > " + EnumChatFormatting.RESET + rank + playerName + joinLeaveSuffix);
return;
}
}
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 edbadb0..e4fea69 100644
--- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java
+++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java
@@ -6,6 +6,7 @@ import de.cowtipper.cowlection.config.gui.MooConfigGui;
import de.cowtipper.cowlection.data.DataHelper.DungeonClass;
import de.cowtipper.cowlection.handler.DungeonCache;
import de.cowtipper.cowlection.util.TickDelay;
+import de.cowtipper.cowlection.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SoundCategory;
import net.minecraft.client.gui.FontRenderer;
@@ -57,6 +58,11 @@ public class DungeonsListener {
*/
private final Pattern DUNGEON_PARTY_FINDER_PLAYER = Pattern.compile("^ (?:\\w+): ([A-Za-z]+) \\((\\d+)\\)$");
/**
+ * examples: "Floor: Entrance", "Floor: Floor 4", "Floor: Floor IV"
+ */
+ private final Pattern DUNGEON_PARTY_FINDER_FLOOR = Pattern.compile("^Floor: (Entrance)?(?:Floor ([IVX]+)?([0-9]+)?)?$");
+ private final Pattern DUNGEON_PARTY_FINDER_SELECTED_FLOOR = Pattern.compile("^Currently Selected: (Entrance)?(?:Floor ([IVX]+)?([0-9]+)?)?$");
+ /**
* example: (Adventuring|Playing|Plundering|Looting|...) The Catacombs with 5/5 players on Floor II!
*/
private final Pattern DUNGEON_ENTERED_DUNGEON = Pattern.compile("^[A-Za-z ]+ The Catacombs( Entrance)? with [0-9]+/[0-9]+ players(?: on Floor ([IVX]+))?!$");
@@ -92,7 +98,8 @@ 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:
* <ul>
@@ -274,7 +281,7 @@ public class DungeonsListener {
IInventory inventory = inventorySlots.getSlot(0).inventory;
if (inventory.getName().equals("Catacombs Gate")) {
// update active selected class
- ItemStack dungeonClassIndicator = inventory.getStackInSlot(47);
+ ItemStack dungeonClassIndicator = getStackInSlotOrByName(inventory, 47, "Dungeon Classes");
if (dungeonClassIndicator == null) {
// couldn't detect dungeon class indicator
return;
@@ -392,6 +399,21 @@ public class DungeonsListener {
}
}
+ private ItemStack getStackInSlotOrByName(IInventory inventory, int slot, String itemDisplayName) {
+ ItemStack item = inventory.getStackInSlot(slot);
+ if (item != null && item.hasDisplayName() && itemDisplayName.equals(EnumChatFormatting.getTextWithoutFormattingCodes(item.getDisplayName()))) {
+ return item;
+ }
+ // an update might have moved the item to another slot, search for it:
+ for (int checkedSlot = 0; checkedSlot < inventory.getSizeInventory(); checkedSlot++) {
+ item = inventory.getStackInSlot(slot);
+ if (item != null && item.hasDisplayName() && itemDisplayName.equals(EnumChatFormatting.getTextWithoutFormattingCodes(item.getDisplayName()))) {
+ return item;
+ }
+ }
+ return null;
+ }
+
// Events inside dungeons
@SubscribeEvent
public void onDungeonsEnterOrLeave(PlayerSetSpawnEvent e) {
@@ -452,12 +474,15 @@ public class DungeonsListener {
}
// player is in dungeon:
Matcher dungeonDeathMatcher = DUNGEON_DEATH_PATTERN.matcher(text);
+ Matcher dungeonRevivedMatcher = DUNGEON_REVIVED_PATTERN.matcher(text);
if (dungeonDeathMatcher.matches()) {
String playerName = dungeonDeathMatcher.group(1);
if (playerName.equals("You")) {
playerName = Minecraft.getMinecraft().thePlayer.getName();
}
- main.getDungeonCache().addDeath(playerName);
+ main.getDungeonCache().addDeath(playerName, dungeonDeathMatcher.group(2).contains("disconnected"));
+ } else if (dungeonRevivedMatcher.matches()) {
+ main.getDungeonCache().revivedPlayer(dungeonRevivedMatcher.group(1));
} else if (text.trim().equals("> EXTRA STATS <")) {
// dungeon "end screen"
new TickDelay(() -> main.getDungeonCache().sendDungeonPerformance(), 5);
@@ -502,18 +527,7 @@ public class DungeonsListener {
// not a valid dungeon party tooltip
return;
}
- for (String toolTipLine : itemToolTip) {
- String line = EnumChatFormatting.getTextWithoutFormattingCodes(toolTipLine);
- if (line.startsWith("Floor: ")) {
- // extract floor number
- int lastSpace = line.lastIndexOf(' ');
- if (lastSpace > 5) {
- String floorNr = line.substring(lastSpace + 1);
- main.getDungeonCache().setQueuedFloor(floorNr);
- }
- break;
- }
- }
+ extractQueuedFloorNr(itemToolTip, DUNGEON_PARTY_FINDER_FLOOR);
}
} else if (inventory.getName().equals("Group Builder")) {
// get dungeon floor nr when creating a dungeon party for party finder
@@ -523,25 +537,14 @@ public class DungeonsListener {
String clickedItemName = EnumChatFormatting.getTextWithoutFormattingCodes(hoveredSlot.getStack().getDisplayName());
if (clickedItemName.equals("Confirm Group")) {
// created dungeon party group
- ItemStack selectedFloorItem = inventory.getStackInSlot(13);
- if (selectedFloorItem != null && selectedFloorItem.hasDisplayName() && EnumChatFormatting.getTextWithoutFormattingCodes(selectedFloorItem.getDisplayName()).equals("Select Floor")) {
+ ItemStack selectedFloorItem = getStackInSlotOrByName(inventory, 12, "Select Floor");
+ if (selectedFloorItem != null) {
List<String> itemToolTip = selectedFloorItem.getTooltip(Minecraft.getMinecraft().thePlayer, false);
if (itemToolTip.size() < 5) {
// not a valid dungeon floor tooltip
return;
}
- for (String toolTipLine : itemToolTip) {
- String line = EnumChatFormatting.getTextWithoutFormattingCodes(toolTipLine);
- if (line.startsWith("Currently Selected: ")) {
- // extract floor number
- int lastSpace = line.lastIndexOf(' ');
- if (lastSpace > 18) {
- String floorNr = line.substring(lastSpace + 1);
- main.getDungeonCache().setQueuedFloor(floorNr);
- break;
- }
- }
- }
+ extractQueuedFloorNr(itemToolTip, DUNGEON_PARTY_FINDER_SELECTED_FLOOR);
}
}
}
@@ -549,6 +552,30 @@ public class DungeonsListener {
}
}
+ private void extractQueuedFloorNr(List<String> itemToolTip, Pattern pattern) {
+ for (String toolTipLine : itemToolTip) {
+ String line = EnumChatFormatting.getTextWithoutFormattingCodes(toolTipLine);
+
+ Matcher floorMatcher = pattern.matcher(line);
+ if (floorMatcher.matches()) {
+ String floorNr = floorMatcher.group(1); // floor == Entrance
+ if (floorNr == null) {
+ floorNr = floorMatcher.group(2); // floor == [IVX]+
+ }
+ if (floorNr == null) {
+ try {
+ int floorNrArabic = Integer.parseInt(floorMatcher.group(3));
+ floorNr = Utils.convertArabicToRoman(floorNrArabic); // floor == [0-9]+
+ } catch (NumberFormatException ex) {
+ floorNr = null;
+ }
+ }
+ main.getDungeonCache().setQueuedFloor(floorNr);
+ break;
+ }
+ }
+ }
+
private Slot getSlotUnderMouse(GuiChest guiChest) {
try {
return ReflectionHelper.getPrivateValue(GuiContainer.class, guiChest, "theSlot", "field_147006_u");
diff --git a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java
index 29b5e51..11f2cda 100644
--- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java
+++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java
@@ -134,7 +134,7 @@ public class SkyBlockListener {
String toolTipLineUnformatted = EnumChatFormatting.getTextWithoutFormattingCodes(toolTip.get(i));
if (toolTipLineUnformatted.startsWith("Top bid: ")
|| toolTipLineUnformatted.startsWith("Starting bid: ")
- || toolTipLineUnformatted.startsWith("Create BIN Auction: ")
+ || toolTipLineUnformatted.startsWith("Item price: ")
|| toolTipLineUnformatted.startsWith("Buy it now: ")
|| toolTipLineUnformatted.startsWith("Sold for: ")
|| toolTipLineUnformatted.startsWith("New bid: ") /* special case: 'Submit Bid' item */) {
@@ -167,7 +167,8 @@ public class SkyBlockListener {
}
private boolean isSubmitBidItem(ItemStack itemStack) {
- return (itemStack.getItem().equals(Items.gold_nugget) || itemStack.getItem().equals(Item.getItemFromBlock(Blocks.gold_block)))
- && (itemStack.hasDisplayName() && (itemStack.getDisplayName().endsWith("Submit Bid") || itemStack.getDisplayName().endsWith("Collect Auction")));
+ return ((itemStack.getItem().equals(Items.gold_nugget) || itemStack.getItem().equals(Item.getItemFromBlock(Blocks.gold_block)))
+ && (itemStack.hasDisplayName() && (itemStack.getDisplayName().endsWith("Submit Bid") || itemStack.getDisplayName().endsWith("Collect Auction"))))
+ || (/* green hardened clay + */ itemStack.hasDisplayName() && (itemStack.getDisplayName().endsWith("Create BIN Auction") || itemStack.getDisplayName().endsWith("Create Auction")));
}
}