aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java50
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java31
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java37
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java26
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java24
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt157
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableEnums.kt28
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsDryStreakDisplay.kt113
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsProfitTracker.kt258
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt (renamed from src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/GuardianReminder.kt)32
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt272
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairsClicksAlert.kt (renamed from src/main/java/at/hannibal2/skyhanni/features/inventory/SuperpairsClicksAlert.kt)6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/UltraRareBookAlert.kt (renamed from src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/UltraRareBookAlert.kt)39
16 files changed, 1011 insertions, 74 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt
index 8eb47d394..b9f21ca22 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt
+++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt
@@ -12,7 +12,7 @@ import com.google.gson.JsonPrimitive
object ConfigUpdaterMigrator {
val logger = LorenzLogger("ConfigMigration")
- const val CONFIG_VERSION = 58
+ const val CONFIG_VERSION = 59
fun JsonElement.at(chain: List<String>, init: Boolean): JsonElement? {
if (chain.isEmpty()) return this
if (this !is JsonObject) return null
diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
index 3f2ddace6..9b85c2cf9 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
+++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
@@ -57,6 +57,7 @@ import at.hannibal2.skyhanni.features.garden.pests.PestFinder
import at.hannibal2.skyhanni.features.garden.pests.PestProfitTracker
import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorDropStatistics
import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentsProfitTracker
import at.hannibal2.skyhanni.features.mining.KingTalismanHelper
import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay
import at.hannibal2.skyhanni.features.mining.fossilexcavator.ExcavatorProfitTracker
@@ -277,6 +278,10 @@ object Commands {
"Resets the Pest Profit Tracker",
) { PestProfitTracker.resetCommand() }
registerCommand(
+ "shresetexperimentsprofittracker",
+ "Resets the Experiments Profit Tracker",
+ ) { ExperimentsProfitTracker.resetCommand() }
+ registerCommand(
"shresetmythologicalcreaturetracker",
"Resets the Mythological Creature Tracker",
) { MythologicalCreatureTracker.resetCommand() }
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java
index 5c3bf3170..062f29b30 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java
@@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.config.FeatureToggle;
import at.hannibal2.skyhanni.config.HasLegacyId;
import at.hannibal2.skyhanni.config.features.inventory.chocolatefactory.ChocolateFactoryConfig;
import at.hannibal2.skyhanni.config.features.inventory.customwardrobe.CustomWardrobeConfig;
+import at.hannibal2.skyhanni.config.features.inventory.experimentationtable.ExperimentationTableConfig;
import at.hannibal2.skyhanni.config.features.inventory.helper.HelperConfig;
import at.hannibal2.skyhanni.config.features.itemability.ItemAbilityConfig;
import at.hannibal2.skyhanni.config.features.misc.EstimatedItemValueConfig;
@@ -39,6 +40,10 @@ public class InventoryConfig {
public BazaarConfig bazaar = new BazaarConfig();
@Expose
+ @Category(name = "Experimentation Table", desc = "QOL features for the Experimentation Table.")
+ public ExperimentationTableConfig experimentationTable = new ExperimentationTableConfig();
+
+ @Expose
@Category(name = "Enchant Parsing", desc = "Settings for SkyHanni's Enchant Parsing")
public EnchantParsingConfig enchantParsing = new EnchantParsingConfig();
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java
new file mode 100644
index 000000000..dfdad2482
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java
@@ -0,0 +1,50 @@
+package at.hannibal2.skyhanni.config.features.inventory.experimentationtable;
+
+import at.hannibal2.skyhanni.config.FeatureToggle;
+import at.hannibal2.skyhanni.config.core.config.Position;
+import com.google.gson.annotations.Expose;
+import io.github.notenoughupdates.moulconfig.annotations.Accordion;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigLink;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
+
+public class ExperimentationTableConfig {
+
+ @Expose
+ @ConfigOption(name = "Profit Tracker", desc = "")
+ @Accordion
+ public ExperimentsProfitTrackerConfig experimentsProfitTracker = new ExperimentsProfitTrackerConfig();
+
+ @Expose
+ @ConfigOption(name = "Dry-Streak Display", desc = "")
+ @Accordion
+ public ExperimentsDryStreakConfig dryStreak = new ExperimentsDryStreakConfig();
+
+ @Expose
+ @ConfigOption(name = "Superpair Data", desc = "Shows a display with useful information while doing the Superpair experiment.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean superpairDisplay = false;
+
+ @Expose
+ @ConfigLink(owner = ExperimentationTableConfig.class, field = "superpairDisplay")
+ public Position superpairDisplayPosition = new Position(-372, 161, false, true);
+
+ @Expose
+ @ConfigOption(name = "Superpairs Clicks Alert", desc = "Display an alert when you reach the maximum clicks gained from Chronomatron or Ultrasequencer.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean superpairsClicksAlert = false;
+
+ @Expose
+ @ConfigOption(name = "ULTRA-RARE Book Alert", desc = "Send a chat message, title and sound when you find an ULTRA-RARE book.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean ultraRareBookAlert = false;
+
+ @Expose
+ @ConfigOption(name = "Guardian Reminder", desc = "Sends a warning when opening the Experimentation Table without a §9§lGuardian Pet §7equipped.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean guardianReminder = false;
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java
new file mode 100644
index 000000000..dfba626a7
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java
@@ -0,0 +1,31 @@
+package at.hannibal2.skyhanni.config.features.inventory.experimentationtable;
+
+import at.hannibal2.skyhanni.config.FeatureToggle;
+import at.hannibal2.skyhanni.config.core.config.Position;
+import com.google.gson.annotations.Expose;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigLink;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
+
+public class ExperimentsDryStreakConfig {
+
+ @Expose
+ @ConfigOption(name = "Enabled", desc = "Display attempts and or XP since your last ULTRA-RARE.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean enabled = false;
+
+ @Expose
+ @ConfigOption(name = "Attempts", desc = "Display Attempts since.")
+ @ConfigEditorBoolean
+ public boolean attemptsSince = true;
+
+ @Expose
+ @ConfigOption(name = "XP", desc = "Display XP since.")
+ @ConfigEditorBoolean
+ public boolean xpSince = true;
+
+ @Expose
+ @ConfigLink(owner = ExperimentsDryStreakConfig.class, field = "enabled")
+ public Position position = new Position(200, -187, false, true);
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java
new file mode 100644
index 000000000..62ee4f540
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java
@@ -0,0 +1,37 @@
+package at.hannibal2.skyhanni.config.features.inventory.experimentationtable;
+
+import at.hannibal2.skyhanni.config.FeatureToggle;
+import at.hannibal2.skyhanni.config.core.config.Position;
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentMessages;
+import com.google.gson.annotations.Expose;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigLink;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExperimentsProfitTrackerConfig {
+
+ @Expose
+ @ConfigOption(name = "Enabled", desc = "Tracker for drops/XP you get from experiments.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean enabled = false;
+
+ @Expose
+ @ConfigOption(name = "Hide Messages", desc = "Change the messages to be hidden after completing Add-on/Main experiments.")
+ @ConfigEditorDraggableList
+ public List<ExperimentMessages> hideMessages = new ArrayList<>();
+
+ @Expose
+ @ConfigOption(name = "Time displayed", desc = "Time displayed after completing an experiment.")
+ @ConfigEditorSlider(minValue = 5, maxValue = 60, minStep = 1)
+ public int timeDisplayed = 30;
+
+ @Expose
+ @ConfigLink(owner = ExperimentsProfitTrackerConfig.class, field = "enabled")
+ public Position position = new Position(20, 20, false, true);
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java
index 5f54e707d..717dd7659 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java
@@ -56,30 +56,4 @@ public class HelperConfig {
@ConfigOption(name = "Reforge Helper", desc = "")
@Accordion
public ReforgeHelperConfig reforge = new ReforgeHelperConfig();
-
- @Expose
- @ConfigOption(name = "Enchanting", desc = "")
- @Accordion
- public EnchantingConfig enchanting = new EnchantingConfig();
-
- public static class EnchantingConfig {
- @Expose
- @ConfigOption(name = "Superpairs Clicks Alert", desc = "Display an alert when you reach the maximum clicks gained from Chronomatron or Ultrasequencer.")
- @ConfigEditorBoolean
- @FeatureToggle
- public boolean superpairsClicksAlert = false;
-
- @Expose
- @ConfigOption(name = "ULTRA-RARE Book Alert", desc = "Send a chat message, title and sound when you find an ULTRA-RARE book.")
- @ConfigEditorBoolean
- @FeatureToggle
- public boolean ultraRareBookAlert = false;
-
- @Expose
- @ConfigOption(name = "Guardian Reminder", desc = "Sends a warning when opening the Experimentation Table without a §9§lGuardian Pet §7equipped.")
- @ConfigEditorBoolean
- @FeatureToggle
- public boolean guardianReminder = false;
- }
-
}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java
index 83e7ea47c..754eea3bb 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java
@@ -31,6 +31,7 @@ import at.hannibal2.skyhanni.features.garden.pests.PestProfitTracker;
import at.hannibal2.skyhanni.features.garden.pests.VinylType;
import at.hannibal2.skyhanni.features.garden.visitor.VisitorReward;
import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker;
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentsProfitTracker;
import at.hannibal2.skyhanni.features.inventory.wardrobe.WardrobeAPI;
import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay;
import at.hannibal2.skyhanni.features.mining.fossilexcavator.ExcavatorProfitTracker;
@@ -66,6 +67,29 @@ public class ProfileSpecificStorage {
public String currentPet = "";
@Expose
+ public ExperimentationStorage experimentation = new ExperimentationStorage();
+
+ public static class ExperimentationStorage {
+
+ @Expose
+ public LorenzVec tablePos = new LorenzVec();
+
+ @Expose
+ public ExperimentsDryStreakStorage dryStreak = new ExperimentsDryStreakStorage();
+
+ public static class ExperimentsDryStreakStorage {
+ @Expose
+ public int attemptsSince = 0;
+
+ @Expose
+ public int xpSince = 0;
+ }
+
+ @Expose
+ public ExperimentsProfitTracker.Data experimentsProfitTracker = new ExperimentsProfitTracker.Data();
+ }
+
+ @Expose
public ChocolateFactoryStorage chocolateFactory = new ChocolateFactoryStorage();
public static class ChocolateFactoryStorage {
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt
new file mode 100644
index 000000000..80433b68e
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt
@@ -0,0 +1,157 @@
+package at.hannibal2.skyhanni.features.inventory.experimentationtable
+
+import at.hannibal2.skyhanni.data.IslandType
+import at.hannibal2.skyhanni.data.ProfileStorageData
+import at.hannibal2.skyhanni.events.InventoryUpdatedEvent
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.utils.EntityUtils
+import at.hannibal2.skyhanni.utils.EntityUtils.hasSkullTexture
+import at.hannibal2.skyhanni.utils.InventoryUtils.openInventoryName
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzVec
+import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher
+import at.hannibal2.skyhanni.utils.RegexUtils.matches
+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
+
+@SkyHanniModule
+object ExperimentationTableAPI {
+
+ private val storage get() = ProfileStorageData.profileSpecific?.experimentation
+
+ val inTable get() = inventoriesPattern.matches(openInventoryName())
+
+ fun inDistanceToTable(vec: LorenzVec, max: Double): Boolean =
+ storage?.tablePos?.let { it.distance(vec) <= max } ?: false
+
+ fun getCurrentExperiment(): Experiment? =
+ superpairsPattern.matchMatcher(openInventoryName()) {
+ Experiment.entries.find { it.nameString == group("experiment") }
+ }
+
+ @SubscribeEvent
+ fun onInventoryUpdated(event: InventoryUpdatedEvent) {
+ if (LorenzUtils.skyBlockIsland != IslandType.PRIVATE_ISLAND || !inTable) return
+
+ val entity = EntityUtils.getEntities<EntityArmorStand>().find { it.hasSkullTexture(experimentationTableSkull) } ?: return
+ val vec = entity.getLorenzVec()
+ if (storage?.tablePos != vec) storage?.tablePos = vec
+ }
+
+ private val experimentationTableSkull =
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTUyOWF" +
+ "iYzg4MzA5NTNmNGQ5MWVkZmZmMjQ2OTVhOWY2Mjc1OGZhNGM1MWIyOWFjMjQ2YzM3NDllYWFlODliMyJ9fX0="
+
+ private val patternGroup = RepoPattern.group("enchanting.experiments")
+
+ /**
+ * REGEX-TEST: Superpairs (Metaphysical)
+ */
+ private val superpairsPattern by patternGroup.pattern(
+ "superpairs",
+ "Superpairs \\((?<experiment>\\w+)\\)",
+ )
+
+ /**
+ * REGEX-TEST: Gained +3 Clicks
+ */
+ val powerUpPattern by patternGroup.pattern(
+ "powerups",
+ "Gained \\+\\d Clicks?|Instant Find|\\+\\S* XP",
+ )
+
+ /**
+ * REGEX-TEST: 123k Enchanting Exp
+ * REGEX-TEST: Titanic Experience Bottle
+ */
+ val rewardPattern by patternGroup.pattern(
+ "rewards",
+ "\\d{1,3}k Enchanting Exp|Enchanted Book|(?:Titanic |Grand |\\b)Experience Bottle|Metaphysical Serum|Experiment The Fish",
+ )
+
+ /**
+ * REGEX-TEST: Superpairs (Metaphysical)
+ * REGEX-TEST: Chronomatron (Metaphysical)
+ */
+ val inventoriesPattern by patternGroup.pattern(
+ "inventories",
+ "(?:Superpairs|Chronomatron|Ultrasequencer) (?:\\(.+\\)|➜ Stakes|Rewards)|Experimentation Table",
+ )
+
+ /**
+ * REGEX-TEST: +42,000 Enchanting Exp
+ */
+ val enchantingExpChatPattern by patternGroup.pattern(
+ "chatexp",
+ "^ \\+(?<amount>\\d+|\\d+,\\d+)k? Enchanting Exp$",
+ )
+
+ /**
+ * REGEX-TEST: +Smite VII
+ * REGEX-TEST: +42,000 Enchanting Exp
+ */
+ val experimentsDropPattern by patternGroup.pattern(
+ "drop",
+ "^ \\+(?<reward>.*)\$",
+ )
+
+ /**
+ * REGEX-TEST: You claimed the Superpairs rewards!
+ */
+ val claimMessagePattern by patternGroup.pattern(
+ "claim",
+ "You claimed the \\S+ rewards!",
+ )
+
+ /**
+ * REGEX-TEST: 131k Enchanting Exp
+ * REGEX-TEST: 42,000 Enchanting Exp
+ */
+ val enchantingExpPattern by patternGroup.pattern(
+ "exp",
+ "(?<amount>\\d+|\\d+,\\d+)k? Enchanting Exp",
+ )
+
+ /**
+ * REGEX-TEST: Titanic Experience Bottle
+ */
+ val experienceBottlePattern by patternGroup.pattern(
+ "xpbottle",
+ "(?:Titanic |Grand |\\b)Experience Bottle",
+ )
+
+ /**
+ * REGEX-TEST: ☕ You renewed the experiment table! (1/3)
+ */
+ val experimentRenewPattern by patternGroup.pattern(
+ "renew",
+ "^☕ You renewed the experiment table! \\((?<current>\\d)/3\\)$",
+ )
+
+ /**
+ * REGEX-TEST: §d§kXX§5 ULTRA-RARE BOOK! §d§kXX
+ */
+ val ultraRarePattern by patternGroup.pattern(
+ "ultrarare",
+ "§d§kXX§5 ULTRA-RARE BOOK! §d§kXX",
+ )
+
+ /**
+ * REGEX-TEST: §9Smite VII
+ */
+ val bookPattern by patternGroup.pattern(
+ "book",
+ "§9(?<enchant>.*)",
+ )
+
+ /**
+ * REGEX-TEST: §dGuardian
+ * REGEX-TEST: §9Guardian§e
+ */
+ val petNamePattern by patternGroup.pattern(
+ "guardianpet",
+ "§[956d]Guardian.*",
+ )
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableEnums.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableEnums.kt
new file mode 100644
index 000000000..0071d3af3
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableEnums.kt
@@ -0,0 +1,28 @@
+package at.hannibal2.skyhanni.features.inventory.experimentationtable
+
+enum class ExperimentMessages(private val str: String) {
+ DONE("§eYou claimed the §dSuperpairs §erewards! §8(§7Claim§8)"),
+ EXPERIENCE("§8 +§3141k Experience §8(§7Experience Drops§8)"),
+ ENCHANTMENTS("§8 +§9Smite VII §8(§7Enchantment Drops§8)"),
+ BOTTLES("§8 +§9Titanic Experience Bottle §8(§7Bottle Drops§8)"),
+ MISC("§8 +§5Metaphysical Serum §8(§7Misc Drops§8)");
+
+ override fun toString(): String {
+ return str
+ }
+}
+
+enum class Experiment(val nameString: String, val gridSize: Int, val startSlot: Int, val endSlot: Int, val sideSpace: Int) {
+ NONE("", 0, 0, 0, 0),
+ BEGINNER("Beginner", 14, 18, 35, 1),
+ HIGH("High", 20, 10, 43, 2),
+ GRAND("Grand", 20, 10, 43, 2),
+ SUPREME("Supreme", 28, 9, 44, 1),
+ TRANSCENDENT("Transcendent", 28, 9, 44, 1),
+ METAPHYSICAL("Metaphysical", 28, 9, 44, 1),
+ ;
+
+ override fun toString(): String {
+ return nameString
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsDryStreakDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsDryStreakDisplay.kt
new file mode 100644
index 000000000..50d033842
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsDryStreakDisplay.kt
@@ -0,0 +1,113 @@
+package at.hannibal2.skyhanni.features.inventory.experimentationtable
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.ProfileStorageData
+import at.hannibal2.skyhanni.events.GuiRenderEvent
+import at.hannibal2.skyhanni.events.InventoryCloseEvent
+import at.hannibal2.skyhanni.events.InventoryOpenEvent
+import at.hannibal2.skyhanni.events.InventoryUpdatedEvent
+import at.hannibal2.skyhanni.events.LorenzChatEvent
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.bookPattern
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.ultraRarePattern
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.utils.ChatUtils
+import at.hannibal2.skyhanni.utils.InventoryUtils
+import at.hannibal2.skyhanni.utils.ItemUtils.getLore
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat
+import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher
+import at.hannibal2.skyhanni.utils.RegexUtils.matches
+import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings
+import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+
+@SkyHanniModule
+object ExperimentsDryStreakDisplay {
+
+ private val config get() = SkyHanniMod.feature.inventory.experimentationTable.dryStreak
+ private val storage get() = ProfileStorageData.profileSpecific?.experimentation?.dryStreak
+
+ private var display = emptyList<String>()
+
+ private var didJustFind = false
+
+ @SubscribeEvent
+ fun onChestGuiOverlayRendered(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
+ if (!isEnabled()) return
+ if (!ExperimentationTableAPI.inventoriesPattern.matches(InventoryUtils.openInventoryName())) return
+
+ display = drawDisplay()
+ config.position.renderStrings(
+ display,
+ posLabel = "Experimentation Table Dry Streak",
+ )
+ }
+
+ @SubscribeEvent
+ fun onInventoryOpen(event: InventoryOpenEvent) {
+ if (event.inventoryName == "Experimentation Table" && didJustFind) didJustFind = false
+ }
+
+ @SubscribeEvent
+ fun onInventoryUpdated(event: InventoryUpdatedEvent) {
+ if (!isEnabled() || didJustFind || ExperimentationTableAPI.getCurrentExperiment() == null) return
+
+ for (lore in event.inventoryItems.map { it.value.getLore() }) {
+ val firstLine = lore.firstOrNull() ?: continue
+ if (!ultraRarePattern.matches(firstLine)) continue
+ val bookNameLine = lore.getOrNull(2) ?: continue
+ bookPattern.matchMatcher(bookNameLine) {
+ val storage = storage ?: return
+ ChatUtils.chat(
+ "§a§lDRY-STREAK ENDED! §eYou have (finally) " +
+ "found a §5ULTRA-RARE §eafter §3${storage.xpSince.shortFormat()} Enchanting Exp " +
+ "§e and §2${storage.attemptsSince} attempts§e!",
+ )
+ storage.attemptsSince = 0
+ storage.xpSince = 0
+ didJustFind = true
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onInventoryClose(event: InventoryCloseEvent) {
+ if (didJustFind || ExperimentationTableAPI.getCurrentExperiment() == null) return
+
+ val storage = storage ?: return
+ storage.attemptsSince += 1
+ }
+
+ @SubscribeEvent
+ fun onChat(event: LorenzChatEvent) {
+ if (!isEnabled() || didJustFind) return
+
+ ExperimentationTableAPI.enchantingExpChatPattern.matchMatcher(event.message.removeColor()) {
+ val storage = storage ?: return
+ storage.xpSince += group("amount").substringBefore(",").toInt() * 1000
+ }
+ }
+
+ private fun drawDisplay() = buildList {
+ val storage = storage ?: return@buildList
+
+ add("§cDry-Streak since last §5ULTRA-RARE")
+
+ val colorPrefix = "§e"
+ val attemptsSince = storage.attemptsSince
+ val xpSince = storage.xpSince.shortFormat()
+ val attemptsSuffix = if (attemptsSince == 1) "" else "s"
+
+ if (config.attemptsSince && config.xpSince) {
+ add("$colorPrefix ├ $attemptsSince Attempt$attemptsSuffix")
+ add("$colorPrefix └ $xpSince XP")
+ } else if (config.attemptsSince) {
+ add("$colorPrefix └ $attemptsSince Attempt$attemptsSuffix")
+ } else {
+ add("$colorPrefix └ $xpSince XP")
+ }
+ }
+
+ private fun isEnabled() =
+ LorenzUtils.inSkyBlock && config.enabled && (config.xpSince || config.attemptsSince)
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsProfitTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsProfitTracker.kt
new file mode 100644
index 000000000..16c0305cb
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsProfitTracker.kt
@@ -0,0 +1,258 @@
+package at.hannibal2.skyhanni.features.inventory.experimentationtable
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.ClickType
+import at.hannibal2.skyhanni.data.IslandType
+import at.hannibal2.skyhanni.events.GuiRenderEvent
+import at.hannibal2.skyhanni.events.InventoryCloseEvent
+import at.hannibal2.skyhanni.events.InventoryUpdatedEvent
+import at.hannibal2.skyhanni.events.IslandChangeEvent
+import at.hannibal2.skyhanni.events.ItemClickEvent
+import at.hannibal2.skyhanni.events.LorenzChatEvent
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.claimMessagePattern
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.enchantingExpPattern
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.experienceBottlePattern
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.experimentRenewPattern
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.experimentsDropPattern
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.inventoriesPattern
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut
+import at.hannibal2.skyhanni.utils.CollectionUtils.addSearchString
+import at.hannibal2.skyhanni.utils.InventoryUtils
+import at.hannibal2.skyhanni.utils.ItemPriceUtils.getNpcPriceOrNull
+import at.hannibal2.skyhanni.utils.ItemPriceUtils.getPrice
+import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
+import at.hannibal2.skyhanni.utils.ItemUtils.getInternalNameOrNull
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.round
+import at.hannibal2.skyhanni.utils.LorenzVec
+import at.hannibal2.skyhanni.utils.NEUInternalName
+import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
+import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat
+import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher
+import at.hannibal2.skyhanni.utils.RegexUtils.matches
+import at.hannibal2.skyhanni.utils.SimpleTimeMark
+import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+import at.hannibal2.skyhanni.utils.renderables.Searchable
+import at.hannibal2.skyhanni.utils.renderables.toSearchable
+import at.hannibal2.skyhanni.utils.tracker.ItemTrackerData
+import at.hannibal2.skyhanni.utils.tracker.SkyHanniItemTracker
+import com.google.gson.annotations.Expose
+import net.minecraft.item.ItemStack
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import kotlin.math.absoluteValue
+
+@SkyHanniModule
+object ExperimentsProfitTracker {
+
+ private val config get() = SkyHanniMod.feature.inventory.experimentationTable.experimentsProfitTracker
+
+ private val tracker = SkyHanniItemTracker(
+ "Experiments Profit Tracker",
+ { Data() },
+ { it.experimentation.experimentsProfitTracker },
+ ) { drawDisplay(it) }
+
+ private var lastSplashes = mutableListOf<ItemStack>()
+ private var lastSplashTime = SimpleTimeMark.farPast()
+ private var lastBottlesInInventory = mutableMapOf<NEUInternalName, Int>()
+ private var currentBottlesInInventory = mutableMapOf<NEUInternalName, Int>()
+
+ class Data : ItemTrackerData() {
+ override fun resetItems() {
+ experimentsDone = 0L
+ xpGained = 0L
+ bitCost = 0L
+ startCost = 0L
+ }
+
+ override fun getDescription(timesGained: Long): List<String> {
+ val percentage = timesGained.toDouble() / experimentsDone
+ val dropRate = LorenzUtils.formatPercentage(percentage.coerceAtMost(1.0))
+ return listOf(
+ "§7Dropped §e${timesGained.addSeparators()} §7times.",
+ "§7Your drop rate: §c$dropRate.",
+ )
+ }
+
+ override fun getCoinName(item: TrackedItem) = ""
+
+ override fun getCoinDescription(item: TrackedItem) = listOf<String>()
+
+ @Expose
+ var experimentsDone = 0L
+
+ @Expose
+ var xpGained = 0L
+
+ @Expose
+ var bitCost = 0L
+
+ @Expose
+ var startCost = 0L
+ }
+
+ @SubscribeEvent
+ fun onChat(event: LorenzChatEvent) {
+ if (!isEnabled()) return
+
+ val message = event.message.removeColor()
+ if (claimMessagePattern.matches(message) && ExperimentMessages.DONE.isSelected())
+ event.blockedReason = "CLAIM_MESSAGE"
+
+ experimentsDropPattern.matchMatcher(message) {
+ val reward = group("reward")
+
+ event.blockedReason = when {
+ enchantingExpPattern.matches(reward) && ExperimentMessages.EXPERIENCE.isSelected() -> "EXPERIENCE_DROP"
+ experienceBottlePattern.matches(reward) && ExperimentMessages.BOTTLES.isSelected() -> "BOTTLE_DROP"
+ listOf("Metaphysical Serum", "Experiment The Fish").contains(reward) && ExperimentMessages.MISC.isSelected() -> "MISC_DROP"
+ ExperimentMessages.ENCHANTMENTS.isSelected() -> "ENCHANT_DROP"
+ else -> ""
+ }
+
+ enchantingExpPattern.matchMatcher(reward) {
+ tracker.modify {
+ it.xpGained += group("amount").substringBefore(",").toInt() * 1000
+ }
+ return
+ }
+
+ val internalName = NEUInternalName.fromItemNameOrNull(reward) ?: return
+ if (!experienceBottlePattern.matches(group("reward"))) tracker.addItem(internalName, 1, false)
+ return
+ }
+
+ experimentRenewPattern.matchMatcher(message) {
+ val increments = mapOf(1 to 150, 2 to 300, 3 to 500)
+ tracker.modify {
+ it.bitCost += increments.getValue(group("current").toInt())
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onItemClick(event: ItemClickEvent) {
+ if (event.clickType == ClickType.RIGHT_CLICK) {
+ val item = event.itemInHand ?: return
+ if (experienceBottlePattern.matches(item.displayName.removeColor())) {
+ lastSplashTime = SimpleTimeMark.now()
+ lastSplashes.add(item)
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onInventoryUpdated(event: InventoryUpdatedEvent) {
+ if (!isEnabled()) return
+
+ if (inventoriesPattern.matches(event.inventoryName)) {
+ var startCostTemp = 0
+ val iterator = lastSplashes.iterator()
+ while (iterator.hasNext()) {
+ val item = iterator.next()
+ val internalName = item.getInternalName()
+ val price = internalName.getPrice()
+ val npcPrice = internalName.getNpcPriceOrNull() ?: 0.0
+ val maxPrice = npcPrice.coerceAtLeast(price)
+ startCostTemp += maxPrice.round(0).toInt()
+ iterator.remove()
+ }
+ tracker.modify {
+ it.startCost -= startCostTemp
+ }
+ lastSplashTime = SimpleTimeMark.farPast()
+ }
+
+ handleExpBottles(false)
+ }
+
+ @SubscribeEvent
+ fun onInventoryClose(event: InventoryCloseEvent) {
+ if (!isEnabled()) return
+
+ if (ExperimentationTableAPI.getCurrentExperiment() != null) {
+ tracker.modify {
+ it.experimentsDone++
+ }
+ }
+ if (ExperimentationTableAPI.inTable && InventoryUtils.openInventoryName() == "Superpairs Rewards") {
+ handleExpBottles(true)
+ }
+ }
+
+ private fun drawDisplay(data: Data): List<Searchable> = buildList {
+ addSearchString("§e§lExperiments Profit Tracker")
+ val profit = tracker.drawItems(data, { true }, this) + data.startCost
+
+ val experimentsDone = data.experimentsDone
+ addSearchString("")
+ addSearchString("§eExperiments Done: §a${experimentsDone.addSeparators()}")
+ val startCostFormat = data.startCost.absoluteValue.shortFormat()
+ val bitCostFormat = data.bitCost.shortFormat()
+ add(
+ Renderable.hoverTips(
+ "§eTotal Cost: §c-$startCostFormat§e/§b-$bitCostFormat",
+ listOf(
+ "§7You paid §c$startCostFormat §7coins and", "§b$bitCostFormat §7bits for starting",
+ "§7experiments.",
+ ),
+ ).toSearchable(),
+ )
+ add(tracker.addTotalProfit(profit, data.experimentsDone, "experiment"))
+ addSearchString("§eTotal Enchanting Exp: §b${data.xpGained.shortFormat()}")
+
+ tracker.addPriceFromButton(this)
+ }
+
+ @SubscribeEvent
+ fun onRenderOverlay(event: GuiRenderEvent) {
+ if (!isEnabled()) return
+
+ tracker.renderDisplay(config.position)
+ }
+
+ @SubscribeEvent
+ fun onIslandChange(event: IslandChangeEvent) {
+ if (event.newIsland == IslandType.PRIVATE_ISLAND) {
+ tracker.firstUpdate()
+ }
+ }
+
+ fun resetCommand() {
+ tracker.resetCommand()
+ }
+
+ private fun handleExpBottles(addToTracker: Boolean) {
+ for (item in InventoryUtils.getItemsInOwnInventory()) {
+ val internalName = item.getInternalNameOrNull() ?: continue
+ if (internalName.asString() !in listOf("EXP_BOTTLE", "GRAND_EXP_BOTTLE", "TITANIC_EXP_BOTTLE")) continue
+ currentBottlesInInventory.addOrPut(internalName, item.stackSize)
+ }
+ for ((internalName, amount) in currentBottlesInInventory) {
+ val lastInInv = lastBottlesInInventory.getOrDefault(internalName, 0)
+ if (lastInInv >= amount) {
+ currentBottlesInInventory[internalName] = 0
+ lastBottlesInInventory[internalName] = amount
+ continue
+ }
+ if (lastInInv == 0) {
+ currentBottlesInInventory[internalName] = 0
+ lastBottlesInInventory[internalName] = amount
+ if (addToTracker) tracker.addItem(internalName, amount, false)
+ continue
+ }
+
+ currentBottlesInInventory[internalName] = 0
+ lastBottlesInInventory[internalName] = amount
+ if (addToTracker) tracker.addItem(internalName, amount - lastInInv, false)
+ }
+ }
+
+ private fun ExperimentMessages.isSelected() = config.hideMessages.contains(this)
+
+ private fun isEnabled() =
+ LorenzUtils.inSkyBlock && config.enabled
+ && ExperimentationTableAPI.inDistanceToTable(LorenzVec.getBlockBelowPlayer(), 5.0)
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/GuardianReminder.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt
index 9ae93f227..216cbf7c6 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/GuardianReminder.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt
@@ -1,6 +1,7 @@
-package at.hannibal2.skyhanni.features.inventory.experiments
+package at.hannibal2.skyhanni.features.inventory.experimentationtable
import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator
import at.hannibal2.skyhanni.data.PetAPI
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent
@@ -16,7 +17,6 @@ import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.SoundUtils
import at.hannibal2.skyhanni.utils.renderables.Renderable
import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.renderXYAligned
-import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.inventory.GuiContainer
import net.minecraft.client.renderer.GlStateManager
@@ -28,31 +28,16 @@ import kotlin.time.Duration.Companion.seconds
@SkyHanniModule
object GuardianReminder {
- private val config get() = SkyHanniMod.feature.inventory.helper.enchanting
+ private val config get() = SkyHanniMod.feature.inventory.experimentationTable
private var lastInventoryOpen = SimpleTimeMark.farPast()
private var lastWarn = SimpleTimeMark.farPast()
private var lastErrorSound = SimpleTimeMark.farPast()
- private val patternGroup = RepoPattern.group("data.enchanting.inventory.experimentstable")
- private val inventoryNamePattern by patternGroup.pattern(
- "mainmenu",
- "Experimentation Table",
- )
-
- /**
- * REGEX-TEST: §dGuardian
- * REGEX-TEST: §9Guardian§e
- */
- private val petNamePattern by patternGroup.pattern(
- "guardianpet",
- "§[956d]Guardian.*",
- )
-
@SubscribeEvent
fun onInventory(event: InventoryFullyOpenedEvent) {
if (!isEnabled()) return
- if (!inventoryNamePattern.matches(event.inventoryName)) return
- if (petNamePattern.matches(PetAPI.currentPet)) return
+ if (event.inventoryName != "Experimentation Table") return
+ if (ExperimentationTableAPI.petNamePattern.matches(PetAPI.currentPet)) return
lastInventoryOpen = SimpleTimeMark.now()
@@ -69,7 +54,7 @@ object GuardianReminder {
@SubscribeEvent
fun onRenderOverlay(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
if (!isEnabled()) return
- if (!inventoryNamePattern.matches(InventoryUtils.openInventoryName())) return
+ if (InventoryUtils.openInventoryName() != "Experimentation Table") return
if (lastInventoryOpen.passedSince() > 2.seconds) return
val gui = Minecraft.getMinecraft().currentScreen as? GuiContainer ?: return
@@ -95,5 +80,10 @@ object GuardianReminder {
GlStateManager.popMatrix()
}
+ @SubscribeEvent
+ fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) {
+ event.move(59, "inventory.helper.enchanting.guardianReminder", "inventory.experimentationTable.guardianReminder")
+ }
+
private fun isEnabled() = LorenzUtils.inSkyBlock && config.guardianReminder
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt
new file mode 100644
index 000000000..21bc6052e
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt
@@ -0,0 +1,272 @@
+package at.hannibal2.skyhanni.features.inventory.experimentationtable
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.GuiContainerEvent.SlotClickEvent
+import at.hannibal2.skyhanni.events.GuiRenderEvent
+import at.hannibal2.skyhanni.events.InventoryCloseEvent
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.utils.InventoryUtils
+import at.hannibal2.skyhanni.utils.ItemUtils.getLore
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.RegexUtils.matches
+import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings
+import at.hannibal2.skyhanni.utils.SimpleTimeMark
+import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import net.minecraft.item.ItemStack
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import kotlin.time.Duration.Companion.milliseconds
+
+@SkyHanniModule
+object SuperpairExperimentInformationDisplay {
+
+ private val config get() = SkyHanniMod.feature.inventory.experimentationTable
+
+ private var display = emptyList<String>()
+
+ private var uncoveredAt = 0
+ private var uncoveredItems = mutableListOf<Pair<Int, String>>()
+ private var possiblePairs = 0
+
+ data class Item(val index: Int, val name: String)
+ data class ItemPair(val first: Item, val second: Item)
+
+ private var found = mutableMapOf<Pair<Item?, ItemPair?>, String>()
+
+ private var toCheck = mutableListOf<Pair<Int, Int>>()
+ private var lastClicked = mutableListOf<Pair<Int, Int>>()
+ private var lastClick = SimpleTimeMark.farPast()
+ private var currentExperiment = Experiment.NONE
+ private var instantFind = 0
+
+ private val sideSpaces1 = listOf(17, 18, 26, 27, 35, 36)
+ private val sideSpaces2 = listOf(16, 17, 18, 19, 25, 26, 27, 28, 34, 35, 36, 37)
+
+ @SubscribeEvent
+ fun onInventoryClose(event: InventoryCloseEvent) {
+ display = emptyList()
+
+ uncoveredAt = 0
+ uncoveredItems.clear()
+ possiblePairs = 0
+
+ found.clear()
+ toCheck.clear()
+ lastClicked.clear()
+ lastClick = SimpleTimeMark.farPast()
+ currentExperiment = Experiment.NONE
+ instantFind = 0
+ }
+
+ @SubscribeEvent
+ fun onChestGuiOverlayRendered(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
+ if (!isEnabled()) return
+ config.superpairDisplayPosition.renderStrings(display, posLabel = "Sperpair Experiment Information")
+ display = checkItems(toCheck)
+ }
+
+ @SubscribeEvent
+ fun onSlotClick(event: SlotClickEvent) {
+ if (!isEnabled()) return
+ currentExperiment = ExperimentationTableAPI.getCurrentExperiment() ?: return
+
+ if (isOutOfBounds(event.slotId, currentExperiment)) return
+ val item = event.item ?: return
+ if (item.displayName.removeColor() == "?") return
+ val clicksItem = InventoryUtils.getItemAtSlotIndex(4)
+
+ if (lastClicked.none { it.first == event.slotId && it.second == uncoveredAt } && lastClick.passedSince() > 100.milliseconds) {
+ if (clicksItem != null && clicksItem.displayName.removeColor().split(" ")[1] == "0") return
+ lastClicked.add(Pair(event.slotId, uncoveredAt))
+ lastClick = SimpleTimeMark.now()
+ toCheck.add(event.slotId to uncoveredAt)
+ uncoveredAt += 1
+ }
+ }
+
+ private fun checkItems(check: MutableList<Pair<Int, Int>>): List<String> {
+ currentExperiment = ExperimentationTableAPI.getCurrentExperiment() ?: return listOf()
+ if (check.isEmpty()) return drawDisplay()
+
+ for ((slot, uncovered) in check) {
+ val itemNow = InventoryUtils.getItemAtSlotIndex(slot) ?: return drawDisplay()
+ val itemName = itemNow.displayName.removeColor()
+
+ if (isWaiting(itemName) || isOutOfBounds(slot, currentExperiment)) return drawDisplay()
+
+ val reward = convertToReward(itemNow)
+ if (uncoveredItems.none { it.first == slot }) uncoveredItems.add(Pair(slot, reward))
+
+ when {
+ isPowerUp(reward) -> handlePowerUp(slot, reward)
+ isReward(itemName) -> handleReward(slot, uncovered, reward)
+ }
+
+ possiblePairs = calculatePossiblePairs()
+
+ val since = clicksSinceSeparator(lastClicked)
+
+ if ((since >= 2 || (since == -1 && lastClicked.size >= 2)) && instantFind == 0) {
+ lastClicked.add(-1 to uncoveredAt)
+ uncoveredAt += 1
+ }
+ toCheck.removeIf { it.first == slot }
+
+ return drawDisplay()
+ }
+ possiblePairs = calculatePossiblePairs()
+ return drawDisplay()
+ }
+
+ private fun handlePowerUp(slot: Int, reward: String) {
+ val item = toEither(Item(slot, reward))
+
+ found[item] = "Powerup"
+ possiblePairs--
+ lastClicked.removeIf { it.first == slot }
+ uncoveredAt -= 1
+ if (reward == "Instant Find") instantFind += 1
+ }
+
+ private fun handleReward(slot: Int, uncovered: Int, reward: String) {
+ val lastSlotClicked =
+ if (instantFind == 0 && lastClicked.none { it.first == -1 && it.second == uncovered - 1 } && lastClicked.size != 1) lastClicked.find { it.second == uncovered - 1 }
+ ?: return else lastClicked.find { it.second == uncovered } ?: return
+
+ val lastItem = InventoryUtils.getItemAtSlotIndex(lastSlotClicked.first) ?: return
+ val lastItemName = convertToReward(lastItem)
+
+ if (isWaiting(lastItemName)) return
+
+ when {
+ instantFind >= 1 -> {
+ handleFoundPair(slot, reward, lastSlotClicked.first)
+ instantFind -= 1
+ lastClicked.add(-1 to uncoveredAt)
+ uncoveredAt += 1
+ }
+
+ hasFoundPair(slot, lastSlotClicked.first, reward, lastItemName) -> handleFoundPair(
+ slot,
+ reward,
+ lastSlotClicked.first,
+ )
+
+ hasFoundMatch(slot, reward) -> handleFoundMatch(slot, reward)
+ else -> handleNormalReward(slot, reward)
+ }
+
+ }
+
+ private fun handleFoundPair(
+ slot: Int,
+ reward: String,
+ lastSlotClicked: Int,
+ ) {
+ val pair = toEither(ItemPair(Item(slot, reward), Item(lastSlotClicked, reward)))
+
+ found[pair] = "Pair"
+ found.entries.removeIf {
+ it.value == "Match" && right(it.key).first.name == reward
+ }
+ found.entries.removeIf {
+ it.value == "Normal" && (left(it.key).index == slot || left(it.key).index == lastSlotClicked)
+ }
+ }
+
+ private fun handleFoundMatch(slot: Int, reward: String) {
+ val match = uncoveredItems.find { it.second == reward }?.first ?: return
+ val pair = toEither(ItemPair(Item(slot, reward), Item(match, reward)))
+
+ found[pair] = "Match"
+ found.entries.removeIf {
+ it.value == "Normal" && (left(it.key).index == slot || left(it.key).index == match)
+ }
+ }
+
+ private fun handleNormalReward(slot: Int, reward: String) {
+ val item = toEither(Item(slot, reward))
+
+ if (found.none {
+ listOf("Match", "Pair").contains(it.value) && (right(it.key).first.index == slot || right(it.key).second.index == slot)
+ } && found.none { it.value == "Normal" && left(it.key).index == slot }) found[item] = "Normal"
+ }
+
+ private fun calculatePossiblePairs() =
+ ((currentExperiment.gridSize - 2) / 2) - found.filter { listOf("Pair", "Match", "Normal").contains(it.value) }.size
+
+ private fun drawDisplay() = buildList {
+ add("§6Superpair Experimentation Data")
+ add("")
+
+ val pairs = found.entries.filter { it.value == "Pair" }
+ val matches = found.entries.filter { it.value == "Match" }
+ val powerups = found.entries.filter { it.value == "Powerup" }
+ val normals = found.entries.filter { it.value == "Normal" }
+
+ if (pairs.isNotEmpty()) add("§2Found")
+ for (pair in pairs) {
+ val prefix = determinePrefix(pairs.indexOf(pair), pairs.lastIndex)
+ add(" $prefix §a${right(pair.key).first.name}")
+ }
+ if (matches.isNotEmpty()) add("§eMatched")
+ for (match in matches) {
+ val prefix = determinePrefix(matches.indexOf(match), matches.lastIndex)
+ add(" $prefix §e${right(match.key).first.name}")
+ }
+ if (powerups.isNotEmpty()) add("§bPowerUp")
+ for (powerup in powerups) {
+ val prefix = determinePrefix(powerups.indexOf(powerup), powerups.size - 1)
+ add(" $prefix §b${left(powerup.key).name}")
+ }
+ val toAdd = mutableListOf<String>()
+ if (possiblePairs >= 1) toAdd.add("§ePairs - $possiblePairs")
+ if (2 - powerups.size >= 1) toAdd.add("§bPowerUps - ${2 - powerups.size}")
+ if (normals.isNotEmpty()) toAdd.add("§7Normals - ${normals.size}")
+
+ if (toAdd.isNotEmpty()) {
+ add("")
+ add("§4Not found")
+ }
+ for (string in toAdd) if (string != toAdd.last()) add(" ├ $string") else add(" └ $string")
+ }
+
+ private fun convertToReward(item: ItemStack) = if (item.displayName.removeColor() == "Enchanted Book") item.getLore()[2].removeColor()
+ else item.displayName.removeColor()
+
+ private fun determinePrefix(index: Int, lastIndex: Int) = if (index == lastIndex) "└" else "├"
+
+ private fun hasFoundPair(
+ firstSlot: Int,
+ secondSlot: Int,
+ firstName: String,
+ secondName: String,
+ ) = firstSlot != secondSlot && firstName == secondName
+
+ private fun hasFoundMatch(itemSlot: Int, reward: String) =
+ uncoveredItems.any { (slot, name) -> slot != itemSlot && name == reward } && found.none {
+ listOf("Pair", "Match").contains(it.value) && (right(it.key).first.index == itemSlot || right(it.key).second.index == itemSlot)
+ }
+
+ private fun isPowerUp(reward: String) = ExperimentationTableAPI.powerUpPattern.matches(reward)
+
+ private fun isReward(reward: String) = ExperimentationTableAPI.rewardPattern.matches(reward)
+
+ private fun isWaiting(itemName: String) =
+ listOf("Click any button!", "Click a second button!", "Next button is instantly rewarded!").contains(itemName)
+
+ private fun clicksSinceSeparator(list: MutableList<Pair<Int, Int>>): Int {
+ val lastIndex = list.indexOfLast { it.first == -1 }
+ return if (lastIndex != -1) list.size - 1 - lastIndex else -1
+ }
+
+ private fun isOutOfBounds(slot: Int, experiment: Experiment): Boolean =
+ slot <= experiment.startSlot || slot >= experiment.endSlot || (if (experiment.sideSpace == 1) slot in sideSpaces1 else slot in sideSpaces2)
+
+ private fun left(it: Pair<Item?, ItemPair?>): Item = it.first ?: Item(-1, "")
+
+ private fun right(it: Pair<Item?, ItemPair?>): ItemPair = it.second ?: ItemPair(Item(-1, ""), Item(-1, ""))
+
+ private fun toEither(it: Any): Pair<Item?, ItemPair?> = if (it is Item) it to null else null to it as ItemPair
+
+ private fun isEnabled() = LorenzUtils.inSkyBlock && config.superpairDisplay && ExperimentationTableAPI.getCurrentExperiment() != null
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/SuperpairsClicksAlert.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairsClicksAlert.kt
index 5c5011c85..ef99c40ba 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/inventory/SuperpairsClicksAlert.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairsClicksAlert.kt
@@ -1,4 +1,4 @@
-package at.hannibal2.skyhanni.features.inventory
+package at.hannibal2.skyhanni.features.inventory.experimentationtable
import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator
@@ -14,7 +14,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
@SkyHanniModule
object SuperpairsClicksAlert {
- private val config get() = SkyHanniMod.feature.inventory.helper.enchanting
+ private val config get() = SkyHanniMod.feature.inventory.experimentationTable
private var roundsNeeded = -1
private val roundsNeededRegex = Regex("""(?:Chain|Series) of (\d+):""")
@@ -66,5 +66,7 @@ object SuperpairsClicksAlert {
@SubscribeEvent
fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) {
event.move(46, "misc.superpairsClicksAlert", "inventory.helper.enchanting.superpairsClicksAlert")
+
+ event.move(59, "inventory.helper.enchanting.superpairsClicksAlert", "inventory.experimentationTable.superpairsClicksAlert")
}
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/UltraRareBookAlert.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/UltraRareBookAlert.kt
index 1cc849cad..e6a9dda42 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/UltraRareBookAlert.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/UltraRareBookAlert.kt
@@ -1,13 +1,15 @@
-package at.hannibal2.skyhanni.features.inventory.experiments
+package at.hannibal2.skyhanni.features.inventory.experimentationtable
import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.InventoryCloseEvent
import at.hannibal2.skyhanni.events.InventoryUpdatedEvent
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.bookPattern
+import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.ultraRarePattern
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.ChatUtils
import at.hannibal2.skyhanni.utils.ColorUtils.withAlpha
-import at.hannibal2.skyhanni.utils.InventoryUtils
import at.hannibal2.skyhanni.utils.ItemUtils.getLore
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher
@@ -18,7 +20,6 @@ import at.hannibal2.skyhanni.utils.SoundUtils.createSound
import at.hannibal2.skyhanni.utils.SoundUtils.playSound
import at.hannibal2.skyhanni.utils.renderables.Renderable
import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.renderXYAligned
-import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.inventory.GuiContainer
import net.minecraft.client.renderer.GlStateManager
@@ -29,23 +30,9 @@ import kotlin.time.Duration.Companion.seconds
@SkyHanniModule
object UltraRareBookAlert {
- private val config get() = SkyHanniMod.feature.inventory.helper.enchanting
+ private val config get() = SkyHanniMod.feature.inventory.experimentationTable
private val dragonSound by lazy { createSound("mob.enderdragon.growl", 1f) }
- private val patternGroup = RepoPattern.group("data.enchanting")
- private val superpairsGui by patternGroup.pattern(
- "inventory.experimentstable.gui",
- "Superpairs.*"
- )
- private val ultraRarePattern by patternGroup.pattern(
- "inventory.experimentstable.ultrarare",
- "§d§kXX§5 ULTRA-RARE BOOK! §d§kXX"
- )
- private val bookPattern by patternGroup.pattern(
- "inventory.experimentstable.book",
- "§9(?<enchant>.*)"
- )
-
private var enchantsFound = false
private var lastNotificationTime = SimpleTimeMark.farPast()
@@ -58,9 +45,7 @@ object UltraRareBookAlert {
@SubscribeEvent
fun onRenderOverlay(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
- if (!LorenzUtils.inSkyBlock) return
- if (!config.ultraRareBookAlert) return
- if (!superpairsGui.matches(InventoryUtils.openInventoryName())) return
+ if (!isEnabled()) return
if (lastNotificationTime.passedSince() > 5.seconds) return
val gui = Minecraft.getMinecraft().currentScreen as? GuiContainer ?: return
@@ -80,10 +65,8 @@ object UltraRareBookAlert {
@SubscribeEvent
fun onInventoryUpdated(event: InventoryUpdatedEvent) {
- if (!LorenzUtils.inSkyBlock) return
- if (!config.ultraRareBookAlert) return
+ if (!isEnabled()) return
if (enchantsFound) return
- if (!superpairsGui.matches(event.inventoryName)) return
for (lore in event.inventoryItems.map { it.value.getLore() }) {
val firstLine = lore.firstOrNull() ?: continue
@@ -101,4 +84,12 @@ object UltraRareBookAlert {
fun onInventoryClose(event: InventoryCloseEvent) {
enchantsFound = false
}
+
+ @SubscribeEvent
+ fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) {
+ event.move(59, "inventory.helper.enchanting.ultraRareBookAlert", "inventory.experimentationTable.ultraRareBookAlert")
+ }
+
+ private fun isEnabled() =
+ LorenzUtils.inSkyBlock && config.ultraRareBookAlert && ExperimentationTableAPI.getCurrentExperiment() != null
}