diff options
author | J10a1n15 <45315647+j10a1n15@users.noreply.github.com> | 2024-03-12 19:59:55 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-12 19:59:55 +0100 |
commit | 4352ffb08d4bfffc06adad2a068f375ab9874333 (patch) | |
tree | b8ce745fca8ab82ffa04f6ab87334139a6b7192b /src/main/java/at/hannibal2/skyhanni/data | |
parent | eb863d60e82b5541a9f42d2608f61cb97ada209b (diff) | |
download | skyhanni-4352ffb08d4bfffc06adad2a068f375ab9874333.tar.gz skyhanni-4352ffb08d4bfffc06adad2a068f375ab9874333.tar.bz2 skyhanni-4352ffb08d4bfffc06adad2a068f375ab9874333.zip |
Feature: CustomScoreboard (#893)
Co-authored-by: Thunderblade73 <85900443+Thunderblade73@users.noreply.github.com>
Co-authored-by: Thunderblade73 <gaidermarkus@gmail.com>
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/data')
18 files changed, 962 insertions, 93 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/data/ArrowType.kt b/src/main/java/at/hannibal2/skyhanni/data/ArrowType.kt new file mode 100644 index 000000000..5ce7dd33f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/ArrowType.kt @@ -0,0 +1,9 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.utils.NEUInternalName + +data class ArrowType(val arrow: String, val internalName: NEUInternalName) { + override fun toString(): String { + return internalName.asString() + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/BitsAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/BitsAPI.kt new file mode 100644 index 000000000..2802399bf --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/BitsAPI.kt @@ -0,0 +1,200 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.FameRanks.getFameRankByNameOrNull +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.ScoreboardChangeEvent +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.StringUtils.matches +import at.hannibal2.skyhanni.utils.StringUtils.removeResets +import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpace +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object BitsAPI { + private val profileStorage get() = ProfileStorageData.profileSpecific?.bits + private val playerStorage get() = SkyHanniMod.feature.storage + + var bits: Int + get() = profileStorage?.bits ?: 0 + private set(value) { + profileStorage?.bits = value + } + var currentFameRank: FameRank? + get() = playerStorage?.currentFameRank?.let { getFameRankByNameOrNull(it) } + private set(value) { + if (value != null) { + playerStorage?.currentFameRank = value.name + } + } + var bitsToClaim: Int + get() = profileStorage?.bitsToClaim ?: 0 + private set(value) { + profileStorage?.bitsToClaim = value + } + + private const val defaultcookiebits = 4800 + + private val bitsDataGroup = RepoPattern.group("data.bits") + + // Scoreboard patterns + val bitsScoreboardPattern by bitsDataGroup.pattern( + "scoreboard", + "^Bits: §b(?<amount>[\\d,.]+).*$" + ) + + // Chat patterns + private val bitsChatGroup = bitsDataGroup.group("chat") + + private val bitsFromFameRankUpChatPattern by bitsChatGroup.pattern( + "famerankup", + "§eYou gained §3(?<amount>.*) Bits Available §ecompounded from all your §epreviously eaten §6cookies§e! Click here to open §6cookie menu§e!" + ) + + private val boosterCookieAte by bitsChatGroup.pattern( + "boostercookieate", + "§eYou consumed a §6Booster Cookie§e!.*" + ) + + // GUI patterns + private val bitsGuiGroup = bitsDataGroup.group("gui") + + private val bitsAvailableMenuPattern by bitsGuiGroup.pattern( + "availablemenu", + "§7Bits Available: §b(?<toClaim>[\\d,]+)(§3.+)?" + ) + + private val fameRankSbMenuPattern by bitsGuiGroup.pattern( + "sbmenufamerank", + "§7Your rank: §e(?<rank>.*)" + ) + + private val fameRankCommunityShopPattern by bitsGuiGroup.pattern( + "communityshopfamerank", + "§7Fame Rank: §e(?<rank>.*)" + ) + + private val bitsGuiNamePattern by bitsGuiGroup.pattern( + "mainmenuname", + "^SkyBlock Menu$" + ) + + private val bitsGuiStackPattern by bitsGuiGroup.pattern( + "mainmenustack", + "^§6Booster Cookie$" + ) + + private val fameRankGuiNamePattern by bitsGuiGroup.pattern( + "famerankmenuname", + "^(Community Shop|Booster Cookie)$" + ) + + private val fameRankGuiStackPattern by bitsGuiGroup.pattern( + "famerankmenustack", + "^(§aCommunity Shop|§eFame Rank)$" + ) + + @SubscribeEvent + fun onScoreboardChange(event: ScoreboardChangeEvent) { + if (!isEnabled()) return + for (line in event.newList) { + val message = line.trimWhiteSpace().removeResets() + + bitsScoreboardPattern.matchMatcher(message) { + val amount = group("amount").formatInt() + + if (amount > bits) { + bitsToClaim -= amount - bits + ChatUtils.debug("You have gained §3${amount - bits} Bits §7according to the scoreboard!") + } + bits = amount + + return + } + } + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + val message = event.message.trimWhiteSpace().removeResets() + + bitsFromFameRankUpChatPattern.matchMatcher(message) { + val amount = group("amount").formatInt() + bitsToClaim += amount + + return + } + + boosterCookieAte.matchMatcher(message) { + bitsToClaim += (defaultcookiebits * (currentFameRank?.bitsMultiplier ?: return)).toInt() + + return + } + } + + @SubscribeEvent + fun onInventoryFullyLoaded(event: InventoryFullyOpenedEvent) { + if (!isEnabled()) return + + val stacks = event.inventoryItems + + if (bitsGuiNamePattern.matches(event.inventoryName)) { + val cookieStack = stacks.values.lastOrNull { bitsGuiStackPattern.matches(it.displayName) } ?: return + for (line in cookieStack.getLore()) { + bitsAvailableMenuPattern.matchMatcher(line) { + bitsToClaim = group("toClaim").formatInt() + + return + } + } + return + } + + if (fameRankGuiNamePattern.matches(event.inventoryName)) { + val fameRankStack = stacks.values.lastOrNull { fameRankGuiStackPattern.matches(it.displayName) } ?: return + + line@ for (line in fameRankStack.getLore()) { + fameRankCommunityShopPattern.matchMatcher(line) { + val rank = group("rank") + + currentFameRank = getFameRankByNameOrNull(rank) + ?: return ErrorManager.logErrorWithData( + FameRankNotFoundException(rank), + "FameRank $rank not found", + "Rank" to rank, + "Lore" to fameRankStack.getLore(), + "FameRanks" to FameRanks.fameRanks + ) + + continue@line + } + + fameRankSbMenuPattern.matchMatcher(line) { + val rank = group("rank") + + currentFameRank = getFameRankByNameOrNull(rank) + ?: return ErrorManager.logErrorWithData( + FameRankNotFoundException(rank), + "FameRank $rank not found", + "Rank" to rank, + "Lore" to fameRankStack.getLore(), + "FameRanks" to FameRanks.fameRanks + ) + + continue@line + } + } + } + } + + fun isEnabled() = LorenzUtils.inSkyBlock && profileStorage != null + + class FameRankNotFoundException(rank: String) : Exception("FameRank not found: $rank") +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/FameRanks.kt b/src/main/java/at/hannibal2/skyhanni/data/FameRanks.kt new file mode 100644 index 000000000..663e2b970 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/FameRanks.kt @@ -0,0 +1,26 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.data.jsonobjects.repo.FameRankJson +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object FameRanks { + var fameRanks = emptyMap<String, FameRank>() + private set + + fun getFameRankByNameOrNull(name: String) = fameRanks[name] + + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + val ranks = event.getConstant<FameRankJson>("FameRank") + fameRanks = ranks.fame_rank.values.map { FameRank(it.name, it.fame_required, it.bits_multiplier, it.votes) } + .associateBy { it.name } + } +} + +data class FameRank( + val name: String, + val fameRequired: Int, + val bitsMultiplier: Double, + val electionVotes: Int +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt b/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt index 4fbebe958..ee9a6a23a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt @@ -3,8 +3,10 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.core.config.Position import at.hannibal2.skyhanni.config.core.config.gui.GuiPositionEditor +import at.hannibal2.skyhanni.events.GuiPositionMovedEvent import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.LorenzKeyPressEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.test.SkyHanniDebugsAndTests import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils.isRancherSign @@ -51,11 +53,20 @@ class GuiEditManager { currentPositions.clear() } + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + lastMovedGui?.let { + GuiPositionMovedEvent(it).postAndCatch() + lastMovedGui = null + } + } + companion object { var currentPositions = mutableMapOf<String, Position>() private var latestPositions = mapOf<String, Position>() private var currentBorderSize = mutableMapOf<String, Pair<Int, Int>>() + private var lastMovedGui: String? = null @JvmStatic fun add(position: Position, posLabel: String, x: Int, y: Int) { @@ -116,6 +127,10 @@ class GuiEditManager { fun GuiProfileViewer.anyTextBoxFocused() = this.getPropertiesWithType<GuiElementTextField>().any { it.focus } + + fun handleGuiPositionMoved(guiName: String) { + lastMovedGui = guiName + } } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt index b206eb565..c347fcdba 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt @@ -300,9 +300,12 @@ class HypixelData { private fun checkIsland() { var newIsland = "" var guesting = false + TabListData.fullyLoaded = false + for (line in TabListData.getTabList()) { islandNamePattern.matchMatcher(line) { newIsland = group("island").removeColor() + TabListData.fullyLoaded = true } if (line == " Status: §r§9Guest") { guesting = true diff --git a/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt new file mode 100644 index 000000000..0f19854f7 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt @@ -0,0 +1,152 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.data.jsonobjects.repo.MaxwellPowersJson +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.StringUtils.matches +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import at.hannibal2.skyhanni.utils.StringUtils.removeResets +import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpace +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.enchantment.Enchantment +import net.minecraft.enchantment.Enchantment.power +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object MaxwellAPI { + + private val storage get() = ProfileStorageData.profileSpecific + + var currentPower: String? + get() = storage?.maxwell?.currentPower + set(value) { + storage?.maxwell?.currentPower = value ?: return + } + var magicalPower: Int? + get() = storage?.maxwell?.magicalPower + set(value) { + storage?.maxwell?.magicalPower = value ?: return + } + + private var powers = mutableListOf<String>() + + private val group = RepoPattern.group("data.maxwell") + private val chatPowerpattern by group.pattern( + "chat.power", + "§eYou selected the §a(?<power>.*) §e(power )?for your §aAccessory Bag§e!" + ) + private val inventoryPowerPattern by group.pattern( + "inventory.power", + "§7Selected Power: §a(?<power>.*)" + ) + private val inventoryMPPattern by group.pattern( + "inventory.magicalpower", + "§7Magical Power: §6(?<mp>[\\d,]+)" + ) + private val thaumaturgyGuiPattern by group.pattern( + "gui.thaumaturgy", + "Accessory Bag Thaumaturgy" + ) + private val yourBagsGuiPattern by group.pattern( + "gui.yourbags", + "Your Bags" + ) + private val powerSelectedPattern by group.pattern( + "gui.selectedpower", + "§aPower is selected!" + ) + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + val message = event.message.trimWhiteSpace().removeResets() + + chatPowerpattern.matchMatcher(message) { + val power = group("power") + currentPower = getPowerByNameOrNull(power) + ?: return ErrorManager.logErrorWithData( + UnknownMaxwellPower("Unknown power: $power"), + "Unknown power: $power", + "power" to power, + "message" to message + ) + } + } + + @SubscribeEvent + fun onInventoryFullyLoaded(event: InventoryFullyOpenedEvent) { + if (!isEnabled()) return + + if (thaumaturgyGuiPattern.matches(event.inventoryName)) { + val selectedPowerStack = + event.inventoryItems.values.find { + powerSelectedPattern.matches(it.getLore().lastOrNull()) + } ?: return + val displayName = selectedPowerStack.displayName.removeColor() + + currentPower = getPowerByNameOrNull(displayName) + ?: return ErrorManager.logErrorWithData( + UnknownMaxwellPower("Unknown power: $power"), + "Unknown power: $power", + "power" to power, + "displayName" to displayName, + "lore" to selectedPowerStack.getLore() + ) + return + } + + if (yourBagsGuiPattern.matches(event.inventoryName)) { + val stacks = event.inventoryItems + + for (stack in stacks.values) { + processStack(stack) + } + } + } + + private fun processStack(stack: ItemStack) { + for (line in stack.getLore()) { + inventoryMPPattern.matchMatcher(line) { + // MagicalPower is boosted in catacombs + if (IslandType.CATACOMBS.isInIsland()) return@matchMatcher + + val mp = group("mp") + magicalPower = mp.formatInt() + return@matchMatcher + } + + inventoryPowerPattern.matchMatcher(line) { + val power = group("power") + currentPower = getPowerByNameOrNull(power) + ?: return@matchMatcher ErrorManager.logErrorWithData( + UnknownMaxwellPower("Unknown power: ${Enchantment.power}"), + "Unknown power: ${Enchantment.power}", + "power" to Enchantment.power, + "displayName" to stack.displayName, + "lore" to stack.getLore() + ) + return@matchMatcher + } + } + } + + private fun getPowerByNameOrNull(name: String) = powers.find { it == name } + + fun isEnabled() = LorenzUtils.inSkyBlock && storage != null + + // Load powers from repo + @SubscribeEvent + fun onRepoLoad(event: RepositoryReloadEvent) { + val data = event.getConstant<MaxwellPowersJson>("MaxwellPowers") + powers = data.powers + } + + class UnknownMaxwellPower(message: String) : Exception(message) +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt new file mode 100644 index 000000000..bc937a5a2 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt @@ -0,0 +1,121 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.ConfigManager +import at.hannibal2.skyhanni.data.Mayor.Companion.setMayorWithActivePerks +import at.hannibal2.skyhanni.data.jsonobjects.local.MayorJson +import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent +import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.CollectionUtils.put +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.asTimeMark +import io.github.moulberry.notenoughupdates.util.SkyBlockTime +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes + +object MayorAPI { + var lastUpdate = SimpleTimeMark.farPast() + private var dispatcher = Dispatchers.IO + + private var rawMayorData: MayorJson? = null + var candidates = mapOf<Int, MayorJson.Candidate>() + private set + var currentMayor: Mayor? = null + private set + var timeTillNextMayor = Duration.ZERO + private set + + private const val ELECTION_END_MONTH = 3 //Late Spring + private const val ELECTION_END_DAY = 27 + + /** + * @param input: The name of the mayor + * @return: The neu color of the mayor; If no mayor was found, it will return "§cUnknown: §7" + */ + fun mayorNameToColorCode(input: String): String { + return Mayor.getMayorFromName(input).color + } + + /** + * @param input: The name of the mayor + * @return: The neu color of the mayor + the name of the mayor; If no mayor was found, it will return "§cUnknown: §7[input]" + */ + fun mayorNameWithColorCode(input: String) = mayorNameToColorCode(input) + input + + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + if (!LorenzUtils.onHypixel) return + + if (event.repeatSeconds(2)) { + checkHypixelAPI() + getTimeTillNextMayor() + } + } + + private fun calculateNextMayorTime(): SimpleTimeMark { + var mayorYear = SkyBlockTime.now().year + + // Check if either the month is already over or the day is after 27th in the third month + if (SkyBlockTime.now().month > ELECTION_END_MONTH || (SkyBlockTime.now().day >= ELECTION_END_DAY && SkyBlockTime.now().month == ELECTION_END_MONTH)) { + // If so, the next mayor will be in the next year + mayorYear++ + } + + return SkyBlockTime(mayorYear, ELECTION_END_MONTH, day = ELECTION_END_DAY).asTimeMark() + } + + private fun getTimeTillNextMayor() { + val nextMayorTime = calculateNextMayorTime() + timeTillNextMayor = nextMayorTime - SimpleTimeMark.now() + } + + private fun checkCurrentMayor() { + val nextMayorTime = calculateNextMayorTime() + + // Check if it is still the mayor from the old SkyBlock year + currentMayor = candidates[nextMayorTime.toSkyBlockTime().year - 1]?.let { + // TODO: Once Jerry is active, add the sub mayor perks in here + setMayorWithActivePerks(it.name, it.perks) + } + } + + private fun checkHypixelAPI() { + if (lastUpdate.passedSince() < 20.minutes) return + lastUpdate = SimpleTimeMark.now() + + SkyHanniMod.coroutineScope.launch { + val url = "https://api.hypixel.net/v2/resources/skyblock/election" + val jsonObject = withContext(dispatcher) { APIUtil.getJSONResponse(url) } + rawMayorData = ConfigManager.gson.fromJson(jsonObject, MayorJson::class.java) + val data = rawMayorData ?: return@launch + val map = mutableMapOf<Int, MayorJson.Candidate>() + map put data.mayor.election.getPairs() + data.current?.let { + map put data.current.getPairs() + } + candidates = map + checkCurrentMayor() + } + } + + private fun MayorJson.Election.getPairs() = year + 1 to candidates.bestCandidate() + + private fun List<MayorJson.Candidate>.bestCandidate() = maxBy { it.votes } + + @SubscribeEvent + fun onDebugDataCollect(event: DebugDataCollectEvent) { + event.title("Mayor") + event.addIrrelevant { + add("Current Mayor: ${currentMayor?.name ?: "Unknown"}") + add("Active Perks: ${currentMayor?.activePerks}") + add("Last Update: $lastUpdate (${lastUpdate.passedSince()} ago)") + add("Time Till Next Mayor: $timeTillNextMayor") + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/MayorElection.kt b/src/main/java/at/hannibal2/skyhanni/data/MayorElection.kt deleted file mode 100644 index e73a6bf14..000000000 --- a/src/main/java/at/hannibal2/skyhanni/data/MayorElection.kt +++ /dev/null @@ -1,79 +0,0 @@ -package at.hannibal2.skyhanni.data - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.config.ConfigManager -import at.hannibal2.skyhanni.data.jsonobjects.local.MayorJson -import at.hannibal2.skyhanni.events.LorenzTickEvent -import at.hannibal2.skyhanni.utils.APIUtil -import at.hannibal2.skyhanni.utils.CollectionUtils.put -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.SimpleTimeMark -import io.github.moulberry.notenoughupdates.util.SkyBlockTime -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import kotlin.time.Duration.Companion.minutes - -class MayorElection { - - private var lastUpdate = SimpleTimeMark.farPast() - private var dispatcher = Dispatchers.IO - - companion object { - - var rawMayorData: MayorJson? = null - var candidates = mapOf<Int, MayorJson.Candidate>() - var currentCandidate: MayorJson.Candidate? = null - - fun isPerkActive(mayor: String, perk: String) = currentCandidate?.let { currentCandidate -> - currentCandidate.name == mayor && currentCandidate.perks.any { it.name == perk } - } ?: false - } - - @SubscribeEvent - fun onTick(event: LorenzTickEvent) { - if (!LorenzUtils.onHypixel) return - - if (event.repeatSeconds(3)) { - check() - } - } - - private fun check() { - if (lastUpdate.passedSince() < 20.minutes) return - lastUpdate = SimpleTimeMark.now() - - SkyHanniMod.coroutineScope.launch { - val url = "https://api.hypixel.net/v2/resources/skyblock/election" - val jsonObject = withContext(dispatcher) { APIUtil.getJSONResponse(url) } - rawMayorData = ConfigManager.gson.fromJson(jsonObject, MayorJson::class.java) - val data = rawMayorData ?: return@launch - val map = mutableMapOf<Int, MayorJson.Candidate>() - map put data.mayor.election.getPairs() - data.current?.let { - map put data.current.getPairs() - } - candidates = map - checkCurrentMayor() - } - } - - private fun checkCurrentMayor() { - var currentYear = SkyBlockTime.now().year - - // The time in the current SkyBlock year when the election circle will restart - val month = 3 // Late Spring - val nextMayorTime = SkyBlockTime(currentYear, month, day = 27).toMillis() - - // Is it still the mayor from old sb year? - if (nextMayorTime > System.currentTimeMillis()) { - currentYear-- - } - currentCandidate = candidates[currentYear] - } - - private fun MayorJson.Election.getPairs() = year + 1 to candidates.bestCandidate() - - private fun List<MayorJson.Candidate>.bestCandidate() = maxBy { it.votes } -} diff --git a/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt new file mode 100644 index 000000000..cd6205c7a --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt @@ -0,0 +1,105 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.data.jsonobjects.local.MayorJson + +enum class Mayor( + val mayorName: String, + val color: String, + private vararg val perks: Perk, +) { + AATROX("Aatrox", "§3", Perk.SLASHED_PRICING, Perk.SLAYER_XP_BUFF, Perk.PATHFINDER), + COLE("Cole", "§e", Perk.PROSPECTION, Perk.MINING_XP_BUFF, Perk.MINING_FIESTA), + DIANA("Diana", "§2", Perk.LUCKY, Perk.MYTHOLOGICAL_RITUAL, Perk.PET_XP_BUFF), + DIAZ("Diaz", "§6", Perk.BARRIER_STREET, Perk.SHOPPING_SPREE), + FINNEGAN("Finnegan", "§c", Perk.FARMING_SIMULATOR, Perk.PELT_POCALYPSE, Perk.GOATED), + FOXY("Foxy", "§d", Perk.SWEET_TOOTH, Perk.BENEVOLENCE, Perk.EXTRA_EVENT), + MARINA("Marina", "§b", Perk.FISHING_XP_BUFF, Perk.LUCK_OF_THE_SEA, Perk.FISHING_FESTIVAL), + PAUL("Paul", "§c", Perk.MARAUDER, Perk.EZPZ, Perk.BENEDICTION), + + SCORPIUS("Scorpius", "§d", Perk.BRIBE, Perk.DARKER_AUCTIONS), + JERRY("Jerry", "§d", Perk.PERKPOCALYPSE, Perk.STATSPOCALYPSE, Perk.JERRYPOCALYPSE), + DERPY("Derpy", "§d", Perk.TURBO_MINIONS, Perk.AH_CLOSED, Perk.DOUBLE_MOBS_HP, Perk.MOAR_SKILLZ), + + UNKNOWN("Unknown", "§c"), + ; + + val activePerks: MutableList<Perk> = mutableListOf() + + companion object { + fun getMayorFromName(name: String) = entries.firstOrNull { it.mayorName == name } ?: UNKNOWN + + fun setMayorWithActivePerks(name: String, perks: ArrayList<MayorJson.Perk>): Mayor { + val mayor = getMayorFromName(name) + + mayor.perks.forEach { it.isActive = false } + mayor.activePerks.clear() + perks.mapNotNull { perk -> Perk.entries.firstOrNull { it.perkName == perk.name } } + .filter { mayor.perks.contains(it) }.forEach { + it.isActive = true + mayor.activePerks.add(it) + } + + return mayor + } + } +} + +enum class Perk(val perkName: String) { + // Aatrox + SLASHED_PRICING("SLASHED Pricing"), + SLAYER_XP_BUFF("Slayer XP Buff"), + PATHFINDER("Pathfinder"), + + // Cole + PROSPECTION("Prospection"), + MINING_XP_BUFF("Mining XP Buff"), + MINING_FIESTA("Mining Fiesta"), + + // Diana + LUCKY("Lucky!"), + MYTHOLOGICAL_RITUAL("Mythological Ritual"), + PET_XP_BUFF("Pet XP Buff"), + + // Diaz + BARRIER_STREET("Barrier Street"), + SHOPPING_SPREE("Shopping Spree"), + + // Finnegan + FARMING_SIMULATOR("Farming Simulator"), + PELT_POCALYPSE("Pelt-pocalypse"), + GOATED("GOATed"), + + // Foxy + SWEET_TOOTH("Sweet Tooth"), + BENEVOLENCE("Benevolence"), + EXTRA_EVENT("Extra Event"), + + // Marina + FISHING_XP_BUFF("Fishing XP Buff"), + LUCK_OF_THE_SEA("Luck of the Sea 2.0"), + FISHING_FESTIVAL("Fishing Festival"), + + // Paul + MARAUDER("Marauder"), + EZPZ("EZPZ"), + BENEDICTION("Benediction"), + + + // Scorpius + BRIBE("Bribe"), + DARKER_AUCTIONS("Darker Auctions"), + + // Jerry + PERKPOCALYPSE("Perkpocalypse"), + STATSPOCALYPSE("Statspocalypse"), + JERRYPOCALYPSE("Jerrypocalypse"), + + // Derpy + TURBO_MINIONS("TURBO MINIONS!!!"), + AH_CLOSED("AH CLOSED!!!"), + DOUBLE_MOBS_HP("DOUBLE MOBS HP!!!"), + MOAR_SKILLZ("MOAR SKILLZ!!!"), + ; + + var isActive = false +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt index 22fb8e4f8..ace56f67f 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt @@ -8,7 +8,7 @@ import at.hannibal2.skyhanni.utils.StringUtils.cleanPlayerName import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.StringUtils.removeResets -import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpaceAndResets +import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpace import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.random.Random @@ -94,7 +94,7 @@ object PartyAPI { @SubscribeEvent fun onChat(event: LorenzChatEvent) { - val message = event.message.trimWhiteSpaceAndResets().removeResets() + val message = event.message.trimWhiteSpace().removeResets() // new member joined youJoinedPartyPattern.matchMatcher(message) { diff --git a/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt index 90ea15627..f4266f800 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt @@ -4,8 +4,8 @@ import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.PurseChangeCause import at.hannibal2.skyhanni.events.PurseChangeEvent -import at.hannibal2.skyhanni.utils.NumberUtil.formatNumber -import at.hannibal2.skyhanni.utils.NumberUtil.milion +import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble +import at.hannibal2.skyhanni.utils.NumberUtil.million import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.client.Minecraft @@ -13,7 +13,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent object PurseAPI { private val patternGroup = RepoPattern.group("data.purse") - private val coinsPattern by patternGroup.pattern( + val coinsPattern by patternGroup.pattern( "coins", "(§.)*(Piggy|Purse): §6(?<coins>[\\d,.]+)( ?(§.)*\\([+-](?<earned>[\\d,.]+)\\)?|.*)?$" ) @@ -22,8 +22,9 @@ object PurseAPI { "Piggy: (?<coins>.*)" ) - private var currentPurse = 0.0 private var inventoryCloseTime = 0L + var currentPurse = 0.0 + private set @SubscribeEvent fun onInventoryClose(event: InventoryCloseEvent) { @@ -32,10 +33,9 @@ object PurseAPI { @SubscribeEvent fun onTick(event: LorenzTickEvent) { - for (line in ScoreboardData.sidebarLinesFormatted) { val newPurse = coinsPattern.matchMatcher(line) { - group("coins").formatNumber().toDouble() + group("coins").formatDouble() } ?: continue val diff = newPurse - currentPurse if (diff == 0.0) continue @@ -52,7 +52,7 @@ object PurseAPI { return PurseChangeCause.GAIN_TALISMAN_OF_COINS } - if (diff == 15.milion || diff == 100.milion) { + if (diff == 15.million || diff == 100.million) { return PurseChangeCause.GAIN_DICE_ROLL } diff --git a/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt new file mode 100644 index 000000000..603b9963b --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt @@ -0,0 +1,256 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.jsonobjects.repo.ArrowTypeJson +import at.hannibal2.skyhanni.data.jsonobjects.repo.ItemsJson +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.PlaySoundEvent +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemCategory +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalNameOrNull +import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.NumberUtil.formatNumber +import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getEnchantments +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.StringUtils.matches +import at.hannibal2.skyhanni.utils.StringUtils.removeResets +import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpace +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.client.Minecraft +import net.minecraft.item.ItemBow +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +private var infinityQuiverLevelMultiplier = 0.03f + +object QuiverAPI { + private val storage get() = ProfileStorageData.profileSpecific + var currentArrow: ArrowType? + get() = storage?.arrows?.currentArrow?.asInternalName()?.let { getArrowByNameOrNull(it) } ?: NONE_ARROW_TYPE + set(value) { + storage?.arrows?.currentArrow = value?.toString() ?: return + } + var arrowAmount: MutableMap<NEUInternalName, Float> + get() = storage?.arrows?.arrowAmount ?: mutableMapOf() + set(value) { + storage?.arrows?.arrowAmount = value + } + var currentAmount: Int + get() = arrowAmount[currentArrow?.internalName]?.toInt() ?: 0 + set(value) { + arrowAmount[currentArrow?.internalName ?: return] = value.toFloat() + } + + private var arrows: List<ArrowType> = listOf() + + const val MAX_ARROW_AMOUNT = 2880 + private val SKELETON_MASTER_CHESTPLATE = "SKELETON_MASTER_CHESTPLATE".asInternalName() + + var NONE_ARROW_TYPE: ArrowType? = null + private var FLINT_ARROW_TYPE: ArrowType? = null + + private val group = RepoPattern.group("data.quiver") + private val chatGroup = group.group("chat") + private val selectPattern by chatGroup.pattern("select", "§aYou set your selected arrow type to §f(?<arrow>.*)§a!") + private val fillUpJaxPattern by chatGroup.pattern( + "fillupjax", + "(§.)*Jax forged (§.)*(?<type>.*?)(§.)* x(?<amount>[\\d,]+)( (§.)*for (§.)*(?<coins>[\\d,]+) Coins)?(§.)*!" + ) + private val fillUpPattern by chatGroup.pattern( + "fillup", + "§aYou filled your quiver with §f(?<flintAmount>.*) §aextra arrows!" + ) + private val clearedPattern by chatGroup.pattern("cleared", "§aCleared your quiver!") + private val arrowResetPattern by chatGroup.pattern("arrowreset", "§cYour favorite arrow has been reset!") + private val addedToQuiverPattern by chatGroup.pattern( + "addedtoquiver", + "(§.)*You've added (§.)*(?<type>.*) x(?<amount>.*) (§.)*to your quiver!" + ) + + // Bows that don't use the players arrows, checked using the SkyBlock Id + private val fakeBowsPattern by group.pattern("fakebows", "^(BOSS_SPIRIT_BOW|CRYPT_BOW)$") + private val quiverInventoryNamePattern by group.pattern("quivername", "^Quiver$") + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + val message = event.message.trimWhiteSpace().removeResets() + + selectPattern.matchMatcher(message) { + val type = group("arrow") + currentArrow = getArrowByNameOrNull(type) + ?: return ErrorManager.logErrorWithData( + UnknownArrowType("Unknown arrow type: $type"), + "Unknown arrow type: $type", + "message" to message, + ) + return + } + + fillUpJaxPattern.matchMatcher(message) { + val type = group("type") + val amount = group("amount").formatNumber().toFloat() + val filledUpType = getArrowByNameOrNull(type) + ?: return ErrorManager.logErrorWithData( + UnknownArrowType("Unknown arrow type: $type"), + "Unknown arrow type: $type", + "message" to message, + ) + + arrowAmount.addOrPut(filledUpType.internalName, amount) + return + } + + fillUpPattern.matchMatcher(message) { + val flintAmount = group("flintAmount").formatNumber().toFloat() + + FLINT_ARROW_TYPE?.let { arrowAmount.addOrPut(it.internalName, flintAmount) } + return + } + + addedToQuiverPattern.matchMatcher(message) { + val type = group("type") + val amount = group("amount").formatNumber().toFloat() + + val filledUpType = getArrowByNameOrNull(type) + ?: return ErrorManager.logErrorWithData( + UnknownArrowType("Unknown arrow type: $type"), + "Unknown arrow type: $type", + "message" to message, + ) + + arrowAmount.addOrPut(filledUpType.internalName, amount) + return + } + + clearedPattern.matchMatcher(message) { + currentAmount = 0 + arrowAmount.clear() + + return + } + + arrowResetPattern.matchMatcher(message) { + currentArrow = NONE_ARROW_TYPE + currentAmount = 0 + + return + } + } + + @SubscribeEvent + fun onInventoryFullyLoaded(event: InventoryFullyOpenedEvent) { + if (!isEnabled()) return + if (!quiverInventoryNamePattern.matches(event.inventoryName)) return + + // clear to prevent duplicates + currentAmount = 0 + arrowAmount.clear() + + val stacks = event.inventoryItems + for (stack in stacks.values) { + if (stack.getItemCategoryOrNull() != ItemCategory.ARROW) continue + + val arrow = stack.getInternalNameOrNull() ?: continue + + val arrowType = getArrowByNameOrNull(arrow) ?: continue + + arrowAmount.addOrPut(arrowType.internalName, stack.stackSize.toFloat()) + } + } + + /* + Modified method to remove arrows from SkyblockFeatures QuiverOverlay + Original method source: + https://github.com/MrFast-js/SkyblockFeatures/blob/ae4bf0b91ed0fb17114d9cdaccaa9aef9a6c8d01/src/main/java/mrfast/sbf/features/overlays/QuiverOverlay.java#L127 + + Changes made: + - Added "fake bows" check + - Added "infinite quiver" check + - Added "sneaking" check + - Added "bow sound distance" check + - Added "skeleton master chestplate" check + */ + @SubscribeEvent(priority = EventPriority.HIGHEST) + fun onPlaySound(event: PlaySoundEvent) { + if (!isEnabled()) return + if (event.soundName != "random.bow") return + + val holdingBow = InventoryUtils.getItemInHand()?.item is ItemBow + && !fakeBowsPattern.matches(InventoryUtils.getItemInHand()?.getInternalNameOrNull()?.asString() ?: "") + + if (!holdingBow) return + + // check if sound location is more than configAmount block away from player + val soundLocation = event.distanceToPlayer + if (soundLocation > SkyHanniMod.feature.dev.bowSoundDistance) return + + val arrowType = currentArrow?.internalName ?: return + val amount = arrowAmount[arrowType] ?: return + if (amount <= 0) return + + if (InventoryUtils.getChestplate() + // The chestplate has the ability to not use arrows + // https://hypixel-skyblock.fandom.com/wiki/Skeleton_Master_Armor + ?.getInternalNameOrNull() == SKELETON_MASTER_CHESTPLATE + ) return + + val infiniteQuiverLevel = InventoryUtils.getItemInHand()?.getEnchantments()?.get("infinite_quiver") ?: 0 + + val amountToRemove = { + when (Minecraft.getMinecraft().thePlayer.isSneaking) { + true -> 1.0f + false -> { + when (infiniteQuiverLevel) { + in 1..10 -> 1 - (infinityQuiverLevelMultiplier * infiniteQuiverLevel) + else -> 1.0f + } + } + } + } + + arrowAmount[arrowType] = amount - amountToRemove() + } + + fun Int.asArrowPercentage() = ((this.toFloat() / MAX_ARROW_AMOUNT) * 100).round(1) + + fun hasBowInInventory(): Boolean { + return InventoryUtils.getItemsInOwnInventory().any { it.item is ItemBow } + } + + fun getArrowByNameOrNull(name: String): ArrowType? { + return arrows.firstOrNull { it.arrow == name } + } + + fun getArrowByNameOrNull(internalName: NEUInternalName): ArrowType? { + return arrows.firstOrNull { it.internalName == internalName } + } + + private fun NEUInternalName.asArrowTypeOrNull() = getArrowByNameOrNull(this) + + fun isEnabled() = LorenzUtils.inSkyBlock && storage != null + + + // Load arrows from repo + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + val itemData = event.getConstant<ItemsJson>("Items") + infinityQuiverLevelMultiplier = itemData.enchant_multiplier["infinite_quiver"] ?: 0.03f + + val arrowData = event.getConstant<ArrowTypeJson>("ArrowTypes") + arrows = arrowData.arrows.map { ArrowType(it.value.arrow, it.key.asInternalName()) } + + NONE_ARROW_TYPE = getArrowByNameOrNull("NONE".asInternalName()) + FLINT_ARROW_TYPE = getArrowByNameOrNull("FLINT".asInternalName()) + } + + class UnknownArrowType(message: String) : Exception(message) +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt b/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt index 661330f92..b2cb66ef0 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt @@ -35,13 +35,23 @@ class ScoreboardData { fun formatLines(rawList: List<String>): List<String> { val list = mutableListOf<String>() for (line in rawList) { - val seperator = splitIcons.find { line.contains(it) } ?: continue - val split = line.split(seperator) + val separator = splitIcons.find { line.contains(it) } ?: continue + val split = line.split(separator) val start = split[0] var end = split[1] - if (end.length >= 2) { - end = end.substring(2) + // get last color code in start + val lastColorIndex = start.lastIndexOf('§') + val lastColor = when { + lastColorIndex != -1 && lastColorIndex + 1 < start.length && (start[lastColorIndex + 1] in '0'..'9' || start[lastColorIndex + 1] in 'a'..'f') -> start.substring( + lastColorIndex, + lastColorIndex + 2 + ) + else -> "" } + + // remove first color code from end, when it is the same as the last color code in start + end = end.removePrefix(lastColor) + list.add(start + end) } diff --git a/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt index 296e2db65..6ecf6935c 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt @@ -30,7 +30,7 @@ object SlayerAPI { var latestSlayerCategory = "" private var latestProgressChangeTime = 0L var latestWrongAreaWarning = 0L - private var latestSlayerProgress = "" + var latestSlayerProgress = "" fun hasActiveSlayerQuest() = latestSlayerCategory != "" diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/ArrowTypeJson.java b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/ArrowTypeJson.java new file mode 100644 index 000000000..3388cb62c --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/ArrowTypeJson.java @@ -0,0 +1,14 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo; + +import com.google.gson.annotations.Expose; +import java.util.Map; + +public class ArrowTypeJson { + @Expose + public Map<String, ArrowAttributes> arrows; + + public static class ArrowAttributes { + @Expose + public String arrow; + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/FameRankJson.java b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/FameRankJson.java new file mode 100644 index 000000000..e060d55d1 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/FameRankJson.java @@ -0,0 +1,24 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo; + +import com.google.gson.annotations.Expose; + +import java.util.Map; + +public class FameRankJson { + @Expose + public Map<String, FameRank> fame_rank; + + public static class FameRank { + @Expose + public String name; + + @Expose + public int fame_required; + + @Expose + public double bits_multiplier; + + @Expose + public int votes; + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/ItemsJson.java b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/ItemsJson.java index ddd814159..0efeeb9fd 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/ItemsJson.java +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/ItemsJson.java @@ -14,6 +14,9 @@ public class ItemsJson { public Map<String, Integer> crimson_tiers; @Expose + public Map<String, Float> enchant_multiplier; + + @Expose public List<NEUInternalName> lava_fishing_rods; @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/MaxwellPowersJson.java b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/MaxwellPowersJson.java new file mode 100644 index 000000000..6ac70abb6 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/MaxwellPowersJson.java @@ -0,0 +1,10 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo; + +import com.google.gson.annotations.Expose; + +import java.util.List; + +public class MaxwellPowersJson { + @Expose + public List<String> powers; +} |